@contentstack/cli-utilities 1.8.4 → 1.10.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.
@@ -0,0 +1,38 @@
1
+ import { Header } from 'tty-table';
2
+ import { FlagInput } from '.';
3
+ export interface TableFlags {
4
+ extended?: boolean;
5
+ columns?: string;
6
+ csv?: boolean;
7
+ filter?: string;
8
+ 'no-header'?: boolean;
9
+ 'no-truncate'?: boolean;
10
+ output?: 'csv' | 'json' | 'yaml';
11
+ sort?: string;
12
+ }
13
+ /** Type for table headers */
14
+ export type TableHeader = Header;
15
+ /** Type for table columns mapping */
16
+ export type TableColumn = {
17
+ [key: string]: {
18
+ minWidth?: number;
19
+ maxWidth?: number;
20
+ alias?: string;
21
+ align?: 'left' | 'center' | 'right';
22
+ };
23
+ };
24
+ export type TableData<T extends Record<string, unknown>> = T[];
25
+ /** Options for CLI Table rendering */
26
+ export type TableOptions = {
27
+ truncate?: boolean;
28
+ borderStyle?: 'solid' | 'dashed' | 'none';
29
+ paddingBottom?: number;
30
+ showHeader?: boolean;
31
+ align?: 'left' | 'center' | 'right';
32
+ enableHeaderTitle?: boolean;
33
+ };
34
+ export default class CLITable {
35
+ /** Returns CLI table flags */
36
+ static getTableFlags(columns?: string[]): FlagInput<TableFlags>;
37
+ static render(headers: TableHeader[], data: Record<string, unknown>[], flags: TableFlags, options?: TableOptions): void;
38
+ }
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const tty_table_1 = tslib_1.__importDefault(require("tty-table"));
5
+ const yaml = tslib_1.__importStar(require("js-yaml"));
6
+ const papaparse_1 = require("papaparse");
7
+ const core_1 = require("@oclif/core");
8
+ const _1 = require(".");
9
+ class CLITable {
10
+ /** Returns CLI table flags */
11
+ static getTableFlags(columns = ['columns', 'sort', 'filter', 'csv', 'no-truncate']) {
12
+ const flags = {
13
+ columns: core_1.Flags.string({
14
+ description: 'Specify columns to display, comma-separated.',
15
+ helpGroup: 'TABLE',
16
+ }),
17
+ sort: core_1.Flags.string({
18
+ description: 'Sort the table by a column. Use "-" for descending.',
19
+ helpGroup: 'TABLE',
20
+ }),
21
+ filter: core_1.Flags.string({
22
+ description: 'Filter rows by a column value (e.g., name=foo).',
23
+ helpGroup: 'TABLE',
24
+ }),
25
+ csv: core_1.Flags.boolean({
26
+ description: 'Output results in CSV format.',
27
+ helpGroup: 'TABLE',
28
+ }),
29
+ 'no-truncate': core_1.Flags.boolean({
30
+ description: 'Prevent truncation of long text in columns.',
31
+ helpGroup: 'TABLE',
32
+ }),
33
+ 'no-header': core_1.Flags.boolean({
34
+ description: 'Hide table headers in output.',
35
+ helpGroup: 'TABLE',
36
+ }),
37
+ output: core_1.Flags.string({
38
+ options: ['csv', 'json', 'yaml'],
39
+ description: 'Specify output format: csv, json, or yaml.',
40
+ helpGroup: 'TABLE',
41
+ }),
42
+ };
43
+ // Return only requested flags
44
+ return Object.entries(flags)
45
+ .filter(([key]) => columns.includes(key))
46
+ .reduce((acc, [key, value]) => {
47
+ acc[key] = value;
48
+ return acc;
49
+ }, {});
50
+ }
51
+ static render(headers, data, flags, options) {
52
+ let tableData = [...data];
53
+ if (flags) {
54
+ // **Filter Data**
55
+ if (flags.filter) {
56
+ const [key, value] = flags.filter.split('=');
57
+ tableData = tableData.filter((row) => { var _a; return (_a = row[key]) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase().includes(value.toLowerCase()); });
58
+ }
59
+ // **Select Specific Columns**
60
+ if (flags.columns) {
61
+ const selectedColumns = flags.columns.split(',');
62
+ headers = headers.filter((header) => selectedColumns.includes(header.value));
63
+ tableData = tableData.map((row) => selectedColumns.reduce((acc, key) => {
64
+ if (row[key] !== undefined) {
65
+ acc[key] = row[key];
66
+ }
67
+ return acc;
68
+ }, {}));
69
+ }
70
+ // **Sort Data**
71
+ if (flags.sort) {
72
+ const sortKey = flags.sort.replace('-', '');
73
+ const descending = flags.sort.startsWith('-');
74
+ tableData.sort((a, b) => {
75
+ if (a[sortKey] < b[sortKey])
76
+ return descending ? 1 : -1;
77
+ if (a[sortKey] > b[sortKey])
78
+ return descending ? -1 : 1;
79
+ return 0;
80
+ });
81
+ }
82
+ // **Format Output**
83
+ if (flags.output) {
84
+ switch (flags.output) {
85
+ case 'json':
86
+ console.log(JSON.stringify(tableData, null, 2));
87
+ return;
88
+ case 'yaml':
89
+ console.log(yaml.dump(tableData));
90
+ return;
91
+ case 'csv':
92
+ console.log((0, papaparse_1.parse)(tableData));
93
+ return;
94
+ }
95
+ }
96
+ if (flags.csv) {
97
+ console.log((0, papaparse_1.parse)(tableData));
98
+ }
99
+ }
100
+ // **Render Table**
101
+ const config = {
102
+ truncate: !(flags === null || flags === void 0 ? void 0 : flags['no-header']),
103
+ borderStyle: 'solid',
104
+ paddingBottom: 0,
105
+ showHeader: !(flags === null || flags === void 0 ? void 0 : flags['no-header']),
106
+ };
107
+ _1.cliux.print((0, tty_table_1.default)(headers, tableData, config).render());
108
+ }
109
+ }
110
+ exports.default = CLITable;
package/lib/cli-ux.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Table } from '@oclif/core/lib/cli-ux';
2
1
  import { Args, Flags, Command } from '@oclif/core';
3
2
  import { Ora } from 'ora';
3
+ import { TableFlags, TableHeader, TableData, TableOptions } from './cli-table';
4
4
  import { PrintOptions, InquirePayload, CliUXPromptOptions } from './interfaces';
5
5
  /**
6
6
  * CLI Interface
@@ -8,16 +8,15 @@ import { PrintOptions, InquirePayload, CliUXPromptOptions } from './interfaces';
8
8
  declare class CLIInterface {
9
9
  private loading;
10
10
  constructor();
11
- get uxTable(): typeof Table.table;
12
11
  init(context: any): void;
13
12
  registerSearchPlugin(): void;
14
13
  print(message: string, opts?: PrintOptions): void;
15
14
  success(message: string): void;
16
15
  error(message: string, ...params: any): void;
17
16
  loader(message?: string): void;
18
- table(data: Record<string, unknown>[], columns: Table.table.Columns<Record<string, unknown>>, options?: Table.table.Options): void;
17
+ table<T extends Record<string, unknown>>(headers: TableHeader[], data: TableData<T>, flags?: TableFlags, options?: TableOptions): void;
19
18
  inquire<T>(inquirePayload: InquirePayload | Array<InquirePayload>): Promise<T>;
20
- prompt(name: string, options?: CliUXPromptOptions): Promise<any>;
19
+ prompt(message: string, options?: CliUXPromptOptions): Promise<any>;
21
20
  confirm(message?: string): Promise<boolean>;
22
21
  progress(options?: any): any;
23
22
  loaderV2(message?: string, spinner?: any): Ora | void;
package/lib/cli-ux.js CHANGED
@@ -9,6 +9,8 @@ Object.defineProperty(exports, "Args", { enumerable: true, get: function () { re
9
9
  Object.defineProperty(exports, "Flags", { enumerable: true, get: function () { return core_1.Flags; } });
10
10
  Object.defineProperty(exports, "Command", { enumerable: true, get: function () { return core_1.Command; } });
11
11
  const ora_1 = tslib_1.__importDefault(require("ora"));
12
+ const cli_progress_1 = tslib_1.__importDefault(require("cli-progress"));
13
+ const cli_table_1 = tslib_1.__importDefault(require("./cli-table"));
12
14
  const message_handler_1 = tslib_1.__importDefault(require("./message-handler"));
13
15
  inquirer_1.default.registerPrompt('table', require('./inquirer-table-prompt'));
14
16
  /**
@@ -18,9 +20,6 @@ class CLIInterface {
18
20
  constructor() {
19
21
  this.loading = false;
20
22
  }
21
- get uxTable() {
22
- return core_1.ux.table;
23
- }
24
23
  init(context) { }
25
24
  registerSearchPlugin() {
26
25
  inquirer_1.default.registerPrompt('search-list', require('inquirer-search-list'));
@@ -33,16 +32,16 @@ class CLIInterface {
33
32
  chalkFn = chalkFn[opts.color];
34
33
  if (opts.bold)
35
34
  chalkFn = chalkFn.bold;
36
- core_1.ux.log(chalkFn(message_handler_1.default.parse(message)));
35
+ core_1.ux.stdout(chalkFn(message_handler_1.default.parse(message)));
37
36
  return;
38
37
  }
39
- core_1.ux.log(message_handler_1.default.parse(message));
38
+ core_1.ux.stdout(message_handler_1.default.parse(message));
40
39
  }
41
40
  success(message) {
42
- core_1.ux.log(chalk_1.default.green(message_handler_1.default.parse(message)));
41
+ core_1.ux.stdout(chalk_1.default.green(message_handler_1.default.parse(message)));
43
42
  }
44
43
  error(message, ...params) {
45
- core_1.ux.log(chalk_1.default.red(message_handler_1.default.parse(message) + (params && params.length > 0 ? ': ' : '')), ...params);
44
+ core_1.ux.stdout(chalk_1.default.red(message_handler_1.default.parse(message) + (params && params.length > 0 ? ': ' : '')), ...params);
46
45
  }
47
46
  loader(message = '') {
48
47
  if (!this.loading) {
@@ -53,10 +52,8 @@ class CLIInterface {
53
52
  }
54
53
  this.loading = !this.loading;
55
54
  }
56
- table(data, columns, options) {
57
- core_1.ux.log('\n');
58
- core_1.ux.table(data, columns, options);
59
- core_1.ux.log('\n');
55
+ table(headers, data, flags, options) {
56
+ cli_table_1.default.render(headers, data, flags, options);
60
57
  }
61
58
  async inquire(inquirePayload) {
62
59
  if (Array.isArray(inquirePayload)) {
@@ -68,14 +65,22 @@ class CLIInterface {
68
65
  return result[inquirePayload.name];
69
66
  }
70
67
  }
71
- prompt(name, options) {
72
- return core_1.ux.prompt(name, options);
68
+ async prompt(message, options) {
69
+ return await this.inquire({
70
+ type: 'input',
71
+ name: 'prompt',
72
+ message,
73
+ });
73
74
  }
74
- confirm(message) {
75
- return core_1.ux.confirm(message);
75
+ async confirm(message) {
76
+ return await this.inquire({
77
+ type: 'confirm',
78
+ name: 'prompt',
79
+ message,
80
+ });
76
81
  }
77
82
  progress(options) {
78
- return core_1.ux.progress(options);
83
+ return new cli_progress_1.default.SingleBar(options);
79
84
  }
80
85
  loaderV2(message = '', spinner) {
81
86
  if (!spinner) {
package/lib/helpers.d.ts CHANGED
@@ -18,3 +18,10 @@ export declare const validateUids: (uid: any) => boolean;
18
18
  export declare const validateFileName: (fileName: any) => boolean;
19
19
  export declare const validateRegex: (str: unknown) => import("recheck").Diagnostics;
20
20
  export declare const formatError: (error: any) => any;
21
+ /**
22
+ * The function redactObject takes an object as input and replaces any sensitive keys with the string
23
+ * '[REDACTED]'.
24
+ * @param {any} obj - The `obj` parameter is an object that you want to redact sensitive information
25
+ * from.
26
+ */
27
+ export declare const redactObject: (obj: any) => any;
package/lib/helpers.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.formatError = exports.validateRegex = exports.validateFileName = exports.validateUids = exports.sanitizePath = exports.escapeRegExp = exports.validatePath = exports.createDeveloperHubUrl = exports.isManagementTokenValid = exports.doesBranchExist = exports.isAuthenticated = void 0;
3
+ exports.redactObject = exports.formatError = exports.validateRegex = exports.validateFileName = exports.validateUids = exports.sanitizePath = exports.escapeRegExp = exports.validatePath = exports.createDeveloperHubUrl = exports.isManagementTokenValid = exports.doesBranchExist = exports.isAuthenticated = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const recheck_1 = require("recheck");
6
+ const traverse_1 = tslib_1.__importDefault(require("traverse"));
6
7
  const auth_handler_1 = tslib_1.__importDefault(require("./auth-handler"));
7
8
  const _1 = require(".");
8
9
  const isAuthenticated = () => auth_handler_1.default.isAuthenticated();
@@ -62,7 +63,12 @@ exports.validatePath = validatePath;
62
63
  const escapeRegExp = (str) => str === null || str === void 0 ? void 0 : str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
63
64
  exports.escapeRegExp = escapeRegExp;
64
65
  // To remove the relative path
65
- const sanitizePath = (str) => str === null || str === void 0 ? void 0 : str.replace(/^(\.\.(\/|\\|$))+/, '');
66
+ const sanitizePath = (str) => {
67
+ if (typeof str !== 'string')
68
+ return;
69
+ const decodedStr = decodeURIComponent(str);
70
+ return decodedStr === null || decodedStr === void 0 ? void 0 : decodedStr.replace(/^([\/\\]){2,}/, "./").replace(/[\/\\]+/g, "/").replace(/(\.\.(\/|\\|$))+/g, ""); // Remove directory traversal (../ or ..\)
71
+ };
66
72
  exports.sanitizePath = sanitizePath;
67
73
  // To validate the UIDs of assets
68
74
  const validateUids = (uid) => /^[a-zA-Z0-9]+$/.test(uid);
@@ -137,3 +143,45 @@ const formatError = function (error) {
137
143
  return message;
138
144
  };
139
145
  exports.formatError = formatError;
146
+ /**
147
+ * The function checks if a given key string matches any of the sensitive keys defined in an array.
148
+ * @param {string} keyStr - The parameter `keyStr` is a string that represents a key.
149
+ * @returns a boolean value. It returns true if the keyStr matches any of the regular expressions in
150
+ * the sensitiveKeys array, and false otherwise.
151
+ */
152
+ const isSensitiveKey = function (keyStr) {
153
+ if (keyStr && typeof keyStr === 'string') {
154
+ return sensitiveKeys.some((regex) => regex.test(keyStr));
155
+ }
156
+ };
157
+ /**
158
+ * The function redactObject takes an object as input and replaces any sensitive keys with the string
159
+ * '[REDACTED]'.
160
+ * @param {any} obj - The `obj` parameter is an object that you want to redact sensitive information
161
+ * from.
162
+ */
163
+ const redactObject = function (obj) {
164
+ (0, traverse_1.default)(obj).forEach(function redactor() {
165
+ // Check if the current key is sensitive
166
+ if (isSensitiveKey(this.key)) {
167
+ // Update the current value with '[REDACTED]'
168
+ this.update('[REDACTED]');
169
+ }
170
+ });
171
+ return obj;
172
+ };
173
+ exports.redactObject = redactObject;
174
+ /* The `sensitiveKeys` array is used to store regular expressions that match sensitive keys. These
175
+ keys are used to redact sensitive information from log messages. When logging an object, any keys
176
+ that match the regular expressions in the `sensitiveKeys` array will be replaced with the string
177
+ '[REDACTED]'. This helps to prevent sensitive information from being logged or displayed. */
178
+ const sensitiveKeys = [
179
+ /authtoken/i,
180
+ /^email$/,
181
+ /^password$/i,
182
+ /secret/i,
183
+ /token/i,
184
+ /api[-._]?key/i,
185
+ /management[-._]?token/i,
186
+ /delivery[-._]?token/i,
187
+ ];
package/lib/index.d.ts CHANGED
@@ -17,8 +17,9 @@ export * from './interfaces';
17
17
  export * from './date-time';
18
18
  export * from './add-locale';
19
19
  export * from './path-validator';
20
+ export { default as CLITable, TableFlags, TableHeader, TableOptions, TableData } from './cli-table';
20
21
  export { App, AppData, Installation, marketplaceSDKClient, MarketplaceSDKInitiator, marketplaceSDKInitiator, ContentstackMarketplaceClient, ContentstackMarketplaceConfig, };
21
- export { Args, CommandHelp, Config, Errors, Flags, loadHelpClass, Help, HelpBase, HelpSection, HelpSectionRenderer, HelpSectionKeyValueTable, Hook, Interfaces, Parser, Plugin, run, toStandardizedId, toConfiguredId, settings, Settings, flush, ux, execute, stderr, stdout, } from '@oclif/core';
22
+ export { Args, CommandHelp, Config, Errors, Flags, loadHelpClass, Help, HelpBase, HelpSection, HelpSectionRenderer, HelpSectionKeyValueTable, Hook, Interfaces, Parser, Plugin, run, toStandardizedId, toConfiguredId, settings, Settings, flush, ux, execute, } from '@oclif/core';
22
23
  export { FlagInput, ArgInput, FlagDefinition } from '@oclif/core/lib/interfaces/parser';
23
24
  export { default as TablePrompt } from './inquirer-table-prompt';
24
25
  export { Logger };
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.authenticationHandler = exports.Logger = exports.TablePrompt = exports.stdout = exports.stderr = exports.execute = exports.ux = exports.flush = exports.settings = exports.toConfiguredId = exports.toStandardizedId = exports.run = exports.Plugin = exports.Parser = exports.Interfaces = exports.HelpBase = exports.Help = exports.loadHelpClass = exports.Flags = exports.Errors = exports.Config = exports.CommandHelp = exports.Args = exports.marketplaceSDKInitiator = exports.MarketplaceSDKInitiator = exports.marketplaceSDKClient = exports.Command = exports.flags = exports.args = exports.NodeCrypto = exports.printFlagDeprecation = exports.managementSDKInitiator = exports.managementSDKClient = exports.configHandler = exports.authHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.LoggerService = void 0;
3
+ exports.authenticationHandler = exports.Logger = exports.TablePrompt = exports.execute = exports.ux = exports.flush = exports.settings = exports.toConfiguredId = exports.toStandardizedId = exports.run = exports.Plugin = exports.Parser = exports.Interfaces = exports.HelpBase = exports.Help = exports.loadHelpClass = exports.Flags = exports.Errors = exports.Config = exports.CommandHelp = exports.Args = exports.marketplaceSDKInitiator = exports.MarketplaceSDKInitiator = exports.marketplaceSDKClient = exports.CLITable = exports.Command = exports.flags = exports.args = exports.NodeCrypto = exports.printFlagDeprecation = exports.managementSDKInitiator = exports.managementSDKClient = exports.configHandler = exports.authHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.LoggerService = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const logger_1 = tslib_1.__importDefault(require("./logger"));
6
6
  exports.Logger = logger_1.default;
@@ -38,6 +38,8 @@ tslib_1.__exportStar(require("./interfaces"), exports);
38
38
  tslib_1.__exportStar(require("./date-time"), exports);
39
39
  tslib_1.__exportStar(require("./add-locale"), exports);
40
40
  tslib_1.__exportStar(require("./path-validator"), exports);
41
+ var cli_table_1 = require("./cli-table");
42
+ Object.defineProperty(exports, "CLITable", { enumerable: true, get: function () { return tslib_1.__importDefault(cli_table_1).default; } });
41
43
  // NOTE Exporting all @oclif/core modules: So that all the module can be acessed through cli-utility
42
44
  var core_1 = require("@oclif/core");
43
45
  Object.defineProperty(exports, "Args", { enumerable: true, get: function () { return core_1.Args; } });
@@ -58,8 +60,6 @@ Object.defineProperty(exports, "settings", { enumerable: true, get: function ()
58
60
  Object.defineProperty(exports, "flush", { enumerable: true, get: function () { return core_1.flush; } });
59
61
  Object.defineProperty(exports, "ux", { enumerable: true, get: function () { return core_1.ux; } });
60
62
  Object.defineProperty(exports, "execute", { enumerable: true, get: function () { return core_1.execute; } });
61
- Object.defineProperty(exports, "stderr", { enumerable: true, get: function () { return core_1.stderr; } });
62
- Object.defineProperty(exports, "stdout", { enumerable: true, get: function () { return core_1.stdout; } });
63
63
  var inquirer_table_prompt_1 = require("./inquirer-table-prompt");
64
64
  Object.defineProperty(exports, "TablePrompt", { enumerable: true, get: function () { return tslib_1.__importDefault(inquirer_table_prompt_1).default; } });
65
65
  var authentication_handler_1 = require("./authentication-handler");
@@ -1,4 +1,10 @@
1
- import { IPromptOptions } from '@oclif/core/lib/cli-ux';
1
+ export interface IPromptOptions {
2
+ prompt?: string;
3
+ type?: 'normal' | 'mask' | 'hide' | 'single';
4
+ timeout?: number;
5
+ required?: boolean;
6
+ default?: string;
7
+ }
2
8
  export interface PrintOptions {
3
9
  bold?: boolean;
4
10
  color?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentstack/cli-utilities",
3
- "version": "1.8.4",
3
+ "version": "1.10.0",
4
4
  "description": "Utilities for contentstack projects",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -34,10 +34,11 @@
34
34
  "dependencies": {
35
35
  "@contentstack/management": "~1.18.4",
36
36
  "@contentstack/marketplace-sdk": "^1.2.5",
37
- "@oclif/core": "^3.27.0",
37
+ "@oclif/core": "^4.2.7",
38
38
  "axios": "^1.8.2",
39
39
  "chalk": "^4.1.2",
40
40
  "cli-cursor": "^3.1.0",
41
+ "cli-progress": "^3.12.0",
41
42
  "cli-table": "^0.3.11",
42
43
  "conf": "^10.2.0",
43
44
  "dotenv": "^16.4.7",
@@ -45,14 +46,17 @@
45
46
  "inquirer": "8.2.6",
46
47
  "inquirer-search-checkbox": "^1.0.0",
47
48
  "inquirer-search-list": "^1.2.6",
49
+ "js-yaml": "^4.1.0",
48
50
  "klona": "^2.0.6",
49
51
  "lodash": "^4.17.21",
50
52
  "mkdirp": "^1.0.4",
51
53
  "open": "^8.4.2",
52
54
  "ora": "^5.4.1",
55
+ "papaparse": "^5.5.2",
53
56
  "recheck": "~4.4.5",
54
57
  "rxjs": "^6.6.7",
55
58
  "traverse": "^0.6.11",
59
+ "tty-table": "^4.2.3",
56
60
  "unique-string": "^2.0.0",
57
61
  "uuid": "^9.0.1",
58
62
  "winston": "^3.17.0",
@@ -68,7 +72,7 @@
68
72
  "@types/traverse": "^0.6.37",
69
73
  "chai": "^4.5.0",
70
74
  "eslint": "^8.57.1",
71
- "eslint-config-oclif": "^4.0.0",
75
+ "eslint-config-oclif": "^6.0.15",
72
76
  "eslint-config-oclif-typescript": "^3.1.14",
73
77
  "fancy-test": "^2.0.42",
74
78
  "mocha": "10.8.2",