Skip to content

Commit e5d5d6d

Browse files
expand model to include language versions of examples
1 parent 8009361 commit e5d5d6d

File tree

14 files changed

+43318
-280
lines changed

14 files changed

+43318
-280
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ validate-no-cache: ## Validate a given endpoint request or response without loca
99

1010
generate: ## Generate the output spec
1111
@echo ">> generating the spec .."
12+
@make generate-language-examples
1213
@npm run generate-schema --prefix compiler -- --spec ../specification/ --output ../output/
1314
@npm run start --prefix typescript-generator
1415

compiler-rs/clients_schema/src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,20 +484,28 @@ impl TypeDefinition {
484484

485485
/// The Example type is used for both requests and responses.
486486
///
487-
/// This type definition is taken from the OpenAPI spec
487+
/// This type definition is based on the OpenAPI spec
488488
/// https://spec.openapis.org/oas/v3.1.0#example-object
489-
/// with the exception of using String as the 'value' type.
489+
/// with the exception of using String as the 'value' type,
490+
/// and some custom additions.
490491
///
491492
/// The OpenAPI v3 spec also defines the 'Example' type, so
492493
/// to distinguish them, this type is called SchemaExample.
493494
495+
#[derive(Debug, Clone, Serialize, Deserialize)]
496+
pub struct ExampleAlternative {
497+
pub language: String,
498+
pub code: String,
499+
}
500+
494501
#[derive(Debug, Clone, Serialize, Deserialize)]
495502
pub struct SchemaExample {
496503
pub summary: Option<String>,
497504
pub method_request: Option<String>,
498505
pub description: Option<String>,
499506
pub value: Option<String>,
500507
pub external_value: Option<String>,
508+
pub alternatives: Option<Vec<ExampleAlternative>>,
501509
}
502510

503511
/// Common attributes for all type definitions

compiler-rs/clients_schema_to_openapi/src/paths.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,14 @@ pub fn add_endpoint(
340340
"source": request_line + "\n" + request_body.as_str(),
341341
}));
342342
}
343+
if let Some(alternatives) = example.alternatives.clone() {
344+
for alternative in alternatives.iter() {
345+
code_samples.push(serde_json::json!({
346+
"lang": alternative.language,
347+
"source": alternative.code.as_str(),
348+
}));
349+
}
350+
}
343351
}
344352
}
345353
if !code_samples.is_empty() {

compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.js

Lines changed: 35 additions & 49 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.

compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm.d.ts

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

compiler/src/model/metamodel.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,14 @@ export class Interface extends BaseType {
260260
variants?: Container
261261
}
262262

263+
/**
264+
* An alternative of an example, coded in a given language.
265+
*/
266+
export class ExampleAlternative {
267+
language: string
268+
code: string
269+
}
270+
263271
/**
264272
* The Example type is used for both requests and responses
265273
* This type definition is taken from the OpenAPI spec
@@ -277,6 +285,8 @@ export class Example {
277285
value?: string
278286
/** A URI that points to the literal example */
279287
external_value?: string
288+
/** An array of alternatives for this example in other languages */
289+
alternatives?: ExampleAlternative[]
280290
}
281291

282292
/**
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
const fs = require('fs');
21+
const path = require('path');
22+
const { parseDocument: yamlParseDocument } = require('yaml');
23+
const { convertRequests, loadSchema } = require('@elastic/request-converter');
24+
25+
const LANGUAGES = ['Python', 'JavaScript', 'Ruby', 'PHP', 'curl'];
26+
27+
async function generateLanguages(example) {
28+
const doc = yamlParseDocument(await fs.promises.readFile(example, 'utf8'));
29+
const data = doc.toJS();
30+
let request = data.method_request;
31+
if (data.value) {
32+
if (typeof data.value === 'string') {
33+
request += '\n' + data.value;
34+
}
35+
else {
36+
request += '\n' + JSON.stringify(data.value);
37+
}
38+
}
39+
data.alternatives = [];
40+
for (const lang of LANGUAGES) {
41+
data.alternatives.push({
42+
language: lang,
43+
code: (await convertRequests(request, lang, {})).trim(),
44+
});
45+
}
46+
doc.delete('alternatives');
47+
doc.add(doc.createPair('alternatives', data.alternatives));
48+
await fs.promises.writeFile(example, doc.toString({lineWidth: 132}));
49+
}
50+
51+
async function* walkExamples(dir) {
52+
for await (const d of await fs.promises.opendir(dir)) {
53+
const entry = path.join(dir, d.name);
54+
if (d.isDirectory()) {
55+
yield* walkExamples(entry);
56+
}
57+
else if (d.isFile() && entry.includes('/examples/request/') && entry.endsWith('.yaml')) {
58+
yield entry;
59+
}
60+
}
61+
}
62+
63+
async function main() {
64+
let count = 0;
65+
let errors = 0;
66+
await loadSchema('output/schema/schema.json');
67+
for await (const example of walkExamples('./specification/')) {
68+
try {
69+
await generateLanguages(example);
70+
}
71+
catch (err) {
72+
console.log(`${example}: ${err}`);
73+
errors += 1;
74+
}
75+
count += 1;
76+
}
77+
console.log(`${count} examples processed, ${errors} errors.`);
78+
}
79+
80+
main();

0 commit comments

Comments
 (0)