@adamlui/scss-to-css 1.7.0 → 1.7.2

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 CHANGED
@@ -1,4 +1,4 @@
1
- <div align="right">
1
+ <div align="center">
2
2
  <h6>
3
3
  <picture>
4
4
  <source type="image/svg+xml" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/adamlui/js-utils/main/docs/images/earth-icon/white/icon32.svg">
@@ -10,7 +10,11 @@
10
10
  <a href="https://github.com/adamlui/js-utils/tree/main/scss-to-css/docs/hi#readme">हिंदी</a> |
11
11
  <a href="https://github.com/adamlui/js-utils/tree/main/scss-to-css/docs/bn#readme">বাংলা</a> |
12
12
  <a href="https://github.com/adamlui/js-utils/tree/main/scss-to-css/docs/mr#readme">मराठी</a> |
13
- <a href="https://github.com/adamlui/js-utils/tree/main/scss-to-css/docs/pa#readme">ਪੰਜਾਬੀ</a>
13
+ <a href="https://github.com/adamlui/js-utils/tree/main/scss-to-css/docs/pa#readme">ਪੰਜਾਬੀ</a> |
14
+ <a href="https://github.com/adamlui/js-utils/tree/main/scss-to-css/docs/de#readme">Deutsch</a> |
15
+ <a href="https://github.com/adamlui/js-utils/tree/main/scss-to-css/docs/es#readme">Español</a> |
16
+ <a href="https://github.com/adamlui/js-utils/tree/main/scss-to-css/docs/fr#readme">Français</a> |
17
+ <a href="https://github.com/adamlui/js-utils/tree/main/scss-to-css/docs/pt#readme">Português</a>
14
18
  </h6>
15
19
  </div>
16
20
 
@@ -20,11 +24,11 @@
20
24
 
21
25
  <a href="https://www.npmjs.com/package/@adamlui/scss-to-css"><img height=31 src="https://img.shields.io/npm/dt/%40adamlui%2Fscss-to-css?logo=npm&color=af68ff&logoColor=white&labelColor=464646&style=for-the-badge"></a>
22
26
  <a href="#%EF%B8%8F-mit-license"><img height=31 src="https://img.shields.io/badge/License-MIT-orange.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
23
- <a href="https://www.npmjs.com/package/@adamlui/scss-to-css?activeTab=versions"><img height=31 src="https://img.shields.io/badge/Latest_Build-1.7.0-44cc11.svg?logo=icinga&logoColor=white&labelColor=464646&style=for-the-badge"></a>
27
+ <a href="https://github.com/adamlui/js-utils/releases/tag/scss-to-css-1.7.2"><img height=31 src="https://img.shields.io/badge/Latest_Build-1.7.2-44cc11.svg?logo=icinga&logoColor=white&labelColor=464646&style=for-the-badge"></a>
24
28
  <a href="https://www.npmjs.com/package/@adamlui/scss-to-css?activeTab=code"><img height=31 src="https://img.shields.io/npm/unpacked-size/%40adamlui%2Fscss-to-css?style=for-the-badge&logo=ebox&logoColor=white&color=blue&labelColor=464646"></a>
25
29
  <a href="https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=adamlui_js-utils:scss-to-css/scss-to-css.js"><img height=31 src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fsonarcloud.io%2Fapi%2Fmeasures%2Fcomponent%3Fcomponent%3Dadamlui_js-utils%3Ascss-to-css%2Fscss-to-css.js%26metricKeys%3Dvulnerabilities&query=%24.component.measures.0.value&style=for-the-badge&logo=sonarcloud&logoColor=white&labelColor=464646&label=Vulnerabilities&color=gold"></a>
26
30
 
27
- <img height=8px width="100%" src="https://github.com/adamlui/js-utils/blob/main/docs/images/aqua-separator.png">
31
+ <img height=6px width="100%" src="https://github.com/adamlui/js-utils/blob/main/docs/images/aqua-separator.png">
28
32
 
29
33
  ## ⚡ Installation
30
34
 
@@ -46,6 +50,10 @@ As a **runtime dependency** (e.g. for on-the-fly compilation), from your project
46
50
  $ npm install @adamlui/scss-to-css
47
51
  ```
48
52
 
53
+ <br>
54
+
55
+ <img height=6px width="100%" src="https://raw.githubusercontent.com/adamlui/js-utils/main/docs/images/aqua-separator.png">
56
+
49
57
  ## 💻 Command line usage
50
58
 
51
59
  The basic **global command** is:
@@ -84,7 +92,8 @@ To use as a **package script**, in your project's `package.json`:
84
92
  ```
85
93
 
86
94
  Replace `<scss-to-css-cmd>` with `scss-to-css` + optional args. Then, `npm run build:css` can be used to run the command.
87
- <br><br>
95
+
96
+ #
88
97
 
89
98
  ### Example commands
90
99
 
@@ -113,7 +122,8 @@ $ scss-to-css input_folder output_folder
113
122
  ```
114
123
 
115
124
  **💡 Note:** Output CSS is minified unless `-M` or `--no-minify` is passed.
116
- <br><br>
125
+
126
+ #
117
127
 
118
128
  ### Command line options
119
129
 
@@ -128,11 +138,15 @@ Config options:
128
138
  -q, --quiet Suppress all logging except errors.
129
139
 
130
140
  Info commands:
131
- -h, --help Display this help screen.
141
+ -h, --help Display help screen.
132
142
  -v, --version Show version number.
133
143
  ```
134
144
 
135
- ## 🔌 API reference
145
+ <br>
146
+
147
+ <img height=6px width="100%" src="https://raw.githubusercontent.com/adamlui/js-utils/main/docs/images/aqua-separator.png">
148
+
149
+ ## 🔌 API usage
136
150
 
137
151
  You can also import **scss-to-css** into your app to use its API methods, both as an ECMAScript module or a CommonJS module.
138
152
 
@@ -148,6 +162,8 @@ import * as scssToCSS from '@adamlui/scss-to-css';
148
162
  const scssToCSS = require('@adamlui/scss-to-css');
149
163
  ```
150
164
 
165
+ #
166
+
151
167
  ### `compile(inputPath[, options])`
152
168
 
153
169
  Compiles SCSS found in the `inputPath` provided into CSS data.
@@ -165,11 +181,11 @@ If a **directory path** is passed, SCSS files are searched for (recursively by d
165
181
 
166
182
  ```js
167
183
  // Outputs paths to SCSS files in working directory + all nested directories
168
- const results = scssToCSS.compile('.');
169
- results.forEach(result => console.log(result.srcPath));
184
+ const compileResults = scssToCSS.compile('.');
185
+ compileResults.forEach(result => console.log(result.srcPath));
170
186
 
171
187
  // Outputs compiled CSS from 2nd SCSS file if found, or `undefined` if not found
172
- console.log(results[1].code);
188
+ console.log(compileResults[1].code);
173
189
  ```
174
190
 
175
191
  Options are boolean, passed as object properties. For example:
@@ -179,16 +195,17 @@ Options are boolean, passed as object properties. For example:
179
195
  scssToCSS.compile(inputDir, { minify: false });
180
196
  ```
181
197
 
182
- Possible parameters (and their default settings) are:
198
+ Available parameters (and their default settings) are:
183
199
 
184
- ```
185
- recursive (true) Recursively search for nested files if dir path
186
- passed.
187
- verbose (true) Show logging in console/terminal.
188
- dotFolders (false) Include dotfolders in file search.
189
- minify (true) Minify output CSS.
190
- sourceMaps (true) Generate CSS source maps.
191
- ```
200
+ Name | Desciption | Default value
201
+ -------------|---------------------------------------------------------|---------------
202
+ `recursive` | Recursively search for nested files if dir path passed. | `true`
203
+ `verbose` | Show logging in console/terminal. | `true`
204
+ `dotFolders` | Include dotfolders in file search. | `false`
205
+ `minify` | Minify output CSS. | `true`
206
+ `sourceMaps` | Generate CSS source maps. | `true`
207
+
208
+ #
192
209
 
193
210
  ### `findSCSS(searchDir[, options])`
194
211
 
@@ -197,25 +214,31 @@ Searches for all SCSS files within the `searchDir` string passed (useful for dis
197
214
  Options are boolean, passed as object properties. For example:
198
215
 
199
216
  ```js
200
- // Returns array containing filepaths to SCSS files in exactly `searchDir`
201
- scssToCSS.findSCSS(searchDir, { recursive: false });
217
+ // Search for SCSS files in exactly assets/scss:
218
+ const searchResults = scssToCSS.findSCSS('assets/scss', { recursive: false });
219
+ console.log(searchResults);
220
+
221
+ /* sample output:
222
+ Searching for SCSS files...
223
+ Search complete. 2 files found.
224
+ [
225
+ 'E:\\js\\utils\\minify.js\\assets\\scss\\foo.scss',
226
+ 'E:\\js\\utils\\minify.js\\assets\\scss\\bar.scss'
227
+ ]
228
+ */
202
229
  ```
203
230
 
204
- Possible parameters (and their default settings) are:
231
+ Available parameters (and their default settings) are:
205
232
 
206
- ```
207
- recursive (true) Recursively search for nested files if dir path
208
- passed.
209
- verbose (true) Show logging in console/terminal.
210
- dotFolders (false) Include dotfolders in file search.
211
- ```
233
+ Name | Desciption | Default value
234
+ -------------|---------------------------------------------------------|---------------
235
+ `recursive` | Recursively search for nested files if dir path passed. | `true`
236
+ `verbose` | Show logging in console/terminal. | `true`
237
+ `dotFolders` | Include dotfolders in file search. | `false`
212
238
 
213
239
  <br>
214
240
 
215
- ## 💖 Support
216
-
217
- Please consider [giving a GitHub ⭐](https://github.com/adamlui/js-utils) or [funding](https://github.com/sponsors/adamlui) this project if it helped you!
218
- <br><br>
241
+ <img height=6px width="100%" src="https://raw.githubusercontent.com/adamlui/js-utils/main/docs/images/aqua-separator.png">
219
242
 
220
243
  ## 🏛️ MIT License
221
244
 
package/docs/LICENSE.md CHANGED
@@ -10,7 +10,11 @@
10
10
  <a href="hi/LICENSE.md">हिंदी</a> |
11
11
  <a href="bn/LICENSE.md">বাংলা</a> |
12
12
  <a href="mr/LICENSE.md">मराठी</a> |
13
- <a href="pa/LICENSE.md">ਪੰਜਾਬੀ</a>
13
+ <a href="pa/LICENSE.md">ਪੰਜਾਬੀ</a> |
14
+ <a href="de/LICENSE.md">Deutsch</a> |
15
+ <a href="es/LICENSE.md">Español</a> |
16
+ <a href="fr/LICENSE.md">Français</a> |
17
+ <a href="pt/LICENSE.md">Português</a>
14
18
  </h6>
15
19
  </div>
16
20
 
package/docs/SECURITY.md CHANGED
@@ -10,7 +10,11 @@
10
10
  <a href="hi/SECURITY.md">हिंदी</a> |
11
11
  <a href="bn/SECURITY.md">বাংলা</a> |
12
12
  <a href="mr/SECURITY.md">मराठी</a> |
13
- <a href="pa/SECURITY.md">ਪੰਜਾਬੀ</a>
13
+ <a href="pa/SECURITY.md">ਪੰਜਾਬੀ</a> |
14
+ <a href="de/SECURITY.md">Deutsch</a> |
15
+ <a href="es/SECURITY.md">Español</a> |
16
+ <a href="fr/SECURITY.md">Français</a> |
17
+ <a href="pt/SECURITY.md">Português</a>
14
18
  </h6>
15
19
  </div>
16
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adamlui/scss-to-css",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Recursively compile all SCSS files into minified CSS",
5
5
  "author": {
6
6
  "name": "Adam Lui",
package/scss-to-css.js CHANGED
@@ -13,6 +13,28 @@ function findSCSS(searchDir, options = {}) {
13
13
  const defaultOptions = { recursive: true, verbose: true, dotFolders: false };
14
14
  options = { ...defaultOptions, ...options };
15
15
 
16
+ // Validate searchDir
17
+ if (!searchDir) return console.error(
18
+ 'findSCSS() error: Please supply a `searchDir` arg.');
19
+ else if (typeof searchDir !== 'string') return console.error(
20
+ 'findSCSS() error: Arg `searchDir` must be a string.');
21
+ else { // verify searchDir path existence
22
+ const searchPath = path.resolve(process.cwd(), searchDir);
23
+ if (!fs.existsSync(searchPath)) return console.error(
24
+ 'findSCSS() error: Arg `searchDir` must be an existing directory.'
25
+ + `\n'${ searchPath }' does not exist.`);
26
+ }
27
+
28
+ // Validate options
29
+ for (const key of Object.keys(options)) {
30
+ if (!Object.prototype.hasOwnProperty.call(defaultOptions, key))
31
+ if (key !== 'isRecursing') return console.error(
32
+ `findSCSS() error: \`${ key }\` is an invalid option.`
33
+ + `\nValid options: [ ${Object.keys(defaultOptions).join(', ')} ]`);
34
+ else if (typeof options[key] !== 'boolean') return console.error(
35
+ `findSCSS() error: \`${ key }\` option must be set to \`true\` or \`false\`.`);
36
+ }
37
+
16
38
  // Search for SCSS
17
39
  const dirFiles = fs.readdirSync(searchDir), scssFiles = [];
18
40
  if (options.verbose && !options.isRecursing) console.info('\nSearching for SCSS files...');
@@ -42,9 +64,23 @@ function compile(inputPath, options = {}) {
42
64
  options = { ...defaultOptions, ...options };
43
65
 
44
66
  // Validate inputPath
45
- if (typeof inputPath !== 'string')
46
- return console.error('ERROR:'
47
- + ' First argument must be a string representing a file/folder path.');
67
+ if (typeof inputPath !== 'string') return console.error(
68
+ 'compile() error: Arg `inputPath` must be a string.');
69
+ else { // verify inputPath path existence
70
+ inputPath = path.resolve(process.cwd(), inputPath);
71
+ if (!fs.existsSync(inputPath)) return console.error(
72
+ 'compile() error: Arg `inputPath` must be an existing directory or file.'
73
+ + `\n'${ inputPath }' does not exist.`);
74
+ }
75
+
76
+ // Validate options
77
+ for (const key of Object.keys(options)) {
78
+ if (!Object.prototype.hasOwnProperty.call(defaultOptions, key)) return console.error(
79
+ `findSCSS() error: \`${ key }\` is an invalid option.`
80
+ + `\nValid options: [ ${Object.keys(defaultOptions).join(', ')} ]`);
81
+ else if (typeof options[key] !== 'boolean') return console.error(
82
+ `findSCSS() error: \`${ key }\` option must be set to \`true\` or \`false\`.`);
83
+ }
48
84
 
49
85
  // Compile SCSS based on inputPath
50
86
  const compileOptions = { style: options.minify ? 'compressed' : 'expanded', sourceMap: options.sourceMaps };
@@ -53,10 +89,11 @@ function compile(inputPath, options = {}) {
53
89
  if (options.verbose) console.info(`Compiling ${ inputPath }...`);
54
90
  try { // to compile file passed
55
91
  const compileResult = sass.compile(inputPath, compileOptions);
56
- return { code: compileResult.css, srcMap: compileResult.sourceMap, srcPath: inputPath };
92
+ return { code: compileResult.css, srcMap: compileResult.sourceMap,
93
+ srcPath: path.resolve(process.cwd(), inputPath) };
57
94
  } catch (err) { console.error(`\nERROR: ${ err.message }\n`); return { error: err }; }
58
95
  } else { // dir path passed
59
- return findSCSS(inputPath, { recursive: options.recursive, verbosity: options.verbose,
96
+ return findSCSS(inputPath, { recursive: options.recursive, verbose: options.verbose,
60
97
  dotFolders: options.dotFolders
61
98
  })?.map(scssPath => { // compile found SCSS files
62
99
  if (options.verbose) console.info(`Compiling ${ scssPath }...`);
@@ -66,14 +103,13 @@ function compile(inputPath, options = {}) {
66
103
  } catch (err) { console.error(`\nERROR: ${ err.message }\n`); return { error: err }; }
67
104
  }).filter(data => !data.error ); // filter out failed compilations
68
105
  }
69
- } else return console.error('First argument must be an existing file or directory.'
70
- + `\n'${ inputPath }' does not exist.`);
106
+ }
71
107
  }
72
108
 
73
- // EXPORT functions if script was required
109
+ // EXPORT main functions if script was required
74
110
  if (require.main !== module) module.exports = { compile, findSCSS };
75
111
 
76
- else { // run as CLI tool
112
+ else { // run as CLI utility
77
113
 
78
114
  // Init UI colors
79
115
  const nc = '\x1b[0m', // no color
@@ -82,46 +118,36 @@ else { // run as CLI tool
82
118
  bg = '\x1b[1;92m'; // bright green
83
119
 
84
120
  // Load FLAG settings
85
- const config = {
86
- dryRun: process.argv.some(arg => /^--?(?:n|dry-?run)$/.test(arg)),
87
- includeDotFolders: process.argv.some(arg =>
88
- /^--?(?:dd?|(?:include-?)?dot-?(?:folder|dir(?:ector(?:y|ie))?)s?=?(?:true|1)?)$/.test(arg)),
89
- noSourceMaps: process.argv.some(arg =>
90
- /^--?(?:S|(?:exclude|disable|no)-?so?u?rce?-?maps?|so?u?rce?-?maps?=(?:false|0))$/.test(arg)),
91
- noRecursion: process.argv.some(arg =>
92
- /^--?(?:R|(?:disable|no)-?recursion|recursion=(?:false|0))$/.test(arg)),
93
- noMinify: process.argv.some(arg =>
94
- /^--?(?:M|(?:disable|no)-?minif(?:y|ication)|minif(?:y|ication)=(?:false|0))$/.test(arg)),
95
- quietMode: process.argv.some(arg => /^--?q(?:uiet)?(?:-?mode)?$/.test(arg))
121
+ const config = {};
122
+ const argRegex = {
123
+ 'dryRun': /^--?(?:n|dry-?run)$/,
124
+ 'includeDotFolders': /^--?(?:dd?|(?:include-?)?dot-?(?:folder|dir(?:ector(?:y|ie))?)s?=?(?:true|1)?)$/,
125
+ 'noSourceMaps': /^--?(?:S|(?:exclude|disable|no)-?so?u?rce?-?maps?|so?u?rce?-?maps?=(?:false|0))$/,
126
+ 'noRecursion': /^--?(?:R|(?:disable|no)-?recursion|recursion=(?:false|0))$/,
127
+ 'noMinify': /^--?(?:M|(?:disable|no)-?minif(?:y|ication)|minif(?:y|ication)=(?:false|0))$/,
128
+ 'quietMode': /^--?q(?:uiet)?(?:-?mode)?$/,
129
+ 'help': /^--?h(?:elp)?$/,
130
+ 'version': /^--?ve?r?s?i?o?n?$/
96
131
  };
132
+ process.argv.forEach(arg => {
133
+ if (!arg.startsWith('-')) return;
134
+ const matchedFlag = Object.keys(argRegex).find(flag => argRegex[flag].test(arg));
135
+ if (matchedFlag) config[matchedFlag] = true;
136
+ else {
137
+ console.error(`\n${br}ERROR: Arg [${ arg }] not recognized.${nc}`);
138
+ console.info(`\n${by}Valid arguments are below.${nc}`);
139
+ printHelpSections(['configOptions', 'infoCmds']);
140
+ process.exit(1);
141
+ }});
97
142
 
98
143
  // Show HELP screen if -h or --help passed
99
- if (process.argv.some(arg => /^--?h(?:elp)?$/.test(arg))) {
100
- printHelp(`\n${by}scss-to-css [inputPath] [outputPath] [options]${nc}`);
101
- printHelp('\nPath arguments:');
102
- printHelp(' [inputPath] '
103
- + 'Path to SCSS file or directory containing SCSS files to be compiled,'
104
- + ' relative to the current working directory.');
105
- printHelp(' [outputPath] '
106
- + 'Path to file or directory where CSS + sourcemap files will be stored,'
107
- + ' relative to original file location (if not provided, css/ is used).');
108
- printHelp('\nConfig options:');
109
- printHelp(' -n, --dry-run Don\'t actually compile the file(s),'
110
- + ' just show if they will be processed.');
111
- printHelp(' -d, --include-dotfolders Include dotfolders in file search.');
112
- printHelp(' -S, --no-source-maps Prevent source maps from being generated.');
113
- printHelp(' -M, --no-minify Disable minification of output CSS.');
114
- printHelp(' -R, --no-recursion Disable recursive file searching.');
115
- printHelp(' -q, --quiet Suppress all logging except errors.');
116
- printHelp('\nInfo commands:');
117
- printHelp(' -h, --help Display this help screen.');
118
- printHelp(' -v, --version Show version number.');
144
+ if (process.argv.some(arg => argRegex.help.test(arg))) printHelpSections();
119
145
 
120
146
  // Show VERSION number if -v or --version passed
121
- } else if (process.argv.some(arg => /^--?ve?r?s?i?o?n?$/.test(arg))) {
147
+ else if (process.argv.some(arg => argRegex.version.test(arg)))
122
148
  console.info('v' + require('./package.json').version);
123
149
 
124
- } else { // run MAIN routine
150
+ else { // run MAIN routine
125
151
 
126
152
  // Init I/O args
127
153
  const [inputArg = '', outputArg = ''] = ( // default to empty strings for error-less handling
@@ -199,27 +225,61 @@ else { // run as CLI tool
199
225
 
200
226
  // Define LOGGING functions
201
227
 
202
- function printHelp(msg) { // wrap msg + indent 2nd+ lines (for --help screen)
203
- const terminalWidth = process.stdout.columns || 80,
204
- indentation = 30, lines = [], words = msg.match(/\S+|\s+/g);
205
-
206
- // Split msg into lines of appropriate lengths
207
- let currentLine = '';
208
- words.forEach(word => {
209
- const lineLength = terminalWidth - ( lines.length === 0 ? 0 : indentation );
210
- if (currentLine.length + word.length > lineLength) { // cap/store it
211
- lines.push(lines.length === 0 ? currentLine : currentLine.trimStart());
212
- currentLine = '';
213
- }
214
- currentLine += word;
215
- });
216
- lines.push(lines.length === 0 ? currentLine : currentLine.trimStart());
217
-
218
- // Print formatted msg
219
- lines.forEach((line, index) => console.info(
220
- index === 0 ? line // print 1st line unindented
221
- : ' '.repeat(indentation) + line // print subsequent lines indented
222
- ));
228
+ function printHelpSections(includeSections = ['cmdFormat', 'pathArgs', 'configOptions', 'infoCmds']) {
229
+ const helpSections = {
230
+ 'cmdFormat': [
231
+ `\n${by}scss-to-css [inputPath] [outputPath] [options]${nc}`
232
+ ],
233
+ 'pathArgs': [
234
+ '\nPath arguments:',
235
+ ' [inputPath] '
236
+ + 'Path to SCSS file or directory containing SCSS files to be compiled,'
237
+ + ' relative to the current working directory.',
238
+ ' [outputPath] '
239
+ + 'Path to file or directory where CSS + sourcemap files will be stored,'
240
+ + ' relative to original file location (if not provided, css/ is used).'
241
+ ],
242
+ 'configOptions': [
243
+ '\nConfig options:',
244
+ ' -n, --dry-run Don\'t actually compile the file(s),'
245
+ + ' just show if they will be processed.',
246
+ ' -d, --include-dotfolders Include dotfolders in file search.',
247
+ ' -S, --no-source-maps Prevent source maps from being generated.',
248
+ ' -M, --no-minify Disable minification of output CSS.',
249
+ ' -R, --no-recursion Disable recursive file searching.',
250
+ ' -q, --quiet Suppress all logging except errors.'
251
+ ],
252
+ 'infoCmds': [
253
+ '\nInfo commands:',
254
+ ' -h, --help Display help screen.',
255
+ ' -v, --version Show version number.'
256
+ ]
257
+ };
258
+ includeSections.forEach(section => { // print valid arg elems
259
+ helpSections[section]?.forEach(line => printHelpMsg(line)); });
260
+
261
+ function printHelpMsg(msg) { // wrap msg + indent 2nd+ lines (for --help screen)
262
+ const terminalWidth = process.stdout.columns || 80,
263
+ indentation = 30, lines = [], words = msg.match(/\S+|\s+/g);
264
+
265
+ // Split msg into lines of appropriate lengths
266
+ let currentLine = '';
267
+ words.forEach(word => {
268
+ const lineLength = terminalWidth - ( lines.length === 0 ? 0 : indentation );
269
+ if (currentLine.length + word.length > lineLength) { // cap/store it
270
+ lines.push(lines.length === 0 ? currentLine : currentLine.trimStart());
271
+ currentLine = '';
272
+ }
273
+ currentLine += word;
274
+ });
275
+ lines.push(lines.length === 0 ? currentLine : currentLine.trimStart());
276
+
277
+ // Print formatted msg
278
+ lines.forEach((line, index) => console.info(
279
+ index === 0 ? line // print 1st line unindented
280
+ : ' '.repeat(indentation) + line // print subsequent lines indented
281
+ ));
282
+ }
223
283
  }
224
284
 
225
285
  function printIfNotQuiet(msg) { if (!config.quietMode) console.info(msg); }