prodex 1.3.0 → 1.4.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 (114) hide show
  1. package/README.md +234 -234
  2. package/dist/cli/cli-input.js +21 -26
  3. package/dist/cli/cli-input.js.map +1 -0
  4. package/dist/cli/flags.js +1 -0
  5. package/dist/cli/flags.js.map +1 -0
  6. package/dist/cli/init.js +5 -5
  7. package/dist/cli/init.js.map +1 -0
  8. package/dist/cli/picker.js +9 -7
  9. package/dist/cli/picker.js.map +1 -0
  10. package/dist/cli/summary.js +16 -9
  11. package/dist/cli/summary.js.map +1 -0
  12. package/dist/constants/cache-keys.js +12 -0
  13. package/dist/constants/cache-keys.js.map +1 -0
  14. package/dist/constants/config-loader.js +2 -2
  15. package/dist/constants/config-loader.js.map +1 -0
  16. package/dist/constants/config.js +7 -5
  17. package/dist/constants/config.js.map +1 -0
  18. package/dist/constants/default-config.js +1 -0
  19. package/dist/constants/default-config.js.map +1 -0
  20. package/dist/constants/flags.js +74 -0
  21. package/dist/constants/flags.js.map +1 -0
  22. package/dist/constants/index.js +21 -0
  23. package/dist/constants/index.js.map +1 -0
  24. package/dist/constants/render-constants.js +1 -4
  25. package/dist/constants/render-constants.js.map +1 -0
  26. package/dist/core/cache.js +54 -0
  27. package/dist/core/cache.js.map +1 -0
  28. package/dist/core/combine.js +32 -13
  29. package/dist/core/combine.js.map +1 -0
  30. package/dist/core/config-manager.js +104 -0
  31. package/dist/core/config-manager.js.map +1 -0
  32. package/dist/core/dependency.js +40 -19
  33. package/dist/core/dependency.js.map +1 -0
  34. package/dist/core/file-utils.js +1 -41
  35. package/dist/core/file-utils.js.map +1 -0
  36. package/dist/core/helpers.js +43 -38
  37. package/dist/core/helpers.js.map +1 -0
  38. package/dist/core/managers/cache.js +54 -0
  39. package/dist/core/managers/cache.js.map +1 -0
  40. package/dist/core/managers/config-manager.js +104 -0
  41. package/dist/core/managers/config-manager.js.map +1 -0
  42. package/dist/core/managers/config.js +104 -0
  43. package/dist/core/managers/config.js.map +1 -0
  44. package/dist/core/output.js +1 -0
  45. package/dist/core/output.js.map +1 -0
  46. package/dist/core/parsers/extract-imports.js +2 -7
  47. package/dist/core/parsers/extract-imports.js.map +1 -0
  48. package/dist/core/renderers.js +10 -8
  49. package/dist/core/renderers.js.map +1 -0
  50. package/dist/debug.js +14 -0
  51. package/dist/debug.js.map +1 -0
  52. package/dist/index.js +43 -13
  53. package/dist/index.js.map +1 -0
  54. package/dist/lib/logger.js +38 -9
  55. package/dist/lib/logger.js.map +1 -0
  56. package/dist/lib/polyfills.js +1 -10
  57. package/dist/lib/polyfills.js.map +1 -0
  58. package/dist/lib/prompt.js +1 -0
  59. package/dist/lib/prompt.js.map +1 -0
  60. package/dist/lib/questions.js +1 -0
  61. package/dist/lib/questions.js.map +1 -0
  62. package/dist/lib/utils.js +1 -13
  63. package/dist/lib/utils.js.map +1 -0
  64. package/dist/resolvers/js/alias-loader.js +1 -0
  65. package/dist/resolvers/js/alias-loader.js.map +1 -0
  66. package/dist/resolvers/js/extract-imports.js +46 -0
  67. package/dist/resolvers/js/extract-imports.js.map +1 -0
  68. package/dist/resolvers/js/js-resolver.js +93 -116
  69. package/dist/resolvers/js/js-resolver.js.map +1 -0
  70. package/dist/resolvers/js/resolve-alias.js +58 -0
  71. package/dist/resolvers/js/resolve-alias.js.map +1 -0
  72. package/dist/resolvers/php/bindings.js +21 -9
  73. package/dist/resolvers/php/bindings.js.map +1 -0
  74. package/dist/resolvers/php/extract-imports.js +50 -0
  75. package/dist/resolvers/php/extract-imports.js.map +1 -0
  76. package/dist/resolvers/php/patterns.js +37 -4
  77. package/dist/resolvers/php/patterns.js.map +1 -0
  78. package/dist/resolvers/php/php-resolver.js +99 -59
  79. package/dist/resolvers/php/php-resolver.js.map +1 -0
  80. package/dist/resolvers/php/psr4.js +19 -5
  81. package/dist/resolvers/php/psr4.js.map +1 -0
  82. package/dist/resolvers/shared/excludes.js +1 -0
  83. package/dist/resolvers/shared/excludes.js.map +1 -0
  84. package/dist/resolvers/shared/file-cache.js +1 -29
  85. package/dist/resolvers/shared/file-cache.js.map +1 -0
  86. package/dist/resolvers/shared/resolve-alias.js +62 -0
  87. package/dist/resolvers/shared/resolve-alias.js.map +1 -0
  88. package/dist/resolvers/shared/stats.js +3 -3
  89. package/dist/resolvers/shared/stats.js.map +1 -0
  90. package/dist/shared/collections.js +34 -0
  91. package/dist/shared/collections.js.map +1 -0
  92. package/dist/shared/index.js +20 -0
  93. package/dist/shared/index.js.map +1 -0
  94. package/dist/shared/io.js +52 -0
  95. package/dist/shared/io.js.map +1 -0
  96. package/dist/shared/patterns.js +30 -0
  97. package/dist/shared/patterns.js.map +1 -0
  98. package/dist/shared/stats.js +32 -0
  99. package/dist/shared/stats.js.map +1 -0
  100. package/dist/store.js +16 -0
  101. package/dist/store.js.map +1 -0
  102. package/dist/types/cli.types.js +1 -0
  103. package/dist/types/cli.types.js.map +1 -0
  104. package/dist/types/config.types.js +1 -0
  105. package/dist/types/config.types.js.map +1 -0
  106. package/dist/types/core.types.js +1 -0
  107. package/dist/types/core.types.js.map +1 -0
  108. package/dist/types/index.js +1 -0
  109. package/dist/types/index.js.map +1 -0
  110. package/dist/types/resolver.types.js +1 -0
  111. package/dist/types/resolver.types.js.map +1 -0
  112. package/dist/types/utils.types.js +1 -0
  113. package/dist/types/utils.types.js.map +1 -0
  114. package/package.json +5 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/core/config-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\r\nimport path from \"path\";\r\nimport { DEFAULT_PRODEX_CONFIG } from \"../constants/default-config\";\r\nimport { normalizePatterns } from \"../lib/utils\";\r\nimport { FLAG_MAP } from \"../constants/flags\";\r\nimport type { ProdexConfig, ProdexFlags, ProdexConfigFile, DeepPartial } from \"../types\";\r\nimport { logger } from \"../lib/logger\";\r\nimport { getConfig } from \"../store\";\r\n\r\n/**\r\n * 🧩 ConfigManager\r\n * Unified loader, merger, and flag applier.\r\n */\r\nexport class ConfigManager {\r\n\tstatic load(cwd: string): ProdexConfigFile {\r\n\t\tconst file = path.join(cwd, \"prodex.json\");\r\n\t\tif (!fs.existsSync(file)) return DEFAULT_PRODEX_CONFIG;\r\n\t\ttry {\r\n\t\t\treturn JSON.parse(fs.readFileSync(file, \"utf8\"));\r\n\t\t} catch {\r\n\t\t\tconsole.warn(\"⚠️ Invalid prodex.json — using defaults.\");\r\n\t\t\treturn DEFAULT_PRODEX_CONFIG;\r\n\t\t}\r\n\t}\r\n\r\n\tstatic merge(user: Partial<ProdexConfigFile>, flags?: Partial<ProdexFlags>, cwd = process.cwd()): ProdexConfig {\r\n\t\tconst merged: ProdexConfig = {\r\n\t\t\t...DEFAULT_PRODEX_CONFIG,\r\n\t\t\t...user,\r\n\t\t\toutput: { ...DEFAULT_PRODEX_CONFIG.output, ...user.output },\r\n\t\t\tentry: {\r\n\t\t\t\t...DEFAULT_PRODEX_CONFIG.entry,\r\n\t\t\t\t...user.entry,\r\n\t\t\t\tui: { ...DEFAULT_PRODEX_CONFIG.entry.ui, ...user.entry?.ui },\r\n\t\t\t},\r\n\t\t\tresolve: { ...DEFAULT_PRODEX_CONFIG.resolve, ...user.resolve },\r\n\t\t\troot: cwd,\r\n\t\t\tname: flags?.name ?? null,\r\n\t\t};\r\n\r\n\t\tthis.applyFlags(merged, flags);\r\n\t\treturn this.normalize(merged);\r\n\t}\r\n\r\n\tstatic applyFlags(cfg: ProdexConfig, flags?: Partial<ProdexFlags>) {\r\n\t\tif (!flags) return cfg;\r\n\r\n\t\tfor (const [key, val] of Object.entries(flags)) {\r\n\t\t\tif (val === undefined) continue;\r\n\t\t\tconst def = FLAG_MAP[key];\r\n\t\t\tif (def?.apply) def.apply(cfg, val);\r\n\t\t}\r\n\r\n\t\tconst hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;\r\n\t\tif (hasFiles && !flags.include) cfg.resolve.include = [];\r\n\r\n\t\treturn cfg;\r\n\t}\r\n\r\n\tstatic normalize(cfg: ProdexConfig): ProdexConfig {\r\n\t\tcfg.entry.files = normalizePatterns(cfg.entry.files);\r\n\t\t//TODO: Is there a need?\r\n\t\t// cfg.resolve.include = normalizePatterns(cfg.resolve.include);\r\n\t\t// cfg.resolve.exclude = normalizePatterns(cfg.resolve.exclude);\r\n\t\treturn cfg;\r\n\t}\r\n\r\n\tstatic persist(partial: DeepPartial<ProdexConfigFile>): void {\r\n\t\tconst cfg = getConfig();\r\n\t\tconst dest = path.join(cfg.root, \"prodex.json\");\r\n\t\tconst { root, name, ...pure } = cfg;\r\n\t\tconst merged = deepMerge(pure, partial);\r\n\r\n\t\ttry {\r\n\t\t\tfs.writeFileSync(dest, JSON.stringify(merged, null, 2) + \"\\n\", \"utf8\");\r\n\t\t\tconsole.log(`✅ Updated ${dest}`);\r\n\t\t} catch (err: any) {\r\n\t\t\tconsole.warn(\"⚠️ Failed to persist config:\", err?.message || err);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction deepMerge<T extends Record<string, any>>(base: T, patch: DeepPartial<T>): T {\r\n\tif (!patch) return base;\r\n\tconst out: any = Array.isArray(base) ? [...base] : { ...base };\r\n\tfor (const [k, v] of Object.entries(patch)) {\r\n\t\tif (v === undefined) continue;\r\n\t\tconst bv = (base as any)[k];\r\n\t\tif (Array.isArray(v)) out[k] = [...v]; // overwrite arrays\r\n\t\telse if (isPlainObject(v) && isPlainObject(bv)) out[k] = deepMerge(bv, v);\r\n\t\telse out[k] = v;\r\n\t}\r\n\treturn out;\r\n}\r\nfunction isPlainObject(x: any): x is Record<string, any> {\r\n\treturn x && typeof x === \"object\" && !Array.isArray(x);\r\n}\r\n"]}
@@ -4,20 +4,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.followChain = followChain;
7
- exports.applyincludes = applyincludes;
7
+ exports.applyIncludes = applyIncludes;
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const config_1 = require("../constants/config");
10
- const file_utils_1 = require("./file-utils");
10
+ const helpers_1 = require("./helpers");
11
11
  const logger_1 = require("../lib/logger");
12
- const utils_1 = require("../lib/utils");
12
+ const collections_1 = require("../shared/collections");
13
+ /**
14
+ * 🧩 followChain()
15
+ * Traverses all dependencies starting from the given entry files.
16
+ * Uses language-specific resolvers (JS / PHP) under the hood.
17
+ */
13
18
  async function followChain(entryFiles, cfg) {
14
19
  const limit = cfg.resolve.limit;
20
+ const resolverDepth = cfg.resolve.depth;
15
21
  logger_1.logger.debug("🧩 Following dependency chain...");
16
22
  const visited = new Set();
17
23
  const all = [];
18
24
  const expected = new Set();
19
25
  const resolved = new Set();
20
- const resolverDepth = cfg.resolve.depth;
21
26
  for (const f of entryFiles) {
22
27
  if (visited.has(f))
23
28
  continue;
@@ -26,30 +31,46 @@ async function followChain(entryFiles, cfg) {
26
31
  if (!config_1.CODE_EXTS.includes(ext))
27
32
  continue;
28
33
  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));
34
+ if (!resolver)
35
+ continue;
36
+ const params = {
37
+ filePath: f,
38
+ visited,
39
+ depth: 0,
40
+ maxDepth: resolverDepth,
41
+ };
42
+ let result = null;
43
+ try {
44
+ result = await resolver(params);
35
45
  }
46
+ catch (err) {
47
+ logger_1.logger.warn(`⚠️ Resolver failed for ${f}:`, err.message || err);
48
+ continue;
49
+ }
50
+ if (!result)
51
+ continue;
52
+ const { files, stats } = result;
53
+ all.push(...files);
54
+ stats.expected.forEach((x) => expected.add(x));
55
+ stats.resolved.forEach((x) => resolved.add(x));
36
56
  if (limit && all.length >= limit) {
37
57
  logger_1.logger.warn("⚠️ Limit reached:", limit);
38
58
  break;
39
59
  }
40
60
  }
41
61
  return {
42
- files: (0, utils_1.unique)(all),
62
+ files: (0, collections_1.unique)(all),
43
63
  stats: { expected, resolved },
44
64
  };
45
65
  }
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 });
66
+ /**
67
+ * 🧩 applyIncludes()
68
+ * Scans and appends additional files defined in config.resolve.include.
69
+ */
70
+ async function applyIncludes(cfg, files) {
71
+ const { resolve, root } = cfg;
72
+ const scan = await (0, helpers_1.globScan)(resolve.include, { cwd: root });
51
73
  logger_1.logger.debug("APPLY_include", _2j(scan));
52
- const combined = (0, utils_1.unique)([...files, ...scan.files]);
53
- ;
54
- return combined;
74
+ return (0, collections_1.unique)([...files, ...scan.files]);
55
75
  }
76
+ //# sourceMappingURL=dependency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency.js","sourceRoot":"","sources":["../../src/core/dependency.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"path\";\r\nimport { CODE_EXTS, RESOLVERS } from \"../constants/config\";\r\nimport { globScan } from \"./helpers\";\r\nimport { logger } from \"../lib/logger\";\r\nimport { unique } from \"../shared/collections\";\r\nimport type { ProdexConfig, ResolverParams, ResolverResult } from \"../types\";\r\n\r\n/**\r\n * 🧩 followChain()\r\n * Traverses all dependencies starting from the given entry files.\r\n * Uses language-specific resolvers (JS / PHP) under the hood.\r\n */\r\nexport async function followChain(entryFiles: string[], cfg: ProdexConfig) {\r\n\tconst limit = cfg.resolve.limit;\r\n\tconst resolverDepth = cfg.resolve.depth;\r\n\r\n\tlogger.debug(\"🧩 Following dependency chain...\");\r\n\r\n\tconst visited = new Set<string>();\r\n\tconst all: string[] = [];\r\n\tconst expected = new Set<string>();\r\n\tconst resolved = new Set<string>();\r\n\r\n\tfor (const f of entryFiles) {\r\n\t\tif (visited.has(f)) continue;\r\n\t\tall.push(f);\r\n\r\n\t\tconst ext = path.extname(f);\r\n\t\tif (!CODE_EXTS.includes(ext)) continue;\r\n\r\n\t\tconst resolver = RESOLVERS[ext];\r\n\t\tif (!resolver) continue;\r\n\r\n\t\tconst params: ResolverParams = {\r\n\t\t\tfilePath: f,\r\n\t\t\tvisited,\r\n\t\t\tdepth: 0,\r\n\t\t\tmaxDepth: resolverDepth,\r\n\t\t};\r\n\r\n\t\tlet result: ResolverResult | null = null;\r\n\t\ttry {\r\n\t\t\tresult = await resolver(params);\r\n\t\t} catch (err: any) {\r\n\t\t\tlogger.warn(`⚠️ Resolver failed for ${f}:`, err.message || err);\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (!result) continue;\r\n\r\n\t\tconst { files, stats } = result;\r\n\t\tall.push(...files);\r\n\t\tstats.expected.forEach((x) => expected.add(x));\r\n\t\tstats.resolved.forEach((x) => resolved.add(x));\r\n\r\n\t\tif (limit && all.length >= limit) {\r\n\t\t\tlogger.warn(\"⚠️ Limit reached:\", limit);\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\treturn {\r\n\t\tfiles: unique(all),\r\n\t\tstats: { expected, resolved },\r\n\t};\r\n}\r\n\r\n/**\r\n * 🧩 applyIncludes()\r\n * Scans and appends additional files defined in config.resolve.include.\r\n */\r\nexport async function applyIncludes(cfg: ProdexConfig, files: string[]) {\r\n\tconst { resolve, root } = cfg;\r\n\tconst scan = await globScan(resolve.include, { cwd: root });\r\n\tlogger.debug(\"APPLY_include\", _2j(scan));\r\n\treturn unique([...files, ...scan.files]);\r\n}\r\n"]}
@@ -1,41 +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.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
- }
1
+ //# sourceMappingURL=file-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-utils.js","sourceRoot":"","sources":["../../src/core/file-utils.ts"],"names":[],"mappings":"","sourcesContent":["\n\n"]}
@@ -3,47 +3,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.rel = rel;
7
- exports.read = read;
8
- exports.isExcluded = isExcluded;
9
6
  exports.walk = walk;
10
7
  exports.orderByPriority = orderByPriority;
8
+ exports.smartNaming = smartNaming;
9
+ exports.globScan = globScan;
11
10
  const fs_1 = __importDefault(require("fs"));
12
- const path_1 = __importDefault(require("path"));
13
11
  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
- }
12
+ const shared_1 = require("../shared");
13
+ const path_1 = __importDefault(require("path"));
14
+ const fast_glob_1 = __importDefault(require("fast-glob"));
15
+ const constants_1 = require("../constants");
16
+ const logger_1 = require("../lib/logger");
40
17
  /**
41
18
  * Recursive walker that respects glob exclude.
42
19
  * Returns all files under the given directory tree.
43
20
  */
44
21
  function* walk(dir, cfg, depth = 0) {
45
- const { scanDepth, entry } = cfg;
46
- const root = process.cwd();
22
+ const { root, entry: { ui: { scanDepth }, }, resolve: { exclude }, } = cfg;
47
23
  if (depth > scanDepth)
48
24
  return;
49
25
  const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
@@ -51,15 +27,15 @@ function* walk(dir, cfg, depth = 0) {
51
27
  const full = path_1.default.join(dir, e.name);
52
28
  if (e.isDirectory()) {
53
29
  // Skip excluded directories entirely
54
- const relPath = rel(full, root);
55
- if (isExcluded(relPath, entry.exclude))
30
+ const relPath = (0, shared_1.rel)(full, root);
31
+ if ((0, shared_1.isExcluded)(relPath, exclude))
56
32
  continue;
57
33
  yield* walk(full, cfg, depth + 1);
58
34
  continue;
59
35
  }
60
36
  if (e.isFile()) {
61
- const relPath = rel(full, root);
62
- if (isExcluded(relPath, entry.exclude))
37
+ const relPath = (0, shared_1.rel)(full, root);
38
+ if ((0, shared_1.isExcluded)(relPath, exclude))
63
39
  continue;
64
40
  yield full;
65
41
  }
@@ -72,10 +48,39 @@ function orderByPriority(files, priorityList = []) {
72
48
  const normal = [];
73
49
  for (const f of files) {
74
50
  const normalized = f.norm().toLowerCase();
75
- if (priorityList.some(p => micromatch_1.default.isMatch(normalized, p.toLowerCase())))
51
+ if (priorityList.some((p) => micromatch_1.default.isMatch(normalized, p.toLowerCase())))
76
52
  prioritized.push(f);
77
53
  else
78
54
  normal.push(f);
79
55
  }
80
- return [...new Set([...prioritized, ...normal])];
56
+ return (0, shared_1.unique)([...prioritized, ...normal]);
57
+ }
58
+ function smartNaming(entries) {
59
+ const names = (0, shared_1.unique)(entries.map((f) => path_1.default.basename(f, path_1.default.extname(f))));
60
+ if (names.length === 1)
61
+ return names[0];
62
+ if (names.length === 2)
63
+ return `${names[0]}-${names[1]}`;
64
+ if (names.length > 2)
65
+ return `${names[0]}-and-${names.length - 1}more`;
66
+ return "prodex";
67
+ }
68
+ /**
69
+ * Safe micromatch.scan wrapper (compatible with micromatch v4 & v5)
70
+ */
71
+ async function globScan(patterns, opts) {
72
+ const { absolute = true, cwd = process.cwd() } = opts;
73
+ if (!patterns?.length)
74
+ return { files: [] };
75
+ const files = (await (0, fast_glob_1.default)(patterns, {
76
+ cwd,
77
+ extglob: true,
78
+ dot: true,
79
+ onlyFiles: true,
80
+ ignore: constants_1.GLOBAL_IGNORE,
81
+ absolute,
82
+ })).map((f) => path_1.default.resolve(f));
83
+ logger_1.logger.debug("globScan →", _2j(files));
84
+ return { files };
81
85
  }
86
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/core/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport micromatch from \"micromatch\";\nimport { ProdexConfig } from \"../types\";\nimport { isExcluded, rel, unique } from \"../shared\";\n\nimport path from \"path\";\nimport fg, { Options } from \"fast-glob\";\n\nimport { GLOBAL_IGNORE } from \"../constants\";\nimport { logger } from \"../lib/logger\";\n\n/**\n * Recursive walker that respects glob exclude.\n * Returns all files under the given directory tree.\n */\nexport function* walk(dir, cfg: ProdexConfig, depth = 0) {\n\tconst {\n\t\troot,\n\t\tentry: {\n\t\t\tui: { scanDepth },\n\t\t},\n\t\tresolve: { exclude },\n\t} = cfg;\n\n\tif (depth > scanDepth) return;\n\n\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\tfor (const e of entries) {\n\t\tconst full = path.join(dir, e.name);\n\n\t\tif (e.isDirectory()) {\n\t\t\t// Skip excluded directories entirely\n\t\t\tconst relPath = rel(full, root);\n\t\t\tif (isExcluded(relPath, exclude)) continue;\n\t\t\tyield* walk(full, cfg, depth + 1);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (e.isFile()) {\n\t\t\tconst relPath = rel(full, root);\n\t\t\tif (isExcluded(relPath, exclude)) continue;\n\t\t\tyield full;\n\t\t}\n\t}\n}\n\nexport function orderByPriority(files, priorityList = []) {\n\tif (!priorityList.length) return files;\n\tconst prioritized = [];\n\tconst normal = [];\n\n\tfor (const f of files) {\n\t\tconst normalized = f.norm().toLowerCase();\n\t\tif (priorityList.some((p) => micromatch.isMatch(normalized, p.toLowerCase()))) prioritized.push(f);\n\t\telse normal.push(f);\n\t}\n\n\treturn unique([...prioritized, ...normal]);\n}\nexport function smartNaming(entries: string[]): string {\n\tconst names = unique(entries.map((f) => path.basename(f, path.extname(f))));\n\tif (names.length === 1) return names[0];\n\tif (names.length === 2) return `${names[0]}-${names[1]}`;\n\tif (names.length > 2) return `${names[0]}-and-${names.length - 1}more`;\n\treturn \"prodex\";\n}\n\n\n\n/**\n * Safe micromatch.scan wrapper (compatible with micromatch v4 & v5)\n */\n\nexport async function globScan(patterns: string[], opts: Options) {\n\tconst { absolute = true, cwd = process.cwd() } = opts;\n\n\tif (!patterns?.length) return { files: [] };\n\tconst files = (\n\t\tawait fg(patterns, {\n\t\t\tcwd,\n\t\t\textglob: true,\n\t\t\tdot: true,\n\t\t\tonlyFiles: true,\n\t\t\tignore: GLOBAL_IGNORE,\n\t\t\tabsolute,\n\t\t})\n\t).map((f) => path.resolve(f));\n\tlogger.debug(\"globScan →\", _2j(files));\n\n\treturn { files };\n}\n"]}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CacheManager = void 0;
4
+ const logger_1 = require("../../lib/logger");
5
+ /**
6
+ * 🧩 CacheManager
7
+ * Unified in-memory registry for all runtime maps.
8
+ *
9
+ * - Namespaced storage (e.g., "aliases", "stats", "resolver")
10
+ * - Purely in-memory (no file I/O)
11
+ * - Static API for symmetry with ConfigManager
12
+ */
13
+ class CacheManager {
14
+ static registry = new Map();
15
+ /** Ensure namespace map exists and return it */
16
+ static ns(ns) {
17
+ if (!this.registry.has(ns))
18
+ this.registry.set(ns, new Map());
19
+ return this.registry.get(ns);
20
+ }
21
+ /** Set or update a cached entry */
22
+ static set(ns, key, val) {
23
+ this.ns(ns).set(key, val);
24
+ logger_1.logger.debug(`🧩 [cache:${ns}] set ${key} → ${String(val)}`);
25
+ }
26
+ /** Retrieve a cached entry */
27
+ static get(ns, key) {
28
+ return this.ns(ns).get(key);
29
+ }
30
+ /** Remove all entries from one namespace or from all */
31
+ static clear(ns) {
32
+ if (ns) {
33
+ this.ns(ns).clear();
34
+ logger_1.logger.debug(`🧩 [cache:${ns}] cleared`);
35
+ }
36
+ else {
37
+ this.registry.forEach((m) => m.clear());
38
+ logger_1.logger.debug("🧩 [cache] cleared all namespaces");
39
+ }
40
+ }
41
+ /** Export a namespace as a plain object (for persistence or inspection) */
42
+ static dump(ns) {
43
+ return Object.fromEntries(this.ns(ns).entries());
44
+ }
45
+ /** Return count of entries per namespace */
46
+ static stats() {
47
+ const summary = {};
48
+ for (const [name, map] of this.registry)
49
+ summary[name] = map.size;
50
+ return summary;
51
+ }
52
+ }
53
+ exports.CacheManager = CacheManager;
54
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/core/managers/cache.ts"],"names":[],"mappings":";;;AAAA,6CAA0C;AAE1C;;;;;;;GAOG;AACH,MAAa,YAAY;IAChB,MAAM,CAAC,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAC;IAE9D,gDAAgD;IACxC,MAAM,CAAC,EAAE,CAAC,EAAU;QAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;IAC/B,CAAC;IAED,mCAAmC;IACnC,MAAM,CAAC,GAAG,CAAU,EAAU,EAAE,GAAW,EAAE,GAAM;QAClD,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1B,eAAM,CAAC,KAAK,CAAC,aAAa,EAAE,SAAS,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,8BAA8B;IAC9B,MAAM,CAAC,GAAG,CAAU,EAAU,EAAE,GAAW;QAC1C,OAAO,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,wDAAwD;IACxD,MAAM,CAAC,KAAK,CAAC,EAAW;QACvB,IAAI,EAAE,EAAE,CAAC;YACR,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;YACpB,eAAM,CAAC,KAAK,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YACxC,eAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACnD,CAAC;IACF,CAAC;IAED,2EAA2E;IAC3E,MAAM,CAAC,IAAI,CAAC,EAAU;QACrB,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,4CAA4C;IAC5C,MAAM,CAAC,KAAK;QACX,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;QAClE,OAAO,OAAO,CAAC;IAChB,CAAC;;AAzCF,oCA0CC","sourcesContent":["import { logger } from \"../../lib/logger\";\r\n\r\n/**\r\n * 🧩 CacheManager\r\n * Unified in-memory registry for all runtime maps.\r\n *\r\n * - Namespaced storage (e.g., \"aliases\", \"stats\", \"resolver\")\r\n * - Purely in-memory (no file I/O)\r\n * - Static API for symmetry with ConfigManager\r\n */\r\nexport class CacheManager {\r\n\tprivate static registry = new Map<string, Map<string, any>>();\r\n\r\n\t/** Ensure namespace map exists and return it */\r\n\tprivate static ns(ns: string): Map<string, any> {\r\n\t\tif (!this.registry.has(ns)) this.registry.set(ns, new Map());\r\n\t\treturn this.registry.get(ns)!;\r\n\t}\r\n\r\n\t/** Set or update a cached entry */\r\n\tstatic set<T = any>(ns: string, key: string, val: T): void {\r\n\t\tthis.ns(ns).set(key, val);\r\n\t\tlogger.debug(`🧩 [cache:${ns}] set ${key} → ${String(val)}`);\r\n\t}\r\n\r\n\t/** Retrieve a cached entry */\r\n\tstatic get<T = any>(ns: string, key: string): T | undefined {\r\n\t\treturn this.ns(ns).get(key);\r\n\t}\r\n\r\n\t/** Remove all entries from one namespace or from all */\r\n\tstatic clear(ns?: string): void {\r\n\t\tif (ns) {\r\n\t\t\tthis.ns(ns).clear();\r\n\t\t\tlogger.debug(`🧩 [cache:${ns}] cleared`);\r\n\t\t} else {\r\n\t\t\tthis.registry.forEach((m) => m.clear());\r\n\t\t\tlogger.debug(\"🧩 [cache] cleared all namespaces\");\r\n\t\t}\r\n\t}\r\n\r\n\t/** Export a namespace as a plain object (for persistence or inspection) */\r\n\tstatic dump(ns: string): Record<string, any> {\r\n\t\treturn Object.fromEntries(this.ns(ns).entries());\r\n\t}\r\n\r\n\t/** Return count of entries per namespace */\r\n\tstatic stats(): Record<string, number> {\r\n\t\tconst summary: Record<string, number> = {};\r\n\t\tfor (const [name, map] of this.registry) summary[name] = map.size;\r\n\t\treturn summary;\r\n\t}\r\n}\r\n"]}
@@ -0,0 +1,104 @@
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.ConfigManager = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const default_config_1 = require("../../constants/default-config");
10
+ const utils_1 = require("../../lib/utils");
11
+ const flags_1 = require("../../constants/flags");
12
+ const store_1 = require("../../store");
13
+ /**
14
+ * 🧩 ConfigManager
15
+ * Unified loader, merger, and flag applier.
16
+ */
17
+ class ConfigManager {
18
+ static load(cwd) {
19
+ const file = path_1.default.join(cwd, "prodex.json");
20
+ if (!fs_1.default.existsSync(file))
21
+ return default_config_1.DEFAULT_PRODEX_CONFIG;
22
+ try {
23
+ return JSON.parse(fs_1.default.readFileSync(file, "utf8"));
24
+ }
25
+ catch {
26
+ console.warn("⚠️ Invalid prodex.json — using defaults.");
27
+ return default_config_1.DEFAULT_PRODEX_CONFIG;
28
+ }
29
+ }
30
+ static merge(user, flags, cwd = process.cwd()) {
31
+ const merged = {
32
+ ...default_config_1.DEFAULT_PRODEX_CONFIG,
33
+ ...user,
34
+ output: { ...default_config_1.DEFAULT_PRODEX_CONFIG.output, ...user.output },
35
+ entry: {
36
+ ...default_config_1.DEFAULT_PRODEX_CONFIG.entry,
37
+ ...user.entry,
38
+ ui: { ...default_config_1.DEFAULT_PRODEX_CONFIG.entry.ui, ...user.entry?.ui },
39
+ },
40
+ resolve: { ...default_config_1.DEFAULT_PRODEX_CONFIG.resolve, ...user.resolve },
41
+ root: cwd,
42
+ name: flags?.name ?? null,
43
+ };
44
+ this.applyFlags(merged, flags);
45
+ return this.normalize(merged);
46
+ }
47
+ static applyFlags(cfg, flags) {
48
+ if (!flags)
49
+ return cfg;
50
+ for (const [key, val] of Object.entries(flags)) {
51
+ if (val === undefined)
52
+ continue;
53
+ const def = flags_1.FLAG_MAP[key];
54
+ if (def?.apply)
55
+ def.apply(cfg, val);
56
+ }
57
+ const hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;
58
+ if (hasFiles && !flags.include)
59
+ cfg.resolve.include = [];
60
+ return cfg;
61
+ }
62
+ static normalize(cfg) {
63
+ cfg.entry.files = (0, utils_1.normalizePatterns)(cfg.entry.files);
64
+ //TODO: Is there a need?
65
+ // cfg.resolve.include = normalizePatterns(cfg.resolve.include);
66
+ // cfg.resolve.exclude = normalizePatterns(cfg.resolve.exclude);
67
+ return cfg;
68
+ }
69
+ static persist(partial) {
70
+ const cfg = (0, store_1.getConfig)();
71
+ const dest = path_1.default.join(cfg.root, "prodex.json");
72
+ const { root, name, ...pure } = cfg;
73
+ const merged = deepMerge(pure, partial);
74
+ try {
75
+ fs_1.default.writeFileSync(dest, JSON.stringify(merged, null, 2) + "\n", "utf8");
76
+ console.log(`✅ Updated ${dest}`);
77
+ }
78
+ catch (err) {
79
+ console.warn("⚠️ Failed to persist config:", err?.message || err);
80
+ }
81
+ }
82
+ }
83
+ exports.ConfigManager = ConfigManager;
84
+ function deepMerge(base, patch) {
85
+ if (!patch)
86
+ return base;
87
+ const out = Array.isArray(base) ? [...base] : { ...base };
88
+ for (const [k, v] of Object.entries(patch)) {
89
+ if (v === undefined)
90
+ continue;
91
+ const bv = base[k];
92
+ if (Array.isArray(v))
93
+ out[k] = [...v]; // overwrite arrays
94
+ else if (isPlainObject(v) && isPlainObject(bv))
95
+ out[k] = deepMerge(bv, v);
96
+ else
97
+ out[k] = v;
98
+ }
99
+ return out;
100
+ }
101
+ function isPlainObject(x) {
102
+ return x && typeof x === "object" && !Array.isArray(x);
103
+ }
104
+ //# sourceMappingURL=config-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../../src/core/managers/config-manager.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,gDAAwB;AACxB,mEAAuE;AACvE,2CAAoD;AACpD,iDAAiD;AAGjD,uCAAwC;AAExC;;;GAGG;AACH,MAAa,aAAa;IACzB,MAAM,CAAC,IAAI,CAAC,GAAW;QACtB,MAAM,IAAI,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAC3C,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,sCAAqB,CAAC;QACvD,IAAI,CAAC;YACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;YACzD,OAAO,sCAAqB,CAAC;QAC9B,CAAC;IACF,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,IAA+B,EAAE,KAA4B,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;QAC9F,MAAM,MAAM,GAAiB;YAC5B,GAAG,sCAAqB;YACxB,GAAG,IAAI;YACP,MAAM,EAAE,EAAE,GAAG,sCAAqB,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;YAC3D,KAAK,EAAE;gBACN,GAAG,sCAAqB,CAAC,KAAK;gBAC9B,GAAG,IAAI,CAAC,KAAK;gBACb,EAAE,EAAE,EAAE,GAAG,sCAAqB,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE;aAC5D;YACD,OAAO,EAAE,EAAE,GAAG,sCAAqB,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE;YAC9D,IAAI,EAAE,GAAG;YACT,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,IAAI;SACzB,CAAC;QAEF,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,GAAiB,EAAE,KAA4B;QAChE,IAAI,CAAC,KAAK;YAAE,OAAO,GAAG,CAAC;QAEvB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChD,IAAI,GAAG,KAAK,SAAS;gBAAE,SAAS;YAChC,MAAM,GAAG,GAAG,gBAAQ,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,GAAG,EAAE,KAAK;gBAAE,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACrC,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;QACrF,IAAI,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,EAAE,CAAC;QAEzD,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,CAAC,SAAS,CAAC,GAAiB;QACjC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,IAAA,yBAAiB,EAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrD,wBAAwB;QACxB,gEAAgE;QAChE,gEAAgE;QAChE,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,OAAsC;QACpD,MAAM,GAAG,GAAG,IAAA,iBAAS,GAAE,CAAC;QACxB,MAAM,IAAI,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QAChD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC;QACpC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAExC,IAAI,CAAC;YACJ,YAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC;QACnE,CAAC;IACF,CAAC;CACD;AAnED,sCAmEC;AAED,SAAS,SAAS,CAAgC,IAAO,EAAE,KAAqB;IAC/E,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,GAAG,GAAQ,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC;IAC/D,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QAC9B,MAAM,EAAE,GAAI,IAAY,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB;aACrD,IAAI,aAAa,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,EAAE,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;;YACrE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AACD,SAAS,aAAa,CAAC,CAAM;IAC5B,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC","sourcesContent":["import fs from \"fs\";\r\nimport path from \"path\";\r\nimport { DEFAULT_PRODEX_CONFIG } from \"../../constants/default-config\";\r\nimport { normalizePatterns } from \"../../lib/utils\";\r\nimport { FLAG_MAP } from \"../../constants/flags\";\r\nimport type { ProdexConfig, ProdexFlags, ProdexConfigFile, DeepPartial } from \"../../types\";\r\nimport { logger } from \"../../lib/logger\";\r\nimport { getConfig } from \"../../store\";\r\n\r\n/**\r\n * 🧩 ConfigManager\r\n * Unified loader, merger, and flag applier.\r\n */\r\nexport class ConfigManager {\r\n\tstatic load(cwd: string): ProdexConfigFile {\r\n\t\tconst file = path.join(cwd, \"prodex.json\");\r\n\t\tif (!fs.existsSync(file)) return DEFAULT_PRODEX_CONFIG;\r\n\t\ttry {\r\n\t\t\treturn JSON.parse(fs.readFileSync(file, \"utf8\"));\r\n\t\t} catch {\r\n\t\t\tconsole.warn(\"⚠️ Invalid prodex.json — using defaults.\");\r\n\t\t\treturn DEFAULT_PRODEX_CONFIG;\r\n\t\t}\r\n\t}\r\n\r\n\tstatic merge(user: Partial<ProdexConfigFile>, flags?: Partial<ProdexFlags>, cwd = process.cwd()): ProdexConfig {\r\n\t\tconst merged: ProdexConfig = {\r\n\t\t\t...DEFAULT_PRODEX_CONFIG,\r\n\t\t\t...user,\r\n\t\t\toutput: { ...DEFAULT_PRODEX_CONFIG.output, ...user.output },\r\n\t\t\tentry: {\r\n\t\t\t\t...DEFAULT_PRODEX_CONFIG.entry,\r\n\t\t\t\t...user.entry,\r\n\t\t\t\tui: { ...DEFAULT_PRODEX_CONFIG.entry.ui, ...user.entry?.ui },\r\n\t\t\t},\r\n\t\t\tresolve: { ...DEFAULT_PRODEX_CONFIG.resolve, ...user.resolve },\r\n\t\t\troot: cwd,\r\n\t\t\tname: flags?.name ?? null,\r\n\t\t};\r\n\r\n\t\tthis.applyFlags(merged, flags);\r\n\t\treturn this.normalize(merged);\r\n\t}\r\n\r\n\tstatic applyFlags(cfg: ProdexConfig, flags?: Partial<ProdexFlags>) {\r\n\t\tif (!flags) return cfg;\r\n\r\n\t\tfor (const [key, val] of Object.entries(flags)) {\r\n\t\t\tif (val === undefined) continue;\r\n\t\t\tconst def = FLAG_MAP[key];\r\n\t\t\tif (def?.apply) def.apply(cfg, val);\r\n\t\t}\r\n\r\n\t\tconst hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;\r\n\t\tif (hasFiles && !flags.include) cfg.resolve.include = [];\r\n\r\n\t\treturn cfg;\r\n\t}\r\n\r\n\tstatic normalize(cfg: ProdexConfig): ProdexConfig {\r\n\t\tcfg.entry.files = normalizePatterns(cfg.entry.files);\r\n\t\t//TODO: Is there a need?\r\n\t\t// cfg.resolve.include = normalizePatterns(cfg.resolve.include);\r\n\t\t// cfg.resolve.exclude = normalizePatterns(cfg.resolve.exclude);\r\n\t\treturn cfg;\r\n\t}\r\n\r\n\tstatic persist(partial: DeepPartial<ProdexConfigFile>): void {\r\n\t\tconst cfg = getConfig();\r\n\t\tconst dest = path.join(cfg.root, \"prodex.json\");\r\n\t\tconst { root, name, ...pure } = cfg;\r\n\t\tconst merged = deepMerge(pure, partial);\r\n\r\n\t\ttry {\r\n\t\t\tfs.writeFileSync(dest, JSON.stringify(merged, null, 2) + \"\\n\", \"utf8\");\r\n\t\t\tconsole.log(`✅ Updated ${dest}`);\r\n\t\t} catch (err: any) {\r\n\t\t\tconsole.warn(\"⚠️ Failed to persist config:\", err?.message || err);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction deepMerge<T extends Record<string, any>>(base: T, patch: DeepPartial<T>): T {\r\n\tif (!patch) return base;\r\n\tconst out: any = Array.isArray(base) ? [...base] : { ...base };\r\n\tfor (const [k, v] of Object.entries(patch)) {\r\n\t\tif (v === undefined) continue;\r\n\t\tconst bv = (base as any)[k];\r\n\t\tif (Array.isArray(v)) out[k] = [...v]; // overwrite arrays\r\n\t\telse if (isPlainObject(v) && isPlainObject(bv)) out[k] = deepMerge(bv, v);\r\n\t\telse out[k] = v;\r\n\t}\r\n\treturn out;\r\n}\r\nfunction isPlainObject(x: any): x is Record<string, any> {\r\n\treturn x && typeof x === \"object\" && !Array.isArray(x);\r\n}\r\n"]}
@@ -0,0 +1,104 @@
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.ConfigManager = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const default_config_1 = require("../../constants/default-config");
10
+ const utils_1 = require("../../lib/utils");
11
+ const flags_1 = require("../../constants/flags");
12
+ const store_1 = require("../../store");
13
+ /**
14
+ * 🧩 ConfigManager
15
+ * Unified loader, merger, and flag applier.
16
+ */
17
+ class ConfigManager {
18
+ static load(cwd) {
19
+ const file = path_1.default.join(cwd, "prodex.json");
20
+ if (!fs_1.default.existsSync(file))
21
+ return default_config_1.DEFAULT_PRODEX_CONFIG;
22
+ try {
23
+ return JSON.parse(fs_1.default.readFileSync(file, "utf8"));
24
+ }
25
+ catch {
26
+ console.warn("⚠️ Invalid prodex.json — using defaults.");
27
+ return default_config_1.DEFAULT_PRODEX_CONFIG;
28
+ }
29
+ }
30
+ static merge(user, flags, cwd = process.cwd()) {
31
+ const merged = {
32
+ ...default_config_1.DEFAULT_PRODEX_CONFIG,
33
+ ...user,
34
+ output: { ...default_config_1.DEFAULT_PRODEX_CONFIG.output, ...user.output },
35
+ entry: {
36
+ ...default_config_1.DEFAULT_PRODEX_CONFIG.entry,
37
+ ...user.entry,
38
+ ui: { ...default_config_1.DEFAULT_PRODEX_CONFIG.entry.ui, ...user.entry?.ui },
39
+ },
40
+ resolve: { ...default_config_1.DEFAULT_PRODEX_CONFIG.resolve, ...user.resolve },
41
+ root: cwd,
42
+ name: flags?.name ?? null,
43
+ };
44
+ this.applyFlags(merged, flags);
45
+ return this.normalize(merged);
46
+ }
47
+ static applyFlags(cfg, flags) {
48
+ if (!flags)
49
+ return cfg;
50
+ for (const [key, val] of Object.entries(flags)) {
51
+ if (val === undefined)
52
+ continue;
53
+ const def = flags_1.FLAG_MAP[key];
54
+ if (def?.apply)
55
+ def.apply(cfg, val);
56
+ }
57
+ const hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;
58
+ if (hasFiles && !flags.include)
59
+ cfg.resolve.include = [];
60
+ return cfg;
61
+ }
62
+ static normalize(cfg) {
63
+ cfg.entry.files = (0, utils_1.normalizePatterns)(cfg.entry.files);
64
+ //TODO: Is there a need?
65
+ // cfg.resolve.include = normalizePatterns(cfg.resolve.include);
66
+ // cfg.resolve.exclude = normalizePatterns(cfg.resolve.exclude);
67
+ return cfg;
68
+ }
69
+ static persist(partial) {
70
+ const cfg = (0, store_1.getConfig)();
71
+ const dest = path_1.default.join(cfg.root, "prodex.json");
72
+ const { root, name, ...pure } = cfg;
73
+ const merged = deepMerge(pure, partial);
74
+ try {
75
+ fs_1.default.writeFileSync(dest, JSON.stringify(merged, null, 2) + "\n", "utf8");
76
+ console.log(`✅ Updated ${dest}`);
77
+ }
78
+ catch (err) {
79
+ console.warn("⚠️ Failed to persist config:", err?.message || err);
80
+ }
81
+ }
82
+ }
83
+ exports.ConfigManager = ConfigManager;
84
+ function deepMerge(base, patch) {
85
+ if (!patch)
86
+ return base;
87
+ const out = Array.isArray(base) ? [...base] : { ...base };
88
+ for (const [k, v] of Object.entries(patch)) {
89
+ if (v === undefined)
90
+ continue;
91
+ const bv = base[k];
92
+ if (Array.isArray(v))
93
+ out[k] = [...v]; // overwrite arrays
94
+ else if (isPlainObject(v) && isPlainObject(bv))
95
+ out[k] = deepMerge(bv, v);
96
+ else
97
+ out[k] = v;
98
+ }
99
+ return out;
100
+ }
101
+ function isPlainObject(x) {
102
+ return x && typeof x === "object" && !Array.isArray(x);
103
+ }
104
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/core/managers/config.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\r\nimport path from \"path\";\r\nimport { DEFAULT_PRODEX_CONFIG } from \"../../constants/default-config\";\r\nimport { normalizePatterns } from \"../../lib/utils\";\r\nimport { FLAG_MAP } from \"../../constants/flags\";\r\nimport type { ProdexConfig, ProdexFlags, ProdexConfigFile, DeepPartial } from \"../../types\";\r\nimport { logger } from \"../../lib/logger\";\r\nimport { getConfig } from \"../../store\";\r\n\r\n/**\r\n * 🧩 ConfigManager\r\n * Unified loader, merger, and flag applier.\r\n */\r\nexport class ConfigManager {\r\n\tstatic load(cwd: string): ProdexConfigFile {\r\n\t\tconst file = path.join(cwd, \"prodex.json\");\r\n\t\tif (!fs.existsSync(file)) return DEFAULT_PRODEX_CONFIG;\r\n\t\ttry {\r\n\t\t\treturn JSON.parse(fs.readFileSync(file, \"utf8\"));\r\n\t\t} catch {\r\n\t\t\tconsole.warn(\"⚠️ Invalid prodex.json — using defaults.\");\r\n\t\t\treturn DEFAULT_PRODEX_CONFIG;\r\n\t\t}\r\n\t}\r\n\r\n\tstatic merge(user: Partial<ProdexConfigFile>, flags?: Partial<ProdexFlags>, cwd = process.cwd()): ProdexConfig {\r\n\t\tconst merged: ProdexConfig = {\r\n\t\t\t...DEFAULT_PRODEX_CONFIG,\r\n\t\t\t...user,\r\n\t\t\toutput: { ...DEFAULT_PRODEX_CONFIG.output, ...user.output },\r\n\t\t\tentry: {\r\n\t\t\t\t...DEFAULT_PRODEX_CONFIG.entry,\r\n\t\t\t\t...user.entry,\r\n\t\t\t\tui: { ...DEFAULT_PRODEX_CONFIG.entry.ui, ...user.entry?.ui },\r\n\t\t\t},\r\n\t\t\tresolve: { ...DEFAULT_PRODEX_CONFIG.resolve, ...user.resolve },\r\n\t\t\troot: cwd,\r\n\t\t\tname: flags?.name ?? null,\r\n\t\t};\r\n\r\n\t\tthis.applyFlags(merged, flags);\r\n\t\treturn this.normalize(merged);\r\n\t}\r\n\r\n\tstatic applyFlags(cfg: ProdexConfig, flags?: Partial<ProdexFlags>) {\r\n\t\tif (!flags) return cfg;\r\n\r\n\t\tfor (const [key, val] of Object.entries(flags)) {\r\n\t\t\tif (val === undefined) continue;\r\n\t\t\tconst def = FLAG_MAP[key];\r\n\t\t\tif (def?.apply) def.apply(cfg, val);\r\n\t\t}\r\n\r\n\t\tconst hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;\r\n\t\tif (hasFiles && !flags.include) cfg.resolve.include = [];\r\n\r\n\t\treturn cfg;\r\n\t}\r\n\r\n\tstatic normalize(cfg: ProdexConfig): ProdexConfig {\r\n\t\tcfg.entry.files = normalizePatterns(cfg.entry.files);\r\n\t\t//TODO: Is there a need?\r\n\t\t// cfg.resolve.include = normalizePatterns(cfg.resolve.include);\r\n\t\t// cfg.resolve.exclude = normalizePatterns(cfg.resolve.exclude);\r\n\t\treturn cfg;\r\n\t}\r\n\r\n\tstatic persist(partial: DeepPartial<ProdexConfigFile>): void {\r\n\t\tconst cfg = getConfig();\r\n\t\tconst dest = path.join(cfg.root, \"prodex.json\");\r\n\t\tconst { root, name, ...pure } = cfg;\r\n\t\tconst merged = deepMerge(pure, partial);\r\n\r\n\t\ttry {\r\n\t\t\tfs.writeFileSync(dest, JSON.stringify(merged, null, 2) + \"\\n\", \"utf8\");\r\n\t\t\tconsole.log(`✅ Updated ${dest}`);\r\n\t\t} catch (err: any) {\r\n\t\t\tconsole.warn(\"⚠️ Failed to persist config:\", err?.message || err);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction deepMerge<T extends Record<string, any>>(base: T, patch: DeepPartial<T>): T {\r\n\tif (!patch) return base;\r\n\tconst out: any = Array.isArray(base) ? [...base] : { ...base };\r\n\tfor (const [k, v] of Object.entries(patch)) {\r\n\t\tif (v === undefined) continue;\r\n\t\tconst bv = (base as any)[k];\r\n\t\tif (Array.isArray(v)) out[k] = [...v]; // overwrite arrays\r\n\t\telse if (isPlainObject(v) && isPlainObject(bv)) out[k] = deepMerge(bv, v);\r\n\t\telse out[k] = v;\r\n\t}\r\n\treturn out;\r\n}\r\nfunction isPlainObject(x: any): x is Record<string, any> {\r\n\treturn x && typeof x === \"object\" && !Array.isArray(x);\r\n}\r\n"]}
@@ -46,3 +46,4 @@ async function produceOutput({ name, files, cfg, showUi }) {
46
46
  fs_1.default.writeFileSync(outputPath, content, "utf8");
47
47
  return outputPath;
48
48
  }
49
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/core/output.ts"],"names":[],"mappings":";;;;;AAgBA,sCAkCC;AAlDD,4CAAoB;AACpB,gDAAwB;AACxB,0CAAuC;AACvC,2CAAiE;AACjE,0CAAuC;AAEvC,wCAA8C;AAC9C,gDAAwD;AACxD,oEAA0D;AAC1D,gDAA6C;AAE7C;;;;GAIG;AACI,KAAK,UAAU,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAgB;IAC7E,MAAM,EACL,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,GAClC,GAAG,GAAG,CAAC;IAER,CAAC;IAED,8BAA8B;IAC9B,IAAI,UAAU,GAAG,IAAI,CAAC;IACtB,IAAI,MAAM,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,MAAM,IAAA,eAAM,EAAyB,gCAAoB,CAAC,CAAC;QAC1E,IAAI,MAAM,EAAE,UAAU;YAAE,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACxD,CAAC;IAED,oCAAoC;IACpC,UAAU,GAAG,GAAG,UAAU,IAAI,eAAM,EAAE,CAAC;IACvC,IAAI,SAAS;QAAE,UAAU,GAAG,GAAG,UAAU,IAAI,IAAA,sBAAc,GAAE,EAAE,CAAC;IAEhE,8BAA8B;IAC9B,IAAI,CAAC;QACJ,YAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACR,eAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;IAED,gCAAgC;IAChC,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,IAAI,MAAM,EAAE,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAA,kBAAM,EAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,qBAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAA,iBAAK,EAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAA,oBAAQ,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,4BAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAExK,YAAE,CAAC,aAAa,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAE9C,OAAO,UAAU,CAAC;AACnB,CAAC","sourcesContent":["import fs from \"fs\";\r\nimport path from \"path\";\r\nimport { prompt } from \"../lib/prompt\";\r\nimport { renderMd, renderTxt, tocMd, tocTxt } from \"./renderers\";\r\nimport { logger } from \"../lib/logger\";\r\nimport type { OutputParams } from \"../types\";\r\nimport { shortTimestamp } from \"../lib/utils\";\r\nimport { OUTPUT_NAME_QUESTION } from \"../lib/questions\";\r\nimport { MD_FOOTER } from \"../constants/render-constants\";\r\nimport { SUFFIX } from \"../constants/config\";\r\n\r\n/**\r\n * 🧩 produceOutput()\r\n * Handles rendering and writing of the final trace file.\r\n * Receives resolved files and configuration from combine.ts.\r\n */\r\nexport async function produceOutput({ name, files, cfg, showUi }: OutputParams): Promise<string> {\r\n\tconst {\r\n\t\toutput: { format, versioned, dir },\r\n\t} = cfg;\r\n\r\n\t;\r\n\r\n\t// 1️⃣ Determine base filename\r\n\tlet outputBase = name;\r\n\tif (showUi) {\r\n\t\tconst result = await prompt<{ outputBase: string }>(OUTPUT_NAME_QUESTION);\r\n\t\tif (result?.outputBase) outputBase = result.outputBase;\r\n\t}\r\n\r\n\t// 2️⃣ Prefix timestamp if versioned\r\n\toutputBase = `${outputBase}-${SUFFIX}`;\r\n\tif (versioned) outputBase = `${outputBase}_${shortTimestamp()}`;\r\n\r\n\t// 3️⃣ Ensure output directory\r\n\ttry {\r\n\t\tfs.mkdirSync(dir, { recursive: true });\r\n\t} catch {\r\n\t\tlogger.warn(\"Could not create dir directory:\", dir);\r\n\t}\r\n\r\n\t// 4️⃣ Prepare and write content\r\n\tconst outputPath = path.join(dir, `${outputBase}.${format}`);\r\n\r\n\tconst sorted = [...files].sort((a, b) => a.localeCompare(b));\r\n\tconst content = format === \"txt\" ? [tocTxt(sorted), ...sorted.map(renderTxt)].join(\"\") : [tocMd(sorted), ...sorted.map((f, i) => renderMd(f, i)), MD_FOOTER].join(\"\\n\");\r\n\r\n\tfs.writeFileSync(outputPath, content, \"utf8\");\r\n\r\n\treturn outputPath;\r\n}\r\n"]}