@oclif/plugin-command-snapshot 3.1.4 → 3.2.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/schema/compare.js +28 -11
- package/lib/commands/schema/generate.d.ts +2 -2
- package/lib/commands/schema/generate.js +13 -16
- package/lib/commands/snapshot/compare.js +24 -24
- package/lib/snapshot-command.d.ts +2 -2
- package/oclif.manifest.json +1 -1
- package/package.json +15 -15
- package/yarn.lock +699 -267
|
@@ -3,12 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const semver = require("semver");
|
|
6
|
-
const
|
|
6
|
+
const lodash_1 = require("lodash");
|
|
7
7
|
const just_diff_1 = require("just-diff");
|
|
8
8
|
const core_1 = require("@oclif/core");
|
|
9
9
|
const snapshot_command_1 = require("../../snapshot-command");
|
|
10
10
|
const generate_1 = require("./generate");
|
|
11
11
|
const chalk_1 = require("chalk");
|
|
12
|
+
function isNumber(n) {
|
|
13
|
+
return Number.isInteger(Number(n));
|
|
14
|
+
}
|
|
15
|
+
function isMeaningless(n) {
|
|
16
|
+
const meaninglessKeys = ['$comment', '__computed'];
|
|
17
|
+
return meaninglessKeys.includes(n);
|
|
18
|
+
}
|
|
12
19
|
class SchemaCompare extends snapshot_command_1.SnapshotCommand {
|
|
13
20
|
async run() {
|
|
14
21
|
const { flags } = await this.parse(SchemaCompare);
|
|
@@ -28,25 +35,34 @@ class SchemaCompare extends snapshot_command_1.SnapshotCommand {
|
|
|
28
35
|
this.log('No changes have been detected.');
|
|
29
36
|
return [];
|
|
30
37
|
}
|
|
31
|
-
const
|
|
38
|
+
const humanReadableChanges = {};
|
|
32
39
|
for (const change of changes) {
|
|
40
|
+
const lastPathElement = change.path[change.path.length - 1];
|
|
41
|
+
if (isMeaningless(lastPathElement))
|
|
42
|
+
continue;
|
|
33
43
|
const objPath = change.path.join('.');
|
|
34
|
-
const existing =
|
|
35
|
-
const latest =
|
|
44
|
+
const existing = (0, lodash_1.get)(existingSchema, objPath);
|
|
45
|
+
const latest = (0, lodash_1.get)(latestSchema, objPath);
|
|
36
46
|
const [commandId] = objPath.split('.definitions');
|
|
37
47
|
const readablePath = objPath.replace(`${commandId}.`, '');
|
|
38
|
-
if (!
|
|
39
|
-
|
|
48
|
+
if (!humanReadableChanges[commandId]) {
|
|
49
|
+
humanReadableChanges[commandId] = [];
|
|
40
50
|
}
|
|
51
|
+
const lastElementIsNum = isNumber(lastPathElement);
|
|
52
|
+
const basePath = lastElementIsNum ? readablePath.replace(`.${lastPathElement}`, '') : readablePath;
|
|
41
53
|
switch (change.op) {
|
|
42
54
|
case 'replace':
|
|
43
|
-
|
|
55
|
+
humanReadableChanges[commandId].push(`${(0, chalk_1.underline)(readablePath)} was changed from ${(0, chalk_1.cyan)(existing)} to ${(0, chalk_1.cyan)(latest)}`);
|
|
44
56
|
break;
|
|
45
57
|
case 'add':
|
|
46
|
-
|
|
58
|
+
humanReadableChanges[commandId].push(lastElementIsNum ?
|
|
59
|
+
`Array item at ${(0, chalk_1.underline)(basePath)} was ${(0, chalk_1.cyan)('added')} to latest schema` :
|
|
60
|
+
`${(0, chalk_1.underline)(readablePath)} was ${(0, chalk_1.cyan)('added')} to latest schema`);
|
|
47
61
|
break;
|
|
48
62
|
case 'remove':
|
|
49
|
-
|
|
63
|
+
humanReadableChanges[commandId].push(lastElementIsNum ?
|
|
64
|
+
`Array item at ${(0, chalk_1.underline)(basePath)} was ${(0, chalk_1.cyan)('not found')} in latest schema` :
|
|
65
|
+
`${(0, chalk_1.underline)(readablePath)} was ${(0, chalk_1.cyan)('not found')} in latest schema`);
|
|
50
66
|
break;
|
|
51
67
|
default:
|
|
52
68
|
break;
|
|
@@ -54,7 +70,7 @@ class SchemaCompare extends snapshot_command_1.SnapshotCommand {
|
|
|
54
70
|
}
|
|
55
71
|
this.log();
|
|
56
72
|
this.log((0, chalk_1.bold)((0, chalk_1.red)('Found the following schema changes:')));
|
|
57
|
-
for (const [commandId, changes] of Object.entries(
|
|
73
|
+
for (const [commandId, changes] of Object.entries(humanReadableChanges)) {
|
|
58
74
|
this.log();
|
|
59
75
|
this.log((0, chalk_1.bold)(commandId));
|
|
60
76
|
for (const change of changes) {
|
|
@@ -62,7 +78,8 @@ class SchemaCompare extends snapshot_command_1.SnapshotCommand {
|
|
|
62
78
|
}
|
|
63
79
|
}
|
|
64
80
|
this.log();
|
|
65
|
-
|
|
81
|
+
const bin = process.platform === 'win32' ? 'bin\\dev.cmd' : 'bin/dev';
|
|
82
|
+
this.log('If intended, please update the schema file(s) and run again:', (0, chalk_1.bold)(`${bin} ${(0, core_1.toConfiguredId)('schema:generate', this.config)}`));
|
|
66
83
|
process.exitCode = 1;
|
|
67
84
|
return changes;
|
|
68
85
|
}
|
|
@@ -11,9 +11,9 @@ export declare type GenerateResponse = string[];
|
|
|
11
11
|
export declare function getAllFiles(dirPath: string, ext: string, allFiles?: string[]): string[];
|
|
12
12
|
export declare class SchemaGenerator {
|
|
13
13
|
private base;
|
|
14
|
-
private
|
|
14
|
+
private ignoreVoid;
|
|
15
15
|
private classToId;
|
|
16
|
-
constructor(base: SnapshotCommand,
|
|
16
|
+
constructor(base: SnapshotCommand, ignoreVoid?: boolean);
|
|
17
17
|
generate(): Promise<Schemas>;
|
|
18
18
|
private generateSchema;
|
|
19
19
|
private getAllCmdFiles;
|
|
@@ -13,7 +13,7 @@ function getAllFiles(dirPath, ext, allFiles = []) {
|
|
|
13
13
|
files = fs.readdirSync(dirPath);
|
|
14
14
|
}
|
|
15
15
|
catch (_a) { }
|
|
16
|
-
|
|
16
|
+
for (const file of files) {
|
|
17
17
|
const fPath = path.join(dirPath, file);
|
|
18
18
|
if (fs.statSync(fPath).isDirectory()) {
|
|
19
19
|
allFiles = getAllFiles(fPath, ext, allFiles);
|
|
@@ -21,14 +21,14 @@ function getAllFiles(dirPath, ext, allFiles = []) {
|
|
|
21
21
|
else if (file.endsWith(ext)) {
|
|
22
22
|
allFiles.push(fPath);
|
|
23
23
|
}
|
|
24
|
-
}
|
|
24
|
+
}
|
|
25
25
|
return allFiles;
|
|
26
26
|
}
|
|
27
27
|
exports.getAllFiles = getAllFiles;
|
|
28
28
|
class SchemaGenerator {
|
|
29
|
-
constructor(base,
|
|
29
|
+
constructor(base, ignoreVoid = true) {
|
|
30
30
|
this.base = base;
|
|
31
|
-
this.
|
|
31
|
+
this.ignoreVoid = ignoreVoid;
|
|
32
32
|
this.classToId = {};
|
|
33
33
|
}
|
|
34
34
|
async generate() {
|
|
@@ -40,7 +40,7 @@ class SchemaGenerator {
|
|
|
40
40
|
const cmdSchemas = {};
|
|
41
41
|
for (const file of this.getAllCmdFiles()) {
|
|
42
42
|
const { returnType, commandId } = this.parseCmdFile(file);
|
|
43
|
-
if (this.
|
|
43
|
+
if (this.ignoreVoid && returnType === 'void')
|
|
44
44
|
continue;
|
|
45
45
|
cmdSchemas[commandId] = this.generateSchema(returnType, file);
|
|
46
46
|
}
|
|
@@ -63,12 +63,8 @@ class SchemaGenerator {
|
|
|
63
63
|
return (0, ts_json_schema_generator_1.createGenerator)(config).createSchema(config.type);
|
|
64
64
|
}
|
|
65
65
|
catch (error) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
66
|
+
const error_ = error.message.toLowerCase().includes('no root type') ? 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.`) : error;
|
|
67
|
+
throw error_;
|
|
72
68
|
}
|
|
73
69
|
}
|
|
74
70
|
getAllCmdFiles() {
|
|
@@ -77,8 +73,9 @@ class SchemaGenerator {
|
|
|
77
73
|
}
|
|
78
74
|
getAllHookFiles() {
|
|
79
75
|
var _a, _b;
|
|
76
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
80
77
|
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
|
|
78
|
+
return Array.isArray(y) ? [...x, ...y] : [...x, y];
|
|
82
79
|
}, []);
|
|
83
80
|
const { rootDir, outDir } = this.getDirs();
|
|
84
81
|
return hookFiles.map(h => `${path.resolve(h)}.ts`.replace(outDir, rootDir));
|
|
@@ -130,13 +127,13 @@ class SchemaGenerator {
|
|
|
130
127
|
return { returnType, hookId };
|
|
131
128
|
}
|
|
132
129
|
validateReturnType(returnType, commandId) {
|
|
133
|
-
const notAllowed = this.
|
|
134
|
-
const
|
|
130
|
+
const notAllowed = this.ignoreVoid ? ['any', 'unknown'] : ['any', 'unknown', 'void'];
|
|
131
|
+
const vagueTypes = ['JsonMap', 'JsonCollection', 'AnyJson'];
|
|
135
132
|
if (notAllowed.includes(returnType)) {
|
|
136
133
|
throw new Error(`${returnType} (from ${commandId}) is not allowed. Please use a more specific type.`);
|
|
137
134
|
}
|
|
138
|
-
else if (
|
|
139
|
-
throw new Error(`${returnType} (from ${commandId}) is too
|
|
135
|
+
else if (vagueTypes.includes(returnType)) {
|
|
136
|
+
throw new Error(`${returnType} (from ${commandId}) is too vague. Please use a more specific type.`);
|
|
140
137
|
}
|
|
141
138
|
}
|
|
142
139
|
determineCommandId(contents) {
|
|
@@ -16,7 +16,7 @@ class Compare extends snapshot_command_1.SnapshotCommand {
|
|
|
16
16
|
async compareSnapshot(initialCommands, updatedCommands) {
|
|
17
17
|
const removedCommands = [];
|
|
18
18
|
const diffCommands = [];
|
|
19
|
-
|
|
19
|
+
for (const initialCommand of initialCommands) {
|
|
20
20
|
const updatedCommand = updatedCommands.find(updatedCommand => {
|
|
21
21
|
// Protect against old snapshot files that don't have the plugin entry filled out.
|
|
22
22
|
const samePlugin = initialCommand.plugin ? initialCommand.plugin === updatedCommand.plugin : true;
|
|
@@ -40,7 +40,7 @@ class Compare extends snapshot_command_1.SnapshotCommand {
|
|
|
40
40
|
else {
|
|
41
41
|
removedCommands.push(initialCommand.command);
|
|
42
42
|
}
|
|
43
|
-
}
|
|
43
|
+
}
|
|
44
44
|
const initialCommandNames = initialCommands.map(initialCommand => initialCommand.command);
|
|
45
45
|
const updatedCommandNames = updatedCommands.map(updatedCommand => updatedCommand.name);
|
|
46
46
|
const addedCommands = _.difference(updatedCommandNames, initialCommandNames);
|
|
@@ -51,30 +51,30 @@ class Compare extends snapshot_command_1.SnapshotCommand {
|
|
|
51
51
|
// Fail the process since there are changes to the snapshot file
|
|
52
52
|
process.exitCode = 1;
|
|
53
53
|
this.log(`The following commands and flags have modified: (${chalk.green('+')} added, ${chalk.red('-')} removed)${os_1.EOL}`);
|
|
54
|
-
|
|
54
|
+
for (const command of removedCommands) {
|
|
55
55
|
this.log(chalk.red(`\t-${command}`));
|
|
56
|
-
}
|
|
57
|
-
|
|
56
|
+
}
|
|
57
|
+
for (const command of addedCommands) {
|
|
58
58
|
this.log(chalk.green(`\t+${command}`));
|
|
59
|
-
}
|
|
59
|
+
}
|
|
60
60
|
const removedProperties = [];
|
|
61
|
-
|
|
61
|
+
const printCommandDiff = (properties, propertyName) => {
|
|
62
|
+
if (properties.some(prop => prop.added || prop.removed))
|
|
63
|
+
this.log(`\t ${propertyName}:`);
|
|
64
|
+
for (const prop of properties) {
|
|
65
|
+
if (prop.added || prop.removed) {
|
|
66
|
+
const color = prop.added ? chalk.green : chalk.red;
|
|
67
|
+
this.log(color(`\t\t${prop.added ? '+' : '-'}${prop.name}`));
|
|
68
|
+
}
|
|
69
|
+
if (prop.removed)
|
|
70
|
+
removedProperties.push();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
for (const command of diffCommands) {
|
|
62
74
|
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}`));
|
|
70
|
-
}
|
|
71
|
-
if (prop.removed)
|
|
72
|
-
removedProperties.push();
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
75
|
printCommandDiff(command.flags, 'Flags');
|
|
76
76
|
printCommandDiff(command.alias, 'Aliases');
|
|
77
|
-
}
|
|
77
|
+
}
|
|
78
78
|
this.log(`${os_1.EOL}Command, flag, or alias differences detected. If intended, please update the snapshot file and run again.`);
|
|
79
79
|
// Check if existent commands, or properties (flags, aliases) have been deleted
|
|
80
80
|
if (removedCommands.length > 0 || removedProperties.length > 0) {
|
|
@@ -104,18 +104,18 @@ class Compare extends snapshot_command_1.SnapshotCommand {
|
|
|
104
104
|
const addedProperty = _.difference(updatedPropertyNames, initial);
|
|
105
105
|
const removedProperty = _.difference(initial, updatedPropertyNames);
|
|
106
106
|
const changedProperty = [];
|
|
107
|
-
|
|
107
|
+
for (const update of updated) {
|
|
108
108
|
if (addedProperty.includes(update.name)) {
|
|
109
109
|
update.added = true;
|
|
110
110
|
changedProperty.push(update);
|
|
111
111
|
}
|
|
112
|
-
}
|
|
113
|
-
|
|
112
|
+
}
|
|
113
|
+
for (const remove of removedProperty) {
|
|
114
114
|
changedProperty.push({ name: remove, removed: true });
|
|
115
115
|
// The removed flags in not included in the updated flags, but we want it to
|
|
116
116
|
// so it shows removed.
|
|
117
117
|
updated.push({ name: remove, removed: true });
|
|
118
|
-
}
|
|
118
|
+
}
|
|
119
119
|
return { addedProperty, removedProperty, updated, changedProperty };
|
|
120
120
|
}
|
|
121
121
|
get changed() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
1
|
+
import { Command, Interfaces } from '@oclif/core';
|
|
2
2
|
export declare type SnapshotEntry = {
|
|
3
3
|
command: string;
|
|
4
4
|
plugin: string;
|
|
@@ -6,6 +6,6 @@ export declare type SnapshotEntry = {
|
|
|
6
6
|
alias: string[];
|
|
7
7
|
};
|
|
8
8
|
export declare abstract class SnapshotCommand extends Command {
|
|
9
|
-
get commands():
|
|
9
|
+
get commands(): Interfaces.Command.Loadable[];
|
|
10
10
|
get entries(): SnapshotEntry[];
|
|
11
11
|
}
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"3.1
|
|
1
|
+
{"version":"3.2.1","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":[]}}}
|
package/package.json
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oclif/plugin-command-snapshot",
|
|
3
3
|
"description": "generates and compares OCLIF plugins snapshot files",
|
|
4
|
-
"version": "3.1
|
|
4
|
+
"version": "3.2.1",
|
|
5
5
|
"author": "Salesforce",
|
|
6
6
|
"bugs": "https://github.com/oclif/plugin-command-snapshot/issues",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@oclif/core": "^1.16.4",
|
|
9
9
|
"chalk": "^4.1.2",
|
|
10
|
-
"just-diff": "^
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"ts-json-schema-generator": "^
|
|
14
|
-
"tslib": "^2"
|
|
10
|
+
"just-diff": "^5.1.1",
|
|
11
|
+
"lodash": "^4.17.21",
|
|
12
|
+
"semver": "^7.3.7",
|
|
13
|
+
"ts-json-schema-generator": "^1.1.2",
|
|
14
|
+
"tslib": "^2.4.0"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@commitlint/config-conventional": "^12.1.4",
|
|
18
18
|
"@oclif/plugin-help": "^5.1.12",
|
|
19
|
-
"@oclif/test": "^2.1
|
|
20
|
-
"@types/chai": "^4",
|
|
19
|
+
"@oclif/test": "^2.2.1",
|
|
20
|
+
"@types/chai": "^4.3.3",
|
|
21
21
|
"@types/mocha": "^8",
|
|
22
22
|
"@types/node": "^15",
|
|
23
|
-
"@types/semver": "^7.3.
|
|
23
|
+
"@types/semver": "^7.3.12",
|
|
24
24
|
"chai": "^4",
|
|
25
25
|
"commitlint": "^12.1.4",
|
|
26
|
-
"eslint": "^7",
|
|
27
|
-
"eslint-config-oclif": "^
|
|
28
|
-
"eslint-config-oclif-typescript": "^0.2",
|
|
29
|
-
"globby": "^11",
|
|
26
|
+
"eslint": "^7.32.0",
|
|
27
|
+
"eslint-config-oclif": "^4",
|
|
28
|
+
"eslint-config-oclif-typescript": "^1.0.2",
|
|
30
29
|
"husky": "6",
|
|
31
30
|
"mocha": "^8",
|
|
32
31
|
"nyc": "^15",
|
|
33
32
|
"oclif": "^2.6.3",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
33
|
+
"sinon": "^11.1.2",
|
|
34
|
+
"ts-node": "^10",
|
|
35
|
+
"typescript": "^4.8.4"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
38
|
"node": ">=12.0.0"
|