@tertium/hlpr 0.3.3 → 0.3.4

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.
Files changed (2) hide show
  1. package/bin/index.js +144 -17
  2. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ #!/usr/bin/env node
2
+
1
3
  // src/index.ts
2
4
  import { readFile } from "node:fs/promises";
3
5
  import { exec } from "node:child_process";
@@ -76,6 +78,142 @@ async function executeCommand(command, variables) {
76
78
  });
77
79
  });
78
80
  }
81
+ async function showHelp() {
82
+ async function getCommandDescription(filePath) {
83
+ try {
84
+ const content = await readFile(filePath, "utf-8");
85
+ const descMatch = content.match(/(?:\/\/|#)\s*@description\s+(.+)/);
86
+ if (descMatch) {
87
+ return descMatch[1].trim();
88
+ }
89
+ const dir = path.dirname(filePath);
90
+ const readmePath = path.join(dir, "README.md");
91
+ if (fs.existsSync(readmePath)) {
92
+ const readme = await readFile(readmePath, "utf-8");
93
+ const firstLine = readme.split(`
94
+ `).find((line) => line.trim() && !line.startsWith("#"));
95
+ if (firstLine) {
96
+ return firstLine.trim();
97
+ }
98
+ }
99
+ } catch (error) {}
100
+ return;
101
+ }
102
+ async function discoverCommands(commandsDir) {
103
+ const commands2 = [];
104
+ try {
105
+ const categories = await fs.promises.readdir(commandsDir, { withFileTypes: true });
106
+ for (const category of categories) {
107
+ if (!category.isDirectory())
108
+ continue;
109
+ const categoryPath = path.join(commandsDir, category.name);
110
+ const items = await fs.promises.readdir(categoryPath, { withFileTypes: true });
111
+ for (const item of items) {
112
+ if (item.isDirectory()) {
113
+ const nestedJsPath = path.join(categoryPath, item.name, `${item.name}.js`);
114
+ const nestedShPath = path.join(categoryPath, item.name, `${item.name}.sh`);
115
+ let commandPath;
116
+ let commandType;
117
+ if (fs.existsSync(nestedJsPath)) {
118
+ commandPath = nestedJsPath;
119
+ commandType = "typescript";
120
+ } else if (fs.existsSync(nestedShPath)) {
121
+ commandPath = nestedShPath;
122
+ commandType = "shell";
123
+ } else {
124
+ continue;
125
+ }
126
+ const description = await getCommandDescription(commandPath);
127
+ commands2.push({
128
+ category: category.name,
129
+ name: item.name,
130
+ type: commandType,
131
+ path: commandPath,
132
+ description
133
+ });
134
+ } else if (item.name.endsWith(".js")) {
135
+ const jsPath = path.join(categoryPath, item.name);
136
+ const commandName = path.basename(item.name, ".js");
137
+ if (commandName !== "test" && !commandName.endsWith(".test")) {
138
+ const description = await getCommandDescription(jsPath);
139
+ commands2.push({
140
+ category: category.name,
141
+ name: commandName,
142
+ type: "typescript",
143
+ path: jsPath,
144
+ description
145
+ });
146
+ }
147
+ } else if (item.name.endsWith(".sh")) {
148
+ const shPath = path.join(categoryPath, item.name);
149
+ const commandName = path.basename(item.name, ".sh");
150
+ const description = await getCommandDescription(shPath);
151
+ commands2.push({
152
+ category: category.name,
153
+ name: commandName,
154
+ type: "shell",
155
+ path: shPath,
156
+ description
157
+ });
158
+ }
159
+ }
160
+ }
161
+ } catch (error) {}
162
+ return commands2;
163
+ }
164
+ const version = await getVersion();
165
+ const binCommandsDir = path.join(__dirname2, "commands");
166
+ const srcCommandsDir = path.join(__dirname2, "..", "src", "commands");
167
+ const commands = [
168
+ ...await discoverCommands(binCommandsDir),
169
+ ...await discoverCommands(srcCommandsDir)
170
+ ];
171
+ const uniqueCommands = commands.filter((cmd, index, self) => index === self.findIndex((c) => c.category === cmd.category && c.name === cmd.name));
172
+ console.log(`
173
+ ╔════════════════════════════════════════════════════════════╗`);
174
+ console.log(`║ hlpr - Helper CLI Tool v${version.padEnd(16)}║`);
175
+ console.log(`╚════════════════════════════════════════════════════════════╝
176
+ `);
177
+ console.log("USAGE:");
178
+ console.log(` hlpr [options] <category> <command> [args...]
179
+ `);
180
+ console.log("OPTIONS:");
181
+ console.log(" -f Force execution (continue on errors)");
182
+ console.log(" -v, --version Show version information");
183
+ console.log(" help, -h, --help, /h, /help, /?");
184
+ console.log(` Show this help message
185
+ `);
186
+ console.log(`AVAILABLE COMMANDS:
187
+ `);
188
+ const grouped = uniqueCommands.reduce((acc, cmd) => {
189
+ if (!acc[cmd.category]) {
190
+ acc[cmd.category] = [];
191
+ }
192
+ acc[cmd.category].push(cmd);
193
+ return acc;
194
+ }, {});
195
+ const sortedCategories = Object.keys(grouped).sort();
196
+ for (const category of sortedCategories) {
197
+ console.log(` ${category}:`);
198
+ const categoryCommands = grouped[category].sort((a, b) => a.name.localeCompare(b.name));
199
+ for (const cmd of categoryCommands) {
200
+ const typeLabel = cmd.type === "typescript" ? "(TS)" : "(sh)";
201
+ const cmdDisplay = cmd.category === cmd.name ? `hlpr ${cmd.name}`.padEnd(35) : `hlpr ${cmd.category} ${cmd.name}`.padEnd(35);
202
+ if (cmd.description) {
203
+ console.log(` ${cmdDisplay} ${typeLabel.padEnd(6)} ${cmd.description}`);
204
+ } else {
205
+ console.log(` ${cmdDisplay} ${typeLabel}`);
206
+ }
207
+ }
208
+ console.log("");
209
+ }
210
+ console.log("EXAMPLES:");
211
+ console.log(" hlpr help");
212
+ console.log(" hlpr file rename --style kebab --dir ./src");
213
+ console.log(" hlpr ssh init-dir");
214
+ console.log(` hlpr -f git precommit
215
+ `);
216
+ }
79
217
  async function main() {
80
218
  if (commandArgs[0] === "--version" || commandArgs[0] === "-v") {
81
219
  const version = await getVersion();
@@ -83,17 +221,8 @@ async function main() {
83
221
  process.exit(0);
84
222
  }
85
223
  if (commandArgs.length === 0 || commandArgs[0] === "help" || commandArgs[0] === "--help" || commandArgs[0] === "-h" || commandArgs[0] === "/help" || commandArgs[0] === "/h" || commandArgs[0] === "/?") {
86
- const helpScriptPath = path.join(__dirname2, "..", "bin", "commands", "help", "help.js");
87
- if (fs.existsSync(helpScriptPath)) {
88
- const helpCommand = `node "${helpScriptPath}"`;
89
- await executeCommand(helpCommand, {});
90
- rl.close();
91
- process.exit(0);
92
- } else {
93
- console.error("Please provide a command. Example: hlpr ssh init-dir");
94
- console.error("Run 'hlpr help' for available commands.");
95
- process.exit(1);
96
- }
224
+ await showHelp();
225
+ process.exit(0);
97
226
  }
98
227
  try {
99
228
  const category = commandArgs[0];
@@ -179,9 +308,7 @@ async function main() {
179
308
  rl.close();
180
309
  }
181
310
  }
182
- if (import.meta.url.startsWith("file:") && process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/\\/g, "/"))) {
183
- main();
184
- }
185
- export {
186
- main
187
- };
311
+ main().catch((error) => {
312
+ console.error("Fatal error:", error);
313
+ process.exit(1);
314
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tertium/hlpr",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Windows and *Nix utility for typical programming activity",
5
5
  "author": "Vitalii Balabanov",
6
6
  "email": "tertiumnon@gmail.com",