prodex 1.1.0 → 1.3.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/README.md +234 -140
- package/bin/prodex.js +1 -17
- package/dist/cli/cli-input.js +106 -0
- package/dist/cli/flags.js +42 -0
- package/dist/cli/init.js +21 -0
- package/dist/cli/picker.js +82 -0
- package/dist/cli/summary.js +26 -0
- package/dist/constants/config-loader.js +95 -0
- package/dist/constants/config.js +26 -0
- package/dist/constants/default-config.js +34 -0
- package/dist/constants/render-constants.js +28 -0
- package/dist/core/combine.js +38 -0
- package/dist/core/dependency.js +55 -0
- package/dist/core/file-utils.js +41 -0
- package/dist/core/helpers.js +81 -0
- package/dist/core/output.js +48 -0
- package/dist/core/parsers/extract-imports.js +51 -0
- package/dist/core/renderers.js +42 -0
- package/dist/index.js +26 -0
- package/dist/lib/logger.js +14 -0
- package/dist/lib/polyfills.js +27 -0
- package/dist/lib/prompt.js +34 -0
- package/dist/lib/questions.js +28 -0
- package/dist/lib/utils.js +51 -0
- package/dist/resolvers/js/alias-loader.js +52 -0
- package/dist/resolvers/js/js-resolver.js +153 -0
- package/dist/resolvers/php/bindings.js +32 -0
- package/dist/resolvers/php/patterns.js +17 -0
- package/dist/resolvers/php/php-resolver.js +88 -0
- package/dist/resolvers/php/psr4.js +26 -0
- package/dist/resolvers/shared/excludes.js +11 -0
- package/dist/resolvers/shared/file-cache.js +29 -0
- package/dist/resolvers/shared/stats.js +17 -0
- package/dist/types/cli.types.js +12 -0
- package/dist/types/config.types.js +2 -0
- package/dist/types/core.types.js +2 -0
- package/dist/types/index.js +21 -0
- package/dist/types/resolver.types.js +2 -0
- package/dist/types/utils.types.js +2 -0
- package/package.json +16 -12
- package/dist/LICENSE +0 -21
- package/dist/README.md +0 -140
- package/dist/bin/prodex.js +0 -18
- package/dist/package.json +0 -45
- package/dist/src/cli/init.js +0 -18
- package/dist/src/cli/picker.js +0 -59
- package/dist/src/cli/summary.js +0 -6
- package/dist/src/constants/config-loader.js +0 -87
- package/dist/src/constants/config.js +0 -13
- package/dist/src/constants/default-config.js +0 -36
- package/dist/src/constants/render-constants.js +0 -22
- package/dist/src/core/alias-loader.js +0 -8
- package/dist/src/core/combine.js +0 -145
- package/dist/src/core/file-utils.js +0 -45
- package/dist/src/core/helpers.js +0 -77
- package/dist/src/core/renderers.js +0 -58
- package/dist/src/index.js +0 -15
- package/dist/src/resolvers/js-resolver.js +0 -180
- package/dist/src/resolvers/php-bindings.js +0 -31
- package/dist/src/resolvers/php-resolver.js +0 -155
package/dist/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Zeki
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/dist/README.md
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# 🧩 Prodex — Unified Project Indexer & Dependency Extractor
|
|
2
|
-
|
|
3
|
-
> **Prodex** *(short for “Project Index”)* — a cross-language dependency combiner for modern full-stack applications.
|
|
4
|
-
> Traverses **Laravel + React + TypeScript** projects to generate a single, organized view of your project’s true dependency scope.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## 🧠 Recent Fixes & Updates — v1.0.8
|
|
9
|
-
- ⭐ **Priority Files Support** — priority files will now appear **first** on the entry selection list.
|
|
10
|
-
|
|
11
|
-
- 🪟 **Windows path resolution fixed** — now uses proper `file://` URLs for full ESM compatibility.
|
|
12
|
-
- 🧾 **Improved output naming** — automatic, context-aware filenames (e.g. `prodex-[entries]-combined.txt`).
|
|
13
|
-
- ⚙️ **“Yes to all” confirmation added** — skip repetitive prompts during CLI runs.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## 📦 Installation
|
|
20
|
-
|
|
21
|
-
### Global install (recommended)
|
|
22
|
-
```bash
|
|
23
|
-
npm install -g prodex
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
## 🚀 Features
|
|
28
|
-
|
|
29
|
-
| Feature | Description |
|
|
30
|
-
|----------|-------------|
|
|
31
|
-
| ⚙️ **Cross-language resolver** | Parses JS/TS (`import`, `export`) and PHP (`use`, `require`, `include`) dependency trees. |
|
|
32
|
-
| 🧭 **Alias detection** | Reads `tsconfig.json` and `vite.config.*` for alias paths (`@/components/...`). |
|
|
33
|
-
| 🧩 **Laravel-aware** | Maps PSR-4 namespaces and detects providers under `app/Providers`. |
|
|
34
|
-
| 🔄 **Recursive chain following** | Resolves dependency graphs up to a configurable depth and file limit. |
|
|
35
|
-
| 🪶 **Clean unified output** | Merges all resolved files into a single `.txt` file with region markers for readability. |
|
|
36
|
-
| 🧠 **Static & safe** | Fully static parsing — no runtime execution or file modification. |
|
|
37
|
-
| 💬 **Interactive CLI** | Select files, confirm settings, or use “Yes to all” for streamlined automation. |
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## ⚙️ Configuration
|
|
42
|
-
|
|
43
|
-
Optional `.prodex.json` (in project root):
|
|
44
|
-
|
|
45
|
-
```json
|
|
46
|
-
{
|
|
47
|
-
"$schema": "https://raw.githubusercontent.com/emxhive/prodex/main/schema/prodex.schema.json",
|
|
48
|
-
"output": "prodex",
|
|
49
|
-
"scanDepth": 2,
|
|
50
|
-
"limit": 200,
|
|
51
|
-
"baseDirs": ["app", "routes", "resources/js"],
|
|
52
|
-
"aliasOverrides": {
|
|
53
|
-
"@hooks": "resources/js/hooks",
|
|
54
|
-
"@data": "resources/js/data"
|
|
55
|
-
},
|
|
56
|
-
"entryExcludes": [
|
|
57
|
-
"resources/js/components/ui/",
|
|
58
|
-
"app/DTOs/"
|
|
59
|
-
],
|
|
60
|
-
"importExcludes": [
|
|
61
|
-
"node_modules",
|
|
62
|
-
"@shadcn/"
|
|
63
|
-
],
|
|
64
|
-
"priorityFiles": [
|
|
65
|
-
"routes/web.php",
|
|
66
|
-
"routes/api.php",
|
|
67
|
-
"index.",
|
|
68
|
-
"main.",
|
|
69
|
-
"app."
|
|
70
|
-
]
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Files are matched using `.includes()` (case-insensitive), so `"index."` will match `src/index.js`, `app/index.tsx`, etc.
|
|
83
|
-
Popular entries appear at the top of the picker.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## 🧱 Example: Laravel + React
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
prodex
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
```
|
|
98
|
-
🧩 Following dependency chain...
|
|
99
|
-
✅ prodex-app-routes-combined.txt written (24 file(s)).
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Included files:
|
|
103
|
-
```
|
|
104
|
-
resources/js/pages/accounts.tsx
|
|
105
|
-
app/Http/Controllers/Shots/AccountsController.php
|
|
106
|
-
app/Repositories/Shots/FireflyApiRepository.php
|
|
107
|
-
app/Enums/Shots/Granularity.php
|
|
108
|
-
app/Support/Shots/CacheKeys.php
|
|
109
|
-
...
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## 🧠 Ideal Use Cases
|
|
115
|
-
|
|
116
|
-
- 📦 Generate single-file **project snapshots**
|
|
117
|
-
- 🤖 Provide structured context for **AI assistants**
|
|
118
|
-
- 🧩 Perform **dependency audits** or code reviews
|
|
119
|
-
- 📄 Simplify documentation and onboarding
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
## 🔮 Upcoming Features
|
|
124
|
-
|
|
125
|
-
- 📝 **Markdown export** (`.md`) with automatic code fences
|
|
126
|
-
- 📦 **Configurable output formats** (txt / md)
|
|
127
|
-
- ⚡ **Alias auto-discovery for Laravel Mix and Next.js**
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## 🧾 License
|
|
132
|
-
|
|
133
|
-
**MIT © 2025 [emxhive](https://github.com/emxhive)**
|
|
134
|
-
Issues and contributions welcome:
|
|
135
|
-
👉 [github.com/emxhive/prodex/issues](https://github.com/emxhive/prodex/issues)
|
|
136
|
-
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
**Prodex** — *Codebase, decoded*
|
|
140
|
-
|
package/dist/bin/prodex.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { pathToFileURL, fileURLToPath } from "url";
|
|
5
|
-
|
|
6
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
-
const __dirname = path.dirname(__filename);
|
|
8
|
-
|
|
9
|
-
const devPath = path.resolve(__dirname, "../src/index.js");
|
|
10
|
-
const distPath = path.resolve(__dirname, "../dist/src/index.js");
|
|
11
|
-
|
|
12
|
-
// prefer dist in published package
|
|
13
|
-
const entry = fs.existsSync(distPath) ? distPath : devPath;
|
|
14
|
-
|
|
15
|
-
// convert to file:// URL for cross-platform ESM loading
|
|
16
|
-
const entryUrl = pathToFileURL(entry).href;
|
|
17
|
-
|
|
18
|
-
import(entryUrl).then(({ default: startProdex }) => startProdex());
|
package/dist/package.json
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "prodex",
|
|
3
|
-
"version": "1.1.0",
|
|
4
|
-
"description": "Unified Project Indexer & Dependency Extractor for Laravel + React + Node stacks.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"prodex": "./bin/prodex.js"
|
|
8
|
-
},
|
|
9
|
-
"main": "./dist/core/combine.js",
|
|
10
|
-
"exports": {
|
|
11
|
-
".": "./dist/core/combine.js"
|
|
12
|
-
},
|
|
13
|
-
"files": [
|
|
14
|
-
"dist/",
|
|
15
|
-
"bin/",
|
|
16
|
-
"README.md",
|
|
17
|
-
"LICENSE"
|
|
18
|
-
],
|
|
19
|
-
"keywords": [
|
|
20
|
-
"laravel",
|
|
21
|
-
"react",
|
|
22
|
-
"typescript",
|
|
23
|
-
"dependency",
|
|
24
|
-
"analyzer",
|
|
25
|
-
"cli",
|
|
26
|
-
"node",
|
|
27
|
-
"indexer"
|
|
28
|
-
],
|
|
29
|
-
"scripts": {
|
|
30
|
-
"clean": "rm -rf dist",
|
|
31
|
-
"build": "npm run clean && node -e \"require('fs').mkdirSync('dist',{recursive:true})\" && cp -r src bin package.json README.md LICENSE dist/",
|
|
32
|
-
"prepare": "npm run build"
|
|
33
|
-
},
|
|
34
|
-
"author": "emxhive",
|
|
35
|
-
"license": "MIT",
|
|
36
|
-
"devDependencies": {
|
|
37
|
-
"@types/node": "^24.9.1",
|
|
38
|
-
"tsup": "^8.5.0",
|
|
39
|
-
"typescript": "^5.9.3"
|
|
40
|
-
},
|
|
41
|
-
"dependencies": {
|
|
42
|
-
"inquirer": "^12.10.0",
|
|
43
|
-
"micromatch": "^4.0.8"
|
|
44
|
-
}
|
|
45
|
-
}
|
package/dist/src/cli/init.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { DEFAULT_PRODEX_CONFIG } from "../constants/default-config.js";
|
|
4
|
-
|
|
5
|
-
export async function initProdex() {
|
|
6
|
-
console.log("🪄 Prodex Init — Configuration Wizard (v2)\n");
|
|
7
|
-
|
|
8
|
-
const dest = path.join(process.cwd(), "prodex.json");
|
|
9
|
-
|
|
10
|
-
if (fs.existsSync(dest)) {
|
|
11
|
-
console.log("❌ prodex.json already exists. Delete or modify it manually.\n");
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
fs.writeFileSync(dest, JSON.stringify(DEFAULT_PRODEX_CONFIG, null, 2) + "\n", "utf8");
|
|
16
|
-
console.log(`✅ Created ${dest}`);
|
|
17
|
-
console.log("💡 Globs supported everywhere (includes, excludes, priority).");
|
|
18
|
-
}
|
package/dist/src/cli/picker.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import inquirer from "inquirer";
|
|
4
|
-
import { ROOT } from "../constants/config.js";
|
|
5
|
-
import { walk, rel, sortWithPriority } from "../core/helpers.js";
|
|
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
|
-
*/
|
|
13
|
-
export async function pickEntries(baseDirs, depth = 2, cfg = {}) {
|
|
14
|
-
let selected = [];
|
|
15
|
-
|
|
16
|
-
while (true) {
|
|
17
|
-
const files = [];
|
|
18
|
-
|
|
19
|
-
// Use an effective cfg that reflects the current depth for this iteration
|
|
20
|
-
const effectiveCfg = { ...cfg, scanDepth: depth };
|
|
21
|
-
|
|
22
|
-
for (const base of baseDirs) {
|
|
23
|
-
const full = path.join(ROOT, base);
|
|
24
|
-
if (!fs.existsSync(full)) continue;
|
|
25
|
-
for (const f of walk(full, effectiveCfg, 0)) files.push(f);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Priority-aware ordering
|
|
29
|
-
const sorted = sortWithPriority(files, cfg.entry?.priority || []);
|
|
30
|
-
|
|
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" });
|
|
35
|
-
|
|
36
|
-
const { picks } = await inquirer.prompt([
|
|
37
|
-
{
|
|
38
|
-
type: "checkbox",
|
|
39
|
-
name: "picks",
|
|
40
|
-
message: `Select entry files (depth ${depth})`,
|
|
41
|
-
choices,
|
|
42
|
-
loop: false,
|
|
43
|
-
pageSize: 20,
|
|
44
|
-
default: selected
|
|
45
|
-
}
|
|
46
|
-
]);
|
|
47
|
-
|
|
48
|
-
if (picks.includes("__loadmore")) {
|
|
49
|
-
depth++;
|
|
50
|
-
selected = picks.filter(p => p !== "__loadmore");
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
selected = picks.filter(p => p !== "__loadmore");
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return [...new Set(selected)];
|
|
59
|
-
}
|
package/dist/src/cli/summary.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import micromatch from "micromatch";
|
|
4
|
-
import { DEFAULT_PRODEX_CONFIG } from "./default-config.js";
|
|
5
|
-
|
|
6
|
-
export function loadProdexConfig() {
|
|
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
|
-
},
|
|
31
|
-
|
|
32
|
-
imports: {
|
|
33
|
-
includes: toArray(raw.imports?.includes ?? []),
|
|
34
|
-
excludes: toArray(raw.imports?.excludes ?? []),
|
|
35
|
-
aliases: raw.imports?.aliases ?? {}
|
|
36
|
-
}
|
|
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
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Utility — ensures array normalization.
|
|
55
|
-
*/
|
|
56
|
-
function toArray(v) {
|
|
57
|
-
return Array.isArray(v) ? v : v ? [v] : [];
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Utility — ensure directory exists.
|
|
62
|
-
*/
|
|
63
|
-
function ensureDir(p) {
|
|
64
|
-
try {
|
|
65
|
-
fs.mkdirSync(p, { recursive: true });
|
|
66
|
-
} catch {
|
|
67
|
-
console.warn("⚠️ Could not create outDir directory:", p);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
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
|
-
}
|
|
78
|
-
|
|
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);
|
|
87
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export const ROOT = process.cwd();
|
|
2
|
-
export const CODE_EXTS = [".js", ".mjs", ".ts", ".tsx", ".d.ts", ".php"];
|
|
3
|
-
|
|
4
|
-
import { resolveJsImports } from "../resolvers/js-resolver.js";
|
|
5
|
-
import { resolvePhpImports } from "../resolvers/php-resolver.js";
|
|
6
|
-
|
|
7
|
-
export const RESOLVERS = {
|
|
8
|
-
".php": resolvePhpImports,
|
|
9
|
-
".ts": resolveJsImports,
|
|
10
|
-
".tsx": resolveJsImports,
|
|
11
|
-
".d.ts": resolveJsImports,
|
|
12
|
-
".js": resolveJsImports
|
|
13
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
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
|
-
};
|
package/dist/src/core/combine.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import inquirer from "inquirer";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import micromatch from "micromatch";
|
|
5
|
-
import { pickEntries } from "../cli/picker.js";
|
|
6
|
-
import { showSummary } from "../cli/summary.js";
|
|
7
|
-
import { loadProdexConfig } from "../constants/config-loader.js";
|
|
8
|
-
import { CODE_EXTS, RESOLVERS, ROOT } from "../constants/config.js";
|
|
9
|
-
import { generateOutputName, resolveOutDirPath, safeMicromatchScan } from "./file-utils.js";
|
|
10
|
-
import { renderMd, renderTxt, tocMd, tocTxt } from "./renderers.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export async function runCombine(opts = {}) {
|
|
14
|
-
const cliLimitFlag = process.argv.find(arg => arg.startsWith("--limit="));
|
|
15
|
-
const customLimit = cliLimitFlag ? parseInt(cliLimitFlag.split("=")[1], 10) : null;
|
|
16
|
-
const cliTxtFlag = process.argv.includes("--txt");
|
|
17
|
-
|
|
18
|
-
const cfg = loadProdexConfig();
|
|
19
|
-
const { scanDepth } = cfg;
|
|
20
|
-
|
|
21
|
-
let entries = opts.entries;
|
|
22
|
-
|
|
23
|
-
// 🧩 Headless mode: expand globs manually
|
|
24
|
-
if (entries && entries.length) {
|
|
25
|
-
const all = [];
|
|
26
|
-
for (const pattern of entries) {
|
|
27
|
-
const abs = path.resolve(process.cwd(), pattern);
|
|
28
|
-
if (fs.existsSync(abs) && fs.statSync(abs).isFile()) {
|
|
29
|
-
// direct file path (no glob)
|
|
30
|
-
all.push(abs);
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// glob pattern
|
|
35
|
-
const result = safeMicromatchScan(pattern, {
|
|
36
|
-
cwd: process.cwd(),
|
|
37
|
-
absolute: true,
|
|
38
|
-
});
|
|
39
|
-
if (result?.files?.length) all.push(...result.files);
|
|
40
|
-
}
|
|
41
|
-
entries = [...new Set(all)];
|
|
42
|
-
} else {
|
|
43
|
-
// fallback to interactive picker
|
|
44
|
-
entries = await pickEntries(cfg.entry.includes, scanDepth, cfg);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (!entries.length) {
|
|
49
|
-
console.log("❌ No entries selected.");
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
console.log("\n📋 You selected:");
|
|
54
|
-
for (const e of entries) console.log(" -", e.replace(ROOT + "/", ""));
|
|
55
|
-
|
|
56
|
-
// 🧩 Auto name suggestion
|
|
57
|
-
const autoName = generateOutputName(entries);
|
|
58
|
-
const outDir = cfg.outDir || path.join(ROOT, "prodex");
|
|
59
|
-
const limit = customLimit || cfg.limit || 200;
|
|
60
|
-
const chain = true;
|
|
61
|
-
|
|
62
|
-
// Skip prompt if entries were passed directly
|
|
63
|
-
let outputBase = autoName;
|
|
64
|
-
if (!opts.entries?.length) {
|
|
65
|
-
const { outputBase: answer } = await inquirer.prompt([
|
|
66
|
-
{
|
|
67
|
-
type: "input",
|
|
68
|
-
name: "outputBase",
|
|
69
|
-
message: "Output file name (without extension):",
|
|
70
|
-
default: autoName,
|
|
71
|
-
filter: v => (v.trim() || autoName).replace(/[<>:"/\\|?*]+/g, "_"),
|
|
72
|
-
},
|
|
73
|
-
]);
|
|
74
|
-
outputBase = answer;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Ensure output directory exists
|
|
78
|
-
try {
|
|
79
|
-
fs.mkdirSync(outDir, { recursive: true });
|
|
80
|
-
} catch {
|
|
81
|
-
console.warn("⚠️ Could not create outDir directory:", outDir);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const outputPath = resolveOutDirPath(outDir, outputBase, cliTxtFlag);
|
|
85
|
-
|
|
86
|
-
showSummary({ outDir, fileName: path.basename(outputPath), entries });
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const result = chain ? await followChain(entries, cfg, limit) : { files: entries, stats: { totalImports: 0, totalResolved: 0 } };
|
|
90
|
-
const sorted = [...result.files].sort((a, b) => a.localeCompare(b));
|
|
91
|
-
|
|
92
|
-
const content = cliTxtFlag
|
|
93
|
-
? [tocTxt(sorted), ...sorted.map(renderTxt)].join("")
|
|
94
|
-
: [tocMd(sorted), ...sorted.map((f, i) => renderMd(f, i === 0))].join("\n");
|
|
95
|
-
|
|
96
|
-
fs.writeFileSync(outputPath, content, "utf8");
|
|
97
|
-
console.log(
|
|
98
|
-
`\n✅ ${outputPath}`
|
|
99
|
-
);
|
|
100
|
-
// 🧩 Print resolver summary (clean version)
|
|
101
|
-
console.log(`\n🧩 Summary:
|
|
102
|
-
• Unique imports expected: ${result.stats.expected.size}
|
|
103
|
-
• Unique imports resolved: ${result.stats.resolved.size}
|
|
104
|
-
`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async function followChain(entryFiles, cfg, limit = 200) {
|
|
108
|
-
console.log("🧩 Following dependency chain...");
|
|
109
|
-
const visited = new Set();
|
|
110
|
-
const all = [];
|
|
111
|
-
const expected = new Set();
|
|
112
|
-
const resolved = new Set();
|
|
113
|
-
const resolverDepth = cfg.resolverDepth ?? 10;
|
|
114
|
-
|
|
115
|
-
for (const f of entryFiles) {
|
|
116
|
-
if (visited.has(f)) continue;
|
|
117
|
-
all.push(f);
|
|
118
|
-
|
|
119
|
-
const ext = path.extname(f);
|
|
120
|
-
if (!CODE_EXTS.includes(ext)) continue;
|
|
121
|
-
|
|
122
|
-
const resolver = RESOLVERS[ext];
|
|
123
|
-
if (resolver) {
|
|
124
|
-
const result = await resolver(f, cfg, visited, 0, resolverDepth);
|
|
125
|
-
const { files, stats } = result;
|
|
126
|
-
all.push(...files);
|
|
127
|
-
stats?.expected?.forEach(x => expected.add(x));
|
|
128
|
-
stats?.resolved?.forEach(x => resolved.add(x));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (limit && all.length >= limit) {
|
|
132
|
-
console.log("⚠️ Limit reached:", limit);
|
|
133
|
-
break;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
files: [...new Set(all)],
|
|
139
|
-
stats: {
|
|
140
|
-
expected,
|
|
141
|
-
resolved
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import micromatch from "micromatch";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Safe micromatch.scan wrapper (compatible with micromatch v4 & v5)
|
|
7
|
-
*/
|
|
8
|
-
export function safeMicromatchScan(pattern, opts = {}) {
|
|
9
|
-
const scanFn = micromatch.scan;
|
|
10
|
-
if (typeof scanFn === "function") return scanFn(pattern, opts);
|
|
11
|
-
|
|
12
|
-
// --- fallback for micromatch v4 ---
|
|
13
|
-
const cwd = opts.cwd || process.cwd();
|
|
14
|
-
const abs = !!opts.absolute;
|
|
15
|
-
const allFiles = listAllFiles(cwd);
|
|
16
|
-
const matched = micromatch.match(allFiles, pattern, { dot: true });
|
|
17
|
-
return { files: abs ? matched.map(f => path.resolve(cwd, f)) : matched };
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Recursively list all files in a directory.
|
|
22
|
-
* Used only for fallback (so performance isn’t critical).
|
|
23
|
-
*/
|
|
24
|
-
function listAllFiles(dir) {
|
|
25
|
-
const out = [];
|
|
26
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
27
|
-
const full = path.join(dir, entry.name);
|
|
28
|
-
if (entry.isDirectory()) out.push(...listAllFiles(full));
|
|
29
|
-
else out.push(full);
|
|
30
|
-
}
|
|
31
|
-
return out;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function generateOutputName(entries) {
|
|
35
|
-
const names = entries.map(f => path.basename(f, path.extname(f)));
|
|
36
|
-
if (names.length === 1) return names[0];
|
|
37
|
-
if (names.length === 2) return `${names[0]}-${names[1]}`;
|
|
38
|
-
if (names.length > 2) return `${names[0]}-and-${names.length - 1}more`;
|
|
39
|
-
return "unknown";
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function resolveOutDirPath(outDir, base, asTxt = false) {
|
|
43
|
-
const ext = asTxt ? "txt" : "md";
|
|
44
|
-
return path.join(outDir, `${base}-combined.${ext}`);
|
|
45
|
-
}
|