@reliverse/dler 1.2.0 → 1.2.2
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 +43 -20
- package/bin/cli/args/init/cmd/index.js +66 -0
- package/bin/cli/args/init/{main.txt → init-mod.txt} +1 -1
- package/bin/cli/args/init/libs/reinit/reint-impl/{mod.txt → reinit-mod.txt} +5 -5
- package/bin/cli/args/init/libs/reinit/reint-impl/templates/t-license.js +1 -1
- package/bin/cli/args/inject/ts-expect-error.txt +3 -3
- package/bin/cli/args/{spells/mod.js → spell/spell-mod.js} +1 -1
- package/bin/cli/args/split/split-impl.js +117 -0
- package/bin/cli/args/split/split-mod.js +22 -113
- package/bin/cli/args/tools/index.js +1 -1
- package/bin/cli/args/tools/tools-impl.js +16 -16
- package/bin/cli.js +3 -2
- package/bin/init.js +8 -8
- package/bin/libs/cfg/cfg-default.js +1 -1
- package/bin/libs/sdk/sdk-impl/build/build-library.js +11 -11
- package/bin/libs/sdk/sdk-impl/build/build-regular.js +24 -14
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/auto.js +1 -1
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/build.js +4 -7
- package/bin/libs/sdk/sdk-impl/build/bundlers/unified/rollup/watch.js +3 -3
- package/bin/libs/sdk/sdk-impl/library-flow.js +1 -1
- package/bin/libs/sdk/sdk-impl/pub/pub-library.js +9 -9
- package/bin/libs/sdk/sdk-impl/pub/pub-regular.js +4 -4
- package/bin/libs/sdk/sdk-impl/regular-flow.js +17 -11
- package/bin/libs/sdk/sdk-impl/{spells/spells-executors.js → spell/spell-executors.js} +1 -1
- package/bin/libs/sdk/sdk-impl/{spells/spells-main.js → spell/spell-mod.js} +3 -3
- package/bin/libs/sdk/sdk-impl/utils/tools/tools-impl.js +7 -7
- package/bin/libs/sdk/sdk-impl/utils/utils-build.js +3 -3
- package/bin/libs/sdk/sdk-impl/utils/utils-bump.js +4 -4
- package/bin/libs/sdk/sdk-impl/utils/utils-fs.js +2 -5
- package/bin/libs/sdk/sdk-impl/utils/utils-info.js +4 -4
- package/bin/libs/sdk/sdk-impl/utils/utils-jsr-json.js +4 -2
- package/bin/libs/sdk/sdk-impl/utils/utils-paths.js +6 -6
- package/bin/libs/sdk/sdk-impl/utils/utils-pkg-json-libs.js +8 -8
- package/bin/libs/sdk/sdk-impl/utils/utils-pkg-json-reg.js +16 -13
- package/bin/load.js +1 -1
- package/bin/tools.txt +1 -1
- package/package.json +12 -12
- package/bin/cli/args/split/split-main.js +0 -26
- package/bin/libs/cfg/cfg-main.js +0 -1
- /package/bin/cli/args/agg/{main.js → agg-mod.js} +0 -0
- /package/bin/cli/args/conv/{main.js → conv-mod.js} +0 -0
- /package/bin/cli/args/deps/{mod.js → deps-mod.js} +0 -0
- /package/bin/cli/args/init/libs/reinit/{reinit-main.js → reinit-mod.js} +0 -0
- /package/bin/cli/args/inject/{cli-mod.js → inject-mod.js} +0 -0
- /package/bin/cli/args/inject/{main.txt → inject-mod.txt} +0 -0
- /package/bin/cli/args/merger/{main.txt → merger-mod.txt} +0 -0
- /package/bin/cli/args/mono/{main.js → mono-mod.js} +0 -0
- /package/bin/libs/sdk/sdk-impl/{spells/spells-filesystem.js → spell/spell-filesystem.js} +0 -0
- /package/bin/libs/sdk/sdk-impl/{spells/spells-parser.js → spell/spell-parser.js} +0 -0
- /package/bin/libs/sdk/sdk-impl/{spells/spells-types.js → spell/spell-types.js} +0 -0
- /package/bin/libs/sdk/{sdk-main.js → sdk-mod.js} +0 -0
- /package/bin/{main.js → mod.js} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# dler (prev. relidler) • reliverse bundler
|
|
2
2
|
|
|
3
|
-
[💖 github sponsors](https://github.com/sponsors/blefnk) — [💬 discord](https://discord.gg/pb8ukbwpsj) — [✨ repo](https://github.com/reliverse/dler
|
|
3
|
+
[💖 github sponsors](https://github.com/sponsors/blefnk) — [💬 discord](https://discord.gg/pb8ukbwpsj) — [✨ repo](https://github.com/reliverse/dler) — [📦 npm](https://npmjs.com/@reliverse/dler) — [📚 docs](https://docs.reliverse.org/reliverse/dler)
|
|
4
4
|
|
|
5
5
|
> @reliverse/dler (`/ˈdiː.lər/`, dealer) is a flexible, unified, and fully automated bundler for typescript and javascript projects, as well as an npm and jsr publishing tool.
|
|
6
6
|
|
|
@@ -51,20 +51,26 @@ ensure git, node.js, and bun/pnpm/yarn/npm are installed. then:
|
|
|
51
51
|
git clone https://github.com/reliverse/dler.git
|
|
52
52
|
cd dler
|
|
53
53
|
bun i
|
|
54
|
-
bun dev # bun src/
|
|
54
|
+
bun dev # bun src/mod.ts --dev
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
### installation
|
|
58
58
|
|
|
59
|
-
1. **install
|
|
59
|
+
1. **install**:
|
|
60
|
+
|
|
61
|
+
**install as dev dep (recommended)**:
|
|
60
62
|
|
|
61
63
|
```sh
|
|
62
|
-
bun
|
|
64
|
+
bun add -D @reliverse/dler
|
|
65
|
+
# or update as needed:
|
|
66
|
+
bun update --latest
|
|
63
67
|
```
|
|
64
68
|
|
|
65
|
-
**or
|
|
69
|
+
**or install globally**:
|
|
66
70
|
|
|
67
71
|
```sh
|
|
72
|
+
bun i -g @reliverse/dler
|
|
73
|
+
# or update as needed:
|
|
68
74
|
bun -g update --latest
|
|
69
75
|
```
|
|
70
76
|
|
|
@@ -83,20 +89,37 @@ bun dev # bun src/main.ts --dev
|
|
|
83
89
|
bun add -d @reliverse/dler-cfg
|
|
84
90
|
```
|
|
85
91
|
|
|
86
|
-
c. **
|
|
92
|
+
c. **add `".config/**/*.ts"` to `include` in `tsconfig.json`**:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
"include": [".config/**/*.ts", ...]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
d. **package.json**:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
"scripts": {
|
|
102
|
+
"build": "dler build", // this is optional
|
|
103
|
+
"pub": "dler pub" // this does build+publish
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
e. **initialize config**:
|
|
87
108
|
|
|
88
109
|
```sh
|
|
89
|
-
|
|
110
|
+
bun [build|pub] # if installed as dev dep
|
|
111
|
+
dler [build|pub] # if installed globally
|
|
90
112
|
```
|
|
91
113
|
|
|
92
114
|
- the `.config/dler.ts` file is automatically created on first run.
|
|
93
115
|
- **it's recommended to customize this file according to your needs.**
|
|
94
|
-
- you can check an example config here: [.config/dler.ts](https://github.com/reliverse/dler
|
|
116
|
+
- you can check an example config here: [.config/dler.ts](https://github.com/reliverse/dler/blob/main/.config/dler.ts)
|
|
95
117
|
|
|
96
118
|
3. **run and enjoy**:
|
|
97
119
|
|
|
98
120
|
```sh
|
|
99
|
-
|
|
121
|
+
bun [build|pub] # if installed as dev dep
|
|
122
|
+
dler [build|pub] # if installed globally
|
|
100
123
|
```
|
|
101
124
|
|
|
102
125
|
absolutely! here’s your improved section, now listing all available spell types:
|
|
@@ -149,17 +172,17 @@ more params coming soon...
|
|
|
149
172
|
|
|
150
173
|
from dler’s cli:
|
|
151
174
|
|
|
152
|
-
- `dler
|
|
153
|
-
- `dler
|
|
154
|
-
- `dler
|
|
175
|
+
- `dler spell --trigger rename-file,... --files tsconfig.json,...`
|
|
176
|
+
- `dler spell --trigger all`
|
|
177
|
+
- `dler spell`
|
|
155
178
|
|
|
156
179
|
from your own code:
|
|
157
180
|
|
|
158
181
|
```ts
|
|
159
|
-
await dler.
|
|
160
|
-
// await dler.
|
|
161
|
-
//
|
|
162
|
-
//
|
|
182
|
+
await dler.spell({ spells: ["rename-file"], files: [] });
|
|
183
|
+
// await dler.spell({}) // means all spells and all files
|
|
184
|
+
// spell: ["all"] // means all spells
|
|
185
|
+
// spell: [] // means all spells
|
|
163
186
|
// files: [] // means all files
|
|
164
187
|
```
|
|
165
188
|
|
|
@@ -221,7 +244,7 @@ deep imports like `dep/some/file` or `@org/dep/some/thing` are always resolved t
|
|
|
221
244
|
builds and publishes specific subdirectories of your main project as standalone packages.
|
|
222
245
|
|
|
223
246
|
**usage example**:
|
|
224
|
-
using `@reliverse/dler-cfg` to package [src/libs/cfg](https://github.com/reliverse/dler
|
|
247
|
+
using `@reliverse/dler-cfg` to package [src/libs/cfg](https://github.com/reliverse/dler/tree/main/src/libs/cfg):
|
|
225
248
|
|
|
226
249
|
```ts
|
|
227
250
|
// .config/dler.ts
|
|
@@ -233,7 +256,7 @@ libslist: {
|
|
|
233
256
|
libdeclarations: true,
|
|
234
257
|
libdescription: "@reliverse/dler defineconfig",
|
|
235
258
|
libdirname: "cfg",
|
|
236
|
-
libmainfile: "cfg/cfg-
|
|
259
|
+
libmainfile: "cfg/cfg-mod.ts",
|
|
237
260
|
libpkgkeepdeps: false,
|
|
238
261
|
libtranspileminify: true,
|
|
239
262
|
},
|
|
@@ -268,12 +291,12 @@ dler tools --tool <tool> --input <dir> --out <file> [options]
|
|
|
268
291
|
|
|
269
292
|
**usage example**: if you're exploring the example [playground](#playground), you can try the following:
|
|
270
293
|
|
|
271
|
-
1. open [src/libs/sdk/sdk-
|
|
294
|
+
1. open [src/libs/sdk/sdk-mod.ts](https://github.com/reliverse/dler/blob/main/src/libs/sdk/sdk-mod.ts) in your ide.
|
|
272
295
|
2. press `ctrl+a`, then `backspace`. run the command below and watch the magic happen:
|
|
273
296
|
|
|
274
297
|
```bash
|
|
275
298
|
bun tools:agg # shortcut for:
|
|
276
|
-
bun src/
|
|
299
|
+
bun src/mod.ts tools --dev --tool agg --input src/libs/sdk/sdk-impl --out src/libs/sdk/sdk-mod.ts --recursive --named --strip src/libs/sdk
|
|
277
300
|
```
|
|
278
301
|
|
|
279
302
|
## api (for advanced users)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { relinka } from "@reliverse/relinka";
|
|
2
|
+
import { defineCommand } from "@reliverse/rempts";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import path from "pathe";
|
|
5
|
+
export default defineCommand({
|
|
6
|
+
meta: {
|
|
7
|
+
name: "init",
|
|
8
|
+
version: "1.0.0",
|
|
9
|
+
description: "Scaffold new CLI commands quickly."
|
|
10
|
+
},
|
|
11
|
+
args: {
|
|
12
|
+
cmd: {
|
|
13
|
+
type: "array",
|
|
14
|
+
required: true,
|
|
15
|
+
description: "Names of commands to initialize"
|
|
16
|
+
},
|
|
17
|
+
force: {
|
|
18
|
+
type: "boolean",
|
|
19
|
+
default: false,
|
|
20
|
+
description: "Overwrite existing commands"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
async run({ args }) {
|
|
24
|
+
const root = path.resolve("src/cli/args");
|
|
25
|
+
for (const cmdName of args.cmd) {
|
|
26
|
+
const dirPath = path.join(root, cmdName);
|
|
27
|
+
const filePath = path.join(dirPath, "index.ts");
|
|
28
|
+
if (await fs.pathExists(filePath) && !args.force) {
|
|
29
|
+
relinka(
|
|
30
|
+
"warn",
|
|
31
|
+
`\u274C Command "${cmdName}" already exists. Use --force to overwrite.`
|
|
32
|
+
);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
36
|
+
const content = generateCommandTemplate(cmdName);
|
|
37
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
38
|
+
relinka("log", `\u2705 Created new command: ${filePath}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
function generateCommandTemplate(cmdName) {
|
|
43
|
+
return `import { relinka } from "@reliverse/relinka";
|
|
44
|
+
|
|
45
|
+
import { defineCommand } from "@reliverse/rempts";
|
|
46
|
+
|
|
47
|
+
export default defineCommand({
|
|
48
|
+
meta: {
|
|
49
|
+
name: "${cmdName}",
|
|
50
|
+
version: "1.0.0",
|
|
51
|
+
description: "Describe what ${cmdName} command does.",
|
|
52
|
+
},
|
|
53
|
+
args: {
|
|
54
|
+
exampleArg: {
|
|
55
|
+
type: "string",
|
|
56
|
+
default: "defaultValue",
|
|
57
|
+
description: "An example argument",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
async run({ args }) {
|
|
61
|
+
relinka("log", "Command '${cmdName}' executed.");
|
|
62
|
+
relinka("log", "Received args:", args);
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
`;
|
|
66
|
+
}
|
|
@@ -197,7 +197,7 @@ async function doInitFile(
|
|
|
197
197
|
}
|
|
198
198
|
if (maybeNewDest !== resolvedDestPath) {
|
|
199
199
|
// e.g., attach-index was chosen
|
|
200
|
-
relinka("
|
|
200
|
+
relinka("log", `attach-index or rename => ${maybeNewDest}`);
|
|
201
201
|
return await finalizeInit(
|
|
202
202
|
req,
|
|
203
203
|
initBehaviour,
|
|
@@ -268,7 +268,7 @@ async function runCopy(
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
relinka(
|
|
271
|
-
"
|
|
271
|
+
"log",
|
|
272
272
|
`Attempting copy:
|
|
273
273
|
- Source Dir: ${resolvedSrcDir}
|
|
274
274
|
- Source Path: ${sourcePath}
|
|
@@ -283,7 +283,7 @@ async function runCopy(
|
|
|
283
283
|
throw new Error(`Source file not found: ${sourcePath}`);
|
|
284
284
|
}
|
|
285
285
|
await fs.copy(sourcePath, resolvedDestPath, { overwrite: true });
|
|
286
|
-
relinka("
|
|
286
|
+
relinka("log", `Copied file: ${chosenVariation} -> ${resolvedDestPath}`);
|
|
287
287
|
return {
|
|
288
288
|
requested: req,
|
|
289
289
|
finalPath: resolvedDestPath,
|
|
@@ -305,7 +305,7 @@ async function runCopy(
|
|
|
305
305
|
}
|
|
306
306
|
await fs.copy(fallbackFullPath, resolvedDestPath, { overwrite: true });
|
|
307
307
|
relinka(
|
|
308
|
-
"
|
|
308
|
+
"log",
|
|
309
309
|
`Fallback copy: ${fallbackSource} -> ${resolvedDestPath}`,
|
|
310
310
|
);
|
|
311
311
|
return {
|
|
@@ -390,6 +390,6 @@ async function attachIndex(originalPath: string) {
|
|
|
390
390
|
newPath = path.join(dir, `${base}.${counter}${ext}`);
|
|
391
391
|
counter++;
|
|
392
392
|
}
|
|
393
|
-
relinka("
|
|
393
|
+
relinka("log", `Attaching index => ${newPath}`);
|
|
394
394
|
return newPath;
|
|
395
395
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const licenseTemplate = `# MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) Nazar Kornienko (blefnk), Reliverse
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -129,7 +129,7 @@ async function runTscAndParseErrors(
|
|
|
129
129
|
// In case of error, try to extract the output.
|
|
130
130
|
const combined = (error.all as string) || "";
|
|
131
131
|
if (!combined) {
|
|
132
|
-
relinka("
|
|
132
|
+
relinka("log", `TSC returned no error lines. Possibly no TS errors?`);
|
|
133
133
|
return [];
|
|
134
134
|
}
|
|
135
135
|
|
|
@@ -191,7 +191,7 @@ async function injectCommentIntoFiles(
|
|
|
191
191
|
lineNums.sort((a, b) => b - a);
|
|
192
192
|
const absPath = path.resolve(filePath);
|
|
193
193
|
relinka(
|
|
194
|
-
"
|
|
194
|
+
"log",
|
|
195
195
|
`Injecting into ${absPath} at lines: ${lineNums.join(", ")}`,
|
|
196
196
|
);
|
|
197
197
|
|
|
@@ -235,7 +235,7 @@ export async function useTsExpectError(args: {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
if (usedAuto) {
|
|
238
|
-
relinka("
|
|
238
|
+
relinka("log", "Running TSC to discover error lines...");
|
|
239
239
|
const tscCommand = userConfig.tscCommand!;
|
|
240
240
|
try {
|
|
241
241
|
const discovered = await runTscAndParseErrors(tscCommand, args.tscPaths);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import { spells } from "../../../libs/sdk/sdk-impl/
|
|
2
|
+
import { spells } from "../../../libs/sdk/sdk-impl/spell/spell-mod.js";
|
|
3
3
|
export const createCli = () => {
|
|
4
4
|
const program = new Command();
|
|
5
5
|
program.name("dler-spells").description("Execute magic spells in your codebase").version("1.0.0");
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "pathe";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
export function parseCommandLineArgs() {
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
let directory = ".";
|
|
7
|
+
let fileLineThreshold = 300;
|
|
8
|
+
let funcLineThreshold = 50;
|
|
9
|
+
for (let i = 0; i < args.length; i++) {
|
|
10
|
+
const arg = args[i];
|
|
11
|
+
if (arg === "--dir" && args[i + 1]) {
|
|
12
|
+
directory = args[i + 1] ?? ".";
|
|
13
|
+
i++;
|
|
14
|
+
} else if (arg === "--file-threshold" && args[i + 1]) {
|
|
15
|
+
fileLineThreshold = Number(args[i + 1]);
|
|
16
|
+
i++;
|
|
17
|
+
} else if (arg === "--func-threshold" && args[i + 1]) {
|
|
18
|
+
funcLineThreshold = Number(args[i + 1]);
|
|
19
|
+
i++;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return { directory, fileLineThreshold, funcLineThreshold };
|
|
23
|
+
}
|
|
24
|
+
export function getAllSourceFiles(dir) {
|
|
25
|
+
const results = [];
|
|
26
|
+
function searchDirectory(directory) {
|
|
27
|
+
const files = fs.readdirSync(directory);
|
|
28
|
+
for (const file of files) {
|
|
29
|
+
const fullPath = path.join(directory, file);
|
|
30
|
+
if (fs.statSync(fullPath).isDirectory()) {
|
|
31
|
+
searchDirectory(fullPath);
|
|
32
|
+
} else if (/\.(ts|js)$/.test(file)) {
|
|
33
|
+
results.push(fullPath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
searchDirectory(dir);
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
export function splitLargeFileByLines(filePath, threshold) {
|
|
41
|
+
const originalContent = fs.readFileSync(filePath, "utf8");
|
|
42
|
+
const lines = originalContent.split("\n");
|
|
43
|
+
if (lines.length <= threshold) {
|
|
44
|
+
return [filePath];
|
|
45
|
+
}
|
|
46
|
+
console.log(`File "${filePath}" exceeds ${threshold} lines. Splitting...`);
|
|
47
|
+
const baseName = path.basename(filePath, path.extname(filePath));
|
|
48
|
+
const ext = path.extname(filePath);
|
|
49
|
+
const dirName = path.dirname(filePath);
|
|
50
|
+
const newFilePaths = [];
|
|
51
|
+
let chunkIndex = 0;
|
|
52
|
+
let i = 0;
|
|
53
|
+
while (i < lines.length) {
|
|
54
|
+
chunkIndex++;
|
|
55
|
+
const chunkLines = lines.slice(i, i + threshold);
|
|
56
|
+
const newFileName = `${baseName}.part${chunkIndex}${ext}`;
|
|
57
|
+
const newFileFullPath = path.join(dirName, newFileName);
|
|
58
|
+
fs.writeFileSync(newFileFullPath, chunkLines.join("\n"), "utf8");
|
|
59
|
+
newFilePaths.push(newFileFullPath);
|
|
60
|
+
i += threshold;
|
|
61
|
+
}
|
|
62
|
+
return newFilePaths;
|
|
63
|
+
}
|
|
64
|
+
export function splitLargeFunctions(filePath, funcLineThreshold) {
|
|
65
|
+
const sourceCode = fs.readFileSync(filePath, "utf8");
|
|
66
|
+
const sourceFile = ts.createSourceFile(
|
|
67
|
+
filePath,
|
|
68
|
+
sourceCode,
|
|
69
|
+
ts.ScriptTarget.ESNext,
|
|
70
|
+
true
|
|
71
|
+
);
|
|
72
|
+
let newSource = sourceCode;
|
|
73
|
+
const getLineOfPosition = (pos) => {
|
|
74
|
+
return sourceFile.getLineAndCharacterOfPosition(pos).line;
|
|
75
|
+
};
|
|
76
|
+
const largeFunctions = [];
|
|
77
|
+
function visit(node) {
|
|
78
|
+
if (ts.isFunctionDeclaration(node) && node.body) {
|
|
79
|
+
const startLine = getLineOfPosition(node.body.pos);
|
|
80
|
+
const endLine = getLineOfPosition(node.body.end);
|
|
81
|
+
const lineCount = endLine - startLine;
|
|
82
|
+
if (lineCount > funcLineThreshold) {
|
|
83
|
+
const name = node.name?.text || "<anonymous>";
|
|
84
|
+
largeFunctions.push({
|
|
85
|
+
name,
|
|
86
|
+
startPos: node.body.pos,
|
|
87
|
+
endPos: node.body.end,
|
|
88
|
+
lineCount
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
ts.forEachChild(node, visit);
|
|
93
|
+
}
|
|
94
|
+
visit(sourceFile);
|
|
95
|
+
if (largeFunctions.length === 0) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
console.log(
|
|
99
|
+
`File "${filePath}" has ${largeFunctions.length} function(s) above ${funcLineThreshold} lines. Attempting to split...`
|
|
100
|
+
);
|
|
101
|
+
largeFunctions.sort((a, b) => b.startPos - a.startPos).forEach((fn) => {
|
|
102
|
+
const bodyText = sourceCode.slice(fn.startPos, fn.endPos);
|
|
103
|
+
const midIndex = Math.floor(bodyText.length / 2);
|
|
104
|
+
const helperFunctionName = `${fn.name}HelperAutoGen`;
|
|
105
|
+
const replacementText = `{
|
|
106
|
+
// Original function was split automatically
|
|
107
|
+
${bodyText.slice(0, midIndex)}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function ${helperFunctionName}() {
|
|
111
|
+
// auto-generated second half
|
|
112
|
+
${bodyText.slice(midIndex)}
|
|
113
|
+
`;
|
|
114
|
+
newSource = newSource.slice(0, fn.startPos) + replacementText + newSource.slice(fn.endPos);
|
|
115
|
+
});
|
|
116
|
+
fs.writeFileSync(filePath, newSource, "utf8");
|
|
117
|
+
}
|
|
@@ -1,117 +1,26 @@
|
|
|
1
1
|
import fs from "fs-extra";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
import {
|
|
3
|
+
getAllSourceFiles,
|
|
4
|
+
parseCommandLineArgs,
|
|
5
|
+
splitLargeFileByLines,
|
|
6
|
+
splitLargeFunctions
|
|
7
|
+
} from "./split-impl.js";
|
|
8
|
+
async function main() {
|
|
9
|
+
const { directory, fileLineThreshold, funcLineThreshold } = parseCommandLineArgs();
|
|
10
|
+
const allFiles = getAllSourceFiles(directory);
|
|
11
|
+
for (const filePath of allFiles) {
|
|
12
|
+
const lineCount = fs.readFileSync(filePath, "utf8").split("\n").length;
|
|
13
|
+
if (lineCount > fileLineThreshold) {
|
|
14
|
+
const newSplits = splitLargeFileByLines(filePath, fileLineThreshold);
|
|
15
|
+
newSplits.forEach((splitFilePath) => {
|
|
16
|
+
splitLargeFunctions(splitFilePath, funcLineThreshold);
|
|
17
|
+
});
|
|
18
|
+
} else {
|
|
19
|
+
splitLargeFunctions(filePath, funcLineThreshold);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
return { directory, fileLineThreshold, funcLineThreshold };
|
|
23
|
-
}
|
|
24
|
-
export function getAllSourceFiles(dir) {
|
|
25
|
-
const results = [];
|
|
26
|
-
function searchDirectory(directory) {
|
|
27
|
-
const files = fs.readdirSync(directory);
|
|
28
|
-
for (const file of files) {
|
|
29
|
-
const fullPath = path.join(directory, file);
|
|
30
|
-
if (fs.statSync(fullPath).isDirectory()) {
|
|
31
|
-
searchDirectory(fullPath);
|
|
32
|
-
} else if (/\.(ts|js)$/.test(file)) {
|
|
33
|
-
results.push(fullPath);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
searchDirectory(dir);
|
|
38
|
-
return results;
|
|
39
|
-
}
|
|
40
|
-
export function splitLargeFileByLines(filePath, threshold) {
|
|
41
|
-
const originalContent = fs.readFileSync(filePath, "utf8");
|
|
42
|
-
const lines = originalContent.split("\n");
|
|
43
|
-
if (lines.length <= threshold) {
|
|
44
|
-
return [filePath];
|
|
45
|
-
}
|
|
46
|
-
console.log(`File "${filePath}" exceeds ${threshold} lines. Splitting...`);
|
|
47
|
-
const baseName = path.basename(filePath, path.extname(filePath));
|
|
48
|
-
const ext = path.extname(filePath);
|
|
49
|
-
const dirName = path.dirname(filePath);
|
|
50
|
-
const newFilePaths = [];
|
|
51
|
-
let chunkIndex = 0;
|
|
52
|
-
let i = 0;
|
|
53
|
-
while (i < lines.length) {
|
|
54
|
-
chunkIndex++;
|
|
55
|
-
const chunkLines = lines.slice(i, i + threshold);
|
|
56
|
-
const newFileName = `${baseName}.part${chunkIndex}${ext}`;
|
|
57
|
-
const newFileFullPath = path.join(dirName, newFileName);
|
|
58
|
-
fs.writeFileSync(newFileFullPath, chunkLines.join("\n"), "utf8");
|
|
59
|
-
newFilePaths.push(newFileFullPath);
|
|
60
|
-
i += threshold;
|
|
61
|
-
}
|
|
62
|
-
return newFilePaths;
|
|
63
|
-
}
|
|
64
|
-
export function splitLargeFunctions(filePath, funcLineThreshold) {
|
|
65
|
-
const sourceCode = fs.readFileSync(filePath, "utf8");
|
|
66
|
-
const sourceFile = ts.createSourceFile(
|
|
67
|
-
filePath,
|
|
68
|
-
sourceCode,
|
|
69
|
-
ts.ScriptTarget.ESNext,
|
|
70
|
-
true
|
|
71
|
-
);
|
|
72
|
-
let newSource = sourceCode;
|
|
73
|
-
const getLineOfPosition = (pos) => {
|
|
74
|
-
return sourceFile.getLineAndCharacterOfPosition(pos).line;
|
|
75
|
-
};
|
|
76
|
-
const largeFunctions = [];
|
|
77
|
-
function visit(node) {
|
|
78
|
-
if (ts.isFunctionDeclaration(node) && node.body) {
|
|
79
|
-
const startLine = getLineOfPosition(node.body.pos);
|
|
80
|
-
const endLine = getLineOfPosition(node.body.end);
|
|
81
|
-
const lineCount = endLine - startLine;
|
|
82
|
-
if (lineCount > funcLineThreshold) {
|
|
83
|
-
const name = node.name?.text || "<anonymous>";
|
|
84
|
-
largeFunctions.push({
|
|
85
|
-
name,
|
|
86
|
-
startPos: node.body.pos,
|
|
87
|
-
endPos: node.body.end,
|
|
88
|
-
lineCount
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
ts.forEachChild(node, visit);
|
|
93
|
-
}
|
|
94
|
-
visit(sourceFile);
|
|
95
|
-
if (largeFunctions.length === 0) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
console.log(
|
|
99
|
-
`File "${filePath}" has ${largeFunctions.length} function(s) above ${funcLineThreshold} lines. Attempting to split...`
|
|
100
|
-
);
|
|
101
|
-
largeFunctions.sort((a, b) => b.startPos - a.startPos).forEach((fn) => {
|
|
102
|
-
const bodyText = sourceCode.slice(fn.startPos, fn.endPos);
|
|
103
|
-
const midIndex = Math.floor(bodyText.length / 2);
|
|
104
|
-
const helperFunctionName = `${fn.name}HelperAutoGen`;
|
|
105
|
-
const replacementText = `{
|
|
106
|
-
// Original function was split automatically
|
|
107
|
-
${bodyText.slice(0, midIndex)}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function ${helperFunctionName}() {
|
|
111
|
-
// auto-generated second half
|
|
112
|
-
${bodyText.slice(midIndex)}
|
|
113
|
-
`;
|
|
114
|
-
newSource = newSource.slice(0, fn.startPos) + replacementText + newSource.slice(fn.endPos);
|
|
115
|
-
});
|
|
116
|
-
fs.writeFileSync(filePath, newSource, "utf8");
|
|
117
22
|
}
|
|
23
|
+
main().catch((err) => {
|
|
24
|
+
console.error(err);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
@@ -52,7 +52,7 @@ export default defineCommand({
|
|
|
52
52
|
}
|
|
53
53
|
if (!TOOLS.includes(args.tool)) {
|
|
54
54
|
relinka("error", `Error: Invalid tool: ${args.tool}`);
|
|
55
|
-
relinka("
|
|
55
|
+
relinka("log", `Available tools: ${TOOLS.join(", ")}`);
|
|
56
56
|
printUsage(isDev);
|
|
57
57
|
process.exit(1);
|
|
58
58
|
}
|
|
@@ -28,7 +28,7 @@ export async function useAggregator({
|
|
|
28
28
|
const exts = [".ts", ".js"];
|
|
29
29
|
if (verbose)
|
|
30
30
|
relinka(
|
|
31
|
-
"
|
|
31
|
+
"log",
|
|
32
32
|
`Scanning directory ${inputDir} for files with extensions: ${exts.join(
|
|
33
33
|
", "
|
|
34
34
|
)}`
|
|
@@ -61,7 +61,7 @@ export async function useAggregator({
|
|
|
61
61
|
const allLines = aggregatorLinesArrays.flat();
|
|
62
62
|
if (sortLines) {
|
|
63
63
|
allLines.sort();
|
|
64
|
-
if (verbose) relinka("
|
|
64
|
+
if (verbose) relinka("log", "Sorted aggregator lines alphabetically.");
|
|
65
65
|
}
|
|
66
66
|
if (outFile.startsWith(inputDir)) {
|
|
67
67
|
relinka(
|
|
@@ -83,7 +83,7 @@ ${AGGREGATOR_END}
|
|
|
83
83
|
if (overrideFile) {
|
|
84
84
|
finalText = aggregatorBlock;
|
|
85
85
|
if (verbose) {
|
|
86
|
-
relinka("
|
|
86
|
+
relinka("log", "Override mode: rewriting entire file.");
|
|
87
87
|
}
|
|
88
88
|
} else {
|
|
89
89
|
let existingContent = "";
|
|
@@ -91,12 +91,12 @@ ${AGGREGATOR_END}
|
|
|
91
91
|
existingContent = await fs.readFile(outFile, "utf8");
|
|
92
92
|
} catch {
|
|
93
93
|
if (verbose)
|
|
94
|
-
relinka("
|
|
94
|
+
relinka("log", "Aggregator file does not exist. Creating new one.");
|
|
95
95
|
}
|
|
96
96
|
if (existingContent?.includes(AGGREGATOR_START) && existingContent.includes(AGGREGATOR_END)) {
|
|
97
97
|
if (verbose) {
|
|
98
98
|
relinka(
|
|
99
|
-
"
|
|
99
|
+
"log",
|
|
100
100
|
"Existing aggregator block found. Updating auto-generated section."
|
|
101
101
|
);
|
|
102
102
|
}
|
|
@@ -109,7 +109,7 @@ ${AGGREGATOR_END}
|
|
|
109
109
|
if (existingContent) {
|
|
110
110
|
if (verbose)
|
|
111
111
|
relinka(
|
|
112
|
-
"
|
|
112
|
+
"log",
|
|
113
113
|
"No aggregator block found. Appending auto-generated section."
|
|
114
114
|
);
|
|
115
115
|
finalText = `${existingContent.trim()}
|
|
@@ -160,7 +160,7 @@ async function collectFiles(dir, exts, recursive, ignoreDirs, verbose, includeIn
|
|
|
160
160
|
if (entry.isDirectory()) {
|
|
161
161
|
if (ignoreDirs.includes(entry.name)) {
|
|
162
162
|
if (verbose) {
|
|
163
|
-
relinka("
|
|
163
|
+
relinka("log", `Skipping ignored directory: ${fullPath}`);
|
|
164
164
|
}
|
|
165
165
|
continue;
|
|
166
166
|
}
|
|
@@ -179,13 +179,13 @@ async function collectFiles(dir, exts, recursive, ignoreDirs, verbose, includeIn
|
|
|
179
179
|
} else if (entry.isFile()) {
|
|
180
180
|
if (!includeInternal && path.basename(fullPath).startsWith(internalMarker)) {
|
|
181
181
|
if (verbose) {
|
|
182
|
-
relinka("
|
|
182
|
+
relinka("log", `Skipping internal file: ${fullPath}`);
|
|
183
183
|
}
|
|
184
184
|
continue;
|
|
185
185
|
}
|
|
186
186
|
if (exts.some((ext) => entry.name.toLowerCase().endsWith(ext))) {
|
|
187
187
|
if (verbose) {
|
|
188
|
-
relinka("
|
|
188
|
+
relinka("log", `Found file: ${fullPath}`);
|
|
189
189
|
}
|
|
190
190
|
found.push(fullPath);
|
|
191
191
|
}
|
|
@@ -275,21 +275,21 @@ function guessStarImportIdentifier(filePath) {
|
|
|
275
275
|
return identifier || "file";
|
|
276
276
|
}
|
|
277
277
|
export function printUsage(isDev) {
|
|
278
|
-
relinka("
|
|
279
|
-
relinka("
|
|
280
|
-
relinka("
|
|
278
|
+
relinka("log", "====================");
|
|
279
|
+
relinka("log", "TOOLS USAGE EXAMPLES");
|
|
280
|
+
relinka("log", "====================");
|
|
281
281
|
relinka(
|
|
282
|
-
"
|
|
282
|
+
"log",
|
|
283
283
|
`${isDev ? "bun dev:agg" : "dler tools"} --tool agg --input <dir> --out <file> [options]`
|
|
284
284
|
);
|
|
285
285
|
if (isDev) {
|
|
286
286
|
relinka(
|
|
287
|
-
"
|
|
288
|
-
"bun dev:tools agg --input src/libs/sdk/sdk-impl --out src/libs/sdk/sdk-
|
|
287
|
+
"log",
|
|
288
|
+
"bun dev:tools agg --input src/libs/sdk/sdk-impl --out src/libs/sdk/sdk-mod.ts --recursive --named --strip src/libs/sdk"
|
|
289
289
|
);
|
|
290
290
|
} else {
|
|
291
291
|
relinka(
|
|
292
|
-
"
|
|
292
|
+
"log",
|
|
293
293
|
"dler tools --tool agg --input src/libs --out aggregator.ts --recursive --named"
|
|
294
294
|
);
|
|
295
295
|
}
|