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.
- package/README.md +234 -234
- package/dist/cli/cli-input.js +20 -26
- package/dist/cli/init.js +4 -5
- package/dist/cli/picker.js +8 -7
- package/dist/cli/summary.js +15 -9
- package/dist/constants/cache-keys.js +11 -0
- package/dist/constants/config.js +6 -5
- package/dist/constants/flags.js +73 -0
- package/dist/constants/index.js +20 -0
- package/dist/constants/render-constants.js +0 -4
- package/dist/core/combine.js +31 -13
- package/dist/core/dependency.js +39 -19
- package/dist/core/helpers.js +42 -38
- package/dist/core/managers/cache.js +53 -0
- package/dist/core/managers/config.js +103 -0
- package/dist/core/renderers.js +9 -8
- package/dist/debug.js +13 -0
- package/dist/index.js +42 -13
- package/dist/lib/logger.js +37 -9
- package/dist/lib/polyfills.js +0 -10
- package/dist/lib/utils.js +0 -13
- package/dist/{core/parsers → resolvers/js}/extract-imports.js +1 -7
- package/dist/resolvers/js/js-resolver.js +92 -116
- package/dist/resolvers/js/resolve-alias.js +57 -0
- package/dist/resolvers/php/bindings.js +20 -9
- package/dist/resolvers/php/extract-imports.js +49 -0
- package/dist/resolvers/php/php-resolver.js +98 -59
- package/dist/resolvers/php/psr4.js +18 -5
- package/dist/shared/collections.js +33 -0
- package/dist/shared/index.js +19 -0
- package/dist/shared/io.js +51 -0
- package/dist/shared/patterns.js +29 -0
- package/dist/store.js +15 -0
- package/package.json +5 -4
- package/dist/cli/flags.js +0 -42
- package/dist/constants/config-loader.js +0 -95
- package/dist/core/file-utils.js +0 -41
- package/dist/resolvers/js/alias-loader.js +0 -52
- package/dist/resolvers/php/patterns.js +0 -17
- package/dist/resolvers/shared/excludes.js +0 -11
- package/dist/resolvers/shared/file-cache.js +0 -29
- package/dist/resolvers/shared/stats.js +0 -17
package/dist/cli/summary.js
CHANGED
|
@@ -4,23 +4,29 @@ exports.endSummary = endSummary;
|
|
|
4
4
|
exports.introSummary = introSummary;
|
|
5
5
|
exports.entrySummary = entrySummary;
|
|
6
6
|
const logger_1 = require("../lib/logger");
|
|
7
|
-
const
|
|
7
|
+
const io_1 = require("../shared/io");
|
|
8
|
+
const store_1 = require("../store");
|
|
9
|
+
let CONFIG;
|
|
10
|
+
let FLAGS;
|
|
8
11
|
function endSummary(out, result) {
|
|
9
12
|
logger_1.logger.debug(`🧩 Summary:
|
|
10
|
-
• Unique imports expected: ${result
|
|
11
|
-
• Unique imports resolved: ${result
|
|
13
|
+
• Unique imports expected: ${result?.stats?.expected.size}
|
|
14
|
+
• Unique imports resolved: ${result?.stats?.resolved.size}
|
|
12
15
|
`);
|
|
13
16
|
logger_1.logger.log(`✅ ${out.norm()}`);
|
|
14
17
|
}
|
|
15
|
-
function introSummary(
|
|
16
|
-
|
|
18
|
+
function introSummary() {
|
|
19
|
+
CONFIG = (0, store_1.getConfig)();
|
|
20
|
+
FLAGS = (0, store_1.getFlags)();
|
|
21
|
+
logger_1.logger.log(`------- PRODEx RUN @ ${new Date().toLocaleTimeString()} — Codebase decoded -------\n`);
|
|
17
22
|
// Log parse results for testing
|
|
18
|
-
logger_1.logger.debug("🧩 Parsed CLI input:", _2j({
|
|
19
|
-
logger_1.logger.debug("Final merged config:", _2j(
|
|
23
|
+
logger_1.logger.debug("🧩 Parsed CLI input:", _2j({ FLAGS }));
|
|
24
|
+
logger_1.logger.debug("Final merged config:", _2j(CONFIG));
|
|
20
25
|
}
|
|
21
26
|
function entrySummary(entries) {
|
|
22
27
|
let result = "📋 You selected:";
|
|
23
28
|
for (const e of entries)
|
|
24
|
-
result += "\n -" + (0,
|
|
25
|
-
|
|
29
|
+
result += "\n -" + (0, io_1.rel)(e);
|
|
30
|
+
if (entries?.length)
|
|
31
|
+
logger_1.logger.log(result);
|
|
26
32
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CACHE_KEYS = void 0;
|
|
4
|
+
exports.CACHE_KEYS = {
|
|
5
|
+
ALIASES: "aliases",
|
|
6
|
+
JS_IMPORTS: "js:imports",
|
|
7
|
+
JS_STATS: "js:stats",
|
|
8
|
+
PHP_PSR4: "php:psr4",
|
|
9
|
+
PHP_BINDINGS: "php:bindings",
|
|
10
|
+
PHP_FILECACHE: "php:fileCache",
|
|
11
|
+
};
|
package/dist/constants/config.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.VALID_GLOB_CHARS = exports.SUFFIX = exports.
|
|
4
|
-
exports.CODE_EXTS = [".js", ".mjs", ".ts", ".tsx", ".d.ts", ".php"];
|
|
3
|
+
exports.VALID_GLOB_CHARS = exports.SUFFIX = exports.GLOBAL_IGNORE = exports.RESOLVERS = exports.DTS_EXT = exports.REAL_EXTS = exports.BASE_EXTS = exports.CODE_EXTS = void 0;
|
|
5
4
|
const js_resolver_1 = require("../resolvers/js/js-resolver");
|
|
6
5
|
const php_resolver_1 = require("../resolvers/php/php-resolver");
|
|
6
|
+
exports.CODE_EXTS = [".js", ".mjs", ".ts", ".tsx", ".d.ts", ".php"];
|
|
7
|
+
exports.BASE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs"];
|
|
8
|
+
exports.REAL_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".d.ts", ".json"]);
|
|
9
|
+
exports.DTS_EXT = ".d.ts";
|
|
7
10
|
exports.RESOLVERS = {
|
|
8
11
|
".php": php_resolver_1.resolvePhpImports,
|
|
9
12
|
".ts": js_resolver_1.resolveJsImports,
|
|
@@ -12,8 +15,6 @@ exports.RESOLVERS = {
|
|
|
12
15
|
".js": js_resolver_1.resolveJsImports,
|
|
13
16
|
};
|
|
14
17
|
exports.GLOBAL_IGNORE = ["**/node_modules/**", "**/vendor/**", "**/dist/**"];
|
|
15
|
-
exports.BASE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".types"];
|
|
16
|
-
exports.DTS_EXT = ".d.ts";
|
|
17
18
|
exports.SUFFIX = "trace";
|
|
18
19
|
/**
|
|
19
20
|
* Normalize and sanitize pattern fields.
|
|
@@ -23,4 +24,4 @@ exports.SUFFIX = "trace";
|
|
|
23
24
|
* - Trims and removes empty elements.
|
|
24
25
|
* - Filters out invalid or unusable characters for Fast-Glob.
|
|
25
26
|
*/
|
|
26
|
-
exports.VALID_GLOB_CHARS = /^[\w\-@./*?|!{}\[\]^$()+]+$/; // allows Fast-Glob-safe
|
|
27
|
+
exports.VALID_GLOB_CHARS = /^[\w\-@./*?|!{}\[\]^$()+]+$/; // allows Fast-Glob-safe symbolsexport const REAL_EXTS = new Set<string>([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".d.ts", ".json"]);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CLI_USAGE = exports.FLAG_SHORT_MAP = exports.FLAG_MAP = void 0;
|
|
4
|
+
exports.FLAG_MAP = {
|
|
5
|
+
txt: {
|
|
6
|
+
short: "t",
|
|
7
|
+
type: "boolean",
|
|
8
|
+
description: "Output as .txt instead of .md.",
|
|
9
|
+
apply: (cfg, v) => (cfg.output.format = v ? "txt" : "md"),
|
|
10
|
+
},
|
|
11
|
+
name: {
|
|
12
|
+
short: "n",
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Custom output filename (without extension).",
|
|
15
|
+
apply: (cfg, v) => (cfg.name = v),
|
|
16
|
+
},
|
|
17
|
+
limit: {
|
|
18
|
+
short: "l",
|
|
19
|
+
type: "number",
|
|
20
|
+
description: "Override traversal limit.",
|
|
21
|
+
apply: (cfg, v) => (cfg.resolve.limit = v),
|
|
22
|
+
},
|
|
23
|
+
include: {
|
|
24
|
+
short: "i",
|
|
25
|
+
type: "list",
|
|
26
|
+
description: "Comma-separated include globs.",
|
|
27
|
+
apply: (cfg, v) => (cfg.resolve.include = v),
|
|
28
|
+
},
|
|
29
|
+
exclude: {
|
|
30
|
+
short: "x",
|
|
31
|
+
type: "list",
|
|
32
|
+
description: "Comma-separated exclude globs.",
|
|
33
|
+
apply: (cfg, v) => (cfg.resolve.exclude = v),
|
|
34
|
+
},
|
|
35
|
+
files: {
|
|
36
|
+
short: "f",
|
|
37
|
+
type: "list",
|
|
38
|
+
description: "Entry files (comma-separated).",
|
|
39
|
+
apply: (cfg, v) => (cfg.entry.files = v),
|
|
40
|
+
},
|
|
41
|
+
ci: {
|
|
42
|
+
short: "c",
|
|
43
|
+
type: "boolean",
|
|
44
|
+
description: "Headless (non-interactive) mode.",
|
|
45
|
+
apply: () => { },
|
|
46
|
+
},
|
|
47
|
+
debug: {
|
|
48
|
+
short: "d",
|
|
49
|
+
type: "boolean",
|
|
50
|
+
description: "Enable debug logs.",
|
|
51
|
+
apply: () => { },
|
|
52
|
+
},
|
|
53
|
+
help: {
|
|
54
|
+
short: "h",
|
|
55
|
+
type: "boolean",
|
|
56
|
+
description: "Show CLI help and exit.",
|
|
57
|
+
apply: () => { },
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
// Reverse lookup for short aliases
|
|
61
|
+
exports.FLAG_SHORT_MAP = Object.entries(exports.FLAG_MAP).reduce((acc, [k, v]) => {
|
|
62
|
+
//@ts-ignore
|
|
63
|
+
if (v.short)
|
|
64
|
+
acc[v.short] = k;
|
|
65
|
+
return acc;
|
|
66
|
+
}, {});
|
|
67
|
+
exports.CLI_USAGE = `
|
|
68
|
+
Usage: prodex [options]
|
|
69
|
+
|
|
70
|
+
${Object.entries(exports.FLAG_MAP)
|
|
71
|
+
.map(([k, v]) => ` --${k}${v.short ? ` | -${v.short}` : ""}\t${v.description}`)
|
|
72
|
+
.join("\n")}
|
|
73
|
+
`;
|
|
@@ -0,0 +1,20 @@
|
|
|
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("./cache-keys"), exports);
|
|
18
|
+
__exportStar(require("./default-config"), exports);
|
|
19
|
+
__exportStar(require("./render-constants"), exports);
|
|
20
|
+
__exportStar(require("./config"), exports);
|
|
@@ -4,10 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.MD_FOOTER = exports.TEXT_HEADERS = exports.LANG_MAP = void 0;
|
|
7
|
-
// ================================================================
|
|
8
|
-
// 🧩 Prodex — Render Constants
|
|
9
|
-
// Defines shared constants for renderer outDir formats.
|
|
10
|
-
// ================================================================
|
|
11
7
|
const package_json_1 = __importDefault(require("../../package.json"));
|
|
12
8
|
exports.LANG_MAP = {
|
|
13
9
|
"": "js",
|
package/dist/core/combine.js
CHANGED
|
@@ -3,36 +3,54 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.runCombine = runCombine;
|
|
4
4
|
const picker_1 = require("../cli/picker");
|
|
5
5
|
const summary_1 = require("../cli/summary");
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const cache_keys_1 = require("../constants/cache-keys");
|
|
7
|
+
const cache_1 = require("./managers/cache");
|
|
8
|
+
const config_1 = require("./managers/config");
|
|
8
9
|
const logger_1 = require("../lib/logger");
|
|
10
|
+
const dependency_1 = require("./dependency");
|
|
11
|
+
const helpers_1 = require("./helpers");
|
|
12
|
+
const helpers_2 = require("./helpers");
|
|
9
13
|
const output_1 = require("./output");
|
|
10
14
|
async function runCombine({ cfg, opts }) {
|
|
15
|
+
(0, summary_1.introSummary)();
|
|
11
16
|
const { showUi, cliName } = opts;
|
|
12
17
|
let entries = (await resolveEntries(showUi, cfg)) ?? [];
|
|
13
|
-
if (!entries.length) {
|
|
14
|
-
logger_1.logger.error("No entries selected.");
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
18
|
(0, summary_1.entrySummary)(entries);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
let result;
|
|
20
|
+
if (!entries.length)
|
|
21
|
+
logger_1.logger.info("No entries found");
|
|
22
|
+
if (entries.length)
|
|
23
|
+
result = await (0, dependency_1.followChain)(entries, cfg);
|
|
24
|
+
const withinclude = await (0, dependency_1.applyIncludes)(cfg, result?.files ?? []);
|
|
25
|
+
if (!withinclude.length)
|
|
26
|
+
return logger_1.logger.info("No Includes found. Exiting process...");
|
|
27
|
+
const autoName = (0, helpers_2.smartNaming)(entries);
|
|
21
28
|
const outputPath = await (0, output_1.produceOutput)({ name: cliName ?? autoName, files: withinclude, cfg, showUi });
|
|
29
|
+
persistAliases();
|
|
22
30
|
(0, summary_1.endSummary)(outputPath, result);
|
|
23
31
|
}
|
|
24
32
|
async function resolveEntries(showUi, cfg) {
|
|
25
|
-
const { root, entry } = cfg;
|
|
26
|
-
const { files } = entry;
|
|
33
|
+
const { root, entry: { files }, resolve: { include }, } = cfg;
|
|
27
34
|
if (!showUi) {
|
|
28
35
|
logger_1.logger.info("CI Mode");
|
|
29
36
|
if (!files?.length) {
|
|
30
37
|
logger_1.logger.warn("No entry files defined and UI mode is disabled.");
|
|
31
|
-
|
|
38
|
+
if (!include.length)
|
|
39
|
+
process.exit(1);
|
|
40
|
+
logger_1.logger.info("Applying Includes");
|
|
32
41
|
}
|
|
33
|
-
return (await (0,
|
|
42
|
+
return (await (0, helpers_1.globScan)(files, { cwd: root })).files;
|
|
34
43
|
}
|
|
35
44
|
else {
|
|
36
45
|
return await (0, picker_1.pickEntries)(cfg);
|
|
37
46
|
}
|
|
38
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* 🧩 Persist discovered aliases (if any)
|
|
50
|
+
*/
|
|
51
|
+
function persistAliases() {
|
|
52
|
+
const aliases = cache_1.CacheManager.dump(cache_keys_1.CACHE_KEYS.ALIASES);
|
|
53
|
+
if (Object.keys(aliases).length) {
|
|
54
|
+
config_1.ConfigManager.persist({ resolve: { aliases } });
|
|
55
|
+
}
|
|
56
|
+
}
|
package/dist/core/dependency.js
CHANGED
|
@@ -4,20 +4,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.followChain = followChain;
|
|
7
|
-
exports.
|
|
7
|
+
exports.applyIncludes = applyIncludes;
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const config_1 = require("../constants/config");
|
|
10
|
-
const
|
|
10
|
+
const helpers_1 = require("./helpers");
|
|
11
11
|
const logger_1 = require("../lib/logger");
|
|
12
|
-
const
|
|
12
|
+
const collections_1 = require("../shared/collections");
|
|
13
|
+
/**
|
|
14
|
+
* 🧩 followChain()
|
|
15
|
+
* Traverses all dependencies starting from the given entry files.
|
|
16
|
+
* Uses language-specific resolvers (JS / PHP) under the hood.
|
|
17
|
+
*/
|
|
13
18
|
async function followChain(entryFiles, cfg) {
|
|
14
19
|
const limit = cfg.resolve.limit;
|
|
20
|
+
const resolverDepth = cfg.resolve.depth;
|
|
15
21
|
logger_1.logger.debug("🧩 Following dependency chain...");
|
|
16
22
|
const visited = new Set();
|
|
17
23
|
const all = [];
|
|
18
24
|
const expected = new Set();
|
|
19
25
|
const resolved = new Set();
|
|
20
|
-
const resolverDepth = cfg.resolve.depth;
|
|
21
26
|
for (const f of entryFiles) {
|
|
22
27
|
if (visited.has(f))
|
|
23
28
|
continue;
|
|
@@ -26,30 +31,45 @@ async function followChain(entryFiles, cfg) {
|
|
|
26
31
|
if (!config_1.CODE_EXTS.includes(ext))
|
|
27
32
|
continue;
|
|
28
33
|
const resolver = config_1.RESOLVERS[ext];
|
|
29
|
-
if (resolver)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
if (!resolver)
|
|
35
|
+
continue;
|
|
36
|
+
const params = {
|
|
37
|
+
filePath: f,
|
|
38
|
+
visited,
|
|
39
|
+
depth: 0,
|
|
40
|
+
maxDepth: resolverDepth,
|
|
41
|
+
};
|
|
42
|
+
let result = null;
|
|
43
|
+
try {
|
|
44
|
+
result = await resolver(params);
|
|
35
45
|
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
logger_1.logger.warn(`⚠️ Resolver failed for ${f}:`, err.message || err);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (!result)
|
|
51
|
+
continue;
|
|
52
|
+
const { files, stats } = result;
|
|
53
|
+
all.push(...files);
|
|
54
|
+
stats.expected.forEach((x) => expected.add(x));
|
|
55
|
+
stats.resolved.forEach((x) => resolved.add(x));
|
|
36
56
|
if (limit && all.length >= limit) {
|
|
37
57
|
logger_1.logger.warn("⚠️ Limit reached:", limit);
|
|
38
58
|
break;
|
|
39
59
|
}
|
|
40
60
|
}
|
|
41
61
|
return {
|
|
42
|
-
files: (0,
|
|
62
|
+
files: (0, collections_1.unique)(all),
|
|
43
63
|
stats: { expected, resolved },
|
|
44
64
|
};
|
|
45
65
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
66
|
+
/**
|
|
67
|
+
* 🧩 applyIncludes()
|
|
68
|
+
* Scans and appends additional files defined in config.resolve.include.
|
|
69
|
+
*/
|
|
70
|
+
async function applyIncludes(cfg, files) {
|
|
71
|
+
const { resolve, root } = cfg;
|
|
72
|
+
const scan = await (0, helpers_1.globScan)(resolve.include, { cwd: root });
|
|
51
73
|
logger_1.logger.debug("APPLY_include", _2j(scan));
|
|
52
|
-
|
|
53
|
-
;
|
|
54
|
-
return combined;
|
|
74
|
+
return (0, collections_1.unique)([...files, ...scan.files]);
|
|
55
75
|
}
|
package/dist/core/helpers.js
CHANGED
|
@@ -3,47 +3,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.rel = rel;
|
|
7
|
-
exports.read = read;
|
|
8
|
-
exports.isExcluded = isExcluded;
|
|
9
6
|
exports.walk = walk;
|
|
10
7
|
exports.orderByPriority = orderByPriority;
|
|
8
|
+
exports.smartNaming = smartNaming;
|
|
9
|
+
exports.globScan = globScan;
|
|
11
10
|
const fs_1 = __importDefault(require("fs"));
|
|
12
|
-
const path_1 = __importDefault(require("path"));
|
|
13
11
|
const micromatch_1 = __importDefault(require("micromatch"));
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Safe text read.
|
|
22
|
-
*/
|
|
23
|
-
function read(p) {
|
|
24
|
-
try {
|
|
25
|
-
return fs_1.default.readFileSync(p, "utf8");
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
return "";
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Check if a path/file matches any of the provided glob patterns.
|
|
33
|
-
*/
|
|
34
|
-
function isExcluded(p, patterns, root = process.cwd()) {
|
|
35
|
-
if (!patterns?.length)
|
|
36
|
-
return false;
|
|
37
|
-
const relPath = rel(p, root);
|
|
38
|
-
return micromatch_1.default.isMatch(relPath, patterns);
|
|
39
|
-
}
|
|
12
|
+
const shared_1 = require("../shared");
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
15
|
+
const constants_1 = require("../constants");
|
|
16
|
+
const logger_1 = require("../lib/logger");
|
|
40
17
|
/**
|
|
41
18
|
* Recursive walker that respects glob exclude.
|
|
42
19
|
* Returns all files under the given directory tree.
|
|
43
20
|
*/
|
|
44
21
|
function* walk(dir, cfg, depth = 0) {
|
|
45
|
-
const {
|
|
46
|
-
const root = process.cwd();
|
|
22
|
+
const { root, entry: { ui: { scanDepth }, }, resolve: { exclude }, } = cfg;
|
|
47
23
|
if (depth > scanDepth)
|
|
48
24
|
return;
|
|
49
25
|
const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
@@ -51,15 +27,15 @@ function* walk(dir, cfg, depth = 0) {
|
|
|
51
27
|
const full = path_1.default.join(dir, e.name);
|
|
52
28
|
if (e.isDirectory()) {
|
|
53
29
|
// Skip excluded directories entirely
|
|
54
|
-
const relPath = rel(full, root);
|
|
55
|
-
if (isExcluded(relPath,
|
|
30
|
+
const relPath = (0, shared_1.rel)(full, root);
|
|
31
|
+
if ((0, shared_1.isExcluded)(relPath, exclude))
|
|
56
32
|
continue;
|
|
57
33
|
yield* walk(full, cfg, depth + 1);
|
|
58
34
|
continue;
|
|
59
35
|
}
|
|
60
36
|
if (e.isFile()) {
|
|
61
|
-
const relPath = rel(full, root);
|
|
62
|
-
if (isExcluded(relPath,
|
|
37
|
+
const relPath = (0, shared_1.rel)(full, root);
|
|
38
|
+
if ((0, shared_1.isExcluded)(relPath, exclude))
|
|
63
39
|
continue;
|
|
64
40
|
yield full;
|
|
65
41
|
}
|
|
@@ -72,10 +48,38 @@ function orderByPriority(files, priorityList = []) {
|
|
|
72
48
|
const normal = [];
|
|
73
49
|
for (const f of files) {
|
|
74
50
|
const normalized = f.norm().toLowerCase();
|
|
75
|
-
if (priorityList.some(p => micromatch_1.default.isMatch(normalized, p.toLowerCase())))
|
|
51
|
+
if (priorityList.some((p) => micromatch_1.default.isMatch(normalized, p.toLowerCase())))
|
|
76
52
|
prioritized.push(f);
|
|
77
53
|
else
|
|
78
54
|
normal.push(f);
|
|
79
55
|
}
|
|
80
|
-
return
|
|
56
|
+
return (0, shared_1.unique)([...prioritized, ...normal]);
|
|
57
|
+
}
|
|
58
|
+
function smartNaming(entries) {
|
|
59
|
+
const names = (0, shared_1.unique)(entries.map((f) => path_1.default.basename(f, path_1.default.extname(f))));
|
|
60
|
+
if (names.length === 1)
|
|
61
|
+
return names[0];
|
|
62
|
+
if (names.length === 2)
|
|
63
|
+
return `${names[0]}-${names[1]}`;
|
|
64
|
+
if (names.length > 2)
|
|
65
|
+
return `${names[0]}-and-${names.length - 1}more`;
|
|
66
|
+
return "prodex";
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Safe micromatch.scan wrapper (compatible with micromatch v4 & v5)
|
|
70
|
+
*/
|
|
71
|
+
async function globScan(patterns, opts) {
|
|
72
|
+
const { absolute = true, cwd = process.cwd() } = opts;
|
|
73
|
+
if (!patterns?.length)
|
|
74
|
+
return { files: [] };
|
|
75
|
+
const files = (await (0, fast_glob_1.default)(patterns, {
|
|
76
|
+
cwd,
|
|
77
|
+
extglob: true,
|
|
78
|
+
dot: true,
|
|
79
|
+
onlyFiles: true,
|
|
80
|
+
ignore: constants_1.GLOBAL_IGNORE,
|
|
81
|
+
absolute,
|
|
82
|
+
})).map((f) => path_1.default.resolve(f));
|
|
83
|
+
logger_1.logger.debug("globScan →", _2j(files));
|
|
84
|
+
return { files };
|
|
81
85
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CacheManager = void 0;
|
|
4
|
+
const logger_1 = require("../../lib/logger");
|
|
5
|
+
/**
|
|
6
|
+
* 🧩 CacheManager
|
|
7
|
+
* Unified in-memory registry for all runtime maps.
|
|
8
|
+
*
|
|
9
|
+
* - Namespaced storage (e.g., "aliases", "stats", "resolver")
|
|
10
|
+
* - Purely in-memory (no file I/O)
|
|
11
|
+
* - Static API for symmetry with ConfigManager
|
|
12
|
+
*/
|
|
13
|
+
class CacheManager {
|
|
14
|
+
static registry = new Map();
|
|
15
|
+
/** Ensure namespace map exists and return it */
|
|
16
|
+
static ns(ns) {
|
|
17
|
+
if (!this.registry.has(ns))
|
|
18
|
+
this.registry.set(ns, new Map());
|
|
19
|
+
return this.registry.get(ns);
|
|
20
|
+
}
|
|
21
|
+
/** Set or update a cached entry */
|
|
22
|
+
static set(ns, key, val) {
|
|
23
|
+
this.ns(ns).set(key, val);
|
|
24
|
+
logger_1.logger.debug(`🧩 [cache:${ns}] set ${key} → ${String(val)}`);
|
|
25
|
+
}
|
|
26
|
+
/** Retrieve a cached entry */
|
|
27
|
+
static get(ns, key) {
|
|
28
|
+
return this.ns(ns).get(key);
|
|
29
|
+
}
|
|
30
|
+
/** Remove all entries from one namespace or from all */
|
|
31
|
+
static clear(ns) {
|
|
32
|
+
if (ns) {
|
|
33
|
+
this.ns(ns).clear();
|
|
34
|
+
logger_1.logger.debug(`🧩 [cache:${ns}] cleared`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.registry.forEach((m) => m.clear());
|
|
38
|
+
logger_1.logger.debug("🧩 [cache] cleared all namespaces");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Export a namespace as a plain object (for persistence or inspection) */
|
|
42
|
+
static dump(ns) {
|
|
43
|
+
return Object.fromEntries(this.ns(ns).entries());
|
|
44
|
+
}
|
|
45
|
+
/** Return count of entries per namespace */
|
|
46
|
+
static stats() {
|
|
47
|
+
const summary = {};
|
|
48
|
+
for (const [name, map] of this.registry)
|
|
49
|
+
summary[name] = map.size;
|
|
50
|
+
return summary;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.CacheManager = CacheManager;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ConfigManager = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const default_config_1 = require("../../constants/default-config");
|
|
10
|
+
const utils_1 = require("../../lib/utils");
|
|
11
|
+
const flags_1 = require("../../constants/flags");
|
|
12
|
+
const store_1 = require("../../store");
|
|
13
|
+
/**
|
|
14
|
+
* 🧩 ConfigManager
|
|
15
|
+
* Unified loader, merger, and flag applier.
|
|
16
|
+
*/
|
|
17
|
+
class ConfigManager {
|
|
18
|
+
static load(cwd) {
|
|
19
|
+
const file = path_1.default.join(cwd, "prodex.json");
|
|
20
|
+
if (!fs_1.default.existsSync(file))
|
|
21
|
+
return default_config_1.DEFAULT_PRODEX_CONFIG;
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(fs_1.default.readFileSync(file, "utf8"));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
console.warn("⚠️ Invalid prodex.json — using defaults.");
|
|
27
|
+
return default_config_1.DEFAULT_PRODEX_CONFIG;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
static merge(user, flags, cwd = process.cwd()) {
|
|
31
|
+
const merged = {
|
|
32
|
+
...default_config_1.DEFAULT_PRODEX_CONFIG,
|
|
33
|
+
...user,
|
|
34
|
+
output: { ...default_config_1.DEFAULT_PRODEX_CONFIG.output, ...user.output },
|
|
35
|
+
entry: {
|
|
36
|
+
...default_config_1.DEFAULT_PRODEX_CONFIG.entry,
|
|
37
|
+
...user.entry,
|
|
38
|
+
ui: { ...default_config_1.DEFAULT_PRODEX_CONFIG.entry.ui, ...user.entry?.ui },
|
|
39
|
+
},
|
|
40
|
+
resolve: { ...default_config_1.DEFAULT_PRODEX_CONFIG.resolve, ...user.resolve },
|
|
41
|
+
root: cwd,
|
|
42
|
+
name: flags?.name ?? null,
|
|
43
|
+
};
|
|
44
|
+
this.applyFlags(merged, flags);
|
|
45
|
+
return this.normalize(merged);
|
|
46
|
+
}
|
|
47
|
+
static applyFlags(cfg, flags) {
|
|
48
|
+
if (!flags)
|
|
49
|
+
return cfg;
|
|
50
|
+
for (const [key, val] of Object.entries(flags)) {
|
|
51
|
+
if (val === undefined)
|
|
52
|
+
continue;
|
|
53
|
+
const def = flags_1.FLAG_MAP[key];
|
|
54
|
+
if (def?.apply)
|
|
55
|
+
def.apply(cfg, val);
|
|
56
|
+
}
|
|
57
|
+
const hasFiles = Array.isArray(flags.files) ? flags.files.length > 0 : !!flags.files;
|
|
58
|
+
if (hasFiles && !flags.include)
|
|
59
|
+
cfg.resolve.include = [];
|
|
60
|
+
return cfg;
|
|
61
|
+
}
|
|
62
|
+
static normalize(cfg) {
|
|
63
|
+
cfg.entry.files = (0, utils_1.normalizePatterns)(cfg.entry.files);
|
|
64
|
+
//TODO: Is there a need?
|
|
65
|
+
// cfg.resolve.include = normalizePatterns(cfg.resolve.include);
|
|
66
|
+
// cfg.resolve.exclude = normalizePatterns(cfg.resolve.exclude);
|
|
67
|
+
return cfg;
|
|
68
|
+
}
|
|
69
|
+
static persist(partial) {
|
|
70
|
+
const cfg = (0, store_1.getConfig)();
|
|
71
|
+
const dest = path_1.default.join(cfg.root, "prodex.json");
|
|
72
|
+
const { root, name, ...pure } = cfg;
|
|
73
|
+
const merged = deepMerge(pure, partial);
|
|
74
|
+
try {
|
|
75
|
+
fs_1.default.writeFileSync(dest, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
76
|
+
console.log(`✅ Updated ${dest}`);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
console.warn("⚠️ Failed to persist config:", err?.message || err);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.ConfigManager = ConfigManager;
|
|
84
|
+
function deepMerge(base, patch) {
|
|
85
|
+
if (!patch)
|
|
86
|
+
return base;
|
|
87
|
+
const out = Array.isArray(base) ? [...base] : { ...base };
|
|
88
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
89
|
+
if (v === undefined)
|
|
90
|
+
continue;
|
|
91
|
+
const bv = base[k];
|
|
92
|
+
if (Array.isArray(v))
|
|
93
|
+
out[k] = [...v]; // overwrite arrays
|
|
94
|
+
else if (isPlainObject(v) && isPlainObject(bv))
|
|
95
|
+
out[k] = deepMerge(bv, v);
|
|
96
|
+
else
|
|
97
|
+
out[k] = v;
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
function isPlainObject(x) {
|
|
102
|
+
return x && typeof x === "object" && !Array.isArray(x);
|
|
103
|
+
}
|
package/dist/core/renderers.js
CHANGED
|
@@ -8,24 +8,25 @@ exports.renderMd = renderMd;
|
|
|
8
8
|
exports.tocTxt = tocTxt;
|
|
9
9
|
exports.renderTxt = renderTxt;
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const
|
|
11
|
+
const io_1 = require("../shared/io");
|
|
12
|
+
const io_2 = require("../shared/io");
|
|
12
13
|
const render_constants_1 = require("../constants/render-constants");
|
|
13
14
|
/**
|
|
14
15
|
* Generate Markdown Table of Contents with anchors
|
|
15
16
|
*/
|
|
16
17
|
function tocMd(files) {
|
|
17
18
|
const count = files.length;
|
|
18
|
-
const items = files.map((f, i) => `- [${(0,
|
|
19
|
-
return [
|
|
19
|
+
const items = files.map((f, i) => `- [${(0, io_2.rel)(f)}](#${i + 1})`).join("\n");
|
|
20
|
+
return ["# Index ", `\nIncluded Source Files (${count})`, items, "", "---"].join("\n");
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
23
|
* Render each file section with invisible anchors
|
|
23
24
|
*/
|
|
24
25
|
function renderMd(p, i) {
|
|
25
|
-
const rp = (0,
|
|
26
|
+
const rp = (0, io_2.rel)(p);
|
|
26
27
|
const ext = path_1.default.extname(p).toLowerCase();
|
|
27
28
|
const lang = render_constants_1.LANG_MAP[ext] || "txt";
|
|
28
|
-
const code = (0,
|
|
29
|
+
const code = (0, io_1.readFileSafe)(p).trimEnd();
|
|
29
30
|
return [`---\n#### ${i + 1}`, "\n", "` File: " + rp + "` [↑ Back to top](#index)", "", "```" + lang, code, "```", ""].join("\n");
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
@@ -33,10 +34,10 @@ function renderMd(p, i) {
|
|
|
33
34
|
*/
|
|
34
35
|
function tocTxt(files) {
|
|
35
36
|
const sorted = [...files].sort((a, b) => a.localeCompare(b));
|
|
36
|
-
return ["##==== Combined Scope ====", ...sorted.map((f) => "## - " + (0,
|
|
37
|
+
return ["##==== Combined Scope ====", ...sorted.map((f) => "## - " + (0, io_2.rel)(f))].join("\n") + "\n\n";
|
|
37
38
|
}
|
|
38
39
|
function renderTxt(p) {
|
|
39
|
-
const relPath = (0,
|
|
40
|
-
const code = (0,
|
|
40
|
+
const relPath = (0, io_2.rel)(p);
|
|
41
|
+
const code = (0, io_1.readFileSafe)(p);
|
|
41
42
|
return ["##==== path: " + relPath + " ====", "##region " + relPath, code, "##endregion", ""].join("\n");
|
|
42
43
|
}
|