prodex 1.1.0 → 1.2.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.
Files changed (57) hide show
  1. package/README.md +174 -86
  2. package/bin/prodex.js +1 -17
  3. package/dist/cli/cli-input.js +86 -0
  4. package/dist/cli/flags.js +42 -0
  5. package/dist/cli/init.js +21 -0
  6. package/dist/cli/picker.js +82 -0
  7. package/dist/cli/summary.js +14 -0
  8. package/dist/constants/config-loader.js +90 -0
  9. package/dist/constants/config.js +17 -0
  10. package/dist/constants/default-config.js +48 -0
  11. package/dist/constants/render-constants.js +23 -0
  12. package/dist/core/combine.js +74 -0
  13. package/dist/core/dependency.js +51 -0
  14. package/dist/core/file-utils.js +44 -0
  15. package/dist/core/helpers.js +81 -0
  16. package/dist/core/parsers/extract-imports.js +51 -0
  17. package/dist/core/renderers.js +42 -0
  18. package/dist/index.js +29 -0
  19. package/dist/lib/logger.js +14 -0
  20. package/dist/lib/polyfills.js +12 -0
  21. package/dist/lib/utils.js +15 -0
  22. package/dist/resolvers/js/alias-loader.js +52 -0
  23. package/dist/resolvers/js/js-resolver.js +153 -0
  24. package/dist/resolvers/php/bindings.js +32 -0
  25. package/dist/resolvers/php/patterns.js +17 -0
  26. package/dist/resolvers/php/php-resolver.js +88 -0
  27. package/dist/resolvers/php/psr4.js +26 -0
  28. package/dist/resolvers/shared/excludes.js +11 -0
  29. package/dist/resolvers/shared/file-cache.js +29 -0
  30. package/dist/resolvers/shared/stats.js +17 -0
  31. package/dist/types/cli.types.js +12 -0
  32. package/dist/types/config.types.js +2 -0
  33. package/dist/types/core.types.js +2 -0
  34. package/dist/types/index.js +21 -0
  35. package/dist/types/resolver.types.js +2 -0
  36. package/dist/types/utils.types.js +2 -0
  37. package/package.json +16 -12
  38. package/dist/LICENSE +0 -21
  39. package/dist/README.md +0 -140
  40. package/dist/bin/prodex.js +0 -18
  41. package/dist/package.json +0 -45
  42. package/dist/src/cli/init.js +0 -18
  43. package/dist/src/cli/picker.js +0 -59
  44. package/dist/src/cli/summary.js +0 -6
  45. package/dist/src/constants/config-loader.js +0 -87
  46. package/dist/src/constants/config.js +0 -13
  47. package/dist/src/constants/default-config.js +0 -36
  48. package/dist/src/constants/render-constants.js +0 -22
  49. package/dist/src/core/alias-loader.js +0 -8
  50. package/dist/src/core/combine.js +0 -145
  51. package/dist/src/core/file-utils.js +0 -45
  52. package/dist/src/core/helpers.js +0 -77
  53. package/dist/src/core/renderers.js +0 -58
  54. package/dist/src/index.js +0 -15
  55. package/dist/src/resolvers/js-resolver.js +0 -180
  56. package/dist/src/resolvers/php-bindings.js +0 -31
  57. package/dist/src/resolvers/php-resolver.js +0 -155
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
- }
@@ -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
- }
@@ -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
- }
@@ -1,6 +0,0 @@
1
- export function showSummary({ outDir, fileName, entries }) {
2
- console.log("\n🧩 Active Run:");
3
- console.log(" • Output Directory:", outDir);
4
- console.log(" • File Name:", fileName);
5
- console.log(" • Entries:", entries.length);
6
- }
@@ -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
- };
@@ -1,8 +0,0 @@
1
- export function loadJsAliases() {
2
- // will later handle vite + tsconfig
3
- return {};
4
- }
5
- export function loadComposerAliases() {
6
- // will later handle composer.json PSR-4
7
- return {};
8
- }
@@ -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
- }
@@ -1,77 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import micromatch from "micromatch";
4
-
5
- /**
6
- * Get a root-relative version of a path.
7
- */
8
- export function rel(p, root = process.cwd()) {
9
- return path.relative(root, p).replaceAll("\\", "/");
10
- }
11
-
12
- /**
13
- * Safe text read.
14
- */
15
- export function read(p) {
16
- try {
17
- return fs.readFileSync(p, "utf8");
18
- } catch {
19
- return "";
20
- }
21
- }
22
-
23
- /**
24
- * Check if a path/file matches any of the provided glob patterns.
25
- */
26
- export function isExcluded(p, patterns, root = process.cwd()) {
27
- if (!patterns?.length) return false;
28
- const relPath = rel(p, root);
29
- return micromatch.isMatch(relPath, patterns);
30
- }
31
-
32
- /**
33
- * Recursive walker that respects glob excludes.
34
- * Returns all files under the given directory tree.
35
- */
36
- export function* walk(dir, cfg, depth = 0) {
37
- const { scanDepth, entry } = cfg;
38
- const root = process.cwd();
39
- if (depth > scanDepth) return;
40
-
41
- const entries = fs.readdirSync(dir, { withFileTypes: true });
42
- for (const e of entries) {
43
- const full = path.join(dir, e.name);
44
-
45
- if (e.isDirectory()) {
46
- // Skip excluded directories entirely
47
- const relPath = rel(full, root);
48
- if (isExcluded(relPath, entry.excludes)) continue;
49
- yield* walk(full, cfg, depth + 1);
50
- continue;
51
- }
52
-
53
- if (e.isFile()) {
54
- const relPath = rel(full, root);
55
- if (isExcluded(relPath, entry.excludes)) continue;
56
- yield full;
57
- }
58
- }
59
- }
60
-
61
- /**
62
- * Sorts files so that priority items appear first.
63
- */
64
- export function sortWithPriority(files, priorityList = []) {
65
- if (!priorityList.length) return files;
66
- const prioritized = [];
67
- const normal = [];
68
-
69
- for (const f of files) {
70
- const normalized = f.replaceAll("\\", "/").toLowerCase();
71
- if (priorityList.some(p => micromatch.isMatch(normalized, p.toLowerCase())))
72
- prioritized.push(f);
73
- else normal.push(f);
74
- }
75
-
76
- return [...new Set([...prioritized, ...normal])];
77
- }
@@ -1,58 +0,0 @@
1
- import path from "path";
2
- import { read, rel } from "./helpers.js";
3
- import { LANG_MAP } from "../constants/render-constants.js";
4
-
5
- /**
6
- * Generate Markdown Table of Contents
7
- * Sorted alphabetically for deterministic structure.
8
- */
9
- export function tocMd(files) {
10
- const sorted = [...files].sort((a, b) => a.localeCompare(b));
11
- const items = sorted.map(f => "- " + rel(f)).join("\n");
12
- return `# Included Source Files\n\n${items}\n\n---\n`;
13
- }
14
-
15
- /**
16
- * Render a single file section in Markdown format.
17
- * The first file skips the leading separator to avoid duplicates.
18
- */
19
- export function renderMd(p, isFirst = false) {
20
- const rp = rel(p);
21
- const ext = path.extname(p).toLowerCase();
22
- const lang = LANG_MAP[ext] || "txt";
23
- const code = read(p).trimEnd();
24
-
25
- return [
26
- isFirst ? "" : "---", // only add separator *after* the first file
27
- `\`File: ${rp}\``,
28
- "",
29
- "```" + lang,
30
- code,
31
- "```",
32
- ""
33
- ]
34
- .filter(Boolean)
35
- .join("\n");
36
- }
37
-
38
- /**
39
- * TXT version (unchanged)
40
- */
41
- export function tocTxt(files) {
42
- const sorted = [...files].sort((a, b) => a.localeCompare(b));
43
- return (
44
- ["##==== Combined Scope ====", ...sorted.map(f => "## - " + rel(f))].join("\n") + "\n\n"
45
- );
46
- }
47
-
48
- export function renderTxt(p) {
49
- const relPath = rel(p);
50
- const code = read(p);
51
- return [
52
- "##==== path: " + relPath + " ====",
53
- "##region " + relPath,
54
- code,
55
- "##endregion",
56
- ""
57
- ].join("\n");
58
- }
package/dist/src/index.js DELETED
@@ -1,15 +0,0 @@
1
- import { runCombine } from "./core/combine.js";
2
- import { initProdex } from "./cli/init.js";
3
-
4
- export default async function startProdex() {
5
- const args = process.argv.slice(2);
6
- if (args.includes("init")) return await initProdex();
7
-
8
- const entryArgs = args.filter(a => !a.startsWith("--"));
9
- const hasEntries = entryArgs.length > 0;
10
-
11
- console.clear();
12
- console.log("🧩 Prodex — Project Dependency Extractor\n");
13
-
14
- await runCombine({ entries: hasEntries ? entryArgs : null });
15
- }