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 +45 -10
- package/package.json +1 -1
- package/test/cli.test.js +112 -1
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
40
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
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
|
});
|