@reliverse/dler 1.2.4 → 1.2.5

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 CHANGED
@@ -116,7 +116,7 @@ bun dev # bun src/mod.ts --dev
116
116
 
117
117
  ## 🔌 plugins
118
118
 
119
- dler ships with a flexible plugin system and **15 built-in plugins** (from [@reliverse/addons](https://reliverse.org/addons)).
119
+ dler ships with a flexible plugin system and **14 built-in plugins** (from [@reliverse/addons](https://reliverse.org/addons)).
120
120
 
121
121
  feel free to create your own plugins. plugins can be implemented as built-in directly in `src/app/plugin-name/impl/*` and then imported from `src/app/plugin-name/cmd.ts`; or implemented in your own library and then imported from `src/app/plugin-name/cmd.ts`.
122
122
 
@@ -128,15 +128,7 @@ generates aggregator file with content like `import { getsomething } from "./uti
128
128
  dler agg ...
129
129
  ```
130
130
 
131
- ### 2. `auth`
132
-
133
- best friend of auth+db libs like [better-auth](https://better-auth.com) and [drizzle-orm](https://orm.drizzle.team).
134
-
135
- ```bash
136
- dler auth better-auth generate
137
- ```
138
-
139
- ### 3. `build`
131
+ ### 2. `build`
140
132
 
141
133
  since dler is fully modular, build command is separated for its own build-in plugin as well.
142
134
 
@@ -144,11 +136,11 @@ since dler is fully modular, build command is separated for its own build-in plu
144
136
  dler build ...
145
137
  ```
146
138
 
147
- ### 4. `conv`
139
+ ### 3. `conv`
148
140
 
149
141
  not yet documented.
150
142
 
151
- ### 5. `deps`
143
+ ### 4. `deps`
152
144
 
153
145
  finds missing dependencies in your project by scanning your code for imports and comparing them to your `package.json`.
154
146
 
@@ -195,11 +187,11 @@ dler deps --all --directory ./src --include-builtins
195
187
  missing dependencies are shown only once, even if used in multiple files.
196
188
  deep imports like `dep/some/file` or `@org/dep/some/thing` are always resolved to their root package.
197
189
 
198
- ### 6. `inject`
190
+ ### 5. `inject`
199
191
 
200
192
  not yet documented.
201
193
 
202
- ### 7. `libs`
194
+ ### 6. `libs`
203
195
 
204
196
  builds and publishes specific subdirectories of your main project as standalone packages.
205
197
 
@@ -235,15 +227,15 @@ libslist: {
235
227
 
236
228
  - more magic commands coming soon...
237
229
 
238
- ### 8. `merge`
230
+ ### 7. `merge`
239
231
 
240
232
  not yet documented.
241
233
 
242
- ### 9. `mono`
234
+ ### 8. `mono`
243
235
 
244
236
  not yet documented.
245
237
 
246
- ### 10. `pub`
238
+ ### 9. `pub`
247
239
 
248
240
  pub command is separated for its own build-in plugin as well.
249
241
 
@@ -253,13 +245,13 @@ it already calls build command by itself, so you don't need to run `dler build`
253
245
  dler pub ...
254
246
  ```
255
247
 
256
- ### 11. `relifso`
248
+ ### 10. `relifso`
257
249
 
258
250
  ```bash
259
251
  dler relifso init ...
260
252
  ```
261
253
 
262
- ### 12. `relinka`
254
+ ### 11. `relinka`
263
255
 
264
256
  @reliverse/relinka's best friend. learn more in its [docs](https://github.com/reliverse/relinka).
265
257
 
@@ -267,7 +259,7 @@ dler relifso init ...
267
259
  dler relinka --console-to-relinka
268
260
  ```
269
261
 
270
- ### 13. `rempts`
262
+ ### 12. `rempts`
271
263
 
272
264
  @reliverse/rempts's best friend. learn more in its [docs](https://github.com/reliverse/rempts).
273
265
 
@@ -276,7 +268,7 @@ dler rempts init --cmd my-cmd-1
276
268
  dler rempts init --cmds
277
269
  ```
278
270
 
279
- ### 14. `spell`
271
+ ### 13. `spell`
280
272
 
281
273
  **available spell types:**
282
274
 
@@ -334,7 +326,7 @@ await dler.spell({ spells: ["rename-file"], files: [] });
334
326
 
335
327
  p.s. [see how rse cli uses hooked=true](https://github.com/reliverse/rse/blob/main/src/postbuild.ts)
336
328
 
337
- ### 15. `tools`
329
+ ### 14. `tools`
338
330
 
339
331
  lets you run standalone dler features directly from the cli:
340
332
 
@@ -0,0 +1,38 @@
1
+ import { defineCommand, defineArgs, confirmPrompt } from "@reliverse/rempts";
2
+ import fs from "fs-extra";
3
+ import { commanderToRempts } from "./impl/commander.js";
4
+ export default defineCommand({
5
+ args: defineArgs({
6
+ provider: {
7
+ type: "string",
8
+ description: "The provider to migrate from",
9
+ required: true,
10
+ allowed: ["commander"]
11
+ },
12
+ input: {
13
+ type: "string",
14
+ description: "Target directory path containing the files to migrate",
15
+ required: true
16
+ }
17
+ }),
18
+ async run({ args }) {
19
+ const { provider, input } = args;
20
+ const confidence = await confirmPrompt({
21
+ title: `This is an experimental feature and probably may broke some things.
22
+ It will be improved in the future.
23
+ Are you sure you want to migrate files in ${input}?`,
24
+ defaultValue: false
25
+ });
26
+ if (!confidence) {
27
+ throw new Error("Migration cancelled");
28
+ }
29
+ if (!await fs.pathExists(input)) {
30
+ throw new Error(`Input directory does not exist: ${input}`);
31
+ }
32
+ if (provider === "commander") {
33
+ await commanderToRempts(input);
34
+ } else {
35
+ throw new Error(`Unsupported provider: ${provider}`);
36
+ }
37
+ }
38
+ });
@@ -0,0 +1,265 @@
1
+ import { glob } from "glob";
2
+ import {
3
+ Project,
4
+ Node,
5
+ ScriptTarget,
6
+ ModuleKind,
7
+ SyntaxKind
8
+ } from "ts-morph";
9
+ function parseCommanderFlags(flags) {
10
+ const parts = flags.split(/[\s,]+/).filter(Boolean);
11
+ let longName = "";
12
+ let shortName;
13
+ let takesValue = false;
14
+ for (const part of parts) {
15
+ if (part.startsWith("--")) {
16
+ longName = part.substring(2);
17
+ } else if (part.startsWith("-") && part.length === 2) {
18
+ shortName = part.substring(1);
19
+ }
20
+ }
21
+ if (flags.includes("<") || flags.includes("[")) {
22
+ takesValue = true;
23
+ longName = longName.replace(/[<[].*/, "").trim();
24
+ }
25
+ if (!longName && shortName) {
26
+ if (flags.includes(`<${shortName}>`)) takesValue = true;
27
+ longName = shortName;
28
+ }
29
+ if (!longName) {
30
+ throw new Error(`Could not parse flags: ${flags}`);
31
+ }
32
+ return { longName, shortName, takesValue };
33
+ }
34
+ function getDefaultValueText(node) {
35
+ if (!node) return void 0;
36
+ if (Node.isLiteralExpression(node)) {
37
+ return node.getText();
38
+ }
39
+ if (Node.isIdentifier(node) || Node.isPropertyAccessExpression(node)) {
40
+ return node.getText();
41
+ }
42
+ if (Node.isCallExpression(node)) {
43
+ return node.getText();
44
+ }
45
+ if (Node.isPrefixUnaryExpression(node)) {
46
+ return node.getText();
47
+ }
48
+ console.warn(
49
+ `Unhandled default value type: ${node.getKindName()}, text: ${node.getText()}`
50
+ );
51
+ return node.getText();
52
+ }
53
+ async function transformCommand(varDecl, info, sourceFile) {
54
+ const commandName = info.commandName;
55
+ if (!commandName) {
56
+ console.warn("No command name found");
57
+ return;
58
+ }
59
+ let actionBodyText = "";
60
+ if (info.actionFunction) {
61
+ if (Node.isArrowFunction(info.actionFunction) || Node.isFunctionExpression(info.actionFunction) || Node.isFunctionDeclaration(info.actionFunction)) {
62
+ const body = info.actionFunction.getBody();
63
+ if (body) {
64
+ actionBodyText = body.getText();
65
+ if (Node.isBlock(body)) {
66
+ actionBodyText = actionBodyText.slice(1, -1).trim();
67
+ }
68
+ }
69
+ } else {
70
+ console.warn(
71
+ `Unhandled action function type: ${info.actionFunction.getKindName()}`
72
+ );
73
+ }
74
+ }
75
+ info.options.reverse();
76
+ if (info.actionFunctionParam) {
77
+ const paramRegex = new RegExp(`\\b${info.actionFunctionParam}\\b`, "g");
78
+ actionBodyText = actionBodyText.replace(paramRegex, "args");
79
+ }
80
+ const argsProperties = info.options.map((opt) => {
81
+ const defaultValueStr = opt.defaultValue ? `,
82
+ default: ${String(opt.defaultValue)}` : "";
83
+ const requiredStr = opt.required ? ",\n required: true" : "";
84
+ return ` ${opt.name}: {
85
+ type: "${opt.type}",
86
+ description: "${opt.description}"${defaultValueStr}${requiredStr}
87
+ }`;
88
+ }).join(",\n");
89
+ const defineCommandText = `
90
+ export const ${varDecl.getName()} = defineCommand({
91
+ meta: {
92
+ name: "${commandName}",
93
+ version: "${info.version || "1.0.0"}",
94
+ description: "${info.description || "Migrated from Commander"}",
95
+ },
96
+ args: {
97
+ ${argsProperties}
98
+ },
99
+ async run({ args }) {
100
+ ${actionBodyText}
101
+ },
102
+ });
103
+
104
+ // Add runMain at the end of the file
105
+ await runMain(${varDecl.getName()});
106
+ `;
107
+ varDecl.replaceWithText(defineCommandText);
108
+ if (info.actionFunction && Node.isIdentifier(info.actionFunction)) {
109
+ const funcName = info.actionFunction.getText();
110
+ const funcDecl = sourceFile.getFunction(funcName);
111
+ if (funcDecl) {
112
+ funcDecl.remove();
113
+ }
114
+ }
115
+ sourceFile.fixMissingImports();
116
+ await sourceFile.save();
117
+ console.log(`Transformed command in: ${sourceFile.getFilePath()}`);
118
+ }
119
+ function extractCommandInfo(node, sourceFile) {
120
+ const info = {
121
+ options: []
122
+ };
123
+ if (Node.isNewExpression(node)) {
124
+ const expr = node.getExpression();
125
+ if (expr && Node.isIdentifier(expr) && expr.getText() === "Command") {
126
+ const commandArg = node.getArguments()[0];
127
+ if (commandArg && Node.isStringLiteral(commandArg)) {
128
+ info.commandName = commandArg.getLiteralText();
129
+ }
130
+ return info;
131
+ }
132
+ }
133
+ if (Node.isCallExpression(node)) {
134
+ let tempExpr = node;
135
+ while (tempExpr && Node.isCallExpression(tempExpr)) {
136
+ const expression = tempExpr.getExpression();
137
+ if (Node.isPropertyAccessExpression(expression)) {
138
+ const methodName = expression.getName();
139
+ switch (methodName) {
140
+ case "action":
141
+ handleActionMethod(tempExpr, info, sourceFile);
142
+ break;
143
+ case "option":
144
+ handleOptionMethod(tempExpr, info);
145
+ break;
146
+ case "description":
147
+ handleDescriptionMethod(tempExpr, info);
148
+ break;
149
+ case "version":
150
+ handleVersionMethod(tempExpr, info);
151
+ break;
152
+ }
153
+ }
154
+ const parent = tempExpr.getParent();
155
+ tempExpr = Node.isCallExpression(parent) ? parent : void 0;
156
+ }
157
+ return info;
158
+ }
159
+ return void 0;
160
+ }
161
+ function handleActionMethod(node, info, sourceFile) {
162
+ const [actionArg] = node.getArguments();
163
+ if (actionArg && Node.isIdentifier(actionArg)) {
164
+ const funcDef = sourceFile.getFunction(actionArg.getText()) || sourceFile.getVariableDeclaration(actionArg.getText())?.getInitializer();
165
+ if (funcDef && (Node.isArrowFunction(funcDef) || Node.isFunctionDeclaration(funcDef) || Node.isFunctionExpression(funcDef))) {
166
+ info.actionFunction = funcDef;
167
+ const firstParam = funcDef.getParameters()[0];
168
+ if (firstParam) {
169
+ info.actionFunctionParam = firstParam.getName();
170
+ }
171
+ }
172
+ }
173
+ }
174
+ function handleOptionMethod(node, info) {
175
+ const [flagsArg, descArg, defaultValueArg] = node.getArguments();
176
+ if (flagsArg && Node.isStringLiteral(flagsArg)) {
177
+ const { longName, shortName, takesValue } = parseCommanderFlags(
178
+ flagsArg.getLiteralText()
179
+ );
180
+ info.options.push({
181
+ name: longName,
182
+ shortFlag: shortName,
183
+ type: takesValue ? "string" : "boolean",
184
+ description: Node.isStringLiteral(descArg) ? descArg.getLiteralText() : "TODO: Add description",
185
+ defaultValue: defaultValueArg ? getDefaultValueText(defaultValueArg) : void 0
186
+ });
187
+ }
188
+ }
189
+ function handleDescriptionMethod(node, info) {
190
+ const [descArg] = node.getArguments();
191
+ if (descArg && Node.isStringLiteral(descArg)) {
192
+ info.description = descArg.getLiteralText();
193
+ }
194
+ }
195
+ function handleVersionMethod(node, info) {
196
+ const [versionArg] = node.getArguments();
197
+ if (versionArg && Node.isStringLiteral(versionArg)) {
198
+ info.version = versionArg.getLiteralText();
199
+ }
200
+ }
201
+ export async function commanderToRempts(targetDirectory) {
202
+ if (!targetDirectory) {
203
+ throw new Error("Target directory is required");
204
+ }
205
+ const project = new Project({
206
+ compilerOptions: {
207
+ target: ScriptTarget.ESNext,
208
+ module: ModuleKind.ESNext,
209
+ esModuleInterop: true,
210
+ skipLibCheck: true
211
+ },
212
+ skipAddingFilesFromTsConfig: true
213
+ });
214
+ const filePaths = await glob(`${targetDirectory}/**/*.ts`, {
215
+ ignore: ["**/node_modules/**", "**/*.d.ts"],
216
+ absolute: true
217
+ });
218
+ for (const filePath of filePaths) {
219
+ console.log(`Processing: ${filePath}`);
220
+ project.addSourceFileAtPath(filePath);
221
+ try {
222
+ await transformFile(filePath, project);
223
+ } catch (error) {
224
+ console.error(`Error transforming file ${filePath}:`, error);
225
+ }
226
+ }
227
+ console.log("Migration completed successfully.");
228
+ }
229
+ async function transformFile(filePath, project) {
230
+ const sourceFile = project.getSourceFile(filePath);
231
+ if (!sourceFile) {
232
+ console.error(`Could not find source file: ${filePath}`);
233
+ return;
234
+ }
235
+ const commanderImport = sourceFile.getImportDeclaration("commander");
236
+ if (commanderImport) {
237
+ commanderImport.remove();
238
+ }
239
+ const remptsImport = sourceFile.getImportDeclaration("@reliverse/rempts");
240
+ const neededRemptsImports = ["defineCommand", "runMain"];
241
+ if (remptsImport) {
242
+ const existingNamedImports = remptsImport.getNamedImports().map((ni) => ni.getName());
243
+ for (const neededImport of neededRemptsImports) {
244
+ if (!existingNamedImports.includes(neededImport)) {
245
+ remptsImport.addNamedImport(neededImport);
246
+ }
247
+ }
248
+ } else {
249
+ sourceFile.addImportDeclaration({
250
+ moduleSpecifier: "@reliverse/rempts",
251
+ namedImports: neededRemptsImports
252
+ });
253
+ }
254
+ const variableDeclarations = sourceFile.getDescendantsOfKind(
255
+ SyntaxKind.VariableDeclaration
256
+ );
257
+ for (const varDecl of variableDeclarations) {
258
+ const initializer = varDecl.getInitializer();
259
+ if (!initializer) continue;
260
+ const commandInfo = extractCommandInfo(initializer, sourceFile);
261
+ if (commandInfo) {
262
+ await transformCommand(varDecl, commandInfo, sourceFile);
263
+ }
264
+ }
265
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "dependencies": {
3
3
  "@reliverse/relico": "^1.1.2",
4
4
  "@reliverse/relinka": "^1.4.5",
5
- "@reliverse/rempts": "^1.7.8",
5
+ "@reliverse/rempts": "^1.7.10",
6
6
  "@rollup/plugin-alias": "^5.1.1",
7
7
  "@rollup/plugin-commonjs": "^28.0.3",
8
8
  "@rollup/plugin-json": "^6.1.0",
@@ -33,6 +33,7 @@
33
33
  "scule": "^1.3.0",
34
34
  "semver": "^7.7.2",
35
35
  "tinyglobby": "^0.2.13",
36
+ "ts-morph": "^25.0.1",
36
37
  "untyped": "^2.0.0"
37
38
  },
38
39
  "description": "dler (prev. relidler) is a flexible, unified, and fully automated bundler for TypeScript and JavaScript projects, as well as an NPM and JSR publishing tool.",
@@ -40,7 +41,7 @@
40
41
  "license": "MIT",
41
42
  "name": "@reliverse/dler",
42
43
  "type": "module",
43
- "version": "1.2.4",
44
+ "version": "1.2.5",
44
45
  "keywords": [
45
46
  "reliverse",
46
47
  "cli",
File without changes