@contentstack/cli-audit 1.2.0 → 1.3.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/README.md +61 -35
- package/lib/audit-base-command.d.ts +2 -2
- package/lib/audit-base-command.js +11 -10
- package/lib/base-command.js +4 -1
- package/lib/commands/cm/stacks/audit/fix.js +7 -3
- package/lib/commands/cm/stacks/audit/index.js +2 -4
- package/lib/config/index.d.ts +1 -0
- package/lib/config/index.js +1 -0
- package/lib/messages/index.d.ts +10 -2
- package/lib/messages/index.js +11 -2
- package/lib/modules/content-types.d.ts +1 -0
- package/lib/modules/content-types.js +59 -9
- package/lib/modules/entries.d.ts +12 -3
- package/lib/modules/entries.js +47 -32
- package/lib/modules/global-fields.d.ts +1 -1
- package/lib/modules/global-fields.js +2 -2
- package/lib/types/common.d.ts +5 -0
- package/lib/types/common.js +2 -0
- package/lib/types/content-types.d.ts +1 -1
- package/lib/types/index.d.ts +2 -1
- package/lib/types/index.js +1 -0
- package/lib/util/flags.d.ts +10 -0
- package/lib/util/flags.js +26 -0
- package/lib/util/index.d.ts +2 -1
- package/lib/util/index.js +5 -5
- package/lib/util/log.js +12 -21
- package/oclif.manifest.json +40 -11
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ $ npm install -g @contentstack/cli-audit
|
|
|
19
19
|
$ csdx COMMAND
|
|
20
20
|
running command...
|
|
21
21
|
$ csdx (--version|-v)
|
|
22
|
-
@contentstack/cli-audit/1.
|
|
22
|
+
@contentstack/cli-audit/1.3.0 linux-x64 node-v18.18.2
|
|
23
23
|
$ csdx --help [COMMAND]
|
|
24
24
|
USAGE
|
|
25
25
|
$ csdx COMMAND
|
|
@@ -56,16 +56,20 @@ USAGE
|
|
|
56
56
|
--no-truncate]
|
|
57
57
|
|
|
58
58
|
FLAGS
|
|
59
|
+
--modules=<option>... Provide the list of modules to be audited
|
|
60
|
+
<options: content-types|global-fields|entries>
|
|
61
|
+
--report-path=<value> Path to store the audit reports
|
|
62
|
+
|
|
63
|
+
COMMON FLAGS
|
|
59
64
|
-c, --config=<value> Path of the external config
|
|
60
65
|
-d, --data-dir=<value> Path where the data is stored
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
--
|
|
64
|
-
--
|
|
65
|
-
|
|
66
|
-
--no-truncate
|
|
67
|
-
--
|
|
68
|
-
--sort=<value> property to sort by (prepend '-' for descending)
|
|
66
|
+
|
|
67
|
+
TABLE FLAGS
|
|
68
|
+
--columns=<value> Show only the specified columns (comma-separated)
|
|
69
|
+
--csv The output is in the CSV format [alias: --output=csv]
|
|
70
|
+
--filter=<value> Filter property by partial string matching. For example: name=foo
|
|
71
|
+
--no-truncate The output is not truncated to fit the screen
|
|
72
|
+
--sort=<value> Property to sort by (prepend '-' for descending)
|
|
69
73
|
|
|
70
74
|
DESCRIPTION
|
|
71
75
|
Perform audits and find possible errors in the exported Contentstack data
|
|
@@ -93,22 +97,29 @@ Perform audits and fix possible errors in the exported Contentstack data.
|
|
|
93
97
|
```
|
|
94
98
|
USAGE
|
|
95
99
|
$ csdx audit:fix [-c <value>] [-d <value>] [--report-path <value>] [--modules
|
|
96
|
-
content-types|global-fields|entries] [--copy-path <value> --copy-dir] [--
|
|
97
|
-
[--
|
|
100
|
+
content-types|global-fields|entries] [--copy-path <value> --copy-dir] [--fix-only
|
|
101
|
+
reference|global_field|json:rte|json:custom-field|blocks|group] [--columns <value> | ] [--sort <value>] [--filter
|
|
102
|
+
<value>] [--csv | --no-truncate]
|
|
98
103
|
|
|
99
104
|
FLAGS
|
|
100
|
-
-c, --config=<value> Path of the external config
|
|
101
|
-
-d, --data-dir=<value> Path where the data is stored
|
|
102
|
-
--columns=<value> only show provided columns (comma-separated)
|
|
103
105
|
--copy-dir Create backup from the original data.
|
|
104
106
|
--copy-path=<value> Provide the path to backup the copied data
|
|
105
|
-
--
|
|
106
|
-
|
|
107
|
+
--fix-only=<option>... Provide the list of fix options
|
|
108
|
+
<options: reference|global_field|json:rte|json:custom-field|blocks|group>
|
|
107
109
|
--modules=<option>... Provide the list of modules to be audited
|
|
108
110
|
<options: content-types|global-fields|entries>
|
|
109
|
-
--no-truncate do not truncate output to fit screen
|
|
110
111
|
--report-path=<value> Path to store the audit reports
|
|
111
|
-
|
|
112
|
+
|
|
113
|
+
COMMON FLAGS
|
|
114
|
+
-c, --config=<value> Path of the external config
|
|
115
|
+
-d, --data-dir=<value> Path where the data is stored
|
|
116
|
+
|
|
117
|
+
TABLE FLAGS
|
|
118
|
+
--columns=<value> Show only the specified columns (comma-separated)
|
|
119
|
+
--csv The output is in the CSV format [alias: --output=csv]
|
|
120
|
+
--filter=<value> Filter property by partial string matching. For example: name=foo
|
|
121
|
+
--no-truncate The output is not truncated to fit the screen
|
|
122
|
+
--sort=<value> Property to sort by (prepend '-' for descending)
|
|
112
123
|
|
|
113
124
|
DESCRIPTION
|
|
114
125
|
Perform audits and fix possible errors in the exported Contentstack data.
|
|
@@ -124,6 +135,8 @@ EXAMPLES
|
|
|
124
135
|
|
|
125
136
|
$ csdx audit:fix --report-path=<path> --copy-dir --csv
|
|
126
137
|
|
|
138
|
+
$ csdx audit:fix --fix-only=reference,global_field --copy-dir
|
|
139
|
+
|
|
127
140
|
$ csdx audit:fix --report-path=<path> --filter="name=<filter-value>"
|
|
128
141
|
|
|
129
142
|
$ csdx audit:fix --report-path=<path> --modules=content-types --filter="name="<filter-value>" --copy-dir --copy-path=<path>
|
|
@@ -140,16 +153,20 @@ USAGE
|
|
|
140
153
|
--no-truncate]
|
|
141
154
|
|
|
142
155
|
FLAGS
|
|
156
|
+
--modules=<option>... Provide the list of modules to be audited
|
|
157
|
+
<options: content-types|global-fields|entries>
|
|
158
|
+
--report-path=<value> Path to store the audit reports
|
|
159
|
+
|
|
160
|
+
COMMON FLAGS
|
|
143
161
|
-c, --config=<value> Path of the external config
|
|
144
162
|
-d, --data-dir=<value> Path where the data is stored
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
--
|
|
148
|
-
--
|
|
149
|
-
|
|
150
|
-
--no-truncate
|
|
151
|
-
--
|
|
152
|
-
--sort=<value> property to sort by (prepend '-' for descending)
|
|
163
|
+
|
|
164
|
+
TABLE FLAGS
|
|
165
|
+
--columns=<value> Show only the specified columns (comma-separated)
|
|
166
|
+
--csv The output is in the CSV format [alias: --output=csv]
|
|
167
|
+
--filter=<value> Filter property by partial string matching. For example: name=foo
|
|
168
|
+
--no-truncate The output is not truncated to fit the screen
|
|
169
|
+
--sort=<value> Property to sort by (prepend '-' for descending)
|
|
153
170
|
|
|
154
171
|
DESCRIPTION
|
|
155
172
|
Perform audits and find possible errors in the exported Contentstack data
|
|
@@ -179,22 +196,29 @@ Perform audits and fix possible errors in the exported Contentstack data.
|
|
|
179
196
|
```
|
|
180
197
|
USAGE
|
|
181
198
|
$ csdx cm:stacks:audit:fix [-c <value>] [-d <value>] [--report-path <value>] [--modules
|
|
182
|
-
content-types|global-fields|entries] [--copy-path <value> --copy-dir] [--
|
|
183
|
-
[--
|
|
199
|
+
content-types|global-fields|entries] [--copy-path <value> --copy-dir] [--fix-only
|
|
200
|
+
reference|global_field|json:rte|json:custom-field|blocks|group] [--columns <value> | ] [--sort <value>] [--filter
|
|
201
|
+
<value>] [--csv | --no-truncate]
|
|
184
202
|
|
|
185
203
|
FLAGS
|
|
186
|
-
-c, --config=<value> Path of the external config
|
|
187
|
-
-d, --data-dir=<value> Path where the data is stored
|
|
188
|
-
--columns=<value> only show provided columns (comma-separated)
|
|
189
204
|
--copy-dir Create backup from the original data.
|
|
190
205
|
--copy-path=<value> Provide the path to backup the copied data
|
|
191
|
-
--
|
|
192
|
-
|
|
206
|
+
--fix-only=<option>... Provide the list of fix options
|
|
207
|
+
<options: reference|global_field|json:rte|json:custom-field|blocks|group>
|
|
193
208
|
--modules=<option>... Provide the list of modules to be audited
|
|
194
209
|
<options: content-types|global-fields|entries>
|
|
195
|
-
--no-truncate do not truncate output to fit screen
|
|
196
210
|
--report-path=<value> Path to store the audit reports
|
|
197
|
-
|
|
211
|
+
|
|
212
|
+
COMMON FLAGS
|
|
213
|
+
-c, --config=<value> Path of the external config
|
|
214
|
+
-d, --data-dir=<value> Path where the data is stored
|
|
215
|
+
|
|
216
|
+
TABLE FLAGS
|
|
217
|
+
--columns=<value> Show only the specified columns (comma-separated)
|
|
218
|
+
--csv The output is in the CSV format [alias: --output=csv]
|
|
219
|
+
--filter=<value> Filter property by partial string matching. For example: name=foo
|
|
220
|
+
--no-truncate The output is not truncated to fit the screen
|
|
221
|
+
--sort=<value> Property to sort by (prepend '-' for descending)
|
|
198
222
|
|
|
199
223
|
DESCRIPTION
|
|
200
224
|
Perform audits and fix possible errors in the exported Contentstack data.
|
|
@@ -210,6 +234,8 @@ EXAMPLES
|
|
|
210
234
|
|
|
211
235
|
$ csdx cm:stacks:audit:fix --report-path=<path> --copy-dir --csv
|
|
212
236
|
|
|
237
|
+
$ csdx cm:stacks:audit:fix --fix-only=reference,global_field --copy-dir
|
|
238
|
+
|
|
213
239
|
$ csdx cm:stacks:audit:fix --report-path=<path> --filter="name=<filter-value>"
|
|
214
240
|
|
|
215
241
|
$ csdx cm:stacks:audit:fix --report-path=<path> --modules=content-types --filter="name="<filter-value>" --copy-dir --copy-path=<path>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import config from './config';
|
|
2
2
|
import { BaseCommand } from './base-command';
|
|
3
|
-
import { ContentTypeStruct } from './types';
|
|
3
|
+
import { CommandNames, ContentTypeStruct } from './types';
|
|
4
4
|
export declare abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseCommand> {
|
|
5
5
|
private currentCommand;
|
|
6
6
|
get fixStatus(): {
|
|
@@ -16,7 +16,7 @@ export declare abstract class AuditBaseCommand extends BaseCommand<typeof AuditB
|
|
|
16
16
|
* @param {string} command - The `command` parameter is a string that represents the current command
|
|
17
17
|
* being executed.
|
|
18
18
|
*/
|
|
19
|
-
start(command:
|
|
19
|
+
start(command: CommandNames): Promise<void>;
|
|
20
20
|
/**
|
|
21
21
|
* The `scan` function performs an audit on different modules (content-types, global-fields, and
|
|
22
22
|
* entries) and returns the missing references for each module.
|
|
@@ -56,6 +56,10 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
|
|
|
56
56
|
else {
|
|
57
57
|
this.log(this.messages.NO_MISSING_REF_FOUND, 'info');
|
|
58
58
|
this.log('');
|
|
59
|
+
if (this.currentCommand === 'cm:stacks:audit:fix' && (0, fs_1.existsSync)(this.sharedConfig.basePath)) {
|
|
60
|
+
// NOTE Clean up the backup dir if no issue found while audit the content
|
|
61
|
+
(0, fs_1.rmSync)(this.sharedConfig.basePath, { recursive: true });
|
|
62
|
+
}
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
/**
|
|
@@ -147,8 +151,8 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
|
|
|
147
151
|
this.log(this.$t(messages_1.auditMsg.NOT_VALID_PATH, { path: ctPath }), 'error');
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
|
-
|
|
151
|
-
|
|
154
|
+
const gfSchema = (0, fs_1.existsSync)(gfPath) ? JSON.parse((0, fs_1.readFileSync)(gfPath, 'utf8')) : [];
|
|
155
|
+
const ctSchema = (0, fs_1.existsSync)(ctPath) ? JSON.parse((0, fs_1.readFileSync)(ctPath, 'utf8')) : [];
|
|
152
156
|
return { ctSchema, gfSchema };
|
|
153
157
|
}
|
|
154
158
|
/**
|
|
@@ -227,14 +231,10 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
|
|
|
227
231
|
* @returns The function `prepareCSV` returns a Promise that resolves to `void`.
|
|
228
232
|
*/
|
|
229
233
|
prepareCSV(moduleName, listOfMissingRefs) {
|
|
230
|
-
const csvStream = csv.format({ headers: true });
|
|
231
234
|
const csvPath = (0, path_1.join)(this.sharedConfig.reportPath, `${moduleName}.csv`);
|
|
232
|
-
const assetFileStream = (0, fs_1.createWriteStream)(csvPath);
|
|
233
|
-
assetFileStream.on('error', (error) => {
|
|
234
|
-
throw error;
|
|
235
|
-
});
|
|
236
235
|
return new Promise((resolve, reject) => {
|
|
237
|
-
|
|
236
|
+
// file deepcode ignore MissingClose: Will auto close once csv stream end
|
|
237
|
+
const ws = (0, fs_1.createWriteStream)(csvPath).on('error', reject);
|
|
238
238
|
const defaultColumns = Object.keys(types_1.OutputColumn);
|
|
239
239
|
const userDefinedColumns = this.sharedConfig.flags.columns ? this.sharedConfig.flags.columns.split(',') : null;
|
|
240
240
|
let missingRefs = Object.values(listOfMissingRefs).flat();
|
|
@@ -245,6 +245,7 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
|
|
|
245
245
|
const [column, value] = this.sharedConfig.flags.filter.split('=');
|
|
246
246
|
missingRefs = missingRefs.filter((row) => row[types_1.OutputColumn[column]] === value);
|
|
247
247
|
}
|
|
248
|
+
const rowData = [];
|
|
248
249
|
for (const issue of missingRefs) {
|
|
249
250
|
let row = {};
|
|
250
251
|
for (const column of columns) {
|
|
@@ -254,9 +255,9 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
|
|
|
254
255
|
if (this.currentCommand === 'cm:stacks:audit:fix') {
|
|
255
256
|
row['Fix status'] = row.fixStatus;
|
|
256
257
|
}
|
|
257
|
-
|
|
258
|
+
rowData.push(row);
|
|
258
259
|
}
|
|
259
|
-
|
|
260
|
+
csv.write(rowData, { headers: true }).pipe(ws).on('error', reject).on('finish', resolve);
|
|
260
261
|
});
|
|
261
262
|
}
|
|
262
263
|
}
|
package/lib/base-command.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BaseCommand = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const merge_1 = tslib_1.__importDefault(require("lodash/merge"));
|
|
5
6
|
const fs_1 = require("fs");
|
|
6
7
|
const cli_command_1 = require("@contentstack/cli-command");
|
|
7
8
|
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
@@ -66,7 +67,7 @@ class BaseCommand extends cli_command_1.Command {
|
|
|
66
67
|
registerConfig() {
|
|
67
68
|
if (this.flags.config && (0, fs_1.existsSync)(this.flags.config)) {
|
|
68
69
|
try {
|
|
69
|
-
this.sharedConfig = JSON.parse((0, fs_1.readFileSync)(this.flags.config, { encoding: 'utf-8' }));
|
|
70
|
+
this.sharedConfig = (0, merge_1.default)(this.sharedConfig, JSON.parse((0, fs_1.readFileSync)(this.flags.config, { encoding: 'utf-8' })));
|
|
70
71
|
}
|
|
71
72
|
catch (error) {
|
|
72
73
|
this.log(error, 'error');
|
|
@@ -79,10 +80,12 @@ exports.BaseCommand = BaseCommand;
|
|
|
79
80
|
BaseCommand.baseFlags = {
|
|
80
81
|
config: cli_utilities_1.Flags.string({
|
|
81
82
|
char: 'c',
|
|
83
|
+
helpGroup: 'COMMON',
|
|
82
84
|
description: messages_1.commonMsg.CONFIG,
|
|
83
85
|
}),
|
|
84
86
|
'data-dir': cli_utilities_1.Flags.string({
|
|
85
87
|
char: 'd',
|
|
88
|
+
helpGroup: 'COMMON',
|
|
86
89
|
description: messages_1.commonMsg.DATA_DIR,
|
|
87
90
|
}),
|
|
88
91
|
};
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
5
5
|
const config_1 = tslib_1.__importDefault(require("../../../../config"));
|
|
6
|
+
const util_1 = require("../../../../util");
|
|
6
7
|
const messages_1 = require("../../../../messages");
|
|
7
8
|
const audit_base_command_1 = require("../../../../audit-base-command");
|
|
8
9
|
class AuditFix extends audit_base_command_1.AuditBaseCommand {
|
|
@@ -29,6 +30,7 @@ AuditFix.examples = [
|
|
|
29
30
|
'$ <%= config.bin %> <%= command.id %> --copy-dir',
|
|
30
31
|
'$ <%= config.bin %> <%= command.id %> --report-path=<path> --copy-dir',
|
|
31
32
|
'$ <%= config.bin %> <%= command.id %> --report-path=<path> --copy-dir --csv',
|
|
33
|
+
'$ <%= config.bin %> <%= command.id %> --fix-only=reference,global_field --copy-dir',
|
|
32
34
|
'$ <%= config.bin %> <%= command.id %> --report-path=<path> --filter="name=<filter-value>"',
|
|
33
35
|
'$ <%= config.bin %> <%= command.id %> --report-path=<path> --modules=content-types --filter="name="<filter-value>" --copy-dir --copy-path=<path>',
|
|
34
36
|
];
|
|
@@ -46,10 +48,12 @@ AuditFix.flags = Object.assign({ 'report-path': cli_utilities_1.Flags.string({
|
|
|
46
48
|
}), 'copy-path': cli_utilities_1.Flags.string({
|
|
47
49
|
dependsOn: ['copy-dir'],
|
|
48
50
|
description: messages_1.auditFixMsg.BKP_PATH,
|
|
51
|
+
}), 'fix-only': cli_utilities_1.Flags.string({
|
|
52
|
+
multiple: true,
|
|
53
|
+
options: config_1.default['fix-fields'],
|
|
54
|
+
description: messages_1.auditFixMsg.FIX_OPTIONS,
|
|
49
55
|
}), yes: cli_utilities_1.Flags.boolean({
|
|
50
56
|
char: 'y',
|
|
51
57
|
hidden: true,
|
|
52
58
|
description: 'Use this flag to skip confirmation',
|
|
53
|
-
}) },
|
|
54
|
-
only: ['columns', 'sort', 'filter', 'csv', 'no-truncate'],
|
|
55
|
-
}));
|
|
59
|
+
}) }, (0, util_1.getTableFlags)());
|
|
@@ -5,6 +5,7 @@ const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
|
5
5
|
const config_1 = tslib_1.__importDefault(require("../../../../config"));
|
|
6
6
|
const messages_1 = require("../../../../messages");
|
|
7
7
|
const audit_base_command_1 = require("../../../../audit-base-command");
|
|
8
|
+
const util_1 = require("../../../../util");
|
|
8
9
|
class Audit extends audit_base_command_1.AuditBaseCommand {
|
|
9
10
|
/**
|
|
10
11
|
* The `run` function is an asynchronous function that performs an audit on different modules
|
|
@@ -16,7 +17,6 @@ class Audit extends audit_base_command_1.AuditBaseCommand {
|
|
|
16
17
|
}
|
|
17
18
|
catch (error) {
|
|
18
19
|
this.log(error instanceof Error ? error.message : error, 'error');
|
|
19
|
-
console.trace(error);
|
|
20
20
|
cli_utilities_1.ux.action.stop('Process failed.!');
|
|
21
21
|
this.exit(1);
|
|
22
22
|
}
|
|
@@ -41,6 +41,4 @@ Audit.flags = Object.assign({ 'report-path': cli_utilities_1.Flags.string({
|
|
|
41
41
|
multiple: true,
|
|
42
42
|
options: config_1.default.modules,
|
|
43
43
|
description: messages_1.auditMsg.MODULES,
|
|
44
|
-
}) },
|
|
45
|
-
only: ['columns', 'sort', 'filter', 'csv', 'no-truncate'],
|
|
46
|
-
}));
|
|
44
|
+
}) }, (0, util_1.getTableFlags)());
|
package/lib/config/index.d.ts
CHANGED
package/lib/config/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const config = {
|
|
|
4
4
|
showTerminalOutput: true,
|
|
5
5
|
skipRefs: ['sys_assets'],
|
|
6
6
|
modules: ['content-types', 'global-fields', 'entries'],
|
|
7
|
+
'fix-fields': ['reference', 'global_field', 'json:rte', 'json:custom-field', 'blocks', 'group'],
|
|
7
8
|
moduleConfig: {
|
|
8
9
|
'content-types': {
|
|
9
10
|
name: 'content type',
|
package/lib/messages/index.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
declare const errors: {};
|
|
2
|
+
declare const tableColumnDescriptions: {
|
|
3
|
+
TABLE_COLUMNS: string;
|
|
4
|
+
TABLE_SORT: string;
|
|
5
|
+
TABLE_CSV: string;
|
|
6
|
+
TABLE_FILTER: string;
|
|
7
|
+
'TABLE_NO-TRUNCATE': string;
|
|
8
|
+
};
|
|
2
9
|
declare const commonMsg: {
|
|
3
10
|
CONFIG: string;
|
|
4
11
|
DATA_DIR: string;
|
|
@@ -20,11 +27,12 @@ declare const auditMsg: {
|
|
|
20
27
|
declare const auditFixMsg: {
|
|
21
28
|
COPY_DATA: string;
|
|
22
29
|
BKP_PATH: string;
|
|
30
|
+
FIX_OPTIONS: string;
|
|
23
31
|
FIXED_CONTENT_PATH_MAG: string;
|
|
24
32
|
EMPTY_FIX_MSG: string;
|
|
25
33
|
AUDIT_FIX_CMD_DESCRIPTION: string;
|
|
26
34
|
};
|
|
27
|
-
declare const messages: typeof errors & typeof commonMsg & typeof auditMsg & typeof auditFixMsg;
|
|
35
|
+
declare const messages: typeof errors & typeof commonMsg & typeof auditMsg & typeof auditFixMsg & typeof tableColumnDescriptions;
|
|
28
36
|
/**
|
|
29
37
|
* The function `$t` is a TypeScript function that replaces placeholders in a string with corresponding
|
|
30
38
|
* values from an object.
|
|
@@ -36,4 +44,4 @@ declare const messages: typeof errors & typeof commonMsg & typeof auditMsg & typ
|
|
|
36
44
|
*/
|
|
37
45
|
declare function $t(msg: string, args: Record<string, string>): string;
|
|
38
46
|
export default messages;
|
|
39
|
-
export { $t, errors, commonMsg, auditMsg, auditFixMsg };
|
|
47
|
+
export { $t, errors, commonMsg, auditMsg, auditFixMsg, tableColumnDescriptions };
|
package/lib/messages/index.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.auditFixMsg = exports.auditMsg = exports.commonMsg = exports.errors = exports.$t = void 0;
|
|
3
|
+
exports.tableColumnDescriptions = exports.auditFixMsg = exports.auditMsg = exports.commonMsg = exports.errors = exports.$t = void 0;
|
|
4
4
|
const errors = {};
|
|
5
5
|
exports.errors = errors;
|
|
6
|
+
const tableColumnDescriptions = {
|
|
7
|
+
TABLE_COLUMNS: 'Show only the specified columns (comma-separated)',
|
|
8
|
+
TABLE_SORT: "Property to sort by (prepend '-' for descending)",
|
|
9
|
+
TABLE_CSV: 'The output is in the CSV format [alias: --output=csv]',
|
|
10
|
+
TABLE_FILTER: 'Filter property by partial string matching. For example: name=foo',
|
|
11
|
+
'TABLE_NO-TRUNCATE': 'The output is not truncated to fit the screen',
|
|
12
|
+
};
|
|
13
|
+
exports.tableColumnDescriptions = tableColumnDescriptions;
|
|
6
14
|
const commonMsg = {
|
|
7
15
|
CONFIG: 'Path of the external config',
|
|
8
16
|
DATA_DIR: 'Path where the data is stored',
|
|
@@ -26,12 +34,13 @@ exports.auditMsg = auditMsg;
|
|
|
26
34
|
const auditFixMsg = {
|
|
27
35
|
COPY_DATA: 'Create backup from the original data.',
|
|
28
36
|
BKP_PATH: 'Provide the path to backup the copied data',
|
|
37
|
+
FIX_OPTIONS: 'Provide the list of fix options',
|
|
29
38
|
FIXED_CONTENT_PATH_MAG: 'You can locate the fixed content at {path}.',
|
|
30
39
|
EMPTY_FIX_MSG: 'Successfully removed the empty field/block found at {path} from the schema.',
|
|
31
40
|
AUDIT_FIX_CMD_DESCRIPTION: 'Perform audits and fix possible errors in the exported Contentstack data.',
|
|
32
41
|
};
|
|
33
42
|
exports.auditFixMsg = auditFixMsg;
|
|
34
|
-
const messages = Object.assign(Object.assign(Object.assign(Object.assign({}, errors), commonMsg), auditMsg), auditFixMsg);
|
|
43
|
+
const messages = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, errors), commonMsg), auditMsg), auditFixMsg), tableColumnDescriptions);
|
|
35
44
|
/**
|
|
36
45
|
* The function `$t` is a TypeScript function that replaces placeholders in a string with corresponding
|
|
37
46
|
* values from an object.
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const find_1 = tslib_1.__importDefault(require("lodash/find"));
|
|
5
|
-
const core_1 = require("@oclif/core");
|
|
6
5
|
const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
|
|
7
6
|
const path_1 = require("path");
|
|
8
7
|
const fs_1 = require("fs");
|
|
8
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
9
9
|
const messages_1 = require("../messages");
|
|
10
10
|
/* The `ContentType` class is responsible for scanning content types, looking for references, and
|
|
11
11
|
generating a report in JSON and CSV formats. */
|
|
12
12
|
class ContentType {
|
|
13
13
|
constructor({ log, fix, config, moduleName, ctSchema, gfSchema }) {
|
|
14
|
+
this.inMemoryFix = false;
|
|
14
15
|
this.schema = [];
|
|
15
16
|
this.missingRefs = {};
|
|
16
17
|
this.log = log;
|
|
@@ -29,6 +30,7 @@ class ContentType {
|
|
|
29
30
|
*/
|
|
30
31
|
async run(returnFixSchema = false) {
|
|
31
32
|
var _a;
|
|
33
|
+
this.inMemoryFix = returnFixSchema;
|
|
32
34
|
if (!(0, fs_1.existsSync)(this.folderPath)) {
|
|
33
35
|
throw new Error((0, messages_1.$t)(messages_1.auditMsg.NOT_VALID_PATH, { path: this.folderPath }));
|
|
34
36
|
}
|
|
@@ -59,12 +61,15 @@ class ContentType {
|
|
|
59
61
|
* JSON to the specified file path.
|
|
60
62
|
*/
|
|
61
63
|
async writeFixContent() {
|
|
64
|
+
var _a;
|
|
62
65
|
let canWrite = true;
|
|
63
|
-
if (this.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
if (!this.inMemoryFix && this.fix) {
|
|
67
|
+
if (!this.config.flags['copy-dir']) {
|
|
68
|
+
canWrite = (_a = this.config.flags.yes) !== null && _a !== void 0 ? _a : (await cli_utilities_1.ux.confirm(messages_1.commonMsg.FIX_CONFIRMATION));
|
|
69
|
+
}
|
|
70
|
+
if (canWrite) {
|
|
71
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(this.folderPath, this.config.moduleConfig[this.moduleName].fileName), JSON.stringify(this.schema));
|
|
72
|
+
}
|
|
68
73
|
}
|
|
69
74
|
}
|
|
70
75
|
/**
|
|
@@ -79,11 +84,14 @@ class ContentType {
|
|
|
79
84
|
* object in the array should have a `uid` and `name` property.
|
|
80
85
|
*/
|
|
81
86
|
async lookForReference(tree, field) {
|
|
82
|
-
var _a;
|
|
87
|
+
var _a, _b;
|
|
88
|
+
const fixTypes = (_a = this.config.flags['fix-only']) !== null && _a !== void 0 ? _a : this.config['fix-fields'];
|
|
83
89
|
if (this.fix) {
|
|
84
90
|
field.schema = this.runFixOnSchema(tree, field.schema);
|
|
85
91
|
}
|
|
86
|
-
for (let child of (
|
|
92
|
+
for (let child of (_b = field.schema) !== null && _b !== void 0 ? _b : []) {
|
|
93
|
+
if (!fixTypes.includes(child.data_type) && child.data_type !== 'json')
|
|
94
|
+
continue;
|
|
87
95
|
switch (child.data_type) {
|
|
88
96
|
case 'reference':
|
|
89
97
|
this.missingRefs[this.currentUid].push(...this.validateReferenceField([...tree, { uid: field.uid, name: child.display_name }], child));
|
|
@@ -93,9 +101,13 @@ class ContentType {
|
|
|
93
101
|
break;
|
|
94
102
|
case 'json':
|
|
95
103
|
if (child.field_metadata.extension) {
|
|
104
|
+
if (!fixTypes.includes('json:custom-field'))
|
|
105
|
+
continue;
|
|
96
106
|
// NOTE Custom field type
|
|
97
107
|
}
|
|
98
108
|
else if (child.field_metadata.allow_json_rte) {
|
|
109
|
+
if (!fixTypes.includes('json:rte'))
|
|
110
|
+
continue;
|
|
99
111
|
// NOTE JSON RTE field type
|
|
100
112
|
this.missingRefs[this.currentUid].push(...this.validateJsonRTEFields([...tree, { uid: child.uid, name: child.display_name }], child));
|
|
101
113
|
}
|
|
@@ -131,6 +143,18 @@ class ContentType {
|
|
|
131
143
|
*/
|
|
132
144
|
async validateGlobalField(tree, field) {
|
|
133
145
|
// NOTE Any GlobalField related logic can be added here
|
|
146
|
+
if (!field.schema && !this.fix) {
|
|
147
|
+
this.missingRefs[this.currentUid].push({
|
|
148
|
+
tree,
|
|
149
|
+
ct_uid: this.currentUid,
|
|
150
|
+
name: this.currentTitle,
|
|
151
|
+
data_type: field.data_type,
|
|
152
|
+
display_name: field.display_name,
|
|
153
|
+
missingRefs: 'Empty schema found',
|
|
154
|
+
treeStr: tree.map(({ name }) => name).join(' ➜ '),
|
|
155
|
+
});
|
|
156
|
+
return void 0;
|
|
157
|
+
}
|
|
134
158
|
await this.lookForReference(tree, field);
|
|
135
159
|
}
|
|
136
160
|
/**
|
|
@@ -233,7 +257,11 @@ class ContentType {
|
|
|
233
257
|
// NOTE Global field Fix
|
|
234
258
|
return schema
|
|
235
259
|
.map((field) => {
|
|
260
|
+
var _a;
|
|
236
261
|
const { data_type } = field;
|
|
262
|
+
const fixTypes = (_a = this.config.flags['fix-only']) !== null && _a !== void 0 ? _a : this.config['fix-fields'];
|
|
263
|
+
if (!fixTypes.includes(data_type) && data_type !== 'json')
|
|
264
|
+
return field;
|
|
237
265
|
switch (data_type) {
|
|
238
266
|
case 'global_field':
|
|
239
267
|
return this.fixGlobalFieldReferences(tree, field);
|
|
@@ -242,9 +270,14 @@ class ContentType {
|
|
|
242
270
|
if (data_type === 'json') {
|
|
243
271
|
if (field.field_metadata.extension) {
|
|
244
272
|
// NOTE Custom field type
|
|
273
|
+
if (!fixTypes.includes('json:custom-field'))
|
|
274
|
+
return field;
|
|
275
|
+
// NOTE Fix logic
|
|
245
276
|
return field;
|
|
246
277
|
}
|
|
247
278
|
else if (field.field_metadata.allow_json_rte) {
|
|
279
|
+
if (!fixTypes.includes('json:rte'))
|
|
280
|
+
return field;
|
|
248
281
|
return this.fixMissingReferences(tree, field);
|
|
249
282
|
}
|
|
250
283
|
}
|
|
@@ -279,6 +312,7 @@ class ContentType {
|
|
|
279
312
|
* doesn't.
|
|
280
313
|
*/
|
|
281
314
|
fixGlobalFieldReferences(tree, field) {
|
|
315
|
+
var _a;
|
|
282
316
|
const { reference_to, display_name, data_type } = field;
|
|
283
317
|
if (reference_to && data_type === 'global_field') {
|
|
284
318
|
tree = [...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }];
|
|
@@ -289,12 +323,28 @@ class ContentType {
|
|
|
289
323
|
data_type,
|
|
290
324
|
display_name,
|
|
291
325
|
fixStatus: 'Fixed',
|
|
292
|
-
missingRefs: [reference_to],
|
|
293
326
|
ct_uid: this.currentUid,
|
|
294
327
|
name: this.currentTitle,
|
|
328
|
+
missingRefs: [reference_to],
|
|
295
329
|
treeStr: tree.map(({ name }) => name).join(' ➜ '),
|
|
296
330
|
});
|
|
297
331
|
}
|
|
332
|
+
else if (!field.schema) {
|
|
333
|
+
const gfSchema = (_a = (0, find_1.default)(this.gfSchema, { uid: field.reference_to })) === null || _a === void 0 ? void 0 : _a.schema;
|
|
334
|
+
if (gfSchema) {
|
|
335
|
+
field.schema = gfSchema;
|
|
336
|
+
this.missingRefs[this.currentUid].push({
|
|
337
|
+
tree,
|
|
338
|
+
data_type,
|
|
339
|
+
display_name,
|
|
340
|
+
fixStatus: 'Fixed',
|
|
341
|
+
ct_uid: this.currentUid,
|
|
342
|
+
name: this.currentTitle,
|
|
343
|
+
missingRefs: 'Empty schema found',
|
|
344
|
+
treeStr: tree.map(({ name }) => name).join(' ➜ '),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
298
348
|
return refExist ? field : null;
|
|
299
349
|
}
|
|
300
350
|
return field;
|
package/lib/modules/entries.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import auditConfig from '../config';
|
|
|
2
2
|
import { LogFn, Locale, ConfigType, EntryStruct, EntryFieldType, ModularBlockType, ContentTypeStruct, CtConstructorParam, GroupFieldDataType, GlobalFieldDataType, JsonRTEFieldDataType, ContentTypeSchemaType, ModularBlocksDataType, ModuleConstructorParam, ReferenceFieldDataType, EntryRefErrorReturnType, EntryGroupFieldDataType, EntryGlobalFieldDataType, EntryJsonRTEFieldDataType, EntryModularBlocksDataType, EntryReferenceFieldDataType } from '../types';
|
|
3
3
|
export default class Entries {
|
|
4
4
|
log: LogFn;
|
|
5
|
-
|
|
5
|
+
protected fix: boolean;
|
|
6
6
|
fileName: string;
|
|
7
7
|
locales: Locale[];
|
|
8
8
|
config: ConfigType;
|
|
@@ -11,7 +11,7 @@ export default class Entries {
|
|
|
11
11
|
currentTitle: string;
|
|
12
12
|
gfSchema: ContentTypeStruct[];
|
|
13
13
|
ctSchema: ContentTypeStruct[];
|
|
14
|
-
|
|
14
|
+
protected entries: Record<string, EntryStruct>;
|
|
15
15
|
protected missingRefs: Record<string, any>;
|
|
16
16
|
entryMetaData: Record<string, any>[];
|
|
17
17
|
moduleName: keyof typeof auditConfig.moduleConfig;
|
|
@@ -22,6 +22,15 @@ export default class Entries {
|
|
|
22
22
|
* @returns the `missingRefs` object.
|
|
23
23
|
*/
|
|
24
24
|
run(): Promise<Record<string, any>>;
|
|
25
|
+
/**
|
|
26
|
+
* The function removes any properties from the `missingRefs` object that have an empty array value.
|
|
27
|
+
*/
|
|
28
|
+
removeEmptyVal(): void;
|
|
29
|
+
/**
|
|
30
|
+
* The function `fixPrerequisiteData` fixes the prerequisite data by updating the `ctSchema` and
|
|
31
|
+
* `gfSchema` properties using the `ContentType` class.
|
|
32
|
+
*/
|
|
33
|
+
fixPrerequisiteData(): Promise<void>;
|
|
25
34
|
/**
|
|
26
35
|
* The function checks if it can write the fix content to a file and if so, it writes the content as
|
|
27
36
|
* JSON to the specified file path.
|
|
@@ -212,7 +221,7 @@ export default class Entries {
|
|
|
212
221
|
* block in the `tree` array.
|
|
213
222
|
* @returns the `entryBlock` object.
|
|
214
223
|
*/
|
|
215
|
-
modularBlockRefCheck(tree: Record<string, unknown>[], blocks: ModularBlockType[], entryBlock: EntryModularBlocksDataType, index:
|
|
224
|
+
modularBlockRefCheck(tree: Record<string, unknown>[], blocks: ModularBlockType[], entryBlock: EntryModularBlocksDataType, index: number): EntryModularBlocksDataType;
|
|
216
225
|
/**
|
|
217
226
|
* The `jsonRefCheck` function checks if a reference exists in a JSON tree and adds missing
|
|
218
227
|
* references to a list if they are not found.
|
package/lib/modules/entries.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const find_1 = tslib_1.__importDefault(require("lodash/find"));
|
|
5
|
-
const core_1 = require("@oclif/core");
|
|
6
5
|
const values_1 = tslib_1.__importDefault(require("lodash/values"));
|
|
7
6
|
const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
|
|
8
7
|
const path_1 = require("path");
|
|
@@ -10,6 +9,7 @@ const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
|
10
9
|
const fs_1 = require("fs");
|
|
11
10
|
const content_types_1 = tslib_1.__importDefault(require("./content-types"));
|
|
12
11
|
const messages_1 = require("../messages");
|
|
12
|
+
const global_fields_1 = tslib_1.__importDefault(require("./global-fields"));
|
|
13
13
|
class Entries {
|
|
14
14
|
constructor({ log, fix, config, moduleName, ctSchema, gfSchema }) {
|
|
15
15
|
this.missingRefs = {};
|
|
@@ -34,26 +34,11 @@ class Entries {
|
|
|
34
34
|
throw new Error((0, messages_1.$t)(messages_1.auditMsg.NOT_VALID_PATH, { path: this.folderPath }));
|
|
35
35
|
}
|
|
36
36
|
await this.prepareEntryMetaData();
|
|
37
|
-
|
|
38
|
-
fix: true,
|
|
39
|
-
log: () => { },
|
|
40
|
-
config: this.config,
|
|
41
|
-
moduleName: 'content-types',
|
|
42
|
-
ctSchema: this.ctSchema,
|
|
43
|
-
gfSchema: this.gfSchema,
|
|
44
|
-
}).run(true));
|
|
45
|
-
this.gfSchema = (await new content_types_1.default({
|
|
46
|
-
fix: true,
|
|
47
|
-
log: () => { },
|
|
48
|
-
config: this.config,
|
|
49
|
-
moduleName: 'entries',
|
|
50
|
-
ctSchema: this.ctSchema,
|
|
51
|
-
gfSchema: this.gfSchema,
|
|
52
|
-
}).run(true));
|
|
37
|
+
await this.fixPrerequisiteData();
|
|
53
38
|
for (const { code } of this.locales) {
|
|
54
39
|
for (const ctSchema of this.ctSchema) {
|
|
55
40
|
const basePath = (0, path_1.join)(this.folderPath, ctSchema.uid, code);
|
|
56
|
-
const fsUtility = new cli_utilities_1.FsUtility({ basePath, indexFileName: 'index.json' });
|
|
41
|
+
const fsUtility = new cli_utilities_1.FsUtility({ basePath, indexFileName: 'index.json', createDirIfNotExist: false });
|
|
57
42
|
const indexer = fsUtility.indexFileContent;
|
|
58
43
|
for (const fileIndex in indexer) {
|
|
59
44
|
const entries = (await fsUtility.readChunkFiles.next());
|
|
@@ -78,12 +63,40 @@ class Entries {
|
|
|
78
63
|
}
|
|
79
64
|
}
|
|
80
65
|
this.log('', 'info'); // Adding empty line
|
|
66
|
+
this.removeEmptyVal();
|
|
67
|
+
return this.missingRefs;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The function removes any properties from the `missingRefs` object that have an empty array value.
|
|
71
|
+
*/
|
|
72
|
+
removeEmptyVal() {
|
|
81
73
|
for (let propName in this.missingRefs) {
|
|
82
74
|
if (!this.missingRefs[propName].length) {
|
|
83
75
|
delete this.missingRefs[propName];
|
|
84
76
|
}
|
|
85
77
|
}
|
|
86
|
-
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The function `fixPrerequisiteData` fixes the prerequisite data by updating the `ctSchema` and
|
|
81
|
+
* `gfSchema` properties using the `ContentType` class.
|
|
82
|
+
*/
|
|
83
|
+
async fixPrerequisiteData() {
|
|
84
|
+
this.ctSchema = (await new content_types_1.default({
|
|
85
|
+
fix: true,
|
|
86
|
+
log: () => { },
|
|
87
|
+
config: this.config,
|
|
88
|
+
moduleName: 'content-types',
|
|
89
|
+
ctSchema: this.ctSchema,
|
|
90
|
+
gfSchema: this.gfSchema,
|
|
91
|
+
}).run(true));
|
|
92
|
+
this.gfSchema = (await new global_fields_1.default({
|
|
93
|
+
fix: true,
|
|
94
|
+
log: () => { },
|
|
95
|
+
config: this.config,
|
|
96
|
+
moduleName: 'global-fields',
|
|
97
|
+
ctSchema: this.ctSchema,
|
|
98
|
+
gfSchema: this.gfSchema,
|
|
99
|
+
}).run(true));
|
|
87
100
|
}
|
|
88
101
|
/**
|
|
89
102
|
* The function checks if it can write the fix content to a file and if so, it writes the content as
|
|
@@ -91,11 +104,13 @@ class Entries {
|
|
|
91
104
|
*/
|
|
92
105
|
async writeFixContent(filePath, schema) {
|
|
93
106
|
let canWrite = true;
|
|
94
|
-
if (this.fix
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
(
|
|
107
|
+
if (this.fix) {
|
|
108
|
+
if (!this.config.flags['copy-dir']) {
|
|
109
|
+
canWrite = this.config.flags.yes || (await cli_utilities_1.ux.confirm(messages_1.commonMsg.FIX_CONFIRMATION));
|
|
110
|
+
}
|
|
111
|
+
if (canWrite) {
|
|
112
|
+
(0, fs_1.writeFileSync)(filePath, JSON.stringify(schema));
|
|
113
|
+
}
|
|
99
114
|
}
|
|
100
115
|
}
|
|
101
116
|
/**
|
|
@@ -118,7 +133,7 @@ class Entries {
|
|
|
118
133
|
for (const child of (_a = field.schema) !== null && _a !== void 0 ? _a : []) {
|
|
119
134
|
const { uid } = child;
|
|
120
135
|
if (!(entry === null || entry === void 0 ? void 0 : entry[uid]))
|
|
121
|
-
|
|
136
|
+
continue;
|
|
122
137
|
switch (child.data_type) {
|
|
123
138
|
case 'reference':
|
|
124
139
|
this.missingRefs[this.currentUid].push(...this.validateReferenceField([...tree, { uid: child.uid, name: child.display_name, field: uid }], child, entry[uid]));
|
|
@@ -190,7 +205,6 @@ class Entries {
|
|
|
190
205
|
*/
|
|
191
206
|
validateJsonRTEFields(tree, fieldStructure, field) {
|
|
192
207
|
var _a;
|
|
193
|
-
// const missingRefIndex = []
|
|
194
208
|
// NOTE Other possible reference logic will be added related to JSON RTE (Ex missing assets, extensions etc.,)
|
|
195
209
|
for (const index in (_a = field === null || field === void 0 ? void 0 : field.children) !== null && _a !== void 0 ? _a : []) {
|
|
196
210
|
const child = field.children[index];
|
|
@@ -325,10 +339,11 @@ class Entries {
|
|
|
325
339
|
if (data_type === 'json') {
|
|
326
340
|
if (field.field_metadata.extension) {
|
|
327
341
|
// NOTE Custom field type
|
|
328
|
-
|
|
342
|
+
break;
|
|
329
343
|
}
|
|
330
344
|
else if (field.field_metadata.allow_json_rte) {
|
|
331
|
-
|
|
345
|
+
this.fixJsonRteMissingReferences([...tree, { uid: field.uid, name: field.display_name, data_type: field.data_type }], field, entry[uid]);
|
|
346
|
+
break;
|
|
332
347
|
}
|
|
333
348
|
}
|
|
334
349
|
// NOTE Reference field
|
|
@@ -479,7 +494,7 @@ class Entries {
|
|
|
479
494
|
data_type: field.data_type,
|
|
480
495
|
display_name: field.display_name,
|
|
481
496
|
treeStr: tree
|
|
482
|
-
.map(({ name, index }) => (index || index === 0 ? `[${index}].${name}` : name))
|
|
497
|
+
.map(({ name, index }) => (index || index === 0 ? `[${+index}].${name}` : name))
|
|
483
498
|
.filter((val) => val)
|
|
484
499
|
.join(' ➜ '),
|
|
485
500
|
missingRefs,
|
|
@@ -516,7 +531,7 @@ class Entries {
|
|
|
516
531
|
fixStatus: this.fix ? 'Fixed' : undefined,
|
|
517
532
|
tree: [...tree, { index, uid: key, name: key }],
|
|
518
533
|
treeStr: [...tree, { index, uid: key, name: key }]
|
|
519
|
-
.map(({ name, index }) => (index || index === 0 ? `[${index}].${name}` : name))
|
|
534
|
+
.map(({ name, index }) => (index || index === 0 ? `[${+index}].${name}` : name))
|
|
520
535
|
.filter((val) => val)
|
|
521
536
|
.join(' ➜ '),
|
|
522
537
|
missingRefs: [key],
|
|
@@ -569,8 +584,8 @@ class Entries {
|
|
|
569
584
|
const localesFolderPath = (0, path_1.resolve)(this.config.basePath, this.config.moduleConfig.locales.dirName);
|
|
570
585
|
const localesPath = (0, path_1.join)(localesFolderPath, this.config.moduleConfig.locales.fileName);
|
|
571
586
|
const masterLocalesPath = (0, path_1.join)(localesFolderPath, 'master-locale.json');
|
|
572
|
-
this.locales = (0, values_1.default)(JSON.parse((0, fs_1.readFileSync)(masterLocalesPath, '
|
|
573
|
-
this.locales.push(...(0, values_1.default)(JSON.parse((0, fs_1.readFileSync)(localesPath, '
|
|
587
|
+
this.locales = (0, values_1.default)(JSON.parse((0, fs_1.readFileSync)(masterLocalesPath, 'utf8')));
|
|
588
|
+
this.locales.push(...(0, values_1.default)(JSON.parse((0, fs_1.readFileSync)(localesPath, 'utf8'))));
|
|
574
589
|
for (const { code } of this.locales) {
|
|
575
590
|
for (const { uid } of this.ctSchema) {
|
|
576
591
|
let basePath = (0, path_1.join)(this.folderPath, uid, code);
|
|
@@ -6,7 +6,7 @@ export default class GlobalField extends ContentType {
|
|
|
6
6
|
* references.
|
|
7
7
|
* @returns the value of the variable `missingRefs`.
|
|
8
8
|
*/
|
|
9
|
-
run(): Promise<Record<string, any>>;
|
|
9
|
+
run(returnFixSchema?: boolean): Promise<Record<string, any>>;
|
|
10
10
|
/**
|
|
11
11
|
* The function validates a field containing modular blocks by traversing each block and checking for
|
|
12
12
|
* references in a given tree.
|
|
@@ -8,9 +8,9 @@ class GlobalField extends content_types_1.default {
|
|
|
8
8
|
* references.
|
|
9
9
|
* @returns the value of the variable `missingRefs`.
|
|
10
10
|
*/
|
|
11
|
-
async run() {
|
|
11
|
+
async run(returnFixSchema = false) {
|
|
12
12
|
// NOTE add any validation if required
|
|
13
|
-
const missingRefs = await super.run();
|
|
13
|
+
const missingRefs = await super.run(returnFixSchema);
|
|
14
14
|
return missingRefs;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
@@ -73,4 +73,4 @@ declare enum OutputColumn {
|
|
|
73
73
|
'Missing references' = "missingRefs",
|
|
74
74
|
Path = "treeStr"
|
|
75
75
|
}
|
|
76
|
-
export { CtConstructorParam, ContentTypeStruct, ModuleConstructorParam, ReferenceFieldDataType, GlobalFieldDataType, CustomFieldDataType, JsonRTEFieldDataType, GroupFieldDataType, ModularBlocksDataType, RefErrorReturnType, ModularBlocksSchemaTypes, ModularBlockType, OutputColumn, ContentTypeSchemaType, };
|
|
76
|
+
export { CtConstructorParam, ContentTypeStruct, ModuleConstructorParam, ReferenceFieldDataType, GlobalFieldDataType, CustomFieldDataType, JsonRTEFieldDataType, GroupFieldDataType, ModularBlocksDataType, RefErrorReturnType, ModularBlocksSchemaTypes, ModularBlockType, OutputColumn, ContentTypeSchemaType, GlobalFieldSchemaTypes, };
|
package/lib/types/index.d.ts
CHANGED
package/lib/types/index.js
CHANGED
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
tslib_1.__exportStar(require("./utils"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./common"), exports);
|
|
5
6
|
tslib_1.__exportStar(require("./entries"), exports);
|
|
6
7
|
tslib_1.__exportStar(require("./content-types"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IFlags, IncludeFlags } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* The function `getTableFlags` returns a set of table flags based on the specified columns, with
|
|
4
|
+
* updated descriptions and help groups.
|
|
5
|
+
* @param {(keyof IFlags)[]} columns - An optional array of column keys from the IFlags interface. The
|
|
6
|
+
* default value is ['columns', 'sort', 'filter', 'csv', 'no-truncate'].
|
|
7
|
+
* @returns an object of type `IncludeFlags<IFlags, keyof IFlags>`.
|
|
8
|
+
*/
|
|
9
|
+
declare function getTableFlags(columns?: (keyof IFlags)[]): IncludeFlags<IFlags, keyof IFlags>;
|
|
10
|
+
export { getTableFlags };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTableFlags = void 0;
|
|
4
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
5
|
+
const messages_1 = require("../messages");
|
|
6
|
+
/**
|
|
7
|
+
* The function `getTableFlags` returns a set of table flags based on the specified columns, with
|
|
8
|
+
* updated descriptions and help groups.
|
|
9
|
+
* @param {(keyof IFlags)[]} columns - An optional array of column keys from the IFlags interface. The
|
|
10
|
+
* default value is ['columns', 'sort', 'filter', 'csv', 'no-truncate'].
|
|
11
|
+
* @returns an object of type `IncludeFlags<IFlags, keyof IFlags>`.
|
|
12
|
+
*/
|
|
13
|
+
function getTableFlags(columns = ['columns', 'sort', 'filter', 'csv', 'no-truncate']) {
|
|
14
|
+
const flags = cli_utilities_1.ux.table.flags({
|
|
15
|
+
only: columns,
|
|
16
|
+
});
|
|
17
|
+
// NOTE Assign group and update Descriptions
|
|
18
|
+
columns.forEach((element) => {
|
|
19
|
+
var _a;
|
|
20
|
+
flags[element].helpGroup = 'TABLE';
|
|
21
|
+
const descriptionKey = `TABLE_${element.toUpperCase()}`;
|
|
22
|
+
flags[element].description = (_a = messages_1.tableColumnDescriptions[descriptionKey]) !== null && _a !== void 0 ? _a : flags[element].description;
|
|
23
|
+
});
|
|
24
|
+
return flags;
|
|
25
|
+
}
|
|
26
|
+
exports.getTableFlags = getTableFlags;
|
package/lib/util/index.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './flags';
|
|
2
|
+
export { default as Logger, print } from './log';
|
package/lib/util/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.Logger = void 0;
|
|
3
|
+
exports.print = exports.Logger = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
tslib_1.__exportStar(require("./flags"), exports);
|
|
7
6
|
var log_1 = require("./log");
|
|
8
|
-
Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return __importDefault(log_1).default; } });
|
|
7
|
+
Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return tslib_1.__importDefault(log_1).default; } });
|
|
8
|
+
Object.defineProperty(exports, "print", { enumerable: true, get: function () { return log_1.print; } });
|
package/lib/util/log.js
CHANGED
|
@@ -4,7 +4,6 @@ exports.print = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const map_1 = tslib_1.__importDefault(require("lodash/map"));
|
|
6
6
|
const winston_1 = tslib_1.__importDefault(require("winston"));
|
|
7
|
-
const fs_1 = require("fs");
|
|
8
7
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
9
8
|
const replace_1 = tslib_1.__importDefault(require("lodash/replace"));
|
|
10
9
|
const isObject_1 = tslib_1.__importDefault(require("lodash/isObject"));
|
|
@@ -52,26 +51,18 @@ class Logger {
|
|
|
52
51
|
if (logType === 'error') {
|
|
53
52
|
consoleOptions.level = logType;
|
|
54
53
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
transports:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
loggerOptions.levels = { error: 0 };
|
|
66
|
-
}
|
|
67
|
-
return winston_1.default.createLogger(loggerOptions);
|
|
54
|
+
const filename = (0, path_1.normalize)((0, path_1.resolve)(this.config.basePath, 'logs', `${logType}.log`)).replace(/^(\.\.(\/|\\|$))+/, '');
|
|
55
|
+
const loggerOptions = {
|
|
56
|
+
transports: [
|
|
57
|
+
new winston_1.default.transports.File(Object.assign(Object.assign({}, this.loggerOptions), { level: logType, filename })),
|
|
58
|
+
new winston_1.default.transports.Console(consoleOptions),
|
|
59
|
+
],
|
|
60
|
+
levels: customLevels.levels,
|
|
61
|
+
};
|
|
62
|
+
if (logType === 'error') {
|
|
63
|
+
loggerOptions.levels = { error: 0 };
|
|
68
64
|
}
|
|
69
|
-
winston_1.default
|
|
70
|
-
.createLogger({
|
|
71
|
-
transports: [new winston_1.default.transports.Console(consoleOptions)],
|
|
72
|
-
})
|
|
73
|
-
.error('Provided base path is not valid');
|
|
74
|
-
throw new Error('Provided base path is not valid');
|
|
65
|
+
return winston_1.default.createLogger(loggerOptions);
|
|
75
66
|
}
|
|
76
67
|
/**
|
|
77
68
|
* The function `log` takes a message and an optional log type, and logs the message using different
|
|
@@ -108,7 +99,7 @@ class Logger {
|
|
|
108
99
|
let returnStr = '';
|
|
109
100
|
const replaceCredentials = (item) => {
|
|
110
101
|
try {
|
|
111
|
-
return JSON.stringify(item).replace(/authtoken"
|
|
102
|
+
return JSON.stringify(item).replace(/"authtoken":\s*".*?"/, '"authtoken": "..."');
|
|
112
103
|
}
|
|
113
104
|
catch (error) { }
|
|
114
105
|
return item;
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.3.0",
|
|
3
3
|
"commands": {
|
|
4
4
|
"cm:stacks:audit:fix": {
|
|
5
5
|
"id": "cm:stacks:audit:fix",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"$ <%= config.bin %> <%= command.id %> --copy-dir",
|
|
17
17
|
"$ <%= config.bin %> <%= command.id %> --report-path=<path> --copy-dir",
|
|
18
18
|
"$ <%= config.bin %> <%= command.id %> --report-path=<path> --copy-dir --csv",
|
|
19
|
+
"$ <%= config.bin %> <%= command.id %> --fix-only=reference,global_field --copy-dir",
|
|
19
20
|
"$ <%= config.bin %> <%= command.id %> --report-path=<path> --filter=\"name=<filter-value>\"",
|
|
20
21
|
"$ <%= config.bin %> <%= command.id %> --report-path=<path> --modules=content-types --filter=\"name=\"<filter-value>\" --copy-dir --copy-path=<path>"
|
|
21
22
|
],
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
"type": "option",
|
|
26
27
|
"char": "c",
|
|
27
28
|
"description": "Path of the external config",
|
|
29
|
+
"helpGroup": "COMMON",
|
|
28
30
|
"multiple": false
|
|
29
31
|
},
|
|
30
32
|
"data-dir": {
|
|
@@ -32,6 +34,7 @@
|
|
|
32
34
|
"type": "option",
|
|
33
35
|
"char": "d",
|
|
34
36
|
"description": "Path where the data is stored",
|
|
37
|
+
"helpGroup": "COMMON",
|
|
35
38
|
"multiple": false
|
|
36
39
|
},
|
|
37
40
|
"report-path": {
|
|
@@ -73,6 +76,20 @@
|
|
|
73
76
|
"copy-dir"
|
|
74
77
|
]
|
|
75
78
|
},
|
|
79
|
+
"fix-only": {
|
|
80
|
+
"name": "fix-only",
|
|
81
|
+
"type": "option",
|
|
82
|
+
"description": "Provide the list of fix options",
|
|
83
|
+
"multiple": true,
|
|
84
|
+
"options": [
|
|
85
|
+
"reference",
|
|
86
|
+
"global_field",
|
|
87
|
+
"json:rte",
|
|
88
|
+
"json:custom-field",
|
|
89
|
+
"blocks",
|
|
90
|
+
"group"
|
|
91
|
+
]
|
|
92
|
+
},
|
|
76
93
|
"yes": {
|
|
77
94
|
"name": "yes",
|
|
78
95
|
"type": "boolean",
|
|
@@ -84,7 +101,8 @@
|
|
|
84
101
|
"columns": {
|
|
85
102
|
"name": "columns",
|
|
86
103
|
"type": "option",
|
|
87
|
-
"description": "only
|
|
104
|
+
"description": "Show only the specified columns (comma-separated)",
|
|
105
|
+
"helpGroup": "TABLE",
|
|
88
106
|
"multiple": false,
|
|
89
107
|
"exclusive": [
|
|
90
108
|
"extended"
|
|
@@ -93,19 +111,22 @@
|
|
|
93
111
|
"sort": {
|
|
94
112
|
"name": "sort",
|
|
95
113
|
"type": "option",
|
|
96
|
-
"description": "
|
|
114
|
+
"description": "Property to sort by (prepend '-' for descending)",
|
|
115
|
+
"helpGroup": "TABLE",
|
|
97
116
|
"multiple": false
|
|
98
117
|
},
|
|
99
118
|
"filter": {
|
|
100
119
|
"name": "filter",
|
|
101
120
|
"type": "option",
|
|
102
|
-
"description": "
|
|
121
|
+
"description": "Filter property by partial string matching. For example: name=foo",
|
|
122
|
+
"helpGroup": "TABLE",
|
|
103
123
|
"multiple": false
|
|
104
124
|
},
|
|
105
125
|
"csv": {
|
|
106
126
|
"name": "csv",
|
|
107
127
|
"type": "boolean",
|
|
108
|
-
"description": "output is
|
|
128
|
+
"description": "The output is in the CSV format [alias: --output=csv]",
|
|
129
|
+
"helpGroup": "TABLE",
|
|
109
130
|
"allowNo": false,
|
|
110
131
|
"exclusive": [
|
|
111
132
|
"no-truncate"
|
|
@@ -114,7 +135,8 @@
|
|
|
114
135
|
"no-truncate": {
|
|
115
136
|
"name": "no-truncate",
|
|
116
137
|
"type": "boolean",
|
|
117
|
-
"description": "
|
|
138
|
+
"description": "The output is not truncated to fit the screen",
|
|
139
|
+
"helpGroup": "TABLE",
|
|
118
140
|
"allowNo": false,
|
|
119
141
|
"exclusive": [
|
|
120
142
|
"csv"
|
|
@@ -147,6 +169,7 @@
|
|
|
147
169
|
"type": "option",
|
|
148
170
|
"char": "c",
|
|
149
171
|
"description": "Path of the external config",
|
|
172
|
+
"helpGroup": "COMMON",
|
|
150
173
|
"multiple": false
|
|
151
174
|
},
|
|
152
175
|
"data-dir": {
|
|
@@ -154,6 +177,7 @@
|
|
|
154
177
|
"type": "option",
|
|
155
178
|
"char": "d",
|
|
156
179
|
"description": "Path where the data is stored",
|
|
180
|
+
"helpGroup": "COMMON",
|
|
157
181
|
"multiple": false
|
|
158
182
|
},
|
|
159
183
|
"report-path": {
|
|
@@ -183,7 +207,8 @@
|
|
|
183
207
|
"columns": {
|
|
184
208
|
"name": "columns",
|
|
185
209
|
"type": "option",
|
|
186
|
-
"description": "only
|
|
210
|
+
"description": "Show only the specified columns (comma-separated)",
|
|
211
|
+
"helpGroup": "TABLE",
|
|
187
212
|
"multiple": false,
|
|
188
213
|
"exclusive": [
|
|
189
214
|
"extended"
|
|
@@ -192,19 +217,22 @@
|
|
|
192
217
|
"sort": {
|
|
193
218
|
"name": "sort",
|
|
194
219
|
"type": "option",
|
|
195
|
-
"description": "
|
|
220
|
+
"description": "Property to sort by (prepend '-' for descending)",
|
|
221
|
+
"helpGroup": "TABLE",
|
|
196
222
|
"multiple": false
|
|
197
223
|
},
|
|
198
224
|
"filter": {
|
|
199
225
|
"name": "filter",
|
|
200
226
|
"type": "option",
|
|
201
|
-
"description": "
|
|
227
|
+
"description": "Filter property by partial string matching. For example: name=foo",
|
|
228
|
+
"helpGroup": "TABLE",
|
|
202
229
|
"multiple": false
|
|
203
230
|
},
|
|
204
231
|
"csv": {
|
|
205
232
|
"name": "csv",
|
|
206
233
|
"type": "boolean",
|
|
207
|
-
"description": "output is
|
|
234
|
+
"description": "The output is in the CSV format [alias: --output=csv]",
|
|
235
|
+
"helpGroup": "TABLE",
|
|
208
236
|
"allowNo": false,
|
|
209
237
|
"exclusive": [
|
|
210
238
|
"no-truncate"
|
|
@@ -213,7 +241,8 @@
|
|
|
213
241
|
"no-truncate": {
|
|
214
242
|
"name": "no-truncate",
|
|
215
243
|
"type": "boolean",
|
|
216
|
-
"description": "
|
|
244
|
+
"description": "The output is not truncated to fit the screen",
|
|
245
|
+
"helpGroup": "TABLE",
|
|
217
246
|
"allowNo": false,
|
|
218
247
|
"exclusive": [
|
|
219
248
|
"csv"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/cli-audit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Contentstack audit plugin",
|
|
5
5
|
"author": "Contentstack CLI",
|
|
6
6
|
"homepage": "https://github.com/contentstack/cli",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"/oclif.manifest.json"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@contentstack/cli-command": "~1.2.
|
|
22
|
-
"@contentstack/cli-utilities": "~1.5.
|
|
21
|
+
"@contentstack/cli-command": "~1.2.16",
|
|
22
|
+
"@contentstack/cli-utilities": "~1.5.7",
|
|
23
23
|
"@oclif/plugin-help": "^5",
|
|
24
24
|
"@oclif/plugin-plugins": "^3.8.4",
|
|
25
25
|
"chalk": "^4.1.2",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"winston": "^3.10.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
+
"@contentstack/cli-dev-dependencies": "^1.2.4",
|
|
33
34
|
"@oclif/test": "^2.0.3",
|
|
34
35
|
"@types/chai": "^4.3.5",
|
|
35
36
|
"@types/fs-extra": "^11.0.2",
|
|
@@ -41,8 +42,10 @@
|
|
|
41
42
|
"eslint-config-oclif-typescript": "^1.0.3",
|
|
42
43
|
"mocha": "^10.2.0",
|
|
43
44
|
"nyc": "^15.1.0",
|
|
44
|
-
"oclif": "^3
|
|
45
|
+
"oclif": "^3",
|
|
45
46
|
"shx": "^0.3.4",
|
|
47
|
+
"sinon": "^17.0.0",
|
|
48
|
+
"ts-jest": "^29.1.1",
|
|
46
49
|
"ts-node": "^10.9.1",
|
|
47
50
|
"tslib": "^2.5.3",
|
|
48
51
|
"typescript": "^5.1.3"
|