prodex 1.0.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +174 -86
  2. package/bin/prodex.js +1 -17
  3. package/dist/cli/cli-input.js +86 -0
  4. package/dist/cli/flags.js +42 -0
  5. package/dist/cli/init.js +21 -0
  6. package/dist/cli/picker.js +82 -0
  7. package/dist/cli/summary.js +14 -0
  8. package/dist/constants/config-loader.js +90 -0
  9. package/dist/constants/config.js +17 -0
  10. package/dist/constants/default-config.js +48 -0
  11. package/dist/constants/render-constants.js +23 -0
  12. package/dist/core/combine.js +74 -0
  13. package/dist/core/dependency.js +51 -0
  14. package/dist/core/file-utils.js +44 -0
  15. package/dist/core/helpers.js +81 -0
  16. package/dist/core/parsers/extract-imports.js +51 -0
  17. package/dist/core/renderers.js +42 -0
  18. package/dist/index.js +29 -0
  19. package/dist/lib/logger.js +14 -0
  20. package/dist/lib/polyfills.js +12 -0
  21. package/dist/lib/utils.js +15 -0
  22. package/dist/resolvers/js/alias-loader.js +52 -0
  23. package/dist/resolvers/js/js-resolver.js +153 -0
  24. package/dist/resolvers/php/bindings.js +32 -0
  25. package/dist/resolvers/php/patterns.js +17 -0
  26. package/dist/resolvers/php/php-resolver.js +88 -0
  27. package/dist/resolvers/php/psr4.js +26 -0
  28. package/dist/resolvers/shared/excludes.js +11 -0
  29. package/dist/resolvers/shared/file-cache.js +29 -0
  30. package/dist/resolvers/shared/stats.js +17 -0
  31. package/dist/types/cli.types.js +12 -0
  32. package/dist/types/config.types.js +2 -0
  33. package/dist/types/core.types.js +2 -0
  34. package/dist/types/index.js +21 -0
  35. package/dist/types/resolver.types.js +2 -0
  36. package/dist/types/utils.types.js +2 -0
  37. package/package.json +17 -11
  38. package/dist/LICENSE +0 -21
  39. package/dist/README.md +0 -140
  40. package/dist/bin/prodex.js +0 -18
  41. package/dist/package.json +0 -43
  42. package/dist/src/cli/init.js +0 -50
  43. package/dist/src/cli/picker.js +0 -64
  44. package/dist/src/cli/summary.js +0 -9
  45. package/dist/src/constants/config-loader.js +0 -64
  46. package/dist/src/constants/config.js +0 -90
  47. package/dist/src/core/alias-loader.js +0 -8
  48. package/dist/src/core/combine.js +0 -141
  49. package/dist/src/core/file-utils.js +0 -13
  50. package/dist/src/core/helpers.js +0 -127
  51. package/dist/src/index.js +0 -11
  52. package/dist/src/resolvers/js-resolver.js +0 -135
  53. package/dist/src/resolvers/php-bindings.js +0 -31
  54. package/dist/src/resolvers/php-resolver.js +0 -115
@@ -1,135 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { IMPORT_EXCLUDES, ROOT } from "../constants/config.js";
4
-
5
- const debug = process.env.PRODEX_DEBUG === "1";
6
- const log = (...args) => { if (debug) console.log("ðŸŠķ [resolver]", ...args); };
7
-
8
- // --- Loaders --------------------------------------------------
9
-
10
- function loadViteAliases() {
11
- const files = [
12
- "vite.config.ts",
13
- "vite.config.js",
14
- "vite.config.mts",
15
- "vite.config.mjs",
16
- "vite.config.cjs",
17
- ];
18
- const map = {};
19
- for (const f of files) {
20
- const p = path.join(ROOT, f);
21
- if (!fs.existsSync(p)) continue;
22
- const s = fs.readFileSync(p, "utf8");
23
- const obj = /resolve\s*:\s*{[\s\S]*?alias\s*:\s*{([\s\S]*?)}/m.exec(s);
24
- if (!obj) continue;
25
- const re = /['"]([^'"]+)['"]\s*:\s*['"]([^'"]+)['"]/g;
26
- let m;
27
- while ((m = re.exec(obj[1]))) {
28
- const key = m[1];
29
- const raw = m[2].replace(/^\/+/, "");
30
- const abs = path.resolve(ROOT, raw);
31
- map[key] = abs;
32
- }
33
- }
34
- return map;
35
- }
36
-
37
- function loadTsconfigAliases() {
38
- const p = path.join(ROOT, "tsconfig.json");
39
- if (!fs.existsSync(p)) return {};
40
- let content = fs.readFileSync(p, "utf8")
41
- .replace(/("(?:\\.|[^"\\])*")|\/\/.*$|\/\*[\s\S]*?\*\//gm, (_, q) => q || "")
42
- .replace(/,\s*([}\]])/g, "$1");
43
- let j;
44
- try {
45
- j = JSON.parse(content);
46
- } catch {
47
- return {};
48
- }
49
- const paths = j.compilerOptions?.paths || {};
50
- const base = j.compilerOptions?.baseUrl || ".";
51
- const map = {};
52
- for (const k in paths) {
53
- const arr = paths[k];
54
- if (!Array.isArray(arr) || !arr.length) continue;
55
- const from = k.replace(/\*$/, "");
56
- const to = arr[0].replace(/\*$/, "");
57
- map[from] = path.resolve(ROOT, base, to);
58
- }
59
- return map;
60
- }
61
-
62
- function loadJsAliases() {
63
- return { ...loadTsconfigAliases(), ...loadViteAliases() };
64
- }
65
-
66
- // --- Resolver Core --------------------------------------------
67
-
68
- function tryResolveImport(basePath) {
69
- const ext = path.extname(basePath);
70
- const tries = [];
71
- if (ext) tries.push(basePath);
72
- else {
73
- for (const x of [".ts", ".tsx", ".d.ts", ".js", ".jsx", ".mjs"])
74
- tries.push(basePath + x, path.join(basePath, "index" + x));
75
- }
76
- for (const t of tries)
77
- if (fs.existsSync(t) && fs.statSync(t).isFile()) return path.resolve(t);
78
- return null;
79
- }
80
-
81
- function isImportExcluded(p) {
82
- return IMPORT_EXCLUDES.some(ex => p.includes(ex));
83
- }
84
-
85
- export async function resolveJsImports(filePath, visited = new Set(), depth = 0, maxDepth = 10) {
86
- if (visited.has(filePath)) return { files: [], visited };
87
- visited.add(filePath);
88
- if (isImportExcluded(filePath) || !fs.existsSync(filePath))
89
- return { files: [], visited };
90
-
91
- const code = fs.readFileSync(filePath, "utf8");
92
- const ext = path.extname(filePath).toLowerCase();
93
- if (![".ts", ".tsx", ".d.ts", ".js", ".jsx", ".mjs"].includes(ext))
94
- return { files: [], visited };
95
-
96
- const aliases = loadJsAliases();
97
- const patterns = [
98
- /import\s+[^'"]*['"]([^'"]+)['"]/g,
99
- /import\(\s*['"]([^'"]+)['"]\s*\)/g,
100
- /require\(\s*['"]([^'"]+)['"]\s*\)/g,
101
- /export\s+\*\s+from\s+['"]([^'"]+)['"]/g,
102
- ];
103
-
104
- const matches = new Set();
105
- for (const r of patterns) {
106
- let m;
107
- while ((m = r.exec(code))) matches.add(m[1]);
108
- }
109
-
110
- const resolved = [];
111
- for (const imp of matches) {
112
- if (!imp.startsWith(".") && !imp.startsWith("/") && !imp.startsWith("@")) continue;
113
- if (isImportExcluded(imp)) continue;
114
-
115
- let importPath;
116
- if (imp.startsWith("@")) {
117
- const aliasKey = Object.keys(aliases).find(a => imp.startsWith(a));
118
- if (aliasKey) {
119
- const relPart = imp.slice(aliasKey.length).replace(/^\/+/, "");
120
- importPath = path.join(aliases[aliasKey], relPart);
121
- } else continue;
122
- } else importPath = path.resolve(path.dirname(filePath), imp);
123
-
124
- const resolvedPath = tryResolveImport(importPath);
125
- if (!resolvedPath || isImportExcluded(resolvedPath)) continue;
126
- resolved.push(resolvedPath);
127
-
128
- if (depth < maxDepth) {
129
- const sub = await resolveJsImports(resolvedPath, visited, depth + 1, maxDepth);
130
- resolved.push(...sub.files);
131
- }
132
- }
133
-
134
- return { files: [...new Set(resolved)], visited };
135
- }
@@ -1,31 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { ROOT } from "../constants/config.js";
4
-
5
- export function loadLaravelBindings() {
6
- const providersDir = path.join(ROOT, "app", "Providers");
7
- const bindings = {};
8
-
9
- if (!fs.existsSync(providersDir)) return bindings;
10
-
11
- const files = fs
12
- .readdirSync(providersDir)
13
- .filter(f => f.endsWith(".php"))
14
- .map(f => path.join(providersDir, f));
15
-
16
- // Match: $this->app->bind(Interface::class, Implementation::class)
17
- const re =
18
- /$this->app->(?:bind|singleton)\s*\(\s*([A-Za-z0-9_:\\\\]+)::class\s*,\s*([A-Za-z0-9_:\\\\]+)::class/g;
19
-
20
- for (const file of files) {
21
- const code = fs.readFileSync(file, "utf8");
22
- let m;
23
- while ((m = re.exec(code))) {
24
- const iface = m[1].replace(/\\\\/g, "\\");
25
- const impl = m[2].replace(/\\\\/g, "\\");
26
- bindings[iface] = impl;
27
- }
28
- }
29
-
30
- return bindings;
31
- }
@@ -1,115 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { ROOT } from "../constants/config.js";
4
- import { loadLaravelBindings } from "./php-bindings.js";
5
-
6
- const debug = process.env.PRODEX_DEBUG === "1";
7
- const log = (...args) => { if (debug) console.log("ðŸŠķ [php-resolver]", ...args); };
8
-
9
- // --- Load Composer PSR-4 Namespaces ----------------------------------------
10
-
11
- function loadComposerNamespaces() {
12
- const composerPath = path.join(ROOT, "composer.json");
13
- if (!fs.existsSync(composerPath)) return {};
14
- try {
15
- const data = JSON.parse(fs.readFileSync(composerPath, "utf8"));
16
- const psr4 = data.autoload?.["psr-4"] || {};
17
- const map = {};
18
- for (const ns in psr4)
19
- map[ns.replace(/\\+$/, "")] = path.resolve(ROOT, psr4[ns]);
20
- return map;
21
- } catch {
22
- return {};
23
- }
24
- }
25
-
26
- // --- File resolver ---------------------------------------------------------
27
-
28
- function tryResolvePhpImport(basePath) {
29
- if (!basePath || typeof basePath !== "string") return null;
30
- const tries = [basePath, basePath + ".php", path.join(basePath, "index.php")];
31
- for (const t of tries)
32
- if (fs.existsSync(t) && fs.statSync(t).isFile()) return path.resolve(t);
33
- return null;
34
- }
35
-
36
- // --- Main resolver ---------------------------------------------------------
37
-
38
- export async function resolvePhpImports(
39
- filePath,
40
- visited = new Set(),
41
- depth = 0,
42
- maxDepth = 10
43
- ) {
44
- if (visited.has(filePath)) return { files: [], visited };
45
- visited.add(filePath);
46
- if (!fs.existsSync(filePath)) return { files: [], visited };
47
-
48
- const code = fs.readFileSync(filePath, "utf8");
49
-
50
- // find include/require + grouped and single use statements
51
- const patterns = [
52
- /\b(?:require|include|require_once|include_once)\s*\(?['"]([^'"]+)['"]\)?/g,
53
- /\buse\s+([A-Z][\w\\]+(?:\s*{[^}]+})?)/g,
54
- ];
55
-
56
- const rawMatches = new Set();
57
- for (const r of patterns) {
58
- let m;
59
- while ((m = r.exec(code))) rawMatches.add(m[1]);
60
- }
61
-
62
- // Expand grouped uses
63
- const matches = new Set();
64
- for (const imp of rawMatches) {
65
- const groupMatch = imp.match(/^(.+?)\s*{([^}]+)}/);
66
- if (groupMatch) {
67
- const base = groupMatch[1].trim().replace(/\\+$/, "");
68
- const parts = groupMatch[2]
69
- .split(",")
70
- .map(x => x.trim())
71
- .filter(Boolean);
72
- for (const p of parts) matches.add(`${base}\\${p}`);
73
- } else {
74
- matches.add(imp.trim());
75
- }
76
- }
77
-
78
- const namespaces = loadComposerNamespaces();
79
- const bindings = loadLaravelBindings();
80
- const resolved = [];
81
-
82
- for (const imp0 of matches) {
83
- let imp = imp0;
84
-
85
- // Interface → Implementation mapping via Service Providers
86
- if (bindings[imp]) {
87
- imp = bindings[imp];
88
- log("🔗 Interface resolved via AppServiceProvider:", imp0, "→", imp);
89
- }
90
-
91
- let importPath;
92
-
93
- // PSR-4 namespace resolution
94
- if (imp.includes("\\")) {
95
- const nsKey = Object.keys(namespaces).find(k => imp.startsWith(k));
96
- if (!nsKey) continue; // skip vendor namespaces
97
- const relPart = imp.slice(nsKey.length).replace(/\\/g, "/");
98
- importPath = path.join(namespaces[nsKey], `${relPart}.php`);
99
- } else {
100
- importPath = path.resolve(path.dirname(filePath), imp);
101
- }
102
-
103
- if (!importPath || typeof importPath !== "string") continue;
104
- const resolvedPath = tryResolvePhpImport(importPath);
105
- if (!resolvedPath) continue;
106
- resolved.push(resolvedPath);
107
-
108
- if (depth < maxDepth) {
109
- const sub = await resolvePhpImports(resolvedPath, visited, depth + 1, maxDepth);
110
- resolved.push(...sub.files);
111
- }
112
- }
113
-
114
- return { files: [...new Set(resolved)], visited };
115
- }