prodex 1.4.11 → 2.0.1

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 (142) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +240 -234
  3. package/bin/prodex.js +0 -0
  4. package/dist/app/execute-run.d.ts +2 -0
  5. package/dist/app/execute-run.js +74 -0
  6. package/dist/app/project-context.d.ts +12 -0
  7. package/dist/app/project-context.js +48 -0
  8. package/dist/app/run-plans.d.ts +11 -0
  9. package/dist/app/run-plans.js +61 -0
  10. package/dist/cache/cache-keys.d.ts +9 -0
  11. package/dist/cache/cache-manager.d.ts +9 -0
  12. package/dist/{core/managers/cache.js → cache/cache-manager.js} +5 -18
  13. package/dist/cli/cli-input.d.ts +2 -0
  14. package/dist/cli/cli-input.js +138 -124
  15. package/dist/cli/flag-specs.d.ts +12 -0
  16. package/dist/cli/flag-specs.js +28 -0
  17. package/dist/cli/help.d.ts +2 -0
  18. package/dist/cli/help.js +83 -0
  19. package/dist/cli/report-command.d.ts +2 -0
  20. package/dist/cli/report-command.js +101 -0
  21. package/dist/cli/reporter.d.ts +2 -0
  22. package/dist/cli/reporter.js +8 -0
  23. package/dist/commands/init-command.d.ts +1 -0
  24. package/dist/commands/init-command.js +9 -0
  25. package/dist/commands/migrate-command.d.ts +7 -0
  26. package/dist/commands/migrate-command.js +76 -0
  27. package/dist/commands/profiles-command.d.ts +6 -0
  28. package/dist/commands/profiles-command.js +16 -0
  29. package/dist/commands/run-command.d.ts +11 -0
  30. package/dist/commands/run-command.js +17 -0
  31. package/dist/config/build-config.d.ts +13 -0
  32. package/dist/config/build-config.js +127 -0
  33. package/dist/config/create-default-config.d.ts +9 -0
  34. package/dist/config/create-default-config.js +25 -0
  35. package/dist/config/default-config.d.ts +2 -0
  36. package/dist/config/default-config.js +23 -0
  37. package/dist/config/json.d.ts +2 -0
  38. package/dist/config/json.js +10 -0
  39. package/dist/config/load.d.ts +9 -0
  40. package/dist/config/load.js +48 -0
  41. package/dist/config/migration/detect.d.ts +4 -0
  42. package/dist/config/migration/detect.js +22 -0
  43. package/dist/config/migration/index.d.ts +4 -0
  44. package/dist/{shared → config/migration}/index.js +4 -3
  45. package/dist/config/migration/messages.d.ts +2 -0
  46. package/dist/config/migration/messages.js +35 -0
  47. package/dist/config/migration/transform.d.ts +2 -0
  48. package/dist/config/migration/transform.js +80 -0
  49. package/dist/config/migration/types.d.ts +16 -0
  50. package/dist/config/string-list.d.ts +2 -0
  51. package/dist/config/string-list.js +17 -0
  52. package/dist/diagnostics/logger.d.ts +3 -0
  53. package/dist/diagnostics/logger.js +33 -0
  54. package/dist/filesystem/glob-scan.d.ts +4 -0
  55. package/dist/filesystem/glob-scan.js +26 -0
  56. package/dist/filesystem/inspect.d.ts +1 -0
  57. package/dist/filesystem/inspect.js +15 -0
  58. package/dist/filesystem/path.d.ts +2 -0
  59. package/dist/filesystem/path.js +11 -0
  60. package/dist/filesystem/read-file.d.ts +8 -0
  61. package/dist/{shared/io.js → filesystem/read-file.js} +0 -25
  62. package/dist/filesystem/stat-cache.d.ts +1 -0
  63. package/dist/filesystem/stat-cache.js +22 -0
  64. package/dist/index.d.ts +3 -0
  65. package/dist/index.js +76 -83
  66. package/dist/output/markdown.d.ts +12 -0
  67. package/dist/output/markdown.js +150 -0
  68. package/dist/output/naming.d.ts +2 -0
  69. package/dist/output/naming.js +30 -0
  70. package/dist/output/produce-output.d.ts +2 -0
  71. package/dist/output/produce-output.js +35 -0
  72. package/dist/output/render-constants.d.ts +21 -0
  73. package/dist/{constants → output}/render-constants.js +2 -1
  74. package/dist/output/text.d.ts +2 -0
  75. package/dist/output/text.js +14 -0
  76. package/dist/resolvers/js/extract-imports.d.ts +1 -0
  77. package/dist/resolvers/js/js-resolver.d.ts +2 -0
  78. package/dist/resolvers/js/js-resolver.js +45 -89
  79. package/dist/resolvers/js/resolve-alias.d.ts +2 -0
  80. package/dist/resolvers/js/resolve-alias.js +12 -20
  81. package/dist/resolvers/php/bindings.d.ts +8 -0
  82. package/dist/resolvers/php/bindings.js +8 -9
  83. package/dist/resolvers/php/extract-imports.d.ts +13 -0
  84. package/dist/resolvers/php/extract-imports.js +1 -1
  85. package/dist/resolvers/php/php-resolver.d.ts +2 -0
  86. package/dist/resolvers/php/php-resolver.js +61 -90
  87. package/dist/resolvers/php/psr4.d.ts +5 -0
  88. package/dist/resolvers/php/psr4.js +7 -7
  89. package/dist/resolvers/resolver-constants.d.ts +4 -0
  90. package/dist/resolvers/resolver-constants.js +7 -0
  91. package/dist/resolvers/resolver-result.d.ts +5 -0
  92. package/dist/resolvers/resolver-result.js +18 -0
  93. package/dist/tracing/exclude.d.ts +6 -0
  94. package/dist/{shared/patterns.js → tracing/exclude.js} +4 -4
  95. package/dist/tracing/follow-chain.d.ts +5 -0
  96. package/dist/tracing/follow-chain.js +63 -0
  97. package/dist/tracing/include-files.d.ts +2 -0
  98. package/dist/tracing/include-files.js +36 -0
  99. package/dist/tracing/resolver-registry.d.ts +5 -0
  100. package/dist/tracing/resolver-registry.js +20 -0
  101. package/dist/tracing/trace-run.d.ts +2 -0
  102. package/dist/tracing/trace-run.js +21 -0
  103. package/dist/tracing/trace-stats.d.ts +4 -0
  104. package/dist/tracing/trace-stats.js +16 -0
  105. package/dist/types/app.types.d.ts +62 -0
  106. package/dist/types/app.types.js +2 -0
  107. package/dist/types/cli.types.d.ts +22 -0
  108. package/dist/types/cli.types.js +0 -10
  109. package/dist/types/config.types.d.ts +34 -0
  110. package/dist/types/index.d.ts +7 -0
  111. package/dist/types/index.js +3 -1
  112. package/dist/types/output.types.d.ts +6 -0
  113. package/dist/types/output.types.js +2 -0
  114. package/dist/types/resolver.types.d.ts +23 -0
  115. package/dist/types/tracing.types.d.ts +23 -0
  116. package/dist/types/tracing.types.js +2 -0
  117. package/dist/types/utils.types.d.ts +10 -0
  118. package/package.json +35 -12
  119. package/schema/prodex.schema.json +122 -0
  120. package/dist/cli/init.js +0 -21
  121. package/dist/cli/picker.js +0 -83
  122. package/dist/cli/summary.js +0 -32
  123. package/dist/constants/config.js +0 -27
  124. package/dist/constants/default-config.js +0 -43
  125. package/dist/constants/flags.js +0 -79
  126. package/dist/constants/index.js +0 -20
  127. package/dist/core/combine.js +0 -56
  128. package/dist/core/dependency.js +0 -98
  129. package/dist/core/helpers.js +0 -85
  130. package/dist/core/managers/config.js +0 -140
  131. package/dist/core/output.js +0 -49
  132. package/dist/core/renderers.js +0 -210
  133. package/dist/debug.js +0 -15
  134. package/dist/lib/logger.js +0 -42
  135. package/dist/lib/polyfills.js +0 -17
  136. package/dist/lib/prompt.js +0 -34
  137. package/dist/lib/questions.js +0 -28
  138. package/dist/lib/utils.js +0 -46
  139. package/dist/shared/collections.js +0 -33
  140. package/dist/store.js +0 -15
  141. /package/dist/{constants → cache}/cache-keys.js +0 -0
  142. /package/dist/{types/core.types.js → config/migration/types.js} +0 -0
@@ -1,98 +0,0 @@
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 helpers_1 = require("./helpers");
11
- const logger_1 = require("../lib/logger");
12
- const collections_1 = require("../shared/collections");
13
- const fs_1 = __importDefault(require("fs"));
14
- /**
15
- * 🧩 followChain()
16
- * Traverses all dependencies starting from the given entry files.
17
- * Uses language-specific resolvers (JS / PHP) under the hood.
18
- */
19
- async function followChain(entryFiles, cfg) {
20
- const limit = cfg.resolve.limit;
21
- const resolverDepth = cfg.resolve.depth;
22
- logger_1.logger.debug("🧩 Following dependency chain...");
23
- const visited = new Set();
24
- const all = [];
25
- const expected = new Set();
26
- const resolved = new Set();
27
- for (const f of entryFiles) {
28
- if (visited.has(f))
29
- continue;
30
- all.push(f);
31
- const ext = path_1.default.extname(f);
32
- if (!config_1.CODE_EXTS.includes(ext))
33
- continue;
34
- const resolver = config_1.RESOLVERS[ext];
35
- if (!resolver)
36
- continue;
37
- const params = {
38
- filePath: f,
39
- visited,
40
- depth: 0,
41
- maxDepth: resolverDepth,
42
- };
43
- let result = null;
44
- try {
45
- result = await resolver(params);
46
- }
47
- catch (err) {
48
- logger_1.logger.warn(`⚠️ Resolver failed for ${f}:`, err.message || err);
49
- continue;
50
- }
51
- if (!result)
52
- continue;
53
- const { files, stats } = result;
54
- all.push(...files);
55
- stats.expected.forEach((x) => expected.add(x));
56
- stats.resolved.forEach((x) => resolved.add(x));
57
- if (limit && all.length >= limit) {
58
- logger_1.logger.warn("⚠️ Limit reached:", limit);
59
- break;
60
- }
61
- }
62
- return {
63
- files: (0, collections_1.unique)(all),
64
- stats: { expected, resolved },
65
- };
66
- }
67
- /**
68
- * 🧩 applyIncludes()
69
- * Scans and appends additional files defined in config.resolve.include.
70
- */
71
- // src/core/dependency.ts
72
- // (existing imports stay)
73
- async function applyIncludes(cfg, files) {
74
- const { resolve, root } = cfg;
75
- const absFiles = [];
76
- const patterns = [];
77
- for (const raw of resolve.include) {
78
- const p = String(raw ?? "").trim();
79
- if (!p)
80
- continue;
81
- const norm = p.norm(); // uses your polyfill (slashes -> "/")
82
- // absolute *file* paths bypass globScan (and its ignores)
83
- if (path_1.default.isAbsolute(norm)) {
84
- try {
85
- if (fs_1.default.statSync(norm).isFile()) {
86
- absFiles.push(path_1.default.resolve(norm));
87
- continue;
88
- }
89
- }
90
- catch {
91
- // doesn't exist / can't stat → treat as pattern
92
- }
93
- }
94
- patterns.push(norm);
95
- }
96
- const scan = await (0, helpers_1.globScan)(patterns, { cwd: root });
97
- return (0, collections_1.unique)([...files, ...absFiles, ...scan.files]);
98
- }
@@ -1,85 +0,0 @@
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.walk = walk;
7
- exports.orderByPriority = orderByPriority;
8
- exports.smartNaming = smartNaming;
9
- exports.globScan = globScan;
10
- const fs_1 = __importDefault(require("fs"));
11
- const micromatch_1 = __importDefault(require("micromatch"));
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");
17
- /**
18
- * Recursive walker that respects glob exclude.
19
- * Returns all files under the given directory tree.
20
- */
21
- function* walk(dir, cfg, depth = 0) {
22
- const { root, entry: { ui: { scanDepth }, }, resolve: { exclude }, } = cfg;
23
- if (depth > scanDepth)
24
- return;
25
- const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
26
- for (const e of entries) {
27
- const full = path_1.default.join(dir, e.name);
28
- if (e.isDirectory()) {
29
- // Skip excluded directories entirely
30
- const relPath = (0, shared_1.rel)(full, root);
31
- if ((0, shared_1.isExcluded)(relPath, exclude))
32
- continue;
33
- yield* walk(full, cfg, depth + 1);
34
- continue;
35
- }
36
- if (e.isFile()) {
37
- const relPath = (0, shared_1.rel)(full, root);
38
- if ((0, shared_1.isExcluded)(relPath, exclude))
39
- continue;
40
- yield full;
41
- }
42
- }
43
- }
44
- function orderByPriority(files, priorityList = []) {
45
- if (!priorityList.length)
46
- return files;
47
- const prioritized = [];
48
- const normal = [];
49
- for (const f of files) {
50
- const normalized = f.norm().toLowerCase();
51
- if (priorityList.some((p) => micromatch_1.default.isMatch(normalized, p.toLowerCase())))
52
- prioritized.push(f);
53
- else
54
- normal.push(f);
55
- }
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 };
85
- }
@@ -1,140 +0,0 @@
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 constants_1 = require("../../constants");
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 rawFile = null;
19
- static load(cwd = process.cwd()) {
20
- const file = path_1.default.join(cwd, "prodex.json");
21
- if (!fs_1.default.existsSync(file))
22
- return constants_1.DEFAULT_PRODEX_CONFIG;
23
- try {
24
- const parsed = JSON.parse(fs_1.default.readFileSync(file, "utf8"));
25
- this.rawFile = parsed; // <-- SAVE RAW COPY
26
- return parsed;
27
- }
28
- catch {
29
- console.warn("⚠️ Invalid prodex.json — using defaults.");
30
- return constants_1.DEFAULT_PRODEX_CONFIG;
31
- }
32
- }
33
- static merge(user, flags, cwd = process.cwd()) {
34
- const merged = {
35
- // ...rest,
36
- ...user,
37
- output: { ...constants_1.DEFAULT_PRODEX_CONFIG.output, ...user.output },
38
- entry: {
39
- ...constants_1.DEFAULT_PRODEX_CONFIG.entry,
40
- ...user.entry,
41
- ui: { ...constants_1.DEFAULT_PRODEX_CONFIG.entry.ui, ...user.entry?.ui },
42
- },
43
- resolve: { ...constants_1.DEFAULT_PRODEX_CONFIG.resolve, ...user.resolve },
44
- root: cwd,
45
- name: flags?.name ?? null,
46
- };
47
- this.applyFlags(merged, flags);
48
- return this.normalize(merged);
49
- }
50
- static applyFlags(cfg, flags) {
51
- if (!flags)
52
- return cfg;
53
- for (const [key, val] of Object.entries(flags)) {
54
- if (val === undefined)
55
- continue;
56
- const def = flags_1.FLAG_MAP[key];
57
- if (def?.apply)
58
- def.apply(cfg, val);
59
- }
60
- const hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;
61
- const hasInclude = Array.isArray(flags.include) ? flags.include.length > 0 : !!flags.include;
62
- if (hasInclude && !hasFiles)
63
- cfg.entry.files = [];
64
- if (hasFiles && !hasInclude)
65
- cfg.resolve.include = [];
66
- if (flags.shortcut && cfg.shortcuts && cfg.shortcuts[flags.shortcut])
67
- return this.applyShortcuts(cfg, flags);
68
- return cfg;
69
- }
70
- static applyShortcuts(cfg, flags) {
71
- const shortcut = cfg.shortcuts?.[flags.shortcut];
72
- if (!shortcut)
73
- return cfg;
74
- const mergeOrReplace = (key, target) => {
75
- const flagValues = (flags[key] || []);
76
- const hasFlags = !(0, utils_1.ArrisEmpty)(flagValues);
77
- let values = shortcut[key];
78
- if (!values && !hasFlags) {
79
- target[key] = [];
80
- return;
81
- }
82
- if (!values)
83
- values = [];
84
- target[key] = hasFlags ? [...flagValues, ...values] : values;
85
- };
86
- // include / exclude live in cfg.resolve
87
- mergeOrReplace("include", cfg.resolve);
88
- mergeOrReplace("exclude", cfg.resolve);
89
- // files live in cfg.entry
90
- mergeOrReplace("files", cfg.entry);
91
- // name override
92
- if (shortcut.prefix)
93
- cfg.name = shortcut.prefix;
94
- return cfg;
95
- }
96
- static normalize(cfg) {
97
- cfg.entry.files = (0, utils_1.normalizePatterns)(cfg.entry.files);
98
- //TODO: Is there a need?
99
- // cfg.resolve.include = normalizePatterns(cfg.resolve.include);
100
- // cfg.resolve.exclude = normalizePatterns(cfg.resolve.exclude);
101
- return cfg;
102
- }
103
- static persist(partial) {
104
- const cfg = (0, store_1.getConfig)();
105
- const dest = path_1.default.join(cfg.root, "prodex.json");
106
- // Start from the raw config, never the merged runtime version
107
- const base = ConfigManager.rawFile
108
- ? JSON.parse(JSON.stringify(ConfigManager.rawFile)) // deep clone to avoid mutation
109
- : {};
110
- // Apply only the partial updates (aliases, etc.)
111
- const patched = deepMerge(base, partial);
112
- try {
113
- fs_1.default.writeFileSync(dest, (0, utils_1.toJson)(patched) + "\n", "utf8");
114
- }
115
- catch (err) {
116
- console.warn("⚠️ Failed to persist config:", err?.message || err);
117
- }
118
- }
119
- }
120
- exports.ConfigManager = ConfigManager;
121
- function deepMerge(base, patch) {
122
- if (!patch)
123
- return base;
124
- const out = Array.isArray(base) ? [...base] : { ...base };
125
- for (const [k, v] of Object.entries(patch)) {
126
- if (v === undefined)
127
- continue;
128
- const bv = base[k];
129
- if (Array.isArray(v))
130
- out[k] = [...v]; // overwrite arrays
131
- else if (isPlainObject(v) && isPlainObject(bv))
132
- out[k] = deepMerge(bv, v);
133
- else
134
- out[k] = v;
135
- }
136
- return out;
137
- }
138
- function isPlainObject(x) {
139
- return x && typeof x === "object" && !Array.isArray(x);
140
- }
@@ -1,49 +0,0 @@
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 constants_1 = require("../constants");
15
- /**
16
- * 🧩 produceOutput()
17
- * Handles rendering and writing of the final trace file.
18
- * Receives resolved files and configuration from combine.ts.
19
- */
20
- async function produceOutput({ name, files, cfg, showUi }) {
21
- const { output: { format, versioned, dir }, } = cfg;
22
- // 1️⃣ Determine base filename
23
- let outputBase = name;
24
- if (showUi) {
25
- const result = await (0, prompt_1.prompt)(questions_1.OUTPUT_NAME_QUESTION);
26
- if (result?.outputBase)
27
- outputBase = result.outputBase;
28
- }
29
- // 2️⃣ Prefix timestamp if versioned
30
- outputBase = `${outputBase}-${constants_1.SUFFIX}`;
31
- if (versioned)
32
- outputBase = `${outputBase}_${(0, utils_1.shortTimestamp)()}`;
33
- // 3️⃣ Ensure output directory
34
- try {
35
- fs_1.default.mkdirSync(dir, { recursive: true });
36
- }
37
- catch {
38
- logger_1.logger.warn("Could not create dir directory:", dir);
39
- }
40
- // 4️⃣ Prepare and write content
41
- const outputPath = path_1.default.join(dir, `${outputBase}.${format}`);
42
- const sorted = [...files].sort((a, b) => a.localeCompare(b));
43
- //[tocMd(sorted), ...sorted.map((f, i) => renderMd(f, i)), MD_FOOTER].join("\n")
44
- const content = format === "txt"
45
- ? [(0, renderers_1.tocTxt)(sorted), ...sorted.map(renderers_1.renderTxt)].join("")
46
- : (0, renderers_1.renderTraceMd)(sorted).content;
47
- fs_1.default.writeFileSync(outputPath, content, "utf8");
48
- return outputPath;
49
- }
@@ -1,210 +0,0 @@
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.renderTraceMd = renderTraceMd;
7
- exports.tocMd = tocMd;
8
- exports.renderMd = renderMd;
9
- exports.tocTxt = tocTxt;
10
- exports.renderTxt = renderTxt;
11
- const path_1 = __importDefault(require("path"));
12
- const shared_1 = require("../shared");
13
- const constants_1 = require("../constants");
14
- /**
15
- * renderTraceMd()
16
- * Builds the full Markdown document AND computes:
17
- * - listing start/end lines
18
- * - each file section start/end lines (in the final output)
19
- */
20
- // src/core/renderers.ts
21
- function renderTraceMd(files) {
22
- const count = files.length;
23
- // Render sections at once (content of each file)
24
- const sections = files.map((f, i) => renderMd(f, i));
25
- // 1) Build a FIRST PASS doc with placeholder TOC (no line ranges)
26
- const pass1Toc = buildToc({
27
- files,
28
- count,
29
- listingStart: 0,
30
- listingEnd: 0,
31
- trace: null,
32
- withRanges: false,
33
- });
34
- const pass1Content = [pass1Toc, ...sections, constants_1.MD_FOOTER].join("\n");
35
- // 2) Analyze the FINAL STRING (pass 1) to get real line indexes
36
- const pass1Analysis = analyzeTrace(pass1Content, count);
37
- // 3) Build pass 2 TOC including listing range + per-file ranges
38
- const pass2Toc = buildToc({
39
- files,
40
- count,
41
- listingStart: pass1Analysis.listingStart,
42
- listingEnd: pass1Analysis.listingEnd,
43
- trace: pass1Analysis.trace,
44
- withRanges: true,
45
- });
46
- const pass2Content = [pass2Toc, ...sections, constants_1.MD_FOOTER].join("\n");
47
- // 4) Re-analyze pass 2 content (should be identical; extra safety)
48
- const pass2Analysis = analyzeTrace(pass2Content, count);
49
- // If anything drifted (it really shouldn’t), trust pass 2’s analysis.
50
- // Rebuilding again would still not change line counts, so this is stable.
51
- return {
52
- content: pass2Content,
53
- trace: pass2Analysis.trace,
54
- listingStart: pass2Analysis.listingStart,
55
- listingEnd: pass2Analysis.listingEnd,
56
- };
57
- }
58
- const rangeText = (start, end) => ` L${start}-L${end}`;
59
- function buildToc(opts) {
60
- const { files, count, listingStart, listingEnd, trace, withRanges } = opts;
61
- const indexRange = withRanges && listingStart && listingEnd
62
- ? `L${listingStart}-L${listingEnd}`
63
- : constants_1.INDEX_RANGE_PLACEHOLDER;
64
- const tocHead = [
65
- constants_1.MD_HEADER,
66
- constants_1.LLM_NOTE,
67
- "",
68
- "# Index",
69
- `<!-- PRODEX_INDEX_RANGE: ${indexRange} -->`,
70
- `<!-- PRODEX_FILE_COUNT: ${count} -->`,
71
- "<!-- PRODEX_INDEX_LIST_START -->",
72
- ];
73
- const items = files.map((f, i) => {
74
- const rp = (0, shared_1.rel)(f);
75
- if (!withRanges || !trace)
76
- return `- [${rp}](#${i + 1})`;
77
- const t = trace[i];
78
- return `- [${rp}](#${i + 1}) ${rangeText(t.startLine, t.endLine)}`;
79
- });
80
- const tocTail = ["<!-- PRODEX_INDEX_LIST_END -->", "", "---"];
81
- return [...tocHead, ...items, ...tocTail].join("\n");
82
- }
83
- /**
84
- * Analyze the already-generated Markdown to compute:
85
- * - listing start/end lines
86
- * - each section start/end line (per file index)
87
- *
88
- * All line numbers are 1-based.
89
- */
90
- function analyzeTrace(content, count) {
91
- const lines = content.split("\n");
92
- // --- Listing range ---
93
- const startMarkerIdx = lines.findIndex((l) => l.trim() === "<!-- PRODEX_INDEX_LIST_START -->");
94
- const endMarkerIdx = lines.findIndex((l) => l.trim() === "<!-- PRODEX_INDEX_LIST_END -->");
95
- let listingStart = 0;
96
- let listingEnd = 0;
97
- if (startMarkerIdx >= 0 && endMarkerIdx > startMarkerIdx) {
98
- const itemIdxs = [];
99
- for (let i = startMarkerIdx + 1; i < endMarkerIdx; i++) {
100
- if (lines[i].trim().startsWith("- "))
101
- itemIdxs.push(i);
102
- }
103
- if (itemIdxs.length) {
104
- listingStart = itemIdxs[0] + 1; // 1-based
105
- // count is zero during the first (placeholder) pass; cap to the requested count when provided, otherwise use the discovered items
106
- const cappedCount = count > 0 ? Math.min(itemIdxs.length, count) : itemIdxs.length;
107
- const lastItemIdx = itemIdxs[cappedCount - 1];
108
- listingEnd = lastItemIdx + 1;
109
- }
110
- else {
111
- listingStart = startMarkerIdx + 2; // move past the marker line (0-based) and convert to 1-based line numbers
112
- listingEnd = listingStart;
113
- }
114
- }
115
- // --- Footer start (exclude footer from last file range) ---
116
- let footerMarkerIdx = lines.findIndex((l) => l.includes("<!-- PRODEx v"));
117
- if (footerMarkerIdx < 0)
118
- footerMarkerIdx = lines.findIndex((l) => l.includes("*Generated with [Prodex]"));
119
- let footerStartIdx = footerMarkerIdx >= 0 ? footerMarkerIdx : lines.length; // 0-based
120
- if (footerStartIdx > 0 && lines[footerStartIdx - 1].trim() === "---")
121
- footerStartIdx = footerStartIdx - 1;
122
- // --- Section markers: find "#### N" lines ---
123
- const markerLineIdxByN = new Map();
124
- for (let i = 0; i < lines.length; i++) {
125
- const m = lines[i].trim().match(/^####\s+(\d+)\s*$/);
126
- if (!m)
127
- continue;
128
- const n = Number(m[1]);
129
- if (!Number.isFinite(n))
130
- continue;
131
- if (n < 1 || n > count)
132
- continue;
133
- if (!markerLineIdxByN.has(n))
134
- markerLineIdxByN.set(n, i);
135
- }
136
- // Compute each section's start idx (prefer the preceding "---" line if present)
137
- const startIdxs = [];
138
- for (let n = 1; n <= count; n++) {
139
- const markerIdx = markerLineIdxByN.get(n);
140
- if (markerIdx == null) {
141
- // Fallback: if marker missing, make it non-crashy.
142
- // Put start at footerStart (it'll produce tiny/empty ranges rather than exploding).
143
- startIdxs.push(footerStartIdx);
144
- continue;
145
- }
146
- const maybeStart = markerIdx > 0 && lines[markerIdx - 1].trim() === "---" ? markerIdx - 1 : markerIdx;
147
- startIdxs.push(maybeStart);
148
- }
149
- // Compute end idx using next section start, or footer start
150
- const trace = [];
151
- for (let i = 0; i < count; i++) {
152
- const startIdx = startIdxs[i];
153
- const nextStartIdx = i < count - 1 ? startIdxs[i + 1] : footerStartIdx;
154
- const endIdx = Math.max(startIdx, nextStartIdx - 1);
155
- trace.push({
156
- file: "", // filled by caller if needed; TOC uses rel(files[i]) anyway
157
- anchor: i + 1,
158
- startLine: startIdx + 1,
159
- endLine: endIdx + 1,
160
- });
161
- }
162
- return { listingStart, listingEnd, trace };
163
- }
164
- /**
165
- * Existing functions kept as-is.
166
- * (renderMd is used by renderTraceMd above)
167
- */
168
- function tocMd(files) {
169
- const count = files.length;
170
- const items = files.map((f, i) => `- [${(0, shared_1.rel)(f)}](#${i + 1})`);
171
- return [
172
- constants_1.MD_HEADER,
173
- constants_1.LLM_NOTE,
174
- "",
175
- "# Index",
176
- `<!-- PRODEX_INDEX_RANGE: ${constants_1.INDEX_RANGE_PLACEHOLDER} -->`,
177
- `<!-- PRODEX_FILE_COUNT: ${count} -->`,
178
- "<!-- PRODEX_INDEX_LIST_START -->",
179
- ...items,
180
- "<!-- PRODEX_INDEX_LIST_END -->",
181
- "",
182
- "---",
183
- ].join("\n");
184
- }
185
- function renderMd(p, i) {
186
- const rp = (0, shared_1.rel)(p);
187
- const ext = path_1.default.extname(p).toLowerCase();
188
- const lang = constants_1.LANG_MAP[ext] || "txt";
189
- const code = (0, shared_1.readFileSafe)(p).trimEnd();
190
- return [
191
- `---\n#### ${i + 1}`,
192
- "\n",
193
- "` File: " + rp + "` [↑ Back to top](#index)",
194
- "",
195
- "```" + lang,
196
- code,
197
- "```",
198
- "",
199
- ].join("\n");
200
- }
201
- // TXT versions unchanged
202
- function tocTxt(files) {
203
- const sorted = [...files].sort((a, b) => a.localeCompare(b));
204
- return ["##==== Combined Scope ====", ...sorted.map((f) => "## - " + (0, shared_1.rel)(f))].join("\n") + "\n\n";
205
- }
206
- function renderTxt(p) {
207
- const relPath = (0, shared_1.rel)(p);
208
- const code = (0, shared_1.readFileSafe)(p);
209
- return ["##==== path: " + relPath + " ====", "##region " + relPath, code, "##endregion", ""].join("\n");
210
- }
package/dist/debug.js DELETED
@@ -1,15 +0,0 @@
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 index_1 = __importDefault(require("./index"));
7
- require("source-map-support/register");
8
- (async () => {
9
- const mockArgs = ["node", "prodex", "-i", "src/**", "-d"];
10
- process.argv = mockArgs;
11
- //"-f", "**/(dashboard|accounts).tsx",
12
- console.log("🧩 Debug runner starting...");
13
- await (0, index_1.default)();
14
- console.log("🧩 Debug runner done.");
15
- })();
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.logger = void 0;
4
- const store_1 = require("../store");
5
- let FLAGS = null;
6
- let DEBUG = false;
7
- let SILENT = false;
8
- function ensureFlags() {
9
- if (FLAGS)
10
- return;
11
- FLAGS = (0, store_1.getFlags)() || {};
12
- DEBUG = !!FLAGS.debug;
13
- SILENT = !!FLAGS.silent;
14
- }
15
- exports.logger = {
16
- debug: (...a) => {
17
- ensureFlags();
18
- if (DEBUG && !SILENT)
19
- console.log("\n🪶 [debug]", ...a);
20
- },
21
- info: (...a) => {
22
- ensureFlags();
23
- if (!SILENT)
24
- console.log("\n📌 [info]", ...a);
25
- },
26
- warn: (...a) => {
27
- ensureFlags();
28
- if (!SILENT)
29
- console.warn("\n⚠️ [warn]", ...a);
30
- },
31
- error: (...a) => {
32
- ensureFlags();
33
- if (!SILENT)
34
- console.error("\n💥 [error]", ...a);
35
- },
36
- log: (...a) => {
37
- ensureFlags();
38
- if (!SILENT)
39
- console.log("\n", ...a);
40
- },
41
- clear: () => console.clear(),
42
- };
@@ -1,17 +0,0 @@
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 });