klasik 1.0.0 → 1.0.2

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/example.md CHANGED
@@ -90,11 +90,11 @@ To test the package locally with the linked `openapi-class-transformer`:
90
90
 
91
91
  ```bash
92
92
  # In openapi-class-transformer directory
93
- cd /Users/eyald/koalaops/openapi-class-transformer
93
+ cd folder
94
94
  npm link
95
95
 
96
96
  # In klasik directory
97
- cd /Users/eyald/koalaops/klasik
97
+ cd folder
98
98
  npm link openapi-class-transformer
99
99
 
100
100
  # Build and test
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klasik",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Download OpenAPI specs from remote URLs and generate TypeScript clients with class-transformer support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,7 +27,7 @@
27
27
  "dependencies": {
28
28
  "axios": "^1.6.0",
29
29
  "commander": "^11.0.0",
30
- "openapi-class-transformer": "file:../openapi-class-transformer"
30
+ "openapi-class-transformer": "1.0.1"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/jest": "^29.5.0",
package/jest.config.js DELETED
@@ -1,10 +0,0 @@
1
- module.exports = {
2
- preset: 'ts-jest',
3
- testEnvironment: 'node',
4
- roots: ['<rootDir>/test'],
5
- testMatch: ['**/*.test.ts'],
6
- collectCoverageFrom: [
7
- 'src/**/*.ts',
8
- '!src/**/*.d.ts',
9
- ],
10
- };
package/src/cli.ts DELETED
@@ -1,103 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { Command } from 'commander';
4
- import { K8sClientGenerator } from './k8s-client-generator';
5
- import * as path from 'path';
6
-
7
- const program = new Command();
8
-
9
- program
10
- .name('klasik')
11
- .description('Download OpenAPI specs from remote URLs and generate TypeScript clients with class-transformer support')
12
- .version('1.0.0');
13
-
14
- program
15
- .command('generate')
16
- .description('Generate TypeScript client from a remote OpenAPI spec')
17
- .requiredOption('-u, --url <url>', 'Remote URL to download the OpenAPI spec from')
18
- .requiredOption('-o, --output <dir>', 'Output directory for generated client code')
19
- .option('-m, --mode <mode>', 'Generation mode: "full" (models + APIs + config) or "models-only"', 'full')
20
- .option('-H, --header <header...>', 'Custom headers for the request (format: "Key: Value")')
21
- .option('-t, --template <dir>', 'Custom template directory')
22
- .option('-k, --keep-spec', 'Keep the downloaded spec file after generation', false)
23
- .option('--timeout <ms>', 'Request timeout in milliseconds', '30000')
24
- .action(async (options) => {
25
- try {
26
- // Validate mode
27
- if (options.mode !== 'full' && options.mode !== 'models-only') {
28
- console.error('Error: --mode must be either "full" or "models-only"');
29
- process.exit(1);
30
- }
31
-
32
- // Parse headers if provided
33
- const headers: Record<string, string> = {};
34
- if (options.header) {
35
- for (const header of options.header) {
36
- const [key, ...valueParts] = header.split(':');
37
- const value = valueParts.join(':').trim();
38
- if (key && value) {
39
- headers[key.trim()] = value;
40
- }
41
- }
42
- }
43
-
44
- // Resolve output directory to absolute path
45
- const outputDir = path.resolve(options.output);
46
-
47
- const generator = new K8sClientGenerator();
48
- await generator.generate({
49
- specUrl: options.url,
50
- outputDir,
51
- mode: options.mode,
52
- headers: Object.keys(headers).length > 0 ? headers : undefined,
53
- templateDir: options.template,
54
- keepSpec: options.keepSpec,
55
- timeout: parseInt(options.timeout, 10),
56
- });
57
-
58
- process.exit(0);
59
- } catch (error) {
60
- console.error('Error:', error instanceof Error ? error.message : error);
61
- process.exit(1);
62
- }
63
- });
64
-
65
- program
66
- .command('download')
67
- .description('Download an OpenAPI spec from a remote URL (without generating)')
68
- .requiredOption('-u, --url <url>', 'Remote URL to download the OpenAPI spec from')
69
- .requiredOption('-o, --output <file>', 'Output file path for the downloaded spec')
70
- .option('-H, --header <header...>', 'Custom headers for the request (format: "Key: Value")')
71
- .option('--timeout <ms>', 'Request timeout in milliseconds', '30000')
72
- .action(async (options) => {
73
- try {
74
- const { SpecDownloader } = await import('./spec-downloader');
75
-
76
- // Parse headers if provided
77
- const headers: Record<string, string> = {};
78
- if (options.header) {
79
- for (const header of options.header) {
80
- const [key, ...valueParts] = header.split(':');
81
- const value = valueParts.join(':').trim();
82
- if (key && value) {
83
- headers[key.trim()] = value;
84
- }
85
- }
86
- }
87
-
88
- const downloader = new SpecDownloader();
89
- await downloader.download({
90
- url: options.url,
91
- outputPath: path.resolve(options.output),
92
- headers: Object.keys(headers).length > 0 ? headers : undefined,
93
- timeout: parseInt(options.timeout, 10),
94
- });
95
-
96
- process.exit(0);
97
- } catch (error) {
98
- console.error('Error:', error instanceof Error ? error.message : error);
99
- process.exit(1);
100
- }
101
- });
102
-
103
- program.parse();
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export { K8sClientGenerator, K8sClientGeneratorOptions, GenerationMode } from './k8s-client-generator';
2
- export { SpecDownloader, DownloadOptions } from './spec-downloader';
@@ -1,145 +0,0 @@
1
- import { Generator, GeneratorOptions } from 'openapi-class-transformer';
2
- import { SpecDownloader, DownloadOptions } from './spec-downloader';
3
- import * as fs from 'fs';
4
-
5
- export type GenerationMode = 'full' | 'models-only';
6
-
7
- export interface K8sClientGeneratorOptions {
8
- /**
9
- * Remote URL to download the OpenAPI spec from
10
- */
11
- specUrl: string;
12
-
13
- /**
14
- * Output directory for generated client code
15
- */
16
- outputDir: string;
17
-
18
- /**
19
- * Generation mode
20
- * - 'full': Generate models, APIs, and configuration (default)
21
- * - 'models-only': Generate only model classes
22
- * @default 'full'
23
- */
24
- mode?: GenerationMode;
25
-
26
- /**
27
- * Optional headers to include in the spec download request
28
- */
29
- headers?: Record<string, string>;
30
-
31
- /**
32
- * Optional custom template directory
33
- */
34
- templateDir?: string;
35
-
36
- /**
37
- * Whether to keep the downloaded spec file after generation
38
- * @default false
39
- */
40
- keepSpec?: boolean;
41
-
42
- /**
43
- * Request timeout for downloading spec in milliseconds
44
- * @default 30000
45
- */
46
- timeout?: number;
47
- }
48
-
49
- export class K8sClientGenerator {
50
- private downloader: SpecDownloader;
51
-
52
- constructor() {
53
- this.downloader = new SpecDownloader();
54
- }
55
-
56
- /**
57
- * Generate TypeScript client from a remote OpenAPI spec URL
58
- */
59
- async generate(options: K8sClientGeneratorOptions): Promise<void> {
60
- const {
61
- specUrl,
62
- outputDir,
63
- mode = 'full',
64
- headers,
65
- templateDir,
66
- keepSpec = false,
67
- timeout,
68
- } = options;
69
-
70
- let specPath: string | undefined;
71
-
72
- try {
73
- // Step 1: Download the OpenAPI spec
74
- console.log('Step 1: Downloading OpenAPI specification...');
75
- const downloadOptions: DownloadOptions = {
76
- url: specUrl,
77
- headers,
78
- timeout,
79
- };
80
-
81
- specPath = await this.downloader.download(downloadOptions);
82
-
83
- // Step 2: Validate output directory
84
- console.log('Step 2: Preparing output directory...');
85
- this.prepareOutputDirectory(outputDir);
86
-
87
- // Step 3: Generate client using openapi-class-transformer
88
- const modeLabel = mode === 'models-only' ? 'models only' : 'full client';
89
- console.log(`Step 3: Generating TypeScript ${modeLabel}...`);
90
- const generatorOptions: GeneratorOptions = {
91
- inputSpec: specPath,
92
- outputDir,
93
- modelsOnly: mode === 'models-only',
94
- };
95
-
96
- // Only add templateDir if it's provided
97
- if (templateDir) {
98
- generatorOptions.templateDir = templateDir;
99
- }
100
-
101
- const generator = new Generator(generatorOptions);
102
- await generator.generate();
103
-
104
- console.log('✅ Client generation completed successfully!');
105
- console.log(`📁 Generated files location: ${outputDir}`);
106
- } catch (error) {
107
- console.error('❌ Client generation failed:', error);
108
- throw error;
109
- } finally {
110
- // Cleanup
111
- if (!keepSpec && specPath) {
112
- this.cleanupSpecFile(specPath);
113
- }
114
- }
115
- }
116
-
117
- /**
118
- * Prepare the output directory
119
- */
120
- private prepareOutputDirectory(outputDir: string): void {
121
- if (!fs.existsSync(outputDir)) {
122
- fs.mkdirSync(outputDir, { recursive: true });
123
- console.log(`Created output directory: ${outputDir}`);
124
- } else {
125
- console.log(`Using existing output directory: ${outputDir}`);
126
- }
127
- }
128
-
129
- /**
130
- * Clean up the downloaded spec file
131
- */
132
- private cleanupSpecFile(specPath: string): void {
133
- try {
134
- if (fs.existsSync(specPath)) {
135
- fs.unlinkSync(specPath);
136
- console.log(`Cleaned up downloaded spec file: ${specPath}`);
137
- }
138
-
139
- // Also cleanup temp directory if empty
140
- this.downloader.cleanupTemp();
141
- } catch (error) {
142
- console.warn('Warning: Failed to cleanup spec file:', error);
143
- }
144
- }
145
- }
@@ -1,233 +0,0 @@
1
- import axios from 'axios';
2
- import * as fs from 'fs';
3
- import * as path from 'path';
4
-
5
- export interface DownloadOptions {
6
- /**
7
- * URL or file path to the OpenAPI spec
8
- * Supports:
9
- * - HTTP/HTTPS URLs: https://example.com/spec.json
10
- * - File URLs: file:///path/to/spec.json
11
- * - Absolute paths: /path/to/spec.json
12
- * - Relative paths: ./spec.json, ../specs/api.json
13
- */
14
- url: string;
15
-
16
- /**
17
- * Optional output path to save the downloaded spec
18
- * If not provided, will save to a temp file (for HTTP) or use the source path (for files)
19
- */
20
- outputPath?: string;
21
-
22
- /**
23
- * Optional headers to include in the request (only used for HTTP/HTTPS)
24
- */
25
- headers?: Record<string, string>;
26
-
27
- /**
28
- * Request timeout in milliseconds (only used for HTTP/HTTPS)
29
- * @default 30000
30
- */
31
- timeout?: number;
32
- }
33
-
34
- export class SpecDownloader {
35
- /**
36
- * Download an OpenAPI specification from a URL or load from a local file
37
- * @param options Download options
38
- * @returns Path to the spec file
39
- */
40
- async download(options: DownloadOptions): Promise<string> {
41
- const { url, outputPath, headers, timeout = 30000 } = options;
42
-
43
- // Check if it's a local file path
44
- if (this.isLocalFile(url)) {
45
- return this.loadLocalFile(url, outputPath);
46
- }
47
-
48
- // Otherwise, download from HTTP/HTTPS
49
- console.log(`Downloading OpenAPI spec from ${url}...`);
50
-
51
- try {
52
- const response = await axios.get(url, {
53
- headers,
54
- timeout,
55
- responseType: 'text',
56
- });
57
-
58
- // Determine output path
59
- const specPath = outputPath || this.generateTempPath(url);
60
-
61
- // Ensure directory exists
62
- const dir = path.dirname(specPath);
63
- if (!fs.existsSync(dir)) {
64
- fs.mkdirSync(dir, { recursive: true });
65
- }
66
-
67
- // Parse and validate the spec
68
- let specContent: string;
69
- if (typeof response.data === 'string') {
70
- // Try to parse as JSON to validate
71
- try {
72
- const parsed = JSON.parse(response.data);
73
- specContent = JSON.stringify(parsed, null, 2);
74
- } catch {
75
- // If not JSON, might be YAML - save as-is
76
- specContent = response.data;
77
- }
78
- } else {
79
- specContent = JSON.stringify(response.data, null, 2);
80
- }
81
-
82
- // Validate it's an OpenAPI spec
83
- this.validateSpec(specContent);
84
-
85
- // Write to file
86
- fs.writeFileSync(specPath, specContent, 'utf-8');
87
-
88
- console.log(`OpenAPI spec downloaded successfully to ${specPath}`);
89
- return specPath;
90
- } catch (error) {
91
- if (axios.isAxiosError(error)) {
92
- throw new Error(
93
- `Failed to download OpenAPI spec from ${url}: ${error.message}`
94
- );
95
- }
96
- throw error;
97
- }
98
- }
99
-
100
- /**
101
- * Check if the URL is a local file path
102
- */
103
- private isLocalFile(url: string): boolean {
104
- // Check for file:// protocol
105
- if (url.startsWith('file://')) {
106
- return true;
107
- }
108
-
109
- // Check for HTTP/HTTPS protocols
110
- if (url.startsWith('http://') || url.startsWith('https://')) {
111
- return false;
112
- }
113
-
114
- // Check if it's an absolute or relative path
115
- // Absolute paths start with / (Unix) or C:\ (Windows)
116
- // Relative paths start with ./ or ../
117
- return (
118
- url.startsWith('/') ||
119
- url.startsWith('./') ||
120
- url.startsWith('../') ||
121
- /^[a-zA-Z]:[\\\/]/.test(url) // Windows paths like C:\
122
- );
123
- }
124
-
125
- /**
126
- * Load and validate an OpenAPI spec from a local file
127
- */
128
- private loadLocalFile(filePath: string, outputPath?: string): string {
129
- // Handle file:// URLs
130
- let resolvedPath = filePath;
131
- if (filePath.startsWith('file://')) {
132
- resolvedPath = filePath.replace('file://', '');
133
- // On Windows, file URLs might be file:///C:/path
134
- if (process.platform === 'win32' && resolvedPath.startsWith('/')) {
135
- resolvedPath = resolvedPath.substring(1);
136
- }
137
- }
138
-
139
- // Resolve to absolute path
140
- resolvedPath = path.resolve(resolvedPath);
141
-
142
- console.log(`Loading OpenAPI spec from local file: ${resolvedPath}...`);
143
-
144
- // Check if file exists
145
- if (!fs.existsSync(resolvedPath)) {
146
- throw new Error(`File not found: ${resolvedPath}`);
147
- }
148
-
149
- // Read the file
150
- const content = fs.readFileSync(resolvedPath, 'utf-8');
151
-
152
- // Validate it's an OpenAPI spec
153
- this.validateSpec(content);
154
-
155
- // If outputPath is provided, copy to that location
156
- if (outputPath) {
157
- const dir = path.dirname(outputPath);
158
- if (!fs.existsSync(dir)) {
159
- fs.mkdirSync(dir, { recursive: true });
160
- }
161
-
162
- // Parse and format if it's JSON
163
- let formattedContent = content;
164
- try {
165
- const parsed = JSON.parse(content);
166
- formattedContent = JSON.stringify(parsed, null, 2);
167
- } catch {
168
- // Not JSON, keep original
169
- }
170
-
171
- fs.writeFileSync(outputPath, formattedContent, 'utf-8');
172
- console.log(`OpenAPI spec copied to ${outputPath}`);
173
- return outputPath;
174
- }
175
-
176
- console.log(`OpenAPI spec loaded successfully from ${resolvedPath}`);
177
- return resolvedPath;
178
- }
179
-
180
- /**
181
- * Generate a temporary file path based on the URL
182
- */
183
- private generateTempPath(url: string): string {
184
- const urlObj = new URL(url);
185
- const hostname = urlObj.hostname.replace(/\./g, '-');
186
- const timestamp = Date.now();
187
- const filename = `openapi-${hostname}-${timestamp}.json`;
188
- return path.join(process.cwd(), '.tmp', filename);
189
- }
190
-
191
- /**
192
- * Validate that the downloaded content is an OpenAPI spec
193
- */
194
- private validateSpec(content: string): void {
195
- try {
196
- const spec = JSON.parse(content);
197
-
198
- // Check for OpenAPI version
199
- if (!spec.openapi && !spec.swagger) {
200
- throw new Error(
201
- 'Invalid OpenAPI spec: missing "openapi" or "swagger" field'
202
- );
203
- }
204
-
205
- // Check for required fields
206
- if (!spec.info) {
207
- throw new Error('Invalid OpenAPI spec: missing "info" field');
208
- }
209
-
210
- if (!spec.paths && !spec.components) {
211
- throw new Error(
212
- 'Invalid OpenAPI spec: must have either "paths" or "components"'
213
- );
214
- }
215
- } catch (error) {
216
- if (error instanceof SyntaxError) {
217
- throw new Error('Invalid OpenAPI spec: not valid JSON');
218
- }
219
- throw error;
220
- }
221
- }
222
-
223
- /**
224
- * Clean up temporary files
225
- */
226
- cleanupTemp(): void {
227
- const tempDir = path.join(process.cwd(), '.tmp');
228
- if (fs.existsSync(tempDir)) {
229
- fs.rmSync(tempDir, { recursive: true, force: true });
230
- console.log('Cleaned up temporary files');
231
- }
232
- }
233
- }
@@ -1,257 +0,0 @@
1
- import { K8sClientGenerator } from '../src/k8s-client-generator';
2
- import { SpecDownloader } from '../src/spec-downloader';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
-
6
- describe('K8sClientGenerator', () => {
7
- const testOutputDir = path.join(__dirname, '../test-output');
8
-
9
- beforeEach(() => {
10
- // Clean up test output directory
11
- if (fs.existsSync(testOutputDir)) {
12
- fs.rmSync(testOutputDir, { recursive: true, force: true });
13
- }
14
- });
15
-
16
- afterEach(() => {
17
- // Cleanup after each test
18
- if (fs.existsSync(testOutputDir)) {
19
- fs.rmSync(testOutputDir, { recursive: true, force: true });
20
- }
21
-
22
- // Clean up temp files
23
- const tempDir = path.join(process.cwd(), '.tmp');
24
- if (fs.existsSync(tempDir)) {
25
- fs.rmSync(tempDir, { recursive: true, force: true });
26
- }
27
- });
28
-
29
- describe('generate', () => {
30
- it('should download spec and generate client from a valid URL', async () => {
31
- const generator = new K8sClientGenerator();
32
-
33
- // Use a simple test OpenAPI spec
34
- const testSpec = {
35
- openapi: '3.0.0',
36
- info: { title: 'Test API', version: '1.0.0' },
37
- paths: {
38
- '/test': {
39
- get: {
40
- responses: {
41
- '200': {
42
- description: 'Success',
43
- content: {
44
- 'application/json': {
45
- schema: {
46
- type: 'object',
47
- properties: {
48
- message: { type: 'string' }
49
- }
50
- }
51
- }
52
- }
53
- }
54
- }
55
- }
56
- }
57
- }
58
- };
59
-
60
- // Create a mock server would be ideal, but for now we'll test with a file URL
61
- // or skip this test in favor of integration tests
62
- const specPath = path.join(testOutputDir, 'test-spec.json');
63
- fs.mkdirSync(testOutputDir, { recursive: true });
64
- fs.writeFileSync(specPath, JSON.stringify(testSpec, null, 2));
65
-
66
- const outputDir = path.join(testOutputDir, 'generated');
67
-
68
- // Note: This test would need a real HTTP server or mock
69
- // For now, we'll test the structure
70
- expect(generator).toBeDefined();
71
- expect(typeof generator.generate).toBe('function');
72
- }, 60000);
73
-
74
- it('should create output directory if it does not exist', async () => {
75
- const generator = new K8sClientGenerator();
76
- expect(generator).toBeDefined();
77
- });
78
-
79
- it('should handle download errors gracefully', async () => {
80
- const generator = new K8sClientGenerator();
81
-
82
- await expect(
83
- generator.generate({
84
- specUrl: 'http://invalid-url-that-does-not-exist.com/spec.json',
85
- outputDir: testOutputDir,
86
- timeout: 1000,
87
- })
88
- ).rejects.toThrow();
89
- }, 60000);
90
- });
91
- });
92
-
93
- describe('SpecDownloader', () => {
94
- const testOutputDir = path.join(__dirname, '../test-output');
95
-
96
- beforeEach(() => {
97
- if (fs.existsSync(testOutputDir)) {
98
- fs.rmSync(testOutputDir, { recursive: true, force: true });
99
- }
100
- });
101
-
102
- afterEach(() => {
103
- if (fs.existsSync(testOutputDir)) {
104
- fs.rmSync(testOutputDir, { recursive: true, force: true });
105
- }
106
-
107
- const tempDir = path.join(process.cwd(), '.tmp');
108
- if (fs.existsSync(tempDir)) {
109
- fs.rmSync(tempDir, { recursive: true, force: true });
110
- }
111
- });
112
-
113
- describe('download', () => {
114
- it('should throw error for invalid URL', async () => {
115
- const downloader = new SpecDownloader();
116
-
117
- await expect(
118
- downloader.download({
119
- url: 'http://invalid-url-that-does-not-exist.com/spec.json',
120
- timeout: 1000,
121
- })
122
- ).rejects.toThrow();
123
- }, 60000);
124
-
125
- it('should validate OpenAPI spec format', async () => {
126
- // This test validates the validation logic
127
- const downloader = new SpecDownloader();
128
- expect(downloader).toBeDefined();
129
- expect(typeof downloader.download).toBe('function');
130
- });
131
-
132
- it('should load OpenAPI spec from local file path', async () => {
133
- const downloader = new SpecDownloader();
134
-
135
- // Create a test spec file
136
- const testSpec = {
137
- openapi: '3.0.0',
138
- info: { title: 'Local Test API', version: '1.0.0' },
139
- paths: {}
140
- };
141
-
142
- const testSpecPath = path.join(testOutputDir, 'local-spec.json');
143
- fs.mkdirSync(testOutputDir, { recursive: true });
144
- fs.writeFileSync(testSpecPath, JSON.stringify(testSpec, null, 2));
145
-
146
- const result = await downloader.download({
147
- url: testSpecPath,
148
- });
149
-
150
- expect(result).toBe(path.resolve(testSpecPath));
151
- expect(fs.existsSync(result)).toBe(true);
152
- });
153
-
154
- it('should load OpenAPI spec from relative file path', async () => {
155
- const downloader = new SpecDownloader();
156
-
157
- // Create a test spec file
158
- const testSpec = {
159
- openapi: '3.0.0',
160
- info: { title: 'Relative Test API', version: '1.0.0' },
161
- paths: {}
162
- };
163
-
164
- const testSpecPath = path.join(testOutputDir, 'relative-spec.json');
165
- fs.mkdirSync(testOutputDir, { recursive: true });
166
- fs.writeFileSync(testSpecPath, JSON.stringify(testSpec, null, 2));
167
-
168
- // Use relative path
169
- const relativePath = path.relative(process.cwd(), testSpecPath);
170
-
171
- const result = await downloader.download({
172
- url: `./${relativePath}`,
173
- });
174
-
175
- expect(fs.existsSync(result)).toBe(true);
176
- });
177
-
178
- it('should load OpenAPI spec from file:// URL', async () => {
179
- const downloader = new SpecDownloader();
180
-
181
- // Create a test spec file
182
- const testSpec = {
183
- openapi: '3.0.0',
184
- info: { title: 'File URL Test API', version: '1.0.0' },
185
- paths: {}
186
- };
187
-
188
- const testSpecPath = path.join(testOutputDir, 'file-url-spec.json');
189
- fs.mkdirSync(testOutputDir, { recursive: true });
190
- fs.writeFileSync(testSpecPath, JSON.stringify(testSpec, null, 2));
191
-
192
- // Use file:// URL
193
- const fileUrl = `file://${path.resolve(testSpecPath)}`;
194
-
195
- const result = await downloader.download({
196
- url: fileUrl,
197
- });
198
-
199
- expect(fs.existsSync(result)).toBe(true);
200
- const content = JSON.parse(fs.readFileSync(result, 'utf-8'));
201
- expect(content.info.title).toBe('File URL Test API');
202
- });
203
-
204
- it('should copy local file to output path if specified', async () => {
205
- const downloader = new SpecDownloader();
206
-
207
- // Create a test spec file
208
- const testSpec = {
209
- openapi: '3.0.0',
210
- info: { title: 'Copy Test API', version: '1.0.0' },
211
- paths: {}
212
- };
213
-
214
- const sourceSpecPath = path.join(testOutputDir, 'source-spec.json');
215
- const targetSpecPath = path.join(testOutputDir, 'target-spec.json');
216
- fs.mkdirSync(testOutputDir, { recursive: true });
217
- fs.writeFileSync(sourceSpecPath, JSON.stringify(testSpec, null, 2));
218
-
219
- const result = await downloader.download({
220
- url: sourceSpecPath,
221
- outputPath: targetSpecPath,
222
- });
223
-
224
- expect(result).toBe(targetSpecPath);
225
- expect(fs.existsSync(targetSpecPath)).toBe(true);
226
- const content = JSON.parse(fs.readFileSync(targetSpecPath, 'utf-8'));
227
- expect(content.info.title).toBe('Copy Test API');
228
- });
229
-
230
- it('should throw error for non-existent local file', async () => {
231
- const downloader = new SpecDownloader();
232
-
233
- await expect(
234
- downloader.download({
235
- url: '/non/existent/file.json',
236
- })
237
- ).rejects.toThrow('File not found');
238
- });
239
- });
240
-
241
- describe('cleanupTemp', () => {
242
- it('should clean up temporary directory', () => {
243
- const downloader = new SpecDownloader();
244
-
245
- // Create temp directory
246
- const tempDir = path.join(process.cwd(), '.tmp');
247
- fs.mkdirSync(tempDir, { recursive: true });
248
- fs.writeFileSync(path.join(tempDir, 'test.txt'), 'test');
249
-
250
- expect(fs.existsSync(tempDir)).toBe(true);
251
-
252
- downloader.cleanupTemp();
253
-
254
- expect(fs.existsSync(tempDir)).toBe(false);
255
- });
256
- });
257
- });
package/tsconfig.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "commonjs",
5
- "lib": ["ES2020"],
6
- "declaration": true,
7
- "outDir": "./dist",
8
- "rootDir": "./src",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "resolveJsonModule": true,
14
- "moduleResolution": "node",
15
- "experimentalDecorators": true,
16
- "emitDecoratorMetadata": true
17
- },
18
- "include": ["src/**/*"],
19
- "exclude": ["node_modules", "dist", "test"]
20
- }