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.
Files changed (60) hide show
  1. package/README.md +234 -140
  2. package/bin/prodex.js +1 -17
  3. package/dist/cli/cli-input.js +106 -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 +26 -0
  8. package/dist/constants/config-loader.js +95 -0
  9. package/dist/constants/config.js +26 -0
  10. package/dist/constants/default-config.js +34 -0
  11. package/dist/constants/render-constants.js +28 -0
  12. package/dist/core/combine.js +38 -0
  13. package/dist/core/dependency.js +55 -0
  14. package/dist/core/file-utils.js +41 -0
  15. package/dist/core/helpers.js +81 -0
  16. package/dist/core/output.js +48 -0
  17. package/dist/core/parsers/extract-imports.js +51 -0
  18. package/dist/core/renderers.js +42 -0
  19. package/dist/index.js +26 -0
  20. package/dist/lib/logger.js +14 -0
  21. package/dist/lib/polyfills.js +27 -0
  22. package/dist/lib/prompt.js +34 -0
  23. package/dist/lib/questions.js +28 -0
  24. package/dist/lib/utils.js +51 -0
  25. package/dist/resolvers/js/alias-loader.js +52 -0
  26. package/dist/resolvers/js/js-resolver.js +153 -0
  27. package/dist/resolvers/php/bindings.js +32 -0
  28. package/dist/resolvers/php/patterns.js +17 -0
  29. package/dist/resolvers/php/php-resolver.js +88 -0
  30. package/dist/resolvers/php/psr4.js +26 -0
  31. package/dist/resolvers/shared/excludes.js +11 -0
  32. package/dist/resolvers/shared/file-cache.js +29 -0
  33. package/dist/resolvers/shared/stats.js +17 -0
  34. package/dist/types/cli.types.js +12 -0
  35. package/dist/types/config.types.js +2 -0
  36. package/dist/types/core.types.js +2 -0
  37. package/dist/types/index.js +21 -0
  38. package/dist/types/resolver.types.js +2 -0
  39. package/dist/types/utils.types.js +2 -0
  40. package/package.json +16 -12
  41. package/dist/LICENSE +0 -21
  42. package/dist/README.md +0 -140
  43. package/dist/bin/prodex.js +0 -18
  44. package/dist/package.json +0 -45
  45. package/dist/src/cli/init.js +0 -18
  46. package/dist/src/cli/picker.js +0 -59
  47. package/dist/src/cli/summary.js +0 -6
  48. package/dist/src/constants/config-loader.js +0 -87
  49. package/dist/src/constants/config.js +0 -13
  50. package/dist/src/constants/default-config.js +0 -36
  51. package/dist/src/constants/render-constants.js +0 -22
  52. package/dist/src/core/alias-loader.js +0 -8
  53. package/dist/src/core/combine.js +0 -145
  54. package/dist/src/core/file-utils.js +0 -45
  55. package/dist/src/core/helpers.js +0 -77
  56. package/dist/src/core/renderers.js +0 -58
  57. package/dist/src/index.js +0 -15
  58. package/dist/src/resolvers/js-resolver.js +0 -180
  59. package/dist/src/resolvers/php-bindings.js +0 -31
  60. package/dist/src/resolvers/php-resolver.js +0 -155
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.endSummary = endSummary;
4
+ exports.introSummary = introSummary;
5
+ exports.entrySummary = entrySummary;
6
+ const logger_1 = require("../lib/logger");
7
+ const helpers_1 = require("../core/helpers");
8
+ function endSummary(out, result) {
9
+ logger_1.logger.debug(`🧩 Summary:
10
+ • Unique imports expected: ${result.stats.expected.size}
11
+ • Unique imports resolved: ${result.stats.resolved.size}
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);
26
+ }
@@ -0,0 +1,95 @@
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.loadProdexConfig = loadProdexConfig;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const default_config_1 = require("./default-config");
10
+ const logger_1 = require("../lib/logger");
11
+ const utils_1 = require("../lib/utils");
12
+ /**
13
+ * 🧩 Load and merge Prodex configuration (v3)
14
+ *
15
+ * 1ļøāƒ£ Reads `prodex.json` if present.
16
+ * 2ļøāƒ£ Merges with `DEFAULT_PRODEX_CONFIG`.
17
+ * 3ļøāƒ£ Normalizes all path-like fields.
18
+ * 4ļøāƒ£ Applies CLI flag overrides.
19
+ */
20
+ async function loadProdexConfig(flags = {}, cwd) {
21
+ const configPath = path_1.default.join(cwd, "prodex.json");
22
+ let userConfig = {};
23
+ // 1ļøāƒ£ Load config if present
24
+ try {
25
+ const content = fs_1.default.readFileSync(configPath, "utf8");
26
+ userConfig = JSON.parse(content);
27
+ }
28
+ catch (err) {
29
+ logger_1.logger.info("No prodex.json found — using defaults.");
30
+ }
31
+ // 2ļøāƒ£ Merge defaults → user config
32
+ const { output, entry, resolve } = default_config_1.DEFAULT_PRODEX_CONFIG;
33
+ const cfg = {
34
+ ...default_config_1.DEFAULT_PRODEX_CONFIG,
35
+ ...userConfig,
36
+ output: { ...output, ...userConfig.output },
37
+ entry: {
38
+ ...entry,
39
+ ...userConfig.entry,
40
+ ui: { ...entry.ui, ...userConfig.entry?.ui },
41
+ },
42
+ resolve: { ...resolve, ...userConfig.resolve },
43
+ root: cwd,
44
+ name: flags?.name,
45
+ };
46
+ // 4ļøāƒ£ Apply CLI flag overrides (if any)
47
+ applyFlagOverrides(cfg, flags);
48
+ tidyArrayFields(cfg);
49
+ return cfg;
50
+ }
51
+ /** Merge CLI flags into config where relevant. */
52
+ /** Merge CLI flags into config where relevant. */
53
+ function applyFlagOverrides(cfg, flags) {
54
+ if (!flags)
55
+ return;
56
+ const outputOverrides = {
57
+ txt: (cfg, v) => (cfg.output.format = v ? "txt" : "md"),
58
+ };
59
+ const resolveOverrides = {
60
+ limit: (cfg, v) => (cfg.resolve.limit = v),
61
+ include: (cfg, v) => (cfg.resolve.include = v),
62
+ exclude: (cfg, v) => (cfg.resolve.exclude = v),
63
+ };
64
+ const entryOverrides = {
65
+ files: (cfg, v) => (cfg.entry.files = v),
66
+ };
67
+ const envOverrides = {
68
+ debug: (_, v) => (process.env.PRODEX_DEBUG = v ? "1" : "0"),
69
+ verbose: (_, v) => (process.env.PRODEX_VERBOSE = v ? "1" : "0"),
70
+ };
71
+ const overrideMap = {
72
+ ...outputOverrides,
73
+ ...resolveOverrides,
74
+ ...entryOverrides,
75
+ ...envOverrides,
76
+ };
77
+ // Apply all flag overrides dynamically
78
+ for (const [flag, value] of Object.entries(flags)) {
79
+ if (value == undefined)
80
+ continue;
81
+ const apply = overrideMap[flag];
82
+ if (apply)
83
+ apply(cfg, value);
84
+ }
85
+ // Conditional override rule:
86
+ // If files exist and include was null/undefined → clear include array
87
+ const hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;
88
+ if (hasFiles && !flags.include) {
89
+ cfg.resolve.include = [];
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
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VALID_GLOB_CHARS = exports.SUFFIX = exports.DTS_EXT = exports.BASE_EXTS = exports.GLOBAL_IGNORE = exports.RESOLVERS = exports.CODE_EXTS = void 0;
4
+ exports.CODE_EXTS = [".js", ".mjs", ".ts", ".tsx", ".d.ts", ".php"];
5
+ const js_resolver_1 = require("../resolvers/js/js-resolver");
6
+ const php_resolver_1 = require("../resolvers/php/php-resolver");
7
+ exports.RESOLVERS = {
8
+ ".php": php_resolver_1.resolvePhpImports,
9
+ ".ts": js_resolver_1.resolveJsImports,
10
+ ".tsx": js_resolver_1.resolveJsImports,
11
+ ".d.ts": js_resolver_1.resolveJsImports,
12
+ ".js": js_resolver_1.resolveJsImports,
13
+ };
14
+ exports.GLOBAL_IGNORE = ["**/node_modules/**", "**/vendor/**", "**/dist/**"];
15
+ exports.BASE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".types"];
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
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_PRODEX_CONFIG = void 0;
4
+ /**
5
+ * Default configuration for Prodex.
6
+ * Conforms strictly to ProdexConfig for full type safety.
7
+ */
8
+ exports.DEFAULT_PRODEX_CONFIG = {
9
+ version: 3.1,
10
+ output: {
11
+ dir: "prodex",
12
+ versioned: true,
13
+ prefix: "combined",
14
+ format: "md",
15
+ },
16
+ entry: {
17
+ files: [],
18
+ ui: {
19
+ roots: ["app", "routes", "resources/js/**"],
20
+ scanDepth: 2,
21
+ priority: ["**/routes/web.php", "**/routes/api.php", "**/*index.*", "**/*main.*", "**/app.*"],
22
+ },
23
+ },
24
+ resolve: {
25
+ include: ["**/*.d.ts", "**/*.interface.ts"],
26
+ aliases: {
27
+ "@hooks": "resources/js/hooks",
28
+ "@data": "resources/js/data",
29
+ },
30
+ exclude: ["node_modules/**", "@shadcn/**", "**/components/ui/**"],
31
+ depth: 10,
32
+ limit: 200,
33
+ },
34
+ };
@@ -0,0 +1,28 @@
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;
7
+ // ================================================================
8
+ // 🧩 Prodex — Render Constants
9
+ // Defines shared constants for renderer outDir formats.
10
+ // ================================================================
11
+ const package_json_1 = __importDefault(require("../../package.json"));
12
+ exports.LANG_MAP = {
13
+ "": "js",
14
+ ".mjs": "js",
15
+ ".jsx": "jsx",
16
+ ".ts": "ts",
17
+ ".tsx": "tsx",
18
+ ".php": "php",
19
+ ".json": "json",
20
+ ".d.ts": "ts",
21
+ };
22
+ exports.TEXT_HEADERS = {
23
+ toc: "##==== Combined Scope ====",
24
+ path: (p) => `##==== path: ${p} ====`,
25
+ regionStart: (p) => `##region ${p}`,
26
+ regionEnd: "##endregion",
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");
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runCombine = runCombine;
4
+ const picker_1 = require("../cli/picker");
5
+ const summary_1 = require("../cli/summary");
6
+ const dependency_1 = require("./dependency");
7
+ const file_utils_1 = require("./file-utils");
8
+ const logger_1 = require("../lib/logger");
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;
27
+ if (!showUi) {
28
+ logger_1.logger.info("CI Mode");
29
+ if (!files?.length) {
30
+ logger_1.logger.warn("No entry files defined and UI mode is disabled.");
31
+ process.exit(1);
32
+ }
33
+ return (await (0, file_utils_1.globScan)(files, { cwd: root })).files;
34
+ }
35
+ else {
36
+ return await (0, picker_1.pickEntries)(cfg);
37
+ }
38
+ }
@@ -0,0 +1,55 @@
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.followChain = followChain;
7
+ exports.applyincludes = applyincludes;
8
+ const path_1 = __importDefault(require("path"));
9
+ const config_1 = require("../constants/config");
10
+ const file_utils_1 = require("./file-utils");
11
+ const logger_1 = require("../lib/logger");
12
+ const utils_1 = require("../lib/utils");
13
+ async function followChain(entryFiles, cfg) {
14
+ const limit = cfg.resolve.limit;
15
+ logger_1.logger.debug("🧩 Following dependency chain...");
16
+ const visited = new Set();
17
+ const all = [];
18
+ const expected = new Set();
19
+ const resolved = new Set();
20
+ const resolverDepth = cfg.resolve.depth;
21
+ for (const f of entryFiles) {
22
+ if (visited.has(f))
23
+ continue;
24
+ all.push(f);
25
+ const ext = path_1.default.extname(f);
26
+ if (!config_1.CODE_EXTS.includes(ext))
27
+ continue;
28
+ const resolver = config_1.RESOLVERS[ext];
29
+ if (resolver) {
30
+ const result = await resolver(f, cfg, visited, 0, resolverDepth);
31
+ const { files, stats } = result;
32
+ all.push(...files);
33
+ stats?.expected?.forEach((x) => expected.add(x));
34
+ stats?.resolved?.forEach((x) => resolved.add(x));
35
+ }
36
+ if (limit && all.length >= limit) {
37
+ logger_1.logger.warn("āš ļø Limit reached:", limit);
38
+ break;
39
+ }
40
+ }
41
+ return {
42
+ files: (0, utils_1.unique)(all),
43
+ stats: { expected, resolved },
44
+ };
45
+ }
46
+ async function applyincludes(cfg, files) {
47
+ ;
48
+ const { resolve } = cfg;
49
+ const ROOT = cfg.root;
50
+ const scan = await (0, file_utils_1.globScan)(resolve.include, { cwd: ROOT });
51
+ logger_1.logger.debug("APPLY_include", _2j(scan));
52
+ const combined = (0, utils_1.unique)([...files, ...scan.files]);
53
+ ;
54
+ return combined;
55
+ }
@@ -0,0 +1,41 @@
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.globScan = globScan;
7
+ exports.produceSmartName = produceSmartName;
8
+ const path_1 = __importDefault(require("path"));
9
+ const fast_glob_1 = __importDefault(require("fast-glob"));
10
+ const config_1 = require("../constants/config");
11
+ const logger_1 = require("../lib/logger");
12
+ const utils_1 = require("../lib/utils");
13
+ /**
14
+ * Safe micromatch.scan wrapper (compatible with micromatch v4 & v5)
15
+ */
16
+ async function globScan(patterns, opts) {
17
+ logger_1.logger.debug("PATTERNS", patterns);
18
+ const { absolute = true, cwd = process.cwd() } = opts;
19
+ if (!patterns?.length)
20
+ return { files: [] };
21
+ const files = (await (0, fast_glob_1.default)(patterns, {
22
+ cwd,
23
+ extglob: true,
24
+ dot: true,
25
+ onlyFiles: true,
26
+ ignore: config_1.GLOBAL_IGNORE,
27
+ absolute,
28
+ })).map((f) => path_1.default.resolve(f));
29
+ logger_1.logger.debug("GLOB-SCAN_FILES ", _2j(files));
30
+ return { files };
31
+ }
32
+ function produceSmartName(entries) {
33
+ const names = (0, utils_1.unique)(entries.map((f) => path_1.default.basename(f, path_1.default.extname(f))));
34
+ if (names.length === 1)
35
+ return names[0];
36
+ if (names.length === 2)
37
+ return `${names[0]}-${names[1]}`;
38
+ if (names.length > 2)
39
+ return `${names[0]}-and-${names.length - 1}more`;
40
+ return "unknown";
41
+ }
@@ -0,0 +1,81 @@
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.rel = rel;
7
+ exports.read = read;
8
+ exports.isExcluded = isExcluded;
9
+ exports.walk = walk;
10
+ exports.orderByPriority = orderByPriority;
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const micromatch_1 = __importDefault(require("micromatch"));
14
+ /**
15
+ * Get a root-relative version of a path.
16
+ */
17
+ function rel(p, root = process.cwd()) {
18
+ return path_1.default.relative(root, p).replaceAll("\\", "/");
19
+ }
20
+ /**
21
+ * Safe text read.
22
+ */
23
+ function read(p) {
24
+ try {
25
+ return fs_1.default.readFileSync(p, "utf8");
26
+ }
27
+ catch {
28
+ return "";
29
+ }
30
+ }
31
+ /**
32
+ * Check if a path/file matches any of the provided glob patterns.
33
+ */
34
+ function isExcluded(p, patterns, root = process.cwd()) {
35
+ if (!patterns?.length)
36
+ return false;
37
+ const relPath = rel(p, root);
38
+ return micromatch_1.default.isMatch(relPath, patterns);
39
+ }
40
+ /**
41
+ * Recursive walker that respects glob exclude.
42
+ * Returns all files under the given directory tree.
43
+ */
44
+ function* walk(dir, cfg, depth = 0) {
45
+ const { scanDepth, entry } = cfg;
46
+ const root = process.cwd();
47
+ if (depth > scanDepth)
48
+ return;
49
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
50
+ for (const e of entries) {
51
+ const full = path_1.default.join(dir, e.name);
52
+ if (e.isDirectory()) {
53
+ // Skip excluded directories entirely
54
+ const relPath = rel(full, root);
55
+ if (isExcluded(relPath, entry.exclude))
56
+ continue;
57
+ yield* walk(full, cfg, depth + 1);
58
+ continue;
59
+ }
60
+ if (e.isFile()) {
61
+ const relPath = rel(full, root);
62
+ if (isExcluded(relPath, entry.exclude))
63
+ continue;
64
+ yield full;
65
+ }
66
+ }
67
+ }
68
+ function orderByPriority(files, priorityList = []) {
69
+ if (!priorityList.length)
70
+ return files;
71
+ const prioritized = [];
72
+ const normal = [];
73
+ for (const f of files) {
74
+ const normalized = f.norm().toLowerCase();
75
+ if (priorityList.some(p => micromatch_1.default.isMatch(normalized, p.toLowerCase())))
76
+ prioritized.push(f);
77
+ else
78
+ normal.push(f);
79
+ }
80
+ return [...new Set([...prioritized, ...normal])];
81
+ }
@@ -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
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ // @ts-nocheck
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.extractImports = extractImports;
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const es_module_lexer_1 = require("es-module-lexer");
10
+ let initialized = false;
11
+ async function extractImports(filePath, code) {
12
+ if (!initialized) {
13
+ await es_module_lexer_1.init;
14
+ initialized = true;
15
+ }
16
+ let src = code;
17
+ if (src == null) {
18
+ try {
19
+ src = await promises_1.default.readFile(filePath, "utf8");
20
+ }
21
+ catch {
22
+ return new Set();
23
+ }
24
+ }
25
+ try {
26
+ const [imports] = (0, es_module_lexer_1.parse)(src);
27
+ const out = new Set();
28
+ for (const i of imports)
29
+ if (i.n)
30
+ out.add(i.n);
31
+ return out;
32
+ }
33
+ catch {
34
+ return fallbackRegex(src);
35
+ }
36
+ }
37
+ function fallbackRegex(code) {
38
+ const patterns = [
39
+ /import\s+[^'"]*['"]([^'"]+)['"]/g,
40
+ /import\(\s*['"]([^'"]+)['"]\s*\)/g,
41
+ /require\(\s*['"]([^'"]+)['"]\s*\)/g,
42
+ /export\s+\*\s+from\s+['"]([^'"]+)['"]/g,
43
+ ];
44
+ const matches = new Set();
45
+ for (const r of patterns) {
46
+ let m;
47
+ while ((m = r.exec(code)))
48
+ matches.add(m[1]);
49
+ }
50
+ return matches;
51
+ }
@@ -0,0 +1,42 @@
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.tocMd = tocMd;
7
+ exports.renderMd = renderMd;
8
+ exports.tocTxt = tocTxt;
9
+ exports.renderTxt = renderTxt;
10
+ const path_1 = __importDefault(require("path"));
11
+ const helpers_1 = require("./helpers");
12
+ const render_constants_1 = require("../constants/render-constants");
13
+ /**
14
+ * Generate Markdown Table of Contents with anchors
15
+ */
16
+ function tocMd(files) {
17
+ const count = files.length;
18
+ const items = files.map((f, i) => `- [${(0, helpers_1.rel)(f)}](#${i + 1})`).join("\n");
19
+ return [`# Index `, `\nIncluded Source Files (${count})`, "", items, "", "---"].join("\n");
20
+ }
21
+ /**
22
+ * Render each file section with invisible anchors
23
+ */
24
+ function renderMd(p, i) {
25
+ const rp = (0, helpers_1.rel)(p);
26
+ const ext = path_1.default.extname(p).toLowerCase();
27
+ const lang = render_constants_1.LANG_MAP[ext] || "txt";
28
+ const code = (0, helpers_1.read)(p).trimEnd();
29
+ return [`---\n#### ${i + 1}`, "\n", "` File: " + rp + "` [↑ Back to top](#index)", "", "```" + lang, code, "```", ""].join("\n");
30
+ }
31
+ /**
32
+ * TXT version (unchanged)
33
+ */
34
+ function tocTxt(files) {
35
+ const sorted = [...files].sort((a, b) => a.localeCompare(b));
36
+ return ["##==== Combined Scope ====", ...sorted.map((f) => "## - " + (0, helpers_1.rel)(f))].join("\n") + "\n\n";
37
+ }
38
+ function renderTxt(p) {
39
+ const relPath = (0, helpers_1.rel)(p);
40
+ const code = (0, helpers_1.read)(p);
41
+ return ["##==== path: " + relPath + " ====", "##region " + relPath, code, "##endregion", ""].join("\n");
42
+ }
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = startProdex;
4
+ const combine_1 = require("./core/combine");
5
+ const init_1 = require("./cli/init");
6
+ const cli_input_1 = require("./cli/cli-input");
7
+ const config_loader_1 = require("./constants/config-loader");
8
+ require("./lib/polyfills");
9
+ const summary_1 = require("./cli/summary");
10
+ async function startProdex() {
11
+ const args = process.argv;
12
+ // Handle init mode
13
+ if (args.includes("init")) {
14
+ return (0, init_1.initProdex)();
15
+ }
16
+ // Parse CLI input
17
+ const { root, flags } = (0, cli_input_1.parseCliInput)(args);
18
+ // Load and merge configuration (with flag overrides)
19
+ const config = await (0, config_loader_1.loadProdexConfig)(flags, root);
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 });
26
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = void 0;
4
+ const env = () => {
5
+ const obj = { debug: process.env.PRODEX_DEBUG === "1", silent: process.env.PRODEX_SILENT === "1" };
6
+ return obj;
7
+ };
8
+ exports.logger = {
9
+ debug: (...args) => !env().silent && env().debug && console.log("\n🪶 [debug]", ...args),
10
+ info: (...args) => !env().silent && console.log("\nšŸ“Œ [info]", ...args),
11
+ warn: (...args) => !env().silent && console.warn("\nāš ļø [warn]", ...args),
12
+ error: (...args) => !env().silent && console.error("\nšŸ’„ [error]", ...args),
13
+ log: (...args) => !env().silent && console.log("\n", ...args),
14
+ };
@@ -0,0 +1,27 @@
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
+ const util_1 = __importDefault(require("util"));
7
+ if (!String.prototype.norm) {
8
+ String.prototype.norm = function () {
9
+ return this.replace(/\\/g, "/");
10
+ };
11
+ }
12
+ if (!String.prototype.clean) {
13
+ String.prototype.clean = function () {
14
+ return this.replace(/[<>:\"/\\|?*]+/g, "_");
15
+ };
16
+ }
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
+ };