prodex 1.0.8 ā 1.1.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.
- package/dist/package.json +4 -2
- package/dist/src/cli/init.js +8 -40
- package/dist/src/cli/picker.js +21 -26
- package/dist/src/cli/summary.js +2 -5
- package/dist/src/constants/config-loader.js +74 -51
- package/dist/src/constants/config.js +3 -80
- package/dist/src/constants/default-config.js +36 -0
- package/dist/src/constants/render-constants.js +22 -0
- package/dist/src/core/combine.js +92 -88
- package/dist/src/core/file-utils.js +34 -2
- package/dist/src/core/helpers.js +41 -91
- package/dist/src/core/renderers.js +58 -0
- package/dist/src/index.js +5 -1
- package/dist/src/resolvers/js-resolver.js +104 -59
- package/dist/src/resolvers/php-resolver.js +70 -30
- package/package.json +4 -2
package/dist/src/core/combine.js
CHANGED
|
@@ -1,122 +1,116 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
2
|
import inquirer from "inquirer";
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
CODE_EXTS,
|
|
7
|
-
RESOLVERS,
|
|
8
|
-
PROMPTS
|
|
9
|
-
} from "../constants/config.js";
|
|
10
|
-
import { loadProdexConfig } from "../constants/config-loader.js";
|
|
11
|
-
import { read, normalizeIndent, stripComments, rel } from "./helpers.js";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import micromatch from "micromatch";
|
|
12
5
|
import { pickEntries } from "../cli/picker.js";
|
|
13
6
|
import { showSummary } from "../cli/summary.js";
|
|
14
|
-
import {
|
|
7
|
+
import { loadProdexConfig } from "../constants/config-loader.js";
|
|
8
|
+
import { CODE_EXTS, RESOLVERS, ROOT } from "../constants/config.js";
|
|
9
|
+
import { generateOutputName, resolveOutDirPath, safeMicromatchScan } from "./file-utils.js";
|
|
10
|
+
import { renderMd, renderTxt, tocMd, tocTxt } from "./renderers.js";
|
|
11
|
+
|
|
15
12
|
|
|
16
|
-
export async function runCombine() {
|
|
13
|
+
export async function runCombine(opts = {}) {
|
|
17
14
|
const cliLimitFlag = process.argv.find(arg => arg.startsWith("--limit="));
|
|
18
15
|
const customLimit = cliLimitFlag ? parseInt(cliLimitFlag.split("=")[1], 10) : null;
|
|
16
|
+
const cliTxtFlag = process.argv.includes("--txt");
|
|
19
17
|
|
|
20
18
|
const cfg = loadProdexConfig();
|
|
21
|
-
const {
|
|
19
|
+
const { scanDepth } = cfg;
|
|
20
|
+
|
|
21
|
+
let entries = opts.entries;
|
|
22
|
+
|
|
23
|
+
// š§© Headless mode: expand globs manually
|
|
24
|
+
if (entries && entries.length) {
|
|
25
|
+
const all = [];
|
|
26
|
+
for (const pattern of entries) {
|
|
27
|
+
const abs = path.resolve(process.cwd(), pattern);
|
|
28
|
+
if (fs.existsSync(abs) && fs.statSync(abs).isFile()) {
|
|
29
|
+
// direct file path (no glob)
|
|
30
|
+
all.push(abs);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// glob pattern
|
|
35
|
+
const result = safeMicromatchScan(pattern, {
|
|
36
|
+
cwd: process.cwd(),
|
|
37
|
+
absolute: true,
|
|
38
|
+
});
|
|
39
|
+
if (result?.files?.length) all.push(...result.files);
|
|
40
|
+
}
|
|
41
|
+
entries = [...new Set(all)];
|
|
42
|
+
} else {
|
|
43
|
+
// fallback to interactive picker
|
|
44
|
+
entries = await pickEntries(cfg.entry.includes, scanDepth, cfg);
|
|
45
|
+
}
|
|
46
|
+
|
|
22
47
|
|
|
23
|
-
const entries = await pickEntries(baseDirs, scanDepth, cfg);
|
|
24
48
|
if (!entries.length) {
|
|
25
49
|
console.log("ā No entries selected.");
|
|
26
50
|
return;
|
|
27
51
|
}
|
|
28
52
|
|
|
29
|
-
const autoName = generateOutputName(entries);
|
|
30
|
-
const outputDir = cfg.output || path.join(ROOT, "prodex");
|
|
31
|
-
const defaultLimit = customLimit || cfg.limit || 200;
|
|
32
|
-
|
|
33
53
|
console.log("\nš You selected:");
|
|
34
|
-
for (const e of entries) console.log(" -",
|
|
35
|
-
|
|
36
|
-
const { yesToAll } = await inquirer.prompt([PROMPTS.yesToAll]);
|
|
37
|
-
|
|
38
|
-
let outputBase = autoName,
|
|
39
|
-
limit = defaultLimit,
|
|
40
|
-
chain = true,
|
|
41
|
-
proceed = true;
|
|
42
|
-
|
|
43
|
-
if (!yesToAll) {
|
|
44
|
-
const combinePrompts = PROMPTS.combine.map(p => ({
|
|
45
|
-
...p,
|
|
46
|
-
default:
|
|
47
|
-
p.name === "outputBase"
|
|
48
|
-
? autoName
|
|
49
|
-
: p.name === "limit"
|
|
50
|
-
? defaultLimit
|
|
51
|
-
: p.default
|
|
52
|
-
}));
|
|
53
|
-
|
|
54
|
-
const ans = await inquirer.prompt(combinePrompts);
|
|
55
|
-
outputBase = ans.outputBase || autoName;
|
|
56
|
-
limit = ans.limit;
|
|
57
|
-
chain = ans.chain;
|
|
58
|
-
proceed = ans.proceed;
|
|
59
|
-
}
|
|
54
|
+
for (const e of entries) console.log(" -", e.replace(ROOT + "/", ""));
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
// š§© Auto name suggestion
|
|
57
|
+
const autoName = generateOutputName(entries);
|
|
58
|
+
const outDir = cfg.outDir || path.join(ROOT, "prodex");
|
|
59
|
+
const limit = customLimit || cfg.limit || 200;
|
|
60
|
+
const chain = true;
|
|
61
|
+
|
|
62
|
+
// Skip prompt if entries were passed directly
|
|
63
|
+
let outputBase = autoName;
|
|
64
|
+
if (!opts.entries?.length) {
|
|
65
|
+
const { outputBase: answer } = await inquirer.prompt([
|
|
66
|
+
{
|
|
67
|
+
type: "input",
|
|
68
|
+
name: "outputBase",
|
|
69
|
+
message: "Output file name (without extension):",
|
|
70
|
+
default: autoName,
|
|
71
|
+
filter: v => (v.trim() || autoName).replace(/[<>:"/\\|?*]+/g, "_"),
|
|
72
|
+
},
|
|
73
|
+
]);
|
|
74
|
+
outputBase = answer;
|
|
64
75
|
}
|
|
65
76
|
|
|
77
|
+
// Ensure output directory exists
|
|
66
78
|
try {
|
|
67
|
-
fs.mkdirSync(
|
|
79
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
68
80
|
} catch {
|
|
69
|
-
console.warn("ā ļø Could not create
|
|
81
|
+
console.warn("ā ļø Could not create outDir directory:", outDir);
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
const
|
|
84
|
+
const outputPath = resolveOutDirPath(outDir, outputBase, cliTxtFlag);
|
|
73
85
|
|
|
74
|
-
showSummary({
|
|
75
|
-
outputDir,
|
|
76
|
-
fileName: path.basename(output),
|
|
77
|
-
entries,
|
|
78
|
-
scanDepth: cfg.scanDepth,
|
|
79
|
-
limit,
|
|
80
|
-
chain
|
|
81
|
-
});
|
|
86
|
+
showSummary({ outDir, fileName: path.basename(outputPath), entries });
|
|
82
87
|
|
|
83
|
-
const finalFiles = chain ? await followChain(entries, limit) : entries;
|
|
84
88
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
[toc(finalFiles), ...finalFiles.map(render)].join(""),
|
|
88
|
-
"utf8"
|
|
89
|
-
);
|
|
89
|
+
const result = chain ? await followChain(entries, cfg, limit) : { files: entries, stats: { totalImports: 0, totalResolved: 0 } };
|
|
90
|
+
const sorted = [...result.files].sort((a, b) => a.localeCompare(b));
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
const content = cliTxtFlag
|
|
93
|
+
? [tocTxt(sorted), ...sorted.map(renderTxt)].join("")
|
|
94
|
+
: [tocMd(sorted), ...sorted.map((f, i) => renderMd(f, i === 0))].join("\n");
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
function regionStart(p) {
|
|
98
|
-
return `##region ${rel(p)}`;
|
|
99
|
-
}
|
|
100
|
-
const regionEnd = "##endregion";
|
|
101
|
-
|
|
102
|
-
function render(p) {
|
|
103
|
-
const ext = path.extname(p);
|
|
104
|
-
let s = read(p);
|
|
105
|
-
return `${header(p)}\n${regionStart(p)}\n${s}\n${regionEnd}\n\n`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function toc(files) {
|
|
109
|
-
return (
|
|
110
|
-
["##==== Combined Scope ====", ...files.map(f => "## - " + rel(f))].join(
|
|
111
|
-
"\n"
|
|
112
|
-
) + "\n\n"
|
|
96
|
+
fs.writeFileSync(outputPath, content, "utf8");
|
|
97
|
+
console.log(
|
|
98
|
+
`\nā
${outputPath}`
|
|
113
99
|
);
|
|
100
|
+
// š§© Print resolver summary (clean version)
|
|
101
|
+
console.log(`\nš§© Summary:
|
|
102
|
+
⢠Unique imports expected: ${result.stats.expected.size}
|
|
103
|
+
⢠Unique imports resolved: ${result.stats.resolved.size}
|
|
104
|
+
`);
|
|
114
105
|
}
|
|
115
106
|
|
|
116
|
-
async function followChain(entryFiles, limit = 200) {
|
|
107
|
+
async function followChain(entryFiles, cfg, limit = 200) {
|
|
117
108
|
console.log("š§© Following dependency chain...");
|
|
118
109
|
const visited = new Set();
|
|
119
110
|
const all = [];
|
|
111
|
+
const expected = new Set();
|
|
112
|
+
const resolved = new Set();
|
|
113
|
+
const resolverDepth = cfg.resolverDepth ?? 10;
|
|
120
114
|
|
|
121
115
|
for (const f of entryFiles) {
|
|
122
116
|
if (visited.has(f)) continue;
|
|
@@ -127,15 +121,25 @@ async function followChain(entryFiles, limit = 200) {
|
|
|
127
121
|
|
|
128
122
|
const resolver = RESOLVERS[ext];
|
|
129
123
|
if (resolver) {
|
|
130
|
-
const
|
|
124
|
+
const result = await resolver(f, cfg, visited, 0, resolverDepth);
|
|
125
|
+
const { files, stats } = result;
|
|
131
126
|
all.push(...files);
|
|
127
|
+
stats?.expected?.forEach(x => expected.add(x));
|
|
128
|
+
stats?.resolved?.forEach(x => resolved.add(x));
|
|
132
129
|
}
|
|
133
130
|
|
|
134
|
-
if (all.length >= limit) {
|
|
131
|
+
if (limit && all.length >= limit) {
|
|
135
132
|
console.log("ā ļø Limit reached:", limit);
|
|
136
133
|
break;
|
|
137
134
|
}
|
|
138
135
|
}
|
|
139
136
|
|
|
140
|
-
return
|
|
137
|
+
return {
|
|
138
|
+
files: [...new Set(all)],
|
|
139
|
+
stats: {
|
|
140
|
+
expected,
|
|
141
|
+
resolved
|
|
142
|
+
}
|
|
143
|
+
};
|
|
141
144
|
}
|
|
145
|
+
|
|
@@ -1,4 +1,35 @@
|
|
|
1
|
+
import fs from "fs";
|
|
1
2
|
import path from "path";
|
|
3
|
+
import micromatch from "micromatch";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Safe micromatch.scan wrapper (compatible with micromatch v4 & v5)
|
|
7
|
+
*/
|
|
8
|
+
export function safeMicromatchScan(pattern, opts = {}) {
|
|
9
|
+
const scanFn = micromatch.scan;
|
|
10
|
+
if (typeof scanFn === "function") return scanFn(pattern, opts);
|
|
11
|
+
|
|
12
|
+
// --- fallback for micromatch v4 ---
|
|
13
|
+
const cwd = opts.cwd || process.cwd();
|
|
14
|
+
const abs = !!opts.absolute;
|
|
15
|
+
const allFiles = listAllFiles(cwd);
|
|
16
|
+
const matched = micromatch.match(allFiles, pattern, { dot: true });
|
|
17
|
+
return { files: abs ? matched.map(f => path.resolve(cwd, f)) : matched };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Recursively list all files in a directory.
|
|
22
|
+
* Used only for fallback (so performance isnāt critical).
|
|
23
|
+
*/
|
|
24
|
+
function listAllFiles(dir) {
|
|
25
|
+
const out = [];
|
|
26
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
27
|
+
const full = path.join(dir, entry.name);
|
|
28
|
+
if (entry.isDirectory()) out.push(...listAllFiles(full));
|
|
29
|
+
else out.push(full);
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
2
33
|
|
|
3
34
|
export function generateOutputName(entries) {
|
|
4
35
|
const names = entries.map(f => path.basename(f, path.extname(f)));
|
|
@@ -8,6 +39,7 @@ export function generateOutputName(entries) {
|
|
|
8
39
|
return "unknown";
|
|
9
40
|
}
|
|
10
41
|
|
|
11
|
-
export function
|
|
12
|
-
|
|
42
|
+
export function resolveOutDirPath(outDir, base, asTxt = false) {
|
|
43
|
+
const ext = asTxt ? "txt" : "md";
|
|
44
|
+
return path.join(outDir, `${base}-combined.${ext}`);
|
|
13
45
|
}
|
package/dist/src/core/helpers.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import
|
|
3
|
+
import micromatch from "micromatch";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Get a root-relative version of a path.
|
|
7
|
+
*/
|
|
8
|
+
export function rel(p, root = process.cwd()) {
|
|
9
|
+
return path.relative(root, p).replaceAll("\\", "/");
|
|
7
10
|
}
|
|
8
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Safe text read.
|
|
14
|
+
*/
|
|
9
15
|
export function read(p) {
|
|
10
16
|
try {
|
|
11
17
|
return fs.readFileSync(p, "utf8");
|
|
@@ -14,104 +20,47 @@ export function read(p) {
|
|
|
14
20
|
}
|
|
15
21
|
}
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Check if a path/file matches any of the provided glob patterns.
|
|
25
|
+
*/
|
|
26
|
+
export function isExcluded(p, patterns, root = process.cwd()) {
|
|
27
|
+
if (!patterns?.length) return false;
|
|
28
|
+
const relPath = rel(p, root);
|
|
29
|
+
return micromatch.isMatch(relPath, patterns);
|
|
23
30
|
}
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
let inStr = false;
|
|
34
|
-
let strChar = "";
|
|
35
|
-
let inBlockComment = false;
|
|
36
|
-
let inLineComment = false;
|
|
37
|
-
|
|
38
|
-
for (let i = 0; i < code.length; i++) {
|
|
39
|
-
const c = code[i];
|
|
40
|
-
const next = code[i + 1];
|
|
41
|
-
|
|
42
|
-
if (inBlockComment) {
|
|
43
|
-
if (c === "*" && next === "/") {
|
|
44
|
-
inBlockComment = false;
|
|
45
|
-
i++;
|
|
46
|
-
}
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (inLineComment) {
|
|
51
|
-
if (c === "\n") {
|
|
52
|
-
inLineComment = false;
|
|
53
|
-
out += c;
|
|
54
|
-
}
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (inStr) {
|
|
59
|
-
if (c === "\\" && next) {
|
|
60
|
-
out += c + next;
|
|
61
|
-
i++;
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
if (c === strChar) inStr = false;
|
|
65
|
-
out += c;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (c === '"' || c === "'" || c === "`") {
|
|
70
|
-
inStr = true;
|
|
71
|
-
strChar = c;
|
|
72
|
-
out += c;
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
32
|
+
/**
|
|
33
|
+
* Recursive walker that respects glob excludes.
|
|
34
|
+
* Returns all files under the given directory tree.
|
|
35
|
+
*/
|
|
36
|
+
export function* walk(dir, cfg, depth = 0) {
|
|
37
|
+
const { scanDepth, entry } = cfg;
|
|
38
|
+
const root = process.cwd();
|
|
39
|
+
if (depth > scanDepth) return;
|
|
75
40
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
41
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
42
|
+
for (const e of entries) {
|
|
43
|
+
const full = path.join(dir, e.name);
|
|
81
44
|
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
45
|
+
if (e.isDirectory()) {
|
|
46
|
+
// Skip excluded directories entirely
|
|
47
|
+
const relPath = rel(full, root);
|
|
48
|
+
if (isExcluded(relPath, entry.excludes)) continue;
|
|
49
|
+
yield* walk(full, cfg, depth + 1);
|
|
85
50
|
continue;
|
|
86
51
|
}
|
|
87
52
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function isEntryExcluded(p) {
|
|
95
|
-
const r = rel(p);
|
|
96
|
-
return ENTRY_EXCLUDES.some(ex => r.startsWith(ex) || r.includes(ex));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function* walk(dir, depth = 0, maxDepth = 2) {
|
|
100
|
-
if (depth > maxDepth) return;
|
|
101
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
102
|
-
for (const e of entries) {
|
|
103
|
-
const full = path.join(dir, e.name);
|
|
104
|
-
if (e.isDirectory()) yield* walk(full, depth + 1, maxDepth);
|
|
105
|
-
else if (e.isFile()) {
|
|
106
|
-
const ext = path.extname(e.name).toLowerCase();
|
|
107
|
-
const relPath = rel(full);
|
|
108
|
-
if (CODE_EXTS.includes(ext) && !ENTRY_EXCLUDES.some(ex => relPath.startsWith(ex))) {
|
|
109
|
-
yield full;
|
|
110
|
-
}
|
|
53
|
+
if (e.isFile()) {
|
|
54
|
+
const relPath = rel(full, root);
|
|
55
|
+
if (isExcluded(relPath, entry.excludes)) continue;
|
|
56
|
+
yield full;
|
|
111
57
|
}
|
|
112
58
|
}
|
|
113
59
|
}
|
|
114
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Sorts files so that priority items appear first.
|
|
63
|
+
*/
|
|
115
64
|
export function sortWithPriority(files, priorityList = []) {
|
|
116
65
|
if (!priorityList.length) return files;
|
|
117
66
|
const prioritized = [];
|
|
@@ -119,7 +68,8 @@ export function sortWithPriority(files, priorityList = []) {
|
|
|
119
68
|
|
|
120
69
|
for (const f of files) {
|
|
121
70
|
const normalized = f.replaceAll("\\", "/").toLowerCase();
|
|
122
|
-
if (priorityList.some(p =>
|
|
71
|
+
if (priorityList.some(p => micromatch.isMatch(normalized, p.toLowerCase())))
|
|
72
|
+
prioritized.push(f);
|
|
123
73
|
else normal.push(f);
|
|
124
74
|
}
|
|
125
75
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { read, rel } from "./helpers.js";
|
|
3
|
+
import { LANG_MAP } from "../constants/render-constants.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate Markdown Table of Contents
|
|
7
|
+
* Sorted alphabetically for deterministic structure.
|
|
8
|
+
*/
|
|
9
|
+
export function tocMd(files) {
|
|
10
|
+
const sorted = [...files].sort((a, b) => a.localeCompare(b));
|
|
11
|
+
const items = sorted.map(f => "- " + rel(f)).join("\n");
|
|
12
|
+
return `# Included Source Files\n\n${items}\n\n---\n`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Render a single file section in Markdown format.
|
|
17
|
+
* The first file skips the leading separator to avoid duplicates.
|
|
18
|
+
*/
|
|
19
|
+
export function renderMd(p, isFirst = false) {
|
|
20
|
+
const rp = rel(p);
|
|
21
|
+
const ext = path.extname(p).toLowerCase();
|
|
22
|
+
const lang = LANG_MAP[ext] || "txt";
|
|
23
|
+
const code = read(p).trimEnd();
|
|
24
|
+
|
|
25
|
+
return [
|
|
26
|
+
isFirst ? "" : "---", // only add separator *after* the first file
|
|
27
|
+
`\`File: ${rp}\``,
|
|
28
|
+
"",
|
|
29
|
+
"```" + lang,
|
|
30
|
+
code,
|
|
31
|
+
"```",
|
|
32
|
+
""
|
|
33
|
+
]
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.join("\n");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* TXT version (unchanged)
|
|
40
|
+
*/
|
|
41
|
+
export function tocTxt(files) {
|
|
42
|
+
const sorted = [...files].sort((a, b) => a.localeCompare(b));
|
|
43
|
+
return (
|
|
44
|
+
["##==== Combined Scope ====", ...sorted.map(f => "## - " + rel(f))].join("\n") + "\n\n"
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function renderTxt(p) {
|
|
49
|
+
const relPath = rel(p);
|
|
50
|
+
const code = read(p);
|
|
51
|
+
return [
|
|
52
|
+
"##==== path: " + relPath + " ====",
|
|
53
|
+
"##region " + relPath,
|
|
54
|
+
code,
|
|
55
|
+
"##endregion",
|
|
56
|
+
""
|
|
57
|
+
].join("\n");
|
|
58
|
+
}
|
package/dist/src/index.js
CHANGED
|
@@ -5,7 +5,11 @@ export default async function startProdex() {
|
|
|
5
5
|
const args = process.argv.slice(2);
|
|
6
6
|
if (args.includes("init")) return await initProdex();
|
|
7
7
|
|
|
8
|
+
const entryArgs = args.filter(a => !a.startsWith("--"));
|
|
9
|
+
const hasEntries = entryArgs.length > 0;
|
|
10
|
+
|
|
8
11
|
console.clear();
|
|
9
12
|
console.log("š§© Prodex ā Project Dependency Extractor\n");
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
await runCombine({ entries: hasEntries ? entryArgs : null });
|
|
11
15
|
}
|