@reliverse/dler 1.7.75 → 1.7.76
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/bin/app/agg/cmd.js +1 -1
- package/bin/cli.js +1 -1
- package/bin/libs/sdk/sdk-impl/config/info.js +1 -1
- package/bin/libs/sdk/sdk-impl/utils/agg/agg-1.d.ts +1 -0
- package/bin/libs/sdk/sdk-impl/utils/agg/agg-1.js +194 -0
- package/bin/libs/sdk/sdk-impl/utils/agg/{agg.d.ts → agg-2.d.ts} +0 -5
- package/bin/libs/sdk/sdk-impl/utils/agg/agg-2.js +148 -0
- package/bin/libs/sdk/sdk-impl/utils/agg/agg-3.d.ts +41 -0
- package/bin/libs/sdk/sdk-impl/utils/agg/agg-3.js +197 -0
- package/bin/libs/sdk/sdk-impl/utils/agg/agg-4.d.ts +8 -0
- package/bin/libs/sdk/sdk-impl/utils/agg/agg-4.js +26 -0
- package/bin/libs/sdk/sdk-impl/utils/agg/agg-5.d.ts +4 -0
- package/bin/libs/sdk/sdk-impl/utils/agg/agg-5.js +17 -0
- package/bin/libs/sdk/sdk-mod.d.ts +46 -42
- package/bin/libs/sdk/sdk-mod.js +232 -31
- package/package.json +1 -1
- package/bin/libs/sdk/sdk-impl/utils/agg/agg.js +0 -800
package/bin/app/agg/cmd.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "@reliverse/pathkit";
|
|
2
2
|
import { inputPrompt, defineArgs, defineCommand } from "@reliverse/rempts";
|
|
3
|
-
import { useAggregator } from "../../libs/sdk/sdk-impl/utils/agg/agg.js";
|
|
3
|
+
import { useAggregator } from "../../libs/sdk/sdk-impl/utils/agg/agg-2.js";
|
|
4
4
|
export default defineCommand({
|
|
5
5
|
args: defineArgs({
|
|
6
6
|
imports: {
|
package/bin/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { runMain, defineCommand, defineArgs, selectPrompt, showUsage } from "@re
|
|
|
3
3
|
import { callCmd } from "./app/cmds.js";
|
|
4
4
|
import { showEndPrompt, showStartPrompt } from "./libs/sdk/sdk-impl/config/info.js";
|
|
5
5
|
import { prepareDlerEnvironment } from "./libs/sdk/sdk-impl/config/prepare.js";
|
|
6
|
-
import { promptAggCommand } from "./libs/sdk/sdk-impl/utils/agg/agg.js";
|
|
6
|
+
import { promptAggCommand } from "./libs/sdk/sdk-impl/utils/agg/agg-1.js";
|
|
7
7
|
const MENU_CMDS = ["agg", "build", "pub", "update"];
|
|
8
8
|
let isDev = process.env.DLER_DEV_MODE === "true";
|
|
9
9
|
const main = defineCommand({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function promptAggCommand(): Promise<void>;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import path from "@reliverse/pathkit";
|
|
2
|
+
import { relinka } from "@reliverse/relinka";
|
|
3
|
+
import { selectPrompt, confirmPrompt, inputPrompt } from "@reliverse/rempts";
|
|
4
|
+
import { getConfigDler } from "../../config/load.js";
|
|
5
|
+
import { useAggregator } from "./agg-2.js";
|
|
6
|
+
import { findMainEntryFile } from "./agg-4.js";
|
|
7
|
+
import { isAggregationDisabled } from "./agg-5.js";
|
|
8
|
+
export async function promptAggCommand() {
|
|
9
|
+
const config = await getConfigDler();
|
|
10
|
+
let selectedLibName = null;
|
|
11
|
+
const mainEntryFile = await findMainEntryFile(config);
|
|
12
|
+
const isMainDisabled = mainEntryFile ? await isAggregationDisabled(mainEntryFile) : false;
|
|
13
|
+
if (config?.libsList && Object.keys(config.libsList).length > 0) {
|
|
14
|
+
const libEntries = await Promise.all(
|
|
15
|
+
Object.entries(config.libsList).map(async ([name, lib]) => {
|
|
16
|
+
const libMainFile = `${config.libsDirSrc}/${lib.libMainFile}`;
|
|
17
|
+
const isLibDisabled = await isAggregationDisabled(libMainFile);
|
|
18
|
+
return {
|
|
19
|
+
name,
|
|
20
|
+
lib,
|
|
21
|
+
isDisabled: isLibDisabled
|
|
22
|
+
};
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
const libs = libEntries.filter(({ isDisabled }) => !isDisabled).map(({ name, lib }) => ({
|
|
26
|
+
value: name,
|
|
27
|
+
label: name,
|
|
28
|
+
hint: `${config.libsDirSrc}/${lib.libDirName}/${lib.libDirName}-impl`
|
|
29
|
+
}));
|
|
30
|
+
if (mainEntryFile && !isMainDisabled) {
|
|
31
|
+
libs.unshift({
|
|
32
|
+
value: "main",
|
|
33
|
+
label: "Main package",
|
|
34
|
+
hint: mainEntryFile
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
libs.push({ value: "", label: "Skip selection", hint: "" });
|
|
38
|
+
selectedLibName = await selectPrompt({
|
|
39
|
+
title: "Select a package to aggregate or skip",
|
|
40
|
+
options: libs
|
|
41
|
+
});
|
|
42
|
+
} else if (mainEntryFile && !isMainDisabled) {
|
|
43
|
+
const shouldUseMain = await confirmPrompt({
|
|
44
|
+
title: `Use main package for aggregation? (Found: ${mainEntryFile})`,
|
|
45
|
+
defaultValue: true
|
|
46
|
+
});
|
|
47
|
+
if (shouldUseMain) {
|
|
48
|
+
selectedLibName = "main";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
let imports = false;
|
|
52
|
+
let input = "";
|
|
53
|
+
let named = true;
|
|
54
|
+
let out = "";
|
|
55
|
+
let recursive = true;
|
|
56
|
+
let strip = "";
|
|
57
|
+
let separateTypesFile = false;
|
|
58
|
+
let typesOut = "";
|
|
59
|
+
if (selectedLibName && selectedLibName !== "") {
|
|
60
|
+
if (selectedLibName === "main" && mainEntryFile && !isMainDisabled) {
|
|
61
|
+
const entryDir = path.dirname(mainEntryFile);
|
|
62
|
+
input = entryDir;
|
|
63
|
+
out = mainEntryFile;
|
|
64
|
+
strip = entryDir;
|
|
65
|
+
} else if (selectedLibName === "main" && isMainDisabled) {
|
|
66
|
+
relinka.log("Main package aggregation is disabled due to <dler-disable-agg> comment.");
|
|
67
|
+
return;
|
|
68
|
+
} else {
|
|
69
|
+
const libConfig = config?.libsList?.[selectedLibName];
|
|
70
|
+
if (config && libConfig) {
|
|
71
|
+
input = `${config.libsDirSrc}/${libConfig.libDirName}/${libConfig.libDirName}-impl`;
|
|
72
|
+
out = `${config.libsDirSrc}/${libConfig.libMainFile}`;
|
|
73
|
+
strip = `${config.libsDirSrc}/${libConfig.libDirName}`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!selectedLibName || !input) {
|
|
78
|
+
input = await inputPrompt({
|
|
79
|
+
title: "Enter the input directory",
|
|
80
|
+
defaultValue: input
|
|
81
|
+
});
|
|
82
|
+
if (input) {
|
|
83
|
+
if (mainEntryFile && isMainDisabled) {
|
|
84
|
+
const mainEntryDir = path.dirname(mainEntryFile);
|
|
85
|
+
if (path.resolve(input) === path.resolve(mainEntryDir) || path.resolve(input) === path.resolve(mainEntryFile)) {
|
|
86
|
+
relinka.log("Main package aggregation is disabled due to <dler-disable-agg> comment.");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (config?.libsList) {
|
|
91
|
+
for (const [libName, libConfig] of Object.entries(config.libsList)) {
|
|
92
|
+
const libImplPath = `${config.libsDirSrc}/${libConfig.libDirName}/${libConfig.libDirName}-impl`;
|
|
93
|
+
const libMainFile = `${config.libsDirSrc}/${libConfig.libMainFile}`;
|
|
94
|
+
if (path.resolve(input) === path.resolve(libImplPath) || path.resolve(input) === path.resolve(libMainFile)) {
|
|
95
|
+
const isLibDisabled = await isAggregationDisabled(libMainFile);
|
|
96
|
+
if (isLibDisabled) {
|
|
97
|
+
relinka.log(
|
|
98
|
+
`Library "${libName}" aggregation is disabled due to <dler-disable-agg> comment.`
|
|
99
|
+
);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const verbose = await confirmPrompt({
|
|
108
|
+
title: "Enable verbose logging and additional options?",
|
|
109
|
+
defaultValue: false
|
|
110
|
+
});
|
|
111
|
+
let sortLines = false;
|
|
112
|
+
let headerComment = "";
|
|
113
|
+
let includeInternal = false;
|
|
114
|
+
let internalMarker = "#";
|
|
115
|
+
let overrideFile = false;
|
|
116
|
+
let extensions = ".ts,.js,.mts,.cts,.mjs,.cjs";
|
|
117
|
+
if (verbose) {
|
|
118
|
+
sortLines = await confirmPrompt({
|
|
119
|
+
title: "Sort aggregated lines alphabetically?",
|
|
120
|
+
defaultValue: false
|
|
121
|
+
});
|
|
122
|
+
headerComment = await inputPrompt({
|
|
123
|
+
title: "Add a header comment to the aggregator output (optional):",
|
|
124
|
+
defaultValue: ""
|
|
125
|
+
});
|
|
126
|
+
includeInternal = await confirmPrompt({
|
|
127
|
+
title: "Include files marked as internal (starting with #)?",
|
|
128
|
+
defaultValue: false
|
|
129
|
+
});
|
|
130
|
+
internalMarker = await inputPrompt({
|
|
131
|
+
title: "Marker for internal files:",
|
|
132
|
+
defaultValue: "#"
|
|
133
|
+
});
|
|
134
|
+
overrideFile = await confirmPrompt({
|
|
135
|
+
title: "Override entire file instead of updating only the aggregator block?",
|
|
136
|
+
defaultValue: false
|
|
137
|
+
});
|
|
138
|
+
extensions = await inputPrompt({
|
|
139
|
+
title: "File extensions to process (comma-separated):",
|
|
140
|
+
defaultValue: ".ts,.js,.mts,.cts,.mjs,.cjs"
|
|
141
|
+
});
|
|
142
|
+
imports = await confirmPrompt({
|
|
143
|
+
title: "Do you want to generate imports instead of exports? (N generates exports)",
|
|
144
|
+
defaultValue: imports
|
|
145
|
+
});
|
|
146
|
+
named = await confirmPrompt({
|
|
147
|
+
title: imports ? "Do you want to generate named imports?" : "Do you want to generate named exports?",
|
|
148
|
+
defaultValue: named
|
|
149
|
+
});
|
|
150
|
+
recursive = await confirmPrompt({
|
|
151
|
+
title: "Do you want to recursively scan subdirectories?",
|
|
152
|
+
defaultValue: recursive
|
|
153
|
+
});
|
|
154
|
+
separateTypesFile = await confirmPrompt({
|
|
155
|
+
title: "Do you want to create a separate file for type exports?",
|
|
156
|
+
defaultValue: separateTypesFile
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (!selectedLibName || !out) {
|
|
160
|
+
out = await inputPrompt({
|
|
161
|
+
title: "Enter the output file",
|
|
162
|
+
defaultValue: out
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (!selectedLibName || !strip) {
|
|
166
|
+
strip = await inputPrompt({
|
|
167
|
+
title: "Enter the path to strip from the final imports/exports",
|
|
168
|
+
defaultValue: strip
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (separateTypesFile) {
|
|
172
|
+
typesOut = await inputPrompt({
|
|
173
|
+
title: "Enter the output file for types",
|
|
174
|
+
defaultValue: out.replace(/\.(ts|js)$/, ".types.$1")
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
await useAggregator({
|
|
178
|
+
inputDir: path.resolve(input),
|
|
179
|
+
isRecursive: recursive,
|
|
180
|
+
outFile: path.resolve(out),
|
|
181
|
+
stripPrefix: strip ? path.resolve(strip) : "",
|
|
182
|
+
useImport: imports,
|
|
183
|
+
useNamed: named,
|
|
184
|
+
sortLines,
|
|
185
|
+
headerComment,
|
|
186
|
+
verbose,
|
|
187
|
+
includeInternal,
|
|
188
|
+
internalMarker,
|
|
189
|
+
overrideFile,
|
|
190
|
+
fileExtensions: extensions.split(",").map((ext) => ext.trim()),
|
|
191
|
+
separateTypesFile,
|
|
192
|
+
typesOutFile: typesOut ? path.resolve(typesOut) : void 0
|
|
193
|
+
});
|
|
194
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export declare function promptAggCommand(): Promise<void>;
|
|
2
1
|
/**
|
|
3
2
|
* Aggregator supporting:
|
|
4
3
|
* - --import or default export,
|
|
@@ -34,7 +33,3 @@ export declare function useAggregator({ inputDir, isRecursive, outFile, stripPre
|
|
|
34
33
|
separateTypesFile?: boolean;
|
|
35
34
|
typesOutFile?: string;
|
|
36
35
|
}): Promise<void>;
|
|
37
|
-
/**
|
|
38
|
-
* Prints usage examples based on whether dev mode or not.
|
|
39
|
-
*/
|
|
40
|
-
export declare function printUsage(isDev?: boolean): void;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import path from "@reliverse/pathkit";
|
|
2
|
+
import fs from "@reliverse/relifso";
|
|
3
|
+
import { relinka } from "@reliverse/relinka";
|
|
4
|
+
import { collectFiles, generateAggregatorLines } from "./agg-3.js";
|
|
5
|
+
const AGGREGATOR_START = "// AUTO-GENERATED AGGREGATOR START (via `dler agg`)";
|
|
6
|
+
const AGGREGATOR_END = "// AUTO-GENERATED AGGREGATOR END";
|
|
7
|
+
export async function useAggregator({
|
|
8
|
+
inputDir,
|
|
9
|
+
isRecursive,
|
|
10
|
+
outFile,
|
|
11
|
+
stripPrefix,
|
|
12
|
+
useImport,
|
|
13
|
+
useNamed,
|
|
14
|
+
ignoreDirs = ["node_modules", ".git"],
|
|
15
|
+
sortLines = false,
|
|
16
|
+
headerComment = "",
|
|
17
|
+
verbose = false,
|
|
18
|
+
includeInternal = false,
|
|
19
|
+
internalMarker = "#",
|
|
20
|
+
overrideFile = false,
|
|
21
|
+
fileExtensions = [".ts", ".js", ".mts", ".cts", ".mjs", ".cjs"],
|
|
22
|
+
separateTypesFile = false,
|
|
23
|
+
typesOutFile
|
|
24
|
+
}) {
|
|
25
|
+
try {
|
|
26
|
+
const st = await fs.stat(inputDir).catch(() => null);
|
|
27
|
+
if (!st?.isDirectory()) {
|
|
28
|
+
relinka("error", `Error: --input is not a valid directory: ${inputDir}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const outDir = path.dirname(outFile);
|
|
32
|
+
try {
|
|
33
|
+
await fs.ensureDir(outDir);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
relinka("error", `Error: Cannot create output directory: ${outDir}
|
|
36
|
+
${error}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
if (separateTypesFile && typesOutFile) {
|
|
40
|
+
const typesOutDir = path.dirname(typesOutFile);
|
|
41
|
+
try {
|
|
42
|
+
await fs.ensureDir(typesOutDir);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
relinka("error", `Error: Cannot create types output directory: ${typesOutDir}
|
|
45
|
+
${error}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const outExt = path.extname(outFile).toLowerCase();
|
|
50
|
+
if (!fileExtensions.includes(outExt)) {
|
|
51
|
+
relinka(
|
|
52
|
+
"warn",
|
|
53
|
+
`Warning: Output file extension (${outExt}) doesn't match any of the input extensions: ${fileExtensions.join(", ")}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (stripPrefix) {
|
|
57
|
+
const stripSt = await fs.stat(stripPrefix).catch(() => null);
|
|
58
|
+
if (!stripSt?.isDirectory()) {
|
|
59
|
+
relinka("error", `Error: --strip is not a valid directory: ${stripPrefix}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (verbose)
|
|
64
|
+
relinka(
|
|
65
|
+
"log",
|
|
66
|
+
`Scanning directory ${inputDir} for files with extensions: ${fileExtensions.join(", ")}`
|
|
67
|
+
);
|
|
68
|
+
const filePaths = await collectFiles(
|
|
69
|
+
inputDir,
|
|
70
|
+
fileExtensions,
|
|
71
|
+
isRecursive,
|
|
72
|
+
ignoreDirs,
|
|
73
|
+
verbose,
|
|
74
|
+
includeInternal,
|
|
75
|
+
internalMarker,
|
|
76
|
+
outFile
|
|
77
|
+
);
|
|
78
|
+
if (!filePaths.length) {
|
|
79
|
+
relinka(
|
|
80
|
+
"warn",
|
|
81
|
+
`No matching files found in ${inputDir} with extensions: ${fileExtensions.join(", ")}`
|
|
82
|
+
);
|
|
83
|
+
if (!overrideFile) {
|
|
84
|
+
relinka("warn", "No changes will be made to the output file.");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const usedIdentifiers = /* @__PURE__ */ new Set();
|
|
89
|
+
const aggregatorLinesArrays = await Promise.all(
|
|
90
|
+
filePaths.map(
|
|
91
|
+
(fp) => generateAggregatorLines(
|
|
92
|
+
fp,
|
|
93
|
+
inputDir,
|
|
94
|
+
stripPrefix,
|
|
95
|
+
useImport,
|
|
96
|
+
useNamed,
|
|
97
|
+
usedIdentifiers
|
|
98
|
+
).catch((error) => {
|
|
99
|
+
relinka("error", `Error processing file ${fp}: ${error}`);
|
|
100
|
+
return [];
|
|
101
|
+
})
|
|
102
|
+
)
|
|
103
|
+
);
|
|
104
|
+
const allLines = aggregatorLinesArrays.flat();
|
|
105
|
+
const typeLines = [];
|
|
106
|
+
const valueLines = [];
|
|
107
|
+
for (const line of allLines) {
|
|
108
|
+
if (line.includes("type {")) {
|
|
109
|
+
typeLines.push(line);
|
|
110
|
+
} else {
|
|
111
|
+
valueLines.push(line);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (sortLines) {
|
|
115
|
+
typeLines.sort();
|
|
116
|
+
valueLines.sort();
|
|
117
|
+
if (verbose) relinka("log", "Sorted aggregator lines alphabetically.");
|
|
118
|
+
}
|
|
119
|
+
const buildAggregatorBlock = (lines) => `${headerComment ? `${headerComment}
|
|
120
|
+
` : ""}${AGGREGATOR_START}
|
|
121
|
+
${lines.join("\n")}
|
|
122
|
+
${AGGREGATOR_END}
|
|
123
|
+
`;
|
|
124
|
+
if (separateTypesFile && typesOutFile) {
|
|
125
|
+
const typeBlock = buildAggregatorBlock(typeLines);
|
|
126
|
+
await fs.ensureFile(typesOutFile);
|
|
127
|
+
await fs.writeFile(typesOutFile, typeBlock, "utf8");
|
|
128
|
+
const valueBlock = buildAggregatorBlock([
|
|
129
|
+
...valueLines,
|
|
130
|
+
`export * from "${path.relative(path.dirname(outFile), typesOutFile).replace(/\\/g, "/")}";`
|
|
131
|
+
]);
|
|
132
|
+
await fs.ensureFile(outFile);
|
|
133
|
+
await fs.writeFile(outFile, valueBlock, "utf8");
|
|
134
|
+
relinka(
|
|
135
|
+
"success",
|
|
136
|
+
`Aggregator done: processed ${typeLines.length} type lines in: ${typesOutFile} and ${valueLines.length} value lines in: ${outFile}`
|
|
137
|
+
);
|
|
138
|
+
} else {
|
|
139
|
+
const aggregatorBlock = buildAggregatorBlock(allLines);
|
|
140
|
+
await fs.ensureFile(outFile);
|
|
141
|
+
await fs.writeFile(outFile, aggregatorBlock, "utf8");
|
|
142
|
+
relinka("success", `Aggregator done: processed ${allLines.length} lines in: ${outFile}`);
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
relinka("error", `Aggregator failed: ${error}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a relative import/export path, removing `stripPrefix` if it is truly a prefix,
|
|
3
|
+
* converting .ts -> .js, and ensuring it starts with "./" or "../".
|
|
4
|
+
*/
|
|
5
|
+
export declare function buildPathRelative(filePath: string, inputDir: string, stripPrefix: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Recursively collects files with given extensions, ignoring specified directories
|
|
8
|
+
* and files marked as internal.
|
|
9
|
+
*/
|
|
10
|
+
export declare function collectFiles(dir: string, exts: string[], recursive: boolean, ignoreDirs: string[], verbose: boolean, includeInternal: boolean, internalMarker: string, outFile?: string): Promise<string[]>;
|
|
11
|
+
/**
|
|
12
|
+
* Creates aggregator lines for a single file.
|
|
13
|
+
*
|
|
14
|
+
* If `useNamed` is true, parses named exports and produces up to two lines:
|
|
15
|
+
* - import type { ... } / export type { ... }
|
|
16
|
+
* - import { ... } / export { ... }
|
|
17
|
+
*
|
|
18
|
+
* If `useNamed` is false, produces a single star import or export.
|
|
19
|
+
*
|
|
20
|
+
* @param usedIdentifiers A set to track and ensure unique identifiers for star imports.
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateAggregatorLines(filePath: string, inputDir: string, stripPrefix: string, useImport: boolean, useNamed: boolean, usedIdentifiers?: Set<string>): Promise<string[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Parses a file to extract named exports, separating type exports from value exports.
|
|
25
|
+
* Deduplicates export names (to handle overloads).
|
|
26
|
+
*/
|
|
27
|
+
export declare function getNamedExports(filePath: string): Promise<{
|
|
28
|
+
typeNames: string[];
|
|
29
|
+
valueNames: string[];
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Generates a valid identifier for star imports based on the file name.
|
|
33
|
+
* For star imports, we generate an identifier from the filename, e.g.
|
|
34
|
+
* 'utils-cwd.ts' -> 'utils_cwd'
|
|
35
|
+
* so we do: import * as utils_cwd from "./utils-cwd";
|
|
36
|
+
*/
|
|
37
|
+
export declare function guessStarImportIdentifier(filePath: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Prints usage examples based on whether dev mode or not.
|
|
40
|
+
*/
|
|
41
|
+
export declare function printUsage(isDev?: boolean): void;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import path from "@reliverse/pathkit";
|
|
2
|
+
import fs from "@reliverse/relifso";
|
|
3
|
+
import { relinka } from "@reliverse/relinka";
|
|
4
|
+
export function buildPathRelative(filePath, inputDir, stripPrefix) {
|
|
5
|
+
let resolved = path.resolve(filePath);
|
|
6
|
+
const resolvedStrip = stripPrefix ? path.resolve(stripPrefix) : "";
|
|
7
|
+
if (resolvedStrip && resolved.startsWith(resolvedStrip)) {
|
|
8
|
+
resolved = resolved.slice(resolvedStrip.length);
|
|
9
|
+
} else {
|
|
10
|
+
resolved = path.relative(path.resolve(inputDir), resolved);
|
|
11
|
+
}
|
|
12
|
+
while (resolved.startsWith(path.sep)) {
|
|
13
|
+
resolved = resolved.slice(1);
|
|
14
|
+
}
|
|
15
|
+
resolved = resolved.replace(/\\/g, "/");
|
|
16
|
+
if (resolved.toLowerCase().endsWith(".ts")) {
|
|
17
|
+
resolved = `${resolved.slice(0, -3)}.js`;
|
|
18
|
+
}
|
|
19
|
+
if (!resolved.startsWith("./") && !resolved.startsWith("../")) {
|
|
20
|
+
resolved = `./${resolved}`;
|
|
21
|
+
}
|
|
22
|
+
resolved = resolved.replace(/\/+/g, "/");
|
|
23
|
+
return resolved;
|
|
24
|
+
}
|
|
25
|
+
export async function collectFiles(dir, exts, recursive, ignoreDirs, verbose, includeInternal, internalMarker, outFile) {
|
|
26
|
+
const found = [];
|
|
27
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
const fullPath = path.join(dir, entry.name);
|
|
30
|
+
if (outFile && path.resolve(fullPath) === path.resolve(outFile)) {
|
|
31
|
+
if (verbose) {
|
|
32
|
+
relinka("log", `Skipping output file: ${fullPath}`);
|
|
33
|
+
}
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
if (ignoreDirs.includes(entry.name)) {
|
|
38
|
+
if (verbose) {
|
|
39
|
+
relinka("log", `Skipping ignored directory: ${fullPath}`);
|
|
40
|
+
}
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (recursive) {
|
|
44
|
+
const sub = await collectFiles(
|
|
45
|
+
fullPath,
|
|
46
|
+
exts,
|
|
47
|
+
recursive,
|
|
48
|
+
ignoreDirs,
|
|
49
|
+
verbose,
|
|
50
|
+
includeInternal,
|
|
51
|
+
internalMarker,
|
|
52
|
+
outFile
|
|
53
|
+
);
|
|
54
|
+
found.push(...sub);
|
|
55
|
+
}
|
|
56
|
+
} else if (entry.isFile()) {
|
|
57
|
+
if (!includeInternal && path.basename(fullPath).startsWith(internalMarker)) {
|
|
58
|
+
if (verbose) {
|
|
59
|
+
relinka("log", `Skipping internal file: ${fullPath}`);
|
|
60
|
+
}
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (exts.some((ext) => entry.name.toLowerCase().endsWith(ext))) {
|
|
64
|
+
if (verbose) {
|
|
65
|
+
relinka("log", `Found file: ${fullPath}`);
|
|
66
|
+
}
|
|
67
|
+
found.push(fullPath);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return found;
|
|
72
|
+
}
|
|
73
|
+
export async function generateAggregatorLines(filePath, inputDir, stripPrefix, useImport, useNamed, usedIdentifiers) {
|
|
74
|
+
const importPath = buildPathRelative(filePath, inputDir, stripPrefix);
|
|
75
|
+
if (!useNamed) {
|
|
76
|
+
if (useImport) {
|
|
77
|
+
let ident = guessStarImportIdentifier(filePath);
|
|
78
|
+
if (usedIdentifiers) {
|
|
79
|
+
let uniqueIdent = ident;
|
|
80
|
+
let counter = 1;
|
|
81
|
+
while (usedIdentifiers.has(uniqueIdent)) {
|
|
82
|
+
uniqueIdent = `${ident}_${counter}`;
|
|
83
|
+
counter++;
|
|
84
|
+
}
|
|
85
|
+
usedIdentifiers.add(uniqueIdent);
|
|
86
|
+
ident = uniqueIdent;
|
|
87
|
+
}
|
|
88
|
+
return [`import * as ${ident} from "${importPath}";`];
|
|
89
|
+
}
|
|
90
|
+
return [`export * from "${importPath}";`];
|
|
91
|
+
}
|
|
92
|
+
const { typeNames, valueNames } = await getNamedExports(filePath);
|
|
93
|
+
if (!typeNames.length && !valueNames.length) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
if (useImport) {
|
|
97
|
+
const lines2 = [];
|
|
98
|
+
if (typeNames.length > 0) {
|
|
99
|
+
lines2.push(`import type { ${typeNames.join(", ")} } from "${importPath}";`);
|
|
100
|
+
}
|
|
101
|
+
if (valueNames.length > 0) {
|
|
102
|
+
lines2.push(`import { ${valueNames.join(", ")} } from "${importPath}";`);
|
|
103
|
+
}
|
|
104
|
+
return lines2;
|
|
105
|
+
}
|
|
106
|
+
const lines = [];
|
|
107
|
+
if (typeNames.length > 0) {
|
|
108
|
+
lines.push(`export type { ${typeNames.join(", ")} } from "${importPath}";`);
|
|
109
|
+
}
|
|
110
|
+
if (valueNames.length > 0) {
|
|
111
|
+
lines.push(`export { ${valueNames.join(", ")} } from "${importPath}";`);
|
|
112
|
+
}
|
|
113
|
+
return lines;
|
|
114
|
+
}
|
|
115
|
+
export async function getNamedExports(filePath) {
|
|
116
|
+
try {
|
|
117
|
+
const code = await fs.readFile(filePath, "utf8");
|
|
118
|
+
const typeNamesSet = /* @__PURE__ */ new Set();
|
|
119
|
+
const valueNamesSet = /* @__PURE__ */ new Set();
|
|
120
|
+
const patterns = [
|
|
121
|
+
// Regular exports and default exports
|
|
122
|
+
/^export\s+(?:default\s+)?(?:async\s+)?(function|const|class|let|var|type|interface|enum)\s+([A-Za-z0-9_$]+)/gm,
|
|
123
|
+
// Named exports and re-exports
|
|
124
|
+
/^export\s*{([^}]+)}(?:\s+from\s+['"][^'"]+['"])?/gm,
|
|
125
|
+
// Export assignments
|
|
126
|
+
/^export\s*=\s*([A-Za-z0-9_$]+)/gm
|
|
127
|
+
];
|
|
128
|
+
for (const pattern of patterns) {
|
|
129
|
+
let match;
|
|
130
|
+
while (true) {
|
|
131
|
+
match = pattern.exec(code);
|
|
132
|
+
if (!match) break;
|
|
133
|
+
const matchGroups = match;
|
|
134
|
+
if (pattern.source.includes("{([^}]+)}") && matchGroups[1]) {
|
|
135
|
+
const exports = (matchGroups[1] ?? "").split(",").map(
|
|
136
|
+
(e) => e?.trim()?.split(/\s+as\s+/)?.[0]?.trim() ?? ""
|
|
137
|
+
);
|
|
138
|
+
for (const exp of exports) {
|
|
139
|
+
const name = exp.replace(/^type\s+/, "");
|
|
140
|
+
if (exp.startsWith("type ")) {
|
|
141
|
+
typeNamesSet.add(name);
|
|
142
|
+
} else {
|
|
143
|
+
valueNamesSet.add(name);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} else if (pattern.source.includes("=\\s*([A-Za-z0-9_$]+)") && matchGroups[1]) {
|
|
147
|
+
valueNamesSet.add(matchGroups[1]);
|
|
148
|
+
} else {
|
|
149
|
+
const keyword = matchGroups[1];
|
|
150
|
+
const name = matchGroups[2];
|
|
151
|
+
if (keyword && name) {
|
|
152
|
+
if (keyword === "type" || keyword === "interface" || keyword === "enum") {
|
|
153
|
+
typeNamesSet.add(name);
|
|
154
|
+
} else {
|
|
155
|
+
valueNamesSet.add(name);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
typeNames: Array.from(typeNamesSet),
|
|
163
|
+
valueNames: Array.from(valueNamesSet)
|
|
164
|
+
};
|
|
165
|
+
} catch (error) {
|
|
166
|
+
relinka("error", `Error reading file ${filePath}: ${error}`);
|
|
167
|
+
return { typeNames: [], valueNames: [] };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
export function guessStarImportIdentifier(filePath) {
|
|
171
|
+
const base = path.basename(filePath, path.extname(filePath));
|
|
172
|
+
let identifier = base.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
173
|
+
if (/^\d/.test(identifier)) {
|
|
174
|
+
identifier = `_${identifier}`;
|
|
175
|
+
}
|
|
176
|
+
return identifier || "file";
|
|
177
|
+
}
|
|
178
|
+
export function printUsage(isDev) {
|
|
179
|
+
relinka("log", "====================");
|
|
180
|
+
relinka("log", "TOOLS USAGE EXAMPLES");
|
|
181
|
+
relinka("log", "====================");
|
|
182
|
+
relinka(
|
|
183
|
+
"log",
|
|
184
|
+
`${isDev ? "bun dev:agg" : "dler tools"} --tool agg --input <dir> --out <file> [options]`
|
|
185
|
+
);
|
|
186
|
+
if (isDev) {
|
|
187
|
+
relinka(
|
|
188
|
+
"log",
|
|
189
|
+
"bun dev:tools agg --input src/libs/sdk/sdk-impl --out src/libs/sdk/sdk-mod.ts --recursive --named --strip src/libs/sdk"
|
|
190
|
+
);
|
|
191
|
+
} else {
|
|
192
|
+
relinka(
|
|
193
|
+
"log",
|
|
194
|
+
"dler tools --tool agg --input src/libs --out aggregator.ts --recursive --named"
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a file exists at the given path
|
|
3
|
+
*/
|
|
4
|
+
export declare function fileExists(filePath: string): Promise<boolean>;
|
|
5
|
+
/**
|
|
6
|
+
* Finds the main package based on dler configuration with fallbacks
|
|
7
|
+
*/
|
|
8
|
+
export declare function findMainEntryFile(config: any): Promise<string | null>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import path from "@reliverse/pathkit";
|
|
2
|
+
import fs from "@reliverse/relifso";
|
|
3
|
+
export async function fileExists(filePath) {
|
|
4
|
+
return await fs.pathExists(filePath);
|
|
5
|
+
}
|
|
6
|
+
export async function findMainEntryFile(config) {
|
|
7
|
+
const { coreEntryFile, coreEntrySrcDir } = config;
|
|
8
|
+
if (coreEntryFile && coreEntrySrcDir) {
|
|
9
|
+
const configuredPath = path.join(coreEntrySrcDir, coreEntryFile);
|
|
10
|
+
if (await fileExists(configuredPath)) {
|
|
11
|
+
return configuredPath;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const fallbackPatterns = [
|
|
15
|
+
path.join(coreEntrySrcDir || "src", "mod.ts"),
|
|
16
|
+
path.join(coreEntrySrcDir || "src", "index.ts"),
|
|
17
|
+
path.join(coreEntrySrcDir || "src", "mod.js"),
|
|
18
|
+
path.join(coreEntrySrcDir || "src", "index.js")
|
|
19
|
+
];
|
|
20
|
+
for (const pattern of fallbackPatterns) {
|
|
21
|
+
if (await fileExists(pattern)) {
|
|
22
|
+
return pattern;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fs from "@reliverse/relifso";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if the first line of a file contains the disable aggregation comment
|
|
5
|
+
*/
|
|
6
|
+
// @ts-expect-error TODO: SOMETHING STRANGE WITH THIS FUNCTION
|
|
7
|
+
// FOR SOME REASON MKDIST DON'T WANT TO REMOVE TS ANNOTATIONS
|
|
8
|
+
// FROM THIS AND ALL FUNCTIONS WHICH LIVE IN THE SAME FILE
|
|
9
|
+
export async function isAggregationDisabled(filePath) {
|
|
10
|
+
try {
|
|
11
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
12
|
+
const firstLine = content.split("\n")[0]?.trim();
|
|
13
|
+
return firstLine === "// <dler-disable-agg>";
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|