contensis-cli 1.0.0-beta.5

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.
Files changed (95) hide show
  1. package/.vscode/launch.json +15 -0
  2. package/README.md +631 -0
  3. package/cli.js +7 -0
  4. package/dist/commands/connect.js +44 -0
  5. package/dist/commands/connect.js.map +7 -0
  6. package/dist/commands/create.js +55 -0
  7. package/dist/commands/create.js.map +7 -0
  8. package/dist/commands/get.js +121 -0
  9. package/dist/commands/get.js.map +7 -0
  10. package/dist/commands/globalOptions.js +139 -0
  11. package/dist/commands/globalOptions.js.map +7 -0
  12. package/dist/commands/import.js +95 -0
  13. package/dist/commands/import.js.map +7 -0
  14. package/dist/commands/index.js +81 -0
  15. package/dist/commands/index.js.map +7 -0
  16. package/dist/commands/list.js +88 -0
  17. package/dist/commands/list.js.map +7 -0
  18. package/dist/commands/login.js +56 -0
  19. package/dist/commands/login.js.map +7 -0
  20. package/dist/commands/push.js +133 -0
  21. package/dist/commands/push.js.map +7 -0
  22. package/dist/commands/remove.js +77 -0
  23. package/dist/commands/remove.js.map +7 -0
  24. package/dist/commands/set.js +55 -0
  25. package/dist/commands/set.js.map +7 -0
  26. package/dist/index.js +32 -0
  27. package/dist/index.js.map +7 -0
  28. package/dist/localisation/en-GB.js +203 -0
  29. package/dist/localisation/en-GB.js.map +7 -0
  30. package/dist/models/AppError.d.js +2 -0
  31. package/dist/models/AppError.d.js.map +7 -0
  32. package/dist/models/Cache.d.js +2 -0
  33. package/dist/models/Cache.d.js.map +7 -0
  34. package/dist/models/JsModules.d.js +2 -0
  35. package/dist/models/JsModules.d.js.map +7 -0
  36. package/dist/providers/CredentialProvider.js +87 -0
  37. package/dist/providers/CredentialProvider.js.map +7 -0
  38. package/dist/providers/SessionCacheProvider.js +91 -0
  39. package/dist/providers/SessionCacheProvider.js.map +7 -0
  40. package/dist/providers/file-provider.js +113 -0
  41. package/dist/providers/file-provider.js.map +7 -0
  42. package/dist/services/ContensisAuthService.js +75 -0
  43. package/dist/services/ContensisAuthService.js.map +7 -0
  44. package/dist/services/ContensisCliService.js +1110 -0
  45. package/dist/services/ContensisCliService.js.map +7 -0
  46. package/dist/shell.js +261 -0
  47. package/dist/shell.js.map +7 -0
  48. package/dist/util/console.printer.js +194 -0
  49. package/dist/util/console.printer.js.map +7 -0
  50. package/dist/util/csv.formatter.js +50 -0
  51. package/dist/util/csv.formatter.js.map +7 -0
  52. package/dist/util/index.js +94 -0
  53. package/dist/util/index.js.map +7 -0
  54. package/dist/util/json.formatter.js +29 -0
  55. package/dist/util/json.formatter.js.map +7 -0
  56. package/dist/util/logger.js +184 -0
  57. package/dist/util/logger.js.map +7 -0
  58. package/dist/util/xml.formatter.js +51 -0
  59. package/dist/util/xml.formatter.js.map +7 -0
  60. package/dist/version.js +29 -0
  61. package/dist/version.js.map +7 -0
  62. package/esbuild.config.js +49 -0
  63. package/headless-setup.sh +7 -0
  64. package/package.json +59 -0
  65. package/patches/inquirer-command-prompt+0.1.0.patch +27 -0
  66. package/src/commands/connect.ts +23 -0
  67. package/src/commands/create.ts +41 -0
  68. package/src/commands/get.ts +139 -0
  69. package/src/commands/globalOptions.ts +126 -0
  70. package/src/commands/import.ts +89 -0
  71. package/src/commands/index.ts +72 -0
  72. package/src/commands/list.ts +90 -0
  73. package/src/commands/login.ts +33 -0
  74. package/src/commands/push.ts +120 -0
  75. package/src/commands/remove.ts +77 -0
  76. package/src/commands/set.ts +40 -0
  77. package/src/index.ts +19 -0
  78. package/src/localisation/en-GB.ts +211 -0
  79. package/src/models/AppError.d.ts +40 -0
  80. package/src/models/Cache.d.ts +25 -0
  81. package/src/models/JsModules.d.ts +1 -0
  82. package/src/providers/CredentialProvider.ts +88 -0
  83. package/src/providers/SessionCacheProvider.ts +74 -0
  84. package/src/providers/file-provider.ts +72 -0
  85. package/src/services/ContensisAuthService.ts +70 -0
  86. package/src/services/ContensisCliService.ts +1390 -0
  87. package/src/shell.ts +250 -0
  88. package/src/util/console.printer.ts +203 -0
  89. package/src/util/csv.formatter.ts +21 -0
  90. package/src/util/index.ts +67 -0
  91. package/src/util/json.formatter.ts +1 -0
  92. package/src/util/logger.ts +165 -0
  93. package/src/util/xml.formatter.ts +20 -0
  94. package/src/version.ts +1 -0
  95. package/tsconfig.json +22 -0
package/src/shell.ts ADDED
@@ -0,0 +1,250 @@
1
+ import path from 'path';
2
+ import figlet from 'figlet';
3
+ import inquirer from 'inquirer';
4
+ import inquirerPrompt from 'inquirer-command-prompt';
5
+ import commands from './commands';
6
+ import { LogMessages } from './localisation/en-GB';
7
+ import { logError, Logger } from './util/logger';
8
+ import CredentialProvider from './providers/CredentialProvider';
9
+ import ContensisCli, { cliCommand } from './services/ContensisCliService';
10
+ import { Logging } from './util';
11
+
12
+ class ContensisShell {
13
+ private currentEnvironment!: string;
14
+ private emptyInputCounter: number = 0;
15
+ private env!: EnvironmentCache;
16
+ private firstStart = true;
17
+ private userId: string = '';
18
+ private log = Logger;
19
+ private messages = LogMessages;
20
+
21
+ private refreshEnvironment = () => {
22
+ // Reload any persisted changes from the disk cache
23
+ const {
24
+ cache: { currentEnvironment = '', environments = {} },
25
+ } = new ContensisCli([]);
26
+ // console.log(`refreshing env w/${currentEnvironment}`);
27
+ this.currentEnvironment = currentEnvironment;
28
+ this.env = environments[currentEnvironment];
29
+
30
+ // Reload logging here to support changing language
31
+ Logging('en-GB').then(({ messages, Log }) => {
32
+ this.log = Log;
33
+ this.messages = messages;
34
+ });
35
+ };
36
+
37
+ constructor() {
38
+ this.refreshEnvironment();
39
+ inquirerPrompt.setConfig({
40
+ history: {
41
+ save: true,
42
+ folder: path.join(__dirname, '../'),
43
+ limit: 100,
44
+ blacklist: ['quit'],
45
+ },
46
+ });
47
+ // inquirer.registerPrompt('command', inquirerPrompt);
48
+
49
+ const { log, messages } = this;
50
+
51
+ figlet.text(
52
+ messages.app.contensis(),
53
+ {
54
+ font: 'Block',
55
+ horizontalLayout: 'default',
56
+ verticalLayout: 'default',
57
+ width: process.stdout.columns,
58
+ whitespaceBreak: true,
59
+ },
60
+ (err, data) => {
61
+ if (err) {
62
+ log.error(messages.app.unknownError());
63
+ console.dir(err);
64
+ return;
65
+ }
66
+ console.log(log.successText(data));
67
+ console.log(log.infoText(messages.app.startup()));
68
+ console.log(log.helpText(messages.app.help()));
69
+
70
+ this.start().catch(ex => log.error(ex));
71
+ }
72
+ );
73
+ }
74
+
75
+ start = async () => {
76
+ this.log.line();
77
+ this.refreshEnvironment();
78
+ this.userId = '';
79
+ const { currentEnvironment, env, log, messages } = this;
80
+
81
+ if (env?.lastUserId) {
82
+ const [credsErr, credentials] = await new CredentialProvider(
83
+ {
84
+ userId: env.lastUserId,
85
+ alias: currentEnvironment,
86
+ },
87
+ env.passwordFallback
88
+ ).Init();
89
+ if (credsErr && !credentials.current) {
90
+ log.error(credsErr.message);
91
+ }
92
+ if (credentials.current) {
93
+ if (this.firstStart) {
94
+ const token = await cliCommand(['login', env.lastUserId]).Login(
95
+ env.lastUserId,
96
+ {
97
+ promptPassword: false,
98
+ silent: true,
99
+ }
100
+ );
101
+ if (token) this.userId = env.lastUserId;
102
+ this.firstStart = false;
103
+ this.refreshEnvironment();
104
+ } else {
105
+ this.userId = env.lastUserId;
106
+ }
107
+ }
108
+ }
109
+ await this.contensisPrompt();
110
+ };
111
+
112
+ contensisPrompt = async (): Promise<any> => {
113
+ const { currentEnvironment, env, log, messages, userId } = this;
114
+
115
+ const availableCommands = [
116
+ {
117
+ filter: (str: string) => {
118
+ return str.replace(/ \[.*$/, '');
119
+ },
120
+ },
121
+ 'connect',
122
+ 'list envs',
123
+ 'quit',
124
+ ];
125
+
126
+ if (currentEnvironment)
127
+ availableCommands.push('login', 'list projects', 'set project');
128
+ if (userId)
129
+ availableCommands.push(
130
+ 'get block',
131
+ 'get block logs',
132
+ 'get contenttype',
133
+ 'get component',
134
+ 'get entries',
135
+ 'import contenttypes',
136
+ 'import components',
137
+ 'import entries',
138
+ 'list blocks',
139
+ 'list contenttypes',
140
+ 'list components',
141
+ 'list models',
142
+ 'list keys',
143
+ 'list webhooks',
144
+ 'create key',
145
+ 'push block',
146
+ 'remove key',
147
+ 'remove entry',
148
+ 'remove contenttypes',
149
+ 'remove components'
150
+ );
151
+
152
+ const prompt = inquirer.createPromptModule();
153
+ prompt.registerPrompt('command', inquirerPrompt);
154
+ return prompt([
155
+ {
156
+ type: 'command',
157
+ name: 'cmd',
158
+ autoCompletion: availableCommands,
159
+ autocompletePrompt: log.infoText(messages.app.autocomplete()),
160
+ message: `${userId ? `${userId}@` : ''}${currentEnvironment || ''}>`,
161
+ context: 0,
162
+ validate: (val: string) => {
163
+ if (!val) this.emptyInputCounter++;
164
+ if (this.emptyInputCounter > 1)
165
+ console.log(this.log.infoText(this.messages.app.suggestions()));
166
+ if (val) {
167
+ this.emptyInputCounter = 0;
168
+ return true;
169
+ }
170
+ },
171
+ prefix: `${env?.currentProject || 'contensis'}`,
172
+ short: true,
173
+ },
174
+ ])
175
+ .then(async (answers: { cmd: string }) => {
176
+ if (answers.cmd === 'quit') {
177
+ this.quit();
178
+ } else {
179
+ try {
180
+ if (answers.cmd) {
181
+ const program = commands();
182
+ await program.parseAsync(
183
+ answers.cmd
184
+ .match(/"[^"]+"|[^\s]+/g)
185
+ ?.map(e => e.replace(/"(.+)"/, '$1')),
186
+ {
187
+ from: 'user',
188
+ }
189
+ );
190
+ }
191
+ } catch (ex: any) {
192
+ const str = ex.toString();
193
+ if (!str.includes('CommanderError'))
194
+ logError(ex, `Shell ${ex.toString()}`);
195
+ } finally {
196
+ return this.contensisPrompt();
197
+ }
198
+ }
199
+ })
200
+ .catch((err: Error) => {
201
+ log.error(err.message);
202
+ this.quit();
203
+ });
204
+ };
205
+
206
+ quit = (error?: Error) => {
207
+ const { log, messages } = this;
208
+ process.removeAllListeners('exit');
209
+
210
+ if (error) {
211
+ log.error(error.message);
212
+ process.exit(1);
213
+ } else {
214
+ log.success(messages.app.quit());
215
+ process.exitCode = 0;
216
+ process.exit(0);
217
+ }
218
+ };
219
+ }
220
+
221
+ let globalShell: ContensisShell;
222
+
223
+ export const shell = () => {
224
+ if (typeof process.argv?.[2] !== 'undefined') return { start() {} } as any;
225
+ if (!globalShell) globalShell = new ContensisShell();
226
+ return globalShell;
227
+ };
228
+
229
+ process.on('uncaughtException', function (err) {
230
+ // Handle the error safely
231
+ console.log(err);
232
+ });
233
+
234
+ process.on('SIGINT', () => {
235
+ console.log('catching SIGINT');
236
+ shell().quit();
237
+ });
238
+
239
+ process.on('SIGTERM', () => {
240
+ console.log('catching SIGTERM');
241
+ shell().quit();
242
+ });
243
+
244
+ process.stdin.on('data', key => {
245
+ if ((key as any) == '\u0003') {
246
+ console.log('');
247
+ Logger.info(`[CTRL]+[C] detected, exiting shell...`);
248
+ shell().quit();
249
+ }
250
+ });
@@ -0,0 +1,203 @@
1
+ import dayjs from 'dayjs';
2
+ import { BlockVersion, MigrateStatus } from 'migratortron';
3
+ import ContensisCli from '~/services/ContensisCliService';
4
+
5
+ const formatDate = (date: Date | string, format = 'DD/MM/YYYY HH:mm') =>
6
+ dayjs(date).format(format);
7
+
8
+ export const printBlockVersion = (
9
+ { log, messages }: ContensisCli,
10
+ block: BlockVersion,
11
+ printOptions = {
12
+ showSource: true,
13
+ showStatus: true,
14
+ showStaticPaths: true,
15
+ showImage: true,
16
+ }
17
+ ) => {
18
+ console.log(
19
+ ` ${log.standardText(`v${block.version.versionNo}`)} ${block.id}`
20
+ );
21
+ console.log(
22
+ ` state: ${messages.blocks.runningStatus(
23
+ block.status.broken ? 'broken' : block.status.running.global
24
+ )}`
25
+ );
26
+ console.log(
27
+ ` released: ${log.infoText(
28
+ block.version.released
29
+ ? `[${formatDate(block.version.released)}] ${block.version.releasedBy}`
30
+ : 'no'
31
+ )}`
32
+ );
33
+ if (block.version.madeLive)
34
+ console.log(
35
+ ` live: ${log.infoText(
36
+ `[${formatDate(block.version.madeLive)}] ${block.version.madeLiveBy}`
37
+ )}`
38
+ );
39
+ if (printOptions.showStatus) {
40
+ console.log(` status:`);
41
+ console.log(` deployment: ${log.infoText(block.status.deployment)}`);
42
+ console.log(` workflow: ${log.infoText(block.status.workflow)}`);
43
+ console.log(
44
+ ` running status: ${messages.blocks.runningStatus(
45
+ block.status.running.global
46
+ )}`
47
+ );
48
+ console.log(` datacentres:`);
49
+ console.log(
50
+ ` hq: ${messages.blocks.runningStatus(
51
+ block.status.running.dataCenters.hq
52
+ )}`
53
+ );
54
+ console.log(
55
+ ` london: ${messages.blocks.runningStatus(
56
+ block.status.running.dataCenters.london
57
+ )}`
58
+ );
59
+ console.log(
60
+ ` manchester: ${messages.blocks.runningStatus(
61
+ block.status.running.dataCenters.manchester
62
+ )}`
63
+ );
64
+ }
65
+ if (printOptions.showSource) {
66
+ console.log(` source:`);
67
+ console.log(` commit: ${log.helpText(block.source.commit.id)}`);
68
+ console.log(
69
+ ` message: ${log.infoText(
70
+ block.source.commit.message
71
+ ?.replaceAll('\n', '\\n')
72
+ .replaceAll('\\n\\n', '\\n')
73
+ .replaceAll('\\n', '; ')
74
+ )}`
75
+ );
76
+ console.log(
77
+ ` committed: ${log.infoText(
78
+ `[${formatDate(block.source.commit.dateTime)}] ${
79
+ block.source.commit.authorEmail
80
+ }`
81
+ )}`
82
+ );
83
+ console.log(
84
+ ` pushed: ${log.infoText(
85
+ `[${formatDate(block.version.pushed)}] ${block.version.pushedBy}`
86
+ )}`
87
+ );
88
+ console.log(` ${log.infoText(block.source.commit.commitUrl)}`);
89
+ }
90
+ if (printOptions.showImage) {
91
+ console.log(` image:`);
92
+ console.log(` uri: ${log.infoText(block.image.uri)}`);
93
+ console.log(` tag: ${log.helpText(block.image.tag)}`);
94
+ }
95
+ if (printOptions.showStaticPaths) {
96
+ if (block.staticPaths?.length) {
97
+ console.log(` static paths:`);
98
+ for (const path of block.staticPaths) console.log(` - ${path}`);
99
+ }
100
+ }
101
+ if (block.stagingUrl)
102
+ console.log(` staging url: ${log.infoText(block.stagingUrl)}`);
103
+ console.log('');
104
+ };
105
+
106
+ export const printMigrateResult = (
107
+ { log, messages, contensis, currentProject }: ContensisCli,
108
+ migrateResult: any,
109
+ { action = 'import' }: { action?: 'import' | 'delete' } = {}
110
+ ) => {
111
+ console.log(``);
112
+
113
+ if (action === 'import') {
114
+ for (const [projectId, contentTypeCounts] of Object.entries(
115
+ migrateResult.entries || {}
116
+ ) as [string, any][]) {
117
+ console.log(
118
+ `import from project ${log.highlightText(projectId)} to ${log.boldText(
119
+ log.successText(currentProject)
120
+ )}`
121
+ );
122
+ for (const [contentTypeId, count] of Object.entries(
123
+ contentTypeCounts
124
+ ) as [string, number][]) {
125
+ const entriesToMigrate =
126
+ migrateResult.entriesToMigrate?.[projectId]?.[contentTypeId];
127
+
128
+ console.log(
129
+ ` - ${
130
+ contentTypeId === 'totalCount'
131
+ ? log.warningText(`${contentTypeId}: ${count}`)
132
+ : log.helpText(`${contentTypeId}: ${count}`)
133
+ } ${log.infoText`[existing: ${(
134
+ ((migrateResult.existing?.[projectId]?.[contentTypeId] || 0) /
135
+ count) *
136
+ 100
137
+ ).toFixed(0)}%]`} [${
138
+ typeof entriesToMigrate !== 'number' ? `unchanged` : `to update`
139
+ }: ${(
140
+ ((typeof entriesToMigrate !== 'number'
141
+ ? entriesToMigrate?.['no change'] || 0
142
+ : entriesToMigrate) /
143
+ count) *
144
+ 100
145
+ ).toFixed(0)}%]`
146
+ );
147
+ }
148
+ console.log(``);
149
+ }
150
+ }
151
+ if (
152
+ contensis?.isPreview &&
153
+ migrateResult.entriesToMigrate?.[currentProject]?.totalCount > 0 &&
154
+ !migrateResult.errors
155
+ ) {
156
+ log.help(messages.entries.commitTip());
157
+ }
158
+ for (const [contentTypeId, entryRes] of Object.entries(
159
+ migrateResult.entriesToMigrate.entryIds
160
+ ) as [string, any]) {
161
+ for (const [originalId, entryStatus] of Object.entries(entryRes) as [
162
+ string,
163
+ any
164
+ ][]) {
165
+ console.log(
166
+ log.infoText(
167
+ `${originalId} [${Object.entries(entryStatus || {})
168
+ .filter(x => x[0] !== 'entryTitle')
169
+ .map(([projectId, projectStatus]) => {
170
+ const [targetGuid, { status }] = (Object.entries(
171
+ projectStatus || {}
172
+ )?.[0] as [string, { status: MigrateStatus }]) || [
173
+ '',
174
+ { x: { status: undefined } },
175
+ ];
176
+ return `${messages.entries.migrateStatus(status)(
177
+ `${projectId}: ${status}`
178
+ )}${targetGuid !== originalId ? `-> ${targetGuid}` : ''}`;
179
+ })}]`
180
+ )
181
+ );
182
+ console.log(` ${log.helpText(contentTypeId)} ${entryStatus.entryTitle}`);
183
+
184
+ for (const [projectId, projectStatus] of Object.entries(
185
+ entryStatus
186
+ ).filter(([key]) => key !== 'entryTitle') as [string, any][]) {
187
+ const [targetGuid, { error, diff, status }] = Object.entries(
188
+ projectStatus
189
+ )[0] as [string, any];
190
+ if (error) log.error(error);
191
+ if (diff) {
192
+ console.log(
193
+ ` ${messages.entries.migrateStatus(status)(status)} ${log.infoText(
194
+ targetGuid
195
+ )} ${log.infoText(contentTypeId)} ${log.infoText(projectId)}`
196
+ );
197
+ console.log(``);
198
+ console.log(log.highlightText(diff));
199
+ }
200
+ }
201
+ }
202
+ }
203
+ };
@@ -0,0 +1,21 @@
1
+ import { flatten } from 'flat';
2
+ import { Parser } from 'json2csv';
3
+ import cleaner from 'deep-cleaner';
4
+
5
+ const flattenObject = (obj: any) => flatten(cleaner(obj, ['workflow']));
6
+
7
+ export const csvFormatter = <T>(entries: T | T[]) => {
8
+ // Flatten the passed in object
9
+ const flatEntries = [];
10
+ if (Array.isArray(entries))
11
+ for (const entry of entries) {
12
+ flatEntries.push(flattenObject(entry));
13
+ }
14
+ else flatEntries.push(flattenObject(entries));
15
+
16
+ // Parse the flattened object to csv
17
+ const json2csvParser = new Parser();
18
+ const csv = json2csvParser.parse(flatEntries);
19
+
20
+ return csv;
21
+ };
@@ -0,0 +1,67 @@
1
+ import mergeWith from 'lodash/mergeWith';
2
+ import { Logger } from './logger';
3
+
4
+ export const isSharedSecret = (str = '') =>
5
+ str.length > 80 && str.split('-').length === 3 ? str : undefined;
6
+
7
+ export const isPassword = (str = '') =>
8
+ !isSharedSecret(str) ? str : undefined;
9
+
10
+ export const tryParse = (str: string) => {
11
+ try {
12
+ return typeof str === 'object' ? str : JSON.parse(str);
13
+ } catch (e) {
14
+ return false;
15
+ }
16
+ };
17
+
18
+ export const isJson = (str: string) =>
19
+ typeof str === 'object' || !!tryParse(str);
20
+
21
+ export const tryStringify = (obj: any) => {
22
+ try {
23
+ return typeof obj === 'object' ? JSON.stringify(obj) : obj;
24
+ } catch (e) {
25
+ return obj;
26
+ }
27
+ };
28
+
29
+ export const isUuid = (str: string) => {
30
+ // Regular expression to check if string is a valid UUID
31
+ const regexExp =
32
+ /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi;
33
+
34
+ return regexExp.test(str);
35
+ };
36
+
37
+ export const url = (alias: string, project: string) => {
38
+ const projectAndAlias =
39
+ project && project.toLowerCase() !== 'website'
40
+ ? `${project.toLowerCase()}-${alias}`
41
+ : alias;
42
+ return {
43
+ api: `https://api-${alias}.cloud.contensis.com`,
44
+ cms: `https://cms-${alias}.cloud.contensis.com`,
45
+ liveWeb: `https://live-${projectAndAlias}.cloud.contensis.com`,
46
+ previewWeb: `https://preview-${projectAndAlias}.cloud.contensis.com`,
47
+ iisWeb: `https://iis-live-${projectAndAlias}.cloud.contensis.com`,
48
+ iisPreviewWeb: `https://iis-preview-${projectAndAlias}.cloud.contensis.com`,
49
+ };
50
+ };
51
+
52
+ export const Logging = async (language = 'en-GB') => {
53
+ const { LogMessages: defaultMessages } = await import(
54
+ `../localisation/en-GB.js`
55
+ );
56
+ const { LogMessages: localisedMessages } = await import(
57
+ `../localisation/${language}.js`
58
+ );
59
+ return {
60
+ messages: mergeWith(
61
+ localisedMessages,
62
+ defaultMessages,
63
+ (v, s) => v || s
64
+ ) as typeof defaultMessages,
65
+ Log: Logger,
66
+ };
67
+ };
@@ -0,0 +1 @@
1
+ export const jsonFormatter = <T>(obj: T) => JSON.stringify(obj, null, 2);
@@ -0,0 +1,165 @@
1
+ /* eslint-disable no-console */
2
+ import chalk from 'chalk';
3
+ import dateFormat from 'dateformat';
4
+ import deepCleaner from 'deep-cleaner';
5
+ import ProgressBar from 'progress';
6
+ import { tryStringify } from '.';
7
+
8
+ type LogMethod = (content: string) => void;
9
+ type LogErrorMethod = (content: string, err?: any) => void;
10
+ type LogJsonMethod = (content: any) => void;
11
+ type LogArrayMethod = (contentArray: string[]) => void;
12
+ type LogErrorFunc = (
13
+ err: any,
14
+ msg?: string,
15
+ level?: 'error' | 'critical'
16
+ ) => void;
17
+
18
+ export class Logger {
19
+ static isUserTerminal = !!process.stdout.columns;
20
+ static getPrefix = () => {
21
+ return Logger.isUserTerminal
22
+ ? Logger.infoText(`[cli]`)
23
+ : `[${dateFormat(new Date(), 'dd/mm HH:MM:ss')}]`;
24
+ };
25
+ static errorText = chalk.bold.red;
26
+ static warningText = chalk.keyword('orange');
27
+ static successText = chalk.keyword('green');
28
+ static helpText = chalk.blue;
29
+ static highlightText = chalk.yellow;
30
+ static infoText = chalk.keyword('grey');
31
+ static standardText = chalk.keyword('white');
32
+ static boldText = chalk.bold;
33
+ static critical: LogMethod = content => {
34
+ const message = `${Logger.getPrefix()} ${Logger.errorText(
35
+ '[CRITICAL]'
36
+ )} ${content}`;
37
+ console.log(message);
38
+ };
39
+ static error: LogErrorMethod = (content, err) => {
40
+ const message = `${Logger.getPrefix()} ${Logger.errorText(
41
+ `${Logger.isUserTerminal ? '❌' : '[ERROR]'} ${content}${
42
+ err ? `\n\n${JSON.stringify(err, null, 2)}` : ''
43
+ }`
44
+ )}\n`;
45
+ if (progress.active) progress.current.interrupt(message);
46
+ else console.log(message);
47
+ };
48
+ static warning: LogMethod = content => {
49
+ // if (process.env.DEBUG === 'true') {
50
+ const message = `${Logger.getPrefix()} ${Logger.warningText(
51
+ `${Logger.isUserTerminal ? '⚠️ ' : '[WARN]'} ${content}`
52
+ )}\n`;
53
+ if (progress.active) progress.current.interrupt(message);
54
+ else console.log(message);
55
+ // }
56
+ };
57
+ static success: LogMethod = content => {
58
+ const message = `${Logger.getPrefix()} ${Logger.successText(
59
+ `${Logger.isUserTerminal ? '✅' : '[OK]'} ${content}`
60
+ )}`;
61
+ if (progress.active) progress.current.interrupt(message);
62
+ else console.log(message);
63
+ };
64
+ static info: LogMethod = content => {
65
+ const message = `${Logger.getPrefix()} ${
66
+ Logger.isUserTerminal ? chalk.bgCyan(' ℹ ') : '[INFO]'
67
+ } ${Logger.infoText(content)}`;
68
+ if (progress.active) progress.current.interrupt(message);
69
+ else console.log(message);
70
+ };
71
+ static help: LogMethod = content => {
72
+ const message = `${Logger.getPrefix()} ${chalk.blue(
73
+ `${Logger.isUserTerminal ? '⏩' : '[HELP]'} ${content}`
74
+ )}\n`;
75
+ if (progress.active) progress.current.interrupt(message);
76
+ else console.log(message);
77
+ };
78
+ static standard: LogMethod = content => {
79
+ const message = `${Logger.getPrefix()} ${
80
+ Logger.isUserTerminal ? '◻️' : '[STD]'
81
+ } \n${Logger.standardText(content)}`;
82
+ if (progress.active) progress.current.interrupt(message);
83
+ else console.log(message);
84
+ progress.current.interrupt(message);
85
+ };
86
+ static json: LogJsonMethod = (content, depth = 9) =>
87
+ console.dir(deepCleaner(content), { colors: true, depth });
88
+ static mixed: LogArrayMethod = contentArray =>
89
+ console.log(`${Logger.getPrefix()} ${contentArray.join(' ')}`);
90
+ static line = () =>
91
+ Logger.raw(` ${Logger.infoText(`-------------------------------------`)}`);
92
+
93
+ static object: LogJsonMethod = content => {
94
+ for (const [key, value] of Object.entries(content)) {
95
+ if (value && typeof value === 'object') {
96
+ Logger.raw(` ${chalk.bold.grey(key)}:`);
97
+ if (key === 'fields' && Array.isArray(value)) {
98
+ for (const field of value || []) {
99
+ Logger.raw(
100
+ ` ${chalk.bold(field.id)}: ${chalk.grey(field.dataType)}`
101
+ );
102
+ }
103
+ } else if (key === 'groups' && Array.isArray(value)) {
104
+ for (const group of value || []) {
105
+ const description =
106
+ Object.keys(group.description).length &&
107
+ Object.values(group.description)?.[0];
108
+ Logger.raw(
109
+ ` ${chalk.bold(group.id)}${
110
+ description
111
+ ? `: ${chalk.grey(Object.values(group.description)?.[0])}`
112
+ : ''
113
+ }`
114
+ );
115
+ }
116
+ } else {
117
+ for (const [innerkey, innervalue] of Object.entries(value)) {
118
+ if (innervalue && typeof innervalue === 'object') {
119
+ Logger.raw(` ${chalk.bold.grey(innerkey)}:`);
120
+ console.table(innervalue);
121
+ } else if (
122
+ typeof innervalue !== 'undefined' ||
123
+ innervalue !== null
124
+ ) {
125
+ Logger.raw(` ${chalk.bold.grey(innerkey)}: ${innervalue}`);
126
+ }
127
+ }
128
+ }
129
+ } else if (typeof value !== 'undefined' || value !== null) {
130
+ Logger.raw(` ${chalk.bold.grey(key)}: ${value}`);
131
+ }
132
+ }
133
+ };
134
+ static raw: LogMethod = (content: string) => {
135
+ if (progress.active) progress.current.interrupt(content);
136
+ else console.log(content);
137
+ };
138
+ }
139
+
140
+ export const logError: LogErrorFunc = (
141
+ err = new Error('Undefined error'),
142
+ msg,
143
+ level = 'error'
144
+ ) => {
145
+ Logger[level](msg || err.message || err?.data?.message || err.Message);
146
+ (Array.isArray(err) ? err : [err]).map((error: AppError) => {
147
+ if ('stack' in error) Logger.raw(` ${Logger.infoText(error.stack)}`);
148
+ if ('data' in error)
149
+ Logger.raw(` ${Logger.infoText(tryStringify(error.data))}`);
150
+ });
151
+ //Logger.line();
152
+ return null;
153
+ };
154
+
155
+ export const progress = {
156
+ active: false,
157
+ done: () => new ProgressBar('', 0),
158
+ colours: { green: '\u001b[42m \u001b[0m', red: '\u001b[41m \u001b[0m' },
159
+ current: new ProgressBar(`:bar`, {
160
+ complete: '=',
161
+ incomplete: ' ',
162
+ width: 20,
163
+ total: 100,
164
+ }),
165
+ };