apollo-conn-gen 0.15.1 → 0.15.3

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.
Files changed (46) hide show
  1. package/dist/oas/generator/typesCollector.js +11 -1
  2. package/dist/oas/generator/typesCollector.js.map +1 -1
  3. package/dist/oas/io/errorsWriter.js +1 -9
  4. package/dist/oas/io/errorsWriter.js.map +1 -1
  5. package/dist/oas/io/operationWriter.js +1 -11
  6. package/dist/oas/io/operationWriter.js.map +1 -1
  7. package/dist/oas/io/schemaWriter.d.ts +0 -1
  8. package/dist/oas/io/schemaWriter.js +3 -14
  9. package/dist/oas/io/schemaWriter.js.map +1 -1
  10. package/dist/oas/io/writer.js +3 -3
  11. package/dist/oas/io/writer.js.map +1 -1
  12. package/dist/oas/nodes/{interfacePromotion.d.ts → allOfBase.d.ts} +2 -4
  13. package/dist/oas/nodes/{interfacePromotion.js → allOfBase.js} +7 -8
  14. package/dist/oas/nodes/allOfBase.js.map +1 -0
  15. package/dist/oas/nodes/batch.js +1 -7
  16. package/dist/oas/nodes/batch.js.map +1 -1
  17. package/dist/oas/nodes/comp.js +1 -1
  18. package/dist/oas/nodes/comp.js.map +1 -1
  19. package/dist/oas/nodes/obj.js +1 -1
  20. package/dist/oas/nodes/obj.js.map +1 -1
  21. package/dist/oas/nodes/param.d.ts +2 -0
  22. package/dist/oas/nodes/param.js +26 -1
  23. package/dist/oas/nodes/param.js.map +1 -1
  24. package/dist/oas/nodes/propMap.js +7 -7
  25. package/dist/oas/nodes/propMap.js.map +1 -1
  26. package/dist/oas/nodes/union.d.ts +3 -0
  27. package/dist/oas/nodes/union.js +53 -62
  28. package/dist/oas/nodes/union.js.map +1 -1
  29. package/dist/oas/oasContext.d.ts +0 -1
  30. package/dist/oas/oasContext.js +0 -1
  31. package/dist/oas/oasContext.js.map +1 -1
  32. package/dist/oas/oasGen.d.ts +0 -1
  33. package/dist/oas/oasGen.js +2 -9
  34. package/dist/oas/oasGen.js.map +1 -1
  35. package/dist/oas/utils/serverUrl.d.ts +5 -0
  36. package/dist/oas/utils/serverUrl.js +25 -0
  37. package/dist/oas/utils/serverUrl.js.map +1 -0
  38. package/dist/tests/runners.d.ts +0 -1
  39. package/dist/tests/runners.js +33 -25
  40. package/dist/tests/runners.js.map +1 -1
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/dist/versions.d.ts +2 -11
  43. package/dist/versions.js +13 -33
  44. package/dist/versions.js.map +1 -1
  45. package/package.json +2 -2
  46. package/dist/oas/nodes/interfacePromotion.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import _ from 'lodash';
2
2
  import { Composed } from '../nodes/comp.js';
3
- import { Prop, PropArray, PropCircRef, PropEn, PropObj, Scalar, T } from '../nodes/internal.js';
3
+ import { Prop, PropArray, PropCircRef, PropEn, PropObj, Res, Scalar, T } from '../nodes/internal.js';
4
4
  import { Naming } from '../utils/naming.js';
5
5
  export class TypesCollector {
6
6
  gen;
@@ -240,6 +240,16 @@ class PathsCollector {
240
240
  // SDL and the selection) instead of silently dropped. see docs/issues.md #10
241
241
  newSelection.add(child.path());
242
242
  }
243
+ else if (child instanceof Scalar && child.parent instanceof Res) {
244
+ // a response that resolves directly to a bare scalar (no property/array/map wrapper) is
245
+ // a leaf too — e.g. a write op that just returns `true` (adobe commerce) or a bare token
246
+ // string (petstore `/user/login`). Without this the op has nothing selectable and is
247
+ // dropped from the schema entirely (not degraded — silently absent). Res.select already
248
+ // emits `$` for it; only the leaf-detection here was missing the case. Scoped to a direct
249
+ // Res child on purpose — a bare scalar nested deeper (e.g. inside a Map's value) has its
250
+ // own separate, unrelated selection gaps; this fix doesn't touch those.
251
+ newSelection.add(child.path());
252
+ }
243
253
  else {
244
254
  this.gen.expand(child);
245
255
  }
@@ -1 +1 @@
1
- {"version":3,"file":"typesCollector.js","sourceRoot":"","sources":["../../../src/oas/generator/typesCollector.ts"],"names":[],"mappings":"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","sourcesContent":["import _ from 'lodash';\nimport { Composed } from '../nodes/comp.js';\nimport { IType, Prop, PropArray, PropCircRef, PropEn, PropObj, Scalar, T } from '../nodes/internal.js';\nimport { OasGen } from '../oasGen.js';\nimport { Naming } from '../utils/naming.js';\n\nexport class TypesCollector {\n types: Map<string, IType> = new Map();\n expanded: string[] = [];\n\n constructor(private gen: OasGen) {}\n\n public collect(selection: string[]): void {\n const pendingTypes: Map<string, IType> = new Map();\n let expanded: string[] = new PathsCollector(this.gen).collectExpandedPaths(selection);\n\n for (const path of expanded) {\n let collection = Array.from(this.gen.paths.values());\n let current: IType | undefined;\n let last: IType | undefined;\n\n let i = 0;\n const parts = path.split('>');\n do {\n const part = Naming.expandRef(parts[i]);\n if (part === '*') {\n // remove the current path from the expanded array\n expanded = expanded.filter((s) => s !== path);\n\n if (current && current instanceof Composed) {\n current!.consolidate(expanded);\n }\n\n // add all the props from the current node and exit loop\n current?.props.forEach((child) => {\n if (T.isLeaf(child)) {\n expanded.push(child.path());\n }\n });\n break;\n }\n\n current = collection.find((t) => t.id === part);\n if (!current) {\n const tree = T.print(last!.ancestors()[0]);\n\n // let's collect the possible paths so we don't have to debug\n throw new Error(\n 'Could not find type: ' + part + ' from ' + path + '\\nlast:\\n' + last?.pathToRoot() + '\\ntree: ' + tree,\n );\n }\n\n // make sure we expand it before we move on to the next part\n this.gen.expand(current);\n last = current;\n\n collection = Array.from(current!.children.values()) || Array.from(current!.props.values()) || [];\n i++;\n } while (i < parts.length);\n\n if (current && !(current instanceof Scalar)) {\n const parentType = T.findNonPropParent(current as IType);\n if (!pendingTypes.has(parentType.id)) {\n pendingTypes.set(parentType.id, parentType);\n }\n\n // add all ancestors (of the parent of the prop) that are containers so they are generated accordingly\n parentType\n .ancestors()\n .filter((t) => !pendingTypes.has(t.id) && T.isContainer(t))\n .forEach((dep) => {\n pendingTypes.set(dep.id, dep);\n });\n }\n }\n\n // One operation can reach the same schema through several routes, and each route builds its\n // own node for it. Cycle detection (#10) removes a field from a node when that field would\n // loop back to an ancestor of ITS route — so two nodes for the same schema can end up with\n // different fields. Only one of them is written to the output schema (the first one found),\n // but the connector selection is assembled from ALL routes: it can ask for a field the\n // written node doesn't have, and composition fails (SELECTED_FIELD_NOT_FOUND).\n //\n // e.g. (confluence, one op): `Space` is reached twice —\n // via Content: its `history` field was removed (history loops back to Content)\n // via Results: `history` kept — and that route's selection asks for it\n //\n // The routes are already spelled out in `expanded`, so for each removed field we look for a\n // selection path carrying the real field under the same type id, walk that path to its node,\n // and tell the writer to emit that version of the field (context.sdlPropOverrides — the TYPE\n // DEFINITION only; selections are left alone, each route keeps its own \"field removed\"\n // comment. Putting the field back into props re-created the loop cycle detection had just\n // broken: rover CIRCULAR_REFERENCE). Because the replacement comes FROM the selection, a\n // field nobody selects is never added (CONNECTORS_UNRESOLVED_FIELD, test_040 AdobeCommerce).\n // see docs/issues.md #13\n const context = this.gen.context!;\n for (const kept of pendingTypes.values()) {\n kept.props.forEach((prop, name) => {\n if (!(prop instanceof PropCircRef)) {\n return;\n }\n const donor = this.findSelectedFieldNode(kept, name, expanded);\n if (donor) {\n let overrides = context.sdlPropOverrides.get(kept);\n if (!overrides) {\n overrides = new Map();\n context.sdlPropOverrides.set(kept, overrides);\n }\n overrides.set(name, donor);\n }\n });\n }\n\n // first pass is to consolidate all Composed & Union nodes\n const composed: Array<Composed> = Array.from(pendingTypes.values())\n .filter((t) => t instanceof Composed)\n .map((t) => t as Composed);\n\n for (const comp of composed) {\n if (!comp.visited) comp.visit(context);\n comp.consolidate(expanded).forEach((id) => pendingTypes.delete(id));\n }\n\n // keep exactly the types the written schema references: confluence emitted `Label` with\n // nothing selecting it, box dropped `Folder--Mini` while still referencing it. see #26\n const reachable = this.collectReachable(expanded);\n for (const [id, type] of Array.from(pendingTypes.entries())) {\n if (!reachable.has(type)) {\n pendingTypes.delete(id);\n }\n }\n for (const type of reachable) {\n if (!pendingTypes.has(type.id)) {\n pendingTypes.set(type.id, type);\n }\n }\n\n this.types = pendingTypes;\n this.expanded = expanded;\n }\n\n // Every type the written schema will point at, walked over each node's own dependencies()\n // from the selected operations' result/body. e.g. `getUser: User` + `User.address: Address`\n // reaches { User, Address }. see #26\n private collectReachable(expanded: string[]): Set<IType> {\n const context = this.gen.context!;\n const opIds = new Set(expanded.map((p) => p.split('>')[0]));\n\n const queue: IType[] = [];\n for (const op of this.gen.paths.values()) {\n if (opIds.has(op.id)) {\n const roots = [_.get(op, 'resultType'), _.get(op, 'body')] as Array<IType | undefined>;\n queue.push(...roots.filter((n): n is IType => !!n));\n }\n }\n\n const visited = new Set<IType>();\n while (queue.length > 0) {\n const node = queue.pop()!;\n if (visited.has(node)) {\n continue;\n }\n // every container was expanded by the collect loop before this walk — an unvisited one\n // means a missed reference, and writing it would silently truncate the schema. Enums are\n // exempt: they are complete at construction and their visit() only registers the name.\n // dependencies() implementations must stay read-only: no visit(), no context stack. #26\n if (!node.visited && T.isContainer(node)) {\n throw new Error(`collectReachable: unvisited type ${node.id} — the collect walk missed a reference`);\n }\n visited.add(node);\n queue.push(...node.dependencies(context, expanded));\n }\n\n return new Set(Array.from(visited).filter(T.isEmittable));\n }\n\n // A selection path that carries the real `name` field under this type id (`>obj:type:X>prop:…:name>`),\n // walked to its node — the un-removed version of a field this node lost to a cycle cut. see #13\n private findSelectedFieldNode(kept: IType, name: string, expanded: string[]): IType | undefined {\n // selection paths abbreviate component refs (`path()` writes `#/c/s`); match that form\n const marker = `>${Naming.abbreviateRef(kept.id)}>`;\n for (const sel of expanded) {\n const at = sel.indexOf(marker);\n if (at < 0) {\n continue;\n }\n const segment = sel.slice(at + marker.length).split('>')[0];\n const isRealProp = segment.startsWith('prop:') && !segment.startsWith('prop:circular-ref');\n if (!isRealProp || !(segment.endsWith(':' + name) || segment.endsWith(':#' + name))) {\n continue;\n }\n const donorPath = sel.slice(0, at + marker.length + segment.length);\n const stack = new PathsCollector(this.gen).collectPaths(donorPath, Array.from(this.gen.paths.values()));\n const donor = stack[stack.length - 1];\n if (donor && !(donor instanceof PropCircRef)) {\n return donor;\n }\n }\n return undefined;\n }\n}\n\nclass PathsCollector {\n constructor(private gen: OasGen) {}\n\n public static findNonPropParent(type: IType) {\n let parent = type;\n while (parent instanceof Prop) {\n parent = parent.parent!;\n }\n return parent;\n }\n\n public static progressiveSplits(input: string): string[] {\n const parts = input.split('>');\n const results: string[] = [];\n for (let i = 1; i <= parts.length; i++) {\n results.push(parts.slice(0, i).join('>'));\n }\n return results;\n }\n\n public collectPaths(path: string, collection: IType[]): IType[] {\n const stack: IType[] = [];\n let current: IType | undefined;\n let last: IType | undefined;\n\n let i = 0;\n const parts = path.split('>');\n do {\n const part = Naming.expandRef(parts[i]);\n\n current = collection.find((t) => t.id === part);\n if (!current) {\n throw new Error('Could not find type: ' + part + ' from ' + path + ', last: ' + last?.pathToRoot());\n }\n\n // make sure we expand it before we move on to the next part\n this.gen.expand(current);\n last = current;\n\n collection = Array.from(current!.children.values()) || Array.from(current!.props.values()) || [];\n\n stack.push(current);\n i++;\n } while (i < parts.length);\n\n return stack;\n }\n\n public collectExpandedPaths(selection: string[]) {\n const newSelection = new Set<string>();\n const expands = selection.filter((p) => p.endsWith('>**'));\n const filtered = expands.map((p) => p.replace('>**', ''));\n\n const paths = Array.from(this.gen.paths.values());\n const nodes = filtered.map((p) => this.collectPaths(p, paths));\n\n nodes.forEach((stack) => {\n const root = _.last(stack)!;\n T.traverse(root, (child) => {\n if (T.isPropScalar(child) || (child instanceof PropArray && child.items instanceof Scalar)) {\n newSelection.add(child.path());\n } else if (child instanceof PropEn) {\n // enum props are leaves too — without this, `>**` silently drops every enum field\n // (slack's `ok`-only stubs collapsed to zero types). see docs/issues.md #24\n newSelection.add(child.path());\n } else if (child instanceof PropCircRef) {\n // a cut cycle is a leaf: include its path so the commented field is emitted (in both the\n // SDL and the selection) instead of silently dropped. see docs/issues.md #10\n newSelection.add(child.path());\n } else {\n this.gen.expand(child);\n }\n });\n\n // an op whose expansion found nothing selectable still has fields to write when its only\n // content is a free-form JSON object (asana: `data: $ref EmptyResponse` -> `data: JSON`,\n // emitted as an EMPTY invalid type before) — take those fields as the leaves. Scoped to\n // otherwise-empty ops on purpose: doing it everywhere diverged the selections of types\n // shared across connectors. see docs/issues.md #32\n if (!Array.from(newSelection).some((p) => p.startsWith(root.path()))) {\n T.traverse(root, (child) => {\n if (child instanceof PropObj && _.isEmpty(child.obj?.props)) {\n newSelection.add(child.path());\n }\n });\n }\n });\n\n // finally remove the expanded paths from the selection\n return [...newSelection, ...selection.filter((p) => !expands.includes(p))];\n }\n}\n"]}
1
+ {"version":3,"file":"typesCollector.js","sourceRoot":"","sources":["../../../src/oas/generator/typesCollector.ts"],"names":[],"mappings":"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","sourcesContent":["import _ from 'lodash';\nimport { Composed } from '../nodes/comp.js';\nimport { IType, Prop, PropArray, PropCircRef, PropEn, PropObj, Res, Scalar, T } from '../nodes/internal.js';\nimport { OasGen } from '../oasGen.js';\nimport { Naming } from '../utils/naming.js';\n\nexport class TypesCollector {\n types: Map<string, IType> = new Map();\n expanded: string[] = [];\n\n constructor(private gen: OasGen) {}\n\n public collect(selection: string[]): void {\n const pendingTypes: Map<string, IType> = new Map();\n let expanded: string[] = new PathsCollector(this.gen).collectExpandedPaths(selection);\n\n for (const path of expanded) {\n let collection = Array.from(this.gen.paths.values());\n let current: IType | undefined;\n let last: IType | undefined;\n\n let i = 0;\n const parts = path.split('>');\n do {\n const part = Naming.expandRef(parts[i]);\n if (part === '*') {\n // remove the current path from the expanded array\n expanded = expanded.filter((s) => s !== path);\n\n if (current && current instanceof Composed) {\n current!.consolidate(expanded);\n }\n\n // add all the props from the current node and exit loop\n current?.props.forEach((child) => {\n if (T.isLeaf(child)) {\n expanded.push(child.path());\n }\n });\n break;\n }\n\n current = collection.find((t) => t.id === part);\n if (!current) {\n const tree = T.print(last!.ancestors()[0]);\n\n // let's collect the possible paths so we don't have to debug\n throw new Error(\n 'Could not find type: ' + part + ' from ' + path + '\\nlast:\\n' + last?.pathToRoot() + '\\ntree: ' + tree,\n );\n }\n\n // make sure we expand it before we move on to the next part\n this.gen.expand(current);\n last = current;\n\n collection = Array.from(current!.children.values()) || Array.from(current!.props.values()) || [];\n i++;\n } while (i < parts.length);\n\n if (current && !(current instanceof Scalar)) {\n const parentType = T.findNonPropParent(current as IType);\n if (!pendingTypes.has(parentType.id)) {\n pendingTypes.set(parentType.id, parentType);\n }\n\n // add all ancestors (of the parent of the prop) that are containers so they are generated accordingly\n parentType\n .ancestors()\n .filter((t) => !pendingTypes.has(t.id) && T.isContainer(t))\n .forEach((dep) => {\n pendingTypes.set(dep.id, dep);\n });\n }\n }\n\n // One operation can reach the same schema through several routes, and each route builds its\n // own node for it. Cycle detection (#10) removes a field from a node when that field would\n // loop back to an ancestor of ITS route — so two nodes for the same schema can end up with\n // different fields. Only one of them is written to the output schema (the first one found),\n // but the connector selection is assembled from ALL routes: it can ask for a field the\n // written node doesn't have, and composition fails (SELECTED_FIELD_NOT_FOUND).\n //\n // e.g. (confluence, one op): `Space` is reached twice —\n // via Content: its `history` field was removed (history loops back to Content)\n // via Results: `history` kept — and that route's selection asks for it\n //\n // The routes are already spelled out in `expanded`, so for each removed field we look for a\n // selection path carrying the real field under the same type id, walk that path to its node,\n // and tell the writer to emit that version of the field (context.sdlPropOverrides — the TYPE\n // DEFINITION only; selections are left alone, each route keeps its own \"field removed\"\n // comment. Putting the field back into props re-created the loop cycle detection had just\n // broken: rover CIRCULAR_REFERENCE). Because the replacement comes FROM the selection, a\n // field nobody selects is never added (CONNECTORS_UNRESOLVED_FIELD, test_040 AdobeCommerce).\n // see docs/issues.md #13\n const context = this.gen.context!;\n for (const kept of pendingTypes.values()) {\n kept.props.forEach((prop, name) => {\n if (!(prop instanceof PropCircRef)) {\n return;\n }\n const donor = this.findSelectedFieldNode(kept, name, expanded);\n if (donor) {\n let overrides = context.sdlPropOverrides.get(kept);\n if (!overrides) {\n overrides = new Map();\n context.sdlPropOverrides.set(kept, overrides);\n }\n overrides.set(name, donor);\n }\n });\n }\n\n // first pass is to consolidate all Composed & Union nodes\n const composed: Array<Composed> = Array.from(pendingTypes.values())\n .filter((t) => t instanceof Composed)\n .map((t) => t as Composed);\n\n for (const comp of composed) {\n if (!comp.visited) comp.visit(context);\n comp.consolidate(expanded).forEach((id) => pendingTypes.delete(id));\n }\n\n // keep exactly the types the written schema references: confluence emitted `Label` with\n // nothing selecting it, box dropped `Folder--Mini` while still referencing it. see #26\n const reachable = this.collectReachable(expanded);\n for (const [id, type] of Array.from(pendingTypes.entries())) {\n if (!reachable.has(type)) {\n pendingTypes.delete(id);\n }\n }\n for (const type of reachable) {\n if (!pendingTypes.has(type.id)) {\n pendingTypes.set(type.id, type);\n }\n }\n\n this.types = pendingTypes;\n this.expanded = expanded;\n }\n\n // Every type the written schema will point at, walked over each node's own dependencies()\n // from the selected operations' result/body. e.g. `getUser: User` + `User.address: Address`\n // reaches { User, Address }. see #26\n private collectReachable(expanded: string[]): Set<IType> {\n const context = this.gen.context!;\n const opIds = new Set(expanded.map((p) => p.split('>')[0]));\n\n const queue: IType[] = [];\n for (const op of this.gen.paths.values()) {\n if (opIds.has(op.id)) {\n const roots = [_.get(op, 'resultType'), _.get(op, 'body')] as Array<IType | undefined>;\n queue.push(...roots.filter((n): n is IType => !!n));\n }\n }\n\n const visited = new Set<IType>();\n while (queue.length > 0) {\n const node = queue.pop()!;\n if (visited.has(node)) {\n continue;\n }\n // every container was expanded by the collect loop before this walk — an unvisited one\n // means a missed reference, and writing it would silently truncate the schema. Enums are\n // exempt: they are complete at construction and their visit() only registers the name.\n // dependencies() implementations must stay read-only: no visit(), no context stack. #26\n if (!node.visited && T.isContainer(node)) {\n throw new Error(`collectReachable: unvisited type ${node.id} — the collect walk missed a reference`);\n }\n visited.add(node);\n queue.push(...node.dependencies(context, expanded));\n }\n\n return new Set(Array.from(visited).filter(T.isEmittable));\n }\n\n // A selection path that carries the real `name` field under this type id (`>obj:type:X>prop:…:name>`),\n // walked to its node — the un-removed version of a field this node lost to a cycle cut. see #13\n private findSelectedFieldNode(kept: IType, name: string, expanded: string[]): IType | undefined {\n // selection paths abbreviate component refs (`path()` writes `#/c/s`); match that form\n const marker = `>${Naming.abbreviateRef(kept.id)}>`;\n for (const sel of expanded) {\n const at = sel.indexOf(marker);\n if (at < 0) {\n continue;\n }\n const segment = sel.slice(at + marker.length).split('>')[0];\n const isRealProp = segment.startsWith('prop:') && !segment.startsWith('prop:circular-ref');\n if (!isRealProp || !(segment.endsWith(':' + name) || segment.endsWith(':#' + name))) {\n continue;\n }\n const donorPath = sel.slice(0, at + marker.length + segment.length);\n const stack = new PathsCollector(this.gen).collectPaths(donorPath, Array.from(this.gen.paths.values()));\n const donor = stack[stack.length - 1];\n if (donor && !(donor instanceof PropCircRef)) {\n return donor;\n }\n }\n return undefined;\n }\n}\n\nclass PathsCollector {\n constructor(private gen: OasGen) {}\n\n public static findNonPropParent(type: IType) {\n let parent = type;\n while (parent instanceof Prop) {\n parent = parent.parent!;\n }\n return parent;\n }\n\n public static progressiveSplits(input: string): string[] {\n const parts = input.split('>');\n const results: string[] = [];\n for (let i = 1; i <= parts.length; i++) {\n results.push(parts.slice(0, i).join('>'));\n }\n return results;\n }\n\n public collectPaths(path: string, collection: IType[]): IType[] {\n const stack: IType[] = [];\n let current: IType | undefined;\n let last: IType | undefined;\n\n let i = 0;\n const parts = path.split('>');\n do {\n const part = Naming.expandRef(parts[i]);\n\n current = collection.find((t) => t.id === part);\n if (!current) {\n throw new Error('Could not find type: ' + part + ' from ' + path + ', last: ' + last?.pathToRoot());\n }\n\n // make sure we expand it before we move on to the next part\n this.gen.expand(current);\n last = current;\n\n collection = Array.from(current!.children.values()) || Array.from(current!.props.values()) || [];\n\n stack.push(current);\n i++;\n } while (i < parts.length);\n\n return stack;\n }\n\n public collectExpandedPaths(selection: string[]) {\n const newSelection = new Set<string>();\n const expands = selection.filter((p) => p.endsWith('>**'));\n const filtered = expands.map((p) => p.replace('>**', ''));\n\n const paths = Array.from(this.gen.paths.values());\n const nodes = filtered.map((p) => this.collectPaths(p, paths));\n\n nodes.forEach((stack) => {\n const root = _.last(stack)!;\n T.traverse(root, (child) => {\n if (T.isPropScalar(child) || (child instanceof PropArray && child.items instanceof Scalar)) {\n newSelection.add(child.path());\n } else if (child instanceof PropEn) {\n // enum props are leaves too — without this, `>**` silently drops every enum field\n // (slack's `ok`-only stubs collapsed to zero types). see docs/issues.md #24\n newSelection.add(child.path());\n } else if (child instanceof PropCircRef) {\n // a cut cycle is a leaf: include its path so the commented field is emitted (in both the\n // SDL and the selection) instead of silently dropped. see docs/issues.md #10\n newSelection.add(child.path());\n } else if (child instanceof Scalar && child.parent instanceof Res) {\n // a response that resolves directly to a bare scalar (no property/array/map wrapper) is\n // a leaf too — e.g. a write op that just returns `true` (adobe commerce) or a bare token\n // string (petstore `/user/login`). Without this the op has nothing selectable and is\n // dropped from the schema entirely (not degraded — silently absent). Res.select already\n // emits `$` for it; only the leaf-detection here was missing the case. Scoped to a direct\n // Res child on purpose — a bare scalar nested deeper (e.g. inside a Map's value) has its\n // own separate, unrelated selection gaps; this fix doesn't touch those.\n newSelection.add(child.path());\n } else {\n this.gen.expand(child);\n }\n });\n\n // an op whose expansion found nothing selectable still has fields to write when its only\n // content is a free-form JSON object (asana: `data: $ref EmptyResponse` -> `data: JSON`,\n // emitted as an EMPTY invalid type before) — take those fields as the leaves. Scoped to\n // otherwise-empty ops on purpose: doing it everywhere diverged the selections of types\n // shared across connectors. see docs/issues.md #32\n if (!Array.from(newSelection).some((p) => p.startsWith(root.path()))) {\n T.traverse(root, (child) => {\n if (child instanceof PropObj && _.isEmpty(child.obj?.props)) {\n newSelection.add(child.path());\n }\n });\n }\n });\n\n // finally remove the expanded paths from the selection\n return [...newSelection, ...selection.filter((p) => !expands.includes(p))];\n }\n}\n"]}
@@ -1,6 +1,4 @@
1
1
  import _ from 'lodash';
2
- import { DEFAULT_VERSIONS, meetsMinimum } from '../../versions.js';
3
- import { warn } from '../log/trace.js';
4
2
  // R4 (opt-in): the `errors:` block of a connector — `message` from the documented error body,
5
3
  // `extensions` carrying `$status`.
6
4
  export class ErrorsWriter {
@@ -12,17 +10,11 @@ export class ErrorsWriter {
12
10
  this.gen = gen;
13
11
  }
14
12
  // emit an `errors { message extensions { statusCode: $status } }` block for operations that
15
- // document HTTP error responses. errors is a connect v0.2+ feature; below that we skip
16
- // with a logged downgrade rather than emit invalid output.
13
+ // document HTTP error responses.
17
14
  write(context, writer, op, indent) {
18
15
  if (!context.generateOptions?.emitConnectorErrors || !this.hasDocumentedErrors(op)) {
19
16
  return;
20
17
  }
21
- const version = this.gen.options.connectorSpecVersion || DEFAULT_VERSIONS.connectorSpecVersion;
22
- if (!meetsMinimum(version, 'v0.2')) {
23
- warn(context, '[errors]', `@connect(errors:) requires connect v0.2, but target is ${version} — not emitted for ${op.verb} ${op.operation.path}`);
24
- return;
25
- }
26
18
  // `message: "$.message"` — the path form yields the field's VALUE; a bare `message`
27
19
  // selection would build the object `{message: …}`, which errors.message rejects. R4
28
20
  const message = this.errorMessageField(context, op);
@@ -1 +1 @@
1
- {"version":3,"file":"errorsWriter.js","sourceRoot":"","sources":["../../../src/oas/io/errorsWriter.ts"],"names":[],"mappings":"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","sourcesContent":["import _ from 'lodash';\nimport { ResponseObject, SchemaObject } from 'oas/types';\nimport { OasContext } from '../oasContext.js';\nimport { OasGen } from '../oasGen.js';\nimport { Op } from '../nodes/internal.js';\nimport { Writer } from './writer.js';\nimport { DEFAULT_VERSIONS, meetsMinimum } from '../../versions.js';\nimport { warn } from '../log/trace.js';\n\n// R4 (opt-in): the `errors:` block of a connector — `message` from the documented error body,\n// `extensions` carrying `$status`.\nexport class ErrorsWriter {\n // corpus-measured priority for the error-body message field: `message` (755 error schemas),\n // `error` (362), `detail` (7)\n private static readonly MESSAGE_FIELDS = ['message', 'error', 'detail'];\n\n constructor(private gen: OasGen) {}\n\n // emit an `errors { message extensions { statusCode: $status } }` block for operations that\n // document HTTP error responses. errors is a connect v0.2+ feature; below that we skip\n // with a logged downgrade rather than emit invalid output.\n public write(context: OasContext, writer: Writer, op: Op, indent: number): void {\n if (!context.generateOptions?.emitConnectorErrors || !this.hasDocumentedErrors(op)) {\n return;\n }\n\n const version = this.gen.options.connectorSpecVersion || DEFAULT_VERSIONS.connectorSpecVersion;\n if (!meetsMinimum(version, 'v0.2')) {\n warn(\n context,\n '[errors]',\n `@connect(errors:) requires connect v0.2, but target is ${version} — not emitted for ${op.verb} ${op.operation.path}`,\n );\n return;\n }\n\n // `message: \"$.message\"` — the path form yields the field's VALUE; a bare `message`\n // selection would build the object `{message: …}`, which errors.message rejects. R4\n const message = this.errorMessageField(context, op);\n\n // fully expanded: `errors {` and `}` at the @connect arg level, message/extensions/body/closing\n // one level deeper (8 spaces) so the body and the closing `\"\"\"` line up.\n const labelSpacing = ' '.repeat(indent + 6);\n const innerSpacing = ' '.repeat(indent + 8);\n writer.write(labelSpacing).write('errors: {\\n');\n if (message) {\n writer.write(innerSpacing).write(`message: \"$.${message}\"\\n`);\n }\n writer\n .write(innerSpacing)\n .write('extensions: \"\"\"\\n')\n .write(innerSpacing)\n .write('statusCode: $status\\n')\n .write(innerSpacing)\n .write('\"\"\"\\n')\n .write(labelSpacing)\n .write('}\\n');\n }\n\n // True when the operation documents an HTTP error response. Accepts both concrete numeric statuses\n // (4xx/5xx) and the OAS range keys `4XX`/`5XX` (case-insensitive). The `default` key is excluded —\n // it also covers 2xx/3xx, so it is not specifically an error indicator.\n private hasDocumentedErrors(op: Op): boolean {\n return op.operation.getResponseStatusCodes().some((code: string) => /^[45](\\d\\d|XX)$/i.test(code));\n }\n\n // the field must be a string on EVERY documented JSON error shape — a field missing on some\n // status would yield a null message there. Non-JSON / shapeless error responses don't veto.\n private errorMessageField(context: OasContext, op: Op): string | undefined {\n const responses = op.operation.schema.responses ?? {};\n const errorShapes: Array<Record<string, unknown>> = [];\n\n for (const [code, response] of Object.entries(responses)) {\n if (!/^[45](\\d\\d|XX)$/i.test(code)) {\n continue;\n }\n const resolved = this.deref(context, response) as ResponseObject | null;\n const mediaKey = Object.keys(resolved?.content ?? {}).find((k) => /^application\\/(?:.*\\+)?json/i.test(k));\n const schema = mediaKey\n ? (this.deref(context, resolved!.content![mediaKey].schema) as SchemaObject | null)\n : null;\n if (schema?.properties) {\n errorShapes.push(schema.properties);\n }\n }\n\n if (errorShapes.length === 0) {\n return undefined;\n }\n return ErrorsWriter.MESSAGE_FIELDS.find((field) =>\n errorShapes.every((props) => (this.deref(context, props[field]) as SchemaObject | null)?.type === 'string'),\n );\n }\n\n // read-only $ref hop — resolvePointer, NOT lookupRef: this sniff must not bump refCount\n private deref(context: OasContext, node: unknown): unknown {\n return _.has(node, '$ref') ? context.resolvePointer(_.get(node, '$ref') as string) : node;\n }\n}\n"]}
1
+ {"version":3,"file":"errorsWriter.js","sourceRoot":"","sources":["../../../src/oas/io/errorsWriter.ts"],"names":[],"mappings":"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","sourcesContent":["import _ from 'lodash';\nimport { ResponseObject, SchemaObject } from 'oas/types';\nimport { OasContext } from '../oasContext.js';\nimport { OasGen } from '../oasGen.js';\nimport { Op } from '../nodes/internal.js';\nimport { Writer } from './writer.js';\n\n// R4 (opt-in): the `errors:` block of a connector — `message` from the documented error body,\n// `extensions` carrying `$status`.\nexport class ErrorsWriter {\n // corpus-measured priority for the error-body message field: `message` (755 error schemas),\n // `error` (362), `detail` (7)\n private static readonly MESSAGE_FIELDS = ['message', 'error', 'detail'];\n\n constructor(private gen: OasGen) {}\n\n // emit an `errors { message extensions { statusCode: $status } }` block for operations that\n // document HTTP error responses.\n public write(context: OasContext, writer: Writer, op: Op, indent: number): void {\n if (!context.generateOptions?.emitConnectorErrors || !this.hasDocumentedErrors(op)) {\n return;\n }\n\n // `message: \"$.message\"` — the path form yields the field's VALUE; a bare `message`\n // selection would build the object `{message: …}`, which errors.message rejects. R4\n const message = this.errorMessageField(context, op);\n\n // fully expanded: `errors {` and `}` at the @connect arg level, message/extensions/body/closing\n // one level deeper (8 spaces) so the body and the closing `\"\"\"` line up.\n const labelSpacing = ' '.repeat(indent + 6);\n const innerSpacing = ' '.repeat(indent + 8);\n writer.write(labelSpacing).write('errors: {\\n');\n if (message) {\n writer.write(innerSpacing).write(`message: \"$.${message}\"\\n`);\n }\n writer\n .write(innerSpacing)\n .write('extensions: \"\"\"\\n')\n .write(innerSpacing)\n .write('statusCode: $status\\n')\n .write(innerSpacing)\n .write('\"\"\"\\n')\n .write(labelSpacing)\n .write('}\\n');\n }\n\n // True when the operation documents an HTTP error response. Accepts both concrete numeric statuses\n // (4xx/5xx) and the OAS range keys `4XX`/`5XX` (case-insensitive). The `default` key is excluded —\n // it also covers 2xx/3xx, so it is not specifically an error indicator.\n private hasDocumentedErrors(op: Op): boolean {\n return op.operation.getResponseStatusCodes().some((code: string) => /^[45](\\d\\d|XX)$/i.test(code));\n }\n\n // the field must be a string on EVERY documented JSON error shape — a field missing on some\n // status would yield a null message there. Non-JSON / shapeless error responses don't veto.\n private errorMessageField(context: OasContext, op: Op): string | undefined {\n const responses = op.operation.schema.responses ?? {};\n const errorShapes: Array<Record<string, unknown>> = [];\n\n for (const [code, response] of Object.entries(responses)) {\n if (!/^[45](\\d\\d|XX)$/i.test(code)) {\n continue;\n }\n const resolved = this.deref(context, response) as ResponseObject | null;\n const mediaKey = Object.keys(resolved?.content ?? {}).find((k) => /^application\\/(?:.*\\+)?json/i.test(k));\n const schema = mediaKey\n ? (this.deref(context, resolved!.content![mediaKey].schema) as SchemaObject | null)\n : null;\n if (schema?.properties) {\n errorShapes.push(schema.properties);\n }\n }\n\n if (errorShapes.length === 0) {\n return undefined;\n }\n return ErrorsWriter.MESSAGE_FIELDS.find((field) =>\n errorShapes.every((props) => (this.deref(context, props[field]) as SchemaObject | null)?.type === 'string'),\n );\n }\n\n // read-only $ref hop — resolvePointer, NOT lookupRef: this sniff must not bump refCount\n private deref(context: OasContext, node: unknown): unknown {\n return _.has(node, '$ref') ? context.resolvePointer(_.get(node, '$ref') as string) : node;\n }\n}\n"]}
@@ -3,8 +3,6 @@ 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';
8
6
  export class OperationWriter {
9
7
  gen;
10
8
  security;
@@ -71,15 +69,7 @@ export class OperationWriter {
71
69
  // body is emitted last; its presence is cheap to compute up front. the body block streams
72
70
  // through the node tree (Body.select), so unlike query/headers it writes to `writer` directly
73
71
  // instead of returning a string. `null` drops the body; a string overrides it; see ROADMAP R9.
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;
72
+ const hasBody = typeof override?.body === 'string' || (override?.body === undefined && !!op.body);
83
73
  // query & header blocks are pure string-building — they return the block, or null when empty
84
74
  const queryBlock = this.queryParamsBlock(context, op, override, queryAuth);
85
75
  const headerBlock = this.headersBlock(op, override, headerAuth);
@@ -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';\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"]}
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 (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"]}
@@ -7,5 +7,4 @@ export declare class SchemaWriter {
7
7
  constructor(gen: OasGen, security: SecurityPlan);
8
8
  writeJSONScalar(writer: Writer): void;
9
9
  writeDirectives(writer: Writer): void;
10
- private getServerUrl;
11
10
  }
@@ -1,4 +1,5 @@
1
1
  import { DEFAULT_VERSIONS } from '../../versions.js';
2
+ import { ServerUrl } from '../utils/serverUrl.js';
2
3
  export class SchemaWriter {
3
4
  gen;
4
5
  security;
@@ -11,8 +12,8 @@ export class SchemaWriter {
11
12
  }
12
13
  writeDirectives(writer) {
13
14
  const api = this.gen.parser;
14
- // a spec's servers[0] can be stale or wrong (petstore) an explicit baseURL wins
15
- const host = this.gen.options.baseURL ?? this.getServerUrl(api.getDefinition().servers?.[0]);
15
+ // an explicit baseURL wins; otherwise pick a usable server. see docs/issues.md #41
16
+ const host = this.gen.options.baseURL ?? ServerUrl.resolve(api.getDefinition().servers);
16
17
  const federationVersion = this.gen.options.federationVersion || DEFAULT_VERSIONS.federationVersion;
17
18
  const connectorSpecVersion = this.gen.options.connectorSpecVersion || DEFAULT_VERSIONS.connectorSpecVersion;
18
19
  const authHeader = this.security.sourceHeader();
@@ -30,17 +31,5 @@ export class SchemaWriter {
30
31
  writer.write(' @source(name: "api", http: { baseURL: "').write(host).write('" })\n\n');
31
32
  }
32
33
  }
33
- getServerUrl(server) {
34
- if (!server) {
35
- return 'http://localhost:4010';
36
- }
37
- let url = server.url;
38
- if (server.variables) {
39
- for (const key in server.variables) {
40
- url = url.replace('{' + key + '}', server.variables[key].default);
41
- }
42
- }
43
- return url;
44
- }
45
34
  }
46
35
  //# sourceMappingURL=schemaWriter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schemaWriter.js","sourceRoot":"","sources":["../../../src/oas/io/schemaWriter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAKrD,MAAM,OAAO,YAAY;IAEb;IACA;IAFV,YACU,GAAW,EACX,QAAsB;QADtB,QAAG,GAAH,GAAG,CAAQ;QACX,aAAQ,GAAR,QAAQ,CAAc;IAC7B,CAAC;IAEG,eAAe,CAAC,MAAc;QACnC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACpC,CAAC;IAEM,eAAe,CAAC,MAAc;QACnC,MAAM,GAAG,GAAQ,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;QACjC,kFAAkF;QAClF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7F,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,IAAI,gBAAgB,CAAC,iBAAiB,CAAC;QACnG,MAAM,oBAAoB,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,IAAI,gBAAgB,CAAC,oBAAoB,CAAC;QAC5G,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QAChD,MAAM;aACH,KAAK,CAAC,iBAAiB,CAAC;aACxB,KAAK,CAAC,qDAAqD,iBAAiB,wBAAwB,CAAC;aACrG,KAAK,CAAC,YAAY,CAAC;aACnB,KAAK,CAAC,8CAA8C,oBAAoB,KAAK,CAAC;aAC9E,KAAK,CAAC,uCAAuC,CAAC;aAC9C,KAAK,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,4CAA4C,IAAI,gBAAgB,UAAU,UAAU,CAAC,CAAC;QACrG,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,MAAgC;QACnD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,uBAAuB,CAAC;QACjC,CAAC;QACD,IAAI,GAAG,GAAW,MAAM,CAAC,GAAG,CAAC;QAC7B,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBACnC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF","sourcesContent":["import Oas from 'oas';\nimport { ServerObject } from 'oas/types';\nimport { DEFAULT_VERSIONS } from '../../versions.js';\nimport { OasGen } from '../oasGen.js';\nimport { Writer } from './writer.js';\nimport { SecurityPlan } from './security.js';\n\nexport class SchemaWriter {\n constructor(\n private gen: OasGen,\n private security: SecurityPlan,\n ) {}\n\n public writeJSONScalar(writer: Writer): void {\n writer.write('\\nscalar JSON\\n\\n');\n }\n\n public writeDirectives(writer: Writer): void {\n const api: Oas = this.gen.parser;\n // a spec's servers[0] can be stale or wrong (petstore) an explicit baseURL wins\n const host = this.gen.options.baseURL ?? this.getServerUrl(api.getDefinition().servers?.[0]);\n const federationVersion = this.gen.options.federationVersion || DEFAULT_VERSIONS.federationVersion;\n const connectorSpecVersion = this.gen.options.connectorSpecVersion || DEFAULT_VERSIONS.connectorSpecVersion;\n const authHeader = this.security.sourceHeader();\n writer\n .write('extend schema\\n')\n .write(` @link(url: \"https://specs.apollo.dev/federation/${federationVersion}\", import: [\"@key\"])\\n`)\n .write(' @link(\\n')\n .write(` url: \"https://specs.apollo.dev/connect/${connectorSpecVersion}\"\\n`)\n .write(' import: [\"@connect\", \"@source\"]\\n')\n .write(' )\\n');\n\n if (authHeader) {\n writer.write(` @source(name: \"api\", http: { baseURL: \"${host}\", headers: [${authHeader}] })\\n\\n`);\n } else {\n writer.write(' @source(name: \"api\", http: { baseURL: \"').write(host).write('\" })\\n\\n');\n }\n }\n\n private getServerUrl(server: ServerObject | undefined): string {\n if (!server) {\n return 'http://localhost:4010';\n }\n let url: string = server.url;\n if (server.variables) {\n for (const key in server.variables) {\n url = url.replace('{' + key + '}', server.variables[key].default);\n }\n }\n return url;\n }\n}\n"]}
1
+ {"version":3,"file":"schemaWriter.js","sourceRoot":"","sources":["../../../src/oas/io/schemaWriter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAIrD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,OAAO,YAAY;IAEb;IACA;IAFV,YACU,GAAW,EACX,QAAsB;QADtB,QAAG,GAAH,GAAG,CAAQ;QACX,aAAQ,GAAR,QAAQ,CAAc;IAC7B,CAAC;IAEG,eAAe,CAAC,MAAc;QACnC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACpC,CAAC;IAEM,eAAe,CAAC,MAAc;QACnC,MAAM,GAAG,GAAQ,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;QACjC,mFAAmF;QACnF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,OAAO,CAAC,CAAC;QACxF,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,IAAI,gBAAgB,CAAC,iBAAiB,CAAC;QACnG,MAAM,oBAAoB,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,IAAI,gBAAgB,CAAC,oBAAoB,CAAC;QAC5G,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QAChD,MAAM;aACH,KAAK,CAAC,iBAAiB,CAAC;aACxB,KAAK,CAAC,qDAAqD,iBAAiB,wBAAwB,CAAC;aACrG,KAAK,CAAC,YAAY,CAAC;aACnB,KAAK,CAAC,8CAA8C,oBAAoB,KAAK,CAAC;aAC9E,KAAK,CAAC,uCAAuC,CAAC;aAC9C,KAAK,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,4CAA4C,IAAI,gBAAgB,UAAU,UAAU,CAAC,CAAC;QACrG,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;CACF","sourcesContent":["import Oas from 'oas';\nimport { DEFAULT_VERSIONS } from '../../versions.js';\nimport { OasGen } from '../oasGen.js';\nimport { Writer } from './writer.js';\nimport { SecurityPlan } from './security.js';\nimport { ServerUrl } from '../utils/serverUrl.js';\n\nexport class SchemaWriter {\n constructor(\n private gen: OasGen,\n private security: SecurityPlan,\n ) {}\n\n public writeJSONScalar(writer: Writer): void {\n writer.write('\\nscalar JSON\\n\\n');\n }\n\n public writeDirectives(writer: Writer): void {\n const api: Oas = this.gen.parser;\n // an explicit baseURL wins; otherwise pick a usable server. see docs/issues.md #41\n const host = this.gen.options.baseURL ?? ServerUrl.resolve(api.getDefinition().servers);\n const federationVersion = this.gen.options.federationVersion || DEFAULT_VERSIONS.federationVersion;\n const connectorSpecVersion = this.gen.options.connectorSpecVersion || DEFAULT_VERSIONS.connectorSpecVersion;\n const authHeader = this.security.sourceHeader();\n writer\n .write('extend schema\\n')\n .write(` @link(url: \"https://specs.apollo.dev/federation/${federationVersion}\", import: [\"@key\"])\\n`)\n .write(' @link(\\n')\n .write(` url: \"https://specs.apollo.dev/connect/${connectorSpecVersion}\"\\n`)\n .write(' import: [\"@connect\", \"@source\"]\\n')\n .write(' )\\n');\n\n if (authHeader) {\n writer.write(` @source(name: \"api\", http: { baseURL: \"${host}\", headers: [${authHeader}] })\\n\\n`);\n } else {\n writer.write(' @source(name: \"api\", http: { baseURL: \"').write(host).write('\" })\\n\\n');\n }\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { T } from '../nodes/internal.js';
2
2
  import { inferEntityResolvers } from '../nodes/entity.js';
3
3
  import { applyBatchResolvers } from '../nodes/batch.js';
4
- import { promoteInterfaces } from '../nodes/interfacePromotion.js';
4
+ import { promoteAllOfBase } from '../nodes/allOfBase.js';
5
5
  import { OperationWriter } from './operationWriter.js';
6
6
  import { SchemaWriter } from './schemaWriter.js';
7
7
  import { SecurityPlan } from './security.js';
@@ -51,8 +51,8 @@ export class Writer {
51
51
  // R6: add batch resolvers (needs the R1 @key above) when a --batch file was given.
52
52
  applyBatchResolvers(context, this.gen, types);
53
53
  // R2: promote discriminated oneOf-with-shared-allOf-base to a GraphQL interface (id-neutral;
54
- // no-op unless consolidateUnions is off and a qualifying union exists). Same `types` map.
55
- promoteInterfaces(context, this.gen, types, selection);
54
+ // no-op unless a qualifying discriminated output union exists). Same `types` map.
55
+ promoteAllOfBase(context, this.gen, types, selection);
56
56
  this.schemaWriter.writeDirectives(writer);
57
57
  this.schemaWriter.writeJSONScalar(writer);
58
58
  types.forEach((type) => {
@@ -1 +1 @@
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"]}
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 { promoteAllOfBase } from '../nodes/allOfBase.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 a qualifying discriminated output union exists). Same `types` map.\n promoteAllOfBase(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"]}
@@ -22,12 +22,10 @@ import { OasGen } from '../oasGen.js';
22
22
  * Promotion is id-neutral: it sets flags (`Obj.emitAsInterface`, `Composed.implementsInterface`,
23
23
  * `Union.interfaceBaseRef`) and never mutates `kind` (which is embedded in node ids).
24
24
  *
25
- * Gating mirrors the committed union slice: `consolidateUnions === false` + a discriminator. (Wiring
26
- * this to the spec version — connect >= v0.4 — is a separate roadmap follow-up.) A candidate union is
27
- * promoted only when ALL hold:
25
+ * A candidate union (a discriminated output union) is promoted only when ALL hold:
28
26
  * 1. every member is an allOf {@link Composed};
29
27
  * 2. exactly one `$ref` is common to every member's `allOf` (empty or >1 -> stay a union);
30
28
  * 3. the base is not used as a concrete type anywhere else (else promoting it would turn an
31
29
  * unrelated field into an interface with no `__typename`) -> stay a union, logged.
32
30
  */
33
- export declare function promoteInterfaces(context: OasContext, gen: OasGen, types: Map<string, IType>, _selection: string[]): void;
31
+ export declare function promoteAllOfBase(context: OasContext, gen: OasGen, types: Map<string, IType>, _selection: string[]): void;
@@ -21,21 +21,20 @@ import { Naming } from '../utils/naming.js';
21
21
  * Promotion is id-neutral: it sets flags (`Obj.emitAsInterface`, `Composed.implementsInterface`,
22
22
  * `Union.interfaceBaseRef`) and never mutates `kind` (which is embedded in node ids).
23
23
  *
24
- * Gating mirrors the committed union slice: `consolidateUnions === false` + a discriminator. (Wiring
25
- * this to the spec version — connect >= v0.4 — is a separate roadmap follow-up.) A candidate union is
26
- * promoted only when ALL hold:
24
+ * A candidate union (a discriminated output union) is promoted only when ALL hold:
27
25
  * 1. every member is an allOf {@link Composed};
28
26
  * 2. exactly one `$ref` is common to every member's `allOf` (empty or >1 -> stay a union);
29
27
  * 3. the base is not used as a concrete type anywhere else (else promoting it would turn an
30
28
  * unrelated field into an interface with no `__typename`) -> stay a union, logged.
31
29
  */
32
- export function promoteInterfaces(context, gen, types, _selection) {
33
- if (context.generateOptions.consolidateUnions) {
34
- return; // interfaces only on the real-abstract-types path
35
- }
30
+ export function promoteAllOfBase(context, gen, types, _selection) {
36
31
  for (const union of candidateUnions(gen)) {
37
32
  if (!union.discriminator)
38
33
  continue;
34
+ // isFlat(): input position, no discriminator, or nested under a field rather than being the
35
+ // op's own response (#38) — already downgraded to one merged type, not an interface candidate.
36
+ if (union.isFlat())
37
+ continue;
39
38
  const members = union.children;
40
39
  if (members.length === 0)
41
40
  continue;
@@ -147,4 +146,4 @@ function baseUsedExternally(context, gen, types, baseRef, members) {
147
146
  }
148
147
  return false;
149
148
  }
150
- //# sourceMappingURL=interfacePromotion.js.map
149
+ //# sourceMappingURL=allOfBase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allOfBase.js","sourceRoot":"","sources":["../../../src/oas/nodes/allOfBase.ts"],"names":[],"mappings":"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","sourcesContent":["import { Composed, IType, Obj, Res, T, Union } from './internal.js';\nimport { OasContext } from '../oasContext.js';\nimport { OasGen } from '../oasGen.js';\nimport { Naming } from '../utils/naming.js';\n\n/**\n * R2 (Scenario B): promote a discriminated `oneOf` whose members all share one `allOf` base into a\n * GraphQL `interface`. Instead of `union X = A | B`, emit:\n *\n * interface Base { <base fields> }\n * type A implements Base { <base fields> <A fields> }\n * type B implements Base { <base fields> <B fields> }\n * field: Base @connect(... selection: \"\"\" ...<discr>->match([...]) \"\"\")\n *\n * The `->match` selection is identical to the union form (rover-verified to compose for interfaces),\n * so this pass only does **type modeling**; selection emission is untouched.\n *\n * Runs as a POST-COLLECT pass over the collected `types` map (the map the writer emits), mirroring\n * {@link inferEntityResolvers}. It must run post-collect because the canonical, about-to-be-emitted\n * node instances only exist there — `context.types` is a name-existence set (stores `undefined`), and\n * the shared base is deleted from `types` during consolidation, surviving only as a child of each\n * member (so it is re-sourced from a member and re-inserted here).\n *\n * Promotion is id-neutral: it sets flags (`Obj.emitAsInterface`, `Composed.implementsInterface`,\n * `Union.interfaceBaseRef`) and never mutates `kind` (which is embedded in node ids).\n *\n * A candidate union (a discriminated output union) is promoted only when ALL hold:\n * 1. every member is an allOf {@link Composed};\n * 2. exactly one `$ref` is common to every member's `allOf` (empty or >1 -> stay a union);\n * 3. the base is not used as a concrete type anywhere else (else promoting it would turn an\n * unrelated field into an interface with no `__typename`) -> stay a union, logged.\n */\nexport function promoteAllOfBase(\n context: OasContext,\n gen: OasGen,\n types: Map<string, IType>,\n _selection: string[],\n): void {\n for (const union of candidateUnions(gen)) {\n if (!union.discriminator) continue;\n // isFlat(): input position, no discriminator, or nested under a field rather than being the\n // op's own response (#38) — already downgraded to one merged type, not an interface candidate.\n if (union.isFlat()) continue;\n\n const members = union.children;\n if (members.length === 0) continue;\n // Rule 1: every member is an allOf Composed.\n if (!members.every((m) => m instanceof Composed && Array.isArray((m as Composed).schema.allOf))) {\n continue;\n }\n const composedMembers = members as Composed[];\n\n // Rule 2: exactly one $ref common to every member's allOf.\n const refSets = composedMembers.map((m) => new Set(allOfRefs(m)));\n const common = [...refSets[0]].filter((ref) => refSets.every((s) => s.has(ref)));\n if (common.length !== 1) {\n continue;\n }\n const baseRef = common[0];\n\n // Rule 3: base must be private to this oneOf (not used concretely elsewhere).\n if (baseUsedExternally(context, gen, types, baseRef, composedMembers)) {\n continue;\n }\n\n // Source the base node from a surviving member (it was deleted from `types` during\n // consolidation but is never detached from its member). All members' copies are\n // field-identical (same $ref schema), so the first is fine.\n const base = composedMembers[0].children.find((c) => c.name === baseRef);\n if (!(base instanceof Obj)) {\n console.warn(`[interface] could not source base node for ${baseRef}; leaving ${union.name} a union.`);\n continue;\n }\n\n // Promote (id-neutral): flag the base as an interface and insert it into the emitted map;\n // tag each member to implement it; redirect/suppress the union.\n base.emitAsInterface = true;\n types.set(base.id, base);\n\n const interfaceName = Naming.genTypeName(baseRef);\n for (const member of composedMembers) {\n const emitted = types.get(member.id);\n if (emitted instanceof Composed) {\n emitted.implementsInterface = interfaceName;\n }\n }\n\n union.interfaceBaseRef = baseRef;\n }\n}\n\n/** Union instances reachable as a GET/op response (the ones whose return type the writer emits). */\nfunction candidateUnions(gen: OasGen): Union[] {\n const out: Union[] = [];\n for (const op of gen.paths.values()) {\n if (!T.isOp(op)) continue;\n let node: IType | undefined = op.resultType;\n if (node instanceof Res) node = node.response;\n if (node instanceof Union) out.push(node);\n }\n return out;\n}\n\n/** The `$ref` strings of a Composed's `allOf` entries (inline, non-$ref entries are dropped). */\nfunction allOfRefs(comp: Composed): string[] {\n const allOf = (comp.schema.allOf ?? []) as Array<{ $ref?: string }>;\n return allOf.map((s) => s.$ref).filter((r): r is string => Boolean(r));\n}\n\n/**\n * True when `baseRef` is referenced as a concrete type outside the promoted union's members.\n * Structural scan is authoritative (catches a field/op that returns the base directly, or another\n * type extending it); the raw refCount is a cross-check that, when it disagrees, is logged. (refCount\n * is the raw `lookupRef` tally here — `decRefCount` only runs on the consolidate path — but it can\n * over-count via repeated ref resolution, so it does not by itself block promotion.)\n */\nfunction baseUsedExternally(\n context: OasContext,\n gen: OasGen,\n types: Map<string, IType>,\n baseRef: string,\n members: Composed[],\n): boolean {\n const memberIds = new Set(members.map((m) => m.id));\n let structural = false;\n let reason = '';\n\n // (a) any op whose result type unwraps directly to the base.\n for (const op of gen.paths.values()) {\n if (!T.isOp(op)) continue;\n let node: IType | undefined = op.resultType;\n if (node instanceof Res) node = node.response;\n if (node && (node instanceof Obj || node instanceof Composed) && node.name === baseRef) {\n structural = true;\n reason = `returned directly by ${op.id}`;\n break;\n }\n }\n\n // (b) any non-member Composed that also extends the base.\n if (!structural) {\n for (const type of types.values()) {\n if (type instanceof Composed && !memberIds.has(type.id) && allOfRefs(type).includes(baseRef)) {\n structural = true;\n reason = `also extended by ${type.id}`;\n break;\n }\n }\n }\n\n // refCount cross-check (advisory).\n const internalRefs = members.reduce((n, m) => n + allOfRefs(m).filter((r) => r === baseRef).length, 0);\n const rc = context.refCount.get(baseRef) ?? 0;\n const refCountExternal = rc > internalRefs;\n\n if (structural) {\n console.warn(\n `[interface] not promoting ${baseRef} to an interface — used as a concrete type (${reason}); ` +\n `field stays a union. (refCount=${rc}, internal=${internalRefs})`,\n );\n return true;\n }\n if (refCountExternal) {\n // Structural scan saw nothing but the tally is higher than the member references — surface it,\n // but trust the structural scan (refCount can over-count). Promotion proceeds.\n console.warn(\n `[interface] refCount for ${baseRef} (${rc}) exceeds member references (${internalRefs}) but no ` +\n `concrete external use was found structurally; promoting anyway.`,\n );\n }\n return false;\n}\n"]}
@@ -1,5 +1,4 @@
1
1
  import { Arr, Obj, PropArray, Res, T } from './internal.js';
2
- import { DEFAULT_VERSIONS, meetsMinimum } from '../../versions.js';
3
2
  import { Params } from '../utils/params.js';
4
3
  import { warn } from '../log/trace.js';
5
4
  // default batch size cap — OAS gives no signal for it, so emit one and let the user edit it.
@@ -18,13 +17,8 @@ export function applyBatchResolvers(context, gen, types) {
18
17
  if (!batch) {
19
18
  return;
20
19
  }
21
- const version = gen.options.connectorSpecVersion || DEFAULT_VERSIONS.connectorSpecVersion;
22
20
  for (const [opId, entry] of Object.entries(batch)) {
23
21
  const skip = (why) => warn(context, '[batch]', `${opId}: ${why} — skipped`);
24
- if (!meetsMinimum(version, 'v0.2')) {
25
- skip(`batch needs connect v0.2+, target is ${version}`);
26
- continue;
27
- }
28
22
  const op = gen.paths.get(opId);
29
23
  if (!op || !T.isOp(op)) {
30
24
  skip('no matching operation');
@@ -77,7 +71,7 @@ export function applyBatchResolvers(context, gen, types) {
77
71
  }
78
72
  }
79
73
  // the response array's item object: `[Product]` -> Product; `{ results: [Product] }` -> Product + "results".
80
- // reads the same result-type node graph as inferEntityResolvers / promoteInterfaces.
74
+ // reads the same result-type node graph as inferEntityResolvers / promoteAllOfBase.
81
75
  function responseItem(op) {
82
76
  let node = op.resultType;
83
77
  if (node instanceof Res) {