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
@@ -5,120 +5,89 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.resolvePhpImports = resolvePhpImports;
7
7
  const fs_1 = __importDefault(require("fs"));
8
+ const promises_1 = __importDefault(require("fs/promises"));
8
9
  const path_1 = __importDefault(require("path"));
9
- const extract_imports_1 = require("./extract-imports");
10
+ const cache_keys_1 = require("../../cache/cache-keys");
11
+ const cache_manager_1 = require("../../cache/cache-manager");
12
+ const logger_1 = require("../../diagnostics/logger");
13
+ const path_2 = require("../../filesystem/path");
14
+ const read_file_1 = require("../../filesystem/read-file");
15
+ const resolver_result_1 = require("../resolver-result");
10
16
  const bindings_1 = require("./bindings");
17
+ const extract_imports_1 = require("./extract-imports");
11
18
  const psr4_1 = require("./psr4");
12
- const logger_1 = require("../../lib/logger");
13
- const shared_1 = require("../../shared");
14
- const store_1 = require("../../store");
15
- const constants_1 = require("../../constants");
16
- const cache_1 = require("../../core/managers/cache");
17
- const collections_1 = require("../../shared/collections");
18
- const promises_1 = __importDefault(require("fs/promises")); // (add near the top if not present)
19
- /**
20
- * Typed PHP resolver (aligned with JS resolver signature).
21
- * - Uses global config via getConfig()
22
- * - Returns ResolverResult (files + stats)
23
- * - Depth/visited guarded recursion
24
- */
25
- async function resolvePhpImports({ filePath, visited = new Set(), depth = 0, maxDepth, ctx }) {
26
- const { root: ROOT, resolve: { exclude: excludePatterns = [], depth: defaultDepth = 10 }, } = (0, store_1.getConfig)();
27
- const limitDepth = maxDepth ?? defaultDepth;
28
- if (depth >= limitDepth)
29
- return (0, collections_1.emptyResult)(visited);
30
- if (visited.has(filePath))
31
- return (0, collections_1.emptyResult)(visited);
32
- visited.add(filePath);
33
- // Fast existence / read
19
+ async function resolvePhpImports({ cfg, filePath, ctx }) {
34
20
  if (!fs_1.default.existsSync(filePath))
35
- return (0, collections_1.emptyResult)(visited);
36
- const code = (0, shared_1.readFileSafe)(filePath);
21
+ return (0, resolver_result_1.emptyResolverResult)();
22
+ const code = (0, read_file_1.readFileSafe)(filePath);
37
23
  if (!code)
38
- return (0, collections_1.emptyResult)(visited);
39
- const nsMatch = code.match(/\bnamespace\s+([^;]+);/);
40
- const currentNamespace = nsMatch ? nsMatch[1].trim() : null;
41
- // Context + exclusions
42
- const phpCtx = buildPhpCtx(ROOT, ctx);
43
- // Parse imports (expand grouped `use` syntax)
44
- const raw = (0, extract_imports_1.extractPhpImports)(code);
45
- const imports = (0, extract_imports_1.expandGroupedUses)(raw);
46
- // Accumulators
47
- const stats = (0, shared_1.newStats)();
48
- const filesOut = [];
49
- for (const imp0 of imports) {
50
- let imp = imp0;
51
- if (!imp || typeof imp !== "string")
52
- continue;
53
- // Fully-qualified check
54
- const isFullyQualified = imp.includes("\\") || imp.startsWith("\\");
55
- if (!isFullyQualified && currentNamespace) {
56
- imp = `${currentNamespace}\\${imp}`;
57
- }
58
- // Respect Laravel container bindings (Interface → Implementation)
59
- if (phpCtx.bindings[imp]) {
60
- // logger.debug("[php-resolver] binding:", imp, "→", _2j(phpCtx.bindings[imp]));
61
- imp = phpCtx.bindings[imp];
62
- }
63
- // Only resolve PSR-4 mapped namespaces
64
- if (!startsWithAnyNamespace(imp, phpCtx.nsKeys))
24
+ return (0, resolver_result_1.emptyResolverResult)();
25
+ const currentNamespace = getCurrentNamespace(code);
26
+ const phpCtx = buildPhpCtx(cfg.root, ctx);
27
+ const imports = (0, extract_imports_1.expandGroupedUses)((0, extract_imports_1.extractPhpImports)(code));
28
+ const stats = (0, resolver_result_1.newResolverStats)();
29
+ const files = [];
30
+ for (const importName of imports) {
31
+ const resolvedImport = resolveNamespaceImport(importName, currentNamespace, phpCtx);
32
+ if (!resolvedImport)
65
33
  continue;
66
- // Resolve namespace file path (sync helper retained)
67
- const resolvedPath = await tryResolvePhpFile(imp, filePath, phpCtx.psr4);
68
- // Exclusion check after final resolution
69
- if ((0, shared_1.isExcluded)(resolvedPath, excludePatterns, ROOT))
70
- continue;
71
- stats.expected.add(imp);
34
+ const resolvedPath = await tryResolvePhpFile(resolvedImport, filePath, phpCtx.psr4);
35
+ stats.expected.add(resolvedImport);
72
36
  if (!resolvedPath)
73
37
  continue;
74
- stats.resolved.add(imp);
75
- filesOut.push(resolvedPath);
76
- // Recurse
77
- const sub = await resolvePhpImports({
78
- filePath: resolvedPath,
79
- visited,
80
- depth: depth + 1,
81
- maxDepth: limitDepth,
82
- ctx: phpCtx,
83
- });
84
- filesOut.push(...sub.files);
85
- (0, shared_1.mergeStats)(stats, sub.stats);
38
+ stats.resolved.add(resolvedImport);
39
+ files.push(resolvedPath);
86
40
  }
87
- const out = (0, shared_1.unique)(filesOut);
88
- const unresolved = (0, shared_1.setDiff)(stats.expected, stats.resolved);
89
- logger_1.logger.debug(`🪶 [php-resolver] ${path_1.default.basename(filePath)} → expected: ${stats.expected.size}, resolved: ${stats.resolved.size}`);
41
+ const unresolved = (0, resolver_result_1.resolverSetDiff)(stats.expected, stats.resolved);
42
+ logger_1.logger.debug(`[php-resolver] ${path_1.default.basename(filePath)} -> expected: ${stats.expected.size}, resolved: ${stats.resolved.size}`);
90
43
  if (unresolved.size)
91
44
  logger_1.logger.debug("[php-resolver] unresolved:", [...unresolved]);
92
- return { files: out, visited, stats };
45
+ return { files: (0, resolver_result_1.uniqueResolvedFiles)(files), stats };
46
+ }
47
+ function getCurrentNamespace(code) {
48
+ const nsMatch = code.match(/\bnamespace\s+([^;]+);/);
49
+ return nsMatch ? nsMatch[1].trim() : null;
50
+ }
51
+ function resolveNamespaceImport(importName, currentNamespace, ctx) {
52
+ if (!importName || typeof importName !== "string")
53
+ return null;
54
+ let resolved = importName;
55
+ const isFullyQualified = resolved.includes("\\") || resolved.startsWith("\\");
56
+ if (!isFullyQualified && currentNamespace)
57
+ resolved = `${currentNamespace}\\${resolved}`;
58
+ if (ctx.bindings[resolved])
59
+ resolved = ctx.bindings[resolved];
60
+ return startsWithAnyNamespace(resolved, ctx.nsKeys) ? resolved : null;
93
61
  }
94
62
  async function tryResolvePhpFile(imp, fromFile, psr4) {
95
63
  const key = `php:${imp}:${fromFile}`;
96
- const cached = cache_1.CacheManager.get(constants_1.CACHE_KEYS.PHP_FILECACHE, key);
64
+ const cached = cache_manager_1.CacheManager.get(cache_keys_1.CACHE_KEYS.PHP_FILECACHE, key);
97
65
  if (cached !== undefined)
98
66
  return cached;
99
- const nsKey = Object.keys(psr4).find((k) => imp.startsWith(k));
67
+ const nsKey = Object.keys(psr4).find((candidate) => imp.startsWith(candidate));
100
68
  if (!nsKey) {
101
- cache_1.CacheManager.set(constants_1.CACHE_KEYS.PHP_FILECACHE, key, null);
69
+ cache_manager_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_FILECACHE, key, null);
102
70
  return null;
103
71
  }
104
- const rel = imp.replace(nsKey, "").norm();
105
- const tries = [path_1.default.join(psr4[nsKey], rel), path_1.default.join(psr4[nsKey], rel + ".php"), path_1.default.join(psr4[nsKey], rel, "index.php")];
106
- // 🔹 Run all stats concurrently
107
- const results = await Promise.allSettled(tries.map(async (p) => {
72
+ const relativeImport = (0, path_2.normalizePath)(imp.replace(nsKey, ""));
73
+ const candidates = [
74
+ path_1.default.join(psr4[nsKey], relativeImport),
75
+ path_1.default.join(psr4[nsKey], relativeImport + ".php"),
76
+ path_1.default.join(psr4[nsKey], relativeImport, "index.php"),
77
+ ];
78
+ const results = await Promise.allSettled(candidates.map(async (candidate) => {
108
79
  try {
109
- const st = await promises_1.default.stat(p);
110
- return st.isFile() ? path_1.default.resolve(p) : null;
80
+ const stats = await promises_1.default.stat(candidate);
81
+ return stats.isFile() ? path_1.default.resolve(candidate) : null;
111
82
  }
112
83
  catch {
113
84
  return null;
114
85
  }
115
86
  }));
116
- //@ts-ignore
117
- const resolved = results.find((r) => r.status === "fulfilled" && r.value)?.value ?? null;
118
- cache_1.CacheManager.set(constants_1.CACHE_KEYS.PHP_FILECACHE, key, resolved);
87
+ const resolved = results.find(isFulfilledPath)?.value ?? null;
88
+ cache_manager_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_FILECACHE, key, resolved);
119
89
  return resolved;
120
90
  }
121
- /** Ensure we have a PHP resolver context for the current root */
122
91
  function buildPhpCtx(root, prev) {
123
92
  if (prev?.kind === "php")
124
93
  return prev;
@@ -127,10 +96,12 @@ function buildPhpCtx(root, prev) {
127
96
  const bindings = (0, bindings_1.loadLaravelBindings)(root);
128
97
  return { kind: "php", psr4, nsKeys, bindings };
129
98
  }
130
- /** Namespace prefix check */
131
99
  function startsWithAnyNamespace(imp, nsKeys) {
132
- for (const k of nsKeys)
133
- if (imp.startsWith(k))
100
+ for (const nsKey of nsKeys)
101
+ if (imp.startsWith(nsKey))
134
102
  return true;
135
103
  return false;
136
104
  }
105
+ function isFulfilledPath(result) {
106
+ return result.status === "fulfilled" && !!result.value;
107
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Builds a PSR-4 namespace to directory map from composer.json.
3
+ * Returns absolute paths in the map values.
4
+ */
5
+ export declare function resolvePsr4(root: string): Record<string, string>;
@@ -6,19 +6,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.resolvePsr4 = resolvePsr4;
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
- const cache_1 = require("../../core/managers/cache");
10
- const cache_keys_1 = require("../../constants/cache-keys");
9
+ const cache_manager_1 = require("../../cache/cache-manager");
10
+ const cache_keys_1 = require("../../cache/cache-keys");
11
11
  /**
12
- * Builds a PSR-4 namespace directory map from composer.json.
12
+ * Builds a PSR-4 namespace to directory map from composer.json.
13
13
  * Returns absolute paths in the map values.
14
14
  */
15
15
  function resolvePsr4(root) {
16
- const cached = cache_1.CacheManager.get(cache_keys_1.CACHE_KEYS.PHP_PSR4, root);
16
+ const cached = cache_manager_1.CacheManager.get(cache_keys_1.CACHE_KEYS.PHP_PSR4, root);
17
17
  if (cached)
18
18
  return cached;
19
19
  const composer = path_1.default.join(root, "composer.json");
20
20
  if (!fs_1.default.existsSync(composer)) {
21
- cache_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_PSR4, root, {});
21
+ cache_manager_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_PSR4, root, {});
22
22
  return {};
23
23
  }
24
24
  try {
@@ -29,11 +29,11 @@ function resolvePsr4(root) {
29
29
  const cleanNs = ns.replace(/\\+$/, "");
30
30
  map[cleanNs] = path_1.default.resolve(root, src[ns]);
31
31
  }
32
- cache_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_PSR4, root, map);
32
+ cache_manager_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_PSR4, root, map);
33
33
  return map;
34
34
  }
35
35
  catch {
36
- cache_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_PSR4, root, {});
36
+ cache_manager_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_PSR4, root, {});
37
37
  return {};
38
38
  }
39
39
  }
@@ -0,0 +1,4 @@
1
+ export declare const CODE_EXTS: string[];
2
+ export declare const BASE_EXTS: string[];
3
+ export declare const REAL_EXTS: Set<string>;
4
+ export declare const DTS_EXT = ".d.ts";
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DTS_EXT = exports.REAL_EXTS = exports.BASE_EXTS = exports.CODE_EXTS = void 0;
4
+ exports.CODE_EXTS = [".js", ".mjs", ".ts", ".tsx", ".d.ts", ".php"];
5
+ exports.BASE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs"];
6
+ exports.REAL_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".d.ts", ".json"]);
7
+ exports.DTS_EXT = ".d.ts";
@@ -0,0 +1,5 @@
1
+ import type { ResolverResult } from "../types";
2
+ export declare function newResolverStats(): ResolverResult["stats"];
3
+ export declare function emptyResolverResult(): ResolverResult;
4
+ export declare function resolverSetDiff<A>(left: Set<A>, right: Set<A>): Set<A>;
5
+ export declare function uniqueResolvedFiles(files: string[]): string[];
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.newResolverStats = newResolverStats;
4
+ exports.emptyResolverResult = emptyResolverResult;
5
+ exports.resolverSetDiff = resolverSetDiff;
6
+ exports.uniqueResolvedFiles = uniqueResolvedFiles;
7
+ function newResolverStats() {
8
+ return { expected: new Set(), resolved: new Set() };
9
+ }
10
+ function emptyResolverResult() {
11
+ return { files: [], stats: newResolverStats() };
12
+ }
13
+ function resolverSetDiff(left, right) {
14
+ return new Set([...left].filter((item) => !right.has(item)));
15
+ }
16
+ function uniqueResolvedFiles(files) {
17
+ return [...new Set(files)];
18
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Centralized exclusion logic.
3
+ * Accepts namespaces, absolute paths, or relative paths
4
+ * and converts everything to a normalized, root-relative glob target.
5
+ */
6
+ export declare function isExcluded(p: string, patterns?: string[], root?: string): boolean;
@@ -4,10 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isExcluded = isExcluded;
7
- // File: src/shared/patterns.ts
8
7
  const micromatch_1 = __importDefault(require("micromatch"));
9
8
  const path_1 = __importDefault(require("path"));
10
- const _1 = require(".");
9
+ const read_file_1 = require("../filesystem/read-file");
10
+ const path_2 = require("../filesystem/path");
11
11
  /**
12
12
  * Centralized exclusion logic.
13
13
  * Accepts namespaces, absolute paths, or relative paths
@@ -18,10 +18,10 @@ function isExcluded(p, patterns = [], root = process.cwd()) {
18
18
  return false;
19
19
  if (!p)
20
20
  return false;
21
- let norm = p.norm();
21
+ let norm = (0, path_2.normalizePath)(p);
22
22
  if (!path_1.default.isAbsolute(norm) && /^[A-Z]/.test(norm))
23
23
  return false;
24
24
  if (path_1.default.isAbsolute(norm))
25
- norm = (0, _1.rel)(norm, root).norm();
25
+ norm = (0, path_2.normalizePath)((0, read_file_1.rel)(norm, root));
26
26
  return micromatch_1.default.isMatch(norm, patterns);
27
27
  }
@@ -0,0 +1,5 @@
1
+ import type { ProdexConfig } from "../types";
2
+ export declare function followChain(entryFiles: string[], cfg: ProdexConfig): Promise<{
3
+ files: string[];
4
+ stats: import("../types").TraceStats;
5
+ }>;
@@ -0,0 +1,63 @@
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
+ const path_1 = __importDefault(require("path"));
8
+ const logger_1 = require("../diagnostics/logger");
9
+ const exclude_1 = require("./exclude");
10
+ const trace_stats_1 = require("./trace-stats");
11
+ const resolver_registry_1 = require("./resolver-registry");
12
+ async function followChain(entryFiles, cfg) {
13
+ const limit = cfg.resolve.maxFiles;
14
+ const resolverDepth = cfg.resolve.maxDepth;
15
+ logger_1.logger.debug("Following dependency chain...");
16
+ const visited = new Set();
17
+ const all = [];
18
+ const stats = (0, trace_stats_1.newStats)();
19
+ for (const file of entryFiles) {
20
+ await visitFile(file, 0);
21
+ }
22
+ return {
23
+ files: (0, trace_stats_1.unique)(all),
24
+ stats,
25
+ };
26
+ async function visitFile(file, depth) {
27
+ if (visited.has(file))
28
+ return;
29
+ visited.add(file);
30
+ all.push(file);
31
+ if (limit && all.length >= limit) {
32
+ logger_1.logger.warn("File limit reached:", limit);
33
+ return;
34
+ }
35
+ if (depth >= resolverDepth)
36
+ return;
37
+ const ext = path_1.default.extname(file);
38
+ if (!(0, resolver_registry_1.hasResolver)(ext))
39
+ return;
40
+ const resolver = (0, resolver_registry_1.getResolver)(ext);
41
+ if (!resolver)
42
+ return;
43
+ const params = { cfg, filePath: file };
44
+ let result = null;
45
+ try {
46
+ result = await resolver(params);
47
+ }
48
+ catch (err) {
49
+ logger_1.logger.warn(`Resolver failed for ${file}:`, err.message || err);
50
+ return;
51
+ }
52
+ if (!result)
53
+ return;
54
+ (0, trace_stats_1.mergeStats)(stats, result.stats);
55
+ for (const resolvedFile of result.files) {
56
+ if ((0, exclude_1.isExcluded)(resolvedFile, cfg.exclude, cfg.root))
57
+ continue;
58
+ if (limit && all.length >= limit)
59
+ return;
60
+ await visitFile(resolvedFile, depth + 1);
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,2 @@
1
+ import type { ProdexConfig } from "../types";
2
+ export declare function applyIncludes(cfg: ProdexConfig, files: string[]): Promise<string[]>;
@@ -0,0 +1,36 @@
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.applyIncludes = applyIncludes;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const glob_scan_1 = require("../filesystem/glob-scan");
10
+ const path_2 = require("../filesystem/path");
11
+ const trace_stats_1 = require("./trace-stats");
12
+ async function applyIncludes(cfg, files) {
13
+ const { include, root } = cfg;
14
+ const absoluteFiles = [];
15
+ const patterns = [];
16
+ for (const raw of include) {
17
+ const candidate = String(raw ?? "").trim();
18
+ if (!candidate)
19
+ continue;
20
+ const normalized = (0, path_2.normalizePath)(candidate);
21
+ if (path_1.default.isAbsolute(normalized)) {
22
+ try {
23
+ if (fs_1.default.statSync(normalized).isFile()) {
24
+ absoluteFiles.push(path_1.default.resolve(normalized));
25
+ continue;
26
+ }
27
+ }
28
+ catch {
29
+ // Treat unreadable absolute paths as glob patterns so include handling stays consistent.
30
+ }
31
+ }
32
+ patterns.push(normalized);
33
+ }
34
+ const scan = await (0, glob_scan_1.globScan)(patterns, { cwd: root });
35
+ return (0, trace_stats_1.unique)([...files, ...absoluteFiles, ...scan.files]);
36
+ }
@@ -0,0 +1,5 @@
1
+ import type { ResolverParams, ResolverResult } from "../types";
2
+ type Resolver = (params: ResolverParams) => Promise<ResolverResult>;
3
+ export declare function hasResolver(extension: string): boolean;
4
+ export declare function getResolver(extension: string): Resolver | undefined;
5
+ export {};
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hasResolver = hasResolver;
4
+ exports.getResolver = getResolver;
5
+ const resolver_constants_1 = require("../resolvers/resolver-constants");
6
+ const js_resolver_1 = require("../resolvers/js/js-resolver");
7
+ const php_resolver_1 = require("../resolvers/php/php-resolver");
8
+ const RESOLVERS = {
9
+ ".php": php_resolver_1.resolvePhpImports,
10
+ ".ts": js_resolver_1.resolveJsImports,
11
+ ".tsx": js_resolver_1.resolveJsImports,
12
+ ".d.ts": js_resolver_1.resolveJsImports,
13
+ ".js": js_resolver_1.resolveJsImports,
14
+ };
15
+ function hasResolver(extension) {
16
+ return resolver_constants_1.CODE_EXTS.includes(extension) && !!RESOLVERS[extension];
17
+ }
18
+ function getResolver(extension) {
19
+ return RESOLVERS[extension];
20
+ }
@@ -0,0 +1,2 @@
1
+ import type { TraceParams, TraceResult } from "../types";
2
+ export declare function runTrace({ cfg, opts }: TraceParams): Promise<TraceResult>;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runTrace = runTrace;
4
+ const follow_chain_1 = require("./follow-chain");
5
+ const include_files_1 = require("./include-files");
6
+ const naming_1 = require("../output/naming");
7
+ const produce_output_1 = require("../output/produce-output");
8
+ async function runTrace({ cfg, opts }) {
9
+ const entries = opts.entries ?? [];
10
+ const result = entries.length ? await (0, follow_chain_1.followChain)(entries, cfg) : undefined;
11
+ const files = await (0, include_files_1.applyIncludes)(cfg, result?.files ?? []);
12
+ if (!files.length) {
13
+ return { entries, files: [], stats: result?.stats };
14
+ }
15
+ const outputPath = await (0, produce_output_1.produceOutput)({
16
+ name: opts.outputName ?? (0, naming_1.smartNaming)(entries),
17
+ files,
18
+ cfg,
19
+ });
20
+ return { outputPath, entries, files, stats: result?.stats };
21
+ }
@@ -0,0 +1,4 @@
1
+ import type { TraceStats } from "../types";
2
+ export declare function newStats(): TraceStats;
3
+ export declare function mergeStats(target: TraceStats, src: TraceStats): TraceStats;
4
+ export declare function unique<T>(arr: T[]): T[];
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.newStats = newStats;
4
+ exports.mergeStats = mergeStats;
5
+ exports.unique = unique;
6
+ function newStats() {
7
+ return { expected: new Set(), resolved: new Set() };
8
+ }
9
+ function mergeStats(target, src) {
10
+ src.expected.forEach((item) => target.expected.add(item));
11
+ src.resolved.forEach((item) => target.resolved.add(item));
12
+ return target;
13
+ }
14
+ function unique(arr) {
15
+ return [...new Set(arr)];
16
+ }
@@ -0,0 +1,62 @@
1
+ import type { MigrationCommandResult } from "../config/migration";
2
+ import type { ProdexFlags } from "./cli.types";
3
+ import type { ProdexConfig } from "./config.types";
4
+ import type { ChainResult } from "./tracing.types";
5
+ export type CliCommand = {
6
+ kind: "run";
7
+ rootArg?: string;
8
+ flags: Partial<ProdexFlags>;
9
+ } | {
10
+ kind: "init";
11
+ rootArg?: string;
12
+ force?: boolean;
13
+ } | {
14
+ kind: "profiles";
15
+ rootArg?: string;
16
+ } | {
17
+ kind: "migrate";
18
+ rootArg?: string;
19
+ write?: boolean;
20
+ check?: boolean;
21
+ } | {
22
+ kind: "help";
23
+ topic?: string;
24
+ } | {
25
+ kind: "version";
26
+ };
27
+ export interface CliParseResult {
28
+ command?: CliCommand;
29
+ warnings: string[];
30
+ errors: string[];
31
+ }
32
+ export interface RunPlan {
33
+ root: string;
34
+ config: ProdexConfig;
35
+ flags: Partial<ProdexFlags>;
36
+ outputName?: string;
37
+ profile?: string;
38
+ }
39
+ export interface RunResult {
40
+ ok: boolean;
41
+ root: string;
42
+ mode: "trace" | "include-only" | "mixed";
43
+ outputPath?: string;
44
+ outputName?: string;
45
+ entries: string[];
46
+ includes: string[];
47
+ files: string[];
48
+ stats?: ChainResult["stats"];
49
+ warnings: string[];
50
+ errors: string[];
51
+ profile?: string;
52
+ }
53
+ export interface CommandResult {
54
+ ok: boolean;
55
+ exitCode: number;
56
+ message?: string;
57
+ profiles?: string[];
58
+ migration?: MigrationCommandResult;
59
+ warnings: string[];
60
+ errors: string[];
61
+ runs: RunResult[];
62
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,22 @@
1
+ export interface ProdexFlags {
2
+ /** Entry globs or file paths. Repeatable and comma-aware. */
3
+ entry?: string[];
4
+ /** Extra files or globs appended without dependency resolution. */
5
+ include?: string[];
6
+ /** Files or globs to skip during traversal. */
7
+ exclude?: string[];
8
+ /** Output format override. */
9
+ format?: "md" | "txt";
10
+ /** Output basename override for this run. */
11
+ name?: string | null;
12
+ /** Maximum dependency traversal depth. */
13
+ maxDepth?: number | null;
14
+ /** Maximum number of files to trace. */
15
+ maxFiles?: number | null;
16
+ /** Enable debug logs. */
17
+ debug?: boolean;
18
+ /** Named profiles to run, in user-provided order. */
19
+ profiles?: string[];
20
+ /** Run all configured profiles. */
21
+ allProfiles?: boolean;
22
+ }
@@ -1,12 +1,2 @@
1
1
  "use strict";
2
- /**
3
- * CLI flag schema for Prodex.
4
- * Mirrors the current CLI synopsis:
5
- *
6
- * prodex [entries...] [-tcdv]
7
- * [--txt] [--ci] [--debug] [--verbose]
8
- * [--name=<string>|-n=<string>]
9
- * [--limit=<int>|-l=<int>]
10
- * [--inc=<globs>] [--exc=<globs>]
11
- */
12
2
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,34 @@
1
+ export interface ProdexConfig extends ProdexBase {
2
+ root: string;
3
+ name?: string;
4
+ }
5
+ export type ProdexConfigFile = DeepPartial<ProdexBase> & {
6
+ $schema: string;
7
+ version: number;
8
+ };
9
+ export type DeepPartial<T> = {
10
+ [K in keyof T]?: T[K] extends Array<infer Item> ? Item[] : T[K] extends object ? DeepPartial<T[K]> : T[K];
11
+ };
12
+ export type ProdexProfile = {
13
+ name?: string;
14
+ entry?: string[];
15
+ include?: string[];
16
+ exclude?: string[];
17
+ };
18
+ interface ProdexBase {
19
+ output: {
20
+ dir: string;
21
+ versioned: boolean;
22
+ format: "md" | "txt";
23
+ };
24
+ entry: string[];
25
+ include: string[];
26
+ exclude: string[];
27
+ resolve: {
28
+ aliases: Record<string, string>;
29
+ maxDepth: number;
30
+ maxFiles: number;
31
+ };
32
+ profiles: Record<string, ProdexProfile>;
33
+ }
34
+ export {};
@@ -0,0 +1,7 @@
1
+ export * from "./config.types";
2
+ export * from "./cli.types";
3
+ export * from "./tracing.types";
4
+ export * from "./output.types";
5
+ export * from "./resolver.types";
6
+ export * from "./utils.types";
7
+ export * from "./app.types";