@asyncapi/parser
Advanced tools
Comparing version 0.16.0 to 0.16.1
@@ -21,6 +21,7 @@ const { createMapOfType, getMapKeyOfType, addExtensions } = require('../utils'); | ||
assignNameToAnonymousMessages(this); | ||
assignIdToAnonymousSchemas(this); | ||
assignNameToComponentMessages(this); | ||
assignNameToComponentMessages(this); | ||
assignUidToComponentSchemas(this); | ||
assignUidToParameterSchemas(this); | ||
assignIdToAnonymousSchemas(this); | ||
} | ||
@@ -41,3 +42,3 @@ | ||
} | ||
/** | ||
@@ -56,3 +57,3 @@ * @returns {string} | ||
} | ||
/** | ||
@@ -79,3 +80,3 @@ * @returns {Object<string, Server>} | ||
} | ||
/** | ||
@@ -87,3 +88,3 @@ * @returns {Object<string, Channel>} | ||
} | ||
/** | ||
@@ -147,3 +148,2 @@ * @returns {string[]} | ||
const messages = new Map(); | ||
if (this.hasChannels()) { | ||
@@ -164,9 +164,7 @@ this.channelNames().forEach(channelName => { | ||
} | ||
if (this.hasComponents()) { | ||
Object.values(this.components().messages()).forEach(m => { | ||
messages.set(m.uid(), m); | ||
messages.set(m.uid(), m); | ||
}); | ||
} | ||
return messages; | ||
@@ -180,3 +178,2 @@ } | ||
const schemas = new Map(); | ||
if (this.hasChannels()) { | ||
@@ -216,9 +213,7 @@ this.channelNames().forEach(channelName => { | ||
} | ||
if (this.hasComponents()) { | ||
Object.values(this.components().schemas()).forEach(s => { | ||
schemas.set(s.uid(), s); | ||
schemas.set(s.uid(), s); | ||
}); | ||
} | ||
return schemas; | ||
@@ -228,5 +223,6 @@ } | ||
function assignNameToComponentMessages(doc){ | ||
function assignNameToComponentMessages(doc) { | ||
if (doc.hasComponents()) { | ||
for(const [key, m] of Object.entries(doc.components().messages())){ | ||
for (const [key, m] of Object.entries(doc.components().messages())) { | ||
if (m.name() === undefined) { | ||
@@ -238,5 +234,25 @@ m.json()['x-parser-message-name'] = key; | ||
} | ||
function assignUidToComponentSchemas(doc){ | ||
/** | ||
* Assign parameter keys as uid for the parameter schema. | ||
* | ||
* @param {AsyncAPIDocument} doc | ||
*/ | ||
function assignUidToParameterSchemas(doc) { | ||
doc.channelNames().forEach(channelName => { | ||
const channel = doc.channel(channelName); | ||
for (const [parameterKey, parameterSchema] of Object.entries(channel.parameters())) { | ||
parameterSchema.json()['x-parser-schema-id'] = parameterKey; | ||
} | ||
}); | ||
} | ||
/** | ||
* Assign uid to component schemas. | ||
* | ||
* @param {AsyncAPIDocument} doc | ||
*/ | ||
function assignUidToComponentSchemas(doc) { | ||
if (doc.hasComponents()) { | ||
for(const [key, s] of Object.entries(doc.components().schemas())){ | ||
for (const [key, s] of Object.entries(doc.components().schemas())) { | ||
s.json()['x-parser-schema-id'] = key; | ||
@@ -270,5 +286,55 @@ } | ||
function assignIdToAnonymousSchemas(doc) { | ||
let anonymousSchemaCounter = 0; | ||
/** | ||
* Recursively go through each schema and execute callback. | ||
* | ||
* @param {Schema} schema found. | ||
* @param {Function} callback(schema) | ||
* the function that is called foreach schema found. | ||
* schema {Schema}: the found schema. | ||
*/ | ||
function recursiveSchema(schema, callback) { | ||
if (schema === null) return; | ||
callback(schema); | ||
if (schema.type() !== null) { | ||
switch (schema.type()) { | ||
case 'object': | ||
const props = schema.properties(); | ||
for (const [, propertySchema] of Object.entries(props)) { | ||
recursiveSchema(propertySchema, callback); | ||
} | ||
break; | ||
case 'array': | ||
if (Array.isArray(schema.items())) { | ||
schema.items().forEach(arraySchema => { | ||
recursiveSchema(arraySchema, callback); | ||
}); | ||
} else { | ||
recursiveSchema(schema.items(), callback); | ||
} | ||
break; | ||
} | ||
} else { | ||
//check for allOf, oneOf, anyOf | ||
const checkCombiningSchemas = (combineArray) => { | ||
if (combineArray !== null && combineArray.length > 0) { | ||
combineArray.forEach(combineSchema => { | ||
recursiveSchema(combineSchema, callback);; | ||
}); | ||
} | ||
} | ||
checkCombiningSchemas(schema.allOf()); | ||
checkCombiningSchemas(schema.anyOf()); | ||
checkCombiningSchemas(schema.oneOf()); | ||
} | ||
} | ||
/** | ||
* Go through each channel and for each parameter, and message payload and headers recursively call the callback for each schema. | ||
* | ||
* @param {AsyncAPIDocument} doc | ||
* @param {Function} callback(schema) | ||
* the function that is called foreach schema found. | ||
* schema {Schema}: the found schema. | ||
*/ | ||
function schemaDocument(doc, callback) { | ||
if (doc.hasChannels()) { | ||
@@ -279,5 +345,3 @@ doc.channelNames().forEach(channelName => { | ||
Object.values(channel.parameters()).forEach(p => { | ||
if (p.schema() && !p.schema().$id()) { | ||
p.schema().json()['x-parser-schema-id'] = `<anonymous-schema-${++anonymousSchemaCounter}>`; | ||
} | ||
recursiveSchema(p.schema(), callback); | ||
}); | ||
@@ -287,9 +351,4 @@ | ||
channel.publish().messages().forEach(m => { | ||
if (m.headers() && !m.headers().$id()) { | ||
m.headers().json()['x-parser-schema-id'] = `<anonymous-schema-${++anonymousSchemaCounter}>`; | ||
} | ||
if (m.payload() && !m.payload().$id()) { | ||
m.payload().json()['x-parser-schema-id'] = `<anonymous-schema-${++anonymousSchemaCounter}>`; | ||
} | ||
recursiveSchema(m.headers(), callback); | ||
recursiveSchema(m.payload(), callback); | ||
}); | ||
@@ -299,9 +358,4 @@ } | ||
channel.subscribe().messages().forEach(m => { | ||
if (m.headers() && !m.headers().$id()) { | ||
m.headers().json()['x-parser-schema-id'] = `<anonymous-schema-${++anonymousSchemaCounter}>`; | ||
} | ||
if (m.payload() && !m.payload().$id()) { | ||
m.payload().json()['x-parser-schema-id'] = `<anonymous-schema-${++anonymousSchemaCounter}>`; | ||
} | ||
recursiveSchema(m.headers(), callback); | ||
recursiveSchema(m.payload(), callback); | ||
}); | ||
@@ -313,2 +367,17 @@ } | ||
/** | ||
* Gives schemas id to all anonymous schemas. | ||
* | ||
* @param {AsyncAPIDocument} doc | ||
*/ | ||
function assignIdToAnonymousSchemas(doc) { | ||
let anonymousSchemaCounter = 0; | ||
const callback = (schema) => { | ||
if (!schema.uid()) { | ||
schema.json()['x-parser-schema-id'] = `<anonymous-schema-${++anonymousSchemaCounter}>`; | ||
} | ||
}; | ||
schemaDocument(doc, callback); | ||
} | ||
module.exports = addExtensions(AsyncAPIDocument); |
{ | ||
"name": "@asyncapi/parser", | ||
"version": "0.16.0", | ||
"version": "0.16.1", | ||
"description": "JavaScript AsyncAPI parser.", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -5,2 +5,10 @@ const { expect } = require('chai'); | ||
describe('AsyncAPIDocument', () => { | ||
describe('assignUidToParameterSchemas()', () => { | ||
it('should assign uids to parameters', () => { | ||
const inputDoc = { "channels": { "smartylighting/{streetlightId}": { "parameters": { "streetlightId": { "schema": { "type": "string" } } } } } }; | ||
const expectedDoc = { "channels": { "smartylighting/{streetlightId}": { "parameters": { "streetlightId": { "schema": { "type": "string", "x-parser-schema-id": "<anonymous-schema-1>" }, "x-parser-schema-id": "streetlightId" } } } } } | ||
const d = new AsyncAPIDocument(inputDoc); | ||
expect(d.json()).to.be.deep.equal(expectedDoc); | ||
}); | ||
}); | ||
describe('#ext()', () => { | ||
@@ -7,0 +15,0 @@ it('should support extensions', () => { |
@@ -13,6 +13,6 @@ const chai = require('chai'); | ||
const inputYAML = fs.readFileSync(path.resolve(__dirname, "./asyncapi.yaml"), 'utf8'); | ||
const outputJSON = '{"asyncapi":"2.0.0","info":{"title":"My API","version":"1.0.0"},"channels":{"mychannel":{"publish":{"externalDocs":{"x-extension":true,"url":"https://company.com/docs"},"message":{"payload":{"type":"object","properties":{"name":{"type":"string"},"test":{"type":"object","properties":{"testing":{"type":"string"}}}},"x-parser-schema-id":"testSchema"},"x-some-extension":"some extension","x-parser-original-traits":[{"x-some-extension":"some extension"}],"schemaFormat":"application/vnd.aai.asyncapi;version=2.0.0","x-parser-message-name":"testMessage"},"x-parser-original-traits":[{"externalDocs":{"url":"https://company.com/docs"}}]}}},"components":{"messages":{"testMessage":{"payload":{"type":"object","properties":{"name":{"type":"string"},"test":{"type":"object","properties":{"testing":{"type":"string"}}}},"x-parser-schema-id":"testSchema"},"x-some-extension":"some extension","x-parser-original-traits":[{"x-some-extension":"some extension"}],"schemaFormat":"application/vnd.aai.asyncapi;version=2.0.0","x-parser-message-name":"testMessage"}},"schemas":{"testSchema":{"type":"object","properties":{"name":{"type":"string"},"test":{"type":"object","properties":{"testing":{"type":"string"}}}},"x-parser-schema-id":"testSchema"}},"messageTraits":{"extension":{"x-some-extension":"some extension"}},"operationTraits":{"docs":{"externalDocs":{"url":"https://company.com/docs"}}}}}'; | ||
const outputJsonNoApplyTraits = '{"asyncapi":"2.0.0","info":{"title":"My API","version":"1.0.0"},"channels":{"mychannel":{"publish":{"traits":[{"externalDocs":{"url":"https://company.com/docs"}}],"externalDocs":{"x-extension":true,"url":"https://irrelevant.com"},"message":{"traits":[{"x-some-extension":"some extension"}],"payload":{"type":"object","properties":{"name":{"type":"string"},"test":{"type":"object","properties":{"testing":{"type":"string"}}}},"x-parser-schema-id":"testSchema"},"schemaFormat":"application/vnd.aai.asyncapi;version=2.0.0","x-parser-message-name":"testMessage"}}}},"components":{"messages":{"testMessage":{"traits":[{"x-some-extension":"some extension"}],"payload":{"type":"object","properties":{"name":{"type":"string"},"test":{"type":"object","properties":{"testing":{"type":"string"}}}},"x-parser-schema-id":"testSchema"},"schemaFormat":"application/vnd.aai.asyncapi;version=2.0.0","x-parser-message-name":"testMessage"}},"schemas":{"testSchema":{"type":"object","properties":{"name":{"type":"string"},"test":{"type":"object","properties":{"testing":{"type":"string"}}}},"x-parser-schema-id":"testSchema"}},"messageTraits":{"extension":{"x-some-extension":"some extension"}},"operationTraits":{"docs":{"externalDocs":{"url":"https://company.com/docs"}}}}}'; | ||
const outputJSON = '{"asyncapi":"2.0.0","info":{"title":"My API","version":"1.0.0"},"channels":{"mychannel":{"publish":{"externalDocs":{"x-extension":true,"url":"https://company.com/docs"},"message":{"payload":{"type":"object","properties":{"name":{"type":"string","x-parser-schema-id":"<anonymous-schema-1>"},"test":{"type":"object","properties":{"testing":{"type":"string","x-parser-schema-id":"<anonymous-schema-3>"}},"x-parser-schema-id":"<anonymous-schema-2>"}},"x-parser-schema-id":"testSchema"},"x-some-extension":"some extension","x-parser-original-traits":[{"x-some-extension":"some extension"}],"schemaFormat":"application/vnd.aai.asyncapi;version=2.0.0","x-parser-message-name":"testMessage"},"x-parser-original-traits":[{"externalDocs":{"url":"https://company.com/docs"}}]}}},"components":{"messages":{"testMessage":{"payload":{"type":"object","properties":{"name":{"type":"string","x-parser-schema-id":"<anonymous-schema-1>"},"test":{"type":"object","properties":{"testing":{"type":"string","x-parser-schema-id":"<anonymous-schema-3>"}},"x-parser-schema-id":"<anonymous-schema-2>"}},"x-parser-schema-id":"testSchema"},"x-some-extension":"some extension","x-parser-original-traits":[{"x-some-extension":"some extension"}],"schemaFormat":"application/vnd.aai.asyncapi;version=2.0.0","x-parser-message-name":"testMessage"}},"schemas":{"testSchema":{"type":"object","properties":{"name":{"type":"string","x-parser-schema-id":"<anonymous-schema-1>"},"test":{"type":"object","properties":{"testing":{"type":"string","x-parser-schema-id":"<anonymous-schema-3>"}},"x-parser-schema-id":"<anonymous-schema-2>"}},"x-parser-schema-id":"testSchema"}},"messageTraits":{"extension":{"x-some-extension":"some extension"}},"operationTraits":{"docs":{"externalDocs":{"url":"https://company.com/docs"}}}}}'; | ||
const outputJsonNoApplyTraits = '{"asyncapi":"2.0.0","info":{"title":"My API","version":"1.0.0"},"channels":{"mychannel":{"publish":{"traits":[{"externalDocs":{"url":"https://company.com/docs"}}],"externalDocs":{"x-extension":true,"url":"https://irrelevant.com"},"message":{"traits":[{"x-some-extension":"some extension"}],"payload":{"type":"object","properties":{"name":{"type":"string","x-parser-schema-id":"<anonymous-schema-1>"},"test":{"type":"object","properties":{"testing":{"type":"string","x-parser-schema-id":"<anonymous-schema-3>"}},"x-parser-schema-id":"<anonymous-schema-2>"}},"x-parser-schema-id":"testSchema"},"schemaFormat":"application/vnd.aai.asyncapi;version=2.0.0","x-parser-message-name":"testMessage"}}}},"components":{"messages":{"testMessage":{"traits":[{"x-some-extension":"some extension"}],"payload":{"type":"object","properties":{"name":{"type":"string","x-parser-schema-id":"<anonymous-schema-1>"},"test":{"type":"object","properties":{"testing":{"type":"string","x-parser-schema-id":"<anonymous-schema-3>"}},"x-parser-schema-id":"<anonymous-schema-2>"}},"x-parser-schema-id":"testSchema"},"schemaFormat":"application/vnd.aai.asyncapi;version=2.0.0","x-parser-message-name":"testMessage"}},"schemas":{"testSchema":{"type":"object","properties":{"name":{"type":"string","x-parser-schema-id":"<anonymous-schema-1>"},"test":{"type":"object","properties":{"testing":{"type":"string","x-parser-schema-id":"<anonymous-schema-3>"}},"x-parser-schema-id":"<anonymous-schema-2>"}},"x-parser-schema-id":"testSchema"}},"messageTraits":{"extension":{"x-some-extension":"some extension"}},"operationTraits":{"docs":{"externalDocs":{"url":"https://company.com/docs"}}}}}'; | ||
const invalidAsyncAPI = { "asyncapi": "2.0.0", "info": {} }; | ||
const errorsOfInvalidAsyncAPI = [{keyword: 'required',dataPath: '.info',schemaPath: '#/required',params: { missingProperty: 'title' },message: 'should have required property \'title\''},{keyword: 'required',dataPath: '.info',schemaPath: '#/required',params: { missingProperty: 'version' },message: 'should have required property \'version\''},{keyword: 'required',dataPath: '',schemaPath: '#/required',params: { missingProperty: 'channels' },message: 'should have required property \'channels\''}]; | ||
const errorsOfInvalidAsyncAPI = [{ keyword: 'required', dataPath: '.info', schemaPath: '#/required', params: { missingProperty: 'title' }, message: 'should have required property \'title\'' }, { keyword: 'required', dataPath: '.info', schemaPath: '#/required', params: { missingProperty: 'version' }, message: 'should have required property \'version\'' }, { keyword: 'required', dataPath: '', schemaPath: '#/required', params: { missingProperty: 'channels' }, message: 'should have required property \'channels\'' }]; | ||
@@ -24,7 +24,7 @@ describe('parse()', function () { | ||
}); | ||
it('should forward ajv errors and AsyncAPI json', async function () { | ||
try { | ||
await parser.parse(invalidAsyncAPI); | ||
} catch(e) { | ||
} catch (e) { | ||
await expect(e.errors).to.deep.equal(errorsOfInvalidAsyncAPI); | ||
@@ -34,7 +34,7 @@ await expect(e.parsedJSON).to.deep.equal(invalidAsyncAPI); | ||
}); | ||
it('should not forward AsyncAPI json when it is not possible to convert it', async function () { | ||
try { | ||
await parser.parse('bad'); | ||
} catch(e) { | ||
} catch (e) { | ||
await expect(e.constructor.name).to.equal('ParserErrorNoJS'); | ||
@@ -48,3 +48,3 @@ await expect(e.parsedJSON).to.equal(undefined); | ||
await parser.parse('bad: true'); | ||
} catch(e) { | ||
} catch (e) { | ||
await expect(e.constructor.name).to.equal('ParserErrorUnsupportedVersion'); | ||
@@ -54,3 +54,3 @@ await expect(e.parsedJSON).to.deep.equal({ bad: true }); | ||
}); | ||
it('should not apply traits', async function () { | ||
@@ -60,3 +60,3 @@ const result = await parser.parse(inputYAML, { path: __filename, applyTraits: false }); | ||
}); | ||
it('should fail to resolve relative files when options.path is not provided', async function () { | ||
@@ -67,3 +67,3 @@ const testFn = async () => await parser.parse(inputYAML); | ||
}); | ||
it('should throw error if document is invalid YAML', async function () { | ||
@@ -70,0 +70,0 @@ const testFn = async () => await parser.parse(invalidYAML, { path: __filename }); |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
244603
4014