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
@@ -1,88 +1,127 @@
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.resolvePhpImports = resolvePhpImports;
8
7
  const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const extract_imports_1 = require("./extract-imports");
9
10
  const bindings_1 = require("./bindings");
10
11
  const psr4_1 = require("./psr4");
11
- const patterns_1 = require("./patterns");
12
12
  const logger_1 = require("../../lib/logger");
13
- const stats_1 = require("../shared/stats");
14
- const file_cache_1 = require("../shared/file-cache");
15
- const excludes_1 = require("../shared/excludes");
16
- async function resolvePhpImports(filePath, cfg, visited = new Set(), depth = 0, maxDepth = cfg?.resolve?.depth ?? 10, ctx = {}) {
17
- if (depth >= maxDepth)
18
- return empty(visited);
19
- const stats = (0, stats_1.newStats)();
20
- const filesOut = [];
21
- const ROOT = cfg.root || process.cwd();
22
- if (!ctx.psr4)
23
- ctx.psr4 = (0, psr4_1.resolvePsr4)(ROOT);
24
- if (!ctx.nsKeys)
25
- ctx.nsKeys = Object.keys(ctx.psr4).sort((a, b) => b.length - a.length);
26
- if (!ctx.bindings)
27
- ctx.bindings = (0, bindings_1.loadLaravelBindings)();
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
+ /** Ensure we have a PHP resolver context for the current root */
19
+ function buildPhpCtx(root, prev) {
20
+ if (prev?.kind === "php")
21
+ return prev;
22
+ const psr4 = (0, psr4_1.resolvePsr4)(root);
23
+ const nsKeys = Object.keys(psr4).sort((a, b) => b.length - a.length);
24
+ const bindings = (0, bindings_1.loadLaravelBindings)(root);
25
+ return { kind: "php", psr4, nsKeys, bindings };
26
+ }
27
+ /** Namespace prefix check */
28
+ function startsWithAnyNamespace(imp, nsKeys) {
29
+ for (const k of nsKeys)
30
+ if (imp.startsWith(k))
31
+ return true;
32
+ return false;
33
+ }
34
+ /**
35
+ * Typed PHP resolver (aligned with JS resolver signature).
36
+ * - Uses global config via getConfig()
37
+ * - Returns ResolverResult (files + stats)
38
+ * - Depth/visited guarded recursion
39
+ */
40
+ async function resolvePhpImports({ filePath, visited = new Set(), depth = 0, maxDepth, ctx }) {
41
+ const { root: ROOT, resolve: { exclude: excludePatterns = [], depth: defaultDepth = 10 }, } = (0, store_1.getConfig)();
42
+ const limitDepth = maxDepth ?? defaultDepth;
43
+ if (depth >= limitDepth)
44
+ return (0, collections_1.emptyResult)(visited);
28
45
  if (visited.has(filePath))
29
- return empty(visited);
46
+ return (0, collections_1.emptyResult)(visited);
30
47
  visited.add(filePath);
48
+ // Fast existence / read
31
49
  if (!fs_1.default.existsSync(filePath))
32
- return empty(visited);
33
- const code = fs_1.default.readFileSync(filePath, "utf8");
34
- const exclude = cfg.imports?.exclude ?? [];
35
- const raw = (0, patterns_1.extractPhpImports)(code);
36
- const imports = expandGroupedUses(raw);
50
+ return (0, collections_1.emptyResult)(visited);
51
+ const code = (0, shared_1.readFileSafe)(filePath);
52
+ if (!code)
53
+ return (0, collections_1.emptyResult)(visited);
54
+ // Context + exclusions
55
+ const phpCtx = buildPhpCtx(ROOT, ctx);
56
+ const isExcluded = (0, shared_1.makeExcludeMatcher)(excludePatterns);
57
+ // Parse imports (expand grouped `use` syntax)
58
+ const raw = (0, extract_imports_1.extractPhpImports)(code);
59
+ const imports = (0, extract_imports_1.expandGroupedUses)(raw);
60
+ // Accumulators
61
+ const stats = (0, shared_1.newStats)();
62
+ const filesOut = [];
37
63
  for (const imp0 of imports) {
38
64
  let imp = imp0;
39
- if (ctx.bindings[imp]) {
40
- log("🔗 Bound:", imp0, "→", ctx.bindings[imp]);
41
- imp = ctx.bindings[imp];
65
+ // Respect Laravel container bindings (Interface → Implementation)
66
+ if (phpCtx.bindings[imp]) {
67
+ logger_1.logger.debug("[php-resolver] binding:", imp, "→", phpCtx.bindings[imp]);
68
+ imp = phpCtx.bindings[imp];
42
69
  }
43
- if (!startsWithAny(imp, ctx.nsKeys))
70
+ // Only resolve PSR-4 mapped namespaces
71
+ if (!startsWithAnyNamespace(imp, phpCtx.nsKeys))
44
72
  continue;
45
- if ((0, excludes_1.isExcluded)(imp, exclude))
73
+ if (isExcluded(imp))
46
74
  continue;
47
75
  stats.expected.add(imp);
48
- const resolvedPath = (0, file_cache_1.tryResolvePhpFile)(imp, filePath, ctx.psr4);
76
+ // Resolve namespace file path (sync helper retained)
77
+ const resolvedPath = await tryResolvePhpFile(imp, filePath, phpCtx.psr4);
49
78
  if (!resolvedPath)
50
79
  continue;
51
80
  stats.resolved.add(imp);
52
81
  filesOut.push(resolvedPath);
53
- const sub = await resolvePhpImports(resolvedPath, cfg, visited, depth + 1, maxDepth, ctx);
82
+ // Recurse
83
+ const sub = await resolvePhpImports({
84
+ filePath: resolvedPath,
85
+ visited,
86
+ depth: depth + 1,
87
+ maxDepth: limitDepth,
88
+ ctx: phpCtx,
89
+ });
54
90
  filesOut.push(...sub.files);
55
- (0, stats_1.mergeStats)(stats, sub.stats);
91
+ (0, shared_1.mergeStats)(stats, sub.stats);
56
92
  }
57
- log("✅ PHP resolver:", filePath, "→", filesOut.length);
58
- return {
59
- files: [...new Set(filesOut)],
60
- visited,
61
- stats
62
- };
93
+ const out = (0, shared_1.unique)(filesOut);
94
+ const unresolved = (0, shared_1.setDiff)(stats.expected, stats.resolved);
95
+ logger_1.logger.debug(`🪶 [php-resolver] ${path_1.default.basename(filePath)} → expected: ${stats.expected.size}, resolved: ${stats.resolved.size}`);
96
+ if (unresolved.size)
97
+ logger_1.logger.debug("[php-resolver] unresolved:", [...unresolved]);
98
+ return { files: out, visited, stats };
63
99
  }
64
- // ---------- Local helpers (resolver-scoped only) ----------
65
- function startsWithAny(imp, nsKeys) {
66
- return nsKeys.some(k => imp.startsWith(k));
67
- }
68
- function empty(visited) {
69
- return { files: [], visited, stats: (0, stats_1.emptyStats)() };
70
- }
71
- const log = (...a) => logger_1.logger.debug("[php-resolver]", ...a);
72
- function expandGroupedUses(raw) {
73
- const out = new Set();
74
- for (const imp of raw) {
75
- const g = imp.match(/^(.+?)\s*{([^}]+)}/);
76
- if (g) {
77
- const base = g[1].trim().replace(/\\+$/, "");
78
- g[2]
79
- .split(",")
80
- .map(x => x.trim())
81
- .forEach(p => out.add(`${base}\\${p}`));
100
+ const promises_1 = __importDefault(require("fs/promises")); // (add near the top if not present)
101
+ async function tryResolvePhpFile(imp, fromFile, psr4) {
102
+ const key = `php:${imp}:${fromFile}`;
103
+ const cached = cache_1.CacheManager.get(constants_1.CACHE_KEYS.PHP_FILECACHE, key);
104
+ if (cached !== undefined)
105
+ return cached;
106
+ const nsKey = Object.keys(psr4).find((k) => imp.startsWith(k));
107
+ if (!nsKey) {
108
+ cache_1.CacheManager.set(constants_1.CACHE_KEYS.PHP_FILECACHE, key, null);
109
+ return null;
110
+ }
111
+ const rel = imp.slice(nsKey.length).norm();
112
+ 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")];
113
+ // 🔹 Run all stats concurrently
114
+ const results = await Promise.allSettled(tries.map(async (p) => {
115
+ try {
116
+ const st = await promises_1.default.stat(p);
117
+ return st.isFile() ? path_1.default.resolve(p) : null;
82
118
  }
83
- else {
84
- out.add(imp.trim());
119
+ catch {
120
+ return null;
85
121
  }
86
- }
87
- return out;
122
+ }));
123
+ //@ts-ignore
124
+ const resolved = results.find((r) => r.status === "fulfilled" && r.value)?.value ?? null;
125
+ cache_1.CacheManager.set(constants_1.CACHE_KEYS.PHP_FILECACHE, key, resolved);
126
+ return resolved;
88
127
  }
@@ -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,20 +6,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
6
  exports.resolvePsr4 = resolvePsr4;
8
7
  const fs_1 = __importDefault(require("fs"));
9
8
  const path_1 = __importDefault(require("path"));
10
- function resolvePsr4(ROOT) {
11
- const composer = path_1.default.join(ROOT, "composer.json");
12
- if (!fs_1.default.existsSync(composer))
9
+ const cache_1 = require("../../core/managers/cache");
10
+ const cache_keys_1 = require("../../constants/cache-keys");
11
+ /**
12
+ * Builds a PSR-4 namespace → directory map from composer.json.
13
+ * Returns absolute paths in the map values.
14
+ */
15
+ function resolvePsr4(root) {
16
+ const cached = cache_1.CacheManager.get(cache_keys_1.CACHE_KEYS.PHP_PSR4, root);
17
+ if (cached)
18
+ return cached;
19
+ const composer = path_1.default.join(root, "composer.json");
20
+ if (!fs_1.default.existsSync(composer)) {
21
+ cache_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_PSR4, root, {});
13
22
  return {};
23
+ }
14
24
  try {
15
25
  const data = JSON.parse(fs_1.default.readFileSync(composer, "utf8"));
16
26
  const src = data.autoload?.["psr-4"] || {};
17
27
  const map = {};
18
28
  for (const ns in src) {
19
- map[ns.replace(/\\+$/, "")] = path_1.default.resolve(ROOT, src[ns]);
29
+ const cleanNs = ns.replace(/\\+$/, "");
30
+ map[cleanNs] = path_1.default.resolve(root, src[ns]);
20
31
  }
32
+ cache_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_PSR4, root, map);
21
33
  return map;
22
34
  }
23
35
  catch {
36
+ cache_1.CacheManager.set(cache_keys_1.CACHE_KEYS.PHP_PSR4, root, {});
24
37
  return {};
25
38
  }
26
39
  }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.newStats = newStats;
4
+ exports.mergeStats = mergeStats;
5
+ exports.setDiff = setDiff;
6
+ exports.unique = unique;
7
+ exports.emptyResult = emptyResult;
8
+ function newStats() {
9
+ return { expected: new Set(), resolved: new Set() };
10
+ }
11
+ function mergeStats(target, src) {
12
+ src.expected.forEach((i) => target.expected.add(i));
13
+ src.resolved.forEach((i) => target.resolved.add(i));
14
+ return target;
15
+ }
16
+ /**
17
+ * Returns a new Set of elements present in A but not in B.
18
+ * Used to detect unresolved imports in JS and PHP resolvers.
19
+ */
20
+ function setDiff(A, B) {
21
+ return new Set([...A].filter((x) => !B.has(x)));
22
+ }
23
+ /**
24
+ * Removes duplicates from an array.
25
+ * Stateless helper used across resolvers and dependency chain.
26
+ */
27
+ function unique(arr) {
28
+ return [...new Set(arr)];
29
+ }
30
+ /** Empty result helper */
31
+ function emptyResult(visited) {
32
+ return { files: [], visited, stats: { expected: new Set(), resolved: new Set() } };
33
+ } // ---------------------------------------------------------
@@ -0,0 +1,19 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./io"), exports);
18
+ __exportStar(require("./patterns"), exports);
19
+ __exportStar(require("./collections"), exports);
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ // File: src/shared/io.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.readFileSafe = readFileSafe;
8
+ exports.safeStatCached = safeStatCached;
9
+ exports.rel = rel;
10
+ const cache_1 = require("../core/managers/cache");
11
+ const path_1 = __importDefault(require("path"));
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const promises_1 = __importDefault(require("fs/promises"));
14
+ /**
15
+ * Read a file safely. Returns "" if the file cannot be read.
16
+ */
17
+ function readFileSafe(p) {
18
+ try {
19
+ return fs_1.default.readFileSync(p, "utf8");
20
+ }
21
+ catch {
22
+ return "";
23
+ }
24
+ }
25
+ /**
26
+ * Cached version of fs.stat().
27
+ * Takes a cache namespace to preserve behavior across resolvers.
28
+ */
29
+ async function safeStatCached(ns, p) {
30
+ const cached = cache_1.CacheManager.get(ns, p);
31
+ if (cached !== undefined)
32
+ return cached;
33
+ try {
34
+ const st = await promises_1.default.stat(p);
35
+ cache_1.CacheManager.set(ns, p, st);
36
+ return st;
37
+ }
38
+ catch {
39
+ cache_1.CacheManager.set(ns, p, null);
40
+ return null;
41
+ }
42
+ }
43
+ /**
44
+ * Return a path relative to a root, normalized for forward slashes.
45
+ */
46
+ function rel(p, root = process.cwd()) {
47
+ return path_1.default.relative(root, p).replaceAll("\\", "/");
48
+ }
49
+ /**
50
+ * Get a root-relative version of a path.
51
+ */
@@ -0,0 +1,29 @@
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.isExcluded = isExcluded;
7
+ exports.makeExcludeMatcher = makeExcludeMatcher;
8
+ // File: src/shared/patterns.ts
9
+ const micromatch_1 = __importDefault(require("micromatch"));
10
+ /**
11
+ * Returns true if a given path matches any of the provided glob patterns.
12
+ * Equivalent to core/helpers.isExcluded().
13
+ */
14
+ function isExcluded(p, patterns = [], root = process.cwd()) {
15
+ if (!patterns?.length)
16
+ return false;
17
+ const relPath = p.replaceAll("\\", "/");
18
+ return micromatch_1.default.isMatch(relPath, patterns);
19
+ }
20
+ /**
21
+ * Builds a reusable micromatch matcher for efficiency.
22
+ * Equivalent to php-resolver.makeExcludeMatcher().
23
+ */
24
+ function makeExcludeMatcher(patterns = []) {
25
+ if (!patterns?.length)
26
+ return () => false;
27
+ const mm = micromatch_1.default.matcher(patterns);
28
+ return (s) => mm(String(s).replace(/\\/g, "/"));
29
+ }
package/dist/store.js ADDED
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFlags = exports.getConfig = void 0;
4
+ exports.setGlobals = setGlobals;
5
+ let globalConfig = null;
6
+ let globalFlags = null;
7
+ function setGlobals(cfg, flags) {
8
+ globalConfig = cfg;
9
+ globalFlags = flags;
10
+ globalThis.__PRODEX__ = Object.freeze({ config: cfg, flags });
11
+ }
12
+ const getConfig = () => globalConfig || globalThis.__PRODEX__?.config;
13
+ exports.getConfig = getConfig;
14
+ const getFlags = () => globalFlags || globalThis.__PRODEX__?.flags;
15
+ exports.getFlags = getFlags;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prodex",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "Unified Project Indexer & Dependency Extractor for Laravel + React + Node stacks.",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -27,7 +27,8 @@
27
27
  "scripts": {
28
28
  "build": "tsc",
29
29
  "dev": "tsc --watch",
30
- "prepare": "npm run build"
30
+ "prepare": "npm run build",
31
+ "d:w": "nodemon --watch dist --delay 500ms --exec node --inspect-brk dist/debug.js"
31
32
  },
32
33
  "engines": {
33
34
  "node": ">=16"
@@ -36,8 +37,8 @@
36
37
  "license": "MIT",
37
38
  "devDependencies": {
38
39
  "@types/node": "^24.9.2",
39
- "typescript": "^5.9.3",
40
- "vitest": "^4.0.4"
40
+ "nodemon": "^3.1.10",
41
+ "typescript": "^5.9.3"
41
42
  },
42
43
  "dependencies": {
43
44
  "es-module-lexer": "^1.7.0",
package/dist/cli/flags.js DELETED
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CLI_USAGE = exports.FLAG_SHORT_MAP = exports.PRODEX_FLAGS = exports.FlagKey = void 0;
4
- var FlagKey;
5
- (function (FlagKey) {
6
- FlagKey["Txt"] = "txt";
7
- FlagKey["Ci"] = "ci";
8
- FlagKey["Debug"] = "debug";
9
- FlagKey["Name"] = "name";
10
- FlagKey["Limit"] = "limit";
11
- FlagKey["Inc"] = "include";
12
- FlagKey["Exc"] = "exclude";
13
- FlagKey["Help"] = "help";
14
- FlagKey["Files"] = "files";
15
- })(FlagKey || (exports.FlagKey = FlagKey = {}));
16
- exports.PRODEX_FLAGS = {
17
- [FlagKey.Files]: { short: "f", type: "list", description: "Comma-separated entry files." },
18
- [FlagKey.Txt]: { short: "t", type: "boolean", description: "Output as .txt instead of .md." },
19
- [FlagKey.Ci]: { short: "c", type: "boolean", description: "Headless/no-UI mode." },
20
- [FlagKey.Debug]: { short: "d", type: "boolean", description: "Enable debug logs." },
21
- [FlagKey.Name]: { short: "n", type: "string", description: "Custom output filename." },
22
- [FlagKey.Limit]: { short: "l", type: "number", description: "Override traversal limit." },
23
- [FlagKey.Inc]: { type: "list", short: "i", description: "Comma-separated include globs." },
24
- [FlagKey.Exc]: { type: "list", short: "x", description: "Comma-separated exclude globs." },
25
- [FlagKey.Help]: { short: "h", type: "boolean", description: "Show CLI help and exit." },
26
- };
27
- /** Reverse lookup for short aliases. */
28
- exports.FLAG_SHORT_MAP = Object.entries(exports.PRODEX_FLAGS).reduce((acc, [key, meta]) => {
29
- if (meta.short)
30
- acc[meta.short] = key;
31
- return acc;
32
- }, {});
33
- exports.CLI_USAGE = `
34
- Usage: prodex [-fcdv]
35
- [--files=<globs>|-f=<globs>]
36
- [--include=<globs>|-i=<globs>]
37
- [--exclude=<globs>|-x=<globs>]
38
- [--txt|-t] [--ci|-c] [--debug|-d] [--version|-v]
39
- [--name=<string>|-n=<string>]
40
- [--limit=<int>|-l=<int>]
41
- [--help|-h]
42
- `;
@@ -1,95 +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.loadProdexConfig = loadProdexConfig;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const default_config_1 = require("./default-config");
10
- const logger_1 = require("../lib/logger");
11
- const utils_1 = require("../lib/utils");
12
- /**
13
- * 🧩 Load and merge Prodex configuration (v3)
14
- *
15
- * 1️⃣ Reads `prodex.json` if present.
16
- * 2️⃣ Merges with `DEFAULT_PRODEX_CONFIG`.
17
- * 3️⃣ Normalizes all path-like fields.
18
- * 4️⃣ Applies CLI flag overrides.
19
- */
20
- async function loadProdexConfig(flags = {}, cwd) {
21
- const configPath = path_1.default.join(cwd, "prodex.json");
22
- let userConfig = {};
23
- // 1️⃣ Load config if present
24
- try {
25
- const content = fs_1.default.readFileSync(configPath, "utf8");
26
- userConfig = JSON.parse(content);
27
- }
28
- catch (err) {
29
- logger_1.logger.info("No prodex.json found — using defaults.");
30
- }
31
- // 2️⃣ Merge defaults → user config
32
- const { output, entry, resolve } = default_config_1.DEFAULT_PRODEX_CONFIG;
33
- const cfg = {
34
- ...default_config_1.DEFAULT_PRODEX_CONFIG,
35
- ...userConfig,
36
- output: { ...output, ...userConfig.output },
37
- entry: {
38
- ...entry,
39
- ...userConfig.entry,
40
- ui: { ...entry.ui, ...userConfig.entry?.ui },
41
- },
42
- resolve: { ...resolve, ...userConfig.resolve },
43
- root: cwd,
44
- name: flags?.name,
45
- };
46
- // 4️⃣ Apply CLI flag overrides (if any)
47
- applyFlagOverrides(cfg, flags);
48
- tidyArrayFields(cfg);
49
- return cfg;
50
- }
51
- /** Merge CLI flags into config where relevant. */
52
- /** Merge CLI flags into config where relevant. */
53
- function applyFlagOverrides(cfg, flags) {
54
- if (!flags)
55
- return;
56
- const outputOverrides = {
57
- txt: (cfg, v) => (cfg.output.format = v ? "txt" : "md"),
58
- };
59
- const resolveOverrides = {
60
- limit: (cfg, v) => (cfg.resolve.limit = v),
61
- include: (cfg, v) => (cfg.resolve.include = v),
62
- exclude: (cfg, v) => (cfg.resolve.exclude = v),
63
- };
64
- const entryOverrides = {
65
- files: (cfg, v) => (cfg.entry.files = v),
66
- };
67
- const envOverrides = {
68
- debug: (_, v) => (process.env.PRODEX_DEBUG = v ? "1" : "0"),
69
- verbose: (_, v) => (process.env.PRODEX_VERBOSE = v ? "1" : "0"),
70
- };
71
- const overrideMap = {
72
- ...outputOverrides,
73
- ...resolveOverrides,
74
- ...entryOverrides,
75
- ...envOverrides,
76
- };
77
- // Apply all flag overrides dynamically
78
- for (const [flag, value] of Object.entries(flags)) {
79
- if (value == undefined)
80
- continue;
81
- const apply = overrideMap[flag];
82
- if (apply)
83
- apply(cfg, value);
84
- }
85
- // Conditional override rule:
86
- // If files exist and include was null/undefined → clear include array
87
- const hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;
88
- if (hasFiles && !flags.include) {
89
- cfg.resolve.include = [];
90
- }
91
- }
92
- function tidyArrayFields(cfg) {
93
- cfg.entry.files = (0, utils_1.normalizePatterns)(cfg.entry.files);
94
- ["include", "exclude"].forEach((k) => (cfg.resolve[k] = cfg.resolve[k]));
95
- }
@@ -1,41 +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.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,52 +0,0 @@
1
- "use strict";
2
- // @ts-nocheck
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.loadProjectAliases = loadProjectAliases;
8
- const fs_1 = __importDefault(require("fs"));
9
- const path_1 = __importDefault(require("path"));
10
- let cacheByRoot = new Map();
11
- function loadProjectAliases(root) {
12
- if (cacheByRoot.has(root))
13
- return cacheByRoot.get(root);
14
- const aliases = {};
15
- const tsPath = path_1.default.join(root, "tsconfig.json");
16
- const viteJs = path_1.default.join(root, "vite.config");
17
- const viteTs = path_1.default.join(root, "vite.config.ts");
18
- if (fs_1.default.existsSync(tsPath)) {
19
- try {
20
- const ts = JSON.parse(fs_1.default.readFileSync(tsPath, "utf8"));
21
- const paths = ts.compilerOptions?.paths || {};
22
- for (const [key, value] of Object.entries(paths)) {
23
- const cleanedKey = key.replace(/\/\*$/, "");
24
- const first = Array.isArray(value) ? value[0] : value;
25
- if (!first)
26
- continue;
27
- const cleanedVal = first.replace(/\/\*$/, "");
28
- aliases[cleanedKey] = path_1.default.resolve(root, cleanedVal);
29
- }
30
- }
31
- catch { }
32
- }
33
- for (const vitePath of [viteJs, viteTs]) {
34
- if (!fs_1.default.existsSync(vitePath))
35
- continue;
36
- try {
37
- const content = fs_1.default.readFileSync(vitePath, "utf8");
38
- const blocks = [...content.matchAll(/alias\s*:\s*\{([^}]+)\}/g)];
39
- for (const m of blocks) {
40
- const inner = m[1];
41
- const pairs = [...inner.matchAll(/['"](.+?)['"]\s*:\s*['"](.+?)['"]/g)];
42
- for (const [, key, val] of pairs) {
43
- const abs = path_1.default.isAbsolute(val) ? val : path_1.default.resolve(root, val);
44
- aliases[key] = abs;
45
- }
46
- }
47
- }
48
- catch { }
49
- }
50
- cacheByRoot.set(root, aliases);
51
- return aliases;
52
- }