klasik 1.0.13 → 1.0.14

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/README.md CHANGED
@@ -6,6 +6,7 @@ Download OpenAPI specifications from remote URLs and generate TypeScript clients
6
6
 
7
7
  - 📥 **Download OpenAPI specs** from remote URLs or local files
8
8
  - 📁 **Multiple input formats** - HTTP/HTTPS URLs, file:// URLs, absolute/relative paths
9
+ - 📄 **JSON and YAML support** - Automatically parse and handle both formats
9
10
  - 🔐 **Authentication support** - Custom headers including Bearer tokens and API keys
10
11
  - 🔗 **External reference resolution** - Automatically download referenced schema files (`$ref`)
11
12
  - 🔄 **Automatic transformation** - Converts API responses to class instances using class-transformer
@@ -27,17 +28,23 @@ npm install klasik
27
28
  Generate a TypeScript client from a remote OpenAPI spec:
28
29
 
29
30
  ```bash
31
+ # JSON spec
30
32
  npx klasik generate \
31
33
  --url https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json \
32
34
  --output ./k8s-client
35
+
36
+ # YAML spec
37
+ npx klasik generate \
38
+ --url https://api.example.com/openapi.yaml \
39
+ --output ./client
33
40
  ```
34
41
 
35
- Generate from a local OpenAPI spec file:
42
+ Generate from a local OpenAPI spec file (JSON or YAML):
36
43
 
37
44
  ```bash
38
45
  # Absolute path
39
46
  npx klasik generate \
40
- --url /path/to/openapi.json \
47
+ --url /path/to/openapi.yaml \
41
48
  --output ./client
42
49
 
43
50
  # Relative path
@@ -47,16 +54,22 @@ npx klasik generate \
47
54
 
48
55
  # file:// URL
49
56
  npx klasik generate \
50
- --url file:///path/to/openapi.json \
57
+ --url file:///path/to/openapi.yaml \
51
58
  --output ./client
52
59
  ```
53
60
 
54
- Download an OpenAPI spec without generating:
61
+ Download an OpenAPI spec without generating (supports JSON and YAML):
55
62
 
56
63
  ```bash
64
+ # Download JSON spec
57
65
  npx klasik download \
58
66
  --url https://api.example.com/openapi.json \
59
67
  --output ./specs/api-spec.json
68
+
69
+ # Download YAML spec
70
+ npx klasik download \
71
+ --url https://api.example.com/openapi.yaml \
72
+ --output ./specs/api-spec.yaml
60
73
  ```
61
74
 
62
75
  ### Programmatic Usage
package/USAGE_EXAMPLES.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # Klasik Usage Examples
2
2
 
3
+ ## JSON and YAML Support
4
+
5
+ Klasik automatically detects and parses both JSON and YAML OpenAPI specifications. The original format is preserved when downloading.
6
+
7
+ ### CLI Examples
8
+
9
+ ```bash
10
+ # JSON spec
11
+ npx klasik generate \
12
+ --url https://api.example.com/openapi.json \
13
+ --output ./client
14
+
15
+ # YAML spec
16
+ npx klasik generate \
17
+ --url https://api.example.com/openapi.yaml \
18
+ --output ./client
19
+
20
+ # Local YAML file
21
+ npx klasik generate \
22
+ --url ./specs/openapi.yaml \
23
+ --output ./client
24
+
25
+ # Download and keep YAML format
26
+ npx klasik download \
27
+ --url https://api.example.com/openapi.yaml \
28
+ --output ./specs/api-spec.yaml \
29
+ --resolve-refs
30
+ ```
31
+
32
+ ### Programmatic Examples
33
+
34
+ ```typescript
35
+ import { K8sClientGenerator } from 'klasik';
36
+
37
+ // Works with both JSON and YAML
38
+ await new K8sClientGenerator().generate({
39
+ specUrl: 'https://api.example.com/openapi.yaml',
40
+ outputDir: './client'
41
+ });
42
+ ```
43
+
44
+ ### Mixed Formats with References
45
+
46
+ Klasik handles specs where the main file is in one format and referenced files are in another:
47
+
48
+ ```yaml
49
+ # openapi.yaml (main spec in YAML)
50
+ openapi: 3.0.0
51
+ paths:
52
+ /users:
53
+ get:
54
+ responses:
55
+ '200':
56
+ content:
57
+ application/json:
58
+ schema:
59
+ $ref: './schemas/users.json#/components/schemas/User' # JSON reference
60
+ ```
61
+
62
+ Both formats work seamlessly together!
63
+
3
64
  ## Using Custom Headers (Authorization)
4
65
 
5
66
  ### CLI Example - Authorization Token
@@ -54,7 +54,7 @@ export declare class SpecDownloader {
54
54
  */
55
55
  private generateTempPath;
56
56
  /**
57
- * Validate that the downloaded content is an OpenAPI spec
57
+ * Validate that the parsed content is an OpenAPI spec
58
58
  */
59
59
  private validateSpec;
60
60
  /**
@@ -40,6 +40,7 @@ exports.SpecDownloader = void 0;
40
40
  const axios_1 = __importDefault(require("axios"));
41
41
  const fs = __importStar(require("fs"));
42
42
  const path = __importStar(require("path"));
43
+ const yaml = __importStar(require("js-yaml"));
43
44
  class SpecDownloader {
44
45
  constructor() {
45
46
  this.downloadedRefs = new Set();
@@ -78,22 +79,31 @@ class SpecDownloader {
78
79
  }
79
80
  // Parse and validate the spec
80
81
  let specContent;
82
+ let parsedSpec;
81
83
  if (typeof response.data === 'string') {
82
- // Try to parse as JSON to validate
84
+ // Try to parse as JSON first
83
85
  try {
84
- const parsed = JSON.parse(response.data);
85
- specContent = JSON.stringify(parsed, null, 2);
86
+ parsedSpec = JSON.parse(response.data);
87
+ specContent = JSON.stringify(parsedSpec, null, 2);
86
88
  }
87
89
  catch {
88
- // If not JSON, might be YAML - save as-is
89
- specContent = response.data;
90
+ // If not JSON, try YAML
91
+ try {
92
+ parsedSpec = yaml.load(response.data);
93
+ // Keep YAML format if input was YAML
94
+ specContent = response.data;
95
+ }
96
+ catch {
97
+ throw new Error('Failed to parse spec: not valid JSON or YAML');
98
+ }
90
99
  }
91
100
  }
92
101
  else {
102
+ parsedSpec = response.data;
93
103
  specContent = JSON.stringify(response.data, null, 2);
94
104
  }
95
105
  // Validate it's an OpenAPI spec
96
- this.validateSpec(specContent);
106
+ this.validateSpec(parsedSpec);
97
107
  // Write to file
98
108
  fs.writeFileSync(specPath, specContent, 'utf-8');
99
109
  console.log(`OpenAPI spec downloaded successfully to ${specPath}`);
@@ -154,24 +164,29 @@ class SpecDownloader {
154
164
  }
155
165
  // Read the file
156
166
  const content = fs.readFileSync(resolvedPath, 'utf-8');
167
+ // Parse the content (JSON or YAML)
168
+ let parsedSpec;
169
+ try {
170
+ parsedSpec = JSON.parse(content);
171
+ }
172
+ catch {
173
+ try {
174
+ parsedSpec = yaml.load(content);
175
+ }
176
+ catch {
177
+ throw new Error(`Failed to parse spec at ${resolvedPath}: not valid JSON or YAML`);
178
+ }
179
+ }
157
180
  // Validate it's an OpenAPI spec
158
- this.validateSpec(content);
181
+ this.validateSpec(parsedSpec);
159
182
  // If outputPath is provided, copy to that location
160
183
  if (outputPath) {
161
184
  const dir = path.dirname(outputPath);
162
185
  if (!fs.existsSync(dir)) {
163
186
  fs.mkdirSync(dir, { recursive: true });
164
187
  }
165
- // Parse and format if it's JSON
166
- let formattedContent = content;
167
- try {
168
- const parsed = JSON.parse(content);
169
- formattedContent = JSON.stringify(parsed, null, 2);
170
- }
171
- catch {
172
- // Not JSON, keep original
173
- }
174
- fs.writeFileSync(outputPath, formattedContent, 'utf-8');
188
+ // Keep the original format (JSON or YAML)
189
+ fs.writeFileSync(outputPath, content, 'utf-8');
175
190
  console.log(`OpenAPI spec copied to ${outputPath}`);
176
191
  return outputPath;
177
192
  }
@@ -189,28 +204,22 @@ class SpecDownloader {
189
204
  return path.join(process.cwd(), '.tmp', filename);
190
205
  }
191
206
  /**
192
- * Validate that the downloaded content is an OpenAPI spec
207
+ * Validate that the parsed content is an OpenAPI spec
193
208
  */
194
- validateSpec(content) {
195
- try {
196
- const spec = JSON.parse(content);
197
- // Check for OpenAPI version
198
- if (!spec.openapi && !spec.swagger) {
199
- throw new Error('Invalid OpenAPI spec: missing "openapi" or "swagger" field');
200
- }
201
- // Check for required fields
202
- if (!spec.info) {
203
- throw new Error('Invalid OpenAPI spec: missing "info" field');
204
- }
205
- if (!spec.paths && !spec.components) {
206
- throw new Error('Invalid OpenAPI spec: must have either "paths" or "components"');
207
- }
209
+ validateSpec(spec) {
210
+ if (!spec || typeof spec !== 'object') {
211
+ throw new Error('Invalid OpenAPI spec: not a valid object');
208
212
  }
209
- catch (error) {
210
- if (error instanceof SyntaxError) {
211
- throw new Error('Invalid OpenAPI spec: not valid JSON');
212
- }
213
- throw error;
213
+ // Check for OpenAPI version
214
+ if (!spec.openapi && !spec.swagger) {
215
+ throw new Error('Invalid OpenAPI spec: missing "openapi" or "swagger" field');
216
+ }
217
+ // Check for required fields
218
+ if (!spec.info) {
219
+ throw new Error('Invalid OpenAPI spec: missing "info" field');
220
+ }
221
+ if (!spec.paths && !spec.components) {
222
+ throw new Error('Invalid OpenAPI spec: must have either "paths" or "components"');
214
223
  }
215
224
  }
216
225
  /**
@@ -250,8 +259,13 @@ class SpecDownloader {
250
259
  spec = JSON.parse(content);
251
260
  }
252
261
  catch {
253
- console.log('Spec is not JSON, skipping reference resolution');
254
- return;
262
+ try {
263
+ spec = yaml.load(content);
264
+ }
265
+ catch {
266
+ console.log('Spec is not valid JSON or YAML, skipping reference resolution');
267
+ return;
268
+ }
255
269
  }
256
270
  const refs = this.findExternalRefs(spec);
257
271
  if (refs.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klasik",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
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",
@@ -28,11 +28,13 @@
28
28
  "axios": "^1.6.0",
29
29
  "class-transformer": "^0.5.1",
30
30
  "commander": "^11.0.0",
31
+ "js-yaml": "^4.1.0",
31
32
  "openapi-class-transformer": "^1.0.11",
32
33
  "reflect-metadata": "^0.2.2"
33
34
  },
34
35
  "devDependencies": {
35
36
  "@types/jest": "^29.5.0",
37
+ "@types/js-yaml": "^4.0.9",
36
38
  "@types/node": "^20.0.0",
37
39
  "jest": "^29.5.0",
38
40
  "ts-jest": "^29.1.0",