prodex 1.2.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 -228
- package/dist/cli/cli-input.js +55 -35
- package/dist/cli/picker.js +37 -37
- package/dist/cli/summary.js +19 -7
- package/dist/constants/config-loader.js +10 -5
- package/dist/constants/config.js +12 -3
- package/dist/constants/default-config.js +3 -17
- package/dist/constants/render-constants.js +11 -6
- package/dist/core/combine.js +22 -58
- package/dist/core/dependency.js +7 -3
- package/dist/core/file-utils.js +10 -13
- package/dist/core/output.js +48 -0
- package/dist/index.js +8 -11
- package/dist/lib/logger.js +1 -1
- package/dist/lib/polyfills.js +15 -0
- package/dist/lib/prompt.js +34 -0
- package/dist/lib/questions.js +28 -0
- package/dist/lib/utils.js +37 -1
- package/package.json +1 -1
package/dist/cli/picker.js
CHANGED
|
@@ -7,76 +7,76 @@ exports.pickEntries = pickEntries;
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
-
const config_1 = require("../constants/config");
|
|
11
10
|
const helpers_1 = require("../core/helpers");
|
|
12
11
|
const file_utils_1 = require("../core/file-utils");
|
|
13
12
|
const utils_1 = require("../lib/utils");
|
|
14
13
|
const logger_1 = require("../lib/logger");
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
const prompt_1 = require("../lib/prompt");
|
|
15
|
+
const questions_1 = require("../lib/questions");
|
|
16
|
+
/**
|
|
17
|
+
* Interactive entry picker for Prodex.
|
|
18
|
+
* Handles depth-based scanning, caching, and priority ordering.
|
|
19
|
+
*/
|
|
20
|
+
async function pickEntries(cfg) {
|
|
21
|
+
const { root, entry: { files, ui: { roots = [], priority = [], scanDepth }, }, } = cfg;
|
|
22
|
+
let depth = scanDepth;
|
|
23
|
+
const entryPatterns = files || [];
|
|
24
|
+
const priorities = [...entryPatterns, ...priority];
|
|
25
|
+
// 1️⃣ Resolve pre-defined entry patterns
|
|
26
|
+
const resolvedEntries = (await (0, file_utils_1.globScan)(entryPatterns, { cwd: root })).files;
|
|
21
27
|
let selected = [...resolvedEntries];
|
|
22
|
-
// cache: depth
|
|
28
|
+
// cache: depth → files[]
|
|
23
29
|
const scanCache = new Map();
|
|
24
30
|
for (;;) {
|
|
25
|
-
const files = await getFilesAtDepth(
|
|
26
|
-
baseDirs,
|
|
27
|
-
depth,
|
|
28
|
-
cfg,
|
|
29
|
-
scanCache,
|
|
30
|
-
verbose,
|
|
31
|
-
});
|
|
31
|
+
const files = await getFilesAtDepth(depth, cfg, scanCache);
|
|
32
32
|
// Merge resolved entries with current scan results
|
|
33
33
|
const combined = (0, utils_1.unique)([...resolvedEntries, ...files]);
|
|
34
|
-
// Priority-aware ordering: entries first, then other priorities
|
|
35
34
|
const sorted = (0, helpers_1.orderByPriority)(combined, priorities);
|
|
36
35
|
// Build UI selection list
|
|
37
|
-
const choices = sorted.map(f => ({
|
|
38
|
-
name:
|
|
36
|
+
const choices = sorted.map((f) => ({
|
|
37
|
+
name: (0, helpers_1.rel)(f, root),
|
|
39
38
|
value: f,
|
|
40
39
|
checked: selected.includes(f),
|
|
41
40
|
}));
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
pageSize: 20,
|
|
52
|
-
}
|
|
53
|
-
]);
|
|
41
|
+
if (depth < scanDepth + 5) {
|
|
42
|
+
choices.push(new inquirer_1.default.Separator());
|
|
43
|
+
choices.push({ name: "🔽 Load more (go deeper)", value: "__loadmore" });
|
|
44
|
+
}
|
|
45
|
+
// 🧠 Use unified prompt wrapper
|
|
46
|
+
const answers = await (0, prompt_1.prompt)((0, questions_1.PICK_ENTRIES_QUESTION)(choices, depth), { picks: [] });
|
|
47
|
+
if (!answers)
|
|
48
|
+
return (0, utils_1.unique)(selected);
|
|
49
|
+
const { picks } = answers;
|
|
54
50
|
if (picks.includes("__loadmore")) {
|
|
55
51
|
depth++;
|
|
56
|
-
selected = picks.filter(p => p !== "__loadmore");
|
|
52
|
+
selected = picks.filter((p) => p !== "__loadmore");
|
|
57
53
|
continue;
|
|
58
54
|
}
|
|
59
|
-
selected = picks.filter(p => p !== "__loadmore");
|
|
55
|
+
selected = picks.filter((p) => p !== "__loadmore");
|
|
60
56
|
break;
|
|
61
57
|
}
|
|
62
58
|
return (0, utils_1.unique)(selected);
|
|
63
59
|
}
|
|
64
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Depth-based directory scanner with caching.
|
|
62
|
+
*/
|
|
63
|
+
async function getFilesAtDepth(depth, cfg, scanCache) {
|
|
64
|
+
const baseDirs = cfg.entry.ui.roots || [];
|
|
65
65
|
if (scanCache.has(depth)) {
|
|
66
|
-
logger_1.logger.debug(`[
|
|
66
|
+
logger_1.logger.debug(`[picker] cache hit → depth=${depth}`);
|
|
67
67
|
return scanCache.get(depth);
|
|
68
68
|
}
|
|
69
|
-
logger_1.logger.debug(`[
|
|
69
|
+
logger_1.logger.debug(`[picker] scanning → depth=${depth}`);
|
|
70
70
|
const files = [];
|
|
71
71
|
const effectiveCfg = { ...cfg, scanDepth: depth };
|
|
72
72
|
for (const base of baseDirs) {
|
|
73
|
-
const full = path_1.default.join(
|
|
73
|
+
const full = path_1.default.join(cfg.root, base);
|
|
74
74
|
if (!fs_1.default.existsSync(full))
|
|
75
75
|
continue;
|
|
76
76
|
for (const f of (0, helpers_1.walk)(full, effectiveCfg, 0))
|
|
77
77
|
files.push(f.norm());
|
|
78
78
|
}
|
|
79
79
|
scanCache.set(depth, files);
|
|
80
|
-
logger_1.logger.debug(`[
|
|
80
|
+
logger_1.logger.debug(`[picker] depth=${depth} found=${files.length}`);
|
|
81
81
|
return files;
|
|
82
82
|
}
|
package/dist/cli/summary.js
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.
|
|
3
|
+
exports.endSummary = endSummary;
|
|
4
|
+
exports.introSummary = introSummary;
|
|
5
|
+
exports.entrySummary = entrySummary;
|
|
5
6
|
const logger_1 = require("../lib/logger");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function importSummary(result) {
|
|
10
|
-
logger_1.logger.debug(`\n🧩 Summary:
|
|
7
|
+
const helpers_1 = require("../core/helpers");
|
|
8
|
+
function endSummary(out, result) {
|
|
9
|
+
logger_1.logger.debug(`🧩 Summary:
|
|
11
10
|
• Unique imports expected: ${result.stats.expected.size}
|
|
12
11
|
• Unique imports resolved: ${result.stats.resolved.size}
|
|
13
12
|
`);
|
|
13
|
+
logger_1.logger.log(`✅ ${out.norm()}`);
|
|
14
|
+
}
|
|
15
|
+
function introSummary({ flags, config }) {
|
|
16
|
+
logger_1.logger.log(`------- PRODEx RUN @ ${new Date().toLocaleTimeString()} — Codebase decoded -------`);
|
|
17
|
+
// Log parse results for testing
|
|
18
|
+
logger_1.logger.debug("🧩 Parsed CLI input:", _2j({ flags }));
|
|
19
|
+
logger_1.logger.debug("Final merged config:", _2j(config));
|
|
20
|
+
}
|
|
21
|
+
function entrySummary(entries) {
|
|
22
|
+
let result = "📋 You selected:";
|
|
23
|
+
for (const e of entries)
|
|
24
|
+
result += "\n -" + (0, helpers_1.rel)(e);
|
|
25
|
+
logger_1.logger.log(result);
|
|
14
26
|
}
|
|
@@ -8,6 +8,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const default_config_1 = require("./default-config");
|
|
10
10
|
const logger_1 = require("../lib/logger");
|
|
11
|
+
const utils_1 = require("../lib/utils");
|
|
11
12
|
/**
|
|
12
13
|
* 🧩 Load and merge Prodex configuration (v3)
|
|
13
14
|
*
|
|
@@ -28,7 +29,7 @@ async function loadProdexConfig(flags = {}, cwd) {
|
|
|
28
29
|
logger_1.logger.info("No prodex.json found — using defaults.");
|
|
29
30
|
}
|
|
30
31
|
// 2️⃣ Merge defaults → user config
|
|
31
|
-
const { output, entry, resolve
|
|
32
|
+
const { output, entry, resolve } = default_config_1.DEFAULT_PRODEX_CONFIG;
|
|
32
33
|
const cfg = {
|
|
33
34
|
...default_config_1.DEFAULT_PRODEX_CONFIG,
|
|
34
35
|
...userConfig,
|
|
@@ -39,11 +40,12 @@ async function loadProdexConfig(flags = {}, cwd) {
|
|
|
39
40
|
ui: { ...entry.ui, ...userConfig.entry?.ui },
|
|
40
41
|
},
|
|
41
42
|
resolve: { ...resolve, ...userConfig.resolve },
|
|
42
|
-
debug: { ...debug, ...userConfig.debug },
|
|
43
43
|
root: cwd,
|
|
44
|
+
name: flags?.name,
|
|
44
45
|
};
|
|
45
46
|
// 4️⃣ Apply CLI flag overrides (if any)
|
|
46
47
|
applyFlagOverrides(cfg, flags);
|
|
48
|
+
tidyArrayFields(cfg);
|
|
47
49
|
return cfg;
|
|
48
50
|
}
|
|
49
51
|
/** Merge CLI flags into config where relevant. */
|
|
@@ -52,8 +54,7 @@ function applyFlagOverrides(cfg, flags) {
|
|
|
52
54
|
if (!flags)
|
|
53
55
|
return;
|
|
54
56
|
const outputOverrides = {
|
|
55
|
-
|
|
56
|
-
txt: (cfg) => (cfg.output.format = "txt"),
|
|
57
|
+
txt: (cfg, v) => (cfg.output.format = v ? "txt" : "md"),
|
|
57
58
|
};
|
|
58
59
|
const resolveOverrides = {
|
|
59
60
|
limit: (cfg, v) => (cfg.resolve.limit = v),
|
|
@@ -84,7 +85,11 @@ function applyFlagOverrides(cfg, flags) {
|
|
|
84
85
|
// Conditional override rule:
|
|
85
86
|
// If files exist and include was null/undefined → clear include array
|
|
86
87
|
const hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;
|
|
87
|
-
if (hasFiles && flags.include
|
|
88
|
+
if (hasFiles && !flags.include) {
|
|
88
89
|
cfg.resolve.include = [];
|
|
89
90
|
}
|
|
90
91
|
}
|
|
92
|
+
function tidyArrayFields(cfg) {
|
|
93
|
+
cfg.entry.files = (0, utils_1.normalizePatterns)(cfg.entry.files);
|
|
94
|
+
["include", "exclude"].forEach((k) => (cfg.resolve[k] = cfg.resolve[k]));
|
|
95
|
+
}
|
package/dist/constants/config.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DTS_EXT = exports.BASE_EXTS = exports.GLOBAL_IGNORE = exports.RESOLVERS = exports.CODE_EXTS =
|
|
4
|
-
exports.ROOT = process.cwd();
|
|
3
|
+
exports.VALID_GLOB_CHARS = exports.SUFFIX = exports.DTS_EXT = exports.BASE_EXTS = exports.GLOBAL_IGNORE = exports.RESOLVERS = exports.CODE_EXTS = void 0;
|
|
5
4
|
exports.CODE_EXTS = [".js", ".mjs", ".ts", ".tsx", ".d.ts", ".php"];
|
|
6
5
|
const js_resolver_1 = require("../resolvers/js/js-resolver");
|
|
7
6
|
const php_resolver_1 = require("../resolvers/php/php-resolver");
|
|
@@ -10,8 +9,18 @@ exports.RESOLVERS = {
|
|
|
10
9
|
".ts": js_resolver_1.resolveJsImports,
|
|
11
10
|
".tsx": js_resolver_1.resolveJsImports,
|
|
12
11
|
".d.ts": js_resolver_1.resolveJsImports,
|
|
13
|
-
".js": js_resolver_1.resolveJsImports
|
|
12
|
+
".js": js_resolver_1.resolveJsImports,
|
|
14
13
|
};
|
|
15
14
|
exports.GLOBAL_IGNORE = ["**/node_modules/**", "**/vendor/**", "**/dist/**"];
|
|
16
15
|
exports.BASE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".types"];
|
|
17
16
|
exports.DTS_EXT = ".d.ts";
|
|
17
|
+
exports.SUFFIX = "trace";
|
|
18
|
+
/**
|
|
19
|
+
* Normalize and sanitize pattern fields.
|
|
20
|
+
* - Always returns an array.
|
|
21
|
+
* - Accepts string or string[].
|
|
22
|
+
* - Splits comma-separated strings.
|
|
23
|
+
* - Trims and removes empty elements.
|
|
24
|
+
* - Filters out invalid or unusable characters for Fast-Glob.
|
|
25
|
+
*/
|
|
26
|
+
exports.VALID_GLOB_CHARS = /^[\w\-@./*?|!{}\[\]^$()+]+$/; // allows Fast-Glob-safe symbols
|
|
@@ -9,7 +9,7 @@ exports.DEFAULT_PRODEX_CONFIG = {
|
|
|
9
9
|
version: 3.1,
|
|
10
10
|
output: {
|
|
11
11
|
dir: "prodex",
|
|
12
|
-
versioned:
|
|
12
|
+
versioned: true,
|
|
13
13
|
prefix: "combined",
|
|
14
14
|
format: "md",
|
|
15
15
|
},
|
|
@@ -18,13 +18,7 @@ exports.DEFAULT_PRODEX_CONFIG = {
|
|
|
18
18
|
ui: {
|
|
19
19
|
roots: ["app", "routes", "resources/js/**"],
|
|
20
20
|
scanDepth: 2,
|
|
21
|
-
priority: [
|
|
22
|
-
"**/routes/web.php",
|
|
23
|
-
"**/routes/api.php",
|
|
24
|
-
"**/*index.*",
|
|
25
|
-
"**/*main.*",
|
|
26
|
-
"**/app.*"
|
|
27
|
-
],
|
|
21
|
+
priority: ["**/routes/web.php", "**/routes/api.php", "**/*index.*", "**/*main.*", "**/app.*"],
|
|
28
22
|
},
|
|
29
23
|
},
|
|
30
24
|
resolve: {
|
|
@@ -33,16 +27,8 @@ exports.DEFAULT_PRODEX_CONFIG = {
|
|
|
33
27
|
"@hooks": "resources/js/hooks",
|
|
34
28
|
"@data": "resources/js/data",
|
|
35
29
|
},
|
|
36
|
-
exclude: [
|
|
37
|
-
"node_modules/**",
|
|
38
|
-
"@shadcn/**",
|
|
39
|
-
"**/components/ui/**"
|
|
40
|
-
],
|
|
30
|
+
exclude: ["node_modules/**", "@shadcn/**", "**/components/ui/**"],
|
|
41
31
|
depth: 10,
|
|
42
32
|
limit: 200,
|
|
43
33
|
},
|
|
44
|
-
debug: {
|
|
45
|
-
verbose: false,
|
|
46
|
-
showSummary: true,
|
|
47
|
-
},
|
|
48
34
|
};
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MD_FOOTER = exports.TEXT_HEADERS = exports.LANG_MAP = void 0;
|
|
2
7
|
// ================================================================
|
|
3
8
|
// 🧩 Prodex — Render Constants
|
|
4
9
|
// Defines shared constants for renderer outDir formats.
|
|
5
10
|
// ================================================================
|
|
6
|
-
|
|
7
|
-
exports.TEXT_HEADERS = exports.LANG_MAP = void 0;
|
|
11
|
+
const package_json_1 = __importDefault(require("../../package.json"));
|
|
8
12
|
exports.LANG_MAP = {
|
|
9
13
|
"": "js",
|
|
10
14
|
".mjs": "js",
|
|
@@ -13,11 +17,12 @@ exports.LANG_MAP = {
|
|
|
13
17
|
".tsx": "tsx",
|
|
14
18
|
".php": "php",
|
|
15
19
|
".json": "json",
|
|
16
|
-
".d.ts": "ts"
|
|
20
|
+
".d.ts": "ts",
|
|
17
21
|
};
|
|
18
22
|
exports.TEXT_HEADERS = {
|
|
19
23
|
toc: "##==== Combined Scope ====",
|
|
20
|
-
path: p => `##==== path: ${p} ====`,
|
|
21
|
-
regionStart: p => `##region ${p}`,
|
|
22
|
-
regionEnd: "##endregion"
|
|
24
|
+
path: (p) => `##==== path: ${p} ====`,
|
|
25
|
+
regionStart: (p) => `##region ${p}`,
|
|
26
|
+
regionEnd: "##endregion",
|
|
23
27
|
};
|
|
28
|
+
exports.MD_FOOTER = ["\n---", "*Generated with [Prodex](https://github.com/emxhive/prodex) — Codebase decoded.*", `<!-- PRODEx v${package_json_1.default.version} | ${new Date().toISOString()} -->`].join("\n");
|
package/dist/core/combine.js
CHANGED
|
@@ -1,74 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.runCombine = runCombine;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const inquirer_1 = __importDefault(require("inquirer"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
4
|
const picker_1 = require("../cli/picker");
|
|
11
5
|
const summary_1 = require("../cli/summary");
|
|
12
6
|
const dependency_1 = require("./dependency");
|
|
13
7
|
const file_utils_1 = require("./file-utils");
|
|
14
|
-
const renderers_1 = require("./renderers");
|
|
15
8
|
const logger_1 = require("../lib/logger");
|
|
16
|
-
const
|
|
17
|
-
async function runCombine(cfg,
|
|
18
|
-
const {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
const output_1 = require("./output");
|
|
10
|
+
async function runCombine({ cfg, opts }) {
|
|
11
|
+
const { showUi, cliName } = opts;
|
|
12
|
+
let entries = (await resolveEntries(showUi, cfg)) ?? [];
|
|
13
|
+
if (!entries.length) {
|
|
14
|
+
logger_1.logger.error("No entries selected.");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
(0, summary_1.entrySummary)(entries);
|
|
18
|
+
const result = await (0, dependency_1.followChain)(entries, cfg);
|
|
19
|
+
const withinclude = await (0, dependency_1.applyincludes)(cfg, result.files);
|
|
20
|
+
const autoName = (0, file_utils_1.produceSmartName)(entries);
|
|
21
|
+
const outputPath = await (0, output_1.produceOutput)({ name: cliName ?? autoName, files: withinclude, cfg, showUi });
|
|
22
|
+
(0, summary_1.endSummary)(outputPath, result);
|
|
23
|
+
}
|
|
24
|
+
async function resolveEntries(showUi, cfg) {
|
|
25
|
+
const { root, entry } = cfg;
|
|
26
|
+
const { files } = entry;
|
|
24
27
|
if (!showUi) {
|
|
25
28
|
logger_1.logger.info("CI Mode");
|
|
26
|
-
if (!
|
|
29
|
+
if (!files?.length) {
|
|
27
30
|
logger_1.logger.warn("No entry files defined and UI mode is disabled.");
|
|
28
|
-
|
|
31
|
+
process.exit(1);
|
|
29
32
|
}
|
|
30
|
-
|
|
33
|
+
return (await (0, file_utils_1.globScan)(files, { cwd: root })).files;
|
|
31
34
|
}
|
|
32
35
|
else {
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
if (!entries.length) {
|
|
36
|
-
logger_1.logger.error("No entries selected.");
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
logger_1.logger.log("\n📋 You selected:");
|
|
40
|
-
for (const e of entries)
|
|
41
|
-
logger_1.logger.log(" -", e.replace(ROOT + "/", ""));
|
|
42
|
-
const autoName = (0, file_utils_1.generateOutputName)(entries);
|
|
43
|
-
const outDir = output.dir;
|
|
44
|
-
const limit = resolve.limit;
|
|
45
|
-
let outputBase = autoName;
|
|
46
|
-
if (showUi) {
|
|
47
|
-
const { outputBase: answer } = await inquirer_1.default.prompt([
|
|
48
|
-
{
|
|
49
|
-
type: "input",
|
|
50
|
-
name: "outputBase",
|
|
51
|
-
message: "Output file name (without extension):",
|
|
52
|
-
default: autoName,
|
|
53
|
-
filter: (v) => (v.trim() || autoName).replace(/[<>:"/\\|?*]+/g, "_"),
|
|
54
|
-
},
|
|
55
|
-
]);
|
|
56
|
-
outputBase = answer;
|
|
36
|
+
return await (0, picker_1.pickEntries)(cfg);
|
|
57
37
|
}
|
|
58
|
-
try {
|
|
59
|
-
fs_1.default.mkdirSync(outDir, { recursive: true });
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
logger_1.logger.warn("Could not create outDir directory:", outDir);
|
|
63
|
-
}
|
|
64
|
-
const outputPath = (0, file_utils_1.resolveOutDirPath)(outDir, outputBase, toMd);
|
|
65
|
-
(0, summary_1.showSummary)({ outDir, fileName: path_1.default.basename(outputPath), entries });
|
|
66
|
-
const result = await (0, dependency_1.followChain)(entries, cfg, limit);
|
|
67
|
-
const withinclude = await (0, dependency_1.applyincludes)(cfg, result.files);
|
|
68
|
-
const sorted = [...withinclude].sort((a, b) => a.localeCompare(b));
|
|
69
|
-
const footer = ["\n---", "*Generated with [Prodex](https://github.com/emxhive/prodex) — Codebase decoded.*", `<!-- PRODEx v${package_json_1.default.version} | ${new Date().toISOString()} -->`].join("\n");
|
|
70
|
-
const content = toMd ? [(0, renderers_1.tocTxt)(sorted), ...sorted.map(renderers_1.renderTxt)].join("") : [(0, renderers_1.tocMd)(sorted), ...sorted.map((f, i) => (0, renderers_1.renderMd)(f, i)), footer].join("\n");
|
|
71
|
-
fs_1.default.writeFileSync(outputPath, content, "utf8");
|
|
72
|
-
logger_1.logger.log(`\n✅ ${outputPath.norm()}`);
|
|
73
|
-
(0, summary_1.importSummary)(result);
|
|
74
38
|
}
|
package/dist/core/dependency.js
CHANGED
|
@@ -9,7 +9,9 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const config_1 = require("../constants/config");
|
|
10
10
|
const file_utils_1 = require("./file-utils");
|
|
11
11
|
const logger_1 = require("../lib/logger");
|
|
12
|
-
|
|
12
|
+
const utils_1 = require("../lib/utils");
|
|
13
|
+
async function followChain(entryFiles, cfg) {
|
|
14
|
+
const limit = cfg.resolve.limit;
|
|
13
15
|
logger_1.logger.debug("🧩 Following dependency chain...");
|
|
14
16
|
const visited = new Set();
|
|
15
17
|
const all = [];
|
|
@@ -37,15 +39,17 @@ async function followChain(entryFiles, cfg, limit = 200) {
|
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
return {
|
|
40
|
-
files:
|
|
42
|
+
files: (0, utils_1.unique)(all),
|
|
41
43
|
stats: { expected, resolved },
|
|
42
44
|
};
|
|
43
45
|
}
|
|
44
46
|
async function applyincludes(cfg, files) {
|
|
47
|
+
;
|
|
45
48
|
const { resolve } = cfg;
|
|
46
49
|
const ROOT = cfg.root;
|
|
47
50
|
const scan = await (0, file_utils_1.globScan)(resolve.include, { cwd: ROOT });
|
|
48
51
|
logger_1.logger.debug("APPLY_include", _2j(scan));
|
|
49
|
-
const combined =
|
|
52
|
+
const combined = (0, utils_1.unique)([...files, ...scan.files]);
|
|
53
|
+
;
|
|
50
54
|
return combined;
|
|
51
55
|
}
|
package/dist/core/file-utils.js
CHANGED
|
@@ -4,32 +4,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.globScan = globScan;
|
|
7
|
-
exports.
|
|
8
|
-
exports.resolveOutDirPath = resolveOutDirPath;
|
|
7
|
+
exports.produceSmartName = produceSmartName;
|
|
9
8
|
const path_1 = __importDefault(require("path"));
|
|
10
9
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
11
10
|
const config_1 = require("../constants/config");
|
|
12
11
|
const logger_1 = require("../lib/logger");
|
|
12
|
+
const utils_1 = require("../lib/utils");
|
|
13
13
|
/**
|
|
14
14
|
* Safe micromatch.scan wrapper (compatible with micromatch v4 & v5)
|
|
15
15
|
*/
|
|
16
|
-
async function globScan(
|
|
17
|
-
logger_1.logger.debug("
|
|
16
|
+
async function globScan(patterns, opts) {
|
|
17
|
+
logger_1.logger.debug("PATTERNS", patterns);
|
|
18
18
|
const { absolute = true, cwd = process.cwd() } = opts;
|
|
19
|
-
if (!
|
|
19
|
+
if (!patterns?.length)
|
|
20
20
|
return { files: [] };
|
|
21
|
-
const files = await (0, fast_glob_1.default)(
|
|
21
|
+
const files = (await (0, fast_glob_1.default)(patterns, {
|
|
22
22
|
cwd,
|
|
23
|
+
extglob: true,
|
|
23
24
|
dot: true,
|
|
24
25
|
onlyFiles: true,
|
|
25
26
|
ignore: config_1.GLOBAL_IGNORE,
|
|
26
27
|
absolute,
|
|
27
|
-
});
|
|
28
|
+
})).map((f) => path_1.default.resolve(f));
|
|
28
29
|
logger_1.logger.debug("GLOB-SCAN_FILES ", _2j(files));
|
|
29
30
|
return { files };
|
|
30
31
|
}
|
|
31
|
-
function
|
|
32
|
-
const names = entries.map((f) => path_1.default.basename(f, path_1.default.extname(f)));
|
|
32
|
+
function produceSmartName(entries) {
|
|
33
|
+
const names = (0, utils_1.unique)(entries.map((f) => path_1.default.basename(f, path_1.default.extname(f))));
|
|
33
34
|
if (names.length === 1)
|
|
34
35
|
return names[0];
|
|
35
36
|
if (names.length === 2)
|
|
@@ -38,7 +39,3 @@ function generateOutputName(entries) {
|
|
|
38
39
|
return `${names[0]}-and-${names.length - 1}more`;
|
|
39
40
|
return "unknown";
|
|
40
41
|
}
|
|
41
|
-
function resolveOutDirPath(outDir, base, asTxt = false) {
|
|
42
|
-
const ext = asTxt ? "txt" : "md";
|
|
43
|
-
return path_1.default.join(outDir, `${base}-combined.${ext}`);
|
|
44
|
-
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.produceOutput = produceOutput;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const prompt_1 = require("../lib/prompt");
|
|
10
|
+
const renderers_1 = require("./renderers");
|
|
11
|
+
const logger_1 = require("../lib/logger");
|
|
12
|
+
const utils_1 = require("../lib/utils");
|
|
13
|
+
const questions_1 = require("../lib/questions");
|
|
14
|
+
const render_constants_1 = require("../constants/render-constants");
|
|
15
|
+
const config_1 = require("../constants/config");
|
|
16
|
+
/**
|
|
17
|
+
* 🧩 produceOutput()
|
|
18
|
+
* Handles rendering and writing of the final trace file.
|
|
19
|
+
* Receives resolved files and configuration from combine.ts.
|
|
20
|
+
*/
|
|
21
|
+
async function produceOutput({ name, files, cfg, showUi }) {
|
|
22
|
+
const { output: { format, versioned, dir }, } = cfg;
|
|
23
|
+
;
|
|
24
|
+
// 1️⃣ Determine base filename
|
|
25
|
+
let outputBase = name;
|
|
26
|
+
if (showUi) {
|
|
27
|
+
const result = await (0, prompt_1.prompt)(questions_1.OUTPUT_NAME_QUESTION);
|
|
28
|
+
if (result?.outputBase)
|
|
29
|
+
outputBase = result.outputBase;
|
|
30
|
+
}
|
|
31
|
+
// 2️⃣ Prefix timestamp if versioned
|
|
32
|
+
outputBase = `${outputBase}-${config_1.SUFFIX}`;
|
|
33
|
+
if (versioned)
|
|
34
|
+
outputBase = `${outputBase}_${(0, utils_1.shortTimestamp)()}`;
|
|
35
|
+
// 3️⃣ Ensure output directory
|
|
36
|
+
try {
|
|
37
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
logger_1.logger.warn("Could not create dir directory:", dir);
|
|
41
|
+
}
|
|
42
|
+
// 4️⃣ Prepare and write content
|
|
43
|
+
const outputPath = path_1.default.join(dir, `${outputBase}.${format}`);
|
|
44
|
+
const sorted = [...files].sort((a, b) => a.localeCompare(b));
|
|
45
|
+
const content = format === "txt" ? [(0, renderers_1.tocTxt)(sorted), ...sorted.map(renderers_1.renderTxt)].join("") : [(0, renderers_1.tocMd)(sorted), ...sorted.map((f, i) => (0, renderers_1.renderMd)(f, i)), render_constants_1.MD_FOOTER].join("\n");
|
|
46
|
+
fs_1.default.writeFileSync(outputPath, content, "utf8");
|
|
47
|
+
return outputPath;
|
|
48
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -3,10 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.default = startProdex;
|
|
4
4
|
const combine_1 = require("./core/combine");
|
|
5
5
|
const init_1 = require("./cli/init");
|
|
6
|
-
const logger_1 = require("./lib/logger");
|
|
7
6
|
const cli_input_1 = require("./cli/cli-input");
|
|
8
7
|
const config_loader_1 = require("./constants/config-loader");
|
|
9
8
|
require("./lib/polyfills");
|
|
9
|
+
const summary_1 = require("./cli/summary");
|
|
10
10
|
async function startProdex() {
|
|
11
11
|
const args = process.argv;
|
|
12
12
|
// Handle init mode
|
|
@@ -14,16 +14,13 @@ async function startProdex() {
|
|
|
14
14
|
return (0, init_1.initProdex)();
|
|
15
15
|
}
|
|
16
16
|
// Parse CLI input
|
|
17
|
-
const { root, flags
|
|
18
|
-
if (warnings.length)
|
|
19
|
-
logger_1.logger.warn("Warnings:", warnings);
|
|
20
|
-
if (errors.length)
|
|
21
|
-
logger_1.logger.error("Errors:", errors);
|
|
17
|
+
const { root, flags } = (0, cli_input_1.parseCliInput)(args);
|
|
22
18
|
// Load and merge configuration (with flag overrides)
|
|
23
19
|
const config = await (0, config_loader_1.loadProdexConfig)(flags, root);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
(0, summary_1.introSummary)({ flags, config });
|
|
21
|
+
const opts = {
|
|
22
|
+
showUi: !flags.ci && !flags?.files?.length && !config?.entry?.ui?.enablePicker,
|
|
23
|
+
cliName: config.name,
|
|
24
|
+
};
|
|
25
|
+
await (0, combine_1.runCombine)({ cfg: config, opts });
|
|
29
26
|
}
|
package/dist/lib/logger.js
CHANGED
|
@@ -8,7 +8,7 @@ const env = () => {
|
|
|
8
8
|
exports.logger = {
|
|
9
9
|
debug: (...args) => !env().silent && env().debug && console.log("\n🪶 [debug]", ...args),
|
|
10
10
|
info: (...args) => !env().silent && console.log("\n📌 [info]", ...args),
|
|
11
|
-
warn: (...args) => !env().silent && console.warn("\n⚠️
|
|
11
|
+
warn: (...args) => !env().silent && console.warn("\n⚠️ [warn]", ...args),
|
|
12
12
|
error: (...args) => !env().silent && console.error("\n💥 [error]", ...args),
|
|
13
13
|
log: (...args) => !env().silent && console.log("\n", ...args),
|
|
14
14
|
};
|
package/dist/lib/polyfills.js
CHANGED
|
@@ -9,4 +9,19 @@ if (!String.prototype.norm) {
|
|
|
9
9
|
return this.replace(/\\/g, "/");
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
+
if (!String.prototype.clean) {
|
|
13
|
+
String.prototype.clean = function () {
|
|
14
|
+
return this.replace(/[<>:\"/\\|?*]+/g, "_");
|
|
15
|
+
};
|
|
16
|
+
}
|
|
12
17
|
globalThis._2j = (obj) => util_1.default.inspect(obj, { colors: true, depth: null, breakLength: 150, compact: 3 });
|
|
18
|
+
globalThis._bpt = function (param) {
|
|
19
|
+
if (process.env.PRODEX_DEBUG !== "1")
|
|
20
|
+
return;
|
|
21
|
+
console.log("⭕ BREAKPOINT");
|
|
22
|
+
if (typeof param === "function")
|
|
23
|
+
param();
|
|
24
|
+
else
|
|
25
|
+
console.log(_2j(param));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.prompt = prompt;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
const logger_1 = require("./logger");
|
|
9
|
+
/**
|
|
10
|
+
* 🧩 prompt()
|
|
11
|
+
* Unified and safe wrapper for inquirer.prompt()
|
|
12
|
+
*
|
|
13
|
+
* - Requires explicit `showUi` flag (no env auto-detection).
|
|
14
|
+
* - Returns `null` or `fallback` on failure or disabled UI.
|
|
15
|
+
* - Handles TTY errors and user cancellations gracefully.
|
|
16
|
+
*/
|
|
17
|
+
async function prompt(questions, fallback) {
|
|
18
|
+
try {
|
|
19
|
+
const answers = (await inquirer_1.default.prompt(questions));
|
|
20
|
+
return answers;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
if (err?.isTtyError) {
|
|
24
|
+
logger_1.logger.warn("Interactive prompts not supported (no TTY).");
|
|
25
|
+
}
|
|
26
|
+
else if (/canceled|aborted/i.test(err?.message)) {
|
|
27
|
+
logger_1.logger.warn("Prompt canceled by user.");
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
logger_1.logger.error("Prompt failed:", err.message || err);
|
|
31
|
+
}
|
|
32
|
+
return fallback ?? null;
|
|
33
|
+
}
|
|
34
|
+
}
|