Skip to content

Commit b8969fc

Browse files
authored
Merge pull request #4 from elastic/feature/master/generate-client-flight-recorder
Create a flight recorder exporter to compare
2 parents 085b9b5 + 64f12df commit b8969fc

File tree

309 files changed

+6032
-697
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

309 files changed

+6032
-697
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ node_modules
3838

3939
# Build output directory
4040
dist/
41-
41+
flight-recorder-generator/output
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Specification } from "../specification/src/api-specification";
2+
export declare class FlightRecorderJsonGenerator {
3+
private specification;
4+
constructor(specification: Specification);
5+
export(folder: string): void;
6+
private createRequestResponse;
7+
private dispatchInterface;
8+
private static createValueType;
9+
private static createEnumSchema;
10+
private lookupType;
11+
private createTypeSchema;
12+
private createArraySchema;
13+
private createDictionarySchema;
14+
private createInterfaceProperty;
15+
private createUnionOfSchema;
16+
private dispatchInstanceOf;
17+
private toSchema;
18+
}

flight-recorder-generator/flight-recorder-json-generator.js

Lines changed: 157 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import {Specification} from "../specification/src/api-specification";
2+
import * as fs from "fs";
3+
import * as path from "path";
4+
import * as Domain from "elasticsearch-client-specification/src/domain";
5+
import stringify from 'json-stable-stringify'
6+
7+
export class FlightRecorderJsonGenerator {
8+
constructor(private specification: Specification) { }
9+
10+
export(folder: string) {
11+
const f = path.join(__dirname, folder);
12+
if (!fs.existsSync(f))
13+
fs.mkdirSync(f);
14+
this.specification.endpoints.forEach(api => {
15+
const pathPrefix = path.join(f, api.name);
16+
const body =this.createRequestResponse(api.typeMapping.request);
17+
let args = api.queryStringParameters.reduce((o, p) => ({...o, [p.name]: p.type}), {});
18+
args = api.url.paths
19+
.flatMap(p=>p.parts)
20+
.reduce((o, p) => ({...o, [p.name]: p.type}), args);
21+
// tslint:disable-next-line:curly
22+
if (Object.keys(body).length > 0) {
23+
// @ts-ignore
24+
args.body = body;
25+
}
26+
27+
const request = {
28+
api: api.name,
29+
args
30+
};
31+
fs.writeFileSync(pathPrefix + "_request.json", stringify(request, {space:2}));
32+
const response = {
33+
api: api.name,
34+
headers: {
35+
"content-length": "string",
36+
"content-type": "application/json; charset=UTF-8"
37+
},
38+
payload: {
39+
body: this.createRequestResponse(api.typeMapping.response)
40+
41+
},
42+
statusCode: [200]
43+
};
44+
fs.writeFileSync(pathPrefix + "_response.json", stringify(response, {space:2}));
45+
});
46+
47+
}
48+
private createRequestResponse(typeName: string) {
49+
const type = this.lookupType(typeName);
50+
const seenTypes = new Set<string>();
51+
seenTypes.add(typeName);
52+
return this.toSchema(type, seenTypes, typeName);
53+
}
54+
55+
private dispatchInterface(i: Domain.Interface, seenTypes: Set<string>) {
56+
if (i.inheritsFromUnresolved.some(t => t === "String")) return "__" + i.name + "__";
57+
const valueType = FlightRecorderJsonGenerator.createValueType(i.name);
58+
if (valueType !== null) return valueType;
59+
60+
return i.properties
61+
.filter(p => !p.isRequestParameter)
62+
.reduce((o, p) => ({...o, [p.name]: this.createInterfaceProperty(p, seenTypes)}), {});
63+
}
64+
65+
private static createValueType(typeName) {
66+
switch (typeName) {
67+
case "Time" : return "__time__";
68+
case "Uri" : return "__uri__";
69+
case "Date" : return "__date__";
70+
case "TimeSpan" : return "__duration__";
71+
case "TDocument" :
72+
case "TPartialDocument" :
73+
case "SourceDocument" : return "__source__";
74+
case "T" : return "__value__";
75+
case "TResult" : return "__value__";
76+
case "string" :
77+
case "boolean" :
78+
return typeName;
79+
case "short" :
80+
case "byte" :
81+
case "integer" :
82+
case "long" :
83+
return "number";
84+
case "float" :
85+
case "double" :
86+
return "number";
87+
case "object" :
88+
return {}
89+
}
90+
return null
91+
}
92+
93+
private static createEnumSchema(enumType: Domain.Enum) {
94+
return "enum";
95+
// return {
96+
// type: "string",
97+
// description: enumType.flags ? "flags" : null,
98+
// enum: enumType.members.map(e => e.name)
99+
// };
100+
}
101+
102+
private lookupType(typeName) {
103+
let i = this.specification.typeLookup[typeName];
104+
if (i != null) return i;
105+
typeName = typeName.replace(/<.+$/, "");
106+
i = this.specification.typeLookup[typeName];
107+
if (i == null && typeName !== "object" &&
108+
(!typeName.endsWith("Response") && !typeName.endsWith("Request")))
109+
throw Error("Can not find " + typeName);
110+
return i;
111+
}
112+
113+
private createTypeSchema(type: Domain.Type, seenTypes: Set<string>) {
114+
const valueType = FlightRecorderJsonGenerator.createValueType(type.name);
115+
if (valueType !== null) return valueType;
116+
117+
if (seenTypes.has(type.name)) return { $type: `Circular reference to: ${type.name}`};
118+
seenTypes.add(type.name);
119+
120+
const i = this.lookupType(type.name);
121+
const schema = this.toSchema(i, seenTypes, type.name);
122+
seenTypes.delete(type.name);
123+
return schema;
124+
}
125+
126+
private createArraySchema(arr: Domain.ArrayOf, seenTypes) {
127+
return [this.dispatchInstanceOf(arr.of, seenTypes)];
128+
}
129+
130+
private createDictionarySchema(dict: Domain.Dictionary, seenTypes: Set<string>) {
131+
return { __name__ : this.dispatchInstanceOf(dict.value, seenTypes) };
132+
}
133+
134+
private createInterfaceProperty(property: Domain.InterfaceProperty, seenTypes: Set<string>) {
135+
return this.dispatchInstanceOf(property.type, seenTypes);
136+
}
137+
138+
private createUnionOfSchema(union: Domain.UnionOf, seenTypes: Set<string>) {
139+
return { __anyOf__ : [
140+
union.items.map(i => this.dispatchInstanceOf(i, seenTypes))
141+
] };
142+
}
143+
144+
private dispatchInstanceOf(type: Domain.InstanceOf, seenTypes: Set<string>) {
145+
146+
if (type instanceof Domain.Dictionary) return this.createDictionarySchema(type, seenTypes);
147+
if (type instanceof Domain.UnionOf) return this.createUnionOfSchema(type, seenTypes);
148+
if (type instanceof Domain.Type) return this.createTypeSchema(type, seenTypes);
149+
if (type instanceof Domain.ArrayOf) return this.createArraySchema(type, seenTypes);
150+
return { type: "object", description: "Unknown InstanceOf" };
151+
}
152+
private toSchema(type: Domain.TypeDeclaration, seenTypes: Set<string>, lastAddedType: string) {
153+
if (type instanceof Domain.Enum) return FlightRecorderJsonGenerator.createEnumSchema(type);
154+
if (type instanceof Domain.Interface) return this.dispatchInterface(type, seenTypes);
155+
return { type: "object", description: "undefined in spec" + lastAddedType};
156+
}
157+
}

flight-recorder-generator/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};

flight-recorder-generator/index.js

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flight-recorder-generator/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import {Specification} from "../specification/src/api-specification";
2+
import {FlightRecorderJsonGenerator} from "./flight-recorder-json-generator";
3+
// tslint:disable:no-console
4+
5+
const specification = Specification.load();
6+
7+
if (specification.endpoint_errors.length > 0) console.error("The specification contains the following endpoint mapping errors:");
8+
9+
for (const e of specification.endpoint_errors) console.error(" - " + e);
10+
11+
if (specification.domain_errors.length + specification.endpoint_errors.length === 0)
12+
console.log("The specification contains no errors in any of the " +
13+
specification.endpoints.length + " endpoints yielding " + specification.types.length + " types");
14+
15+
console.log("The specification contains " + specification.endpoints.length + " endpoints yielding " + specification.types.length + " types");
16+
17+
const swaggerGenerator = new FlightRecorderJsonGenerator(specification);
18+
swaggerGenerator.export("output");

0 commit comments

Comments
 (0)