yargs-file-commands 0.0.20 → 1.0.1

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 (57) hide show
  1. package/README.md +13 -13
  2. package/dist/index.js +1 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/lib/Command.js +1 -0
  5. package/dist/lib/Command.js.map +1 -0
  6. package/dist/lib/buildSegmentTree.d.ts +1 -1
  7. package/dist/lib/buildSegmentTree.js +7 -3
  8. package/dist/lib/buildSegmentTree.js.map +1 -0
  9. package/dist/lib/buildSegmentTree.test.js +279 -26
  10. package/dist/lib/buildSegmentTree.test.js.map +1 -0
  11. package/dist/lib/fileCommands.d.ts +2 -1
  12. package/dist/lib/fileCommands.js +39 -21
  13. package/dist/lib/fileCommands.js.map +1 -0
  14. package/dist/lib/fileCommands.test.js +107 -30
  15. package/dist/lib/fileCommands.test.js.map +1 -0
  16. package/dist/lib/fixtures/commands/$default.js +1 -0
  17. package/dist/lib/fixtures/commands/$default.js.map +1 -0
  18. package/dist/lib/fixtures/commands/create.js +1 -0
  19. package/dist/lib/fixtures/commands/create.js.map +1 -0
  20. package/dist/lib/fixtures/commands/db/health.d.ts +2 -1
  21. package/dist/lib/fixtures/commands/db/health.js +2 -3
  22. package/dist/lib/fixtures/commands/db/health.js.map +1 -0
  23. package/dist/lib/fixtures/commands/db/migration/command.d.ts +9 -2
  24. package/dist/lib/fixtures/commands/db/migration/command.js +6 -7
  25. package/dist/lib/fixtures/commands/db/migration/command.js.map +1 -0
  26. package/dist/lib/importCommand.d.ts +3 -3
  27. package/dist/lib/importCommand.js +39 -27
  28. package/dist/lib/importCommand.js.map +1 -0
  29. package/dist/lib/importCommand.test.js +157 -33
  30. package/dist/lib/importCommand.test.js.map +1 -0
  31. package/dist/lib/scanDirectory.js +54 -25
  32. package/dist/lib/scanDirectory.js.map +1 -0
  33. package/dist/lib/scanDirectory.test.js +148 -25
  34. package/dist/lib/scanDirectory.test.js.map +1 -0
  35. package/dist/lib/segmentPath.js +8 -6
  36. package/dist/lib/segmentPath.js.map +1 -0
  37. package/dist/lib/segmentPath.test.js +10 -38
  38. package/dist/lib/segmentPath.test.js.map +1 -0
  39. package/dist/tsconfig.tsbuildinfo +1 -0
  40. package/package.json +6 -9
  41. package/CHANGELOG.md +0 -62
  42. package/src/index.ts +0 -1
  43. package/src/lib/Command.ts +0 -16
  44. package/src/lib/buildSegmentTree.test.ts +0 -90
  45. package/src/lib/buildSegmentTree.ts +0 -149
  46. package/src/lib/fileCommands.test.ts +0 -55
  47. package/src/lib/fileCommands.ts +0 -149
  48. package/src/lib/fixtures/commands/$default.ts +0 -5
  49. package/src/lib/fixtures/commands/create.ts +0 -6
  50. package/src/lib/fixtures/commands/db/health.ts +0 -9
  51. package/src/lib/fixtures/commands/db/migration/command.ts +0 -12
  52. package/src/lib/importCommand.test.ts +0 -60
  53. package/src/lib/importCommand.ts +0 -196
  54. package/src/lib/scanDirectory.test.ts +0 -75
  55. package/src/lib/scanDirectory.ts +0 -109
  56. package/src/lib/segmentPath.test.ts +0 -71
  57. package/src/lib/segmentPath.ts +0 -38
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  [![NPM Package][npm]][npm-url]
4
4
  [![NPM Downloads][npm-downloads]][npmtrends-url]
5
+ [![Tests][tests-badge]][tests-url]
6
+ [![Coverage][coverage-badge]][coverage-url]
5
7
 
6
8
  This Yargs helper function lets you define all your commands as individual files and their file names and directory structure defines via implication your nested command structure.
7
9
 
@@ -187,25 +189,19 @@ If you want to contribute, just check out [this git project](https://github.com/
187
189
 
188
190
  ```sh
189
191
  # install dependencies
190
- npm install
192
+ pnpm install
191
193
 
192
194
  # build everything
193
- npm run build
195
+ pnpm run build
194
196
 
195
- # prettify
196
- npm run format
197
+ # biome
198
+ pnpm run chec
197
199
 
198
- # eslint
199
- npm run lint
200
-
201
- # build and run tests
202
- npm run test
200
+ # tests
201
+ pnpm vitest
203
202
 
204
203
  # clean everything, should be like doing a fresh git checkout of the repo.
205
- npm run clean
206
-
207
- # publish the npm package
208
- npm run publish
204
+ pnpm clean
209
205
 
210
206
  # run example cli
211
207
  npx example-cli
@@ -217,3 +213,7 @@ Underneath the hood, we are using [NX](https://nx.dev) to manage the monorepo an
217
213
  [npm-url]: https://www.npmjs.com/package/yargs-file-commands
218
214
  [npm-downloads]: https://img.shields.io/npm/dw/yargs-file-commands
219
215
  [npmtrends-url]: https://www.npmtrends.com/yargs-file-commands
216
+ [tests-badge]: https://github.com/bhouston/yargs-file-commands/workflows/Tests/badge.svg
217
+ [tests-url]: https://github.com/bhouston/yargs-file-commands/actions/workflows/test.yml
218
+ [coverage-badge]: https://codecov.io/gh/bhouston/yargs-file-commands/branch/main/graph/badge.svg
219
+ [coverage-url]: https://codecov.io/gh/bhouston/yargs-file-commands
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export * from './lib/fileCommands.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=Command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Command.js","sourceRoot":"","sources":["../../src/lib/Command.ts"],"names":[],"mappings":""}
@@ -38,6 +38,6 @@ export declare const buildSegmentTree: (commands: Command[]) => CommandTreeNode[
38
38
  * For leaf nodes, returns the actual command implementation.
39
39
  * For internal nodes, creates a parent command that manages subcommands.
40
40
  */
41
- export declare const createCommand: (treeNode: CommandTreeNode) => CommandModule;
41
+ export declare const createCommand: (treeNode: CommandTreeNode) => CommandModule<{}, {}>;
42
42
  export declare const logCommandTree: (commands: CommandTreeNode[], level?: number) => void;
43
43
  export {};
@@ -27,6 +27,9 @@ function insertIntoTree(treeNodes, command, depth) {
27
27
  return;
28
28
  }
29
29
  const currentSegmentName = command.segments[depth];
30
+ if (currentSegmentName === undefined) {
31
+ return;
32
+ }
30
33
  let currentSegment = treeNodes.find((s) => s.segmentName === currentSegmentName);
31
34
  // If this is the last segment, create a leaf node
32
35
  if (depth === command.segments.length - 1) {
@@ -34,7 +37,7 @@ function insertIntoTree(treeNodes, command, depth) {
34
37
  treeNodes.push({
35
38
  type: 'leaf',
36
39
  segmentName: currentSegmentName,
37
- command
40
+ command,
38
41
  });
39
42
  }
40
43
  else if (currentSegment.type === 'internal') {
@@ -47,7 +50,7 @@ function insertIntoTree(treeNodes, command, depth) {
47
50
  currentSegment = {
48
51
  type: 'internal',
49
52
  segmentName: currentSegmentName,
50
- children: []
53
+ children: [],
51
54
  };
52
55
  treeNodes.push(currentSegment);
53
56
  }
@@ -85,7 +88,7 @@ export const createCommand = (treeNode) => {
85
88
  },
86
89
  handler: async () => {
87
90
  // Internal nodes don't need handlers as they'll demand subcommands
88
- }
91
+ },
89
92
  };
90
93
  return command;
91
94
  };
@@ -97,3 +100,4 @@ export const logCommandTree = (commands, level = 0) => {
97
100
  }
98
101
  });
99
102
  };
103
+ //# sourceMappingURL=buildSegmentTree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildSegmentTree.js","sourceRoot":"","sources":["../../src/lib/buildSegmentTree.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,6 @@
1
- import assert from 'node:assert/strict';
2
- import { describe, it } from 'node:test';
3
- import { buildSegmentTree } from './buildSegmentTree.js';
4
- describe('buildSegmentTree', async () => {
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { buildSegmentTree, createCommand, logCommandTree } from './buildSegmentTree.js';
3
+ describe('buildSegmentTree', () => {
5
4
  it('should build correct tree structure', () => {
6
5
  const commands = [
7
6
  {
@@ -12,8 +11,8 @@ describe('buildSegmentTree', async () => {
12
11
  describe: 'Migration command',
13
12
  handler: async () => {
14
13
  // Test handler
15
- }
16
- }
14
+ },
15
+ },
17
16
  },
18
17
  {
19
18
  fullPath: '/commands/db/health.js',
@@ -23,28 +22,29 @@ describe('buildSegmentTree', async () => {
23
22
  describe: 'Health command',
24
23
  handler: async () => {
25
24
  // Test handler
26
- }
27
- }
28
- }
25
+ },
26
+ },
27
+ },
29
28
  ];
30
29
  const tree = buildSegmentTree(commands);
31
- assert.equal(tree.length, 1, 'Should have one root node');
30
+ expect(tree.length).toBe(1);
32
31
  const rootNode = tree[0];
33
- assert(rootNode, 'Root node should exist');
34
- assert.equal(rootNode.segmentName, 'db', 'Root node should be "db"');
35
- assert.equal(rootNode.type, 'internal', 'Root node should be internal type');
32
+ expect(rootNode).toBeDefined();
33
+ if (!rootNode) {
34
+ throw new Error('Root node should exist');
35
+ }
36
+ expect(rootNode.segmentName).toBe('db');
37
+ expect(rootNode.type).toBe('internal');
36
38
  if (rootNode.type !== 'internal') {
37
39
  throw new Error('Expected internal node');
38
40
  }
39
- assert.equal(rootNode.children.length, 2, 'Should have two child nodes');
40
- const childSegments = rootNode.children
41
- .map((child) => child.segmentName)
42
- .sort();
43
- assert.deepEqual(childSegments, ['health', 'migration'], 'Should have "health" and "migration" sub-commands');
41
+ expect(rootNode.children.length).toBe(2);
42
+ const childSegments = rootNode.children.map((child) => child.segmentName).sort();
43
+ expect(childSegments).toEqual(['health', 'migration']);
44
44
  });
45
45
  it('should handle empty input', () => {
46
46
  const tree = buildSegmentTree([]);
47
- assert.equal(tree.length, 0, 'Should return empty array for empty input');
47
+ expect(tree.length).toBe(0);
48
48
  });
49
49
  it('should handle single command', () => {
50
50
  const commands = [
@@ -56,15 +56,268 @@ describe('buildSegmentTree', async () => {
56
56
  describe: 'Test command',
57
57
  handler: async () => {
58
58
  // Test handler
59
- }
60
- }
61
- }
59
+ },
60
+ },
61
+ },
62
62
  ];
63
63
  const tree = buildSegmentTree(commands);
64
- assert.equal(tree.length, 1, 'Should have one node');
64
+ expect(tree.length).toBe(1);
65
65
  const node = tree[0];
66
- assert(node, 'Node should exist');
67
- assert.equal(node.segmentName, 'test', 'Should have correct segment');
68
- assert.equal(node.type, 'leaf', 'Should be a leaf node');
66
+ expect(node).toBeDefined();
67
+ if (!node) {
68
+ throw new Error('Node should exist');
69
+ }
70
+ expect(node.segmentName).toBe('test');
71
+ expect(node.type).toBe('leaf');
72
+ });
73
+ it('should throw error when directory conflicts with command name (directory first)', () => {
74
+ const commands = [
75
+ {
76
+ fullPath: '/commands/db/migration/command.js',
77
+ segments: ['db', 'migration'],
78
+ commandModule: {
79
+ command: 'migration',
80
+ describe: 'Migration command',
81
+ handler: async () => { },
82
+ },
83
+ },
84
+ {
85
+ fullPath: '/commands/db.js',
86
+ segments: ['db'],
87
+ commandModule: {
88
+ command: 'db',
89
+ describe: 'DB command',
90
+ handler: async () => { },
91
+ },
92
+ },
93
+ ];
94
+ expect(() => buildSegmentTree(commands)).toThrow(/Conflict: db is both a directory and a command/);
95
+ });
96
+ it('should throw error when directory conflicts with command name (command first)', () => {
97
+ const commands = [
98
+ {
99
+ fullPath: '/commands/db.js',
100
+ segments: ['db'],
101
+ commandModule: {
102
+ command: 'db',
103
+ describe: 'DB command',
104
+ handler: async () => { },
105
+ },
106
+ },
107
+ {
108
+ fullPath: '/commands/db/migration/command.js',
109
+ segments: ['db', 'migration'],
110
+ commandModule: {
111
+ command: 'migration',
112
+ describe: 'Migration command',
113
+ handler: async () => { },
114
+ },
115
+ },
116
+ ];
117
+ expect(() => buildSegmentTree(commands)).toThrow(/Conflict: db is both a directory and a command/);
118
+ });
119
+ it('should handle multiple root commands', () => {
120
+ const commands = [
121
+ {
122
+ fullPath: '/commands/hello.ts',
123
+ segments: ['hello'],
124
+ commandModule: {
125
+ command: 'hello',
126
+ describe: 'Hello command',
127
+ handler: async () => { },
128
+ },
129
+ },
130
+ {
131
+ fullPath: '/commands/world.ts',
132
+ segments: ['world'],
133
+ commandModule: {
134
+ command: 'world',
135
+ describe: 'World command',
136
+ handler: async () => { },
137
+ },
138
+ },
139
+ ];
140
+ const tree = buildSegmentTree(commands);
141
+ expect(tree.length).toBe(2);
142
+ expect(tree.map((n) => n.segmentName).sort()).toEqual(['hello', 'world']);
143
+ });
144
+ it('should handle nested commands at different depths', () => {
145
+ const commands = [
146
+ {
147
+ fullPath: '/commands/a/b/c.ts',
148
+ segments: ['a', 'b', 'c'],
149
+ commandModule: {
150
+ command: 'c',
151
+ describe: 'C command',
152
+ handler: async () => { },
153
+ },
154
+ },
155
+ {
156
+ fullPath: '/commands/a/d.ts',
157
+ segments: ['a', 'd'],
158
+ commandModule: {
159
+ command: 'd',
160
+ describe: 'D command',
161
+ handler: async () => { },
162
+ },
163
+ },
164
+ ];
165
+ const tree = buildSegmentTree(commands);
166
+ expect(tree.length).toBe(1);
167
+ expect(tree[0]?.segmentName).toBe('a');
168
+ if (tree[0]?.type === 'internal') {
169
+ expect(tree[0].children.length).toBe(2);
170
+ const childNames = tree[0].children.map((c) => c.segmentName).sort();
171
+ expect(childNames).toEqual(['b', 'd']);
172
+ const bNode = tree[0].children.find((c) => c.segmentName === 'b');
173
+ if (bNode?.type === 'internal') {
174
+ expect(bNode.children.length).toBe(1);
175
+ expect(bNode.children[0]?.segmentName).toBe('c');
176
+ expect(bNode.children[0]?.type).toBe('leaf');
177
+ }
178
+ }
179
+ });
180
+ });
181
+ describe('createCommand', () => {
182
+ it('should create command module from leaf node', () => {
183
+ const command = {
184
+ fullPath: '/commands/test.ts',
185
+ segments: ['test'],
186
+ commandModule: {
187
+ command: 'test',
188
+ describe: 'Test command',
189
+ handler: async () => {
190
+ // Test handler
191
+ },
192
+ },
193
+ };
194
+ const treeNode = {
195
+ type: 'leaf',
196
+ segmentName: 'test',
197
+ command,
198
+ };
199
+ const commandModule = createCommand(treeNode);
200
+ expect(commandModule.command).toBe('test');
201
+ expect(commandModule.describe).toBe('Test command');
202
+ expect(commandModule.handler).toBe(command.commandModule.handler);
203
+ });
204
+ it('should create command module from internal node with children', () => {
205
+ const childCommand = {
206
+ fullPath: '/commands/db/health.ts',
207
+ segments: ['db', 'health'],
208
+ commandModule: {
209
+ command: 'health',
210
+ describe: 'Health check',
211
+ handler: async () => { },
212
+ },
213
+ };
214
+ const childTreeNode = {
215
+ type: 'leaf',
216
+ segmentName: 'health',
217
+ command: childCommand,
218
+ };
219
+ const internalTreeNode = {
220
+ type: 'internal',
221
+ segmentName: 'db',
222
+ children: [childTreeNode],
223
+ };
224
+ const commandModule = createCommand(internalTreeNode);
225
+ expect(commandModule.command).toBe('db');
226
+ expect(commandModule.describe).toBe('db commands');
227
+ expect(commandModule.builder).toBeDefined();
228
+ expect(commandModule.handler).toBeDefined();
229
+ });
230
+ it('should create nested command structure with builder', () => {
231
+ const healthCommand = {
232
+ fullPath: '/commands/db/health.ts',
233
+ segments: ['db', 'health'],
234
+ commandModule: {
235
+ command: 'health',
236
+ describe: 'Health check',
237
+ handler: async () => { },
238
+ },
239
+ };
240
+ const migrationCommand = {
241
+ fullPath: '/commands/db/migration.ts',
242
+ segments: ['db', 'migration'],
243
+ commandModule: {
244
+ command: 'migration',
245
+ describe: 'Migration',
246
+ handler: async () => { },
247
+ },
248
+ };
249
+ const tree = buildSegmentTree([healthCommand, migrationCommand]);
250
+ const dbNode = tree[0];
251
+ if (!dbNode || dbNode.type !== 'internal') {
252
+ throw new Error('Expected internal node');
253
+ }
254
+ const commandModule = createCommand(dbNode);
255
+ expect(commandModule.command).toBe('db');
256
+ expect(commandModule.builder).toBeDefined();
257
+ // Test the builder function
258
+ if (commandModule.builder && typeof commandModule.builder === 'function') {
259
+ const mockYargs = {
260
+ command: vi.fn().mockReturnThis(),
261
+ demandCommand: vi.fn().mockReturnThis(),
262
+ };
263
+ commandModule.builder(mockYargs);
264
+ expect(mockYargs.command).toHaveBeenCalledTimes(1);
265
+ expect(mockYargs.demandCommand).toHaveBeenCalledWith(1, 'You must specify a db subcommand');
266
+ }
267
+ });
268
+ });
269
+ describe('logCommandTree', () => {
270
+ it('should log command tree structure', () => {
271
+ const consoleSpy = vi.spyOn(console, 'debug').mockImplementation(() => { });
272
+ const commands = [
273
+ {
274
+ fullPath: '/commands/db/health.ts',
275
+ segments: ['db', 'health'],
276
+ commandModule: {
277
+ command: 'health',
278
+ describe: 'Health',
279
+ handler: async () => { },
280
+ },
281
+ },
282
+ {
283
+ fullPath: '/commands/hello.ts',
284
+ segments: ['hello'],
285
+ commandModule: {
286
+ command: 'hello',
287
+ describe: 'Hello',
288
+ handler: async () => { },
289
+ },
290
+ },
291
+ ];
292
+ const tree = buildSegmentTree(commands);
293
+ logCommandTree(tree);
294
+ expect(consoleSpy).toHaveBeenCalled();
295
+ const calls = consoleSpy.mock.calls.map((call) => call[0]);
296
+ expect(calls.some((call) => call.includes('db'))).toBe(true);
297
+ expect(calls.some((call) => call.includes('health'))).toBe(true);
298
+ expect(calls.some((call) => call.includes('hello'))).toBe(true);
299
+ consoleSpy.mockRestore();
300
+ });
301
+ it('should log command tree with correct indentation levels', () => {
302
+ const consoleSpy = vi.spyOn(console, 'debug').mockImplementation(() => { });
303
+ const commands = [
304
+ {
305
+ fullPath: '/commands/a/b/c.ts',
306
+ segments: ['a', 'b', 'c'],
307
+ commandModule: {
308
+ command: 'c',
309
+ describe: 'C',
310
+ handler: async () => { },
311
+ },
312
+ },
313
+ ];
314
+ const tree = buildSegmentTree(commands);
315
+ logCommandTree(tree, 2);
316
+ expect(consoleSpy).toHaveBeenCalled();
317
+ const calls = consoleSpy.mock.calls.map((call) => call[0]);
318
+ // Check for indentation (initial level 2 = 4 spaces, then children add more)
319
+ expect(calls.length).toBeGreaterThan(0);
320
+ consoleSpy.mockRestore();
69
321
  });
70
322
  });
323
+ //# sourceMappingURL=buildSegmentTree.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildSegmentTree.test.js","sourceRoot":"","sources":["../../src/lib/buildSegmentTree.test.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { CommandModule } from 'yargs';
1
2
  import { type ScanDirectoryOptions } from './scanDirectory.js';
2
3
  /**
3
4
  * Configuration options for file-based command generation
@@ -30,4 +31,4 @@ export declare const DefaultFileCommandsOptions: Required<FileCommandsOptions>;
30
31
  * 3. Build a tree structure based on file paths
31
32
  * 4. Convert the tree into a command hierarchy
32
33
  */
33
- export declare const fileCommands: (options: FileCommandsOptions) => Promise<import("yargs").CommandModule<{}, {}>[]>;
34
+ export declare const fileCommands: (options: FileCommandsOptions) => Promise<CommandModule<{}, {}>[]>;
@@ -1,4 +1,4 @@
1
- import path from 'path';
1
+ import path from 'node:path';
2
2
  import { buildSegmentTree, createCommand, logCommandTree } from './buildSegmentTree.js';
3
3
  import { importCommandFromFile } from './importCommand.js';
4
4
  import { scanDirectory } from './scanDirectory.js';
@@ -13,17 +13,19 @@ export const DefaultFileCommandsOptions = {
13
13
  commandDirs: [],
14
14
  /** Default file extensions to process */
15
15
  extensions: ['.js', '.ts'],
16
- /** Default patterns to ignore when scanning directories */
16
+ /** Default patterns to ignore when scanning directories.
17
+ * Note: System files (files starting with '.') are ALWAYS ignored regardless of these patterns.
18
+ * These defaults can be overridden by providing your own ignorePatterns.
19
+ */
17
20
  ignorePatterns: [
18
- /^[.|_].*/, // Hidden files and underscore files
19
21
  /\.(?:test|spec)\.[jt]s$/, // Test files
20
22
  /__(?:test|spec)__/, // Test directories
21
- /\.d\.ts$/ // TypeScript declaration files
23
+ /\.d\.ts$/, // TypeScript declaration files
22
24
  ],
23
25
  /** Default logging level */
24
26
  logLevel: 'info',
25
27
  /** Default log prefix */
26
- logPrefix: ' '
28
+ logPrefix: ' ',
27
29
  };
28
30
  /**
29
31
  * Generates a command tree structure from files in specified directories
@@ -45,7 +47,7 @@ export const DefaultFileCommandsOptions = {
45
47
  export const fileCommands = async (options) => {
46
48
  const fullOptions = {
47
49
  ...DefaultFileCommandsOptions,
48
- ...options
50
+ ...options,
49
51
  };
50
52
  // validate extensions have dots in them
51
53
  if (fullOptions.extensions.some((ext) => !ext.startsWith('.'))) {
@@ -61,29 +63,44 @@ export const fileCommands = async (options) => {
61
63
  throw new Error(`Command directories must be absolute paths: ${nonAbsoluteDirs.join(', ')}`);
62
64
  }
63
65
  const commands = [];
64
- for (const commandDir of fullOptions.commandDirs) {
66
+ // Process all command directories in parallel
67
+ const directoryResults = await Promise.all(fullOptions.commandDirs.map(async (commandDir) => {
65
68
  const fullPath = path.resolve(commandDir);
66
69
  if (fullOptions.logLevel === 'debug') {
67
70
  console.debug(`Scanning directory for commands: ${fullPath}`);
68
71
  }
69
72
  const filePaths = await scanDirectory(commandDir, commandDir, fullOptions);
73
+ return { commandDir, filePaths };
74
+ }));
75
+ if (fullOptions.logLevel === 'debug') {
76
+ console.debug(`Importing found commands:`);
77
+ }
78
+ // Process all files in parallel
79
+ const fileResults = await Promise.all(directoryResults.flatMap(({ commandDir, filePaths }) => filePaths.map(async (filePath) => {
80
+ const localPath = path.relative(commandDir, filePath);
81
+ const segments = segmentPath(filePath, commandDir);
82
+ // Remove extension (last segment) if there are multiple segments
83
+ // If there's only one segment, it means the file has no name (e.g., .js)
84
+ if (segments.length > 1) {
85
+ segments.pop(); // remove extension.
86
+ }
87
+ else if (segments.length === 0) {
88
+ throw new Error(`No segments found for file: ${filePath}`);
89
+ }
70
90
  if (fullOptions.logLevel === 'debug') {
71
- console.debug(`Importing found commands:`);
91
+ console.debug(` ${localPath} - importing command module`);
72
92
  }
73
- for (const filePath of filePaths) {
74
- const localPath = path.relative(commandDir, filePath);
75
- const segments = segmentPath(filePath, commandDir);
76
- segments.pop(); // remove extension.
77
- if (fullOptions.logLevel === 'debug') {
78
- console.debug(` ${localPath} - importing command module`);
79
- }
80
- commands.push({
81
- fullPath: filePath,
82
- segments,
83
- commandModule: await importCommandFromFile(filePath, segments[segments.length - 1], fullOptions)
84
- });
93
+ const lastSegment = segments[segments.length - 1];
94
+ if (lastSegment === undefined) {
95
+ throw new Error(`No segments found for file: ${filePath}`);
85
96
  }
86
- }
97
+ return {
98
+ fullPath: filePath,
99
+ segments,
100
+ commandModule: await importCommandFromFile(filePath, lastSegment, fullOptions),
101
+ };
102
+ })));
103
+ commands.push(...fileResults);
87
104
  // check if no commands were found
88
105
  if (commands.length === 0) {
89
106
  throw new Error(`No commands found in specified directories: ${fullOptions.commandDirs.join(', ')}`);
@@ -96,3 +113,4 @@ export const fileCommands = async (options) => {
96
113
  const rootCommands = commandRootNodes.map((node) => createCommand(node));
97
114
  return rootCommands;
98
115
  };
116
+ //# sourceMappingURL=fileCommands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileCommands.js","sourceRoot":"","sources":["../../src/lib/fileCommands.ts"],"names":[],"mappings":"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"}