@asyncapi/cli 0.12.9 → 0.13.1
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/lib/commands/diff.d.ts +19 -0
- package/lib/commands/diff.js +151 -0
- package/lib/errors/diff-error.d.ts +6 -0
- package/lib/errors/diff-error.js +19 -0
- package/lib/errors/validation-error.js +11 -1
- package/lib/models/Context.js +2 -3
- package/oclif.manifest.json +1 -1
- package/package.json +5 -4
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { flags } from '@oclif/command';
|
|
2
|
+
import AsyncAPIDiff from '@asyncapi/diff/lib/asyncapidiff';
|
|
3
|
+
import Command from '../base';
|
|
4
|
+
export default class Diff extends Command {
|
|
5
|
+
static description: string;
|
|
6
|
+
static flags: {
|
|
7
|
+
help: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
|
|
8
|
+
format: flags.IOptionFlag<string>;
|
|
9
|
+
type: flags.IOptionFlag<string>;
|
|
10
|
+
overrides: flags.IOptionFlag<string | undefined>;
|
|
11
|
+
};
|
|
12
|
+
static args: {
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
required: boolean;
|
|
16
|
+
}[];
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
outputJson(diffOutput: AsyncAPIDiff, outputType: string): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
/* eslint-disable sonarjs/no-duplicate-string */
|
|
5
|
+
const command_1 = require("@oclif/command");
|
|
6
|
+
const diff = tslib_1.__importStar(require("@asyncapi/diff"));
|
|
7
|
+
const parser = tslib_1.__importStar(require("@asyncapi/parser"));
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const SpecificationFile_1 = require("../models/SpecificationFile");
|
|
10
|
+
const base_1 = tslib_1.__importDefault(require("../base"));
|
|
11
|
+
const validation_error_1 = require("../errors/validation-error");
|
|
12
|
+
const specification_file_1 = require("../errors/specification-file");
|
|
13
|
+
const diff_error_1 = require("../errors/diff-error");
|
|
14
|
+
const { readFile } = fs_1.promises;
|
|
15
|
+
class Diff extends base_1.default {
|
|
16
|
+
async run() {
|
|
17
|
+
const { args, flags } = this.parse(Diff); // NOSONAR
|
|
18
|
+
const firstDocumentPath = args['old'];
|
|
19
|
+
const secondDocumentPath = args['new'];
|
|
20
|
+
const outputFormat = flags['format'];
|
|
21
|
+
const outputType = flags['type'];
|
|
22
|
+
const overrideFilePath = flags['overrides'];
|
|
23
|
+
let firstDocument, secondDocument;
|
|
24
|
+
try {
|
|
25
|
+
firstDocument = await SpecificationFile_1.load(firstDocumentPath);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (err instanceof specification_file_1.SpecificationFileNotFound) {
|
|
29
|
+
this.error(new validation_error_1.ValidationError({
|
|
30
|
+
type: 'invalid-file',
|
|
31
|
+
filepath: firstDocumentPath,
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
this.error(err);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
secondDocument = await SpecificationFile_1.load(secondDocumentPath);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
if (err instanceof specification_file_1.SpecificationFileNotFound) {
|
|
43
|
+
this.error(new validation_error_1.ValidationError({
|
|
44
|
+
type: 'invalid-file',
|
|
45
|
+
filepath: secondDocumentPath,
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.error(err);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let overrides = {};
|
|
53
|
+
if (overrideFilePath) {
|
|
54
|
+
try {
|
|
55
|
+
overrides = await readOverrideFile(overrideFilePath);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
this.error(err);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const firstDocumentParsed = await parser.parse(firstDocument.text());
|
|
63
|
+
const secondDocumentParsed = await parser.parse(secondDocument.text());
|
|
64
|
+
const diffOutput = diff.diff(firstDocumentParsed.json(), secondDocumentParsed.json(), {
|
|
65
|
+
override: overrides,
|
|
66
|
+
});
|
|
67
|
+
if (outputFormat === 'json') {
|
|
68
|
+
this.outputJson(diffOutput, outputType);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
this.log(`The output format ${outputFormat} is not supported at the moment.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw new validation_error_1.ValidationError({
|
|
76
|
+
type: 'parser-error',
|
|
77
|
+
err: error,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
outputJson(diffOutput, outputType) {
|
|
82
|
+
if (outputType === 'breaking') {
|
|
83
|
+
this.log(JSON.stringify(diffOutput.breaking(), null, 2));
|
|
84
|
+
}
|
|
85
|
+
else if (outputType === 'non-breaking') {
|
|
86
|
+
this.log(JSON.stringify(diffOutput.nonBreaking(), null, 2));
|
|
87
|
+
}
|
|
88
|
+
else if (outputType === 'unclassified') {
|
|
89
|
+
this.log(JSON.stringify(diffOutput.unclassified(), null, 2));
|
|
90
|
+
}
|
|
91
|
+
else if (outputType === 'all') {
|
|
92
|
+
this.log(JSON.stringify(diffOutput.getOutput(), null, 2));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.log(`The output type ${outputType} is not supported at the moment.`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.default = Diff;
|
|
100
|
+
Diff.description = 'find diff between two asyncapi files';
|
|
101
|
+
Diff.flags = {
|
|
102
|
+
help: command_1.flags.help({ char: 'h' }),
|
|
103
|
+
format: command_1.flags.string({
|
|
104
|
+
char: 'f',
|
|
105
|
+
description: 'format of the output',
|
|
106
|
+
default: 'json',
|
|
107
|
+
options: ['json'],
|
|
108
|
+
}),
|
|
109
|
+
type: command_1.flags.string({
|
|
110
|
+
char: 't',
|
|
111
|
+
description: 'type of the output',
|
|
112
|
+
default: 'all',
|
|
113
|
+
options: ['breaking', 'non-breaking', 'unclassified', 'all'],
|
|
114
|
+
}),
|
|
115
|
+
overrides: command_1.flags.string({
|
|
116
|
+
char: 'o',
|
|
117
|
+
description: 'path to JSON file containing the override properties',
|
|
118
|
+
}),
|
|
119
|
+
};
|
|
120
|
+
Diff.args = [
|
|
121
|
+
{
|
|
122
|
+
name: 'old',
|
|
123
|
+
description: 'old spec path, URL or context-name',
|
|
124
|
+
required: true,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'new',
|
|
128
|
+
description: 'new spec path, URL or context-name',
|
|
129
|
+
required: true,
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
/**
|
|
133
|
+
* Reads the file from give path and parses it as JSON
|
|
134
|
+
* @param path The path to override file
|
|
135
|
+
* @returns The override object
|
|
136
|
+
*/
|
|
137
|
+
async function readOverrideFile(path) {
|
|
138
|
+
let overrideStringData;
|
|
139
|
+
try {
|
|
140
|
+
overrideStringData = await readFile(path, { encoding: 'utf8' });
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
throw new diff_error_1.DiffOverrideFileError();
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
return JSON.parse(overrideStringData);
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
throw new diff_error_1.DiffOverrideJSONError();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DiffOverrideJSONError = exports.DiffOverrideFileError = void 0;
|
|
4
|
+
class DiffOverrideFileError extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super();
|
|
7
|
+
this.name = 'DiffOverrideFileError';
|
|
8
|
+
this.message = 'Override file not found';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.DiffOverrideFileError = DiffOverrideFileError;
|
|
12
|
+
class DiffOverrideJSONError extends Error {
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.name = 'DiffOverrideJSONError';
|
|
16
|
+
this.message = 'Provided override file is not a valid JSON file';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.DiffOverrideJSONError = DiffOverrideJSONError;
|
|
@@ -27,11 +27,21 @@ class ValidationError extends Error {
|
|
|
27
27
|
for (const e of err.validationErrors) {
|
|
28
28
|
const errorHasTitle = !!e.title;
|
|
29
29
|
const errorHasLocation = !!e.location;
|
|
30
|
-
|
|
30
|
+
/*
|
|
31
|
+
* All the conditions below are needed since validationErrors (from ParserError) come from Parser JS library,
|
|
32
|
+
* so we cannot assure that all the fields or properties are always provided in the error. There might be cases
|
|
33
|
+
* that even title is not provided.
|
|
34
|
+
*/
|
|
35
|
+
if (errorHasTitle && errorHasLocation) {
|
|
31
36
|
errorsInfo.push(`${e.title} ${e.location.startLine}:${e.location.startColumn}`);
|
|
37
|
+
continue;
|
|
32
38
|
}
|
|
33
39
|
if (errorHasTitle) {
|
|
34
40
|
errorsInfo.push(`${e.title}`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (errorHasLocation) {
|
|
44
|
+
errorsInfo.push(`${e.location.startLine}:${e.location.startColumn}`);
|
|
35
45
|
}
|
|
36
46
|
}
|
|
37
47
|
}
|
package/lib/models/Context.js
CHANGED
|
@@ -7,9 +7,8 @@ const path = tslib_1.__importStar(require("path"));
|
|
|
7
7
|
const os = tslib_1.__importStar(require("os"));
|
|
8
8
|
const context_error_1 = require("../errors/context-error");
|
|
9
9
|
const { readFile, writeFile } = fs_1.promises;
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
exports.DEFAULT_CONTEXT_FILE_PATH = path.resolve(os.homedir(), CONTEXT_FILENAME);
|
|
10
|
+
const CONTEXT_FILENAME = process.env.CONTEXT_FILENAME || '.asyncapi';
|
|
11
|
+
exports.DEFAULT_CONTEXT_FILE_PATH = path.resolve(process.env.CONTEXT_FILE_PATH || os.homedir(), CONTEXT_FILENAME);
|
|
13
12
|
async function loadContext(contextName) {
|
|
14
13
|
const fileContent = await loadContextFile();
|
|
15
14
|
if (contextName) {
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.
|
|
1
|
+
{"version":"0.13.1","commands":{"config":{"id":"config","description":"access configs","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"diff":{"id":"diff","description":"find diff between two asyncapi files","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"format":{"name":"format","type":"option","char":"f","description":"format of the output","options":["json"],"default":"json"},"type":{"name":"type","type":"option","char":"t","description":"type of the output","options":["breaking","non-breaking","unclassified","all"],"default":"all"},"overrides":{"name":"overrides","type":"option","char":"o","description":"path to JSON file containing the override properties"}},"args":[{"name":"old","description":"old spec path, URL or context-name","required":true},{"name":"new","description":"new spec path, URL or context-name","required":true}]},"new":{"id":"new","description":"creates a new asyncapi file","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"file-name":{"name":"file-name","type":"option","char":"n","description":"name of the file"},"example":{"name":"example","type":"option","char":"e","description":"name of the example to use"},"studio":{"name":"studio","type":"boolean","char":"s","description":"open in Studio","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"port in which to start Studio"},"no-tty":{"name":"no-tty","type":"boolean","description":"do not use an interactive terminal","allowNo":false}},"args":[]},"start":{"id":"start","description":"starts a new local instance of Studio","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"validate":{"id":"validate","description":"validate asyncapi file","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[{"name":"spec-file","description":"spec path, url, or context-name","required":false}]},"config:context":{"id":"config:context","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"start:studio":{"id":"start:studio","description":"starts a new local instance of Studio","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"file":{"name":"file","type":"option","char":"f","description":"path to the AsyncAPI file to link with Studio"},"port":{"name":"port","type":"option","char":"p","description":"port in which to start Studio"}},"args":[]},"config:context:add":{"id":"config:context:add","description":"Add or modify a context in the store","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[{"name":"context-name","description":"context name","required":true},{"name":"spec-file-path","description":"file path of the spec file","required":true}]},"config:context:current":{"id":"config:context:current","description":"Shows the current context that is being used","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"config:context:list":{"id":"config:context:list","description":"List all the stored context in the store","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"config:context:remove":{"id":"config:context:remove","description":"Delete a context from the store","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[{"name":"context-name","description":"Name of the context to delete","required":true}]},"config:context:use":{"id":"config:context:use","description":"Set a context as current","pluginName":"@asyncapi/cli","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[{"name":"context-name","description":"name of the saved context","required":true}]}}}
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asyncapi/cli",
|
|
3
3
|
"description": "All in one CLI for all AsyncAPI tools",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.13.1",
|
|
5
5
|
"author": "@asyncapi",
|
|
6
6
|
"bin": {
|
|
7
7
|
"asyncapi": "./bin/run"
|
|
8
8
|
},
|
|
9
9
|
"bugs": "https://github.com/asyncapi/cli/issues",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@asyncapi/
|
|
12
|
-
"@asyncapi/
|
|
11
|
+
"@asyncapi/diff": "^0.2.2",
|
|
12
|
+
"@asyncapi/parser": "^1.14.0",
|
|
13
|
+
"@asyncapi/studio": "^0.9.0",
|
|
13
14
|
"@fmvilas/oclif-plugin-spaced-commands": "^1.0.4",
|
|
14
15
|
"@oclif/command": "^1.8.0",
|
|
15
16
|
"@oclif/config": "^1.17.0",
|
|
@@ -133,7 +134,7 @@
|
|
|
133
134
|
"pretest:coverage": "npm run build",
|
|
134
135
|
"release": "semantic-release",
|
|
135
136
|
"start": "npm run build && node dist/cli.js",
|
|
136
|
-
"test": "cross-env TEST=1 nyc --extension .ts mocha --require ts-node/register --reporter spec --timeout 10000 \"test/**/*.test.ts\"",
|
|
137
|
+
"test": "cross-env TEST=1 CONTEXT_FILENAME=\"./test.asyncapi\" CONTEXT_FILE_PATH=\"./\" nyc --extension .ts mocha --require ts-node/register --reporter spec --timeout 10000 \"test/**/*.test.ts\"",
|
|
137
138
|
"version": "oclif-dev readme && git add README.md",
|
|
138
139
|
"readme": "oclif readme"
|
|
139
140
|
},
|