fetch-client-generator 1.1.0 → 1.2.0

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/cli.js CHANGED
@@ -4,6 +4,7 @@ import { program } from 'commander';
4
4
  import { readFileSync, writeFileSync } from 'fs';
5
5
  import { fileURLToPath } from 'url';
6
6
  import path from 'path';
7
+ import chokidar from 'chokidar';
7
8
  import { generate } from '../index.js';
8
9
 
9
10
  const __filename = fileURLToPath(import.meta.url);
@@ -20,6 +21,7 @@ program
20
21
  .description('Generate fetch client code')
21
22
  .option('-i, --input <file>', 'input specification file')
22
23
  .option('-o, --output <file>', 'output file path')
24
+ .option('-w, --watch', 'watch input file for changes and regenerate automatically')
23
25
  .action((options) => {
24
26
  if (!options.input) {
25
27
  console.error('Error: Input file is required');
@@ -31,18 +33,51 @@ program
31
33
  process.exit(1);
32
34
  }
33
35
 
34
- try {
35
- console.log('Generating fetch client...');
36
- console.log('Input:', options.input);
37
- console.log('Output:', options.output);
36
+ const generateClient = () => {
37
+ try {
38
+ console.log('Generating fetch client...');
39
+ console.log('Input:', options.input);
40
+ console.log('Output:', options.output);
38
41
 
39
- const clientCode = generate(options.input);
40
- writeFileSync(options.output, clientCode, 'utf8');
42
+ const clientCode = generate(options.input);
43
+ writeFileSync(options.output, clientCode, 'utf8');
44
+
45
+ console.log('✓ Fetch client generated successfully!');
46
+ } catch (error) {
47
+ console.error('Error generating client:', error.message);
48
+ if (!options.watch) {
49
+ process.exit(1);
50
+ }
51
+ }
52
+ };
53
+
54
+ // Generate initially
55
+ generateClient();
56
+
57
+ // If watch flag is set, watch for changes
58
+ if (options.watch) {
59
+ console.log(`Watching ${options.input} for changes...`);
41
60
 
42
- console.log('✓ Fetch client generated successfully!');
43
- } catch (error) {
44
- console.error('Error generating client:', error.message);
45
- process.exit(1);
61
+ const watcher = chokidar.watch(options.input, {
62
+ persistent: true,
63
+ ignoreInitial: true
64
+ });
65
+
66
+ watcher.on('change', () => {
67
+ console.log('\nFile changed, regenerating...');
68
+ generateClient();
69
+ });
70
+
71
+ watcher.on('error', (error) => {
72
+ console.error('Watcher error:', error);
73
+ });
74
+
75
+ // Keep the process alive
76
+ process.on('SIGINT', () => {
77
+ console.log('\nStopping file watcher...');
78
+ watcher.close();
79
+ process.exit(0);
80
+ });
46
81
  }
47
82
  });
48
83
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fetch-client-generator",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A tool for generating fetch-based HTTP client code",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/test/cli.test.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { expect } from 'chai';
2
- import { exec } from 'child_process';
2
+ import { exec, spawn } from 'child_process';
3
3
  import path from 'path';
4
4
  import { fileURLToPath } from 'url';
5
+ import { writeFileSync, unlinkSync, existsSync, readFileSync } from 'fs';
5
6
 
6
7
  const __filename = fileURLToPath(import.meta.url);
7
8
  const __dirname = path.dirname(__filename);
@@ -23,4 +24,114 @@ describe('CLI', () => {
23
24
  done();
24
25
  });
25
26
  });
27
+
28
+ describe('watch functionality', () => {
29
+ const testInputPath = path.join(__dirname, 'test-input.json');
30
+ const testOutputPath = path.join(__dirname, 'test-output.js');
31
+ const sampleSpec = {
32
+ "openapi": "3.0.1",
33
+ "info": { "title": "Watch Test API", "version": "1.0.0" },
34
+ "paths": {
35
+ "/test": {
36
+ "get": {
37
+ "operationId": "getTest",
38
+ "responses": { "200": { "description": "OK" } }
39
+ }
40
+ }
41
+ }
42
+ };
43
+
44
+ beforeEach(() => {
45
+ writeFileSync(testInputPath, JSON.stringify(sampleSpec, null, 2));
46
+ });
47
+
48
+ afterEach(() => {
49
+ [testInputPath, testOutputPath].forEach(file => {
50
+ if (existsSync(file)) {
51
+ unlinkSync(file);
52
+ }
53
+ });
54
+ });
55
+
56
+ it('should regenerate client when input file changes', function(done) {
57
+ this.timeout(5000);
58
+
59
+ const cliPath = path.join(__dirname, '../bin/cli.js');
60
+ const child = spawn('node', [cliPath, 'generate', '-i', testInputPath, '-o', testOutputPath, '--watch'], {
61
+ stdio: ['pipe', 'pipe', 'pipe']
62
+ });
63
+
64
+ let outputReceived = false;
65
+ let regenerateReceived = false;
66
+
67
+ child.stdout.on('data', (data) => {
68
+ const output = data.toString();
69
+
70
+ if (output.includes('✓ Fetch client generated successfully!') && !outputReceived) {
71
+ outputReceived = true;
72
+ expect(existsSync(testOutputPath)).to.be.true;
73
+
74
+ setTimeout(() => {
75
+ const updatedSpec = { ...sampleSpec };
76
+ updatedSpec.info.title = "Updated Watch Test API";
77
+ writeFileSync(testInputPath, JSON.stringify(updatedSpec, null, 2));
78
+ }, 100);
79
+ }
80
+
81
+ if (output.includes('File changed, regenerating...') && !regenerateReceived) {
82
+ regenerateReceived = true;
83
+ }
84
+
85
+ if (outputReceived && regenerateReceived && output.includes('✓ Fetch client generated successfully!')) {
86
+ const clientCode = readFileSync(testOutputPath, 'utf8');
87
+ expect(clientCode).to.include('class ApiClient');
88
+ child.kill('SIGINT');
89
+ done();
90
+ }
91
+ });
92
+
93
+ child.stderr.on('data', (data) => {
94
+ console.error('CLI stderr:', data.toString());
95
+ });
96
+
97
+ child.on('error', (error) => {
98
+ done(error);
99
+ });
100
+ });
101
+
102
+ it('should handle watch mode with invalid input gracefully', function(done) {
103
+ this.timeout(3000);
104
+
105
+ const cliPath = path.join(__dirname, '../bin/cli.js');
106
+ const child = spawn('node', [cliPath, 'generate', '-i', testInputPath, '-o', testOutputPath, '--watch'], {
107
+ stdio: ['pipe', 'pipe', 'pipe']
108
+ });
109
+
110
+ let initialGeneration = false;
111
+
112
+ child.stdout.on('data', (data) => {
113
+ const output = data.toString();
114
+
115
+ if (output.includes('✓ Fetch client generated successfully!') && !initialGeneration) {
116
+ initialGeneration = true;
117
+
118
+ setTimeout(() => {
119
+ writeFileSync(testInputPath, 'invalid json');
120
+ }, 100);
121
+ }
122
+ });
123
+
124
+ child.stderr.on('data', (data) => {
125
+ const errorOutput = data.toString();
126
+ if (errorOutput.includes('Error generating client:')) {
127
+ child.kill('SIGINT');
128
+ done();
129
+ }
130
+ });
131
+
132
+ child.on('error', (error) => {
133
+ done(error);
134
+ });
135
+ });
136
+ });
26
137
  });