Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/W-17413312/Incorrect-rendering-of-OAS-Specification-in-Design-centre-and-Exchange #69

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
754 changes: 754 additions & 0 deletions demo/W-17413312/W-17413312.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class ComponentDemo extends ApiDemoPage {
['xml-api', 'xml-api'],
['W-11843862', 'W-11843862'],
['W-17309546', 'W-17309546'],
['W-17413312', 'W-17413312'],
['v4_0_0_api_specs', 'v4_0_0_api_specs']
].map(
([file, label]) => html`
Expand Down
1 change: 1 addition & 0 deletions demo/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ files.set('APIC-332/APIC-332.raml', { type: 'RAML 1.0' });
files.set('APIC-690/APIC-690.raml', { type: 'RAML 1.0' });
files.set('10732397/10732397.raml', { type: 'RAML 1.0' });
files.set('W-17309546/W-17309546.raml', { type: 'RAML 1.0' });
files.set('W-17413312/W-17413312.json', { type: 'OAS 3.0', mime: 'application/json' });
files.set('oas-3-api/oas-3-api.yaml', { type: 'OAS 3.0', mime: 'application/yaml' });
files.set('allof-types/allof-types.yaml', { type: 'OAS 3.0', mime: 'application/yaml' });
files.set('APIC-679/APIC-679.yaml', { type: 'OAS 3.0', mime: 'application/yaml' });
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@api-components/api-example-generator",
"description": "Examples generator from AMF model",
"version": "4.4.30",
"version": "4.4.31",
"license": "Apache-2.0",
"main": "index.js",
"module": "index.js",
Expand Down
40 changes: 40 additions & 0 deletions src/ExampleGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,9 @@ export class ExampleGenerator extends AmfHelperMixin(Object) {
return this._computeJsonPropertyValue(oneOfOptions[0], typeName);
}
}
if (this._hasType(range, this.ns.w3.shacl.Shape)) {
return this._computeJsonOrValue(range);
}
return undefined;
}

Expand Down Expand Up @@ -1649,6 +1652,43 @@ export class ExampleGenerator extends AmfHelperMixin(Object) {
return examples.reduce((acc, value) => ({ ...acc, ...value }), {});
}

/**
* Computes a JSON object or value from a given range.
*
* @param {Object} range AMF's range definition for a shape.
* @return {any|undefined} A JavaScript object or value computed from the range.
*/
_computeJsonOrValue(range) {
const key = this._getAmfKey(this.ns.w3.shacl.or);
const list = this._ensureArray(range[key]);
if (!list) {
return undefined;
}

const examples = [];
const anyOfKey = this._getAmfKey(this.ns.aml.vocabularies.shapes.anyOf);

// Iterate over all items in the list
for (const item of list) {
const properties = this._ensureArray(item[anyOfKey]);
if (properties) {
// Iterate over all properties to get all propertiesSchemas
for (const property of properties) {
const propertiesSchemas = this._listProperties(property);
if (propertiesSchemas) {
const propertiesExamples = this._jsonExampleFromProperties(propertiesSchemas);
if (propertiesExamples && typeof propertiesExamples === 'object') {
examples.push(propertiesExamples);
}
}
}
}
}

// Merge all examples into a single object
return examples.reduce((acc, value) => ({ ...acc, ...value }), {});
}

/**
* Computes JSON object as an example from a range that is an object.
*
Expand Down
8 changes: 4 additions & 4 deletions test/ExampleGenerator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -688,11 +688,11 @@ describe('ExampleGenerator', () => {
assert.equal(root.querySelector('etag').textContent.trim(), 'W\\\\244m4n5kj3gbn2nj4k4n4', 'the etag value');

const image = root.querySelector('image');

assert.ok(image, 'has the image node');
assert.equal(image.querySelector('url').textContent.trim(), 'https://www.domain.com/people/Qawer63J73HJ6khjswuqyq62382jG21s/image', 'the image.url value');
assert.equal(image.querySelector('thumb').textContent.trim(), 'https://www.domain.com/people/Qawer63J73HJ6khjswuqyq62382jG21s/image/thumb', 'the image.thumb value');

assert.typeOf(ex2.raw, 'string', 'example 2 has the raw value');
});

Expand Down Expand Up @@ -2321,7 +2321,7 @@ describe('ExampleGenerator', () => {
schema = element._resolve(schema);
const result = element._computeJsonPropertyValue(schema);
assert.typeOf(result, 'object');
assert.deepEqual(result, { messages: [{ "referrers": [{"type": "Salesforce:Core:Bot:Id", "value": ""}], "sequenceId": 1, "text": "", "type": "init", "tz": "", "variables": [] }]})
assert.deepEqual(result, { messages: [{ "referrers": [{"type": "Salesforce:Core:Bot:Id", "value": ""}], "sequenceId": 1, "text": "", "type": "init", "tz": "", "variables": [{}] }]})
});
});
});
Expand Down Expand Up @@ -2525,7 +2525,7 @@ describe('ExampleGenerator', () => {
assert.typeOf(parsed, 'array', 'represents an array');
assert.lengthOf(parsed, 2, 'has 2 items');
const [e1, e2] = parsed;

assert.equal(e1.id, 1, 'has the example1.id');
assert.equal(e1.name, 'John', 'has the example1.name');
assert.equal(e2.id, 2, 'has the example2.id');
Expand Down
63 changes: 63 additions & 0 deletions test/W-17413312.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { fixture, assert, html } from '@open-wc/testing';
import { AmfLoader } from './amf-loader.js';
import '../api-example-generator.js';

describe('W-17413312', () => {
async function basicFixture(amf) {
return (await fixture(html`<api-example-generator
.amf="${amf}"></api-example-generator>`));
}

const apiFile = 'W-17413312';

[
['json+ld data model', false],
['Compact data model', true]
].forEach(([label, compact]) => {
describe(label, () => {
let element;
let amf;

before(async () => {
amf = await AmfLoader.load(compact, apiFile);
});

beforeEach(async () => {
element = await basicFixture(amf);
});

it('renders examples right', () => {
const payloads = AmfLoader.lookupReturnsPayload(amf, '/sources', 'get', 200);
const result = element.generatePayloadsExamples(payloads, 'application/json');
assert.typeOf(result, 'array');
const item = result[0];
assert.equal(item.value, `{
"data": [
{
"id": "64f1f0d46ad16b6acdaa3e0e",
"name": "Main Station Track 5a",
"type": "Camera",
"class": "Common",
"audio": {
"isEnabled": true
},
"externalReference": "b8755c8d-ef9d-4a7e-a8a2-7b5abace1af7",
"streams": [
{
"id": "64f1eff26ad16b6acdaa3e08",
"url": "rtsp://ipcam573.example.com:554/live/ch0",
"decoderOptions": {
"protocols": 2,
"tcp-timeout": 10000000
}
}
],
"authentication": {}
}
],
"meta": {}
}`);
});
});
});
});
Loading