@oclif/plugin-command-snapshot 3.0.0 → 3.1.3
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/CHANGELOG.md +34 -0
- package/README.md +1 -1
- package/lib/commands/schema/compare.js +21 -10
- package/lib/commands/schema/generate.d.ts +22 -2
- package/lib/commands/schema/generate.js +119 -32
- package/lib/commands/snapshot/compare.d.ts +19 -6
- package/lib/commands/snapshot/compare.js +63 -39
- package/lib/commands/snapshot/generate.d.ts +2 -6
- package/lib/snapshot-command.d.ts +1 -0
- package/lib/snapshot-command.js +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +12 -12
- package/schemas/snapshot-compare.json +22 -0
- package/schemas/snapshot-generate.json +29 -19
- package/yarn.lock +1632 -2227
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [3.1.3](https://github.com/oclif/plugin-command-snapshot/compare/v3.1.2...v3.1.3) (2022-02-14)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* bump demps ([c2643c7](https://github.com/oclif/plugin-command-snapshot/commit/c2643c745aa121677be1bac60547180ba406b8e4))
|
|
11
|
+
|
|
12
|
+
### [3.1.2](https://github.com/oclif/plugin-command-snapshot/compare/v3.1.1...v3.1.2) (2021-11-10)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* adds alias property to command-snapshot \n BREAKING CHANGE: this changes the output of the file of the command snapshot which will cause compare to fail ([dea464e](https://github.com/oclif/plugin-command-snapshot/commit/dea464e17c11efd6a777982f4689bfc41f6ce9bd))
|
|
18
|
+
|
|
19
|
+
### [3.1.1](https://github.com/oclif/plugin-command-snapshot/compare/v3.1.0...v3.1.1) (2021-10-11)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
* update hook regex ([#144](https://github.com/oclif/plugin-command-snapshot/issues/144)) ([dc1225c](https://github.com/oclif/plugin-command-snapshot/commit/dc1225cc22e071958436e320b8951063b038d4cc))
|
|
25
|
+
|
|
26
|
+
## [3.1.0](https://github.com/oclif/plugin-command-snapshot/compare/v3.0.0...v3.1.0) (2021-10-08)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
|
|
31
|
+
* generate schema for hooks ([266b832](https://github.com/oclif/plugin-command-snapshot/commit/266b83242fab1961b036998119791b999a08ee19))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Bug Fixes
|
|
35
|
+
|
|
36
|
+
* ignore hooks with no return type ([070ed41](https://github.com/oclif/plugin-command-snapshot/commit/070ed41902268d48034fdaa2b96f9a4a54eefd2c))
|
|
37
|
+
* schema:compare with hooks ([508549a](https://github.com/oclif/plugin-command-snapshot/commit/508549a372e56b3d79dec970e62477d9905dec13))
|
|
38
|
+
|
|
5
39
|
### [2.2.2](https://github.com/oclif/plugin-command-snapshot/compare/v2.2.1...v2.2.2) (2021-06-30)
|
|
6
40
|
|
|
7
41
|
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Generates and compares OCLIF plugins snapshot files
|
|
|
6
6
|
[](https://oclif.io)
|
|
7
7
|
[](https://npmjs.org/package/@oclif/plugin-command-snapshot)
|
|
8
8
|
[](https://npmjs.org/package/@oclif/plugin-command-snapshot)
|
|
9
|
-
[](https://github.com/nramyasri-sf/@oclif/plugin-command-snapshot/blob/
|
|
9
|
+
[](https://github.com/nramyasri-sf/@oclif/plugin-command-snapshot/blob/main/package.json)
|
|
10
10
|
|
|
11
11
|
<!-- toc -->
|
|
12
12
|
* [Usage](#usage)
|
|
@@ -20,8 +20,10 @@ class SchemaCompare extends snapshot_command_1.SnapshotCommand {
|
|
|
20
20
|
return [];
|
|
21
21
|
}
|
|
22
22
|
const existingSchema = this.readExistingSchema(flags.filepath);
|
|
23
|
-
const latestSchema = await this.generateLatestSchema();
|
|
24
|
-
|
|
23
|
+
const latestSchema = (await this.generateLatestSchema());
|
|
24
|
+
this.debug('existingSchema', existingSchema);
|
|
25
|
+
this.debug('latestSchema', latestSchema);
|
|
26
|
+
const changes = (0, just_diff_1.diff)(latestSchema, existingSchema);
|
|
25
27
|
if (changes.length === 0) {
|
|
26
28
|
this.log('No changes have been detected.');
|
|
27
29
|
return [];
|
|
@@ -38,23 +40,23 @@ class SchemaCompare extends snapshot_command_1.SnapshotCommand {
|
|
|
38
40
|
}
|
|
39
41
|
switch (change.op) {
|
|
40
42
|
case 'replace':
|
|
41
|
-
humandReadableChanges[commandId].push(`${chalk_1.underline(readablePath)} was changed from ${chalk_1.cyan(existing)} to ${chalk_1.cyan(latest)}`);
|
|
43
|
+
humandReadableChanges[commandId].push(`${(0, chalk_1.underline)(readablePath)} was changed from ${(0, chalk_1.cyan)(existing)} to ${(0, chalk_1.cyan)(latest)}`);
|
|
42
44
|
break;
|
|
43
45
|
case 'add':
|
|
44
|
-
humandReadableChanges[commandId].push(`${chalk_1.underline(readablePath)} was ${chalk_1.cyan('added')} to latest schema`);
|
|
46
|
+
humandReadableChanges[commandId].push(`${(0, chalk_1.underline)(readablePath)} was ${(0, chalk_1.cyan)('added')} to latest schema`);
|
|
45
47
|
break;
|
|
46
48
|
case 'remove':
|
|
47
|
-
humandReadableChanges[commandId].push(`${chalk_1.underline(readablePath)} was ${chalk_1.cyan('
|
|
49
|
+
humandReadableChanges[commandId].push(`${(0, chalk_1.underline)(readablePath)} was ${(0, chalk_1.cyan)('not found')} in latest schema`);
|
|
48
50
|
break;
|
|
49
51
|
default:
|
|
50
52
|
break;
|
|
51
53
|
}
|
|
52
54
|
}
|
|
53
55
|
this.log();
|
|
54
|
-
this.log(chalk_1.bold(chalk_1.red('Found the following schema changes:')));
|
|
56
|
+
this.log((0, chalk_1.bold)((0, chalk_1.red)('Found the following schema changes:')));
|
|
55
57
|
for (const [commandId, changes] of Object.entries(humandReadableChanges)) {
|
|
56
58
|
this.log();
|
|
57
|
-
this.log(chalk_1.bold(commandId));
|
|
59
|
+
this.log((0, chalk_1.bold)(commandId));
|
|
58
60
|
for (const change of changes) {
|
|
59
61
|
this.log(` - ${change}`);
|
|
60
62
|
}
|
|
@@ -68,15 +70,24 @@ class SchemaCompare extends snapshot_command_1.SnapshotCommand {
|
|
|
68
70
|
const contents = fs.readdirSync(filePath);
|
|
69
71
|
const folderIsVersioned = contents.every(c => semver.valid(c));
|
|
70
72
|
const schemasDir = folderIsVersioned ? path.join(filePath, semver.rsort(contents)[0] || '') : filePath;
|
|
71
|
-
const schemaFiles =
|
|
72
|
-
let schemas = {
|
|
73
|
+
const schemaFiles = (0, generate_1.getAllFiles)(schemasDir, '.json');
|
|
74
|
+
let schemas = {
|
|
75
|
+
commands: {},
|
|
76
|
+
hooks: {},
|
|
77
|
+
};
|
|
73
78
|
if (schemaFiles.length === 1 && schemaFiles[0].endsWith('schema.json')) {
|
|
74
79
|
schemas = JSON.parse(fs.readFileSync(schemaFiles[0]).toString('utf8'));
|
|
75
80
|
}
|
|
76
81
|
else {
|
|
77
82
|
for (const file of schemaFiles) {
|
|
78
83
|
const schema = JSON.parse(fs.readFileSync(file).toString('utf8'));
|
|
79
|
-
|
|
84
|
+
const key = path.basename(file.replace(/-/g, ':')).replace('.json', '');
|
|
85
|
+
if (file.split(path.sep).includes('hooks')) {
|
|
86
|
+
schemas.hooks[key] = schema;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
schemas.commands[key] = schema;
|
|
90
|
+
}
|
|
80
91
|
}
|
|
81
92
|
}
|
|
82
93
|
return schemas;
|
|
@@ -3,17 +3,37 @@ import { SnapshotCommand } from '../../snapshot-command';
|
|
|
3
3
|
export declare type SchemasMap = {
|
|
4
4
|
[key: string]: Schema;
|
|
5
5
|
};
|
|
6
|
+
export declare type Schemas = {
|
|
7
|
+
commands: SchemasMap;
|
|
8
|
+
hooks: SchemasMap;
|
|
9
|
+
};
|
|
6
10
|
export declare type GenerateResponse = string[];
|
|
11
|
+
export declare function getAllFiles(dirPath: string, ext: string, allFiles?: string[]): string[];
|
|
7
12
|
export declare class SchemaGenerator {
|
|
8
13
|
private base;
|
|
9
14
|
private ignorevoid;
|
|
10
15
|
private classToId;
|
|
11
16
|
constructor(base: SnapshotCommand, ignorevoid?: boolean);
|
|
12
|
-
generate(): Promise<
|
|
17
|
+
generate(): Promise<Schemas>;
|
|
18
|
+
private generateSchema;
|
|
13
19
|
private getAllCmdFiles;
|
|
14
|
-
private
|
|
20
|
+
private getAllHookFiles;
|
|
21
|
+
/**
|
|
22
|
+
* Use regex to find the typescript type being returned by the command's
|
|
23
|
+
* `run` method.
|
|
24
|
+
* @param file the file to parse
|
|
25
|
+
* @returns Returns the name of the return type and the command id.
|
|
26
|
+
*/
|
|
27
|
+
private parseCmdFile;
|
|
28
|
+
/**
|
|
29
|
+
* Use regex to find the typescript type being returned by the hook
|
|
30
|
+
* @param file the file to parse
|
|
31
|
+
* @returns Returns the name of the return type and the hook id.
|
|
32
|
+
*/
|
|
33
|
+
private parseHookFile;
|
|
15
34
|
private validateReturnType;
|
|
16
35
|
private determineCommandId;
|
|
36
|
+
private getDirs;
|
|
17
37
|
}
|
|
18
38
|
export default class SchemaGenerate extends SnapshotCommand {
|
|
19
39
|
static flags: {
|
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SchemaGenerator = void 0;
|
|
3
|
+
exports.SchemaGenerator = exports.getAllFiles = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const core_1 = require("@oclif/core");
|
|
7
7
|
const ts_json_schema_generator_1 = require("ts-json-schema-generator");
|
|
8
8
|
const snapshot_command_1 = require("../../snapshot-command");
|
|
9
9
|
const chalk_1 = require("chalk");
|
|
10
|
+
function getAllFiles(dirPath, ext, allFiles = []) {
|
|
11
|
+
let files = [];
|
|
12
|
+
try {
|
|
13
|
+
files = fs.readdirSync(dirPath);
|
|
14
|
+
}
|
|
15
|
+
catch (_a) { }
|
|
16
|
+
files.forEach(file => {
|
|
17
|
+
const fPath = path.join(dirPath, file);
|
|
18
|
+
if (fs.statSync(fPath).isDirectory()) {
|
|
19
|
+
allFiles = getAllFiles(fPath, ext, allFiles);
|
|
20
|
+
}
|
|
21
|
+
else if (file.endsWith(ext)) {
|
|
22
|
+
allFiles.push(fPath);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return allFiles;
|
|
26
|
+
}
|
|
27
|
+
exports.getAllFiles = getAllFiles;
|
|
10
28
|
class SchemaGenerator {
|
|
11
29
|
constructor(base, ignorevoid = true) {
|
|
12
30
|
this.base = base;
|
|
@@ -19,45 +37,59 @@ class SchemaGenerator {
|
|
|
19
37
|
const loadedCmd = await cmd.load(); // commands are loaded async in oclif/core
|
|
20
38
|
this.classToId[loadedCmd.name] = loadedCmd.id;
|
|
21
39
|
}
|
|
22
|
-
const
|
|
40
|
+
const cmdSchemas = {};
|
|
23
41
|
for (const file of this.getAllCmdFiles()) {
|
|
24
|
-
const { returnType, commandId } = this.
|
|
42
|
+
const { returnType, commandId } = this.parseCmdFile(file);
|
|
25
43
|
if (this.ignorevoid && returnType === 'void')
|
|
26
44
|
continue;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
schemas[commandId] = schema;
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
if (error.message.toLowerCase().includes('no root type')) {
|
|
38
|
-
throw new Error(`Schema generator could not find the ${chalk_1.red(returnType)} type. Please make sure that ${chalk_1.red(returnType)} is exported.`);
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
45
|
+
cmdSchemas[commandId] = this.generateSchema(returnType, file);
|
|
46
|
+
}
|
|
47
|
+
const hookSchemas = {};
|
|
48
|
+
for (const file of this.getAllHookFiles()) {
|
|
49
|
+
const { returnType, hookId } = this.parseHookFile(file);
|
|
50
|
+
if (returnType && hookId) {
|
|
51
|
+
hookSchemas[hookId] = this.generateSchema(returnType, file);
|
|
43
52
|
}
|
|
44
53
|
}
|
|
45
|
-
return
|
|
54
|
+
return { commands: cmdSchemas, hooks: hookSchemas };
|
|
46
55
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
generateSchema(returnType, file) {
|
|
57
|
+
try {
|
|
58
|
+
const config = {
|
|
59
|
+
path: file,
|
|
60
|
+
type: returnType,
|
|
61
|
+
skipTypeCheck: true,
|
|
62
|
+
};
|
|
63
|
+
return (0, ts_json_schema_generator_1.createGenerator)(config).createSchema(config.type);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error.message.toLowerCase().includes('no root type')) {
|
|
67
|
+
throw new Error(`Schema generator could not find the ${(0, chalk_1.red)(returnType)} type. Please make sure that ${(0, chalk_1.red)(returnType)} is exported.`);
|
|
53
68
|
}
|
|
54
|
-
else
|
|
55
|
-
|
|
69
|
+
else {
|
|
70
|
+
throw error;
|
|
56
71
|
}
|
|
57
|
-
}
|
|
58
|
-
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
getAllCmdFiles() {
|
|
75
|
+
const { rootDir } = this.getDirs();
|
|
76
|
+
return getAllFiles(path.join(rootDir, 'commands'), '.ts');
|
|
77
|
+
}
|
|
78
|
+
getAllHookFiles() {
|
|
79
|
+
var _a, _b;
|
|
80
|
+
const hookFiles = Object.values((_b = (_a = this.base.config.pjson.oclif) === null || _a === void 0 ? void 0 : _a.hooks) !== null && _b !== void 0 ? _b : {}).reduce((x, y) => {
|
|
81
|
+
return Array.isArray(y) ? x.concat(y) : x.concat([y]);
|
|
82
|
+
}, []);
|
|
83
|
+
const { rootDir, outDir } = this.getDirs();
|
|
84
|
+
return hookFiles.map(h => `${path.resolve(h)}.ts`.replace(outDir, rootDir));
|
|
59
85
|
}
|
|
60
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Use regex to find the typescript type being returned by the command's
|
|
88
|
+
* `run` method.
|
|
89
|
+
* @param file the file to parse
|
|
90
|
+
* @returns Returns the name of the return type and the command id.
|
|
91
|
+
*/
|
|
92
|
+
parseCmdFile(file) {
|
|
61
93
|
const returnTypeRegex = /(?<=async\srun\(\):\sPromise<)(.*?)(>*)(?=>)/g;
|
|
62
94
|
const contents = fs.readFileSync(file, 'utf8');
|
|
63
95
|
const [returnType] = returnTypeRegex.exec(contents) || [];
|
|
@@ -71,6 +103,32 @@ class SchemaGenerator {
|
|
|
71
103
|
this.validateReturnType(returnType, commandId);
|
|
72
104
|
return { returnType, commandId };
|
|
73
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Use regex to find the typescript type being returned by the hook
|
|
108
|
+
* @param file the file to parse
|
|
109
|
+
* @returns Returns the name of the return type and the hook id.
|
|
110
|
+
*/
|
|
111
|
+
parseHookFile(file) {
|
|
112
|
+
var _a, _b;
|
|
113
|
+
const returnTypeRegex = /(?<=const\shook:\s(.*?)<)[^'](.*?)[^'](>*)(?=>)/g;
|
|
114
|
+
const contents = fs.readFileSync(file, 'utf8');
|
|
115
|
+
const [returnType] = returnTypeRegex.exec(contents) || [];
|
|
116
|
+
if (!returnType || returnType === 'void') {
|
|
117
|
+
return { returnType: null, hookId: null };
|
|
118
|
+
}
|
|
119
|
+
const hooks = (_b = (_a = this.base.config.pjson.oclif) === null || _a === void 0 ? void 0 : _a.hooks) !== null && _b !== void 0 ? _b : {};
|
|
120
|
+
const hookId = Object.keys(hooks).find(key => {
|
|
121
|
+
const hookFiles = (Array.isArray(hooks[key]) ? hooks[key] : [hooks[key]]);
|
|
122
|
+
const hookFileNames = hookFiles.map(f => path.basename(f).split('.')[0]);
|
|
123
|
+
const currentFileName = path.basename(file).split('.')[0];
|
|
124
|
+
return hookFileNames.includes(currentFileName);
|
|
125
|
+
});
|
|
126
|
+
if (!hookId) {
|
|
127
|
+
return { returnType: null, hookId: null };
|
|
128
|
+
}
|
|
129
|
+
this.validateReturnType(returnType, hookId);
|
|
130
|
+
return { returnType, hookId };
|
|
131
|
+
}
|
|
74
132
|
validateReturnType(returnType, commandId) {
|
|
75
133
|
const notAllowed = this.ignorevoid ? ['any', 'unknown'] : ['any', 'unknown', 'void'];
|
|
76
134
|
const vaugeTypes = ['JsonMap', 'JsonCollection', 'AnyJson'];
|
|
@@ -89,6 +147,24 @@ class SchemaGenerator {
|
|
|
89
147
|
}
|
|
90
148
|
}
|
|
91
149
|
}
|
|
150
|
+
getDirs() {
|
|
151
|
+
const dirs = {
|
|
152
|
+
rootDir: path.join(this.base.config.root, 'src'),
|
|
153
|
+
outDir: path.join(this.base.config.root, 'lib'),
|
|
154
|
+
};
|
|
155
|
+
try {
|
|
156
|
+
const tsConfig = JSON.parse(fs.readFileSync(path.join(this.base.config.root, 'tsconfig.json'), 'utf-8'));
|
|
157
|
+
if (tsConfig.compilerOptions.rootDir) {
|
|
158
|
+
dirs.rootDir = path.join(this.base.config.root, tsConfig.compilerOptions.rootDir);
|
|
159
|
+
}
|
|
160
|
+
if (tsConfig.compilerOptions.outDir) {
|
|
161
|
+
dirs.outDir = path.join(this.base.config.root, tsConfig.compilerOptions.outDir);
|
|
162
|
+
}
|
|
163
|
+
return dirs;
|
|
164
|
+
}
|
|
165
|
+
catch (_a) { }
|
|
166
|
+
return dirs;
|
|
167
|
+
}
|
|
92
168
|
}
|
|
93
169
|
exports.SchemaGenerator = SchemaGenerator;
|
|
94
170
|
class SchemaGenerate extends snapshot_command_1.SnapshotCommand {
|
|
@@ -106,13 +182,24 @@ class SchemaGenerate extends snapshot_command_1.SnapshotCommand {
|
|
|
106
182
|
files.push(filePath);
|
|
107
183
|
}
|
|
108
184
|
else {
|
|
109
|
-
for (const [cmdId, schema] of Object.entries(schemas)) {
|
|
185
|
+
for (const [cmdId, schema] of Object.entries(schemas.commands)) {
|
|
110
186
|
const fileName = `${cmdId.replace(/:/g, '-')}.json`;
|
|
111
187
|
const filePath = path.join(directory, fileName);
|
|
112
188
|
fs.writeFileSync(filePath, JSON.stringify(schema, null, 2));
|
|
113
189
|
this.log(`Generated JSON schema file "${filePath}"`);
|
|
114
190
|
files.push(filePath);
|
|
115
191
|
}
|
|
192
|
+
if (Object.values(schemas.hooks).length > 0) {
|
|
193
|
+
const hooksDir = path.join(directory, 'hooks');
|
|
194
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
195
|
+
for (const [hookId, schema] of Object.entries(schemas.hooks)) {
|
|
196
|
+
const fileName = `${hookId.replace(/:/g, '-')}.json`;
|
|
197
|
+
const filePath = path.join(hooksDir, fileName);
|
|
198
|
+
fs.writeFileSync(filePath, JSON.stringify(schema, null, 2));
|
|
199
|
+
this.log(`Generated JSON schema file "${filePath}"`);
|
|
200
|
+
files.push(filePath);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
116
203
|
}
|
|
117
204
|
return files;
|
|
118
205
|
}
|
|
@@ -7,6 +7,7 @@ interface Change {
|
|
|
7
7
|
declare type CommandChange = {
|
|
8
8
|
plugin: string;
|
|
9
9
|
flags: Change[];
|
|
10
|
+
alias: Change[];
|
|
10
11
|
} & Change;
|
|
11
12
|
export declare type CompareResponse = {
|
|
12
13
|
addedCommands?: string[];
|
|
@@ -26,18 +27,30 @@ export default class Compare extends SnapshotCommand {
|
|
|
26
27
|
*/
|
|
27
28
|
compareSnapshot(initialCommands: SnapshotEntry[], updatedCommands: CommandChange[]): Promise<CompareResponse>;
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
* @deprecated in favor of diffCommandProperty
|
|
31
|
+
* Compares a flag snapshot with the current command's flags
|
|
32
|
+
* @param {string[]} initialFlags Flag list from the snapshot
|
|
33
|
+
* @param {string[]} updatedFlags Flag list from runtime
|
|
34
|
+
* @return {boolean} true if no changes, false otherwise
|
|
35
|
+
*/
|
|
35
36
|
diffCommandFlags(initialFlags: string[], updatedFlags: Change[]): {
|
|
36
37
|
addedFlags: string[];
|
|
37
38
|
removedFlags: string[];
|
|
38
39
|
updatedFlags: Change[];
|
|
39
40
|
changedFlags: Change[];
|
|
40
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* compares two command's properties to each other
|
|
44
|
+
* @return a list of added, removed, updated, and changed properties
|
|
45
|
+
* @param initial initial command property to compare against
|
|
46
|
+
* @param updated generated command property to compare with
|
|
47
|
+
*/
|
|
48
|
+
diffCommandProperty(initial: string[], updated: Change[]): {
|
|
49
|
+
addedProperty: string[];
|
|
50
|
+
removedProperty: string[];
|
|
51
|
+
updated: Change[];
|
|
52
|
+
changedProperty: Change[];
|
|
53
|
+
};
|
|
41
54
|
get changed(): CommandChange[];
|
|
42
55
|
run(): Promise<CompareResponse>;
|
|
43
56
|
}
|
|
@@ -23,8 +23,17 @@ class Compare extends snapshot_command_1.SnapshotCommand {
|
|
|
23
23
|
return initialCommand.command === updatedCommand.name && samePlugin;
|
|
24
24
|
});
|
|
25
25
|
if (updatedCommand) {
|
|
26
|
-
const
|
|
27
|
-
|
|
26
|
+
const changedFlags = this.diffCommandProperty(initialCommand.flags, updatedCommand.flags).changedProperty;
|
|
27
|
+
const changedAlias = this.diffCommandProperty(initialCommand.alias, updatedCommand.alias).changedProperty;
|
|
28
|
+
const flagsChanged = changedFlags.length > 0;
|
|
29
|
+
const aliasChanged = changedAlias.length > 0;
|
|
30
|
+
if (aliasChanged) {
|
|
31
|
+
updatedCommand.alias = changedAlias;
|
|
32
|
+
}
|
|
33
|
+
if (flagsChanged) {
|
|
34
|
+
updatedCommand.flags = changedFlags;
|
|
35
|
+
}
|
|
36
|
+
if (flagsChanged || aliasChanged) {
|
|
28
37
|
diffCommands.push(updatedCommand);
|
|
29
38
|
}
|
|
30
39
|
}
|
|
@@ -48,52 +57,66 @@ class Compare extends snapshot_command_1.SnapshotCommand {
|
|
|
48
57
|
addedCommands.forEach(command => {
|
|
49
58
|
this.log(chalk.green(`\t+${command}`));
|
|
50
59
|
});
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
const removedProperties = [];
|
|
61
|
+
diffCommands.forEach(command => {
|
|
62
|
+
this.log(`\t${command.name}`);
|
|
63
|
+
const printCommandDiff = (properties, propertyName) => {
|
|
64
|
+
if (properties.find(prop => prop.added || prop.removed))
|
|
65
|
+
this.log(`\t ${propertyName}:`);
|
|
66
|
+
properties.forEach(prop => {
|
|
67
|
+
if (prop.added || prop.removed) {
|
|
68
|
+
const color = prop.added ? chalk.green : chalk.red;
|
|
69
|
+
this.log(color(`\t\t${prop.added ? '+' : '-'}${prop.name}`));
|
|
59
70
|
}
|
|
60
|
-
if (
|
|
61
|
-
|
|
71
|
+
if (prop.removed)
|
|
72
|
+
removedProperties.push();
|
|
62
73
|
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
};
|
|
75
|
+
printCommandDiff(command.flags, 'Flags');
|
|
76
|
+
printCommandDiff(command.alias, 'Aliases');
|
|
77
|
+
});
|
|
78
|
+
this.log(`${os_1.EOL}Command, flag, or alias differences detected. If intended, please update the snapshot file and run again.`);
|
|
79
|
+
// Check if existent commands, or properties (flags, aliases) have been deleted
|
|
80
|
+
if (removedCommands.length > 0 || removedProperties.length > 0) {
|
|
68
81
|
this.log(chalk.red(`${os_1.EOL}Since there are deletions, a major version bump is required.`));
|
|
69
82
|
}
|
|
70
|
-
return { addedCommands, removedCommands, removedFlags, diffCommands };
|
|
83
|
+
return { addedCommands, removedCommands, removedFlags: removedCommands, diffCommands };
|
|
71
84
|
}
|
|
72
85
|
/**
|
|
73
|
-
*
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
86
|
+
* @deprecated in favor of diffCommandProperty
|
|
87
|
+
* Compares a flag snapshot with the current command's flags
|
|
88
|
+
* @param {string[]} initialFlags Flag list from the snapshot
|
|
89
|
+
* @param {string[]} updatedFlags Flag list from runtime
|
|
90
|
+
* @return {boolean} true if no changes, false otherwise
|
|
91
|
+
*/
|
|
79
92
|
diffCommandFlags(initialFlags, updatedFlags) {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
const diffedFlags = this.diffCommandProperty(initialFlags, updatedFlags);
|
|
94
|
+
return { addedFlags: diffedFlags.addedProperty, removedFlags: diffedFlags.removedProperty, updatedFlags: diffedFlags.updated, changedFlags: diffedFlags.changedProperty };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* compares two command's properties to each other
|
|
98
|
+
* @return a list of added, removed, updated, and changed properties
|
|
99
|
+
* @param initial initial command property to compare against
|
|
100
|
+
* @param updated generated command property to compare with
|
|
101
|
+
*/
|
|
102
|
+
diffCommandProperty(initial, updated) {
|
|
103
|
+
const updatedPropertyNames = updated.map(update => update.name);
|
|
104
|
+
const addedProperty = _.difference(updatedPropertyNames, initial);
|
|
105
|
+
const removedProperty = _.difference(initial, updatedPropertyNames);
|
|
106
|
+
const changedProperty = [];
|
|
107
|
+
updated.forEach(update => {
|
|
108
|
+
if (addedProperty.includes(update.name)) {
|
|
109
|
+
update.added = true;
|
|
110
|
+
changedProperty.push(update);
|
|
88
111
|
}
|
|
89
112
|
});
|
|
90
|
-
|
|
91
|
-
|
|
113
|
+
removedProperty.forEach(remove => {
|
|
114
|
+
changedProperty.push({ name: remove, removed: true });
|
|
92
115
|
// The removed flags in not included in the updated flags, but we want it to
|
|
93
116
|
// so it shows removed.
|
|
94
|
-
|
|
117
|
+
updated.push({ name: remove, removed: true });
|
|
95
118
|
});
|
|
96
|
-
return {
|
|
119
|
+
return { addedProperty, removedProperty, updated, changedProperty };
|
|
97
120
|
}
|
|
98
121
|
get changed() {
|
|
99
122
|
return this.commands.map(command => {
|
|
@@ -101,14 +124,15 @@ class Compare extends snapshot_command_1.SnapshotCommand {
|
|
|
101
124
|
name: command.id,
|
|
102
125
|
plugin: command.pluginName || '',
|
|
103
126
|
flags: Object.entries(command.flags).map(flagName => ({ name: flagName[0] })),
|
|
127
|
+
alias: command.aliases.map(alias => ({ name: alias })),
|
|
104
128
|
};
|
|
105
129
|
});
|
|
106
130
|
}
|
|
107
131
|
async run() {
|
|
108
132
|
const { flags } = await this.parse(Compare);
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
return this.compareSnapshot(
|
|
133
|
+
const oldCommands = JSON.parse(fs.readFileSync(flags.filepath).toString('utf8'));
|
|
134
|
+
const newCommands = this.changed;
|
|
135
|
+
return this.compareSnapshot(oldCommands, newCommands);
|
|
112
136
|
}
|
|
113
137
|
}
|
|
114
138
|
exports.default = Compare;
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { SnapshotCommand } from '../../snapshot-command';
|
|
2
|
-
export declare type Snapshots =
|
|
3
|
-
command: string;
|
|
4
|
-
plugin: string;
|
|
5
|
-
flags: string[];
|
|
6
|
-
}[];
|
|
1
|
+
import { SnapshotCommand, SnapshotEntry } from '../../snapshot-command';
|
|
2
|
+
export declare type Snapshots = SnapshotEntry[];
|
|
7
3
|
export default class Generate extends SnapshotCommand {
|
|
8
4
|
static flags: {
|
|
9
5
|
filepath: import("@oclif/core/lib/interfaces").OptionFlag<string>;
|
package/lib/snapshot-command.js
CHANGED
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"3.
|
|
1
|
+
{"version":"3.1.3","commands":{"schema:compare":{"id":"schema:compare","strict":true,"pluginName":"@oclif/plugin-command-snapshot","pluginAlias":"@oclif/plugin-command-snapshot","pluginType":"core","aliases":[],"flags":{"filepath":{"name":"filepath","type":"option","description":"path of the generated snapshot file","multiple":false,"default":"./schemas"}},"args":[]},"schema:generate":{"id":"schema:generate","strict":true,"pluginName":"@oclif/plugin-command-snapshot","pluginAlias":"@oclif/plugin-command-snapshot","pluginType":"core","aliases":[],"flags":{"filepath":{"name":"filepath","type":"option","description":"directory to save the generated schema files; can use \"{version}\" to insert the current CLI/plugin version","multiple":false,"default":"./schemas"},"singlefile":{"name":"singlefile","type":"boolean","description":"put generated schema into a single file","allowNo":false},"ignorevoid":{"name":"ignorevoid","type":"boolean","description":"ignore commands that return void","allowNo":false}},"args":[]},"snapshot:compare":{"id":"snapshot:compare","strict":true,"pluginName":"@oclif/plugin-command-snapshot","pluginAlias":"@oclif/plugin-command-snapshot","pluginType":"core","aliases":[],"flags":{"filepath":{"name":"filepath","type":"option","description":"path of the generated snapshot file","multiple":false,"default":"./command-snapshot.json"}},"args":[]},"snapshot:generate":{"id":"snapshot:generate","strict":true,"pluginName":"@oclif/plugin-command-snapshot","pluginAlias":"@oclif/plugin-command-snapshot","pluginType":"core","aliases":[],"flags":{"filepath":{"name":"filepath","type":"option","description":"path to save the generated snapshot file; can use \"{version}\" to replace the current CLI/plugin version","multiple":false,"default":"./command-snapshot.json"}},"args":[]}}}
|