toolcraft-openapi 0.0.60 → 0.0.62

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.
@@ -126,6 +126,7 @@ export interface GeneratedCommand {
126
126
  idempotencyHeader?: string;
127
127
  rawResponse?: boolean;
128
128
  confirm: boolean;
129
+ positional: string[];
129
130
  params: GeneratedParam[];
130
131
  paramsSchemaOptions?: GeneratedObjectSchemaOptions;
131
132
  preflightBlocks: GeneratedPreflightBlock[];
package/dist/generate.js CHANGED
@@ -21,16 +21,6 @@ const NULL_HELPER_SUPPORT = {
21
21
  query: { array: false, scalar: false }
22
22
  };
23
23
  const TRANSPORT_PARAMS = [
24
- {
25
- paramName: "dryRun",
26
- sourceName: "dryRun",
27
- location: "transport",
28
- description: "Print the HTTP request and exit without sending it.",
29
- scope: ["cli", "sdk"],
30
- global: true,
31
- optional: true,
32
- definition: { kind: "boolean" }
33
- },
34
24
  {
35
25
  paramName: "verbose",
36
26
  sourceName: "verbose",
@@ -279,6 +269,7 @@ function createGeneratedCommand(document, entry) {
279
269
  const noun = createSafeGeneratedNoun(deriveNoun(operation, entry.path, operationId));
280
270
  const verb = deriveVerb(entry.method, entry.path, operation, operationId, noun);
281
271
  const collected = collectParams(document, entry, operation, operationId, auth, response.mode);
272
+ const positional = collectPathPositionals(entry.path, collected.params, operationId);
282
273
  const methodDefaults = METHOD_DEFAULTS[entry.method];
283
274
  const exportName = `${toCamelCase(noun)}${toPascalCase(verb)}Command`;
284
275
  const filePath = `${noun}/${verb}.ts`;
@@ -299,6 +290,7 @@ function createGeneratedCommand(document, entry) {
299
290
  contentType: collected.contentType,
300
291
  multipartBinaryFields: collected.multipartBinaryFields,
301
292
  confirm: methodDefaults?.confirm === true,
293
+ positional,
302
294
  params: collected.params,
303
295
  paramsSchemaOptions: collected.paramsSchemaOptions,
304
296
  preflightBlocks: collected.preflightBlocks,
@@ -307,6 +299,28 @@ function createGeneratedCommand(document, entry) {
307
299
  optionalSections: collected.optionalSections
308
300
  };
309
301
  }
302
+ function collectPathPositionals(pathTemplate, params, operationId) {
303
+ const pathParamNames = new Set(params.filter((param) => param.location === "path").map((param) => param.sourceName));
304
+ const positionals = [];
305
+ for (const segment of pathTemplate.split("/")) {
306
+ if (!segment.startsWith("{") || !segment.endsWith("}")) {
307
+ continue;
308
+ }
309
+ const sourceName = segment.slice(1, -1);
310
+ if (!pathParamNames.has(sourceName)) {
311
+ throw new UserError(`Operation ${JSON.stringify(operationId)} path parameter ${JSON.stringify(sourceName)} is missing from generated params.`);
312
+ }
313
+ const param = params.find((candidate) => candidate.location === "path" && candidate.sourceName === sourceName);
314
+ if (param === undefined) {
315
+ continue;
316
+ }
317
+ if (param.definition.kind === "array" && positionals.length < pathParamNames.size - 1) {
318
+ throw new UserError(`Operation ${JSON.stringify(operationId)} path parameter ${JSON.stringify(sourceName)} is an array and can only be the final positional argument.`);
319
+ }
320
+ positionals.push(param.paramName);
321
+ }
322
+ return positionals;
323
+ }
310
324
  function resolveOperationBaseUrl(operation, operationId) {
311
325
  if (operation.servers === undefined) {
312
326
  return undefined;
@@ -1489,6 +1503,9 @@ function createCommandFile(options) {
1489
1503
  if (options.confirm) {
1490
1504
  lines.push(" confirm: true,");
1491
1505
  }
1506
+ if (options.positional.length > 0) {
1507
+ lines.push(` positional: ${JSON.stringify(options.positional)},`);
1508
+ }
1492
1509
  lines.push(" params: S.Object({");
1493
1510
  lines.push(...renderParamLines(options.params));
1494
1511
  lines.push(options.paramsSchemaOptions?.additionalProperties === false
@@ -1550,7 +1567,6 @@ function createCommandFile(options) {
1550
1567
  }
1551
1568
  lines.push(" tokenSource,");
1552
1569
  lines.push(" fetch,");
1553
- lines.push(" dryRun: params.dryRun,");
1554
1570
  lines.push(" verbose: params.verbose,");
1555
1571
  if (options.rawResponse === true) {
1556
1572
  lines.push(" rawResponse: params.rawResponse,");
@@ -1806,7 +1822,7 @@ function createIndexFile(commands) {
1806
1822
  if (groups.length === 0) {
1807
1823
  return {
1808
1824
  path: "index.ts",
1809
- contents: createGeneratedTypeScriptFile(["export {};", ""])
1825
+ contents: createGeneratedTypeScriptFile(["export const generatedCommands = [] as const;", ""])
1810
1826
  };
1811
1827
  }
1812
1828
  const lines = createGeneratedTypeScriptFileLines();
@@ -1826,6 +1842,8 @@ function createIndexFile(commands) {
1826
1842
  lines.push("});");
1827
1843
  lines.push("");
1828
1844
  }
1845
+ lines.push(`export const generatedCommands = [${groups.map(({ noun }) => toCamelCase(noun)).join(", ")}] as const;`);
1846
+ lines.push("");
1829
1847
  return {
1830
1848
  path: "index.ts",
1831
1849
  contents: lines.join("\n")
@@ -1838,11 +1856,11 @@ function createCliFile(theme) {
1838
1856
  "#!/usr/bin/env node",
1839
1857
  ...createGeneratedTypeScriptFileLines(),
1840
1858
  'import { configureTheme, runCLI } from "toolcraft/cli";',
1841
- 'import * as groups from "./index.js";',
1859
+ 'import { generatedCommands } from "./index.js";',
1842
1860
  "",
1843
1861
  `configureTheme({ brand: ${JSON.stringify(theme.brand)}, label: ${JSON.stringify(theme.label)} });`,
1844
1862
  "",
1845
- "await runCLI(Object.values(groups));",
1863
+ "await runCLI([...generatedCommands]);",
1846
1864
  ""
1847
1865
  ].join("\n")
1848
1866
  };
package/dist/http.d.ts CHANGED
@@ -24,7 +24,6 @@ export interface HttpRequestOptions {
24
24
  multipartBinaryFields?: readonly string[];
25
25
  responseMode?: "json" | "text" | "binary";
26
26
  accept?: string;
27
- dryRun?: boolean;
28
27
  verbose?: boolean;
29
28
  signal?: AbortSignal;
30
29
  rawResponse?: boolean;
@@ -41,7 +40,6 @@ export interface HttpRequestOptions {
41
40
  key?: string;
42
41
  createKey?: () => string;
43
42
  };
44
- writeStdout?: (chunk: string) => void;
45
43
  writeStderr?: (chunk: string) => void;
46
44
  }
47
45
  export interface BinaryHttpResponse {
package/dist/http.js CHANGED
@@ -28,13 +28,7 @@ export async function requestJson(options) {
28
28
  }
29
29
  : {};
30
30
  const headers = createHeaders(token, hasBody, { ...options.headers, ...idempotencyHeader }, options.accept, options.bodyMode, options.contentType);
31
- const writeStdout = options.writeStdout ?? process.stdout.write.bind(process.stdout);
32
31
  const writeStderr = options.writeStderr ?? process.stderr.write.bind(process.stderr);
33
- const requestLine = `${method} ${redactSensitiveQueryValues(url)}`;
34
- if (options.dryRun) {
35
- writeStdout(formatDryRunOutput(requestLine, headers, options.body));
36
- return undefined;
37
- }
38
32
  if (options.verbose) {
39
33
  writeStderr(formatTranscriptLines(formatVerboseRequestTranscript(method, url, headers, options.body)));
40
34
  }
@@ -453,20 +447,6 @@ function createHttpErrorRequest(method, url, headers, body) {
453
447
  function serializeHeaders(headers) {
454
448
  return Object.fromEntries(headers.entries());
455
449
  }
456
- function formatDryRunOutput(requestLine, headers, body) {
457
- const lines = [
458
- requestLine,
459
- ...Object.entries(headers).map(([key, value]) => {
460
- const headerValue = redactHeaderValue(key, value);
461
- return `${key}: ${headerValue}`;
462
- }),
463
- ""
464
- ];
465
- if (body !== undefined) {
466
- lines.push(JSON.stringify(body));
467
- }
468
- return `${lines.join("\n")}\n`;
469
- }
470
450
  function formatVerboseRequestTranscript(method, url, headers, body) {
471
451
  const lines = [
472
452
  `→ ${method} ${redactSensitiveQueryValues(url)}`,
package/dist/runtime.js CHANGED
@@ -62,6 +62,7 @@ function createRuntimeCommand(command) {
62
62
  ...(command.description === undefined ? {} : { description: command.description }),
63
63
  scope: RUNTIME_COMMAND_SCOPE,
64
64
  ...(command.confirm ? { confirm: true } : {}),
65
+ ...(command.positional.length > 0 ? { positional: command.positional } : {}),
65
66
  params: paramsSchema,
66
67
  handler: createRuntimeHandler(command)
67
68
  });
@@ -88,7 +89,6 @@ function createRuntimeHandler(command) {
88
89
  multipartBinaryFields: command.multipartBinaryFields,
89
90
  tokenSource,
90
91
  fetch,
91
- dryRun: params.dryRun,
92
92
  verbose: params.verbose,
93
93
  ...preparedRequestShape
94
94
  });
@@ -100,7 +100,7 @@ export function formatColumns(opts) {
100
100
  return [`${firstIndent}${row.left}`];
101
101
  }
102
102
  const rightLines = wrapWords(row.right, rightWidth);
103
- if (row.left.length > leftWidth) {
103
+ if (row.left.length >= leftWidth) {
104
104
  return [
105
105
  `${firstIndent}${row.left}`,
106
106
  ...rightLines.map((line) => `${continuationIndent}${line}`)
@@ -159,7 +159,7 @@ export function formatColumns(opts) {
159
159
  return [`${firstIndent}${row.left}`];
160
160
  }
161
161
  const rightLines = wrapWords(row.right, rightWidth);
162
- if (visibleWidth(row.left) > leftWidth) {
162
+ if (visibleWidth(row.left) >= leftWidth) {
163
163
  return [
164
164
  `${firstIndent}${row.left}`,
165
165
  ...rightLines.map((line) => `${continuationIndent}${line}`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-openapi",
3
- "version": "0.0.60",
3
+ "version": "0.0.62",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  "toolcraft-openapi-generate": "dist/bin/generate.js"
29
29
  },
30
30
  "dependencies": {
31
- "toolcraft": "0.0.60",
31
+ "toolcraft": "0.0.62",
32
32
  "auth-store": "^0.0.1",
33
33
  "fast-string-width": "^3.0.2",
34
34
  "fast-wrap-ansi": "^0.2.0",