@raisenow/tamaro-cli 1.0.26 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,20 +1,21 @@
1
1
  import {existsSync} from 'fs'
2
2
  import stripIndent from 'strip-indent'
3
+ import {
4
+ assertProfilesPresent,
5
+ type AwsOptions,
6
+ prepareFlags,
7
+ promptProfile,
8
+ withAwsAuthenticate,
9
+ } from 'lib/aws'
10
+ import {halt, runCommandSync} from 'lib/command'
3
11
  import {
4
12
  AWS_CLOUDFRONT_DISTRIBUTION_ID,
5
13
  AWS_S3_BUCKET,
6
14
  CORE_CONFIG_NAME,
7
15
  } from 'lib/constants'
8
- import {
9
- assertProfileValid,
10
- AwsOptions,
11
- withAwsAuthenticate,
12
- prepareFlags as prepareAwsFlags,
13
- } from 'lib/aws'
14
- import {getIfCoreFns, getPaths, getWidgetUuid} from 'lib/resolve'
15
16
  import {logCommand, logDataTable, logTitle} from 'lib/logging'
16
17
  import {notify} from 'lib/notifier'
17
- import {halt, runCommandSync} from 'lib/command'
18
+ import {getIfCoreFns, getPaths, getWidgetUuid} from 'lib/resolve'
18
19
 
19
20
  ///////////////////////////////////////////////////////////////////////////////
20
21
 
@@ -31,6 +32,11 @@ export const deploy = async (options: DeployOptions): Promise<void> => {
31
32
  assertOptionsValid(options)
32
33
  assertDistPathExists(paths.appDist)
33
34
 
35
+ if (!options.ci) {
36
+ assertProfilesPresent()
37
+ options.profile = await promptProfile()
38
+ }
39
+
34
40
  const flags = prepareFlags([], options).join(' ')
35
41
  const {tag} = options
36
42
  const configName = ifCore(CORE_CONFIG_NAME, getWidgetUuid())
@@ -106,7 +112,7 @@ export const deploy = async (options: DeployOptions): Promise<void> => {
106
112
  const demoPage = `https://${AWS_S3_BUCKET}/${configName}/${tag}/index.html`
107
113
  const entryPoint = `https://${AWS_S3_BUCKET}/${configName}/${tag}/${entryFilename}`
108
114
 
109
- logTitle(`\nBundle for “${configName} is deployed with tag “${tag}”.`)
115
+ logTitle(`\nBundle for "${configName}" is deployed with tag "${tag}".`)
110
116
  logDataTable({
111
117
  'Demo page:': demoPage,
112
118
  'Entry point:': entryPoint,
@@ -118,7 +124,7 @@ export const deploy = async (options: DeployOptions): Promise<void> => {
118
124
  notify({
119
125
  title: 'deploy',
120
126
  message: `
121
- Bundle for “${configName} is deployed with tag “${tag}”.
127
+ Bundle for "${configName}" is deployed with tag "${tag}".
122
128
  Demo page: ${demoPage}
123
129
  Entry point: ${entryPoint}
124
130
  `,
@@ -129,10 +135,9 @@ export const deploy = async (options: DeployOptions): Promise<void> => {
129
135
  ///////////////////////////////////////////////////////////////////////////////
130
136
 
131
137
  const assertOptionsValid = (options: DeployOptions) => {
132
- const {tag, profile} = options
138
+ const {tag} = options
133
139
 
134
140
  assertTagValid(tag)
135
- assertProfileValid(profile)
136
141
  }
137
142
 
138
143
  ///////////////////////////////////////////////////////////////////////////////
@@ -155,13 +160,7 @@ const assertTagValid = (tag: string) => {
155
160
 
156
161
  if (!regex.test(tag)) {
157
162
  halt(
158
- `Flag “--tag has forbidden format. Allowed format: ${regex.toString()}.`,
163
+ `Flag "--tag" has forbidden format. Allowed format: ${regex.toString()}.`,
159
164
  )
160
165
  }
161
166
  }
162
-
163
- ///////////////////////////////////////////////////////////////////////////////
164
-
165
- const prepareFlags = (flags: string[], options: DeployOptions): string[] => {
166
- return prepareAwsFlags(flags, options)
167
- }
@@ -1,9 +1,9 @@
1
1
  import {getPortPromise} from 'portfinder'
2
- import {getIfCoreFns, resolveBin, resolveOwn} from 'lib/resolve'
3
- import {logCommand, logTitle} from 'lib/logging'
4
2
  import {halt, runCommandSync} from 'lib/command'
5
3
  import {applyEnv, assertEnvValid} from 'lib/env'
6
4
  import {assertCrtExists} from 'lib/https'
5
+ import {logCommand, logTitle} from 'lib/logging'
6
+ import {getIfCoreFns, resolveBin, resolveOwn} from 'lib/resolve'
7
7
 
8
8
  ///////////////////////////////////////////////////////////////////////////////
9
9
 
@@ -48,11 +48,11 @@ const assertOptionsValid = (options: DevOptions) => {
48
48
  const {ifCore} = getIfCoreFns()
49
49
 
50
50
  if (ifCore() && localCore) {
51
- halt('Flag “--local-core is redundant if running in Tamaro Core context.')
51
+ halt('Flag "--local-core" is redundant if running in Tamaro Core context.')
52
52
  }
53
53
 
54
54
  if (isNaN(Number(port))) {
55
- halt('Flag “--port should be a number.')
55
+ halt('Flag "--port" should be a number.')
56
56
  }
57
57
 
58
58
  if (https) {
@@ -1,13 +1,14 @@
1
- import {AWS_S3_BUCKET, CORE_CONFIG_NAME} from 'lib/constants'
2
1
  import {
3
- assertProfileValid,
4
- AwsOptions,
2
+ assertProfilesPresent,
3
+ type AwsOptions,
4
+ prepareFlags,
5
+ promptProfile,
5
6
  withAwsAuthenticate,
6
- prepareFlags as prepareAwsFlags,
7
7
  } from 'lib/aws'
8
- import {getIfCoreFns, getWidgetUuid} from 'lib/resolve'
9
- import {logCommand, logTitle} from 'lib/logging'
10
8
  import {halt, runCommandSync} from 'lib/command'
9
+ import {AWS_S3_BUCKET, CORE_CONFIG_NAME} from 'lib/constants'
10
+ import {logCommand, logTitle} from 'lib/logging'
11
+ import {getIfCoreFns, getWidgetUuid} from 'lib/resolve'
11
12
 
12
13
  ///////////////////////////////////////////////////////////////////////////////
13
14
 
@@ -22,6 +23,11 @@ export const listDeployed = async (
22
23
  ): Promise<void> => {
23
24
  assertOptionsValid(options)
24
25
 
26
+ if (!options.ci) {
27
+ assertProfilesPresent()
28
+ options.profile = await promptProfile()
29
+ }
30
+
25
31
  const flags = prepareFlags([], options).join(' ')
26
32
  const {config} = options
27
33
  const {ifCore} = getIfCoreFns()
@@ -29,7 +35,7 @@ export const listDeployed = async (
29
35
  const title =
30
36
  !config && ifCore()
31
37
  ? `Listing deployments of Tamaro Core …`
32
- : `Listing deployments of “${configName} customer configuration …`
38
+ : `Listing deployments of "${configName}" customer configuration …`
33
39
 
34
40
  const deployUrl = `s3://${AWS_S3_BUCKET}/${configName}/`
35
41
  const cmd = `aws s3 ls ${deployUrl} ${flags}`
@@ -44,7 +50,7 @@ export const listDeployed = async (
44
50
  const result = withAwsAuthenticate(() => runCommandSync(cmd), options)
45
51
  out = result.stdout
46
52
  } catch (error: any) {
47
- out = error.stdout
53
+ out = error.stdout as string
48
54
 
49
55
  if (error.stderr) {
50
56
  halt(error.stderr)
@@ -66,16 +72,16 @@ export const listDeployed = async (
66
72
  .join('\n')
67
73
  }
68
74
 
75
+ // eslint-disable-next-line no-console
69
76
  console.log(`${text}\n`)
70
77
  }
71
78
 
72
79
  ///////////////////////////////////////////////////////////////////////////////
73
80
 
74
81
  const assertOptionsValid = (options: ListDeployedOptions) => {
75
- const {config, profile} = options
82
+ const {config} = options
76
83
 
77
84
  assertConfigValid(config)
78
- assertProfileValid(profile)
79
85
  }
80
86
 
81
87
  ///////////////////////////////////////////////////////////////////////////////
@@ -89,22 +95,13 @@ const assertConfigValid = (config: string | undefined) => {
89
95
 
90
96
  if (!regex.test(config)) {
91
97
  halt(
92
- `Flag “--config has forbidden format. Allowed format: ${regex.toString()}.`,
98
+ `Flag "--config" has forbidden format. Allowed format: ${regex.toString()}.`,
93
99
  )
94
100
  }
95
101
  }
96
102
 
97
103
  ///////////////////////////////////////////////////////////////////////////////
98
104
 
99
- const prepareFlags = (
100
- flags: string[],
101
- options: ListDeployedOptions,
102
- ): string[] => {
103
- return prepareAwsFlags(flags, options)
104
- }
105
-
106
- ///////////////////////////////////////////////////////////////////////////////
107
-
108
105
  const parseTags = (lines: string[]): string[] => {
109
106
  const regex = /^\s*PRE\s*/
110
107
 
@@ -1,10 +1,10 @@
1
1
  import {resolve} from 'path'
2
2
  import {getPortPromise} from 'portfinder'
3
- import {getIfCoreFns, getPaths} from 'lib/resolve'
4
- import {logCommand, logTitle} from 'lib/logging'
5
3
  import {halt, runCommandSync} from 'lib/command'
6
- import {assertCrtExists} from 'lib/https'
7
4
  import {HTTPS_CRT_FILE, HTTPS_KEY_FILE} from 'lib/constants'
5
+ import {assertCrtExists} from 'lib/https'
6
+ import {logCommand, logTitle} from 'lib/logging'
7
+ import {getIfCoreFns, getPaths} from 'lib/resolve'
8
8
 
9
9
  ///////////////////////////////////////////////////////////////////////////////
10
10
 
@@ -1,10 +1,10 @@
1
- import {Compiler} from 'webpack'
2
- import HtmlWebpackPlugin from 'html-webpack-plugin'
3
1
  import escapeStringRegexp from 'escape-string-regexp'
2
+ import HtmlWebpackPlugin from 'html-webpack-plugin'
3
+ import {type Compiler} from 'webpack'
4
4
 
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
6
 
7
- export type Replacements = {[key: string]: string | undefined}
7
+ export type Replacements = Record<string, string | undefined>
8
8
 
9
9
  ///////////////////////////////////////////////////////////////////////////////
10
10
 
@@ -24,9 +24,9 @@ export class InterpolateHtmlPlugin {
24
24
  const hooks = HtmlWebpackPlugin.getHooks(compilation)
25
25
 
26
26
  hooks.alterAssetTagGroups.tap(PLUGIN_NAME, (assets) => {
27
- const publicUrl = this.replacements['PUBLIC_URL'] ?? ''
28
- const entry = assets.headTags[0].attributes['src'] as string
29
- this.replacements['ENTRY'] = `${publicUrl}${entry}`
27
+ const publicUrl = this.replacements.PUBLIC_URL ?? ''
28
+ const entry = assets.headTags[0].attributes.src as string
29
+ this.replacements.ENTRY = `${publicUrl}${entry}`
30
30
 
31
31
  return assets
32
32
  })
@@ -36,7 +36,7 @@ export class InterpolateHtmlPlugin {
36
36
  Object.entries(this.replacements).forEach(([key, value]) => {
37
37
  data.html = data.html.replace(
38
38
  new RegExp(`%${escapeStringRegexp(key)}%`, 'g'),
39
- value || '',
39
+ value ?? '',
40
40
  )
41
41
  })
42
42
 
package/src/lib/aws.ts CHANGED
@@ -1,11 +1,18 @@
1
1
  import {execaCommandSync} from 'execa'
2
+ // eslint-disable-next-line import/no-named-as-default
3
+ import prompts from 'prompts'
2
4
  import stripIndent from 'strip-indent'
3
5
  import {halt} from 'lib/command'
6
+ import {
7
+ AWS_S3_EMAIL_CONFIG_PROD_BUCKET,
8
+ AWS_S3_EMAIL_CONFIG_STAGE_BUCKET,
9
+ } from 'lib/constants'
4
10
 
5
11
  ///////////////////////////////////////////////////////////////////////////////
6
12
 
7
13
  export type AwsOptions = {
8
- profile: string
14
+ profile?: string
15
+ ci?: boolean
9
16
  }
10
17
 
11
18
  ///////////////////////////////////////////////////////////////////////////////
@@ -22,10 +29,10 @@ export const withAwsAuthenticate = <Result = any>(
22
29
  ///////////////////////////////////////////////////////////////////////////////
23
30
 
24
31
  export const awsAuthenticate = (options: AwsOptions) => {
25
- if (isSetEnv()) {
32
+ if (options.ci) {
26
33
  // Don't try to authenticate the user.
27
- // This may be useful if CLI is running within an automated system like pipeline,
28
- // where "AWS_ACCESS_KEY_ID" and "AWS_SECRET_ACCESS_KEY" are used instead of "AWS_PROFILE".
34
+ // This is done when CLI is running within an automated system like pipeline,
35
+ // In this case "AWS_ACCESS_KEY_ID" and "AWS_SECRET_ACCESS_KEY" are used instead of "AWS_PROFILE".
29
36
  return
30
37
  }
31
38
 
@@ -38,49 +45,24 @@ export const awsAuthenticate = (options: AwsOptions) => {
38
45
 
39
46
  ///////////////////////////////////////////////////////////////////////////////
40
47
 
41
- // Returns true if "AWS_ACCESS_KEY_ID" and "AWS_SECRET_ACCESS_KEY" environment variables are set.
42
- export const isSetEnv = () => {
43
- return !!(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY)
44
- }
45
-
46
- ///////////////////////////////////////////////////////////////////////////////
47
-
48
- export const assertProfileValid = (profile: string) => {
49
- if (isSetEnv()) {
50
- return
51
- }
52
-
48
+ export const assertProfilesPresent = () => {
53
49
  const profiles = getAvailableProfiles()
54
50
 
55
- if (!profiles.includes(profile)) {
56
- console.log(`Using AWS profile: “${profile}”`)
57
-
58
- let message
59
-
60
- if (profiles.length === 0) {
61
- message = stripIndent(`
51
+ if (profiles.length === 0) {
52
+ halt(
53
+ stripIndent(`
62
54
  No AWS profiles found.
63
- `)
64
- } else {
65
- message = stripIndent(`
66
- AWS profile “${profile}” has not been found.
67
- Available profiles are: ${profiles.map((v) => `“${v}”`).join(', ')}.
68
- `)
69
- }
70
-
71
- message += stripIndent(`
72
- Run “aws configure sso” to set up SSO-enabled profile.
73
- Check the wiki for more information:
74
- https://raisenow.atlassian.net/wiki/x/lIrWvg
75
- `)
76
-
77
- halt(message)
55
+ Run "aws configure sso" to set up SSO-enabled profile.
56
+ Check the wiki for more information:
57
+ https://raisenow.atlassian.net/wiki/x/lIrWvg
58
+ `),
59
+ )
78
60
  }
79
61
  }
80
62
 
81
63
  ///////////////////////////////////////////////////////////////////////////////
82
64
 
83
- const getAvailableProfiles = (): string[] => {
65
+ export const getAvailableProfiles = (): string[] => {
84
66
  const {stdout} = execaCommandSync('aws configure list-profiles')
85
67
 
86
68
  return stdout.split('\n')
@@ -105,6 +87,7 @@ const login = (options: AwsOptions) => {
105
87
 
106
88
  try {
107
89
  execaCommandSync(`aws sso login ${flags}`, {stdio: 'inherit'})
90
+ // eslint-disable-next-line no-console
108
91
  console.log('')
109
92
  } catch (error) {
110
93
  halt('Login failed.')
@@ -119,9 +102,58 @@ export const prepareFlags = (
119
102
  ): string[] => {
120
103
  const {profile} = options
121
104
 
122
- if (!isSetEnv()) {
105
+ if (profile) {
123
106
  flags.push(`--profile ${profile}`)
124
107
  }
125
108
 
126
109
  return flags
127
110
  }
111
+
112
+ ///////////////////////////////////////////////////////////////////////////////
113
+
114
+ export const promptProfile = async (): Promise<string | undefined> => {
115
+ const profiles = getAvailableProfiles()
116
+ .filter((v) => !!v)
117
+ .map((v) => ({title: v, value: v}))
118
+
119
+ const {profile} = await prompts(
120
+ [
121
+ {
122
+ type: 'select',
123
+ name: 'profile',
124
+ message: 'Select AWS profile',
125
+ choices: profiles,
126
+ },
127
+ ],
128
+ {
129
+ onCancel: () => process.exit(1),
130
+ },
131
+ )
132
+
133
+ return profile
134
+ }
135
+
136
+ ///////////////////////////////////////////////////////////////////////////////
137
+
138
+ export const promptBucket = async (): Promise<string> => {
139
+ const buckets = [
140
+ {title: 'stage', value: AWS_S3_EMAIL_CONFIG_STAGE_BUCKET},
141
+ {title: 'prod', value: AWS_S3_EMAIL_CONFIG_PROD_BUCKET},
142
+ ]
143
+
144
+ const {bucket} = await prompts(
145
+ [
146
+ {
147
+ type: 'select',
148
+ name: 'bucket',
149
+ message: 'Select environment',
150
+ choices: buckets,
151
+ },
152
+ ],
153
+ {
154
+ onCancel: () => process.exit(1),
155
+ },
156
+ )
157
+
158
+ return bucket
159
+ }
@@ -1,4 +1,8 @@
1
- import {execaCommandSync, ExecaSyncReturnValue, SyncOptions} from 'execa'
1
+ import {
2
+ execaCommandSync,
3
+ type ExecaSyncReturnValue,
4
+ type SyncOptions,
5
+ } from 'execa'
2
6
  import {logError} from 'lib/logging'
3
7
 
4
8
  ///////////////////////////////////////////////////////////////////////////////
@@ -1,7 +1,8 @@
1
1
  export const DEFAULT_TAG = 'latest'
2
2
  export const DEFAULT_PORT = 1234
3
3
  export const DEFAULT_AWS_PROFILE = 'payments-prod-cs-deployer'
4
- export const DEFAULT_AWS_S3_EMAIL_CONFIG_BUCKET = 'rnw-email-service'
4
+ export const AWS_S3_EMAIL_CONFIG_PROD_BUCKET = 'rnw-email-service'
5
+ export const AWS_S3_EMAIL_CONFIG_STAGE_BUCKET = 'rnw-stage-email-service'
5
6
  export const AWS_S3_BUCKET = 'tamaro.raisenow.com'
6
7
  export const CORE_CONFIG_NAME = 'tamaro-core'
7
8
  export const AWS_CLOUDFRONT_DISTRIBUTION_ID = 'EHJ1OM458YQ0I'
package/src/lib/env.ts CHANGED
@@ -1,18 +1,16 @@
1
1
  import {createRequire} from 'module'
2
2
  import {basename} from 'path'
3
- import {globSync} from 'glob'
4
- import type {IfUtilsFn} from 'webpack-config-utils'
5
- import {expand as dotenvExpand} from 'dotenv-expand'
6
3
  import {config as dotenvConfig} from 'dotenv'
4
+ import {expand as dotenvExpand} from 'dotenv-expand'
5
+ import {globSync} from 'glob'
7
6
  import stripIndent from 'strip-indent'
8
- import {getIfCoreFns, getPaths, getWidgetUuid, resolveApp} from 'lib/resolve'
7
+ import type {IfUtilsFn} from 'webpack-config-utils'
9
8
  import {halt} from 'lib/command'
9
+ import {getIfCoreFns, getPaths, getWidgetUuid, resolveApp} from 'lib/resolve'
10
10
 
11
11
  ///////////////////////////////////////////////////////////////////////////////
12
12
 
13
- export type EnvVars = {
14
- [key: string]: string | undefined
15
- }
13
+ export type EnvVars = Record<string, string | undefined>
16
14
 
17
15
  ///////////////////////////////////////////////////////////////////////////////
18
16
 
@@ -60,7 +58,7 @@ export const getEnvVars = (
60
58
 
61
59
  if (ifLocalCore()) {
62
60
  const protocol = ifHttps() ? 'https' : 'http'
63
- process.env.CORE_URL = `${protocol}://0.0.0.0:1234/index.js`
61
+ process.env.CORE_URL = `${protocol}://localhost:1234/index.js`
64
62
  } else {
65
63
  let version = process.env.CORE_VERSION
66
64
  version = version ? `@${version}` : ''
@@ -105,7 +103,7 @@ export const getEnvVars = (
105
103
 
106
104
  // Collect all vars which names start from "PUBLIC_" or present in "varNames" array
107
105
  const raw = Object.keys(process.env)
108
- .filter((key) => /^PUBLIC_/.test(key) || varNames.includes(key))
106
+ .filter((key) => key.startsWith('PUBLIC_') || varNames.includes(key))
109
107
  .reduce<EnvVars>((env, key) => {
110
108
  env[key] = process.env[key]
111
109
 
@@ -138,7 +136,8 @@ export const assertEnvValid = (env?: string) => {
138
136
  if (envs.length === 0) {
139
137
  if (env) {
140
138
  // There are no ".env.<env>" files, so we must ignore "--env" flag
141
- console.log('Flag “--env” is ignored.')
139
+ // eslint-disable-next-line no-console
140
+ console.log('Flag "--env" is ignored.')
142
141
  }
143
142
  }
144
143
 
@@ -146,15 +145,15 @@ export const assertEnvValid = (env?: string) => {
146
145
  if (!env) {
147
146
  // There are some ".env.<env>" files, but no "--env" flag is specified,
148
147
  // so we must require it
149
- halt('Flag “--env is required.')
148
+ halt('Flag "--env" is required.')
150
149
  }
151
150
 
152
151
  if (env && !envs.includes(env)) {
153
152
  // There are some ".env.<env>" files, but specified "--env" flag is incorrect
154
153
  halt(
155
154
  stripIndent(`
156
- Flag “--env has wrong value.
157
- Available values are: ${envs.map((v) => `“${v}”`).join(', ')}.
155
+ Flag "--env" has wrong value.
156
+ Available values are: ${envs.map((v) => `"${v}"`).join(', ')}.
158
157
  `),
159
158
  )
160
159
  }
package/src/lib/https.ts CHANGED
@@ -2,8 +2,8 @@ import {existsSync} from 'fs'
2
2
  import {resolve} from 'path'
3
3
  import stripIndent from 'strip-indent'
4
4
  import {halt} from 'lib/command'
5
- import {getIfCoreFns, getPaths} from 'lib/resolve'
6
5
  import {HTTPS_CRT_FILE, HTTPS_KEY_FILE} from 'lib/constants'
6
+ import {getIfCoreFns, getPaths} from 'lib/resolve'
7
7
 
8
8
  ///////////////////////////////////////////////////////////////////////////////
9
9
 
@@ -19,7 +19,7 @@ export const assertCrtExists = () => {
19
19
 
20
20
  halt(
21
21
  stripIndent(`
22
- Flag “--https is used, but “${HTTPS_CRT_FILE} and/or “${HTTPS_KEY_FILE} files are not found.
22
+ Flag "--https" is used, but "${HTTPS_CRT_FILE}" and/or "${HTTPS_KEY_FILE}" files are not found.
23
23
  You need to generate certificate first.
24
24
  Check docs: https://unpkg.com/@raisenow/tamaro-cli/readme.html#/?id=use-transport-level-security-https
25
25
  `),
@@ -1,10 +1,11 @@
1
1
  import chalk from 'chalk'
2
- import stripIndent from 'strip-indent'
3
2
  import columnify from 'columnify'
3
+ import stripIndent from 'strip-indent'
4
4
 
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
6
 
7
7
  export const logTitle = (title: string) => {
8
+ // eslint-disable-next-line no-console
8
9
  console.log(`${chalk.bold(title)}`)
9
10
  }
10
11
 
@@ -12,6 +13,7 @@ export const logTitle = (title: string) => {
12
13
 
13
14
  export const logError = (message?: string) => {
14
15
  if (message) {
16
+ // eslint-disable-next-line no-console
15
17
  console.log(chalk.red(message))
16
18
  }
17
19
  }
@@ -19,14 +21,17 @@ export const logError = (message?: string) => {
19
21
  ///////////////////////////////////////////////////////////////////////////////
20
22
 
21
23
  export const logCommand = (cmd: string): void => {
24
+ // eslint-disable-next-line no-console
22
25
  console.log(`\n${chalk.dim(stripIndent(cmd).trim())}\n`)
23
26
  }
24
27
 
25
28
  ///////////////////////////////////////////////////////////////////////////////
26
29
 
27
- export const logDataTable = (data: {
28
- [key: string]: string | undefined
29
- }): void => {
30
+ export const logDataTable = (
31
+ data: Record<string, string | undefined>,
32
+ ): void => {
33
+ // eslint-disable-next-line no-console
30
34
  console.log(columnify(data, {showHeaders: false}))
35
+ // eslint-disable-next-line no-console
31
36
  console.log('')
32
37
  }
@@ -1,10 +1,10 @@
1
+ import {existsSync, realpathSync} from 'fs'
1
2
  import {createRequire} from 'module'
2
3
  import {basename, dirname, join, relative, resolve} from 'path'
3
- import {existsSync, realpathSync} from 'fs'
4
- import {getIfUtils, IfUtils, IfUtilsFn} from 'webpack-config-utils'
5
- import {logError} from 'lib/logging'
6
- import stripIndent from 'strip-indent'
7
4
  import chalk from 'chalk'
5
+ import stripIndent from 'strip-indent'
6
+ import {getIfUtils, type IfUtils, type IfUtilsFn} from 'webpack-config-utils'
7
+ import {logError} from 'lib/logging'
8
8
 
9
9
  ///////////////////////////////////////////////////////////////////////////////
10
10
 
@@ -93,9 +93,7 @@ export const getPaths = (ifCore: IfUtilsFn) => {
93
93
 
94
94
  ///////////////////////////////////////////////////////////////////////////////
95
95
 
96
- type Paths = {
97
- [key: string]: string | undefined
98
- }
96
+ type Paths = Record<string, string | undefined>
99
97
 
100
98
  export const getRelativePaths = (paths: Paths): Paths => {
101
99
  const relativePaths: Paths = {}