openapi-sync 5.0.6 → 6.0.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
@@ -1,39 +1,366 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // ──────────────────────────────────────────────────────────────────────────────
4
+ // openapi-sync CLI
5
+ //
6
+ // AGENT USAGE GUIDE
7
+ // -----------------
8
+ // All commands support `--json` for machine-readable stdout and `--silent` to
9
+ // suppress progress logs. Exit codes: 0 = success, 1 = config error,
10
+ // 2 = network/spec error, 3 = generation error.
11
+ //
12
+ // Non-interactive init (no prompts, safe for agents):
13
+ // npx openapi-sync init --no-interactive \
14
+ // --api-name petstore \
15
+ // --api-url https://petstore3.swagger.io/api/v3/openapi.json \
16
+ // --output-folder ./src/api \
17
+ // --client-type react-query \
18
+ // --validation-library zod \
19
+ // --config-format typescript
20
+ //
21
+ // Validate config and specs without writing files:
22
+ // npx openapi-sync validate --json
23
+ //
24
+ // List all endpoints:
25
+ // npx openapi-sync list-endpoints --json
26
+ //
27
+ // Sync (generate types + endpoints + validation schemas):
28
+ // npx openapi-sync --json
29
+ //
30
+ // Generate a typed API client:
31
+ // npx openapi-sync generate-client --type react-query --json
32
+ // ──────────────────────────────────────────────────────────────────────────────
33
+
3
34
  const OpenApisync = require("../dist/index");
4
35
 
5
36
  const yargs = require("yargs/yargs");
6
37
  const { hideBin } = require("yargs/helpers");
7
38
 
8
- // Setup yargs with commands
9
- const argv = yargs(hideBin(process.argv))
39
+ // ── Output helpers ───────────────────────────────────────────────────────────
40
+
41
+ /**
42
+ * Write a JSON result to stdout and exit with the appropriate code.
43
+ * Used when --json flag is present.
44
+ */
45
+ function jsonExit(data, exitCode = 0) {
46
+ process.stdout.write(JSON.stringify(data, null, 2) + "\n");
47
+ process.exit(exitCode);
48
+ }
49
+
50
+ /**
51
+ * Determine the exit code from a SyncResult or ValidationResult.
52
+ */
53
+ function exitCodeFromResult(result) {
54
+ if (result.success === false || result.valid === false) return 1;
55
+ if (result.errors && result.errors.length > 0) return 1;
56
+ return 0;
57
+ }
58
+
59
+ // ── CLI definition ────────────────────────────────────────────────────────────
60
+
61
+ yargs(hideBin(process.argv))
62
+ // ── Global flags ──────────────────────────────────────────────────────────
63
+ .option("json", {
64
+ type: "boolean",
65
+ global: true,
66
+ description:
67
+ "Emit a single JSON object to stdout instead of human-readable logs. " +
68
+ "Use this when calling from scripts or AI agents.",
69
+ default: false,
70
+ })
71
+ .option("silent", {
72
+ type: "boolean",
73
+ global: true,
74
+ description: "Suppress all console output (implied by --json).",
75
+ default: false,
76
+ })
77
+
78
+ // ── `init` command ─────────────────────────────────────────────────────────
10
79
  .command(
11
80
  "init",
12
- "Interactive setup wizard to create configuration",
81
+ "Create an openapi.sync config file (interactive or non-interactive)",
82
+ (yargs) => {
83
+ return yargs
84
+ .option("no-interactive", {
85
+ alias: "y",
86
+ type: "boolean",
87
+ description:
88
+ "Skip all prompts and create config from flags + defaults. " +
89
+ "Use this from scripts or AI agents.",
90
+ default: false,
91
+ })
92
+ // All wizard fields available as flags so agents can pass everything:
93
+ .option("api-name", {
94
+ type: "string",
95
+ description: "Name for this API (e.g. petstore)",
96
+ })
97
+ .option("api-url", {
98
+ type: "string",
99
+ description: "URL to the OpenAPI spec (JSON or YAML)",
100
+ })
101
+ .option("api-file", {
102
+ type: "string",
103
+ description: "Path to a local OpenAPI spec file",
104
+ })
105
+ .option("output-folder", {
106
+ type: "string",
107
+ description: "Output folder for generated files",
108
+ default: "./src/api",
109
+ })
110
+ .option("config-format", {
111
+ type: "string",
112
+ choices: ["typescript", "json", "javascript"],
113
+ description: "Config file format",
114
+ default: "typescript",
115
+ })
116
+ .option("client-type", {
117
+ type: "string",
118
+ choices: ["react-query", "swr", "fetch", "axios", "rtk-query"],
119
+ description: "API client type to generate",
120
+ })
121
+ .option("validation-library", {
122
+ type: "string",
123
+ choices: ["zod", "yup", "joi"],
124
+ description: "Runtime validation library",
125
+ })
126
+ .option("folder-split", {
127
+ type: "boolean",
128
+ description: "Organize generated code into folders by OpenAPI tags",
129
+ default: false,
130
+ })
131
+ .option("types-prefix", {
132
+ type: "string",
133
+ description: "Prefix for generated TypeScript interface names",
134
+ default: "I",
135
+ })
136
+ .option("use-operation-id", {
137
+ type: "boolean",
138
+ description: "Use operationId from spec for type/function names",
139
+ default: true,
140
+ })
141
+ .option("exclude-tags", {
142
+ type: "string",
143
+ description: "Comma-separated tags to exclude (e.g. deprecated,internal)",
144
+ })
145
+ .option("show-curl", {
146
+ type: "boolean",
147
+ description: "Include cURL examples in generated docs",
148
+ default: true,
149
+ })
150
+ .option("refetch-interval", {
151
+ type: "number",
152
+ description: "Auto-refetch interval in ms (0 to disable)",
153
+ default: 0,
154
+ })
155
+ .option("run-sync", {
156
+ type: "boolean",
157
+ description: "Run initial sync after creating config",
158
+ default: false,
159
+ })
160
+ .example(
161
+ "$0 init",
162
+ "Interactive wizard (human use)"
163
+ )
164
+ .example(
165
+ "$0 init --no-interactive --api-name petstore --api-url https://petstore3.swagger.io/api/v3/openapi.json",
166
+ "Non-interactive setup (agent use)"
167
+ )
168
+ .example(
169
+ "$0 init --no-interactive --api-name myapi --api-url https://api.example.com/openapi.json --client-type react-query --validation-library zod --json",
170
+ "Full non-interactive setup with JSON output"
171
+ );
172
+ },
173
+ async (argv) => {
174
+ const noInteractive = argv["no-interactive"] || argv.y;
175
+
176
+ if (noInteractive) {
177
+ // ── Non-interactive path (agent-safe) ─────────────────────────────
178
+ const silent = argv.silent || argv.json;
179
+
180
+ const apiName = argv["api-name"] || "myapi";
181
+ const apiSource = argv["api-url"] || argv["api-file"];
182
+
183
+ if (!apiSource) {
184
+ const err = {
185
+ success: false,
186
+ error: {
187
+ code: "CONFIG_INVALID",
188
+ message:
189
+ "You must provide --api-url or --api-file when using --no-interactive.",
190
+ },
191
+ };
192
+ if (argv.json) return jsonExit(err, 1);
193
+ console.error(`❌ ${err.error.message}`);
194
+ process.exit(1);
195
+ }
196
+
197
+ const { nonInteractiveInit } = require("../dist/Openapi-sync/interactive-init");
198
+
199
+ const result = await nonInteractiveInit({
200
+ apiName,
201
+ apiSource,
202
+ outputFolder: argv["output-folder"],
203
+ configFormat: argv["config-format"],
204
+ clientType: argv["client-type"],
205
+ validationLibrary: argv["validation-library"],
206
+ folderSplit: argv["folder-split"],
207
+ typesPrefix: argv["types-prefix"],
208
+ useOperationId: argv["use-operation-id"],
209
+ excludeTags: argv["exclude-tags"]
210
+ ? argv["exclude-tags"].split(",").map((t) => t.trim())
211
+ : [],
212
+ showCurl: argv["show-curl"],
213
+ refetchInterval: argv["refetch-interval"] || undefined,
214
+ runSync: argv["run-sync"],
215
+ silent,
216
+ });
217
+
218
+ if (argv.json) {
219
+ return jsonExit(result, result.success ? 0 : 1);
220
+ }
221
+ } else {
222
+ // ── Interactive wizard path (human use) ───────────────────────────
223
+ await OpenApisync.InteractiveInit();
224
+ }
225
+ }
226
+ )
227
+
228
+ // ── `validate` command ─────────────────────────────────────────────────────
229
+ .command(
230
+ "validate",
231
+ "Validate the config file and all API specs without writing any files. " +
232
+ "Safe to run repeatedly — no side effects.",
13
233
  () => {},
14
- async () => {
15
- await OpenApisync.InteractiveInit();
234
+ async (argv) => {
235
+ const silent = argv.silent || argv.json;
236
+
237
+ const result = await OpenApisync.ValidateConfig({ silent });
238
+
239
+ if (argv.json) {
240
+ return jsonExit(result, result.valid ? 0 : 1);
241
+ }
242
+
243
+ process.exit(result.valid ? 0 : 1);
16
244
  }
17
245
  )
246
+
247
+ // ── `list-endpoints` command ───────────────────────────────────────────────
18
248
  .command(
19
- ["$0", "sync"],
20
- "Sync OpenAPI specifications and generate types",
249
+ "list-endpoints",
250
+ "List all endpoints discovered from your OpenAPI specs. No files are written.",
21
251
  (yargs) => {
22
- return yargs.option("refreshinterval", {
23
- alias: "ri",
24
- type: "number",
25
- description: "Interval at which to refetch specifications",
252
+ return yargs
253
+ .option("api", {
254
+ alias: "a",
255
+ type: "string",
256
+ description: "Limit to a specific API from your config",
257
+ })
258
+ .option("tags", {
259
+ type: "string",
260
+ description: "Comma-separated tags to filter by",
261
+ })
262
+ .example("$0 list-endpoints --json", "List all endpoints as JSON")
263
+ .example(
264
+ "$0 list-endpoints --api petstore --tags pet --json",
265
+ "List pet-tagged endpoints for petstore"
266
+ );
267
+ },
268
+ async (argv) => {
269
+ const silent = argv.silent || argv.json;
270
+ const tags = argv.tags
271
+ ? argv.tags.split(",").map((t) => t.trim())
272
+ : undefined;
273
+
274
+ const result = await OpenApisync.ListEndpoints({
275
+ apiName: argv.api,
276
+ tags,
277
+ silent,
26
278
  });
279
+
280
+ if (argv.json) {
281
+ return jsonExit(result, 0);
282
+ }
283
+
284
+ // Human-readable output
285
+ for (const [api, endpoints] of Object.entries(result)) {
286
+ console.log(`\n📋 ${api} (${endpoints.length} endpoints)`);
287
+ for (const ep of endpoints) {
288
+ const tags = ep.tags?.length ? ` [${ep.tags.join(", ")}]` : "";
289
+ console.log(` ${ep.method.padEnd(7)} ${ep.path}${tags}`);
290
+ if (ep.summary) console.log(` ${ep.summary}`);
291
+ }
292
+ }
293
+ }
294
+ )
295
+
296
+ // ── `sync` / default command ───────────────────────────────────────────────
297
+ .command(
298
+ ["$0", "sync"],
299
+ "Sync OpenAPI specifications and generate types, endpoints, and validation schemas",
300
+ (yargs) => {
301
+ return yargs
302
+ .option("refreshinterval", {
303
+ alias: "ri",
304
+ type: "number",
305
+ description: "Interval in ms to auto-refetch specifications",
306
+ })
307
+ .option("dry-run", {
308
+ type: "boolean",
309
+ description:
310
+ "Show what files would be written without actually writing them",
311
+ default: false,
312
+ })
313
+ .example("$0", "Sync all APIs")
314
+ .example("$0 --json", "Sync and emit JSON result")
315
+ .example("$0 --dry-run --json", "Preview what would be written");
27
316
  },
28
- (argv) => {
29
- OpenApisync.Init({
317
+ async (argv) => {
318
+ if (argv["dry-run"]) {
319
+ // Dry-run: validate first to count endpoints, then report what would be written
320
+ const silent = argv.silent || argv.json;
321
+ const validation = await OpenApisync.ValidateConfig({ silent });
322
+
323
+ const dryRunResult = {
324
+ dryRun: true,
325
+ valid: validation.valid,
326
+ apis: validation.apis,
327
+ message: validation.valid
328
+ ? "Dry run complete. Run without --dry-run to write files."
329
+ : "Validation failed. Fix errors before syncing.",
330
+ };
331
+
332
+ if (argv.json) {
333
+ return jsonExit(dryRunResult, validation.valid ? 0 : 1);
334
+ }
335
+
336
+ if (validation.valid) {
337
+ console.log("\n✅ Dry run: config and specs are valid.");
338
+ console.log(" Run without --dry-run to write files.\n");
339
+ } else {
340
+ console.error("\n❌ Dry run: validation failed — see errors above.\n");
341
+ process.exit(1);
342
+ }
343
+ return;
344
+ }
345
+
346
+ const silent = argv.silent || argv.json;
347
+ const result = await OpenApisync.Init({
30
348
  refetchInterval: argv.refreshinterval,
349
+ silent,
31
350
  });
351
+
352
+ if (argv.json) {
353
+ return jsonExit(result, exitCodeFromResult(result));
354
+ }
355
+
356
+ if (!result.success) process.exit(1);
32
357
  }
33
358
  )
359
+
360
+ // ── `generate-client` command ──────────────────────────────────────────────
34
361
  .command(
35
362
  "generate-client",
36
- "Generate API client from OpenAPI specification",
363
+ "Generate a type-safe API client from your OpenAPI specs",
37
364
  (yargs) => {
38
365
  return yargs
39
366
  .option("type", {
@@ -68,17 +395,22 @@ const argv = yargs(hideBin(process.argv))
68
395
  type: "string",
69
396
  description: "Base URL for API requests",
70
397
  })
398
+ .option("dry-run", {
399
+ type: "boolean",
400
+ description: "Show what files would be written without writing them",
401
+ default: false,
402
+ })
71
403
  .example(
72
- "$0 generate-client --type fetch",
73
- "Generate fetch client for all APIs"
404
+ "$0 generate-client --type fetch --json",
405
+ "Generate fetch client and emit JSON result"
74
406
  )
75
407
  .example(
76
408
  "$0 generate-client --type react-query --api petstore",
77
- "Generate React Query hooks for petstore API"
409
+ "Generate React Query hooks for petstore"
78
410
  )
79
411
  .example(
80
412
  "$0 generate-client --type axios --tags pets,users",
81
- "Generate axios client for endpoints with pets or users tags"
413
+ "Generate axios client filtered by tags"
82
414
  )
83
415
  .example(
84
416
  "$0 generate-client --type swr --endpoints getPetById,createPet",
@@ -86,26 +418,63 @@ const argv = yargs(hideBin(process.argv))
86
418
  );
87
419
  },
88
420
  async (argv) => {
89
- // First, sync API specs and generate types/endpoints
90
- console.log("🔄 Syncing API specifications first...\n");
91
- await OpenApisync.Init();
421
+ if (argv["dry-run"]) {
422
+ // Validate and list what would be generated
423
+ const silent = argv.silent || argv.json;
424
+ const endpoints = await OpenApisync.ListEndpoints({
425
+ apiName: argv.api,
426
+ tags: argv.tags,
427
+ silent,
428
+ });
429
+ const dryRunResult = {
430
+ dryRun: true,
431
+ type: argv.type,
432
+ apis: endpoints,
433
+ message: `Would generate a ${argv.type} client. Run without --dry-run to write files.`,
434
+ };
435
+ if (argv.json) return jsonExit(dryRunResult, 0);
436
+ console.log(`\n✅ Dry run: would generate ${argv.type} client.`);
437
+ for (const [api, eps] of Object.entries(endpoints)) {
438
+ console.log(` ${api}: ${eps.length} endpoints`);
439
+ }
440
+ return;
441
+ }
92
442
 
93
- console.log("\n🚀 Now generating client...\n");
443
+ // First sync to get fresh types
444
+ const silent = argv.silent || argv.json;
445
+ const silent2 = silent;
446
+ await OpenApisync.Init({ silent: silent2 });
94
447
 
95
- // Then generate the client
96
- await OpenApisync.GenerateClient({
448
+ const result = await OpenApisync.GenerateClient({
97
449
  type: argv.type,
98
450
  apiName: argv.api,
99
451
  tags: argv.tags,
100
452
  endpoints: argv.endpoints,
101
453
  outputDir: argv.output,
102
454
  baseURL: argv["base-url"],
455
+ silent,
103
456
  });
457
+
458
+ if (argv.json) {
459
+ return jsonExit(result, exitCodeFromResult(result));
460
+ }
461
+
462
+ if (!result.success) process.exit(1);
104
463
  }
105
464
  )
106
- .example("$0 init", "Start interactive setup wizard")
107
- .example("$0", "Sync API types and endpoints")
108
- .example("$0 --refreshinterval 10000", "Sync with 10s refresh interval")
465
+
466
+ .example("$0 init", "Interactive setup wizard (human)")
467
+ .example(
468
+ "$0 init --no-interactive --api-name petstore --api-url https://petstore3.swagger.io/api/v3/openapi.json",
469
+ "Non-interactive init (agent)"
470
+ )
471
+ .example("$0 validate --json", "Validate config + specs (no file writes)")
472
+ .example("$0 list-endpoints --json", "List all endpoints as JSON")
473
+ .example("$0 --json", "Sync and get JSON result")
474
+ .example(
475
+ "$0 generate-client --type react-query --json",
476
+ "Generate React Query hooks with JSON output"
477
+ )
109
478
  .help()
110
479
  .alias("help", "h")
111
480
  .version()
package/bin/mcp.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * openapi-sync MCP Server entry point.
5
+ *
6
+ * Starts the Model Context Protocol server over stdio so that AI agents
7
+ * (Claude Desktop, Cursor, Copilot, etc.) can call openapi-sync operations
8
+ * as structured tool invocations.
9
+ *
10
+ * Usage — add to Claude Desktop config
11
+ * (~/ Library/Application Support/Claude/claude_desktop_config.json):
12
+ *
13
+ * {
14
+ * "mcpServers": {
15
+ * "openapi-sync": {
16
+ * "command": "npx",
17
+ * "args": ["-y", "openapi-sync-mcp"],
18
+ * "cwd": "/path/to/your/project"
19
+ * }
20
+ * }
21
+ * }
22
+ *
23
+ * Usage — add to Cursor config (.cursor/mcp.json in project root):
24
+ *
25
+ * {
26
+ * "mcpServers": {
27
+ * "openapi-sync": {
28
+ * "command": "npx",
29
+ * "args": ["-y", "openapi-sync-mcp"],
30
+ * "cwd": "${workspaceFolder}"
31
+ * }
32
+ * }
33
+ * }
34
+ */
35
+
36
+ require("../dist/mcp/server.js");
@@ -0,0 +1,22 @@
1
+ import {d,f}from'./chunk-VLACEFT4.mjs';import F from'prompts';import s from'fs';import a from'path';function k(){return f(this,null,function*(){try{let e=yield F([{type:"select",name:"configFormat",message:"What configuration format would you like to use?",choices:[{title:"TypeScript (openapi.sync.ts)",value:"typescript"},{title:"JSON (openapi.sync.json)",value:"json"},{title:"JavaScript (openapi.sync.js)",value:"javascript"}],initial:0},{type:"select",name:"apiSource",message:"Where is your OpenAPI specification?",choices:[{title:"URL (e.g., https://api.example.com/openapi.json)",value:"url"},{title:"Local file",value:"file"}],initial:0},{type:t=>t==="url"?"text":null,name:"apiUrl",message:"Enter the OpenAPI specification URL:",validate:t=>t.startsWith("http://")||t.startsWith("https://")?!0:"Please enter a valid URL starting with http:// or https://"},{type:(t,c)=>c.apiSource==="file"?"text":null,name:"apiFile",message:"Enter the path to your OpenAPI file:",validate:t=>t.trim()!==""?!0:"Please enter a valid file path"},{type:"text",name:"apiName",message:"What would you like to name this API?",initial:"myapi",validate:t=>/^[a-zA-Z0-9_-]+$/.test(t)?!0:"API name must contain only letters, numbers, hyphens, and underscores"},{type:"text",name:"outputFolder",message:"Where should generated files be saved?",initial:"./src/api",validate:t=>{if(!t||t.trim()==="")return "Output folder cannot be empty";let c=a.normalize(t);if(c==="/"||c==="C:\\"||c==="\\")return "Cannot use filesystem root directory. Please use a project subfolder like './src/api'";if(a.isAbsolute(t)){let m=process.cwd();if(!t.startsWith(m))return "\u26A0\uFE0F Warning: Using absolute path outside project directory. Recommended: use relative path like './src/api'"}return !0}},{type:"confirm",name:"enableFolderSplit",message:"Organize generated code into folders by OpenAPI tags?",initial:!1},{type:"confirm",name:"generateClient",message:"Generate API client code?",initial:!0},{type:t=>t?"select":null,name:"clientType",message:"Which client type would you like?",choices:[{title:"React Query (Recommended for React)",value:"react-query"},{title:"RTK Query (Redux Toolkit)",value:"rtk-query"},{title:"SWR",value:"swr"},{title:"Fetch API",value:"fetch"},{title:"Axios",value:"axios"}],initial:0},{type:"confirm",name:"enableValidation",message:"Enable runtime validation schemas?",initial:!0},{type:t=>t?"select":null,name:"validationLibrary",message:"Which validation library?",choices:[{title:"Zod (Recommended)",value:"zod"},{title:"Yup",value:"yup"},{title:"Joi",value:"joi"}],initial:0},{type:"confirm",name:"enableCustomCode",message:"Enable custom code preservation?",initial:!0},{type:"confirm",name:"typesUseOperationId",message:"Use operationId from OpenAPI spec for type names?",initial:!0},{type:"text",name:"typesPrefix",message:"Prefix for TypeScript interface names (leave empty for none):",initial:"I"},{type:"confirm",name:"excludeEndpointsByTags",message:"Exclude endpoints by tags (e.g., deprecated, internal)?",initial:!1},{type:t=>t?"text":null,name:"excludeTags",message:"Enter tags to exclude (comma-separated):",initial:"deprecated,internal"},{type:"confirm",name:"showCurlInDocs",message:"Include cURL examples in generated documentation?",initial:!0},{type:"number",name:"refetchInterval",message:"Refetch interval in milliseconds (0 to disable auto-refresh):",initial:5e3,min:0},{type:"confirm",name:"runSync",message:"Run initial sync after setup?",initial:!0}],{onCancel:()=>{throw r||process.exit(0),new Error("Setup cancelled")}}),n={refetchInterval:e.refetchInterval||void 0,folder:e.outputFolder,api:{[e.apiName]:e.apiUrl||e.apiFile}};e.enableFolderSplit&&(n.folderSplit={byTags:!0}),n.types={name:{prefix:e.typesPrefix||"",useOperationId:e.typesUseOperationId}},n.endpoints={name:{useOperationId:e.typesUseOperationId},doc:{showCurl:e.showCurlInDocs}},e.excludeEndpointsByTags&&e.excludeTags&&(n.endpoints.exclude={tags:e.excludeTags.split(",").map(t=>t.trim())}),e.generateClient&&e.clientType&&(n.clientGeneration={enabled:!0,type:e.clientType,outputDir:a.join(e.outputFolder,e.apiName,"client")},e.clientType==="react-query"?n.clientGeneration.reactQuery={version:5,mutations:!0}:e.clientType==="swr"&&(n.clientGeneration.swr={mutations:!0})),e.enableValidation&&e.validationLibrary&&(n.validations={library:e.validationLibrary}),e.enableCustomCode&&(n.customCode={enabled:!0,position:"bottom"});let g,i;e.configFormat==="json"?(i="openapi.sync.json",g=JSON.stringify(n,null,2)):e.configFormat==="typescript"?(i="openapi.sync.ts",g=`import { IConfig } from "openapi-sync";
2
+
3
+ const config: IConfig = ${JSON.stringify(n,null,2)};
4
+
5
+ export default config;
6
+ `):(i="openapi.sync.js",g=`module.exports = ${JSON.stringify(n,null,2)};
7
+ `);let d=a.join(process.cwd(),i);if(s.existsSync(d)&&!(yield F({type:"confirm",name:"value",message:`${i} already exists. Overwrite?`,initial:!1})).value)throw r||process.exit(0),new Error("Configuration file not created");s.writeFileSync(d,g,"utf-8"),r||`${i}`;let l=a.isAbsolute(e.outputFolder)?e.outputFolder:a.join(process.cwd(),e.outputFolder);if(!s.existsSync(l))try{s.mkdirSync(l,{recursive:!0}),r||`${e.outputFolder}`;}catch(t){r||`${t.message}`;}let y=a.join(process.cwd(),".gitignore");if(s.existsSync(y)&&(s.readFileSync(y,"utf-8").includes(e.outputFolder)||s.appendFileSync(y,`
8
+ # OpenAPI Sync generated files
9
+ ${e.outputFolder}
10
+ `)),r||(`${i}`,e.generateClient&&e.clientType&&(e.clientType==="axios"||e.clientType==="react-query"||e.clientType==="swr"||e.clientType),e.enableValidation&&e.validationLibrary&&(e.generateClient,`${e.validationLibrary}`)),e.runSync&&!r)try{let{Init:t,GenerateClient:c}=yield import('./index.mjs');yield t({refetchInterval:e.refetchInterval}),e.generateClient&&e.clientType&&(yield c({type:e.clientType,apiName:e.apiName}));}catch(t){console.error(`
11
+ \u274C Error during sync:`,t.message),t.stack&&process.env.DEBUG&&console.error(t.stack);}else r||(e.generateClient||e.enableValidation,e.generateClient&&e.clientType&&(e.generateClient||e.enableValidation,`${e.clientType}`));r||(`${e.outputFolder}${e.apiName}`,e.generateClient&&`${e.outputFolder}${e.apiName}`,e.generateClient&&e.clientType&&`${e.clientType}`);}catch(e){throw r||(console.error(`
12
+ \u274C Error during setup:`,e.message),process.exit(1)),e}})}function G(e){return f(this,null,function*(){let{apiName:n,apiSource:g,outputFolder:i="./src/api",configFormat:d="typescript",clientType:l,validationLibrary:y,folderSplit:t=false,typesPrefix:c="I",useOperationId:m=true,excludeTags:I=[],showCurl:T=true,refetchInterval:v,runSync:O=false,silent:w=false}=e,h=w?{log:()=>{},warn:()=>{},error:()=>{}}:{log:console.log,warn:console.warn,error:console.error},u=[],o={folder:i,api:{[n]:g}};v&&v>0&&(o.refetchInterval=v),t&&(o.folderSplit={byTags:true}),o.types={name:{prefix:c,useOperationId:m}},o.endpoints={name:{useOperationId:m},doc:{showCurl:T}},I.length>0&&(o.endpoints.exclude={tags:I}),l&&(o.clientGeneration={enabled:true,type:l,outputDir:a.join(i,n,"client")},l==="react-query"?o.clientGeneration.reactQuery={version:5,mutations:true}:l==="swr"&&(o.clientGeneration.swr={mutations:true})),y&&(o.validations={library:y}),o.customCode={enabled:true,position:"bottom"};let b,p;d==="json"?(p="openapi.sync.json",b=JSON.stringify(o,null,2)):d==="typescript"?(p="openapi.sync.ts",b=`import { IConfig } from "openapi-sync";
13
+
14
+ const config: IConfig = ${JSON.stringify(o,null,2)};
15
+
16
+ export default config;
17
+ `):(p="openapi.sync.js",b=`module.exports = ${JSON.stringify(o,null,2)};
18
+ `);let P=a.join(process.cwd(),p);try{s.writeFileSync(P,b,"utf-8"),h.log(`
19
+ \u2705 Config written: ${p}`);}catch(f){return u.push(`Failed to write config: ${f.message}`),{success:false,configFile:p,message:"Config write failed.",errors:u}}let C=a.isAbsolute(i)?i:a.join(process.cwd(),i);if(!s.existsSync(C))try{s.mkdirSync(C,{recursive:!0});}catch(f){}if(O){h.log(`
20
+ \u{1F504} Running initial sync...`);try{let{Init:f,GenerateClient:j}=yield import('./index.mjs');yield f({silent:w}),l&&(yield j({type:l,apiName:n,silent:w})),h.log("\u2705 Sync complete.");}catch(f){u.push(`Sync failed: ${f.message}`);}}let S=u.length===0?`Config created: ${p}. Run \`npx openapi-sync\` to generate types.`:`Config created with errors (${u.length}).`;return h.log(`
21
+ ${S}
22
+ `),{success:u.length===0,configFile:p,message:S,errors:u}})}var r,N=d(()=>{r=process.env.NODE_ENV==="test"||process.env.JEST_WORKER_ID!==void 0;});export{k as a,G as b,N as c};
@@ -0,0 +1,24 @@
1
+ import {d}from'./chunk-VLACEFT4.mjs';import*as f from'js-yaml';var N,y,G=d(()=>{N=/^[A-Za-z_$][A-Za-z0-9_$]*$/,y=/[A-Za-z0-9_$]/;});function J(t,a){return a.split(".").reduce((r,n)=>r&&r[n]!==void 0?r[n]:void 0,t)}var w,M,z,E,D,k,I,O,T,C,U,B=d(()=>{G();w=t=>["object"].includes(typeof t)&&!(t instanceof Blob),M=t=>{try{return f.load(t),!0}catch(a){let o=a;if(o instanceof f.YAMLException)return false;throw o}},z=t=>{if(M(t)){let a=f.load(t),o=JSON.stringify(a,null,2);return JSON.parse(o)}},E=t=>t.substring(0,1).toUpperCase()+t.substring(1),D=(t,a)=>{let o=t.split("/"),r=`${E(a)}`,n=[];return o.forEach(s=>{if(s[0]==="{"&&s[s.length-1]==="}"){let e=s.replace(/{/,"").replace(/}/,"");n.push(e),s=`$${e}`;}else if(s[0]==="<"&&s[s.length-1]===">"){let e=s.replace(/</,"").replace(/>/,"");n.push(e),s=`$${e}`;}else if(s[0]===":"){let e=s.replace(/:/,"");n.push(e),s=`$${e}`;}let c="";s.split("").forEach(e=>{let i=e;y.test(e)||(i="/"),c+=i;}),c.split("/").forEach(e=>{r+=E(e);});}),{name:r,variables:n,pathParts:o}},k=(t,a=1)=>{let o="{",r=Object.keys(t);for(let n=0;n<r.length;n++){let s=r[n],c=t[s];if(o+=`
2
+ `+" ".repeat(a)+s+": ",Array.isArray(c)){o+="[";for(let e=0;e<c.length;e++){let i=c[e];typeof i=="object"&&i!==null?o+=k(i,a+1):o+=typeof i=="string"?`"${i}"`:i,e<c.length-1&&(o+=", ");}o+="]";}else typeof c=="object"&&c!==null?o+=""+k(c,a+1):o+=c.split(`
3
+ `).filter(e=>e.trim()!=="").join(`
4
+ ${" ".repeat(a)}`);n<r.length-1&&(o+=", ");}return o+=`
5
+ ${" ".repeat(a-1)}}`,o},I=(t,a=1)=>{let o=t.replace(/\/\*\*?[\s\S]*?\*\//g,r=>r.replace(/^\/\*\*?\s*/,"").replace(/\s*\*\/$/,"").split(`
6
+ `).map(s=>s.replace(/^\s*\*\s?/,"").trim()).filter(s=>s.length>0).map(s=>`// ${s}`).join(`
7
+ `));return `
8
+ \`\`\`typescript
9
+ ${" ".repeat(a)} ${o.split(`
10
+ `).filter(r=>r.trim()!=="").join(`
11
+ ${" ".repeat(a)} `)}
12
+ \`\`\``};O=(t,a="CUSTOM CODE")=>{let r=["//","#"].map(e=>({start:`${e} \u{1F512} ${a} START`,end:`${e} \u{1F512} ${a} END`})),n={beforeGenerated:"",afterGenerated:""},s=0,c=[];for(;s<t.length;){let e=null,i=-1;for(let d of r){let b=t.indexOf(d.start,s);b!==-1&&(i===-1||b<i)&&(i=b,e=d);}if(i===-1||!e)break;let p=t.indexOf(e.end,i);if(p===-1)break;let l=p+e.end.length,$=t.substring(l,l+100),u=$.match(/^\s*\n\s*((?:\/\/|#)\s*=+)/);if(u){let d=$.indexOf(`
13
+ `,u.index+1);d!==-1?l+=d+1:l+=u[0].length;}let g=i,S=t.substring(Math.max(0,i-200),i),A=/(^|\n)\s*(?:\/\/|#)\s*=+/g,h,m=-1;for(;(h=A.exec(S))!==null;)m=h.index+h[1].length;m!==-1&&(g=Math.max(0,i-200)+m);let j=t.substring(g,l);c.push({start:g,end:l,content:j}),s=l;}return c.length>0&&(t.substring(0,c[0].start).split(`
14
+ `).filter(p=>{let l=p.trim();return l.length>0&&!l.startsWith("//")&&!l.startsWith("#")}).join("").length===0?(n.beforeGenerated=c[0].content,c.length>1&&(n.afterGenerated=c[1].content)):(n.afterGenerated=c[0].content,c.length>1&&!n.beforeGenerated&&(n.beforeGenerated=c[1].content))),n},T=(t,a="CUSTOM CODE",o=true,r="//")=>{let n=o?`${r} ${t==="top"?"Add your custom code below this line":"Add your custom code above this line"}
15
+ ${r} This section will be preserved during regeneration
16
+ `:"";return `${r} ${"=".repeat(60)}
17
+ ${r} \u{1F512} ${a} START
18
+ ${n}${r} ${"=".repeat(60)}
19
+
20
+ ${r} \u{1F512} ${a} END
21
+ ${r} ${"=".repeat(60)}`},C=(t,a,o)=>{if(!t)return t;let r=new RegExp(`^\\s*//\\s*(?:={3,}|\u{1F512}\\s+${a}\\s+(?:START|END)|Add your custom code (?:below|above) this line|This section will be preserved during regeneration)\\s*$`);return t.split(`
22
+ `).map(n=>r.test(n)?n.replace(/^\s*\/\//,o):n).join(`
23
+ `)},U=(t,a,o={})=>{let{position:r="bottom",markerText:n="CUSTOM CODE",includeInstructions:s=true,commentPrefix:c="//"}=o,e={beforeGenerated:"",afterGenerated:""};a&&(e=O(a,n),e.beforeGenerated=C(e.beforeGenerated,n,c),e.afterGenerated=C(e.afterGenerated,n,c)),!e.beforeGenerated&&!e.afterGenerated&&((r==="top"||r==="both")&&(e.beforeGenerated=T("top",n,s,c)),(r==="bottom"||r==="both")&&(e.afterGenerated=T("bottom",n,s,c)));let i=[];return e.beforeGenerated&&(i.push(e.beforeGenerated),i.push("")),i.push(t),e.afterGenerated&&(i.push(""),i.push(e.afterGenerated)),i.join(`
24
+ `)};});export{N as a,y as b,G as c,w as d,M as e,z as f,E as g,D as h,k as i,I as j,J as k,O as l,T as m,U as n,B as o};