prodex 1.0.8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +4 -2
- package/dist/src/cli/init.js +8 -40
- package/dist/src/cli/picker.js +21 -26
- package/dist/src/cli/summary.js +2 -5
- package/dist/src/constants/config-loader.js +74 -51
- package/dist/src/constants/config.js +3 -80
- package/dist/src/constants/default-config.js +36 -0
- package/dist/src/constants/render-constants.js +22 -0
- package/dist/src/core/combine.js +92 -88
- package/dist/src/core/file-utils.js +34 -2
- package/dist/src/core/helpers.js +41 -91
- package/dist/src/core/renderers.js +58 -0
- package/dist/src/index.js +5 -1
- package/dist/src/resolvers/js-resolver.js +104 -59
- package/dist/src/resolvers/php-resolver.js +70 -30
- package/package.json +4 -2
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prodex",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Unified Project Indexer & Dependency Extractor for Laravel + React + Node stacks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,10 +34,12 @@
|
|
|
34
34
|
"author": "emxhive",
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"devDependencies": {
|
|
37
|
+
"@types/node": "^24.9.1",
|
|
37
38
|
"tsup": "^8.5.0",
|
|
38
39
|
"typescript": "^5.9.3"
|
|
39
40
|
},
|
|
40
41
|
"dependencies": {
|
|
41
|
-
"inquirer": "^12.10.0"
|
|
42
|
+
"inquirer": "^12.10.0",
|
|
43
|
+
"micromatch": "^4.0.8"
|
|
42
44
|
}
|
|
43
45
|
}
|
package/dist/src/cli/init.js
CHANGED
|
@@ -1,50 +1,18 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import
|
|
3
|
+
import { DEFAULT_PRODEX_CONFIG } from "../constants/default-config.js";
|
|
4
4
|
|
|
5
5
|
export async function initProdex() {
|
|
6
|
-
console.log("🪄 Prodex Init — Configuration Wizard\n");
|
|
6
|
+
console.log("🪄 Prodex Init — Configuration Wizard (v2)\n");
|
|
7
|
+
|
|
8
|
+
const dest = path.join(process.cwd(), "prodex.json");
|
|
7
9
|
|
|
8
|
-
const dest = path.join(process.cwd(), ".prodex.json");
|
|
9
10
|
if (fs.existsSync(dest)) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
]);
|
|
13
|
-
if (!overwrite) {
|
|
14
|
-
console.log("❌ Cancelled.");
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
11
|
+
console.log("❌ prodex.json already exists. Delete or modify it manually.\n");
|
|
12
|
+
return;
|
|
17
13
|
}
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
"$schema": "https://raw.githubusercontent.com/emxhive/prodex/main/schema/prodex.schema.json",
|
|
21
|
-
"output": "prodex",
|
|
22
|
-
"scanDepth": 2,
|
|
23
|
-
"limit": 200,
|
|
24
|
-
"baseDirs": ["app", "routes", "resources/js"],
|
|
25
|
-
"aliasOverrides": {
|
|
26
|
-
"@hooks": "resources/js/hooks",
|
|
27
|
-
"@data": "resources/js/data"
|
|
28
|
-
},
|
|
29
|
-
"priorityFiles": [
|
|
30
|
-
"routes/web.php",
|
|
31
|
-
"routes/api.php",
|
|
32
|
-
"index.",
|
|
33
|
-
"main.",
|
|
34
|
-
"app."
|
|
35
|
-
],
|
|
36
|
-
"entryExcludes": [
|
|
37
|
-
"resources/js/components/ui/",
|
|
38
|
-
"app/DTOs/"
|
|
39
|
-
],
|
|
40
|
-
"importExcludes": [
|
|
41
|
-
"node_modules",
|
|
42
|
-
"@shadcn/"
|
|
43
|
-
]
|
|
44
|
-
}
|
|
45
|
-
`;
|
|
46
|
-
|
|
47
|
-
fs.writeFileSync(dest, jsonc, "utf8");
|
|
15
|
+
fs.writeFileSync(dest, JSON.stringify(DEFAULT_PRODEX_CONFIG, null, 2) + "\n", "utf8");
|
|
48
16
|
console.log(`✅ Created ${dest}`);
|
|
49
|
-
console.log("💡
|
|
17
|
+
console.log("💡 Globs supported everywhere (includes, excludes, priority).");
|
|
50
18
|
}
|
package/dist/src/cli/picker.js
CHANGED
|
@@ -4,33 +4,34 @@ import inquirer from "inquirer";
|
|
|
4
4
|
import { ROOT } from "../constants/config.js";
|
|
5
5
|
import { walk, rel, sortWithPriority } from "../core/helpers.js";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Prodex v2 picker
|
|
9
|
+
* - Keeps "Load more" (depth++)
|
|
10
|
+
* - Removes manual path entry
|
|
11
|
+
* - Uses cfg.entry.includes / cfg.entry.priority
|
|
12
|
+
*/
|
|
7
13
|
export async function pickEntries(baseDirs, depth = 2, cfg = {}) {
|
|
8
14
|
let selected = [];
|
|
15
|
+
|
|
9
16
|
while (true) {
|
|
10
17
|
const files = [];
|
|
18
|
+
|
|
19
|
+
// Use an effective cfg that reflects the current depth for this iteration
|
|
20
|
+
const effectiveCfg = { ...cfg, scanDepth: depth };
|
|
21
|
+
|
|
11
22
|
for (const base of baseDirs) {
|
|
12
23
|
const full = path.join(ROOT, base);
|
|
13
24
|
if (!fs.existsSync(full)) continue;
|
|
14
|
-
for (const f of walk(full,
|
|
25
|
+
for (const f of walk(full, effectiveCfg, 0)) files.push(f);
|
|
15
26
|
}
|
|
16
27
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const prioritized = sorted.filter(f =>
|
|
20
|
-
cfg.priorityFiles?.some(p =>
|
|
21
|
-
rel(f).replaceAll("\\", "/").toLowerCase().includes(p.toLowerCase())
|
|
22
|
-
)
|
|
23
|
-
);
|
|
28
|
+
// Priority-aware ordering
|
|
29
|
+
const sorted = sortWithPriority(files, cfg.entry?.priority || []);
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
// if (prioritized.length) {
|
|
31
|
-
// choices.unshift(new inquirer.Separator("⭐ Recommended entries"));
|
|
32
|
-
// choices.splice(prioritized.length + 1, 0, new inquirer.Separator("─ Other files"));
|
|
33
|
-
// }
|
|
31
|
+
// Build choices + the "Load more" control
|
|
32
|
+
const choices = sorted.map(f => ({ name: rel(f), value: f }));
|
|
33
|
+
choices.push(new inquirer.Separator());
|
|
34
|
+
choices.push({ name: "🔽 Load more (go deeper)", value: "__loadmore" });
|
|
34
35
|
|
|
35
36
|
const { picks } = await inquirer.prompt([
|
|
36
37
|
{
|
|
@@ -44,21 +45,15 @@ export async function pickEntries(baseDirs, depth = 2, cfg = {}) {
|
|
|
44
45
|
}
|
|
45
46
|
]);
|
|
46
47
|
|
|
47
|
-
if (picks.includes("__manual")) {
|
|
48
|
-
const { manual } = await inquirer.prompt([
|
|
49
|
-
{ name: "manual", message: "Enter relative path:" }
|
|
50
|
-
]);
|
|
51
|
-
if (manual.trim()) selected.push(path.resolve(ROOT, manual.trim()));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
48
|
if (picks.includes("__loadmore")) {
|
|
55
49
|
depth++;
|
|
56
|
-
selected = picks.filter(p =>
|
|
50
|
+
selected = picks.filter(p => p !== "__loadmore");
|
|
57
51
|
continue;
|
|
58
52
|
}
|
|
59
53
|
|
|
60
|
-
selected = picks.filter(p =>
|
|
54
|
+
selected = picks.filter(p => p !== "__loadmore");
|
|
61
55
|
break;
|
|
62
56
|
}
|
|
57
|
+
|
|
63
58
|
return [...new Set(selected)];
|
|
64
59
|
}
|
package/dist/src/cli/summary.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
export function showSummary({
|
|
1
|
+
export function showSummary({ outDir, fileName, entries }) {
|
|
2
2
|
console.log("\n🧩 Active Run:");
|
|
3
|
-
console.log(" • Output Directory:",
|
|
3
|
+
console.log(" • Output Directory:", outDir);
|
|
4
4
|
console.log(" • File Name:", fileName);
|
|
5
5
|
console.log(" • Entries:", entries.length);
|
|
6
|
-
console.log(" • Scan Depth:", scanDepth);
|
|
7
|
-
console.log(" • Limit:", limit);
|
|
8
|
-
console.log(" • Chain:", chain ? "Enabled" : "Disabled");
|
|
9
6
|
}
|
|
@@ -1,64 +1,87 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
CODE_EXTS,
|
|
6
|
-
ENTRY_EXCLUDES,
|
|
7
|
-
IMPORT_EXCLUDES,
|
|
8
|
-
BASE_DIRS,
|
|
9
|
-
PRIORITY_FILES
|
|
10
|
-
} from "./config.js";
|
|
3
|
+
import micromatch from "micromatch";
|
|
4
|
+
import { DEFAULT_PRODEX_CONFIG } from "./default-config.js";
|
|
11
5
|
|
|
12
|
-
/**
|
|
13
|
-
* Loads and merges the Prodex configuration.
|
|
14
|
-
* - `output` is treated strictly as a directory.
|
|
15
|
-
* - Defaults to ROOT/prodex when not defined.
|
|
16
|
-
*/
|
|
17
6
|
export function loadProdexConfig() {
|
|
18
|
-
const
|
|
19
|
-
|
|
7
|
+
const ROOT = process.cwd();
|
|
8
|
+
const configPath = path.join(ROOT, "prodex.json");
|
|
9
|
+
|
|
10
|
+
if (!fs.existsSync(configPath)) {
|
|
11
|
+
console.log("🪄 No prodex.json found — generating default config...\n");
|
|
12
|
+
fs.writeFileSync(configPath, JSON.stringify(DEFAULT_PRODEX_CONFIG, null, 2) + "\n", "utf8");
|
|
13
|
+
}
|
|
14
|
+
let raw;
|
|
15
|
+
try {
|
|
16
|
+
raw = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
17
|
+
} catch (err) {
|
|
18
|
+
throw new Error(`❌ Invalid prodex.json: ${err.message}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const cfg = {
|
|
22
|
+
outDir: path.resolve(ROOT, raw.outDir || "prodex"),
|
|
23
|
+
scanDepth: raw.scanDepth ?? 2,
|
|
24
|
+
limit: raw.limit ?? 200,
|
|
25
|
+
|
|
26
|
+
entry: {
|
|
27
|
+
includes: toArray(raw.entry?.includes ?? []),
|
|
28
|
+
excludes: toArray(raw.entry?.excludes ?? []),
|
|
29
|
+
priority: toArray(raw.entry?.priority ?? [])
|
|
30
|
+
},
|
|
20
31
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
console.log("? Loaded .prodex.json overrides");
|
|
26
|
-
} catch (err) {
|
|
27
|
-
console.warn("?? Failed to parse .prodex.json:", err.message);
|
|
32
|
+
imports: {
|
|
33
|
+
includes: toArray(raw.imports?.includes ?? []),
|
|
34
|
+
excludes: toArray(raw.imports?.excludes ?? []),
|
|
35
|
+
aliases: raw.imports?.aliases ?? {}
|
|
28
36
|
}
|
|
29
|
-
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
ensureDir(cfg.outDir);
|
|
40
|
+
|
|
41
|
+
// // === Validation summary ===
|
|
42
|
+
// console.log("🧩 Prodex Config Loaded\n");
|
|
43
|
+
// console.log(" • outDir Dir:", cfg.outDir);
|
|
44
|
+
// console.log(" • Entry Includes:", shortList(cfg.entry.includes));
|
|
45
|
+
// console.log(" • Entry Excludes:", shortList(cfg.entry.excludes));
|
|
46
|
+
// console.log(" • Import Includes:", shortList(cfg.imports.includes));
|
|
47
|
+
// console.log(" • Import Excludes:", shortList(cfg.imports.excludes));
|
|
48
|
+
// console.log(" • Aliases:", Object.keys(cfg.imports.aliases).length);
|
|
49
|
+
|
|
50
|
+
return cfg;
|
|
51
|
+
}
|
|
30
52
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Utility — ensures array normalization.
|
|
55
|
+
*/
|
|
56
|
+
function toArray(v) {
|
|
57
|
+
return Array.isArray(v) ? v : v ? [v] : [];
|
|
58
|
+
}
|
|
34
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Utility — ensure directory exists.
|
|
62
|
+
*/
|
|
63
|
+
function ensureDir(p) {
|
|
35
64
|
try {
|
|
36
|
-
fs.mkdirSync(
|
|
37
|
-
} catch
|
|
38
|
-
console.warn("
|
|
65
|
+
fs.mkdirSync(p, { recursive: true });
|
|
66
|
+
} catch {
|
|
67
|
+
console.warn("⚠️ Could not create outDir directory:", p);
|
|
39
68
|
}
|
|
69
|
+
}
|
|
40
70
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
aliasOverrides: userConfig.aliasOverrides || {},
|
|
49
|
-
limit: userConfig.limit || 200,
|
|
50
|
-
priorityFiles: userConfig.priorityFiles || PRIORITY_FILES
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// console.log("?? Active Config:");
|
|
54
|
-
// console.log(" • Output Directory:", merged.output);
|
|
55
|
-
// console.log(" • Scan Depth:", merged.scanDepth);
|
|
56
|
-
// console.log(" • Base Dirs:", merged.baseDirs.join(", "));
|
|
57
|
-
// if (userConfig.entryExcludes || userConfig.importExcludes)
|
|
58
|
-
// console.log(" • Custom Exclusions:", {
|
|
59
|
-
// entries: userConfig.entryExcludes?.length || 0,
|
|
60
|
-
// imports: userConfig.importExcludes?.length || 0
|
|
61
|
-
// });
|
|
71
|
+
/**
|
|
72
|
+
* Utility — shortens list for display.
|
|
73
|
+
*/
|
|
74
|
+
function shortList(list) {
|
|
75
|
+
if (!list.length) return "(none)";
|
|
76
|
+
return list.length > 3 ? list.slice(0, 3).join(", ") + "..." : list.join(", ");
|
|
77
|
+
}
|
|
62
78
|
|
|
63
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Glob matcher factory
|
|
81
|
+
* Creates helpers for downstream modules.
|
|
82
|
+
*/
|
|
83
|
+
export function makeGlobChecker(patterns) {
|
|
84
|
+
const safe = toArray(patterns);
|
|
85
|
+
if (!safe.length) return () => false;
|
|
86
|
+
return (input) => micromatch.isMatch(input.replaceAll("\\", "/"), safe);
|
|
64
87
|
}
|
|
@@ -1,45 +1,9 @@
|
|
|
1
|
-
import { resolveJsImports } from "../resolvers/js-resolver.js";
|
|
2
|
-
import { resolvePhpImports } from "../resolvers/php-resolver.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
1
|
export const ROOT = process.cwd();
|
|
6
|
-
|
|
7
2
|
export const CODE_EXTS = [".js", ".mjs", ".ts", ".tsx", ".d.ts", ".php"];
|
|
8
|
-
export const ENTRY_EXCLUDES = [
|
|
9
|
-
"resources/js/components/ui/",
|
|
10
|
-
"app/Enums/",
|
|
11
|
-
"app/DTOs/",
|
|
12
|
-
"app/Models/",
|
|
13
|
-
"app/Data/",
|
|
14
|
-
"resources/js/wayfinder/",
|
|
15
|
-
"resources/js/routes/",
|
|
16
|
-
"resources/js/actions/",
|
|
17
|
-
"resources/js/hooks/"
|
|
18
|
-
];
|
|
19
|
-
export const IMPORT_EXCLUDES = [
|
|
20
|
-
"node_modules",
|
|
21
|
-
"@shadcn/",
|
|
22
|
-
"@/components/ui/",
|
|
23
|
-
"@components/ui/",
|
|
24
|
-
"resources/js/components/ui/",
|
|
25
|
-
"resources/js/hooks/",
|
|
26
|
-
"resources/js/wayfinder/",
|
|
27
|
-
"resources/js/routes/",
|
|
28
|
-
"resources/js/actions/"
|
|
29
|
-
];
|
|
30
|
-
export const BASE_DIRS = ["src", "bin", "schema", "app", "routes", "resources/js"];
|
|
31
3
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"index.",
|
|
36
|
-
"main.",
|
|
37
|
-
"app."
|
|
38
|
-
]
|
|
39
|
-
/**
|
|
40
|
-
* Resolver map — links file extensions to their resolver functions.
|
|
41
|
-
* Extend this to support new formats (.vue, .jsx, etc.).
|
|
42
|
-
*/
|
|
4
|
+
import { resolveJsImports } from "../resolvers/js-resolver.js";
|
|
5
|
+
import { resolvePhpImports } from "../resolvers/php-resolver.js";
|
|
6
|
+
|
|
43
7
|
export const RESOLVERS = {
|
|
44
8
|
".php": resolvePhpImports,
|
|
45
9
|
".ts": resolveJsImports,
|
|
@@ -47,44 +11,3 @@ export const RESOLVERS = {
|
|
|
47
11
|
".d.ts": resolveJsImports,
|
|
48
12
|
".js": resolveJsImports
|
|
49
13
|
};
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Prompt definitions used by Inquirer in combine.js.
|
|
53
|
-
* These are constants to keep UI consistent across releases.
|
|
54
|
-
*/
|
|
55
|
-
export const PROMPTS = {
|
|
56
|
-
yesToAll: {
|
|
57
|
-
type: "confirm",
|
|
58
|
-
name: "yesToAll",
|
|
59
|
-
message: "Proceed automatically with default settings (Yes to all)?",
|
|
60
|
-
default: true
|
|
61
|
-
},
|
|
62
|
-
combine: [
|
|
63
|
-
{
|
|
64
|
-
type: "input",
|
|
65
|
-
name: "outputBase",
|
|
66
|
-
message: "Output base name (without extension):",
|
|
67
|
-
default: null, // will be set dynamically
|
|
68
|
-
filter: v => v.trim()
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
type: "number",
|
|
72
|
-
name: "limit",
|
|
73
|
-
message: "Limit number of merged files:",
|
|
74
|
-
default: 200, // will be overridden at runtime
|
|
75
|
-
validate: v => (!isNaN(v) && v > 0) || "Enter a valid positive number"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
type: "confirm",
|
|
79
|
-
name: "chain",
|
|
80
|
-
message: "Follow dependency chain?",
|
|
81
|
-
default: true
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
type: "confirm",
|
|
85
|
-
name: "proceed",
|
|
86
|
-
message: "Proceed with combine?",
|
|
87
|
-
default: true
|
|
88
|
-
}
|
|
89
|
-
]
|
|
90
|
-
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const DEFAULT_PRODEX_CONFIG = {
|
|
2
|
+
$schema: "https://raw.githubusercontent.com/emxhive/prodex/main/schema/prodex.schema.json",
|
|
3
|
+
outDir: "prodex",
|
|
4
|
+
scanDepth: 2,
|
|
5
|
+
limit: 200,
|
|
6
|
+
resolverDepth: 10,
|
|
7
|
+
|
|
8
|
+
entry: {
|
|
9
|
+
includes: ["app", "routes", "resources/js"],
|
|
10
|
+
excludes: [
|
|
11
|
+
"**/components/ui/**",
|
|
12
|
+
"**/DTOs/**",
|
|
13
|
+
"**/Enums/**"
|
|
14
|
+
],
|
|
15
|
+
priority: [
|
|
16
|
+
"**/routes/web.php",
|
|
17
|
+
"**/routes/api.php",
|
|
18
|
+
"**/*index.*",
|
|
19
|
+
"**/*main.*",
|
|
20
|
+
"**/app.*"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
imports: {
|
|
25
|
+
includes: ["**/*.d.ts", "**/*.interface.ts"],
|
|
26
|
+
excludes: [
|
|
27
|
+
"node_modules/**",
|
|
28
|
+
"@shadcn/**",
|
|
29
|
+
"**/components/ui/**"
|
|
30
|
+
],
|
|
31
|
+
aliases: {
|
|
32
|
+
"@hooks": "resources/js/hooks",
|
|
33
|
+
"@data": "resources/js/data"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// ================================================================
|
|
2
|
+
// 🧩 Prodex — Render Constants
|
|
3
|
+
// Defines shared constants for renderer outDir formats.
|
|
4
|
+
// ================================================================
|
|
5
|
+
|
|
6
|
+
export const LANG_MAP = {
|
|
7
|
+
".js": "js",
|
|
8
|
+
".mjs": "js",
|
|
9
|
+
".jsx": "jsx",
|
|
10
|
+
".ts": "ts",
|
|
11
|
+
".tsx": "tsx",
|
|
12
|
+
".php": "php",
|
|
13
|
+
".json": "json",
|
|
14
|
+
".d.ts": "ts"
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const TEXT_HEADERS = {
|
|
18
|
+
toc: "##==== Combined Scope ====",
|
|
19
|
+
path: p => `##==== path: ${p} ====`,
|
|
20
|
+
regionStart: p => `##region ${p}`,
|
|
21
|
+
regionEnd: "##endregion"
|
|
22
|
+
};
|