apollo-conn-gen 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/oas.js +19 -1
- package/dist/cli/oas.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js.map +1 -1
- package/dist/json/io/writer.js +3 -1
- package/dist/json/io/writer.js.map +1 -1
- package/dist/json/walker/jsonContext.d.ts +1 -0
- package/dist/json/walker/jsonContext.js +27 -0
- package/dist/json/walker/jsonContext.js.map +1 -1
- package/dist/json/walker/jsonGen.js +18 -10
- package/dist/json/walker/jsonGen.js.map +1 -1
- package/dist/oas/generator/typesCollector.js +13 -1
- package/dist/oas/generator/typesCollector.js.map +1 -1
- package/dist/oas/io/errorsWriter.d.ts +13 -0
- package/dist/oas/io/errorsWriter.js +72 -0
- package/dist/oas/io/errorsWriter.js.map +1 -0
- package/dist/oas/io/operationWriter.d.ts +8 -2
- package/dist/oas/io/operationWriter.js +109 -85
- package/dist/oas/io/operationWriter.js.map +1 -1
- package/dist/oas/io/schemaWriter.js +2 -1
- package/dist/oas/io/schemaWriter.js.map +1 -1
- package/dist/oas/nodes/comp.js +1 -8
- package/dist/oas/nodes/comp.js.map +1 -1
- package/dist/oas/nodes/entity.js +2 -6
- package/dist/oas/nodes/entity.js.map +1 -1
- package/dist/oas/nodes/factory.d.ts +5 -4
- package/dist/oas/nodes/factory.js +15 -5
- package/dist/oas/nodes/factory.js.map +1 -1
- package/dist/oas/nodes/get.d.ts +1 -1
- package/dist/oas/nodes/get.js +24 -9
- package/dist/oas/nodes/get.js.map +1 -1
- package/dist/oas/nodes/interfacePromotion.js +8 -6
- package/dist/oas/nodes/interfacePromotion.js.map +1 -1
- package/dist/oas/nodes/op.d.ts +2 -1
- package/dist/oas/nodes/op.js.map +1 -1
- package/dist/oas/nodes/post.d.ts +1 -1
- package/dist/oas/nodes/post.js +9 -8
- package/dist/oas/nodes/post.js.map +1 -1
- package/dist/oas/nodes/propComp.js +1 -1
- package/dist/oas/nodes/propComp.js.map +1 -1
- package/dist/oas/nodes/propEn.js +1 -1
- package/dist/oas/nodes/propEn.js.map +1 -1
- package/dist/oas/nodes/propMap.js +1 -1
- package/dist/oas/nodes/propMap.js.map +1 -1
- package/dist/oas/nodes/propObj.js +1 -1
- package/dist/oas/nodes/propObj.js.map +1 -1
- package/dist/oas/nodes/propScalar.js +3 -2
- package/dist/oas/nodes/propScalar.js.map +1 -1
- package/dist/oas/nodes/scalar.d.ts +1 -1
- package/dist/oas/nodes/scalar.js +21 -7
- package/dist/oas/nodes/scalar.js.map +1 -1
- package/dist/oas/nodes/type.d.ts +1 -0
- package/dist/oas/nodes/type.js +11 -0
- package/dist/oas/nodes/type.js.map +1 -1
- package/dist/oas/nodes/typeUtils.d.ts +2 -1
- package/dist/oas/nodes/typeUtils.js +5 -1
- package/dist/oas/nodes/typeUtils.js.map +1 -1
- package/dist/oas/nodes/union.d.ts +2 -0
- package/dist/oas/nodes/union.js +23 -5
- package/dist/oas/nodes/union.js.map +1 -1
- package/dist/oas/oasContext.d.ts +9 -1
- package/dist/oas/oasContext.js +10 -3
- package/dist/oas/oasContext.js.map +1 -1
- package/dist/oas/oasGen.d.ts +4 -2
- package/dist/oas/oasGen.js +13 -2
- package/dist/oas/oasGen.js.map +1 -1
- package/dist/oas/schemas/index.js +3 -1
- package/dist/oas/schemas/index.js.map +1 -1
- package/dist/oas/utils/naming.js +5 -4
- package/dist/oas/utils/naming.js.map +1 -1
- package/dist/tests/runners.d.ts +6 -0
- package/dist/tests/runners.js +12 -4
- package/dist/tests/runners.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/versions.d.ts +12 -4
- package/dist/versions.js +23 -6
- package/dist/versions.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +21 -0
package/dist/cli/oas.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
1
2
|
import { Command } from 'commander';
|
|
2
3
|
import { DEFAULT_VERSIONS } from '../versions.js';
|
|
3
4
|
import { generateFromSelection, promptForSelection } from './oas-helpers/index.js';
|
|
@@ -25,13 +26,28 @@ function loadRules(opts) {
|
|
|
25
26
|
}
|
|
26
27
|
return mapper;
|
|
27
28
|
}
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
function loadOverrides(opts) {
|
|
31
|
+
if (!opts.overrides) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(fs.readFileSync(opts.overrides, 'utf-8'));
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(`Error loading overrides: ${error}`);
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
28
42
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- for options
|
|
29
43
|
async function main(sourceFile, opts) {
|
|
30
44
|
console.log = () => { };
|
|
31
45
|
const mapper = loadRules(opts);
|
|
46
|
+
const overrides = loadOverrides(opts);
|
|
32
47
|
const gen = await OasGen.fromFile(sourceFile, {
|
|
33
48
|
...opts,
|
|
34
|
-
|
|
49
|
+
baseURL: opts.baseUrl,
|
|
50
|
+
overrides,
|
|
35
51
|
showParentInSelections: false,
|
|
36
52
|
federationVersion: opts.federationVersion,
|
|
37
53
|
connectorSpecVersion: opts.connectorSpecVersion,
|
|
@@ -86,6 +102,8 @@ program
|
|
|
86
102
|
.option('-t --transform-rules <file>', 'Load transform rules from a JSON file to apply multiple name transformations')
|
|
87
103
|
.option('--federation-version <version>', 'Federation version to use', DEFAULT_VERSIONS.federationVersion)
|
|
88
104
|
.option('--connector-spec-version <version>', 'Connector spec version to use', DEFAULT_VERSIONS.connectorSpecVersion)
|
|
105
|
+
.option('--base-url <url>', 'Override the @source base URL (default: servers[0] from the spec)')
|
|
106
|
+
.option('--overrides <file>', 'Load per-operation path/queryParams overrides from a JSON file')
|
|
89
107
|
.option('--skip-optional-args', 'Skip optional arguments in queries', false)
|
|
90
108
|
.option('--infer-entity-resolvers', 'Infer entity resolvers and emit @key / entity: true', false)
|
|
91
109
|
.parse(process.argv);
|
package/dist/cli/oas.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oas.js","sourceRoot":"","sources":["../../src/cli/oas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;
|
|
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 } from 'commander';\nimport { DEFAULT_VERSIONS } from '../versions.js';\nimport { generateFromSelection, promptForSelection } from './oas-helpers/index.js';\nimport { OasGen } from '../oas/oasGen.js';\nimport { 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\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction loadRules(opts: any): 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 } else if (opts.postName) {\n // Backward compatibility with legacy --post-name\n mapper = OpNameMapper.fromPattern(opts.postName);\n }\n\n return mapper;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction loadOverrides(opts: any): 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\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- for options\nasync function main(sourceFile: string, opts: any): Promise<void> {\n console.log = () => {};\n\n const mapper = loadRules(opts);\n const overrides = loadOverrides(opts);\n\n const gen = await OasGen.fromFile(sourceFile, {\n ...opts,\n baseURL: opts.baseUrl,\n overrides,\n showParentInSelections: false,\n federationVersion: opts.federationVersion,\n connectorSpecVersion: opts.connectorSpecVersion,\n postName: opts.postName,\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('--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"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC","sourcesContent":["export { JsonGen } from './json/index.js';\nexport { OasGen } from './oas/oasGen.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC","sourcesContent":["export { JsonGen } from './json/index.js';\nexport { OasGen } from './oas/oasGen.js';\nexport type { GenerateOptions, RequestOverride } from './oas/oasContext.js';\n"]}
|
package/dist/json/io/writer.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../src/json/io/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAMhE,MAAM,OAAO,YAAY;IACvB,OAAO,GAAa,EAAE,CAAC;IAEvB,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;IACpB,CAAC;CACF;AAWD,MAAM,OAAO,eAAe;IACnB,MAAM,CAAC,KAAK,CAAC,MAAe,EAAE,MAAe,EAAE,OAAgC;QACpF,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IAEO,MAAM,CAAC,cAAc,CAAC,MAAe,EAAE,OAAgC;QAC7E,MAAM,iBAAiB,GAAG,OAAO,EAAE,iBAAiB,IAAI,gBAAgB,CAAC,iBAAiB,CAAC;QAC3F,MAAM,oBAAoB,GAAG,OAAO,EAAE,oBAAoB,IAAI,gBAAgB,CAAC,oBAAoB,CAAC;QACpG,MAAM,CAAC,KAAK,CAAC;oDACmC,iBAAiB;;6CAExB,oBAAoB;;;2CAGtB,OAAO,EAAE,OAAO,IAAI,uBAAuB
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../src/json/io/writer.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEFAULT_VERSIONS } from '../../versions.js';\nimport { JsonGen } from '../walker/jsonGen.js';\nimport { sanitiseField, upperFirst } from '../walker/naming.js';\n\nexport interface IWriter {\n write(text: string): void;\n}\n\nexport class StringWriter implements IWriter {\n builder: string[] = [];\n\n write(text: string): void {\n this.builder.push(text);\n }\n\n flush(): string {\n return this.builder.join('');\n }\n\n clear(): void {\n this.builder = [];\n }\n}\n\nexport interface ConnectorWriterOptions {\n federationVersion?: string;\n connectorSpecVersion?: string;\n rootType?: string;\n baseURL?: string;\n relativePath?: string;\n queryField?: string;\n}\n\nexport class ConnectorWriter {\n public static write(walker: JsonGen, writer: IWriter, options?: ConnectorWriterOptions): void {\n this.writeConnector(writer, options);\n writer.write(walker.writeTypes());\n this.writeQuery(walker, writer, options);\n }\n\n private static writeConnector(writer: IWriter, options?: ConnectorWriterOptions): void {\n const federationVersion = options?.federationVersion || DEFAULT_VERSIONS.federationVersion;\n const connectorSpecVersion = options?.connectorSpecVersion || DEFAULT_VERSIONS.connectorSpecVersion;\n writer.write(`extend schema\n @link(url: \"https://specs.apollo.dev/federation/${federationVersion}\", import: [\"@key\"])\n @link(\n url: \"https://specs.apollo.dev/connect/${connectorSpecVersion}\"\n import: [\"@connect\", \"@source\"]\n )\n @source(name: \"api\", http: { baseURL: \"${options?.baseURL || 'http://localhost:4010'}\" })\n\nscalar JSON\n\n`);\n }\n\n private static parseRootType(raw?: string): { typeName: string; fieldName: string; isList: boolean } {\n if (!raw) return { typeName: 'Root', fieldName: 'root', isList: false };\n const listMatch = raw.match(/^\\[(.+)]$/);\n const name = listMatch ? listMatch[1] : raw;\n return {\n typeName: upperFirst(sanitiseField(name)),\n fieldName: sanitiseField(name),\n isList: !!listMatch,\n };\n }\n\n private static writeQuery(walker: JsonGen, writer: IWriter, options?: ConnectorWriterOptions): void {\n const { typeName, fieldName, isList } = this.parseRootType(options?.rootType);\n const queryField = options?.queryField ?? fieldName;\n const relativePath = options?.relativePath ?? '/test';\n const returnType = isList ? `[${typeName}]` : typeName;\n\n writer.write(\n '\\n' +\n `type Query {\n ${queryField}: ${returnType}\n @connect(\n source: \"api\"\n http: { GET: \"${relativePath}\" }\n selection: \"\"\"` +\n '\\n',\n );\n\n writer.write(walker.writeSelection());\n\n const ctx = walker.getContext();\n\n writer.write(ctx.getIndent() + '\"\"\"\\n');\n writer.write(ctx.getIndentWith(2) + ')}');\n }\n}\n"]}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { JsonArray } from '../walker/types/jsonArray.js';
|
|
1
2
|
import { JsonObj } from '../walker/types/jsonObj.js';
|
|
3
|
+
import { JsonScalar } from '../walker/types/jsonScalar.js';
|
|
2
4
|
export class JsonContext {
|
|
3
5
|
stack;
|
|
4
6
|
types;
|
|
@@ -36,16 +38,41 @@ export class JsonContext {
|
|
|
36
38
|
this.types.set(type.id(), type);
|
|
37
39
|
}
|
|
38
40
|
}
|
|
41
|
+
// converge both instances on the field union: the stored one feeds getTypes(), the incoming
|
|
42
|
+
// one is what the parent's field map (the written tree) points at. #35
|
|
39
43
|
merge(type) {
|
|
40
44
|
const source = this.types.get(type.id());
|
|
41
45
|
// Only merge if both are Obj instances
|
|
42
46
|
if (source instanceof JsonObj && type instanceof JsonObj) {
|
|
43
47
|
type.getFields().forEach((value, key) => {
|
|
48
|
+
// an unknown-shape twin (`[]`/`{}` walked to the JSON scalar) must not clobber a typed field
|
|
49
|
+
const existing = source.getFields().get(key);
|
|
50
|
+
if (existing && this.isUnknownShape(value) && !this.isUnknownShape(existing)) {
|
|
51
|
+
type.getFields().set(key, existing);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
44
54
|
source.getFields().set(key, value);
|
|
45
55
|
});
|
|
56
|
+
// and back the other way: fields only earlier documents knew about
|
|
57
|
+
source.getFields().forEach((value, key) => {
|
|
58
|
+
if (!type.getFields().has(key)) {
|
|
59
|
+
type.getFields().set(key, value);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
46
62
|
this.types.set(source.id(), source);
|
|
47
63
|
}
|
|
48
64
|
}
|
|
65
|
+
// `[]` / `{}` values walk to the JSON scalar (unknown shape) — see #19/#21/#35
|
|
66
|
+
isUnknownShape(type) {
|
|
67
|
+
if (type instanceof JsonScalar) {
|
|
68
|
+
return type.getType() === 'JSON';
|
|
69
|
+
}
|
|
70
|
+
if (type instanceof JsonArray) {
|
|
71
|
+
const items = type.getArrayType();
|
|
72
|
+
return items === null || this.isUnknownShape(items);
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
49
76
|
getTypes() {
|
|
50
77
|
return Array.from(this.types.values());
|
|
51
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonContext.js","sourceRoot":"","sources":["../../../src/json/walker/jsonContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"jsonContext.js","sourceRoot":"","sources":["../../../src/json/walker/jsonContext.ts"],"names":[],"mappings":"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","sourcesContent":["import { JsonArray } from '../walker/types/jsonArray.js';\nimport { JsonObj } from '../walker/types/jsonObj.js';\nimport { JsonScalar } from '../walker/types/jsonScalar.js';\nimport { JsonType } from '../walker/types/jsonType.js';\n\nexport class JsonContext {\n private stack: JsonType[];\n private types: Map<string, JsonType>;\n private indent: number = 0;\n public verbose: boolean = false;\n\n constructor() {\n this.stack = [];\n this.types = new Map<string, JsonType>();\n }\n\n public getStack(): JsonType[] {\n return this.stack;\n }\n\n public getIndent(): string {\n return ' '.repeat(this.stack.length + this.indent);\n }\n\n public getIndentWith(subtract: number): string {\n return ' '.repeat(this.stack.length - subtract + this.indent);\n }\n\n public setIndent(indent: number): void {\n this.indent = indent;\n }\n\n public enter(element: JsonType): void {\n // trace(this, \"[context]\", \"-> enter: (\" + this.stack.length + \") \" + element.getName());\n this.stack.push(element);\n }\n\n public leave(_element: JsonType): void {\n // trace(this, \"[context]\", \"<- leave: (\" + this.stack.length + \") \" + element.getName());\n this.stack.pop();\n }\n\n public store(type: JsonType): void {\n if (this.types.has(type.id())) {\n this.merge(type);\n } else {\n this.types.set(type.id(), type);\n }\n }\n\n // converge both instances on the field union: the stored one feeds getTypes(), the incoming\n // one is what the parent's field map (the written tree) points at. #35\n private merge(type: JsonType): void {\n const source = this.types.get(type.id());\n // Only merge if both are Obj instances\n if (source instanceof JsonObj && type instanceof JsonObj) {\n type.getFields().forEach((value: JsonType, key: string) => {\n // an unknown-shape twin (`[]`/`{}` walked to the JSON scalar) must not clobber a typed field\n const existing = source.getFields().get(key);\n if (existing && this.isUnknownShape(value) && !this.isUnknownShape(existing)) {\n type.getFields().set(key, existing);\n return;\n }\n source.getFields().set(key, value);\n });\n // and back the other way: fields only earlier documents knew about\n source.getFields().forEach((value: JsonType, key: string) => {\n if (!type.getFields().has(key)) {\n type.getFields().set(key, value);\n }\n });\n this.types.set(source.id(), source);\n }\n }\n\n // `[]` / `{}` values walk to the JSON scalar (unknown shape) — see #19/#21/#35\n private isUnknownShape(type: JsonType): boolean {\n if (type instanceof JsonScalar) {\n return type.getType() === 'JSON';\n }\n if (type instanceof JsonArray) {\n const items = type.getArrayType();\n return items === null || this.isUnknownShape(items);\n }\n return false;\n }\n\n public getTypes(): JsonType[] {\n return Array.from(this.types.values());\n }\n}\n"]}
|
|
@@ -59,23 +59,22 @@ export class JsonGen {
|
|
|
59
59
|
const types = this.context.getTypes();
|
|
60
60
|
const root = types.find((t) => t.getParent() === null);
|
|
61
61
|
if (root) {
|
|
62
|
+
// only Obj nodes are collected — arrays recurse into their item type, scalars are skipped
|
|
62
63
|
const orderedSet = new Set();
|
|
63
64
|
this.writeType(root, orderedSet);
|
|
64
65
|
const generatedSet = new Map();
|
|
65
|
-
orderedSet.forEach((
|
|
66
|
-
// Assumes t is an Obj
|
|
67
|
-
const obj = t;
|
|
66
|
+
orderedSet.forEach((obj) => {
|
|
68
67
|
let typeName = obj.getType();
|
|
69
68
|
if (generatedSet.has(typeName)) {
|
|
70
69
|
// If same type, skip generation
|
|
71
70
|
if (_.isEqual(obj, generatedSet.get(typeName))) {
|
|
72
71
|
return;
|
|
73
72
|
}
|
|
74
|
-
obj.setType(JsonGen.generateNewObjType(generatedSet,
|
|
73
|
+
obj.setType(JsonGen.generateNewObjType(generatedSet, obj, typeName));
|
|
75
74
|
typeName = obj.getType();
|
|
76
75
|
}
|
|
77
|
-
|
|
78
|
-
generatedSet.set(typeName,
|
|
76
|
+
obj.write(this.context, writer);
|
|
77
|
+
generatedSet.set(typeName, obj);
|
|
79
78
|
});
|
|
80
79
|
}
|
|
81
80
|
return writer.flush();
|
|
@@ -108,9 +107,15 @@ export class JsonGen {
|
|
|
108
107
|
trace(context, '-> [walkElement]', 'in: ' + name);
|
|
109
108
|
let result;
|
|
110
109
|
if (typeof element === 'object' && !Array.isArray(element) && element !== null) {
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
// an empty {} value declares no fields — a field-less type would be skipped at write
|
|
111
|
+
// time, dangling its reference; use the JSON scalar instead (the #19 convention). #21
|
|
112
|
+
if (Object.keys(element).length === 0) {
|
|
113
|
+
result = new JsonScalar(name, parent, 'JSON');
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
result = this.walkObject(context, parent, name, element);
|
|
117
|
+
context.store(result);
|
|
118
|
+
}
|
|
114
119
|
}
|
|
115
120
|
else if (Array.isArray(element)) {
|
|
116
121
|
result = this.walkArray(context, parent, name, element);
|
|
@@ -153,7 +158,10 @@ export class JsonGen {
|
|
|
153
158
|
result.setArrayType(arrayType);
|
|
154
159
|
}
|
|
155
160
|
else {
|
|
156
|
-
|
|
161
|
+
// an empty [] gives no item shape — a typeless array is dropped from the SDL but still
|
|
162
|
+
// selected, breaking compose; `[JSON]` keeps both artifacts consistent (#19/#21 convention). #35
|
|
163
|
+
warn(context, ' [walkArray]', "Array is empty -- using JSON for field '" + name + "'");
|
|
164
|
+
result.setArrayType(new JsonScalar(name, result, 'JSON'));
|
|
157
165
|
}
|
|
158
166
|
trace(context, '-> [walkArray]', 'in: ' + name);
|
|
159
167
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonGen.js","sourceRoot":"","sources":["../../../src/json/walker/jsonGen.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport _ from 'lodash';\nimport { DEFAULT_VERSIONS, validateVersionOptions } from '../../versions.js';\nimport { ConnectorWriter, JsonArray, JsonContext, JsonObj, JsonScalar, JsonType, StringWriter } from '../index.js';\nimport { trace, warn } from './log/trace.js';\nimport { sanitiseField } from './naming.js';\n\nexport interface JsonGenOptions {\n federationVersion?: string;\n connectorSpecVersion?: string;\n rootType?: string;\n baseURL?: string;\n relativePath?: string;\n queryField?: string;\n verbose?: boolean;\n}\n\nexport class JsonGen {\n private readonly context: JsonContext;\n private readonly options: JsonGenOptions;\n\n // Private constructor\n private constructor(options: JsonGenOptions = {}) {\n this.context = new JsonContext();\n this.context.verbose = options.verbose ?? false;\n this.options = {\n federationVersion: DEFAULT_VERSIONS.federationVersion,\n connectorSpecVersion: DEFAULT_VERSIONS.connectorSpecVersion,\n ...options,\n };\n validateVersionOptions(this.options);\n }\n\n public getContext(): JsonContext {\n return this.context;\n }\n\n public static new(options?: JsonGenOptions): JsonGen {\n return new JsonGen(options);\n }\n\n // Factory method from a JSON string\n public static fromReader(json: string, options?: JsonGenOptions): JsonGen {\n const walker = new JsonGen(options);\n walker.walkJson(json);\n return walker;\n }\n\n public static fromJsons(jsons: string[], options?: JsonGenOptions): JsonGen {\n const walker = new JsonGen(options);\n for (const json of jsons) {\n walker.walkJson(json);\n }\n return walker;\n }\n\n public generateSchema(): string {\n const writer = new StringWriter();\n ConnectorWriter.write(this, writer, this.options);\n return writer.flush();\n }\n\n // Writes selection using a given Writer\n public writeSelection(indent: number = 6): string {\n const writer = new StringWriter();\n this.context.setIndent(indent);\n\n const types = this.context.getTypes();\n const root = types.find((t: JsonType) => t.getParent() === null);\n if (root) {\n root.select(this.context, writer);\n }\n\n return writer.flush();\n }\n\n // Writes all types in order using the provided Writer\n public writeTypes(): string {\n const writer = new StringWriter();\n\n const types = this.context.getTypes();\n const root = types.find((t: JsonType) => t.getParent() === null);\n if (root) {\n const orderedSet = new Set<JsonType>();\n this.writeType(root, orderedSet);\n\n const generatedSet = new Map<string, JsonType>();\n orderedSet.forEach((t) => {\n // Assumes t is an Obj\n const obj = t as unknown as JsonObj;\n let typeName = obj.getType();\n if (generatedSet.has(typeName)) {\n // If same type, skip generation\n if (_.isEqual(obj, generatedSet.get(typeName))) {\n return;\n }\n obj.setType(JsonGen.generateNewObjType(generatedSet, t, typeName));\n typeName = obj.getType();\n }\n t.write(this.context, writer);\n generatedSet.set(typeName, t);\n });\n }\n\n return writer.flush();\n }\n\n // Recursive helper to order types\n private writeType(type: JsonType, orderedSet: Set<JsonType>): void {\n if (type instanceof JsonObj) {\n // Traverse children first\n for (const child of Array.from((type as JsonObj).getFields().values())) {\n this.writeType(child, orderedSet);\n }\n orderedSet.add(type);\n } else if (type instanceof JsonArray) {\n const arrayType = (type as JsonArray).getArrayType();\n if (arrayType) {\n this.writeType(arrayType, orderedSet);\n }\n }\n }\n\n // Walk the JSON provided as a string\n public walkJson(json: string): void {\n const rootElement = JSON.parse(json);\n const rootName = (this.options.rootType ?? 'root').replace(/^\\[|]$/g, '');\n this.walkElement(this.context, null, rootName, rootElement);\n trace(this.context, ' [walkSource]', 'types found: ' + this.context.getTypes().length);\n }\n\n // Walk an element in the JSON tree\n private walkElement(context: JsonContext, parent: JsonType | null, name: string, element: any): JsonType {\n trace(context, '-> [walkElement]', 'in: ' + name);\n let result: JsonType;\n\n if (typeof element === 'object' && !Array.isArray(element) && element !== null) {\n // JSON object\n result = this.walkObject(context, parent, name, element);\n context.store(result);\n } else if (Array.isArray(element)) {\n result = this.walkArray(context, parent, name, element);\n } else if (typeof element === 'string' || typeof element === 'number' || typeof element === 'boolean') {\n result = this.walkPrimitive(context, parent, name, element);\n } else if (element === null) {\n // we'll treat null as a string\n result = this.walkPrimitive(context, parent, name, 'string');\n } else {\n throw new Error(\"Cannot yet handle '\" + name + \"' of type \" + typeof element);\n }\n\n trace(context, '<- [walkElement]', 'out: ' + name);\n return result;\n }\n\n // Walk a JSON object\n private walkObject(context: JsonContext, parent: JsonType | null, name: string, object: any): JsonObj {\n trace(context, '-> [walkObject]', 'in: ' + name);\n const result = new JsonObj(name, parent);\n const fieldSet = Object.keys(object);\n trace(context, ' [walkObject]', 'fieldSet: ' + fieldSet);\n\n for (const field of fieldSet) {\n trace(context, ' [walkObject]', 'field: ' + field);\n const childElement = object[field];\n const type = this.walkElement(context, result, field, childElement);\n result.add(field, type);\n }\n\n trace(context, '<- [walkObject]', 'out: ' + name);\n return result;\n }\n\n // Walk a JSON array\n private walkArray(context: JsonContext, parent: JsonType | null, name: string, array: any[]): JsonArray {\n trace(context, '-> [walkArray]', 'in: ' + name);\n const result = new JsonArray(name, parent);\n if (array.length > 0) {\n const firstElement = array[0];\n const arrayType = this.walkElement(context, parent, name, firstElement);\n result.setArrayType(arrayType);\n } else {\n warn(context, ' [walkArray]', \"Array is empty -- cannot derive type for field '\" + name + \"'\");\n }\n trace(context, '-> [walkArray]', 'in: ' + name);\n return result;\n }\n\n // Walk a primitive JSON value\n private walkPrimitive(_context: JsonContext, parent: JsonType | null, name: string, primitive: any): JsonScalar {\n let result: JsonScalar;\n if (typeof primitive === 'string') {\n result = new JsonScalar(name, parent, 'String');\n } else if (typeof primitive === 'boolean') {\n result = new JsonScalar(name, parent, 'Boolean');\n } else if (typeof primitive === 'number') {\n result = new JsonScalar(name, parent, 'Int');\n } else {\n throw new Error('Cannot yet handle primitive: ' + primitive);\n }\n return result;\n }\n\n // Utility method for naming conflict resolution\n private static generateNewObjType(generatedSet: Map<string, JsonType>, t: JsonType, typeName: string): string {\n let newName: string;\n let type: JsonType | null = t;\n do {\n const parent: JsonType | null = type.getParent();\n const parentName = parent === null ? '' : sanitiseField(parent.getName()).replace(/^\\w/, (c) => c.toUpperCase());\n const thisName = sanitiseField(typeName).replace(/^\\w/, (c) => c.toUpperCase());\n newName = parentName + thisName;\n type = parent;\n } while (type !== null && generatedSet.has(newName));\n return newName;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"jsonGen.js","sourceRoot":"","sources":["../../../src/json/walker/jsonGen.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport _ from 'lodash';\nimport { DEFAULT_VERSIONS, validateVersionOptions } from '../../versions.js';\nimport { ConnectorWriter, JsonArray, JsonContext, JsonObj, JsonScalar, JsonType, StringWriter } from '../index.js';\nimport { trace, warn } from './log/trace.js';\nimport { sanitiseField } from './naming.js';\n\nexport interface JsonGenOptions {\n federationVersion?: string;\n connectorSpecVersion?: string;\n rootType?: string;\n baseURL?: string;\n relativePath?: string;\n queryField?: string;\n verbose?: boolean;\n}\n\nexport class JsonGen {\n private readonly context: JsonContext;\n private readonly options: JsonGenOptions;\n\n // Private constructor\n private constructor(options: JsonGenOptions = {}) {\n this.context = new JsonContext();\n this.context.verbose = options.verbose ?? false;\n this.options = {\n federationVersion: DEFAULT_VERSIONS.federationVersion,\n connectorSpecVersion: DEFAULT_VERSIONS.connectorSpecVersion,\n ...options,\n };\n validateVersionOptions(this.options);\n }\n\n public getContext(): JsonContext {\n return this.context;\n }\n\n public static new(options?: JsonGenOptions): JsonGen {\n return new JsonGen(options);\n }\n\n // Factory method from a JSON string\n public static fromReader(json: string, options?: JsonGenOptions): JsonGen {\n const walker = new JsonGen(options);\n walker.walkJson(json);\n return walker;\n }\n\n public static fromJsons(jsons: string[], options?: JsonGenOptions): JsonGen {\n const walker = new JsonGen(options);\n for (const json of jsons) {\n walker.walkJson(json);\n }\n return walker;\n }\n\n public generateSchema(): string {\n const writer = new StringWriter();\n ConnectorWriter.write(this, writer, this.options);\n return writer.flush();\n }\n\n // Writes selection using a given Writer\n public writeSelection(indent: number = 6): string {\n const writer = new StringWriter();\n this.context.setIndent(indent);\n\n const types = this.context.getTypes();\n const root = types.find((t: JsonType) => t.getParent() === null);\n if (root) {\n root.select(this.context, writer);\n }\n\n return writer.flush();\n }\n\n // Writes all types in order using the provided Writer\n public writeTypes(): string {\n const writer = new StringWriter();\n\n const types = this.context.getTypes();\n const root = types.find((t: JsonType) => t.getParent() === null);\n if (root) {\n // only Obj nodes are collected — arrays recurse into their item type, scalars are skipped\n const orderedSet = new Set<JsonObj>();\n this.writeType(root, orderedSet);\n\n const generatedSet = new Map<string, JsonType>();\n orderedSet.forEach((obj) => {\n let typeName = obj.getType();\n if (generatedSet.has(typeName)) {\n // If same type, skip generation\n if (_.isEqual(obj, generatedSet.get(typeName))) {\n return;\n }\n obj.setType(JsonGen.generateNewObjType(generatedSet, obj, typeName));\n typeName = obj.getType();\n }\n obj.write(this.context, writer);\n generatedSet.set(typeName, obj);\n });\n }\n\n return writer.flush();\n }\n\n // Recursive helper to order types\n private writeType(type: JsonType, orderedSet: Set<JsonObj>): void {\n if (type instanceof JsonObj) {\n // Traverse children first\n for (const child of Array.from(type.getFields().values())) {\n this.writeType(child, orderedSet);\n }\n orderedSet.add(type);\n } else if (type instanceof JsonArray) {\n const arrayType = type.getArrayType();\n if (arrayType) {\n this.writeType(arrayType, orderedSet);\n }\n }\n }\n\n // Walk the JSON provided as a string\n public walkJson(json: string): void {\n const rootElement = JSON.parse(json);\n const rootName = (this.options.rootType ?? 'root').replace(/^\\[|]$/g, '');\n this.walkElement(this.context, null, rootName, rootElement);\n trace(this.context, ' [walkSource]', 'types found: ' + this.context.getTypes().length);\n }\n\n // Walk an element in the JSON tree\n private walkElement(context: JsonContext, parent: JsonType | null, name: string, element: any): JsonType {\n trace(context, '-> [walkElement]', 'in: ' + name);\n let result: JsonType;\n\n if (typeof element === 'object' && !Array.isArray(element) && element !== null) {\n // an empty {} value declares no fields — a field-less type would be skipped at write\n // time, dangling its reference; use the JSON scalar instead (the #19 convention). #21\n if (Object.keys(element).length === 0) {\n result = new JsonScalar(name, parent, 'JSON');\n } else {\n result = this.walkObject(context, parent, name, element);\n context.store(result);\n }\n } else if (Array.isArray(element)) {\n result = this.walkArray(context, parent, name, element);\n } else if (typeof element === 'string' || typeof element === 'number' || typeof element === 'boolean') {\n result = this.walkPrimitive(context, parent, name, element);\n } else if (element === null) {\n // we'll treat null as a string\n result = this.walkPrimitive(context, parent, name, 'string');\n } else {\n throw new Error(\"Cannot yet handle '\" + name + \"' of type \" + typeof element);\n }\n\n trace(context, '<- [walkElement]', 'out: ' + name);\n return result;\n }\n\n // Walk a JSON object\n private walkObject(context: JsonContext, parent: JsonType | null, name: string, object: any): JsonObj {\n trace(context, '-> [walkObject]', 'in: ' + name);\n const result = new JsonObj(name, parent);\n const fieldSet = Object.keys(object);\n trace(context, ' [walkObject]', 'fieldSet: ' + fieldSet);\n\n for (const field of fieldSet) {\n trace(context, ' [walkObject]', 'field: ' + field);\n const childElement = object[field];\n const type = this.walkElement(context, result, field, childElement);\n result.add(field, type);\n }\n\n trace(context, '<- [walkObject]', 'out: ' + name);\n return result;\n }\n\n // Walk a JSON array\n private walkArray(context: JsonContext, parent: JsonType | null, name: string, array: any[]): JsonArray {\n trace(context, '-> [walkArray]', 'in: ' + name);\n const result = new JsonArray(name, parent);\n if (array.length > 0) {\n const firstElement = array[0];\n const arrayType = this.walkElement(context, parent, name, firstElement);\n result.setArrayType(arrayType);\n } else {\n // an empty [] gives no item shape — a typeless array is dropped from the SDL but still\n // selected, breaking compose; `[JSON]` keeps both artifacts consistent (#19/#21 convention). #35\n warn(context, ' [walkArray]', \"Array is empty -- using JSON for field '\" + name + \"'\");\n result.setArrayType(new JsonScalar(name, result, 'JSON'));\n }\n trace(context, '-> [walkArray]', 'in: ' + name);\n return result;\n }\n\n // Walk a primitive JSON value\n private walkPrimitive(_context: JsonContext, parent: JsonType | null, name: string, primitive: any): JsonScalar {\n let result: JsonScalar;\n if (typeof primitive === 'string') {\n result = new JsonScalar(name, parent, 'String');\n } else if (typeof primitive === 'boolean') {\n result = new JsonScalar(name, parent, 'Boolean');\n } else if (typeof primitive === 'number') {\n result = new JsonScalar(name, parent, 'Int');\n } else {\n throw new Error('Cannot yet handle primitive: ' + primitive);\n }\n return result;\n }\n\n // Utility method for naming conflict resolution\n private static generateNewObjType(generatedSet: Map<string, JsonType>, t: JsonType, typeName: string): string {\n let newName: string;\n let type: JsonType | null = t;\n do {\n const parent: JsonType | null = type.getParent();\n const parentName = parent === null ? '' : sanitiseField(parent.getName()).replace(/^\\w/, (c) => c.toUpperCase());\n const thisName = sanitiseField(typeName).replace(/^\\w/, (c) => c.toUpperCase());\n newName = parentName + thisName;\n type = parent;\n } while (type !== null && generatedSet.has(newName));\n return newName;\n }\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import { Composed } from '../nodes/comp.js';
|
|
3
|
-
import { Prop, PropArray, PropCircRef, PropEn, Scalar, T } from '../nodes/internal.js';
|
|
3
|
+
import { Prop, PropArray, PropCircRef, PropEn, PropObj, Scalar, T } from '../nodes/internal.js';
|
|
4
4
|
import { Naming } from '../utils/naming.js';
|
|
5
5
|
export class TypesCollector {
|
|
6
6
|
gen;
|
|
@@ -244,6 +244,18 @@ class PathsCollector {
|
|
|
244
244
|
this.gen.expand(child);
|
|
245
245
|
}
|
|
246
246
|
});
|
|
247
|
+
// an op whose expansion found nothing selectable still has fields to write when its only
|
|
248
|
+
// content is a free-form JSON object (asana: `data: $ref EmptyResponse` -> `data: JSON`,
|
|
249
|
+
// emitted as an EMPTY invalid type before) — take those fields as the leaves. Scoped to
|
|
250
|
+
// otherwise-empty ops on purpose: doing it everywhere diverged the selections of types
|
|
251
|
+
// shared across connectors. see docs/issues.md #32
|
|
252
|
+
if (!Array.from(newSelection).some((p) => p.startsWith(root.path()))) {
|
|
253
|
+
T.traverse(root, (child) => {
|
|
254
|
+
if (child instanceof PropObj && _.isEmpty(child.obj?.props)) {
|
|
255
|
+
newSelection.add(child.path());
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
247
259
|
});
|
|
248
260
|
// finally remove the expanded paths from the selection
|
|
249
261
|
return [...newSelection, ...selection.filter((p) => !expands.includes(p))];
|
|
@@ -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, 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\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, 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"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { OasContext } from '../oasContext.js';
|
|
2
|
+
import { OasGen } from '../oasGen.js';
|
|
3
|
+
import { Op } from '../nodes/internal.js';
|
|
4
|
+
import { Writer } from './writer.js';
|
|
5
|
+
export declare class ErrorsWriter {
|
|
6
|
+
private gen;
|
|
7
|
+
private static readonly MESSAGE_FIELDS;
|
|
8
|
+
constructor(gen: OasGen);
|
|
9
|
+
write(context: OasContext, writer: Writer, op: Op, indent: number): void;
|
|
10
|
+
private hasDocumentedErrors;
|
|
11
|
+
private errorMessageField;
|
|
12
|
+
private deref;
|
|
13
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { DEFAULT_VERSIONS, meetsMinimum } from '../../versions.js';
|
|
3
|
+
import { warn } from '../log/trace.js';
|
|
4
|
+
// R4 (opt-in): the `errors:` block of a connector — `message` from the documented error body,
|
|
5
|
+
// `extensions` carrying `$status`.
|
|
6
|
+
export class ErrorsWriter {
|
|
7
|
+
gen;
|
|
8
|
+
// corpus-measured priority for the error-body message field: `message` (755 error schemas),
|
|
9
|
+
// `error` (362), `detail` (7)
|
|
10
|
+
static MESSAGE_FIELDS = ['message', 'error', 'detail'];
|
|
11
|
+
constructor(gen) {
|
|
12
|
+
this.gen = gen;
|
|
13
|
+
}
|
|
14
|
+
// emit `errors: { message: "$.message" extensions: """statusCode: $status""" }` for operations
|
|
15
|
+
// that 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.
|
|
17
|
+
write(context, writer, op, indent) {
|
|
18
|
+
if (!context.generateOptions?.emitConnectorErrors || !this.hasDocumentedErrors(op)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
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
|
+
// `message: "$.message"` — the path form yields the field's VALUE; a bare `message`
|
|
27
|
+
// selection would build the object `{message: …}`, which errors.message rejects. R4
|
|
28
|
+
const message = this.errorMessageField(context, op);
|
|
29
|
+
const spacing = ' '.repeat(indent + 6);
|
|
30
|
+
writer
|
|
31
|
+
.write(spacing)
|
|
32
|
+
.write(message ? `errors: { message: "$.${message}" extensions: """\n` : 'errors: { extensions: """\n')
|
|
33
|
+
.write(spacing)
|
|
34
|
+
.write('statusCode: $status\n')
|
|
35
|
+
.write(spacing)
|
|
36
|
+
.write('""" }\n');
|
|
37
|
+
}
|
|
38
|
+
// True when the operation documents an HTTP error response. Accepts both concrete numeric statuses
|
|
39
|
+
// (4xx/5xx) and the OAS range keys `4XX`/`5XX` (case-insensitive). The `default` key is excluded —
|
|
40
|
+
// it also covers 2xx/3xx, so it is not specifically an error indicator.
|
|
41
|
+
hasDocumentedErrors(op) {
|
|
42
|
+
return op.operation.getResponseStatusCodes().some((code) => /^[45](\d\d|XX)$/i.test(code));
|
|
43
|
+
}
|
|
44
|
+
// the field must be a string on EVERY documented JSON error shape — a field missing on some
|
|
45
|
+
// status would yield a null message there. Non-JSON / shapeless error responses don't veto.
|
|
46
|
+
errorMessageField(context, op) {
|
|
47
|
+
const responses = op.operation.schema.responses ?? {};
|
|
48
|
+
const errorShapes = [];
|
|
49
|
+
for (const [code, response] of Object.entries(responses)) {
|
|
50
|
+
if (!/^[45](\d\d|XX)$/i.test(code)) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const resolved = this.deref(context, response);
|
|
54
|
+
const mediaKey = Object.keys(resolved?.content ?? {}).find((k) => /^application\/(?:.*\+)?json/i.test(k));
|
|
55
|
+
const schema = mediaKey
|
|
56
|
+
? this.deref(context, resolved.content[mediaKey].schema)
|
|
57
|
+
: null;
|
|
58
|
+
if (schema?.properties) {
|
|
59
|
+
errorShapes.push(schema.properties);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (errorShapes.length === 0) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return ErrorsWriter.MESSAGE_FIELDS.find((field) => errorShapes.every((props) => this.deref(context, props[field])?.type === 'string'));
|
|
66
|
+
}
|
|
67
|
+
// read-only $ref hop — resolvePointer, NOT lookupRef: this sniff must not bump refCount
|
|
68
|
+
deref(context, node) {
|
|
69
|
+
return _.has(node, '$ref') ? context.resolvePointer(_.get(node, '$ref')) : node;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=errorsWriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorsWriter.js","sourceRoot":"","sources":["../../../src/oas/io/errorsWriter.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAC;AAMvB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,8FAA8F;AAC9F,mCAAmC;AACnC,MAAM,OAAO,YAAY;IAKH;IAJpB,4FAA4F;IAC5F,8BAA8B;IACtB,MAAM,CAAU,cAAc,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAExE,YAAoB,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;IAAG,CAAC;IAEnC,+FAA+F;IAC/F,4FAA4F;IAC5F,2DAA2D;IACpD,KAAK,CAAC,OAAmB,EAAE,MAAc,EAAE,EAAM,EAAE,MAAc;QACtE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,mBAAmB,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC,EAAE,CAAC;YACnF,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,IAAI,gBAAgB,CAAC,oBAAoB,CAAC;QAC/F,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;YACnC,IAAI,CACF,OAAO,EACP,UAAU,EACV,0DAA0D,OAAO,sBAAsB,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CACtH,CAAC;YACF,OAAO;QACT,CAAC;QAED,oFAAoF;QACpF,oFAAoF;QACpF,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAEpD,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvC,MAAM;aACH,KAAK,CAAC,OAAO,CAAC;aACd,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,OAAO,qBAAqB,CAAC,CAAC,CAAC,6BAA6B,CAAC;aACtG,KAAK,CAAC,OAAO,CAAC;aACd,KAAK,CAAC,uBAAuB,CAAC;aAC9B,KAAK,CAAC,OAAO,CAAC;aACd,KAAK,CAAC,SAAS,CAAC,CAAC;IACtB,CAAC;IAED,mGAAmG;IACnG,mGAAmG;IACnG,wEAAwE;IAChE,mBAAmB,CAAC,EAAM;QAChC,OAAO,EAAE,CAAC,SAAS,CAAC,sBAAsB,EAAE,CAAC,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrG,CAAC;IAED,4FAA4F;IAC5F,4FAA4F;IACpF,iBAAiB,CAAC,OAAmB,EAAE,EAAM;QACnD,MAAM,SAAS,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QACtD,MAAM,WAAW,GAAmC,EAAE,CAAC;QAEvD,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACzD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,SAAS;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAA0B,CAAC;YACxE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,8BAA8B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1G,MAAM,MAAM,GAAG,QAAQ;gBACrB,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,QAAS,CAAC,OAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAyB;gBACnF,CAAC,CAAC,IAAI,CAAC;YACT,IAAI,MAAM,EAAE,UAAU,EAAE,CAAC;gBACvB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,YAAY,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAChD,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAyB,EAAE,IAAI,KAAK,QAAQ,CAAC,CAC5G,CAAC;IACJ,CAAC;IAED,wFAAwF;IAChF,KAAK,CAAC,OAAmB,EAAE,IAAa;QAC9C,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5F,CAAC","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 `errors: { message: \"$.message\" extensions: \"\"\"statusCode: $status\"\"\" }` for operations\n // that 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 const spacing = ' '.repeat(indent + 6);\n writer\n .write(spacing)\n .write(message ? `errors: { message: \"$.${message}\" extensions: \"\"\"\\n` : 'errors: { extensions: \"\"\"\\n')\n .write(spacing)\n .write('statusCode: $status\\n')\n .write(spacing)\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"]}
|