apollo-conn-gen 0.14.0 → 0.15.1

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/dist/cli/oas.js CHANGED
@@ -61,6 +61,7 @@ async function main(sourceFile, opts) {
61
61
  mapper: mapper,
62
62
  skipOptionalArgs: opts.skipOptionalArgs,
63
63
  inferEntityResolvers: opts.inferEntityResolvers,
64
+ skipAuth: opts.skipAuth,
64
65
  });
65
66
  await gen.visit();
66
67
  let pathSet = Array.from(gen.paths.values());
@@ -113,6 +114,7 @@ program
113
114
  .option('--batch <file>', 'Load batch endpoints (op id -> { maxSize? }) from a JSON file')
114
115
  .option('--skip-optional-args', 'Skip optional arguments in queries', false)
115
116
  .option('--infer-entity-resolvers', 'Infer entity resolvers and emit @key / entity: true', false)
117
+ .option('--skip-auth', 'Omit all auth (no headers on @source, no auth on @connect)', false)
116
118
  .parse(process.argv);
117
119
  const source = program.args[0];
118
120
  main(source, program.opts()).then(() => console.log('done'));
@@ -1 +1 @@
1
- {"version":3,"file":"oas.js","sourceRoot":"","sources":["../../src/cli/oas.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport { Command, OptionValues } from 'commander';\nimport { DEFAULT_VERSIONS } from '../versions.js';\nimport { generateFromSelection, promptForSelection } from './oas-helpers/index.js';\nimport { OasGen } from '../oas/oasGen.js';\nimport { BatchConfig, RequestOverride } from '../oas/oasContext.js';\nimport { RulesLoader, OpNameMapper, MapRules, Mapper } from '../oas/mapper/index.js';\n\nconst originalConsole = Object.assign(\n {\n log: console.log,\n },\n console,\n);\n\nfunction loadRules(opts: OptionValues): Mapper | undefined {\n let mapper;\n if (opts.transformRules) {\n try {\n const rules = RulesLoader.fromFile(opts.transformRules);\n mapper = OpNameMapper.fromRules(rules);\n } catch (error) {\n console.error(`Error loading transform rules: ${error}`);\n return undefined;\n }\n }\n\n return mapper;\n}\n\nfunction loadOverrides(opts: OptionValues): Record<string, RequestOverride> | undefined {\n if (!opts.overrides) {\n return undefined;\n }\n try {\n return JSON.parse(fs.readFileSync(opts.overrides, 'utf-8'));\n } catch (error) {\n console.error(`Error loading overrides: ${error}`);\n return undefined;\n }\n}\n\nfunction loadBatch(opts: OptionValues): BatchConfig | undefined {\n if (!opts.batch) {\n return undefined;\n }\n try {\n return JSON.parse(fs.readFileSync(opts.batch, 'utf-8'));\n } catch (error) {\n console.error(`Error loading batch file: ${error}`);\n return undefined;\n }\n}\n\nasync function main(sourceFile: string, opts: OptionValues): Promise<void> {\n console.log = () => {};\n\n const mapper = loadRules(opts);\n const overrides = loadOverrides(opts);\n const batch = loadBatch(opts);\n\n const gen = await OasGen.fromFile(sourceFile, {\n ...opts,\n baseURL: opts.baseUrl,\n overrides,\n batch,\n showParentInSelections: false,\n federationVersion: opts.federationVersion,\n connectorSpecVersion: opts.connectorSpecVersion,\n mapper: mapper,\n skipOptionalArgs: opts.skipOptionalArgs,\n inferEntityResolvers: opts.inferEntityResolvers,\n });\n\n await gen.visit();\n\n let pathSet = Array.from(gen.paths.values());\n if (opts.loadSelections) {\n generateFromSelection(opts, gen);\n return;\n }\n\n if (opts.grep !== '*') {\n const regex = new RegExp(opts.grep, 'ig');\n pathSet = pathSet.filter((p) => regex.test(p.path()));\n }\n\n if (opts.listPaths) {\n pathSet.forEach((path) => console.info(path.path()));\n return;\n }\n\n let paths: string[];\n if (opts.skipSelection) {\n paths = pathSet.map((p) => p.path() + '>**');\n } else {\n paths = await promptForSelection(gen, opts, pathSet);\n }\n\n if (opts.verbose) console = originalConsole;\n\n console.info(gen.generateSchema(paths));\n\n if (opts.printSelections) {\n console.info('# --------------- Selections -----------------');\n console.info(gen.selections);\n console.info('# --------------- Paths -----------------');\n console.info('paths =', JSON.stringify(paths, null, 2));\n }\n}\n\nconst program = new Command();\nprogram\n .version('0.0.1')\n .argument('<source>', 'source spec (yaml or json)')\n .option('-i --skip-validation', 'Skip validation step', false)\n .option('-n --skip-selection', 'Generate all [filtered] paths without prompting for a selection', false)\n .option('-l --list-paths', 'Only list the paths that can be generated', false)\n .option('-g --grep <regex>', 'Filter the list of paths with the passed expression', '*')\n .option('-p --page-size <num>', 'Number of rows to display in selection mode', '10')\n .option('-s --load-selections <file>', 'Load a JSON file with field selections (other options are ignored)')\n .option('-v --verbose', 'Log all messages from generator')\n .option('-m --print-selections', 'Print selections from generator')\n .option('-t --transform-rules <file>', 'Load transform rules from a JSON file to apply multiple name transformations')\n .option('--federation-version <version>', 'Federation version to use', DEFAULT_VERSIONS.federationVersion)\n .option('--connector-spec-version <version>', 'Connector spec version to use', DEFAULT_VERSIONS.connectorSpecVersion)\n .option('--base-url <url>', 'Override the @source base URL (default: servers[0] from the spec)')\n .option('--overrides <file>', 'Load per-operation path/queryParams overrides from a JSON file')\n .option('--batch <file>', 'Load batch endpoints (op id -> { maxSize? }) from a JSON file')\n .option('--skip-optional-args', 'Skip optional arguments in queries', false)\n .option('--infer-entity-resolvers', 'Infer entity resolvers and emit @key / entity: true', false)\n .parse(process.argv);\n\nconst source = program.args[0];\nmain(source, program.opts()).then(() => console.log('done'));\n"]}
1
+ {"version":3,"file":"oas.js","sourceRoot":"","sources":["../../src/cli/oas.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport { Command, OptionValues } from 'commander';\nimport { DEFAULT_VERSIONS } from '../versions.js';\nimport { generateFromSelection, promptForSelection } from './oas-helpers/index.js';\nimport { OasGen } from '../oas/oasGen.js';\nimport { BatchConfig, RequestOverride } from '../oas/oasContext.js';\nimport { RulesLoader, OpNameMapper, MapRules, Mapper } from '../oas/mapper/index.js';\n\nconst originalConsole = Object.assign(\n {\n log: console.log,\n },\n console,\n);\n\nfunction loadRules(opts: OptionValues): Mapper | undefined {\n let mapper;\n if (opts.transformRules) {\n try {\n const rules = RulesLoader.fromFile(opts.transformRules);\n mapper = OpNameMapper.fromRules(rules);\n } catch (error) {\n console.error(`Error loading transform rules: ${error}`);\n return undefined;\n }\n }\n\n return mapper;\n}\n\nfunction loadOverrides(opts: OptionValues): Record<string, RequestOverride> | undefined {\n if (!opts.overrides) {\n return undefined;\n }\n try {\n return JSON.parse(fs.readFileSync(opts.overrides, 'utf-8'));\n } catch (error) {\n console.error(`Error loading overrides: ${error}`);\n return undefined;\n }\n}\n\nfunction loadBatch(opts: OptionValues): BatchConfig | undefined {\n if (!opts.batch) {\n return undefined;\n }\n try {\n return JSON.parse(fs.readFileSync(opts.batch, 'utf-8'));\n } catch (error) {\n console.error(`Error loading batch file: ${error}`);\n return undefined;\n }\n}\n\nasync function main(sourceFile: string, opts: OptionValues): Promise<void> {\n console.log = () => {};\n\n const mapper = loadRules(opts);\n const overrides = loadOverrides(opts);\n const batch = loadBatch(opts);\n\n const gen = await OasGen.fromFile(sourceFile, {\n ...opts,\n baseURL: opts.baseUrl,\n overrides,\n batch,\n showParentInSelections: false,\n federationVersion: opts.federationVersion,\n connectorSpecVersion: opts.connectorSpecVersion,\n mapper: mapper,\n skipOptionalArgs: opts.skipOptionalArgs,\n inferEntityResolvers: opts.inferEntityResolvers,\n skipAuth: opts.skipAuth,\n });\n\n await gen.visit();\n\n let pathSet = Array.from(gen.paths.values());\n if (opts.loadSelections) {\n generateFromSelection(opts, gen);\n return;\n }\n\n if (opts.grep !== '*') {\n const regex = new RegExp(opts.grep, 'ig');\n pathSet = pathSet.filter((p) => regex.test(p.path()));\n }\n\n if (opts.listPaths) {\n pathSet.forEach((path) => console.info(path.path()));\n return;\n }\n\n let paths: string[];\n if (opts.skipSelection) {\n paths = pathSet.map((p) => p.path() + '>**');\n } else {\n paths = await promptForSelection(gen, opts, pathSet);\n }\n\n if (opts.verbose) console = originalConsole;\n\n console.info(gen.generateSchema(paths));\n\n if (opts.printSelections) {\n console.info('# --------------- Selections -----------------');\n console.info(gen.selections);\n console.info('# --------------- Paths -----------------');\n console.info('paths =', JSON.stringify(paths, null, 2));\n }\n}\n\nconst program = new Command();\nprogram\n .version('0.0.1')\n .argument('<source>', 'source spec (yaml or json)')\n .option('-i --skip-validation', 'Skip validation step', false)\n .option('-n --skip-selection', 'Generate all [filtered] paths without prompting for a selection', false)\n .option('-l --list-paths', 'Only list the paths that can be generated', false)\n .option('-g --grep <regex>', 'Filter the list of paths with the passed expression', '*')\n .option('-p --page-size <num>', 'Number of rows to display in selection mode', '10')\n .option('-s --load-selections <file>', 'Load a JSON file with field selections (other options are ignored)')\n .option('-v --verbose', 'Log all messages from generator')\n .option('-m --print-selections', 'Print selections from generator')\n .option('-t --transform-rules <file>', 'Load transform rules from a JSON file to apply multiple name transformations')\n .option('--federation-version <version>', 'Federation version to use', DEFAULT_VERSIONS.federationVersion)\n .option('--connector-spec-version <version>', 'Connector spec version to use', DEFAULT_VERSIONS.connectorSpecVersion)\n .option('--base-url <url>', 'Override the @source base URL (default: servers[0] from the spec)')\n .option('--overrides <file>', 'Load per-operation path/queryParams overrides from a JSON file')\n .option('--batch <file>', 'Load batch endpoints (op id -> { maxSize? }) from a JSON file')\n .option('--skip-optional-args', 'Skip optional arguments in queries', false)\n .option('--infer-entity-resolvers', 'Infer entity resolvers and emit @key / entity: true', false)\n .option('--skip-auth', 'Omit all auth (no headers on @source, no auth on @connect)', false)\n .parse(process.argv);\n\nconst source = program.args[0];\nmain(source, program.opts()).then(() => console.log('done'));\n"]}
@@ -3,6 +3,8 @@ import { T } from '../nodes/internal.js';
3
3
  import { Naming } from '../utils/naming.js';
4
4
  import { Params } from '../utils/params.js';
5
5
  import { ErrorsWriter } from './errorsWriter.js';
6
+ import { DEFAULT_VERSIONS, meetsMinimum } from '../../versions.js';
7
+ import { warn } from '../log/trace.js';
6
8
  export class OperationWriter {
7
9
  gen;
8
10
  security;
@@ -69,7 +71,15 @@ export class OperationWriter {
69
71
  // body is emitted last; its presence is cheap to compute up front. the body block streams
70
72
  // through the node tree (Body.select), so unlike query/headers it writes to `writer` directly
71
73
  // instead of returning a string. `null` drops the body; a string overrides it; see ROADMAP R9.
72
- const hasBody = typeof override?.body === 'string' || (override?.body === undefined && !!op.body);
74
+ // C2: `body:` is a connect v0.2+ feature — gate it like errors (R4) and batch (R6). Below the
75
+ // floor, drop the body and warn once per op (do not emit invalid output for an ancient target).
76
+ const wouldEmitBody = typeof override?.body === 'string' || (override?.body === undefined && !!op.body);
77
+ const version = this.gen.options.connectorSpecVersion || DEFAULT_VERSIONS.connectorSpecVersion;
78
+ const bodyAllowed = meetsMinimum(version, 'v0.2');
79
+ if (!bodyAllowed && wouldEmitBody) {
80
+ warn(context, '[body]', `@connect(http.body) requires connect v0.2, but target is ${version} — body not emitted for ${op.verb} ${op.operation.path}`);
81
+ }
82
+ const hasBody = bodyAllowed && wouldEmitBody;
73
83
  // query & header blocks are pure string-building — they return the block, or null when empty
74
84
  const queryBlock = this.queryParamsBlock(context, op, override, queryAuth);
75
85
  const headerBlock = this.headersBlock(op, override, headerAuth);
@@ -86,11 +96,13 @@ export class OperationWriter {
86
96
  writer.write(queryBlock);
87
97
  if (headerBlock)
88
98
  writer.write(headerBlock);
89
- if (typeof override?.body === 'string') {
90
- this.writeBodyOverride(writer, override.body);
91
- }
92
- else if (override?.body === undefined && op.body) {
93
- this.writeBodySelection(context, writer, op.body, selection);
99
+ if (hasBody) {
100
+ if (typeof override?.body === 'string') {
101
+ this.writeBodyOverride(writer, override.body);
102
+ }
103
+ else if (op.body) {
104
+ this.writeBodySelection(context, writer, op.body, selection);
105
+ }
94
106
  }
95
107
  writer.write(' '.repeat(6) + '}');
96
108
  }
@@ -1 +1 @@
1
- {"version":3,"file":"operationWriter.js","sourceRoot":"","sources":["../../../src/oas/io/operationWriter.ts"],"names":[],"mappings":"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","sourcesContent":["import _ from 'lodash';\nimport { ParameterObject } from 'oas/types';\nimport { OasContext, RequestOverride } from '../oasContext.js';\nimport { OasGen } from '../oasGen.js';\nimport { Body, IType, Op, Param, T } from '../nodes/internal.js';\nimport { Naming } from '../utils/naming.js';\nimport { Params } from '../utils/params.js';\nimport { ErrorsWriter } from './errorsWriter.js';\nimport { Writer } from './writer.js';\nimport { NameValue, SecurityPlan } from './security.js';\n\nexport class OperationWriter {\n private errorsWriter: ErrorsWriter;\n\n constructor(\n private gen: OasGen,\n private security: SecurityPlan,\n ) {\n this.errorsWriter = new ErrorsWriter(gen);\n }\n\n public writeQuery(context: OasContext, writer: Writer, collected: Map<string, IType>, selection: string[]): void {\n const selectionSet = new Set<string>(selection.map((s) => s.split('>')[0]));\n\n const paths = Array.from(collected.values()).filter((path) => selectionSet.has(path.id));\n if (_.isEmpty(paths)) return;\n\n writer.write('type Query {\\n');\n\n for (const path of paths) {\n path.generate(context, writer, []);\n this.writeConnector(context, writer, path, selection);\n context.generatedSet.add(path.id);\n }\n\n writer.write('}\\n\\n');\n }\n\n public writeMutations(context: OasContext, writer: Writer, collected: Map<string, IType>, selection: string[]): void {\n const selectionSet = new Set<string>(selection.map((s) => s.split('>')[0]));\n\n const paths = Array.from(collected.values()).filter((path) => selectionSet.has(path.id));\n if (_.isEmpty(paths)) return;\n\n writer.write('type Mutation {\\n');\n\n for (const path of paths) {\n path.generate(context, writer, []);\n this.writeConnector(context, writer, path, selection);\n context.generatedSet.add(path.id);\n }\n\n writer.write('}\\n\\n');\n }\n\n public writeConnector(context: OasContext, writer: Writer, type: IType, selection: string[]): void {\n if (!T.isOp(type)) {\n throw new Error(`expected an operation node, got ${type.id}`);\n }\n\n const op = type;\n const indent = 0;\n let spacing = ' '.repeat(indent + 4);\n writer.write(spacing).write('@connect(\\n');\n\n spacing = ' '.repeat(indent + 6);\n writer.write(spacing).write('source: \"api\"\\n').write(spacing).write('http: ');\n\n this.requestMethod(context, writer, op, selection, indent);\n\n writer.write('\\n').write(spacing).write('selection: \"\"\"\\n');\n\n // truthiness, not _.has — the declared-but-unset field is still an own property. #33\n if (op.resultType) {\n this.writeSelection(context, writer, op.resultType, selection);\n }\n\n writer.write(spacing).write('\"\"\"\\n');\n\n this.errorsWriter.write(context, writer, op, indent);\n\n spacing = ' '.repeat(indent + 4);\n writer.write(spacing).write(')\\n');\n }\n\n private requestMethod(context: OasContext, writer: Writer, op: Op, selection: string[], _indent: number): void {\n const override = context.generateOptions.overrides?.[op.id];\n\n // R5: this op's resolved auth, split by placement. A header lives on @connect only in per-op\n // mode (uniform mode puts it on @source); query auth always lives here (@source has no\n // queryParams). Warnings are owned by the plan — see security.ts.\n const { header: headerAuth, query: queryAuth } = this.security.forOp(op);\n\n const path = this.templatedPath(op, override);\n\n // body is emitted last; its presence is cheap to compute up front. the body block streams\n // through the node tree (Body.select), so unlike query/headers it writes to `writer` directly\n // instead of returning a string. `null` drops the body; a string overrides it; see ROADMAP R9.\n const hasBody = typeof override?.body === 'string' || (override?.body === undefined && !!op.body);\n\n // query & header blocks are pure string-building — they return the block, or null when empty\n const queryBlock = this.queryParamsBlock(context, op, override, queryAuth);\n const headerBlock = this.headersBlock(op, override, headerAuth);\n\n if (!queryBlock && !headerBlock && !hasBody) {\n // nothing but the path: keep the compact single-line form `{ GET: \"/x\"}`\n writer.write(`{ ${op.verb}: \"${path}\"}`);\n return;\n }\n\n // expanded: `http: {` on its own line, the verb and each member at indent 8, the closing `}`\n // aligned under `http:` (indent 6). members are comma-less (GraphQL multiline object style).\n writer.write('{\\n');\n writer.write(' '.repeat(8) + `${op.verb}: \"${path}\"\\n`);\n if (queryBlock) writer.write(queryBlock);\n if (headerBlock) writer.write(headerBlock);\n if (typeof override?.body === 'string') {\n this.writeBodyOverride(writer, override.body);\n } else if (override?.body === undefined && op.body) {\n this.writeBodySelection(context, writer, op.body, selection);\n }\n writer.write(' '.repeat(6) + '}');\n }\n\n // template each {elem} as {$args.<sanitised>} (the arg name), not the raw OAS key. see docs/issues.md #2\n // an override path may already template (`{$args.id}`, `{$config.v}`) — leave `$` segments alone\n private templatedPath(op: Op, override?: RequestOverride): string {\n return (override?.path ?? op.operation.path).replace(/\\{([^}]+)\\}/g, (m, name) =>\n name.startsWith('$') ? m : `{$args.${Naming.genParamName(name)}}`,\n );\n }\n\n // the op's queryParams block (a self-contained string ending in a newline), or null when the op\n // has no query params and no apiKey-in-query auth. `auth` is the op's resolved apiKey-in-query\n // entry (or null) — see requestMethod / security.forOp.\n private queryParamsBlock(\n context: OasContext,\n op: Op,\n override: RequestOverride | undefined,\n auth: NameValue | null,\n ): string | null {\n // we now include all query params, not just required ones. if they are not set,\n // then the connectors will not include them in the request.\n let queryParams = op.params.filter((p: Param) => {\n return p.parameter.in && p.parameter.in.toLowerCase() === 'query';\n });\n\n // Skip optional params if skipOptionalArgs is true\n if (context.generateOptions?.skipOptionalArgs) {\n queryParams = queryParams.filter((p: Param) => p.required);\n }\n\n // e.g. `\"api-version\": $('2024-01')` appended, `\"ids\": ids->joinNotNull(\";\")` replaced\n const entries = this.mergeOverrides(\n queryParams,\n override?.queryParams ?? {},\n (p) => `${Naming.genParamName(p.name)}${this.arrayJoin(p)}`,\n );\n\n // R5 slice 3: apiKey-in-query auth merges into the same query-param object as a JSONSelection\n // sibling outside the `$args { … }` block, so an auth-only op still emits a queryParams block.\n if (entries.length === 0 && !auth) {\n return null;\n }\n\n const lines: string[] = [' queryParams: \"\"\"'];\n // the `$args { … }` block only when there are arg-derived params (skipped for auth-only ops)\n if (entries.length > 0) {\n lines.push(' $args {');\n for (const { name, value } of entries) {\n lines.push(` \"${name}\": ${value}`);\n }\n lines.push(' }');\n }\n // e.g. `\"api_key\": $config.apiKey` — key quoted so non-identifier names like `api-key` are safe\n if (auth) {\n lines.push(` \"${auth.name}\": ${auth.value}`);\n }\n lines.push(' \"\"\"');\n return lines.join('\\n') + '\\n';\n }\n\n // the op's headers block (a self-contained string ending in a newline), or null when there are\n // no headers to send. `auth` is the op's resolved auth header (or null) — see requestMethod.\n private headersBlock(op: Op, override: RequestOverride | undefined, auth: NameValue | null): string | null {\n // OAS `header` params, with user overrides merged in (string replaces, null drops)\n const headers = op.operation.getParameters().filter((p) => p.in && p.in.toLowerCase() === 'header');\n let entries = this.mergeOverrides(headers, override?.headers ?? {}, (p) => this.headerExample(p));\n\n // HTTP header names are case-insensitive: an explicit user override of the same name wins;\n // otherwise the resolved auth replaces any inferred OAS header of that name (so we never emit\n // a real credential alongside a placeholder that differs only in case).\n if (auth) {\n const sameName = (name: string) => name.toLowerCase() === auth.name.toLowerCase();\n const overridden = Object.keys(override?.headers ?? {}).some(sameName);\n if (!overridden) {\n entries = [auth, ...entries.filter((entry) => !sameName(entry.name))];\n }\n }\n\n if (entries.length === 0) {\n return null;\n }\n\n const lines: string[] = [' headers: ['];\n for (const { name, value } of entries) {\n lines.push(` { name: \"${name}\", value: \"${value}\" }`);\n }\n lines.push(' ]');\n return lines.join('\\n') + '\\n';\n }\n\n // merge user overrides over the inferred params: a string replaces the inferred value,\n // null drops the entry, an unknown key is appended. see ROADMAP R8\n private mergeOverrides<T extends { name: string }>(\n inferred: T[],\n overrides: Record<string, string | null>,\n inferredValue: (item: T) => string,\n ): NameValue[] {\n const kept = inferred\n .filter((item) => overrides[item.name] !== null)\n .map((item): NameValue => ({ name: item.name, value: overrides[item.name] ?? inferredValue(item) }));\n\n // overrides whose key isn't an inferred param are appended (null already excluded above)\n const known = new Set(inferred.map((item) => item.name));\n const appended: NameValue[] = [];\n for (const [name, value] of Object.entries(overrides)) {\n if (!known.has(name) && value != null) {\n appended.push({ name, value });\n }\n }\n\n return [...kept, ...appended];\n }\n\n // inferred header value: the example, the example keys, or a placeholder for the user to fill\n private headerExample(p: ParameterObject): string {\n if (p.example != null) {\n return p.example.toString();\n }\n if (p.examples && Object.keys(p.examples).length > 0) {\n return Object.keys(p.examples).join(',');\n }\n return '<placeholder>';\n }\n\n // see Params.arrayJoin (shared with the R6 batch path)\n private arrayJoin(p: Param): string {\n return Params.arrayJoin(p.parameter);\n }\n\n private writeSelection(context: OasContext, writer: Writer, type: IType, selection: string[]): void {\n context.indent = 6;\n type.select(context, writer, selection);\n }\n\n // mirrors Body.select formatting, but the user's raw JSONSelection replaces the whole mapping.\n // emits the block at indent 8 (an http-object member), ending with a newline; the caller places\n // the http object's closing brace.\n private writeBodyOverride(writer: Writer, body: string): void {\n const spacing = ' '.repeat(8);\n writer.write(spacing + 'body: \"\"\"\\n');\n for (const line of body.split('\\n')) {\n writer.write(spacing + ' ' + line + '\\n');\n }\n writer.write(spacing + '\"\"\"\\n');\n }\n\n private writeBodySelection(context: OasContext, writer: Writer, body: Body, selection: string[]): void {\n context.indent = 8;\n body.select(context, writer, selection);\n }\n}\n"]}
1
+ {"version":3,"file":"operationWriter.js","sourceRoot":"","sources":["../../../src/oas/io/operationWriter.ts"],"names":[],"mappings":"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","sourcesContent":["import _ from 'lodash';\nimport { ParameterObject } from 'oas/types';\nimport { OasContext, RequestOverride } from '../oasContext.js';\nimport { OasGen } from '../oasGen.js';\nimport { Body, IType, Op, Param, T } from '../nodes/internal.js';\nimport { Naming } from '../utils/naming.js';\nimport { Params } from '../utils/params.js';\nimport { ErrorsWriter } from './errorsWriter.js';\nimport { Writer } from './writer.js';\nimport { NameValue, SecurityPlan } from './security.js';\nimport { DEFAULT_VERSIONS, meetsMinimum } from '../../versions.js';\nimport { warn } from '../log/trace.js';\n\nexport class OperationWriter {\n private errorsWriter: ErrorsWriter;\n\n constructor(\n private gen: OasGen,\n private security: SecurityPlan,\n ) {\n this.errorsWriter = new ErrorsWriter(gen);\n }\n\n public writeQuery(context: OasContext, writer: Writer, collected: Map<string, IType>, selection: string[]): void {\n const selectionSet = new Set<string>(selection.map((s) => s.split('>')[0]));\n\n const paths = Array.from(collected.values()).filter((path) => selectionSet.has(path.id));\n if (_.isEmpty(paths)) return;\n\n writer.write('type Query {\\n');\n\n for (const path of paths) {\n path.generate(context, writer, []);\n this.writeConnector(context, writer, path, selection);\n context.generatedSet.add(path.id);\n }\n\n writer.write('}\\n\\n');\n }\n\n public writeMutations(context: OasContext, writer: Writer, collected: Map<string, IType>, selection: string[]): void {\n const selectionSet = new Set<string>(selection.map((s) => s.split('>')[0]));\n\n const paths = Array.from(collected.values()).filter((path) => selectionSet.has(path.id));\n if (_.isEmpty(paths)) return;\n\n writer.write('type Mutation {\\n');\n\n for (const path of paths) {\n path.generate(context, writer, []);\n this.writeConnector(context, writer, path, selection);\n context.generatedSet.add(path.id);\n }\n\n writer.write('}\\n\\n');\n }\n\n public writeConnector(context: OasContext, writer: Writer, type: IType, selection: string[]): void {\n if (!T.isOp(type)) {\n throw new Error(`expected an operation node, got ${type.id}`);\n }\n\n const op = type;\n const indent = 0;\n let spacing = ' '.repeat(indent + 4);\n writer.write(spacing).write('@connect(\\n');\n\n spacing = ' '.repeat(indent + 6);\n writer.write(spacing).write('source: \"api\"\\n').write(spacing).write('http: ');\n\n this.requestMethod(context, writer, op, selection, indent);\n\n writer.write('\\n').write(spacing).write('selection: \"\"\"\\n');\n\n // truthiness, not _.has — the declared-but-unset field is still an own property. #33\n if (op.resultType) {\n this.writeSelection(context, writer, op.resultType, selection);\n }\n\n writer.write(spacing).write('\"\"\"\\n');\n\n this.errorsWriter.write(context, writer, op, indent);\n\n spacing = ' '.repeat(indent + 4);\n writer.write(spacing).write(')\\n');\n }\n\n private requestMethod(context: OasContext, writer: Writer, op: Op, selection: string[], _indent: number): void {\n const override = context.generateOptions.overrides?.[op.id];\n\n // R5: this op's resolved auth, split by placement. A header lives on @connect only in per-op\n // mode (uniform mode puts it on @source); query auth always lives here (@source has no\n // queryParams). Warnings are owned by the plan — see security.ts.\n const { header: headerAuth, query: queryAuth } = this.security.forOp(op);\n\n const path = this.templatedPath(op, override);\n\n // body is emitted last; its presence is cheap to compute up front. the body block streams\n // through the node tree (Body.select), so unlike query/headers it writes to `writer` directly\n // instead of returning a string. `null` drops the body; a string overrides it; see ROADMAP R9.\n // C2: `body:` is a connect v0.2+ feature — gate it like errors (R4) and batch (R6). Below the\n // floor, drop the body and warn once per op (do not emit invalid output for an ancient target).\n const wouldEmitBody = typeof override?.body === 'string' || (override?.body === undefined && !!op.body);\n const version = this.gen.options.connectorSpecVersion || DEFAULT_VERSIONS.connectorSpecVersion;\n const bodyAllowed = meetsMinimum(version, 'v0.2');\n if (!bodyAllowed && wouldEmitBody) {\n warn(\n context,\n '[body]',\n `@connect(http.body) requires connect v0.2, but target is ${version} — body not emitted for ${op.verb} ${op.operation.path}`,\n );\n }\n const hasBody = bodyAllowed && wouldEmitBody;\n\n // query & header blocks are pure string-building — they return the block, or null when empty\n const queryBlock = this.queryParamsBlock(context, op, override, queryAuth);\n const headerBlock = this.headersBlock(op, override, headerAuth);\n\n if (!queryBlock && !headerBlock && !hasBody) {\n // nothing but the path: keep the compact single-line form `{ GET: \"/x\"}`\n writer.write(`{ ${op.verb}: \"${path}\"}`);\n return;\n }\n\n // expanded: `http: {` on its own line, the verb and each member at indent 8, the closing `}`\n // aligned under `http:` (indent 6). members are comma-less (GraphQL multiline object style).\n writer.write('{\\n');\n writer.write(' '.repeat(8) + `${op.verb}: \"${path}\"\\n`);\n if (queryBlock) writer.write(queryBlock);\n if (headerBlock) writer.write(headerBlock);\n if (hasBody) {\n if (typeof override?.body === 'string') {\n this.writeBodyOverride(writer, override.body);\n } else if (op.body) {\n this.writeBodySelection(context, writer, op.body, selection);\n }\n }\n writer.write(' '.repeat(6) + '}');\n }\n\n // template each {elem} as {$args.<sanitised>} (the arg name), not the raw OAS key. see docs/issues.md #2\n // an override path may already template (`{$args.id}`, `{$config.v}`) — leave `$` segments alone\n private templatedPath(op: Op, override?: RequestOverride): string {\n return (override?.path ?? op.operation.path).replace(/\\{([^}]+)\\}/g, (m, name) =>\n name.startsWith('$') ? m : `{$args.${Naming.genParamName(name)}}`,\n );\n }\n\n // the op's queryParams block (a self-contained string ending in a newline), or null when the op\n // has no query params and no apiKey-in-query auth. `auth` is the op's resolved apiKey-in-query\n // entry (or null) — see requestMethod / security.forOp.\n private queryParamsBlock(\n context: OasContext,\n op: Op,\n override: RequestOverride | undefined,\n auth: NameValue | null,\n ): string | null {\n // we now include all query params, not just required ones. if they are not set,\n // then the connectors will not include them in the request.\n let queryParams = op.params.filter((p: Param) => {\n return p.parameter.in && p.parameter.in.toLowerCase() === 'query';\n });\n\n // Skip optional params if skipOptionalArgs is true\n if (context.generateOptions?.skipOptionalArgs) {\n queryParams = queryParams.filter((p: Param) => p.required);\n }\n\n // e.g. `\"api-version\": $('2024-01')` appended, `\"ids\": ids->joinNotNull(\";\")` replaced\n const entries = this.mergeOverrides(\n queryParams,\n override?.queryParams ?? {},\n (p) => `${Naming.genParamName(p.name)}${this.arrayJoin(p)}`,\n );\n\n // R5 slice 3: apiKey-in-query auth merges into the same query-param object as a JSONSelection\n // sibling outside the `$args { … }` block, so an auth-only op still emits a queryParams block.\n if (entries.length === 0 && !auth) {\n return null;\n }\n\n const lines: string[] = [' queryParams: \"\"\"'];\n // the `$args { … }` block only when there are arg-derived params (skipped for auth-only ops)\n if (entries.length > 0) {\n lines.push(' $args {');\n for (const { name, value } of entries) {\n lines.push(` \"${name}\": ${value}`);\n }\n lines.push(' }');\n }\n // e.g. `\"api_key\": $config.apiKey` — key quoted so non-identifier names like `api-key` are safe\n if (auth) {\n lines.push(` \"${auth.name}\": ${auth.value}`);\n }\n lines.push(' \"\"\"');\n return lines.join('\\n') + '\\n';\n }\n\n // the op's headers block (a self-contained string ending in a newline), or null when there are\n // no headers to send. `auth` is the op's resolved auth header (or null) — see requestMethod.\n private headersBlock(op: Op, override: RequestOverride | undefined, auth: NameValue | null): string | null {\n // OAS `header` params, with user overrides merged in (string replaces, null drops)\n const headers = op.operation.getParameters().filter((p) => p.in && p.in.toLowerCase() === 'header');\n let entries = this.mergeOverrides(headers, override?.headers ?? {}, (p) => this.headerExample(p));\n\n // HTTP header names are case-insensitive: an explicit user override of the same name wins;\n // otherwise the resolved auth replaces any inferred OAS header of that name (so we never emit\n // a real credential alongside a placeholder that differs only in case).\n if (auth) {\n const sameName = (name: string) => name.toLowerCase() === auth.name.toLowerCase();\n const overridden = Object.keys(override?.headers ?? {}).some(sameName);\n if (!overridden) {\n entries = [auth, ...entries.filter((entry) => !sameName(entry.name))];\n }\n }\n\n if (entries.length === 0) {\n return null;\n }\n\n const lines: string[] = [' headers: ['];\n for (const { name, value } of entries) {\n lines.push(` { name: \"${name}\", value: \"${value}\" }`);\n }\n lines.push(' ]');\n return lines.join('\\n') + '\\n';\n }\n\n // merge user overrides over the inferred params: a string replaces the inferred value,\n // null drops the entry, an unknown key is appended. see ROADMAP R8\n private mergeOverrides<T extends { name: string }>(\n inferred: T[],\n overrides: Record<string, string | null>,\n inferredValue: (item: T) => string,\n ): NameValue[] {\n const kept = inferred\n .filter((item) => overrides[item.name] !== null)\n .map((item): NameValue => ({ name: item.name, value: overrides[item.name] ?? inferredValue(item) }));\n\n // overrides whose key isn't an inferred param are appended (null already excluded above)\n const known = new Set(inferred.map((item) => item.name));\n const appended: NameValue[] = [];\n for (const [name, value] of Object.entries(overrides)) {\n if (!known.has(name) && value != null) {\n appended.push({ name, value });\n }\n }\n\n return [...kept, ...appended];\n }\n\n // inferred header value: the example, the example keys, or a placeholder for the user to fill\n private headerExample(p: ParameterObject): string {\n if (p.example != null) {\n return p.example.toString();\n }\n if (p.examples && Object.keys(p.examples).length > 0) {\n return Object.keys(p.examples).join(',');\n }\n return '<placeholder>';\n }\n\n // see Params.arrayJoin (shared with the R6 batch path)\n private arrayJoin(p: Param): string {\n return Params.arrayJoin(p.parameter);\n }\n\n private writeSelection(context: OasContext, writer: Writer, type: IType, selection: string[]): void {\n context.indent = 6;\n type.select(context, writer, selection);\n }\n\n // mirrors Body.select formatting, but the user's raw JSONSelection replaces the whole mapping.\n // emits the block at indent 8 (an http-object member), ending with a newline; the caller places\n // the http object's closing brace.\n private writeBodyOverride(writer: Writer, body: string): void {\n const spacing = ' '.repeat(8);\n writer.write(spacing + 'body: \"\"\"\\n');\n for (const line of body.split('\\n')) {\n writer.write(spacing + ' ' + line + '\\n');\n }\n writer.write(spacing + '\"\"\"\\n');\n }\n\n private writeBodySelection(context: OasContext, writer: Writer, body: Body, selection: string[]): void {\n context.indent = 8;\n body.select(context, writer, selection);\n }\n}\n"]}
@@ -14,11 +14,17 @@ export interface NameValue {
14
14
  * each `@connect`. Query auth always lives per-`@connect` — `SourceHTTP` has no `queryParams`.
15
15
  */
16
16
  export declare class SecurityPlan {
17
+ private readonly skipAuth;
17
18
  private readonly schemes;
18
19
  private readonly globalReq;
19
20
  private readonly perOpMode;
21
+ private readonly globalWarningBodies;
22
+ private globalWarningsEmitted;
20
23
  private constructor();
21
- static from(api: Oas): SecurityPlan;
24
+ static from(api: Oas, opts?: {
25
+ skipAuth?: boolean;
26
+ }): SecurityPlan;
27
+ private emitGlobalWarningsOnce;
22
28
  /** The `@source`-level auth header literal (uniform mode + header kind), or null. */
23
29
  sourceHeader(): string | null;
24
30
  /**
@@ -27,7 +33,9 @@ export declare class SecurityPlan {
27
33
  * - `query`: the query entry, always (SourceHTTP has no queryParams), else null
28
34
  *
29
35
  * Per-op warnings are emitted here with op context; in uniform mode the global warnings were
30
- * already emitted once by sourceHeader.
36
+ * already emitted once by sourceHeader. C3: in per-op mode, the global's dropped-scheme
37
+ * warnings are emitted exactly once (via emitGlobalWarningsOnce) — only genuinely op-specific
38
+ * warnings carry the `(operation …)` suffix.
31
39
  */
32
40
  forOp(op: Op): {
33
41
  header: NameValue | null;
@@ -99,24 +99,45 @@ function hasPerOperationSecurity(def) {
99
99
  * each `@connect`. Query auth always lives per-`@connect` — `SourceHTTP` has no `queryParams`.
100
100
  */
101
101
  export class SecurityPlan {
102
+ skipAuth;
102
103
  schemes;
103
104
  globalReq;
104
105
  perOpMode;
105
- constructor(schemes, globalReq, perOpMode) {
106
+ // C3: the global requirement's dropped-scheme warnings, pre-resolved once. In per-op mode every
107
+ // inheriting op would re-fire them otherwise; this set identifies them so forOp can skip what's
108
+ // already been emitted (once) and only surface genuinely op-specific warnings with op context.
109
+ globalWarningBodies;
110
+ globalWarningsEmitted = false;
111
+ constructor(schemes, globalReq, perOpMode, skipAuth = false) {
112
+ this.skipAuth = skipAuth;
106
113
  this.schemes = schemes;
107
114
  this.globalReq = globalReq;
108
115
  this.perOpMode = perOpMode;
116
+ this.globalWarningBodies = new Set(globalReq ? resolveAuth(globalReq, schemes).warnings : []);
109
117
  }
110
- static from(api) {
118
+ static from(api, opts) {
111
119
  const def = api.getDefinition();
112
120
  // oas-normalize usually up-converts Swagger 2.0 → components.securitySchemes; the
113
121
  // securityDefinitions fallback (same shape) is a safety net. refs are dereferenced by oas,
114
122
  // so the shape is a plain SecuritySchemesObject.
115
123
  const schemes = (def.components?.securitySchemes ?? def.securityDefinitions ?? {});
116
- return new SecurityPlan(schemes, def.security, hasPerOperationSecurity(def));
124
+ return new SecurityPlan(schemes, def.security, hasPerOperationSecurity(def), opts?.skipAuth ?? false);
125
+ }
126
+ // C3: emit the global's dropped-scheme warnings exactly once per generation. Called from
127
+ // sourceHeader (uniform mode) and the first forOp (per-op mode) — both run before the warnings
128
+ // would otherwise leak per-op. Idempotent via `globalWarningsEmitted`.
129
+ emitGlobalWarningsOnce() {
130
+ if (this.globalWarningsEmitted)
131
+ return;
132
+ this.globalWarningsEmitted = true;
133
+ for (const body of this.globalWarningBodies)
134
+ console.warn(body);
117
135
  }
118
136
  /** The `@source`-level auth header literal (uniform mode + header kind), or null. */
119
137
  sourceHeader() {
138
+ // --skip-auth: emit no auth anywhere — no header on @source (and forOp returns nothing too)
139
+ if (this.skipAuth)
140
+ return null;
120
141
  // per-op mode: each @connect carries its own auth — nothing on @source
121
142
  if (this.perOpMode)
122
143
  return null;
@@ -124,9 +145,10 @@ export class SecurityPlan {
124
145
  if (!this.globalReq || this.globalReq.length === 0)
125
146
  return null;
126
147
  const { auth, warnings } = resolveAuth(this.globalReq, this.schemes);
127
- // surface every dropped scheme loudly, exactly once
128
- for (const w of warnings)
129
- console.warn(w);
148
+ // C3: surface the global's dropped-scheme warnings exactly once (uniform mode; per-op mode
149
+ // emits them from the first forOp).
150
+ this.emitGlobalWarningsOnce();
151
+ void warnings; // already accounted for via globalWarningBodies
130
152
  // @source carries only header auth; query auth lives on each @connect (SourceHTTP has no
131
153
  // queryParams) and is returned by forOp — emit nothing here.
132
154
  if (auth?.kind !== 'header') {
@@ -144,16 +166,27 @@ export class SecurityPlan {
144
166
  * - `query`: the query entry, always (SourceHTTP has no queryParams), else null
145
167
  *
146
168
  * Per-op warnings are emitted here with op context; in uniform mode the global warnings were
147
- * already emitted once by sourceHeader.
169
+ * already emitted once by sourceHeader. C3: in per-op mode, the global's dropped-scheme
170
+ * warnings are emitted exactly once (via emitGlobalWarningsOnce) — only genuinely op-specific
171
+ * warnings carry the `(operation …)` suffix.
148
172
  */
149
173
  forOp(op) {
174
+ // --skip-auth: no per-@connect auth either (companion to sourceHeader's skip)
175
+ if (this.skipAuth)
176
+ return { header: null, query: null };
150
177
  // `??` not `||`: an explicit `security: []` (public) must NOT fall back to the global.
151
178
  const effective = op.operation.schema.security ?? this.globalReq;
152
179
  const { auth, warnings } = resolveAuth(effective, this.schemes);
153
180
  if (this.perOpMode) {
181
+ // surface the global's dropped-scheme warnings exactly once (idempotent), then warn only
182
+ // about op-specific drops with the op's location attached.
183
+ this.emitGlobalWarningsOnce();
154
184
  const where = `${op.verb} ${op.operation.path}`;
155
- for (const w of warnings)
156
- console.warn(`${w} (operation ${where})`);
185
+ for (const w of warnings) {
186
+ if (!this.globalWarningBodies.has(w)) {
187
+ console.warn(`${w} (operation ${where})`);
188
+ }
189
+ }
157
190
  }
158
191
  return {
159
192
  header: this.perOpMode && auth?.kind === 'header' ? auth : null,
@@ -1 +1 @@
1
- {"version":3,"file":"security.js","sourceRoot":"","sources":["../../../src/oas/io/security.ts"],"names":[],"mappings":"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","sourcesContent":["import _ from 'lodash';\nimport type Oas from 'oas';\nimport { SecurityRequirementObject, SecuritySchemeObject, SecuritySchemesObject } from 'oas/types';\nimport type { Op } from '../nodes/internal.js';\n\n// A connector name/value entry: a header (`{ name, value }`) or a query param (`\"name\": value`).\n// Also the shape mergeOverrides produces for inferred/overridden header & query params.\nexport interface NameValue {\n name: string;\n value: string;\n}\n\n// One resolved auth credential: a NameValue plus where it goes. Header values carry `{}`\n// interpolation (`Bearer {$config.token}`); a query value is a raw JSONSelection (`$config.apiKey`).\ninterface AuthEntry extends NameValue {\n kind: 'header' | 'query';\n}\n\n// The HTTP methods the generator actually emits (see OasGen.isSupported). Scanning only these for\n// the per-op-mode switch keeps the decision consistent with what gets written — a `security` on an\n// un-emitted HEAD/OPTIONS op no longer flips the whole spec into per-op mode.\nconst SUPPORTED_METHODS: readonly string[] = ['get', 'post', 'put', 'patch', 'delete'];\n\n/**\n * Map one OAS security scheme to its connector auth entry, or null when it makes none.\n * Header values carry `{}` interpolation; a query value is a raw JSONSelection (no braces) because\n * it lands in a `queryParams: \"\"\"…\"\"\"` block, which is already a JSONSelection context.\n */\nfunction mapSchemeToAuth(scheme: SecuritySchemeObject): AuthEntry | null {\n switch (scheme.type) {\n case 'apiKey':\n // apiKey in a header, e.g. `{ type: apiKey, in: header, name: X-API-Key }`\n if (scheme.in === 'header' && scheme.name) {\n return { kind: 'header', name: scheme.name, value: '{$config.apiKey}' };\n }\n // apiKey in the query string, e.g. `{ type: apiKey, in: query, name: api_key }`\n if (scheme.in === 'query' && scheme.name) {\n return { kind: 'query', name: scheme.name, value: '$config.apiKey' };\n }\n return null; // cookie is deferred and warned about, not emitted\n case 'http':\n if (scheme.scheme === 'bearer') {\n return { kind: 'header', name: 'Authorization', value: 'Bearer {$config.token}' };\n }\n if (scheme.scheme === 'basic') {\n return { kind: 'header', name: 'Authorization', value: 'Basic {$config.token}' };\n }\n return null;\n case 'oauth2':\n case 'openIdConnect':\n // both flows ultimately send a bearer token\n return { kind: 'header', name: 'Authorization', value: 'Bearer {$config.token}' };\n default:\n return null;\n }\n}\n\n/** The warning text for a referenced scheme we did not emit (undefined, deferred, or not the winner). */\nfunction droppedSchemeWarning(name: string, scheme: SecuritySchemeObject | undefined): string {\n if (!scheme) {\n return `[security] scheme \"${name}\" is referenced but not defined; skipped.`;\n }\n if (scheme.type === 'apiKey' && scheme.in === 'cookie') {\n return `[security] scheme \"${name}\" is apiKey in cookie — not emitted (cookie auth deferred).`;\n }\n return `[security] scheme \"${name}\" (${scheme.type}) has no supported connector mapping; skipped.`;\n}\n\n/**\n * Resolve a security requirement to the single auth entry the connector should send.\n *\n * A requirement is an OR of scheme-name sets (`[{ a: [] }, { b: [] }]` = \"a OR b\"). We flatten to\n * names in order and pick the FIRST that maps to an entry. A later viable alternative is a\n * legitimate OR choice, not a failure, so it stays silent; only genuinely unresolvable names —\n * undefined, deferred (cookie), or an unmappable scheme — are reported in `warnings`. An absent or\n * empty (`[]`, public) requirement yields no entry and no warnings.\n */\nfunction resolveAuth(\n securityRequirements: SecurityRequirementObject[] | undefined,\n schemes: SecuritySchemesObject,\n): { auth: AuthEntry | null; warnings: string[] } {\n let auth: AuthEntry | null = null;\n const warnings: string[] = [];\n\n for (const name of securityRequirements?.flatMap((requirement) => Object.keys(requirement)) ?? []) {\n const scheme = schemes[name];\n const entry = scheme ? mapSchemeToAuth(scheme) : null;\n\n if (entry) {\n // first scheme that maps wins; a later viable alternative is a silent OR choice\n if (!auth) auth = entry;\n } else {\n // genuinely unresolvable: undefined scheme, cookie, or no supported mapping\n warnings.push(droppedSchemeWarning(name, scheme));\n }\n }\n\n return { auth, warnings };\n}\n\n/** True when ANY emitted operation declares its own `security` (empty `[]` or non-empty). */\nfunction hasPerOperationSecurity(def: ReturnType<Oas['getDefinition']>): boolean {\n const paths = def.paths ?? {};\n for (const pathName of Object.keys(paths)) {\n const path = paths[pathName];\n if (!path) continue;\n for (const method of SUPPORTED_METHODS) {\n // own property (not inherited) — an explicit `security: []` is still a declaration\n if (_.has(path, [method, 'security'])) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Resolved security for one generation pass: computed once from the parsed spec, then queried for\n * `@source` (sourceHeader) and per-`@connect` (forOp). Owning all auth warnings here removes the old\n * uniform-vs-per-op \"who warns when\" coordination between SchemaWriter and OperationWriter.\n *\n * Mode switch: when any emitted op declares its own `security`, a shared `@source` header is unsafe\n * (a public op would leak it; a differently-named override would send both), so header auth moves to\n * each `@connect`. Query auth always lives per-`@connect` — `SourceHTTP` has no `queryParams`.\n */\nexport class SecurityPlan {\n private readonly schemes: SecuritySchemesObject;\n private readonly globalReq: SecurityRequirementObject[] | undefined;\n private readonly perOpMode: boolean;\n\n private constructor(\n schemes: SecuritySchemesObject,\n globalReq: SecurityRequirementObject[] | undefined,\n perOpMode: boolean,\n ) {\n this.schemes = schemes;\n this.globalReq = globalReq;\n this.perOpMode = perOpMode;\n }\n\n static from(api: Oas): SecurityPlan {\n const def = api.getDefinition();\n // oas-normalize usually up-converts Swagger 2.0 → components.securitySchemes; the\n // securityDefinitions fallback (same shape) is a safety net. refs are dereferenced by oas,\n // so the shape is a plain SecuritySchemesObject.\n const schemes = (def.components?.securitySchemes ?? def.securityDefinitions ?? {}) as SecuritySchemesObject;\n return new SecurityPlan(schemes, def.security, hasPerOperationSecurity(def));\n }\n\n /** The `@source`-level auth header literal (uniform mode + header kind), or null. */\n sourceHeader(): string | null {\n // per-op mode: each @connect carries its own auth — nothing on @source\n if (this.perOpMode) return null;\n // no global requirement -> keep the headerless @source byte-for-byte\n if (!this.globalReq || this.globalReq.length === 0) return null;\n\n const { auth, warnings } = resolveAuth(this.globalReq, this.schemes);\n // surface every dropped scheme loudly, exactly once\n for (const w of warnings) console.warn(w);\n\n // @source carries only header auth; query auth lives on each @connect (SourceHTTP has no\n // queryParams) and is returned by forOp — emit nothing here.\n if (auth?.kind !== 'header') {\n if (!auth) {\n const names = this.globalReq.flatMap((req) => Object.keys(req));\n console.warn(\n `[security] global security requirement (${names.join(', ')}) maps to no header-producing scheme; no auth header emitted on @source.`,\n );\n }\n return null;\n }\n\n return `{ name: \"${auth.name}\", value: \"${auth.value}\" }`;\n }\n\n /**\n * This op's resolved auth, split by placement.\n * - `header`: the header entry in per-op mode (uniform mode puts it on `@source`), else null\n * - `query`: the query entry, always (SourceHTTP has no queryParams), else null\n *\n * Per-op warnings are emitted here with op context; in uniform mode the global warnings were\n * already emitted once by sourceHeader.\n */\n forOp(op: Op): { header: NameValue | null; query: NameValue | null } {\n // `??` not `||`: an explicit `security: []` (public) must NOT fall back to the global.\n const effective = op.operation.schema.security ?? this.globalReq;\n const { auth, warnings } = resolveAuth(effective, this.schemes);\n\n if (this.perOpMode) {\n const where = `${op.verb} ${op.operation.path}`;\n for (const w of warnings) console.warn(`${w} (operation ${where})`);\n }\n\n return {\n header: this.perOpMode && auth?.kind === 'header' ? auth : null,\n query: auth?.kind === 'query' ? auth : null,\n };\n }\n}\n"]}
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../../src/oas/io/security.ts"],"names":[],"mappings":"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","sourcesContent":["import _ from 'lodash';\nimport type Oas from 'oas';\nimport { SecurityRequirementObject, SecuritySchemeObject, SecuritySchemesObject } from 'oas/types';\nimport type { Op } from '../nodes/internal.js';\n\n// A connector name/value entry: a header (`{ name, value }`) or a query param (`\"name\": value`).\n// Also the shape mergeOverrides produces for inferred/overridden header & query params.\nexport interface NameValue {\n name: string;\n value: string;\n}\n\n// One resolved auth credential: a NameValue plus where it goes. Header values carry `{}`\n// interpolation (`Bearer {$config.token}`); a query value is a raw JSONSelection (`$config.apiKey`).\ninterface AuthEntry extends NameValue {\n kind: 'header' | 'query';\n}\n\n// The HTTP methods the generator actually emits (see OasGen.isSupported). Scanning only these for\n// the per-op-mode switch keeps the decision consistent with what gets written — a `security` on an\n// un-emitted HEAD/OPTIONS op no longer flips the whole spec into per-op mode.\nconst SUPPORTED_METHODS: readonly string[] = ['get', 'post', 'put', 'patch', 'delete'];\n\n/**\n * Map one OAS security scheme to its connector auth entry, or null when it makes none.\n * Header values carry `{}` interpolation; a query value is a raw JSONSelection (no braces) because\n * it lands in a `queryParams: \"\"\"…\"\"\"` block, which is already a JSONSelection context.\n */\nfunction mapSchemeToAuth(scheme: SecuritySchemeObject): AuthEntry | null {\n switch (scheme.type) {\n case 'apiKey':\n // apiKey in a header, e.g. `{ type: apiKey, in: header, name: X-API-Key }`\n if (scheme.in === 'header' && scheme.name) {\n return { kind: 'header', name: scheme.name, value: '{$config.apiKey}' };\n }\n // apiKey in the query string, e.g. `{ type: apiKey, in: query, name: api_key }`\n if (scheme.in === 'query' && scheme.name) {\n return { kind: 'query', name: scheme.name, value: '$config.apiKey' };\n }\n return null; // cookie is deferred and warned about, not emitted\n case 'http':\n if (scheme.scheme === 'bearer') {\n return { kind: 'header', name: 'Authorization', value: 'Bearer {$config.token}' };\n }\n if (scheme.scheme === 'basic') {\n return { kind: 'header', name: 'Authorization', value: 'Basic {$config.token}' };\n }\n return null;\n case 'oauth2':\n case 'openIdConnect':\n // both flows ultimately send a bearer token\n return { kind: 'header', name: 'Authorization', value: 'Bearer {$config.token}' };\n default:\n return null;\n }\n}\n\n/** The warning text for a referenced scheme we did not emit (undefined, deferred, or not the winner). */\nfunction droppedSchemeWarning(name: string, scheme: SecuritySchemeObject | undefined): string {\n if (!scheme) {\n return `[security] scheme \"${name}\" is referenced but not defined; skipped.`;\n }\n if (scheme.type === 'apiKey' && scheme.in === 'cookie') {\n return `[security] scheme \"${name}\" is apiKey in cookie — not emitted (cookie auth deferred).`;\n }\n return `[security] scheme \"${name}\" (${scheme.type}) has no supported connector mapping; skipped.`;\n}\n\n/**\n * Resolve a security requirement to the single auth entry the connector should send.\n *\n * A requirement is an OR of scheme-name sets (`[{ a: [] }, { b: [] }]` = \"a OR b\"). We flatten to\n * names in order and pick the FIRST that maps to an entry. A later viable alternative is a\n * legitimate OR choice, not a failure, so it stays silent; only genuinely unresolvable names —\n * undefined, deferred (cookie), or an unmappable scheme — are reported in `warnings`. An absent or\n * empty (`[]`, public) requirement yields no entry and no warnings.\n */\nfunction resolveAuth(\n securityRequirements: SecurityRequirementObject[] | undefined,\n schemes: SecuritySchemesObject,\n): { auth: AuthEntry | null; warnings: string[] } {\n let auth: AuthEntry | null = null;\n const warnings: string[] = [];\n\n for (const name of securityRequirements?.flatMap((requirement) => Object.keys(requirement)) ?? []) {\n const scheme = schemes[name];\n const entry = scheme ? mapSchemeToAuth(scheme) : null;\n\n if (entry) {\n // first scheme that maps wins; a later viable alternative is a silent OR choice\n if (!auth) auth = entry;\n } else {\n // genuinely unresolvable: undefined scheme, cookie, or no supported mapping\n warnings.push(droppedSchemeWarning(name, scheme));\n }\n }\n\n return { auth, warnings };\n}\n\n/** True when ANY emitted operation declares its own `security` (empty `[]` or non-empty). */\nfunction hasPerOperationSecurity(def: ReturnType<Oas['getDefinition']>): boolean {\n const paths = def.paths ?? {};\n for (const pathName of Object.keys(paths)) {\n const path = paths[pathName];\n if (!path) continue;\n for (const method of SUPPORTED_METHODS) {\n // own property (not inherited) — an explicit `security: []` is still a declaration\n if (_.has(path, [method, 'security'])) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Resolved security for one generation pass: computed once from the parsed spec, then queried for\n * `@source` (sourceHeader) and per-`@connect` (forOp). Owning all auth warnings here removes the old\n * uniform-vs-per-op \"who warns when\" coordination between SchemaWriter and OperationWriter.\n *\n * Mode switch: when any emitted op declares its own `security`, a shared `@source` header is unsafe\n * (a public op would leak it; a differently-named override would send both), so header auth moves to\n * each `@connect`. Query auth always lives per-`@connect` — `SourceHTTP` has no `queryParams`.\n */\nexport class SecurityPlan {\n private readonly schemes: SecuritySchemesObject;\n private readonly globalReq: SecurityRequirementObject[] | undefined;\n private readonly perOpMode: boolean;\n // C3: the global requirement's dropped-scheme warnings, pre-resolved once. In per-op mode every\n // inheriting op would re-fire them otherwise; this set identifies them so forOp can skip what's\n // already been emitted (once) and only surface genuinely op-specific warnings with op context.\n private readonly globalWarningBodies: Set<string>;\n private globalWarningsEmitted = false;\n\n private constructor(\n schemes: SecuritySchemesObject,\n globalReq: SecurityRequirementObject[] | undefined,\n perOpMode: boolean,\n private readonly skipAuth: boolean = false,\n ) {\n this.schemes = schemes;\n this.globalReq = globalReq;\n this.perOpMode = perOpMode;\n this.globalWarningBodies = new Set(globalReq ? resolveAuth(globalReq, schemes).warnings : []);\n }\n\n static from(api: Oas, opts?: { skipAuth?: boolean }): SecurityPlan {\n const def = api.getDefinition();\n // oas-normalize usually up-converts Swagger 2.0 → components.securitySchemes; the\n // securityDefinitions fallback (same shape) is a safety net. refs are dereferenced by oas,\n // so the shape is a plain SecuritySchemesObject.\n const schemes = (def.components?.securitySchemes ?? def.securityDefinitions ?? {}) as SecuritySchemesObject;\n return new SecurityPlan(schemes, def.security, hasPerOperationSecurity(def), opts?.skipAuth ?? false);\n }\n\n // C3: emit the global's dropped-scheme warnings exactly once per generation. Called from\n // sourceHeader (uniform mode) and the first forOp (per-op mode) — both run before the warnings\n // would otherwise leak per-op. Idempotent via `globalWarningsEmitted`.\n private emitGlobalWarningsOnce(): void {\n if (this.globalWarningsEmitted) return;\n this.globalWarningsEmitted = true;\n for (const body of this.globalWarningBodies) console.warn(body);\n }\n\n /** The `@source`-level auth header literal (uniform mode + header kind), or null. */\n sourceHeader(): string | null {\n // --skip-auth: emit no auth anywhere — no header on @source (and forOp returns nothing too)\n if (this.skipAuth) return null;\n // per-op mode: each @connect carries its own auth — nothing on @source\n if (this.perOpMode) return null;\n // no global requirement -> keep the headerless @source byte-for-byte\n if (!this.globalReq || this.globalReq.length === 0) return null;\n\n const { auth, warnings } = resolveAuth(this.globalReq, this.schemes);\n // C3: surface the global's dropped-scheme warnings exactly once (uniform mode; per-op mode\n // emits them from the first forOp).\n this.emitGlobalWarningsOnce();\n void warnings; // already accounted for via globalWarningBodies\n\n // @source carries only header auth; query auth lives on each @connect (SourceHTTP has no\n // queryParams) and is returned by forOp — emit nothing here.\n if (auth?.kind !== 'header') {\n if (!auth) {\n const names = this.globalReq.flatMap((req) => Object.keys(req));\n console.warn(\n `[security] global security requirement (${names.join(', ')}) maps to no header-producing scheme; no auth header emitted on @source.`,\n );\n }\n return null;\n }\n\n return `{ name: \"${auth.name}\", value: \"${auth.value}\" }`;\n }\n\n /**\n * This op's resolved auth, split by placement.\n * - `header`: the header entry in per-op mode (uniform mode puts it on `@source`), else null\n * - `query`: the query entry, always (SourceHTTP has no queryParams), else null\n *\n * Per-op warnings are emitted here with op context; in uniform mode the global warnings were\n * already emitted once by sourceHeader. C3: in per-op mode, the global's dropped-scheme\n * warnings are emitted exactly once (via emitGlobalWarningsOnce) — only genuinely op-specific\n * warnings carry the `(operation …)` suffix.\n */\n forOp(op: Op): { header: NameValue | null; query: NameValue | null } {\n // --skip-auth: no per-@connect auth either (companion to sourceHeader's skip)\n if (this.skipAuth) return { header: null, query: null };\n // `??` not `||`: an explicit `security: []` (public) must NOT fall back to the global.\n const effective = op.operation.schema.security ?? this.globalReq;\n const { auth, warnings } = resolveAuth(effective, this.schemes);\n\n if (this.perOpMode) {\n // surface the global's dropped-scheme warnings exactly once (idempotent), then warn only\n // about op-specific drops with the op's location attached.\n this.emitGlobalWarningsOnce();\n const where = `${op.verb} ${op.operation.path}`;\n for (const w of warnings) {\n if (!this.globalWarningBodies.has(w)) {\n console.warn(`${w} (operation ${where})`);\n }\n }\n }\n\n return {\n header: this.perOpMode && auth?.kind === 'header' ? auth : null,\n query: auth?.kind === 'query' ? auth : null,\n };\n }\n}\n"]}
@@ -19,7 +19,7 @@ export class Writer {
19
19
  // resolve the spec's security once (schemes, global requirement, per-op mode) and share it —
20
20
  // schemaWriter (@source) and operationWriter (per-@connect) both query it instead of re-walking
21
21
  // the whole spec per operation.
22
- const security = SecurityPlan.from(gen.parser);
22
+ const security = SecurityPlan.from(gen.parser, { skipAuth: gen.options.skipAuth });
23
23
  this.schemaWriter = new SchemaWriter(gen, security);
24
24
  this.operationWriter = new OperationWriter(gen, security);
25
25
  }
@@ -56,15 +56,18 @@ export class Writer {
56
56
  this.schemaWriter.writeDirectives(writer);
57
57
  this.schemaWriter.writeJSONScalar(writer);
58
58
  types.forEach((type) => {
59
+ if (!type.name) {
60
+ // Box `metadata_query_indices` has `MetadataQueryIndex.fields.items` as an inline allOf.
61
+ // That node must be named `Fields` before the writer can emit `type Fields { ... }`.
62
+ throw new Error(`[writer] cannot emit a GraphQL definition without a name: id=${type.id}. ` +
63
+ `Name the type where it is created.`);
64
+ }
59
65
  const count = refCount.get(type.name) !== undefined ? refCount.get(type.name) : Infinity;
60
- // a `$ref` is one shared type but can reach here under two ids `obj:type:X` (an array item)
61
- // and `comp:type:X` (a single-member `allOf`). e.g. `AgencyMini`, splitting at `ProgramNormal`:
62
- // …>prop:array:#program>obj:type:#/c/s/ProgramNormal>prop:array:#agencies>obj:type:#/c/s/AgencyMini
63
- // …>prop:array:#program>obj:type:#/c/s/ProgramNormal>prop:array:#mission_patches>obj:type:#/c/s/MissionPatch>prop:comp:agency>comp:type:#/c/s/AgencyMini
64
- // the two ids differ, so the check above doesn't catch the repeat — also check the name it
65
- // will print. use the printed name (`Pet`), not the `$ref`: an output `Pet` and its request
66
- // `PetInput` come from the same `$ref` but are different types, so keying on the `$ref` would
67
- // drop one. see #26
66
+ // `generatedSet` is keyed by internal id, but two ids can print the same GraphQL type.
67
+ // Launch Library reaches `AgencyMini` as both `obj:type:...AgencyMini` (`program.agencies`)
68
+ // and `comp:type:...AgencyMini` (`mission_patches.agency`). Track the printed name too, so
69
+ // `type AgencyMini` is emitted once. Keep the kind suffix because output `Pet` and input
70
+ // `PetInput` can both come from the same $ref.
68
71
  const nameKey = T.isRef(type.name)
69
72
  ? 'name:' + Naming.genTypeName(type.name) + (type.kind === 'input' ? 'Input' : '')
70
73
  : null;
@@ -1 +1 @@
1
- {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../src/oas/io/writer.ts"],"names":[],"mappings":"AACA,OAAO,EAAS,CAAC,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,CAAC,MAAM,QAAQ,CAAC;AAEvB,MAAM,OAAO,MAAM;IAKE;IAJX,YAAY,CAAe;IAC3B,eAAe,CAAkB;IAClC,MAAM,CAAW;IAExB,YAAmB,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;QAC5B,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,6FAA6F;QAC7F,gGAAgG;QAChG,gCAAgC;QAChC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/C,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACpD,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC5D,CAAC;IAEM,KAAK,CAAC,KAAa;QACxB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,KAAK;QACV,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAEM,QAAQ,CAAC,KAAe;QAC7B,MAAM,SAAS,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/C,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAEzB,OAAO,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAChE,CAAC;IAEM,YAAY,CAAC,KAAyB,EAAE,SAAmB;QAChE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QACzC,OAAO,SAAS,CAAC;IACnB,CAAC;IAEM,WAAW,CAAC,MAAc,EAAE,KAAyB,EAAE,SAAmB;QAC/E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAQ,CAAC;QAClC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QAE1C,uFAAuF;QACvF,MAAM,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAE/C,oFAAoF;QACpF,2EAA2E;QAC3E,+EAA+E;QAC/E,oBAAoB,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAE1D,mFAAmF;QACnF,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE9C,6FAA6F;QAC7F,0FAA0F;QAC1F,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAEvD,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC,IAAW,EAAE,EAAE;YAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;YAE1F,8FAA8F;YAC9F,gGAAgG;YAChG,sGAAsG;YACtG,2JAA2J;YAC3J,2FAA2F;YAC3F,4FAA4F;YAC5F,8FAA8F;YAC9F,oBAAoB;YACpB,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;gBAChC,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClF,CAAC,CAAC,IAAI,CAAC;YACT,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACvF,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;gBACxC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC1B,IAAI,OAAO;oBAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACvC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YACrC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAErC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACrF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEnF,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QACrE,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAE3E,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;CACF","sourcesContent":["import { OasGen } from '../oasGen.js';\nimport { IType, T } from '../nodes/internal.js';\nimport { inferEntityResolvers } from '../nodes/entity.js';\nimport { applyBatchResolvers } from '../nodes/batch.js';\nimport { promoteInterfaces } from '../nodes/interfacePromotion.js';\nimport { OperationWriter } from './operationWriter.js';\nimport { SchemaWriter } from './schemaWriter.js';\nimport { SecurityPlan } from './security.js';\nimport { TypesCollector } from '../generator/typesCollector.js';\nimport { Naming } from '../utils/naming.js';\nimport _ from 'lodash';\n\nexport class Writer {\n private schemaWriter: SchemaWriter;\n private operationWriter: OperationWriter;\n public buffer: string[];\n\n constructor(public gen: OasGen) {\n this.buffer = [];\n // resolve the spec's security once (schemes, global requirement, per-op mode) and share it —\n // schemaWriter (@source) and operationWriter (per-@connect) both query it instead of re-walking\n // the whole spec per operation.\n const security = SecurityPlan.from(gen.parser);\n this.schemaWriter = new SchemaWriter(gen, security);\n this.operationWriter = new OperationWriter(gen, security);\n }\n\n public write(input: string): Writer {\n this.buffer.push(input);\n return this;\n }\n\n public flush(): string {\n return this.buffer.join('');\n }\n\n public generate(paths: string[]): string[] {\n const collector = new TypesCollector(this.gen);\n collector.collect(paths);\n\n return this.generateWith(collector.types, collector.expanded);\n }\n\n public generateWith(types: Map<string, IType>, selection: string[]) {\n this.writeSchema(this, types, selection);\n return selection;\n }\n\n public writeSchema(writer: Writer, types: Map<string, IType>, selection: string[]): void {\n const context = this.gen.context!;\n const generatedSet = context.generatedSet;\n\n // make our own copy of the refCount, so it doesn't get modified by the writing process\n const refCount = _.cloneDeep(context.refCount);\n\n // Attach entity resolvers onto the (single, canonical) collected type instances the\n // loop below generates, so each entity type can emit @key + its type-level\n // @connect/$this resolver. Resets first, so it's a no-op when the flag is off.\n inferEntityResolvers(context, this.gen, types, selection);\n\n // R6: add batch resolvers (needs the R1 @key above) when a --batch file was given.\n applyBatchResolvers(context, this.gen, types);\n\n // R2: promote discriminated oneOf-with-shared-allOf-base to a GraphQL interface (id-neutral;\n // no-op unless consolidateUnions is off and a qualifying union exists). Same `types` map.\n promoteInterfaces(context, this.gen, types, selection);\n\n this.schemaWriter.writeDirectives(writer);\n this.schemaWriter.writeJSONScalar(writer);\n\n types.forEach((type: IType) => {\n const count = refCount.get(type.name) !== undefined ? refCount.get(type.name)! : Infinity;\n\n // a `$ref` is one shared type but can reach here under two ids `obj:type:X` (an array item)\n // and `comp:type:X` (a single-member `allOf`). e.g. `AgencyMini`, splitting at `ProgramNormal`:\n // …>prop:array:#program>obj:type:#/c/s/ProgramNormal>prop:array:#agencies>obj:type:#/c/s/AgencyMini\n // …>prop:array:#program>obj:type:#/c/s/ProgramNormal>prop:array:#mission_patches>obj:type:#/c/s/MissionPatch>prop:comp:agency>comp:type:#/c/s/AgencyMini\n // the two ids differ, so the check above doesn't catch the repeat — also check the name it\n // will print. use the printed name (`Pet`), not the `$ref`: an output `Pet` and its request\n // `PetInput` come from the same `$ref` but are different types, so keying on the `$ref` would\n // drop one. see #26\n const nameKey = T.isRef(type.name)\n ? 'name:' + Naming.genTypeName(type.name) + (type.kind === 'input' ? 'Input' : '')\n : null;\n if (!generatedSet.has(type.id) && !(nameKey && generatedSet.has(nameKey)) && count > 0) {\n type.generate(context, this, selection);\n generatedSet.add(type.id);\n if (nameKey) generatedSet.add(nameKey);\n refCount.set(type.name, count - 1);\n }\n });\n\n const expanded = [...this.gen.paths];\n\n const queries = new Map(expanded.filter(([_k, type]) => type.id.startsWith('get:')));\n const mutations = new Map(expanded.filter(([_k, type]) => T.isMutationType(type)));\n\n this.operationWriter.writeQuery(context, writer, queries, selection);\n this.operationWriter.writeMutations(context, writer, mutations, selection);\n\n writer.flush();\n }\n}\n"]}
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../src/oas/io/writer.ts"],"names":[],"mappings":"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","sourcesContent":["import { OasGen } from '../oasGen.js';\nimport { IType, T } from '../nodes/internal.js';\nimport { inferEntityResolvers } from '../nodes/entity.js';\nimport { applyBatchResolvers } from '../nodes/batch.js';\nimport { promoteInterfaces } from '../nodes/interfacePromotion.js';\nimport { OperationWriter } from './operationWriter.js';\nimport { SchemaWriter } from './schemaWriter.js';\nimport { SecurityPlan } from './security.js';\nimport { TypesCollector } from '../generator/typesCollector.js';\nimport { Naming } from '../utils/naming.js';\nimport _ from 'lodash';\n\nexport class Writer {\n private schemaWriter: SchemaWriter;\n private operationWriter: OperationWriter;\n public buffer: string[];\n\n constructor(public gen: OasGen) {\n this.buffer = [];\n // resolve the spec's security once (schemes, global requirement, per-op mode) and share it —\n // schemaWriter (@source) and operationWriter (per-@connect) both query it instead of re-walking\n // the whole spec per operation.\n const security = SecurityPlan.from(gen.parser, { skipAuth: gen.options.skipAuth });\n this.schemaWriter = new SchemaWriter(gen, security);\n this.operationWriter = new OperationWriter(gen, security);\n }\n\n public write(input: string): Writer {\n this.buffer.push(input);\n return this;\n }\n\n public flush(): string {\n return this.buffer.join('');\n }\n\n public generate(paths: string[]): string[] {\n const collector = new TypesCollector(this.gen);\n collector.collect(paths);\n\n return this.generateWith(collector.types, collector.expanded);\n }\n\n public generateWith(types: Map<string, IType>, selection: string[]) {\n this.writeSchema(this, types, selection);\n return selection;\n }\n\n public writeSchema(writer: Writer, types: Map<string, IType>, selection: string[]): void {\n const context = this.gen.context!;\n const generatedSet = context.generatedSet;\n\n // make our own copy of the refCount, so it doesn't get modified by the writing process\n const refCount = _.cloneDeep(context.refCount);\n\n // Attach entity resolvers onto the (single, canonical) collected type instances the\n // loop below generates, so each entity type can emit @key + its type-level\n // @connect/$this resolver. Resets first, so it's a no-op when the flag is off.\n inferEntityResolvers(context, this.gen, types, selection);\n\n // R6: add batch resolvers (needs the R1 @key above) when a --batch file was given.\n applyBatchResolvers(context, this.gen, types);\n\n // R2: promote discriminated oneOf-with-shared-allOf-base to a GraphQL interface (id-neutral;\n // no-op unless consolidateUnions is off and a qualifying union exists). Same `types` map.\n promoteInterfaces(context, this.gen, types, selection);\n\n this.schemaWriter.writeDirectives(writer);\n this.schemaWriter.writeJSONScalar(writer);\n\n types.forEach((type: IType) => {\n if (!type.name) {\n // Box `metadata_query_indices` has `MetadataQueryIndex.fields.items` as an inline allOf.\n // That node must be named `Fields` before the writer can emit `type Fields { ... }`.\n throw new Error(\n `[writer] cannot emit a GraphQL definition without a name: id=${type.id}. ` +\n `Name the type where it is created.`,\n );\n }\n\n const count = refCount.get(type.name) !== undefined ? refCount.get(type.name)! : Infinity;\n\n // `generatedSet` is keyed by internal id, but two ids can print the same GraphQL type.\n // Launch Library reaches `AgencyMini` as both `obj:type:...AgencyMini` (`program.agencies`)\n // and `comp:type:...AgencyMini` (`mission_patches.agency`). Track the printed name too, so\n // `type AgencyMini` is emitted once. Keep the kind suffix because output `Pet` and input\n // `PetInput` can both come from the same $ref.\n const nameKey = T.isRef(type.name)\n ? 'name:' + Naming.genTypeName(type.name) + (type.kind === 'input' ? 'Input' : '')\n : null;\n\n if (!generatedSet.has(type.id) && !(nameKey && generatedSet.has(nameKey)) && count > 0) {\n type.generate(context, this, selection);\n generatedSet.add(type.id);\n if (nameKey) generatedSet.add(nameKey);\n refCount.set(type.name, count - 1);\n }\n });\n\n const expanded = [...this.gen.paths];\n\n const queries = new Map(expanded.filter(([_k, type]) => type.id.startsWith('get:')));\n const mutations = new Map(expanded.filter(([_k, type]) => T.isMutationType(type)));\n\n this.operationWriter.writeQuery(context, writer, queries, selection);\n this.operationWriter.writeMutations(context, writer, mutations, selection);\n\n writer.flush();\n }\n}\n"]}
@@ -171,26 +171,31 @@ export class Composed extends Type {
171
171
  return super.add(this.withUniqueName(child));
172
172
  }
173
173
  updateName() {
174
- let name = this.name;
175
- if (!name) {
176
- if (this.parent instanceof Res) {
177
- const op = this.parent.parent;
178
- name = op.getGqlOpName() + 'Response';
179
- }
180
- else if (this.schema?.allOf?.length === 1) {
181
- // single member: adopt its ref name (avoids an unusable '[inline:…]' name). see docs/issues.md #7
182
- name = _.get(this.schema?.allOf[0], '$ref');
183
- }
184
- else if (this.parent instanceof Prop) {
185
- // emitted inline allOf-property type needs a real name, not '[inline:…]'. see docs/issues.md #7
186
- name = Naming.genTypeName(Naming.getRefName(this.parent.name));
187
- }
188
- else {
189
- // consolidated allOf member: keep the '[inline:…]' id that selection paths reference. issue #7
190
- name = `[inline:${this.parent.name}]`;
174
+ if (this.name) {
175
+ return;
176
+ }
177
+ if (this.parent instanceof Res) {
178
+ const op = this.parent.parent;
179
+ this.name = op.getGqlOpName() + 'Response';
180
+ return;
181
+ }
182
+ if (this.schema?.allOf?.length === 1) {
183
+ // A single-member allOf with a $ref is just a wrapper around that component:
184
+ // `allOf: [{ $ref: "#/components/schemas/Field" }]` emits `Field`.
185
+ // A single inline member has no component name, so `fields.items.allOf: [{ type: object }]`
186
+ // falls through and is named from the parent field as `Fields`.
187
+ const ref = _.get(this.schema.allOf[0], '$ref');
188
+ if (ref) {
189
+ this.name = ref;
190
+ return;
191
191
  }
192
192
  }
193
- this.name = name;
193
+ if (this.parent instanceof Prop) {
194
+ this.name = Naming.genTypeName(Naming.getRefName(this.parent.name));
195
+ return;
196
+ }
197
+ // Consolidated allOf members keep the internal id that selection paths reference.
198
+ this.name = `[inline:${this.parent.name}]`;
194
199
  }
195
200
  }
196
201
  //# sourceMappingURL=comp.js.map