prodex 1.3.0 → 1.4.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 (42) hide show
  1. package/README.md +234 -234
  2. package/dist/cli/cli-input.js +20 -26
  3. package/dist/cli/init.js +4 -5
  4. package/dist/cli/picker.js +8 -7
  5. package/dist/cli/summary.js +15 -9
  6. package/dist/constants/cache-keys.js +11 -0
  7. package/dist/constants/config.js +6 -5
  8. package/dist/constants/flags.js +73 -0
  9. package/dist/constants/index.js +20 -0
  10. package/dist/constants/render-constants.js +0 -4
  11. package/dist/core/combine.js +31 -13
  12. package/dist/core/dependency.js +39 -19
  13. package/dist/core/helpers.js +42 -38
  14. package/dist/core/managers/cache.js +53 -0
  15. package/dist/core/managers/config.js +103 -0
  16. package/dist/core/renderers.js +9 -8
  17. package/dist/debug.js +13 -0
  18. package/dist/index.js +42 -13
  19. package/dist/lib/logger.js +37 -9
  20. package/dist/lib/polyfills.js +0 -10
  21. package/dist/lib/utils.js +0 -13
  22. package/dist/{core/parsers → resolvers/js}/extract-imports.js +1 -7
  23. package/dist/resolvers/js/js-resolver.js +92 -116
  24. package/dist/resolvers/js/resolve-alias.js +57 -0
  25. package/dist/resolvers/php/bindings.js +20 -9
  26. package/dist/resolvers/php/extract-imports.js +49 -0
  27. package/dist/resolvers/php/php-resolver.js +98 -59
  28. package/dist/resolvers/php/psr4.js +18 -5
  29. package/dist/shared/collections.js +33 -0
  30. package/dist/shared/index.js +19 -0
  31. package/dist/shared/io.js +51 -0
  32. package/dist/shared/patterns.js +29 -0
  33. package/dist/store.js +15 -0
  34. package/package.json +5 -4
  35. package/dist/cli/flags.js +0 -42
  36. package/dist/constants/config-loader.js +0 -95
  37. package/dist/core/file-utils.js +0 -41
  38. package/dist/resolvers/js/alias-loader.js +0 -52
  39. package/dist/resolvers/php/patterns.js +0 -17
  40. package/dist/resolvers/shared/excludes.js +0 -11
  41. package/dist/resolvers/shared/file-cache.js +0 -29
  42. package/dist/resolvers/shared/stats.js +0 -17
package/dist/debug.js ADDED
@@ -0,0 +1,13 @@
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
+ (async () => {
8
+ const mockArgs = ["node", "prodex", "C:\\Users\\USER\\Herd\\fireshot", "-f", "**/(dashboard|accounts).tsx", "-cd"];
9
+ process.argv = mockArgs;
10
+ console.log("🧩 Debug runner starting...");
11
+ await (0, index_1.default)();
12
+ console.log("🧩 Debug runner done.");
13
+ })();
package/dist/index.js CHANGED
@@ -1,26 +1,55 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.default = startProdex;
4
- const combine_1 = require("./core/combine");
5
37
  const init_1 = require("./cli/init");
6
38
  const cli_input_1 = require("./cli/cli-input");
7
- const config_loader_1 = require("./constants/config-loader");
8
- require("./lib/polyfills");
9
- const summary_1 = require("./cli/summary");
10
- async function startProdex() {
11
- const args = process.argv;
12
- // Handle init mode
13
- if (args.includes("init")) {
39
+ const config_1 = require("./core/managers/config");
40
+ const store_1 = require("./store");
41
+ const combine_1 = require("./core/combine");
42
+ async function startProdex(args = process.argv) {
43
+ if (args.includes("init"))
14
44
  return (0, init_1.initProdex)();
15
- }
16
- // Parse CLI input
17
45
  const { root, flags } = (0, cli_input_1.parseCliInput)(args);
18
- // Load and merge configuration (with flag overrides)
19
- const config = await (0, config_loader_1.loadProdexConfig)(flags, root);
20
- (0, summary_1.introSummary)({ flags, config });
46
+ const userConfig = config_1.ConfigManager.load(root);
47
+ const config = config_1.ConfigManager.merge(userConfig, flags, root);
48
+ (0, store_1.setGlobals)(config, flags);
21
49
  const opts = {
22
50
  showUi: !flags.ci && !flags?.files?.length && !config?.entry?.ui?.enablePicker,
23
51
  cliName: config.name,
24
52
  };
53
+ await Promise.resolve().then(() => __importStar(require("./lib/polyfills")));
25
54
  await (0, combine_1.runCombine)({ cfg: config, opts });
26
55
  }
@@ -1,14 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.logger = void 0;
4
- const env = () => {
5
- const obj = { debug: process.env.PRODEX_DEBUG === "1", silent: process.env.PRODEX_SILENT === "1" };
6
- return obj;
7
- };
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
+ }
8
15
  exports.logger = {
9
- debug: (...args) => !env().silent && env().debug && console.log("\n🪶 [debug]", ...args),
10
- info: (...args) => !env().silent && console.log("\n📌 [info]", ...args),
11
- warn: (...args) => !env().silent && console.warn("\n⚠️ [warn]", ...args),
12
- error: (...args) => !env().silent && console.error("\n💥 [error]", ...args),
13
- log: (...args) => !env().silent && console.log("\n", ...args),
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(),
14
42
  };
@@ -15,13 +15,3 @@ if (!String.prototype.clean) {
15
15
  };
16
16
  }
17
17
  globalThis._2j = (obj) => util_1.default.inspect(obj, { colors: true, depth: null, breakLength: 150, compact: 3 });
18
- globalThis._bpt = function (param) {
19
- if (process.env.PRODEX_DEBUG !== "1")
20
- return;
21
- console.log("⭕ BREAKPOINT");
22
- if (typeof param === "function")
23
- param();
24
- else
25
- console.log(_2j(param));
26
- process.exit(1);
27
- };
package/dist/lib/utils.js CHANGED
@@ -1,21 +1,8 @@
1
1
  "use strict";
2
- // @ts-nocheck
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.unique = unique;
5
- exports.setDiff = setDiff;
6
- exports.toArray = toArray;
7
3
  exports.shortTimestamp = shortTimestamp;
8
4
  exports.normalizePatterns = normalizePatterns;
9
5
  const config_1 = require("../constants/config");
10
- function unique(arr) {
11
- return [...new Set(arr)];
12
- }
13
- function setDiff(A, B) {
14
- return new Set([...A].filter((x) => !B.has(x)));
15
- }
16
- function toArray(v) {
17
- return Array.isArray(v) ? v : [v];
18
- }
19
6
  /** Compact YYMMDD-HHmm timestamp for versioned filenames. */
20
7
  function shortTimestamp() {
21
8
  const d = new Date();
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // @ts-nocheck
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
@@ -35,12 +34,7 @@ async function extractImports(filePath, code) {
35
34
  }
36
35
  }
37
36
  function fallbackRegex(code) {
38
- const patterns = [
39
- /import\s+[^'"]*['"]([^'"]+)['"]/g,
40
- /import\(\s*['"]([^'"]+)['"]\s*\)/g,
41
- /require\(\s*['"]([^'"]+)['"]\s*\)/g,
42
- /export\s+\*\s+from\s+['"]([^'"]+)['"]/g,
43
- ];
37
+ const patterns = [/import\s+[^'"]*['"]([^'"]+)['"]/g, /import\(\s*['"]([^'"]+)['"]\s*\)/g, /require\(\s*['"]([^'"]+)['"]\s*\)/g, /export\s+\*\s+from\s+['"]([^'"]+)['"]/g];
44
38
  const matches = new Set();
45
39
  for (const r of patterns) {
46
40
  let m;
@@ -1,153 +1,129 @@
1
1
  "use strict";
2
- // @ts-nocheck
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
6
5
  Object.defineProperty(exports, "__esModule", { value: true });
7
6
  exports.resolveJsImports = resolveJsImports;
8
- const promises_1 = __importDefault(require("fs/promises"));
9
7
  const path_1 = __importDefault(require("path"));
10
- const micromatch_1 = __importDefault(require("micromatch"));
11
- const extract_imports_1 = require("../../core/parsers/extract-imports");
12
- const alias_loader_1 = require("./alias-loader");
8
+ const extract_imports_1 = require("./extract-imports");
13
9
  const config_1 = require("../../constants/config");
14
- const utils_1 = require("../../lib/utils");
10
+ const collections_1 = require("../../shared/collections");
15
11
  const logger_1 = require("../../lib/logger");
16
- const IMPORTS_CACHE = new Map();
17
- const STAT_CACHE = new Map();
18
- async function resolveJsImports(filePath, cfg, visited = new Set(), depth = 0, maxDepth = cfg?.resolve?.depth ?? 8, ctx = {}) {
19
- if (depth >= maxDepth)
20
- return empty(visited);
21
- const ROOT = cfg.root;
22
- const resolveCfg = cfg.resolve ?? {};
23
- // Single exclude list, applied to RAW SPECIFIERS only.
24
- const exclude = resolveCfg.exclude ?? [];
25
- const isExcluded = micromatch_1.default.matcher(exclude);
12
+ const store_1 = require("../../store");
13
+ const resolve_alias_1 = require("./resolve-alias"); // alias: config + cache + fast-glob
14
+ const cache_1 = require("../../core/managers/cache");
15
+ const cache_keys_1 = require("../../constants/cache-keys");
16
+ const shared_1 = require("../../shared");
17
+ const shared_2 = require("../../shared");
18
+ const { JS_STATS, JS_IMPORTS } = cache_keys_1.CACHE_KEYS;
19
+ async function resolveJsImports({ filePath, visited = new Set(), depth = 0, maxDepth }) {
20
+ const limitDepth = maxDepth;
21
+ if (depth >= limitDepth)
22
+ return (0, collections_1.emptyResult)(visited);
26
23
  if (visited.has(filePath))
27
- return empty(visited);
24
+ return (0, collections_1.emptyResult)(visited);
28
25
  visited.add(filePath);
26
+ const { root: ROOT, resolve: { exclude: excludePatterns }, } = (0, store_1.getConfig)();
29
27
  const ext = path_1.default.extname(filePath).toLowerCase();
30
28
  const isDts = ext === config_1.DTS_EXT;
31
29
  if (!config_1.BASE_EXTS.includes(ext) && !isDts)
32
- return empty(visited);
33
- let code;
34
- try {
35
- code = await promises_1.default.readFile(filePath, "utf8");
36
- }
37
- catch {
38
- return empty(visited);
39
- }
40
- if (!ctx.aliases) {
41
- ctx.aliases = { ...(0, alias_loader_1.loadProjectAliases)(ROOT), ...(resolveCfg.aliases || {}) };
42
- }
43
- const aliases = ctx.aliases;
44
- const matches = await getImportsCached(filePath, code);
45
- if (!matches.size)
46
- return empty(visited);
47
- const filesOut = [];
30
+ return (0, collections_1.emptyResult)(visited);
31
+ let code = (0, shared_1.readFileSafe)(filePath);
32
+ if (!code)
33
+ return (0, collections_1.emptyResult)(visited);
34
+ // Extract imports ---------------------------------------
35
+ const imports = await getImportsCached(filePath, code);
36
+ if (!imports.size)
37
+ return (0, collections_1.emptyResult)(visited);
38
+ // Trackers ----------------------------------------------
48
39
  const expected = new Set();
49
- const resolvedSet = new Set();
50
- for (const imp of matches) {
51
- // Only consider relative, absolute, or known-alias specifiers
52
- if (!imp.startsWith(".") && !imp.startsWith("/") && !startsWithAnyAlias(imp, aliases)) {
40
+ const resolved = new Set();
41
+ const files = [];
42
+ // Main resolution loop ----------------------------------
43
+ for (const imp of imports) {
44
+ // skip bare packages (react, lodash, etc.)
45
+ if (!imp.startsWith(".") && !imp.startsWith("/") && !imp.startsWith("@"))
53
46
  continue;
54
- }
55
- // Apply single exclude matcher to the RAW specifier
56
- if (isExcluded(imp))
47
+ if ((0, shared_1.isExcluded)(imp, excludePatterns))
57
48
  continue;
58
- // Always count valid, non-excluded specifiers as "expected"
59
- expected.add(imp);
60
- const basePath = resolveBasePath(filePath, imp, aliases);
61
- if (!basePath)
49
+ let base = null;
50
+ if (imp.startsWith(".")) {
51
+ // relative like original resolver
52
+ base = path_1.default.resolve(path_1.default.dirname(filePath), imp);
53
+ }
54
+ else if (imp.startsWith("/")) {
55
+ // absolute path import → like original resolver
56
+ base = path_1.default.resolve(imp);
57
+ }
58
+ else {
59
+ // alias (@...) → unified resolver (config + cache + glob)
60
+ base = await (0, resolve_alias_1.resolveAliasPath)(imp, ROOT, (0, store_1.getConfig)());
61
+ }
62
+ if (!base)
62
63
  continue;
63
- const resolvedPath = await tryResolveImport(basePath, ROOT);
64
+ const absBase = path_1.default.resolve(base);
65
+ expected.add(absBase);
66
+ const resolvedPath = await tryResolveImport(absBase);
64
67
  if (!resolvedPath)
65
68
  continue;
66
- filesOut.push(resolvedPath);
67
- resolvedSet.add(imp);
68
- // Never recurse into `.d.ts`
69
- if (resolvedPath.toLowerCase().endsWith(config_1.DTS_EXT)) {
70
- continue;
71
- logger_1.logger.debug("HERE HERE");
72
- }
73
- const sub = await resolveJsImports(resolvedPath, cfg, visited, depth + 1, maxDepth, ctx);
74
- if (sub.files.length)
75
- filesOut.push(...sub.files);
76
- for (const s of sub.stats.expected)
77
- expected.add(s);
69
+ resolved.add(absBase);
70
+ files.push(resolvedPath);
71
+ // Recursive traversal
72
+ const sub = await resolveJsImports({
73
+ filePath: resolvedPath,
74
+ visited,
75
+ depth: depth + 1,
76
+ maxDepth: limitDepth,
77
+ });
78
+ files.push(...sub.files);
79
+ for (const e of sub.stats.expected)
80
+ expected.add(e);
78
81
  for (const r of sub.stats.resolved)
79
- resolvedSet.add(r);
82
+ resolved.add(r);
80
83
  }
81
- const uniqueFiles = [...new Set(filesOut)];
82
- //Stat Log
83
- const expCount = expected.size;
84
- const resCount = resolvedSet.size;
85
- const diff = (0, utils_1.setDiff)(expected, resolvedSet);
86
- logger_1.logger.debug(`🪶 [js-resolver] ${filePath} expected: ${expCount}, resolved: ${resCount}`);
87
- logger_1.logger.debug([...diff], "🔴THE diff");
88
- return { files: uniqueFiles, visited, stats: { expected, resolved: resolvedSet } };
89
- }
90
- // ---------- helpers ----------
91
- function startsWithAnyAlias(imp, aliases) {
92
- return Object.keys(aliases).some((a) => imp === a || imp.startsWith(a + "/"));
84
+ const uniqueFiles = (0, collections_1.unique)(files);
85
+ const diff = (0, shared_2.setDiff)(expected, resolved);
86
+ logger_1.logger.debug(`🪶 [js-resolver] ${filePath} expected: ${expected.size}, resolved: ${resolved.size}`);
87
+ if (diff.size)
88
+ logger_1.logger.debug([...diff], "🔴 THE diff");
89
+ return { files: uniqueFiles, visited, stats: { expected, resolved } };
93
90
  }
94
- function resolveBasePath(fromFile, specifier, aliases) {
95
- if (specifier.startsWith("@")) {
96
- const key = Object.keys(aliases)
97
- .filter((a) => specifier === a || specifier.startsWith(a + "/"))
98
- .sort((a, b) => b.length - a.length)[0];
99
- if (!key)
100
- return null;
101
- const relPart = specifier.slice(key.length).replace(/^\/+/, "");
102
- return path_1.default.resolve(aliases[key], relPart);
103
- }
104
- if (specifier.startsWith(".")) {
105
- return path_1.default.resolve(path_1.default.dirname(fromFile), specifier);
106
- }
107
- if (specifier.startsWith("/")) {
108
- return path_1.default.resolve(specifier);
109
- }
110
- return null;
111
- }
112
- async function tryResolveImport(basePath, ROOT) {
91
+ // ---------------------------------------------------------
92
+ // tryResolveImport (pure)
93
+ // ---------------------------------------------------------
94
+ async function tryResolveImport(basePath) {
113
95
  const candidates = [];
114
- if (path_1.default.extname(basePath)) {
96
+ const ext = path_1.default.extname(basePath).toLowerCase();
97
+ if (ext && config_1.REAL_EXTS.has(ext)) {
115
98
  candidates.push(basePath);
116
99
  }
117
100
  else {
118
- for (const ext of [...config_1.BASE_EXTS, config_1.DTS_EXT]) {
119
- candidates.push(basePath + ext);
120
- candidates.push(path_1.default.join(basePath, "index" + ext));
101
+ for (const e of [...config_1.BASE_EXTS, config_1.DTS_EXT]) {
102
+ candidates.push(basePath + e);
103
+ candidates.push(path_1.default.join(basePath, "index" + e));
121
104
  }
122
105
  }
123
- for (const c of candidates) {
106
+ // Run all stat checks in parallel
107
+ const results = await Promise.allSettled(candidates.map(async (c) => {
124
108
  const abs = path_1.default.resolve(c);
125
- const st = await safeStat(abs);
126
- if (st && st.isFile())
127
- return abs;
109
+ const st = await (0, shared_1.safeStatCached)(JS_STATS, abs);
110
+ return st && st.isFile() ? abs : null;
111
+ }));
112
+ // Find the first fulfilled non-null result
113
+ for (const r of results) {
114
+ if (r.status === "fulfilled" && r.value)
115
+ return r.value;
128
116
  }
129
117
  return null;
130
118
  }
131
- async function safeStat(p) {
132
- if (STAT_CACHE.has(p))
133
- return STAT_CACHE.get(p);
134
- try {
135
- const st = await promises_1.default.stat(p);
136
- STAT_CACHE.set(p, st);
137
- return st;
138
- }
139
- catch {
140
- STAT_CACHE.set(p, null);
141
- return null;
142
- }
143
- }
119
+ // ---------------------------------------------------------
120
+ // Cached stat + import scanners
121
+ // ---------------------------------------------------------
144
122
  async function getImportsCached(filePath, code) {
145
- if (IMPORTS_CACHE.has(filePath))
146
- return IMPORTS_CACHE.get(filePath);
123
+ const cached = cache_1.CacheManager.get(JS_IMPORTS, filePath);
124
+ if (cached)
125
+ return cached;
147
126
  const set = await (0, extract_imports_1.extractImports)(filePath, code);
148
- IMPORTS_CACHE.set(filePath, set);
127
+ cache_1.CacheManager.set(JS_IMPORTS, filePath, set);
149
128
  return set;
150
129
  }
151
- function empty(visited) {
152
- return { files: [], visited, stats: { expected: new Set(), resolved: new Set() } };
153
- }
@@ -0,0 +1,57 @@
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.resolveAliasPath = resolveAliasPath;
7
+ const path_1 = __importDefault(require("path"));
8
+ const cache_1 = require("../../core/managers/cache");
9
+ const constants_1 = require("../../constants");
10
+ const helpers_1 = require("../../core/helpers");
11
+ /**
12
+ * 🧩 resolveAliasPath()
13
+ * Unifies alias lookup across config, cache, and fallback discovery.
14
+ *
15
+ * - Checks cfg.resolve.aliases first.
16
+ * - Then cached aliases (from Cache Manager).
17
+ * - If still unresolved, runs Fast-Glob to discover and cache new alias root.
18
+ */
19
+ async function resolveAliasPath(specifier, root, cfg) {
20
+ if (!specifier.includes("/"))
21
+ return null;
22
+ const [aliasName, ...rest] = specifier.split("/");
23
+ const remainder = rest.join("/");
24
+ const knownAliases = cfg.resolve.aliases || {};
25
+ const aliasKey = aliasName.startsWith("@") ? aliasName : `@${aliasName}`;
26
+ // 1️⃣ Check config-defined aliases
27
+ if (knownAliases[aliasKey]) {
28
+ const relPart = remainder.replace(/^\/+/, "");
29
+ return path_1.default.resolve(root, knownAliases[aliasKey], relPart);
30
+ }
31
+ // 2️⃣ Check cached aliases
32
+ const cached = cache_1.CacheManager.get(constants_1.CACHE_KEYS.ALIASES, aliasKey);
33
+ if (cached) {
34
+ const relPart = remainder.replace(/^\/+/, "");
35
+ return path_1.default.resolve(root, cached, relPart);
36
+ }
37
+ // 3️⃣ Fallback discovery with Fast-Glob
38
+ const stripped = remainder; // remove prefix before first '/'
39
+ const hasExt = /\.[a-z0-9]+$/i.test(stripped);
40
+ const patterns = hasExt ? [`**/${stripped}`] : [`**/${stripped}.*`, `**/${stripped}/index.*`];
41
+ const { files: matches } = await (0, helpers_1.globScan)(patterns, { cwd: root });
42
+ if (matches.length === 1) {
43
+ return resolveMatches(matches, remainder, aliasKey);
44
+ }
45
+ //There are multiple matches, Assuming they match the target approximate folder.
46
+ if (matches.length > 1) {
47
+ const resolvedMatch = resolveMatches(matches, remainder, aliasKey);
48
+ return resolvedMatch.replace(/\.[^/.]+$/, "");
49
+ }
50
+ return null;
51
+ }
52
+ function resolveMatches(matches, remainder, aliasKey) {
53
+ const foundFile = matches[0];
54
+ const aliasRoot = foundFile.split(remainder)[0].replace(/\\/g, "/");
55
+ cache_1.CacheManager.set(constants_1.CACHE_KEYS.ALIASES, aliasKey, aliasRoot);
56
+ return foundFile;
57
+ }
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // @ts-nocheck
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
@@ -7,18 +6,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
6
  exports.loadLaravelBindings = loadLaravelBindings;
8
7
  const fs_1 = __importDefault(require("fs"));
9
8
  const path_1 = __importDefault(require("path"));
10
- const config_1 = require("../../constants/config");
11
- function loadLaravelBindings() {
12
- const providersDir = path_1.default.join(config_1.ROOT, "app", "Providers");
9
+ const cache_1 = require("../../core/managers/cache");
10
+ const cache_keys_1 = require("../../constants/cache-keys");
11
+ /**
12
+ * Scans app/Providers/*.php for `$this->app->bind()` / `singleton()` calls
13
+ * and returns a map of Interface::class → Implementation::class (FQCN strings).
14
+ */
15
+ function loadLaravelBindings(root) {
16
+ const cached = cache_1.CacheManager.get(cache_keys_1.CACHE_KEYS.PHP_BINDINGS, root);
17
+ if (cached)
18
+ return cached;
19
+ const providersDir = path_1.default.join(root, "app", "Providers");
13
20
  const bindings = {};
14
- if (!fs_1.default.existsSync(providersDir))
21
+ if (!fs_1.default.existsSync(providersDir)) {
22
+ cache_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_BINDINGS, root, bindings);
15
23
  return bindings;
24
+ }
16
25
  const files = fs_1.default
17
26
  .readdirSync(providersDir)
18
- .filter(f => f.endsWith(".php"))
19
- .map(f => path_1.default.join(providersDir, f));
20
- // Match: $this->app->bind(Interface::class, Implementation::class)
21
- const re = /$this->app->(?:bind|singleton)\s*\(\s*([A-Za-z0-9_:\\\\]+)::class\s*,\s*([A-Za-z0-9_:\\\\]+)::class/g;
27
+ .filter((f) => f.endsWith(".php"))
28
+ .map((f) => path_1.default.join(providersDir, f));
29
+ // $this->app->bind(Interface::class, Implementation::class)
30
+ // $this->app->singleton(Interface::class, Implementation::class)
31
+ const re = /\$this->app->(?:bind|singleton)\s*\(\s*([A-Za-z0-9_:\\\\]+)::class\s*,\s*([A-Za-z0-9_:\\\\]+)::class/g;
22
32
  for (const file of files) {
23
33
  const code = fs_1.default.readFileSync(file, "utf8");
24
34
  let m;
@@ -28,5 +38,6 @@ function loadLaravelBindings() {
28
38
  bindings[iface] = impl;
29
39
  }
30
40
  }
41
+ cache_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_BINDINGS, root, bindings);
31
42
  return bindings;
32
43
  }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractPhpImports = extractPhpImports;
4
+ exports.expandGroupedUses = expandGroupedUses;
5
+ /**
6
+ * Extracts import-like references from PHP code.
7
+ * Supports:
8
+ * - require/include/require_once/include_once
9
+ * - use statements (including grouped imports like `use App\Models\{User, Team};`)
10
+ */
11
+ function extractPhpImports(code) {
12
+ const out = new Set();
13
+ const patterns = [
14
+ /\b(?:require|include|require_once|include_once)\s*\(?['"]([^'"]+)['"]\)?/g,
15
+ /\buse\s+([A-Z][\w\\]+(?:\s*{[^}]+})?)/g,
16
+ ];
17
+ for (const r of patterns) {
18
+ let m;
19
+ while ((m = r.exec(code))) {
20
+ const val = m[1];
21
+ if (val)
22
+ out.add(val);
23
+ }
24
+ }
25
+ return out;
26
+ }
27
+ /**
28
+ * Expands grouped `use` imports into individual fully qualified names.
29
+ * Example:
30
+ * "App\\Models\\{User, Team}" → ["App\\Models\\User", "App\\Models\\Team"]
31
+ */
32
+ function expandGroupedUses(raw) {
33
+ const out = new Set();
34
+ for (const imp of raw) {
35
+ const g = imp.match(/^(.+?)\s*{([^}]+)}/);
36
+ if (g) {
37
+ const base = g[1].trim().replace(/\\+$/, "");
38
+ g[2]
39
+ .split(",")
40
+ .map((x) => x.trim())
41
+ .filter(Boolean)
42
+ .forEach((p) => out.add(`${base}\\${p}`));
43
+ }
44
+ else {
45
+ out.add(imp.trim());
46
+ }
47
+ }
48
+ return out;
49
+ }