@asyncapi/generator 1.11.0 → 1.13.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/.sonarcloud.properties +1 -1
- package/CODEOWNERS +1 -1
- package/docs/configuration-file.md +2 -2
- package/lib/generator.js +46 -27
- package/lib/parser.js +38 -19
- package/lib/templateConfigValidator.js +20 -11
- package/package.json +4 -7
package/.sonarcloud.properties
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#we need to explicitly exclude them as some are commit to the repo
|
|
2
|
-
sonar.exclusions=test
|
|
2
|
+
sonar.exclusions=test/**/*
|
package/CODEOWNERS
CHANGED
|
@@ -8,7 +8,7 @@ The `generator` property from `package.json` file must contain a JSON object tha
|
|
|
8
8
|
|Name|Type|Description|
|
|
9
9
|
|---|---|---|
|
|
10
10
|
|`renderer`| String | Its value can be either `react` or `nunjucks` (default).
|
|
11
|
-
|`apiVersion`| String | Determines which **major** version of the [Parser-API](https://github.com/asyncapi/parser-api) the template uses. For example, `
|
|
11
|
+
|`apiVersion`| String | Determines which **major** version of the [Parser-API](https://github.com/asyncapi/parser-api) the template uses. For example, `v2` for `v2.x.x`. If not specified, the Generator assumes the template is not compatible with the Parser-API so it will use the [Parser-JS v1 API](https://github.com/asyncapi/parser-js/tree/v1.18.1#api-documentation). For templates that need to support AsyncAPI specification v3 make sure to use `v2` [Parser-API](https://github.com/asyncapi/parser-api). If the template uses a version of the Parser-API that is not supported by the Generator, the Generator will throw an error.
|
|
12
12
|
|`supportedProtocols`| [String] | A list with all the protocols this template supports.
|
|
13
13
|
|`parameters`| Object[String, Object] | An object with all the parameters that can be passed when generating the template. When using the command line, it's done by indicating `--param name=value` or `-p name=value`.
|
|
14
14
|
|`parameters[param].description`| String | A user-friendly description about the parameter.
|
|
@@ -28,7 +28,7 @@ The `generator` property from `package.json` file must contain a JSON object tha
|
|
|
28
28
|
"generator":
|
|
29
29
|
{
|
|
30
30
|
"renderer": "react",
|
|
31
|
-
"apiVersion": "
|
|
31
|
+
"apiVersion": "v2",
|
|
32
32
|
"supportedProtocols": ["amqp", "mqtt"],
|
|
33
33
|
"parameters": {
|
|
34
34
|
"server": {
|
package/lib/generator.js
CHANGED
|
@@ -155,13 +155,19 @@ class Generator {
|
|
|
155
155
|
* console.error(e);
|
|
156
156
|
* }
|
|
157
157
|
*
|
|
158
|
-
* @param {AsyncAPIDocument} asyncapiDocument AsyncAPIDocument object to use as source.
|
|
158
|
+
* @param {AsyncAPIDocument | string} asyncapiDocument AsyncAPIDocument object to use as source.
|
|
159
|
+
* @param {Object} [parseOptions={}] AsyncAPI Parser parse options. Check out {@link https://www.github.com/asyncapi/parser-js|@asyncapi/parser} for more information. Remember to use the right options to the right parser depending on the template you are using.
|
|
159
160
|
* @return {Promise}
|
|
160
161
|
*/
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
163
|
+
async generate(asyncapiDocument, parseOptions = {}) {
|
|
164
|
+
const isAlreadyParsedDocument = isAsyncAPIDocument(asyncapiDocument);
|
|
165
|
+
const isParsableCompatible = asyncapiDocument && typeof asyncapiDocument === 'string';
|
|
166
|
+
if (!isAlreadyParsedDocument && !isParsableCompatible) {
|
|
167
|
+
throw new Error('Parameter "asyncapiDocument" must be a non-empty string or an already parsed AsyncAPI document.');
|
|
168
|
+
}
|
|
169
|
+
this.asyncapi = this.originalAsyncAPI = asyncapiDocument;
|
|
163
170
|
|
|
164
|
-
this.asyncapi = asyncapiDocument;
|
|
165
171
|
if (this.output === 'fs') {
|
|
166
172
|
xfs.mkdirpSync(this.targetDir);
|
|
167
173
|
if (!this.forceWrite) await this.verifyTargetDir(this.targetDir);
|
|
@@ -176,11 +182,11 @@ class Generator {
|
|
|
176
182
|
this.templateName = templatePkgName;
|
|
177
183
|
this.templateContentDir = path.resolve(this.templateDir, TEMPLATE_CONTENT_DIRNAME);
|
|
178
184
|
await this.loadTemplateConfig();
|
|
179
|
-
validateTemplateConfig(this.templateConfig, this.templateParams, asyncapiDocument);
|
|
180
|
-
await this.configureTemplate();
|
|
181
185
|
|
|
182
|
-
|
|
183
|
-
|
|
186
|
+
await this.parseInput(this.asyncapi, parseOptions);
|
|
187
|
+
|
|
188
|
+
validateTemplateConfig(this.templateConfig, this.templateParams, this.asyncapi);
|
|
189
|
+
await this.configureTemplate();
|
|
184
190
|
|
|
185
191
|
if (!isReactTemplate(this.templateConfig)) {
|
|
186
192
|
await registerFilters(this.nunjucks, this.templateConfig, this.templateDir, FILTERS_DIRNAME);
|
|
@@ -192,17 +198,38 @@ class Generator {
|
|
|
192
198
|
const entrypointPath = path.resolve(this.templateContentDir, this.entrypoint);
|
|
193
199
|
if (!(await exists(entrypointPath))) throw new Error(`Template entrypoint "${entrypointPath}" couldn't be found.`);
|
|
194
200
|
if (this.output === 'fs') {
|
|
195
|
-
await this.generateFile(
|
|
201
|
+
await this.generateFile(this.asyncapi, path.basename(entrypointPath), path.dirname(entrypointPath));
|
|
196
202
|
await this.launchHook('generate:after');
|
|
197
203
|
} else if (this.output === 'string') {
|
|
198
|
-
return this.renderFile(
|
|
204
|
+
return this.renderFile(this.asyncapi, entrypointPath);
|
|
199
205
|
}
|
|
200
206
|
} else {
|
|
201
|
-
await this.generateDirectoryStructure(
|
|
207
|
+
await this.generateDirectoryStructure(this.asyncapi);
|
|
202
208
|
await this.launchHook('generate:after');
|
|
203
209
|
}
|
|
204
210
|
}
|
|
205
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Parse the generator input based on the template `templateConfig.apiVersion` value.
|
|
214
|
+
*/
|
|
215
|
+
async parseInput(asyncapiDocument, parseOptions = {}) {
|
|
216
|
+
const isAlreadyParsedDocument = isAsyncAPIDocument(asyncapiDocument);
|
|
217
|
+
// use the expected document API based on `templateConfig.apiVersion` value
|
|
218
|
+
if (isAlreadyParsedDocument) {
|
|
219
|
+
this.asyncapi = getProperApiDocument(asyncapiDocument, this.templateConfig);
|
|
220
|
+
} else {
|
|
221
|
+
/** @type {AsyncAPIDocument} Parsed AsyncAPI schema. See {@link https://github.com/asyncapi/parser-js/blob/master/API.md#module_@asyncapi/parser+AsyncAPIDocument|AsyncAPIDocument} for details on object structure. */
|
|
222
|
+
const { document, diagnostics } = await parse(asyncapiDocument, parseOptions, this);
|
|
223
|
+
if (!document) {
|
|
224
|
+
const err = new Error('Input is not a correct AsyncAPI document so it cannot be processed.');
|
|
225
|
+
err.diagnostics = diagnostics;
|
|
226
|
+
throw err;
|
|
227
|
+
} else {
|
|
228
|
+
this.asyncapi = document;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
206
233
|
/**
|
|
207
234
|
* Configure the templates based the desired renderer.
|
|
208
235
|
*/
|
|
@@ -250,22 +277,15 @@ class Generator {
|
|
|
250
277
|
*
|
|
251
278
|
* @param {String} asyncapiString AsyncAPI string to use as source.
|
|
252
279
|
* @param {Object} [parseOptions={}] AsyncAPI Parser parse options. Check out {@link https://www.github.com/asyncapi/parser-js|@asyncapi/parser} for more information.
|
|
280
|
+
* @deprecated Use the `generate` function instead. Just change the function name and it works out of the box.
|
|
253
281
|
* @return {Promise}
|
|
254
282
|
*/
|
|
255
283
|
async generateFromString(asyncapiString, parseOptions = {}) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
this.originalAsyncAPI = asyncapiString;
|
|
260
|
-
|
|
261
|
-
/** @type {AsyncAPIDocument} Parsed AsyncAPI schema. See {@link https://github.com/asyncapi/parser-js/blob/master/API.md#module_@asyncapi/parser+AsyncAPIDocument|AsyncAPIDocument} for details on object structure. */
|
|
262
|
-
const { document, diagnostics } = await parse(asyncapiString, parseOptions, this);
|
|
263
|
-
if (!document) {
|
|
264
|
-
const err = new Error('Input is not a corrent AsyncAPI document so it cannot be processed.');
|
|
265
|
-
err.diagnostics = diagnostics;
|
|
266
|
-
throw err;
|
|
284
|
+
const isParsableCompatible = asyncapiString && typeof asyncapiString === 'string';
|
|
285
|
+
if (!isParsableCompatible) {
|
|
286
|
+
throw new Error('Parameter "asyncapiString" must be a non-empty string.');
|
|
267
287
|
}
|
|
268
|
-
return this.generate(
|
|
288
|
+
return this.generate(asyncapiString, parseOptions);
|
|
269
289
|
}
|
|
270
290
|
|
|
271
291
|
/**
|
|
@@ -292,7 +312,7 @@ class Generator {
|
|
|
292
312
|
*/
|
|
293
313
|
async generateFromURL(asyncapiURL) {
|
|
294
314
|
const doc = await fetchSpec(asyncapiURL);
|
|
295
|
-
return this.
|
|
315
|
+
return this.generate(doc, { path: asyncapiURL });
|
|
296
316
|
}
|
|
297
317
|
|
|
298
318
|
/**
|
|
@@ -319,7 +339,7 @@ class Generator {
|
|
|
319
339
|
*/
|
|
320
340
|
async generateFromFile(asyncapiFile) {
|
|
321
341
|
const doc = await readFile(asyncapiFile, { encoding: 'utf8' });
|
|
322
|
-
return this.
|
|
342
|
+
return this.generate(doc, { path: asyncapiFile });
|
|
323
343
|
}
|
|
324
344
|
|
|
325
345
|
/**
|
|
@@ -416,7 +436,6 @@ class Generator {
|
|
|
416
436
|
*/
|
|
417
437
|
getAllParameters(asyncapiDocument) {
|
|
418
438
|
const parameters = new Map();
|
|
419
|
-
|
|
420
439
|
if (usesNewAPI(this.templateConfig)) {
|
|
421
440
|
asyncapiDocument.channels().all().forEach(channel => {
|
|
422
441
|
channel.parameters().all().forEach(parameter => {
|
|
@@ -436,7 +455,7 @@ class Generator {
|
|
|
436
455
|
}
|
|
437
456
|
});
|
|
438
457
|
}
|
|
439
|
-
|
|
458
|
+
|
|
440
459
|
if (asyncapiDocument.hasComponents()) {
|
|
441
460
|
for (const [key, value] of Object.entries(asyncapiDocument.components().parameters())) {
|
|
442
461
|
parameters.set(key, value);
|
package/lib/parser.js
CHANGED
|
@@ -1,33 +1,52 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
const { OpenAPISchemaParser } = require('@asyncapi/openapi-schema-parser');
|
|
5
|
-
const { AvroSchemaParser } = require('@asyncapi/avro-schema-parser');
|
|
6
|
-
const { RamlDTSchemaParser } = require('@asyncapi/raml-dt-schema-parser');
|
|
7
|
-
const { ProtoBuffSchemaParser } = require('@asyncapi/protobuf-schema-parser');
|
|
2
|
+
const { convertToOldAPI } = require('@asyncapi/parser');
|
|
3
|
+
const { ConvertDocumentParserAPIVersion, NewParser } = require('@smoya/multi-parser');
|
|
8
4
|
|
|
9
5
|
const parser = module.exports;
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Convert the template defined value `apiVersion: 'v1'` to only contain the numeric value `1`.
|
|
9
|
+
*/
|
|
10
|
+
parser.sanitizeTemplateApiVersion = (apiVersion) => {
|
|
11
|
+
if (apiVersion && apiVersion.length > 1) {
|
|
12
|
+
return apiVersion.substring(1);
|
|
13
|
+
}
|
|
14
|
+
return apiVersion;
|
|
15
|
+
};
|
|
19
16
|
|
|
20
|
-
parser.parse = (asyncapi, oldOptions, generator) => {
|
|
17
|
+
parser.parse = async (asyncapi, oldOptions, generator) => {
|
|
18
|
+
let apiVersion = this.sanitizeTemplateApiVersion(generator.templateConfig.apiVersion);
|
|
19
|
+
// Defaulting to apiVersion v1 to convert it to the Parser-API v1 afterwards.
|
|
20
|
+
if (!this.usesNewAPI(generator.templateConfig)) {
|
|
21
|
+
apiVersion = '1';
|
|
22
|
+
}
|
|
21
23
|
const options = convertOldOptionsToNew(oldOptions, generator);
|
|
22
|
-
|
|
24
|
+
const parser = NewParser(apiVersion, {parserOptions: options, includeSchemaParsers: true});
|
|
25
|
+
const { document, diagnostics } = await parser.parse(asyncapi, options);
|
|
26
|
+
if (!document) {
|
|
27
|
+
return {document, diagnostics};
|
|
28
|
+
}
|
|
29
|
+
const correctDocument = this.getProperApiDocument(document, generator.templateConfig);
|
|
30
|
+
return {document: correctDocument, diagnostics};
|
|
23
31
|
};
|
|
24
32
|
|
|
33
|
+
/**
|
|
34
|
+
* If the template expect one of the Parser-API versions, it must be above 0
|
|
35
|
+
*/
|
|
25
36
|
parser.usesNewAPI = (templateConfig = {}) => {
|
|
26
|
-
return templateConfig.apiVersion
|
|
37
|
+
return Number(this.sanitizeTemplateApiVersion(templateConfig.apiVersion)) > 0;
|
|
27
38
|
};
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Based on the current parsed AsyncAPI document, convert it to expected API version from the template.
|
|
42
|
+
*/
|
|
43
|
+
parser.getProperApiDocument = (asyncapiDocument, templateConfig = {}) => {
|
|
44
|
+
const apiVersion = this.sanitizeTemplateApiVersion(templateConfig.apiVersion);
|
|
45
|
+
if (apiVersion === undefined) {
|
|
46
|
+
// Convert to old API from JS Parser v1
|
|
47
|
+
return convertToOldAPI(asyncapiDocument);
|
|
48
|
+
}
|
|
49
|
+
return ConvertDocumentParserAPIVersion(asyncapiDocument, apiVersion);
|
|
31
50
|
};
|
|
32
51
|
|
|
33
52
|
// The new options for the v2 Parser are different from those for the v1 version, but in order not to release Generator v2, we are converting the old options of Parser to the new ones.
|
|
@@ -2,22 +2,26 @@ const semver = require('semver');
|
|
|
2
2
|
const Ajv = require('ajv');
|
|
3
3
|
const { getGeneratorVersion } = require('./utils');
|
|
4
4
|
const levenshtein = require('levenshtein-edit-distance');
|
|
5
|
+
// eslint-disable-next-line no-unused-vars
|
|
6
|
+
const {AsyncAPIDocumentInterface, AsyncAPIDocument} = require('@asyncapi/parser');
|
|
7
|
+
const { usesNewAPI } = require('./parser');
|
|
5
8
|
|
|
6
9
|
const ajv = new Ajv({ allErrors: true });
|
|
7
10
|
|
|
8
11
|
// See https://github.com/asyncapi/parser-api
|
|
9
12
|
const supportedParserAPIMajorVersions = [
|
|
10
13
|
'v1',
|
|
14
|
+
'v2'
|
|
11
15
|
];
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
* Validates the template configuration.
|
|
19
|
+
*
|
|
20
|
+
* @param {Object} templateConfig Template configuration.
|
|
21
|
+
* @param {Object} templateParams Params specified when running generator.
|
|
22
|
+
* @param {AsyncAPIDocumentInterface | AsyncAPIDocument} asyncapiDocument AsyncAPIDocument object to use as source.
|
|
23
|
+
* @return {Boolean}
|
|
24
|
+
*/
|
|
21
25
|
module.exports.validateTemplateConfig = (templateConfig, templateParams, asyncapiDocument) => {
|
|
22
26
|
const { parameters, supportedProtocols, conditionalFiles, generator, apiVersion } = templateConfig;
|
|
23
27
|
|
|
@@ -25,10 +29,15 @@ module.exports.validateTemplateConfig = (templateConfig, templateParams, asyncap
|
|
|
25
29
|
isTemplateCompatible(generator, apiVersion);
|
|
26
30
|
isRequiredParamProvided(parameters, templateParams);
|
|
27
31
|
isProvidedTemplateRendererSupported(templateConfig);
|
|
28
|
-
if (asyncapiDocument) {
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
if (asyncapiDocument && templateParams.server) {
|
|
33
|
+
let server;
|
|
34
|
+
if (usesNewAPI(templateConfig)) {
|
|
35
|
+
server = asyncapiDocument.servers().get(templateParams.server);
|
|
36
|
+
} else {
|
|
37
|
+
server = asyncapiDocument.servers()[templateParams.server];
|
|
38
|
+
}
|
|
31
39
|
isServerProtocolSupported(server, supportedProtocols, templateParams.server);
|
|
40
|
+
isServerProvidedInDocument(server, templateParams.server);
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
isProvidedParameterSupported(parameters, templateParams);
|
|
@@ -48,7 +57,7 @@ function isTemplateCompatible(generator, apiVersion) {
|
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
if (typeof apiVersion === 'string' && !supportedParserAPIMajorVersions.includes(apiVersion)) {
|
|
51
|
-
throw new Error(`The version specified in apiVersion is not supported by this Generator version. Supported versions are: ${supportedParserAPIMajorVersions.
|
|
60
|
+
throw new Error(`The version specified in apiVersion is not supported by this Generator version. Supported versions are: ${supportedParserAPIMajorVersions.join(', ')}`);
|
|
52
61
|
}
|
|
53
62
|
}
|
|
54
63
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asyncapi/generator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "The AsyncAPI generator. It can generate documentation, code, anything!",
|
|
5
5
|
"main": "./lib/generator.js",
|
|
6
6
|
"bin": {
|
|
@@ -48,13 +48,10 @@
|
|
|
48
48
|
"license": "Apache-2.0",
|
|
49
49
|
"homepage": "https://github.com/asyncapi/generator",
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@asyncapi/
|
|
52
|
-
"@asyncapi/
|
|
53
|
-
"@asyncapi/openapi-schema-parser": "^3.0.4",
|
|
54
|
-
"@asyncapi/parser": "^2.1.0",
|
|
55
|
-
"@asyncapi/protobuf-schema-parser": "3.0.0",
|
|
56
|
-
"@asyncapi/raml-dt-schema-parser": "^4.0.4",
|
|
51
|
+
"@asyncapi/generator-react-sdk": "^0.2.23",
|
|
52
|
+
"@asyncapi/parser": "2.1.0",
|
|
57
53
|
"@npmcli/arborist": "^2.2.4",
|
|
54
|
+
"@smoya/multi-parser": "3.0.0",
|
|
58
55
|
"ajv": "^8.12.0",
|
|
59
56
|
"chokidar": "^3.4.0",
|
|
60
57
|
"commander": "^6.1.0",
|