generate-pw 2.1.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -11
- package/dist/cli/index.js +47 -0
- package/dist/cli/lib/color.js +31 -0
- package/dist/cli/lib/data.js +30 -0
- package/dist/cli/lib/init.js +49 -0
- package/dist/cli/lib/jsdelivr.js +10 -0
- package/dist/cli/lib/language.js +106 -0
- package/dist/cli/lib/log.js +171 -0
- package/dist/cli/lib/pkg.js +78 -0
- package/dist/cli/lib/settings.js +153 -0
- package/dist/cli/lib/string.js +3 -0
- package/dist/data/generate-pw.config.mjs +2 -2
- package/dist/data/messages.json +14 -4
- package/dist/data/package-data.json +1 -1
- package/dist/generate-pw.min.js +1 -1
- package/docs/README.md +13 -11
- package/package.json +8 -4
- package/dist/cli/index.min.js +0 -8
- package/dist/cli/lib/data.min.js +0 -6
- package/dist/cli/lib/init.min.js +0 -6
- package/dist/cli/lib/jsdelivr.min.js +0 -6
- package/dist/cli/lib/language.min.js +0 -7
- package/dist/cli/lib/log.min.js +0 -22
- package/dist/cli/lib/pkg.min.js +0 -6
- package/dist/cli/lib/settings.min.js +0 -7
package/README.md
CHANGED
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
<img height=31 src="https://img.shields.io/npm/dm/generate-pw?logo=npm&color=af68ff&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
26
26
|
<a href="#%EF%B8%8F-mit-license">
|
|
27
27
|
<img height=31 src="https://img.shields.io/badge/License-MIT-orange.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
28
|
-
<a href="https://github.com/adamlui/js-utils/releases/tag/generate-pw-2.
|
|
29
|
-
<img height=31 src="https://img.shields.io/badge/Latest_Build-2.
|
|
28
|
+
<a href="https://github.com/adamlui/js-utils/releases/tag/generate-pw-2.2.0">
|
|
29
|
+
<img height=31 src="https://img.shields.io/badge/Latest_Build-2.2.0-44cc11.svg?logo=icinga&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
30
30
|
<a href="https://www.npmjs.com/package/generate-pw?activeTab=code">
|
|
31
31
|
<img height=31 src="https://img.shields.io/npm/unpacked-size/generate-pw?style=for-the-badge&logo=ebox&logoColor=white&labelColor=464646&color=blue"></a>
|
|
32
|
-
<a href="
|
|
33
|
-
<img height=31 src="https://img.shields.io/
|
|
32
|
+
<a href="#">
|
|
33
|
+
<img height=31 src="https://img.shields.io/bundlejs/size/generate-pw%402.1.2?label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
|
|
34
34
|
<a href="https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=adamlui_js-utils:generate-pw/src/generate-pw.js">
|
|
35
35
|
<img height=31 src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fsonarcloud.io%2Fapi%2Fmeasures%2Fcomponent%3Fcomponent%3Dadamlui_js-utils%3Agenerate-pw%2Fsrc%2Fgenerate-pw.js%26metricKeys%3Dvulnerabilities&query=%24.component.measures.0.value&style=for-the-badge&logo=sonarcloud&logoColor=white&labelColor=464646&label=Vulnerabilities&color=gold"></a>
|
|
36
36
|
<a href="https://github.com/toolleeo/cli-apps#password-managers">
|
|
@@ -94,14 +94,14 @@ const pw = require('generate-pw')
|
|
|
94
94
|
#### <> HTML script tag:
|
|
95
95
|
|
|
96
96
|
```html
|
|
97
|
-
<script src="https://cdn.jsdelivr.net/npm/generate-pw@2.
|
|
97
|
+
<script src="https://cdn.jsdelivr.net/npm/generate-pw@2.2.0/dist/generate-pw.min.js"></script>
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
#### ES6:
|
|
101
101
|
|
|
102
102
|
```js
|
|
103
103
|
(async () => {
|
|
104
|
-
await import('https://cdn.jsdelivr.net/npm/generate-pw@2.
|
|
104
|
+
await import('https://cdn.jsdelivr.net/npm/generate-pw@2.2.0/dist/generate-pw.min.js')
|
|
105
105
|
// Your code here...
|
|
106
106
|
})()
|
|
107
107
|
```
|
|
@@ -110,7 +110,7 @@ const pw = require('generate-pw')
|
|
|
110
110
|
|
|
111
111
|
```js
|
|
112
112
|
...
|
|
113
|
-
// @require https://cdn.jsdelivr.net/npm/generate-pw@2.
|
|
113
|
+
// @require https://cdn.jsdelivr.net/npm/generate-pw@2.2.0/dist/generate-pw.min.js
|
|
114
114
|
// ==/UserScript==
|
|
115
115
|
|
|
116
116
|
// Your code here...
|
|
@@ -118,7 +118,7 @@ const pw = require('generate-pw')
|
|
|
118
118
|
|
|
119
119
|
<br>
|
|
120
120
|
|
|
121
|
-
**💡 Note:** To always import the latest version (not recommended in production!) remove the `@2.
|
|
121
|
+
**💡 Note:** To always import the latest version (not recommended in production!) remove the `@2.2.0` version tag from the jsDelivr URL: `https://cdn.jsdelivr.net/npm/generate-pw/dist/generate-pw.min.js`
|
|
122
122
|
|
|
123
123
|
<br>
|
|
124
124
|
|
|
@@ -255,7 +255,7 @@ Name | Type | Description
|
|
|
255
255
|
`uppercase` | Boolean | Allow uppercase letters in password(s). | `true`
|
|
256
256
|
`similarChars` | Boolean | Include similar characters (e.g. o,0,O,i,l,1,\|) in password(s). | `false`
|
|
257
257
|
`strict` | Boolean | Require at least one character from each allowed character set in password(s). | `true`
|
|
258
|
-
`entropy` | Boolean | Calculate/log estimated entropy. | `
|
|
258
|
+
`entropy` | Boolean | Calculate/log estimated entropy. | `true`
|
|
259
259
|
|
|
260
260
|
##### _*Only available in [`generatePassword([options])`](#generatepasswordoptions) since [`generatePasswords(qty[, options])`](#generatepasswordsqty-options) takes a `qty` argument_
|
|
261
261
|
|
|
@@ -297,13 +297,15 @@ Boolean options:
|
|
|
297
297
|
-S, --similar-chars Include similar characters in password(s).
|
|
298
298
|
-S, --unstrict Don't require at least one character from
|
|
299
299
|
each allowed character set in password(s).
|
|
300
|
-
-
|
|
300
|
+
-E, --no-entropy Don't calculate/log estimated entropy.
|
|
301
301
|
-q, --quiet Suppress all logging except errors.
|
|
302
302
|
|
|
303
303
|
Commands:
|
|
304
304
|
-i, --init Create config file (in project root).
|
|
305
305
|
-h, --help Display help screen.
|
|
306
306
|
-v, --version Show version number.
|
|
307
|
+
--stats Show npm stats.
|
|
308
|
+
--debug [targetKey] Show debug logs.
|
|
307
309
|
```
|
|
308
310
|
|
|
309
311
|
#
|
|
@@ -327,7 +329,7 @@ export default {
|
|
|
327
329
|
excludeUpperChars: false, // disallow uppercase letters in password(s)
|
|
328
330
|
similarChars: false, // include similar chars in password(s)
|
|
329
331
|
unstrict: false, // don't require 1+ char from each allowed charset in password(s)
|
|
330
|
-
|
|
332
|
+
noEntropy: false, // don't calculate/log estimated entropy
|
|
331
333
|
quietMode: false // suppress all logging except errors
|
|
332
334
|
}
|
|
333
335
|
```
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
(async () => {
|
|
4
|
+
'use strict'
|
|
5
|
+
|
|
6
|
+
globalThis.env = {
|
|
7
|
+
args: process.argv.slice(2),
|
|
8
|
+
modes: { dev: /[\\/]src(?:[\\/]|$)/i.test(__dirname) },
|
|
9
|
+
paths: { lib: './lib' }
|
|
10
|
+
}
|
|
11
|
+
env.modes.debug = env.args.some(arg => /^--?(?:V|debug(?:[-_]?mode)?)$/.test(arg))
|
|
12
|
+
|
|
13
|
+
// Import LIBS
|
|
14
|
+
globalThis.log = require(`${env.paths.lib}/log`)
|
|
15
|
+
const clipboardy = require('node-clipboardy'),
|
|
16
|
+
{ generatePassword } = require(`../generate-pw${ env.modes.dev ? '' : '.min' }.js`),
|
|
17
|
+
init = require(`${env.paths.lib}/init`)
|
|
18
|
+
|
|
19
|
+
await init.cli()
|
|
20
|
+
|
|
21
|
+
// Exec CMD arg if passed
|
|
22
|
+
if (cli.config.init) return init.configFile()
|
|
23
|
+
else if (cli.config.help) return log.help()
|
|
24
|
+
else if (cli.config.version) return log.version()
|
|
25
|
+
else if (cli.config.stats) return log.stats()
|
|
26
|
+
|
|
27
|
+
// Copy random PASSWORD(s)
|
|
28
|
+
const genOptions = {
|
|
29
|
+
length: cli.config.length,
|
|
30
|
+
qty: cli.config.qty,
|
|
31
|
+
strength: cli.config.mode || cli.config.strength,
|
|
32
|
+
charset: cli.config.charset,
|
|
33
|
+
exclude: cli.config.excludeChars,
|
|
34
|
+
numbers: !cli.config.excludeNums,
|
|
35
|
+
symbols: !cli.config.excludeSymbols,
|
|
36
|
+
lowercase: !cli.config.excludeLowerChars,
|
|
37
|
+
uppercase: !cli.config.excludeUpperChars,
|
|
38
|
+
similarChars: cli.config.similarChars,
|
|
39
|
+
strict: !cli.config.unstrict,
|
|
40
|
+
entropy: !cli.config.noEntropy,
|
|
41
|
+
verbose: !cli.config.quietMode
|
|
42
|
+
}
|
|
43
|
+
log.break()
|
|
44
|
+
clipboardy.writeSync([].concat(generatePassword(genOptions)).join('\n'))
|
|
45
|
+
log.ifNotQuiet(`${cli.msgs.info_copyingToClip}...`)
|
|
46
|
+
|
|
47
|
+
})()
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const color = module.exports = {
|
|
2
|
+
nc: '\x1b[0m',
|
|
3
|
+
hex: {
|
|
4
|
+
br: '#ff0000', by: '#ffff00', bo: '#ffa500', bg: '#00ff00',
|
|
5
|
+
bw: '#ffffff', gry: '#808080', blk: '#000000', tlBG: '#008080'
|
|
6
|
+
},
|
|
7
|
+
schemes: {
|
|
8
|
+
get default() {
|
|
9
|
+
return [
|
|
10
|
+
'#00e5bc', '#18c8ae', '#30ac9f', '#488f91', '#607383',
|
|
11
|
+
'#775674', '#8f3966', '#a71d57', '#bf0049', '#9a1b5e'
|
|
12
|
+
].map(color.hexToANSI)
|
|
13
|
+
},
|
|
14
|
+
get rainbow() {
|
|
15
|
+
return [
|
|
16
|
+
'#e41a1c', '#ff7f00', '#ffff33', '#4daf4a', '#377eb8',
|
|
17
|
+
'#984ea3', '#f781bf', '#999999', '#a65628', '#d95f02'
|
|
18
|
+
].map(color.hexToANSI)
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
hexToANSI(hex) {
|
|
23
|
+
const r = parseInt(hex.slice(1,3), 16),
|
|
24
|
+
g = parseInt(hex.slice(3,5), 16),
|
|
25
|
+
b = parseInt(hex.slice(5,7), 16)
|
|
26
|
+
return `\x1b[38;2;${r};${g};${b}m`
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const hexKey of Object.keys(color.hex)) // add color[hexKey] getters that return ANSI
|
|
31
|
+
Object.defineProperty(color, hexKey, { get: () => color.hexToANSI(color.hex[hexKey]) })
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
|
|
3
|
+
atomicWrite(filePath, data, encoding = 'utf8') { // to prevent TOCTOU
|
|
4
|
+
const fs = require('fs'),
|
|
5
|
+
path = require('path'),
|
|
6
|
+
tmpPath = path.join(path.dirname(filePath), `.${path.basename(filePath)}.tmp`)
|
|
7
|
+
fs.writeFileSync(tmpPath, data, encoding) ; fs.renameSync(tmpPath, filePath)
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
fetch(url) { // to support Node.js < v21
|
|
11
|
+
return typeof fetch == 'undefined' ? new Promise((resolve, reject) => { // using https?.get()
|
|
12
|
+
const protocol = url.match(/^([^:]+):\/\//)[1]
|
|
13
|
+
if (!/^https?$/.test(protocol))
|
|
14
|
+
reject(new Error(`${cli.msgs.error_invalidURL}.`))
|
|
15
|
+
require(protocol).get(url, resp => {
|
|
16
|
+
let rawData = ''
|
|
17
|
+
resp.on('data', chunk => rawData += chunk)
|
|
18
|
+
resp.on('end', () => resolve({ json: () => JSON.parse(rawData), text: () => rawData }))
|
|
19
|
+
}).on('error', reject)
|
|
20
|
+
}) : fetch(url) // using Node.js fetch()
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
flatten(json, { key = 'message' } = {}) { // eliminate need to ref nested keys
|
|
24
|
+
const flatObj = {}
|
|
25
|
+
for (const jsonKey in json) flatObj[jsonKey] =
|
|
26
|
+
typeof json[jsonKey] == 'object' && key in json[jsonKey] ? json[jsonKey][key]
|
|
27
|
+
: json[jsonKey]
|
|
28
|
+
return flatObj
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const language = require('./language'),
|
|
2
|
+
settings = require('./settings')
|
|
3
|
+
|
|
4
|
+
const dataPath = `../../${ env.modes.dev ? '../' : 'data/' }`
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
|
|
8
|
+
async cli() {
|
|
9
|
+
Object.assign(globalThis.cli ??= {}, require(`${dataPath}package-data.json`))
|
|
10
|
+
cli.msgs = await language.getMsgs('en')
|
|
11
|
+
cli.msgs = await language.getMsgs(cli.lang = settings.load('uiLang') || (
|
|
12
|
+
env.modes.debug ? language.generateRandomLang({ excludes: ['en'] }) : language.getSysLang() ))
|
|
13
|
+
cli.urls.cliDocs = `${cli.urls.docs}/#-command-line-usage`
|
|
14
|
+
if (!cli.lang.startsWith('en')) { // localize cli.urls.cliDocs
|
|
15
|
+
cli.docLocale = cli.lang.replace('_', '-').toLowerCase()
|
|
16
|
+
cli.docLocales ??= await language.getDocLocales()
|
|
17
|
+
if (cli.docLocales?.includes(cli.docLocale))
|
|
18
|
+
log.debug(cli.urls.cliDocs = `${cli.urls.docs}/${cli.docLocale}#readme`)
|
|
19
|
+
}
|
|
20
|
+
settings.load() // all keys to cli.config
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
async configFile(filename = settings.configFilename) {
|
|
24
|
+
const fs = require('fs'),
|
|
25
|
+
path = require('path'),
|
|
26
|
+
paths = { target: path.resolve(process.cwd(), filename) }
|
|
27
|
+
|
|
28
|
+
if (fs.existsSync(paths.target)) // use existing config file
|
|
29
|
+
return log.warn(`${cli.msgs.warn_configFileExists}:`, paths.target)
|
|
30
|
+
if (fs.existsSync(paths.src = path.resolve(__dirname, `${dataPath}${filename}`)))
|
|
31
|
+
fs.copyFileSync(paths.src, paths.target) // use found template
|
|
32
|
+
|
|
33
|
+
else { // use jsDelivr copy
|
|
34
|
+
const jsdURL = `${require('./jsdelivr').pkgVerURL()}/${filename}`
|
|
35
|
+
log.data(`${cli.msgs.info_fetchingRemoteConfigFrom} ${jsdURL}...`)
|
|
36
|
+
try {
|
|
37
|
+
const data = require('./data'),
|
|
38
|
+
resp = await data.fetch(jsdURL)
|
|
39
|
+
if (resp.ok) data.atomicWrite(paths.target, await resp.text())
|
|
40
|
+
else return log.warn(`${cli.msgs.warn_remoteConfigNotFound}: ${jsdURL} (${resp.status})`)
|
|
41
|
+
} catch (err) {
|
|
42
|
+
return log.warn(`${cli.msgs.warn_remoteConfigFailed}: ${jsdURL} ${err.message}`) }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
log.success(`${cli.msgs.info_configFileCreated}: ${paths.target}\n`)
|
|
46
|
+
log.tip(`${cli.msgs.tip_editToSetDefaults}.`)
|
|
47
|
+
log.tip(`${cli.msgs.tip_cliArgsPrioritized}.`)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
|
|
3
|
+
pkgVerURL(version) {
|
|
4
|
+
version ||= cli.version ||= require('./pkg').getVer('local') || 'none'
|
|
5
|
+
const verTag = !/^\d+\.\d+\.\d+$/.test(version) ? 'latest' : `${cli.name}-${version}`
|
|
6
|
+
return `${cli.urls.jsdelivr}@${verTag}/${cli.name}`
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
commitURL(hash = 'latest') { return `${cli.urls.jsdelivr}@${hash}/${cli.name}` }
|
|
10
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const data = require('./data')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
|
|
5
|
+
formatCode(langCode) { // to match locale dir name
|
|
6
|
+
return langCode.replace(
|
|
7
|
+
/([a-z]{2,8})[-_]([a-z]{2})/i, (_, lang, region) =>`${lang.toLowerCase()}_${region.toUpperCase()}`) },
|
|
8
|
+
|
|
9
|
+
async getDocLocales() {
|
|
10
|
+
cli.version ||= require('./pkg').getVer('local') || 'none'
|
|
11
|
+
const jsdURL = `${require('./jsdelivr').pkgVerURL()}/docs/`,
|
|
12
|
+
locales = []
|
|
13
|
+
try {
|
|
14
|
+
const respText = await (await data.fetch(jsdURL)).text(),
|
|
15
|
+
reLocale = /href=".*\/docs\/([^/]+)\/"/g
|
|
16
|
+
let match ; while ((match = reLocale.exec(respText))) locales.push(match[1]) // store locale dir names
|
|
17
|
+
} catch (err) {
|
|
18
|
+
log.warn(`${cli.msgs.warn_docLocalesFetchFailed}:`, err.message)
|
|
19
|
+
}
|
|
20
|
+
return locales
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
generateRandomLang({ includes = [], excludes = [] } = {}) {
|
|
24
|
+
const fs = require('fs'),
|
|
25
|
+
path = require('path')
|
|
26
|
+
|
|
27
|
+
let locales = includes.length ? includes : (() => {
|
|
28
|
+
|
|
29
|
+
// Read cache if found
|
|
30
|
+
const cacheDir = path.join(__dirname, '..', '.cache'),
|
|
31
|
+
localeCache = path.join(cacheDir, 'locales.json')
|
|
32
|
+
if (fs.existsSync(localeCache))
|
|
33
|
+
try { return JSON.parse(fs.readFileSync(localeCache, 'utf8')) } catch (err) {}
|
|
34
|
+
|
|
35
|
+
// Discover pkg _locales
|
|
36
|
+
const localesDir = path.resolve(process.cwd(), '_locales')
|
|
37
|
+
if (!fs.existsSync(localesDir)) return ['en']
|
|
38
|
+
const locales = fs.readdirSync(localesDir, { withFileTypes: true })
|
|
39
|
+
.filter(entry => entry.isDirectory()).map(entry => entry.name)
|
|
40
|
+
.filter(name => /^\w{2}[-_]?\w{0,2}$/.test(name))
|
|
41
|
+
|
|
42
|
+
// Cache result
|
|
43
|
+
fs.mkdirSync(cacheDir, { recursive: true })
|
|
44
|
+
data.atomicWrite(localeCache, JSON.stringify(locales, null, 2))
|
|
45
|
+
|
|
46
|
+
return locales
|
|
47
|
+
})()
|
|
48
|
+
|
|
49
|
+
// Filter out excludes
|
|
50
|
+
const excludeSet = new Set(excludes)
|
|
51
|
+
locales = locales.filter(locale => !excludeSet.has(locale))
|
|
52
|
+
|
|
53
|
+
// Get random language
|
|
54
|
+
let randomLang = 'en'
|
|
55
|
+
if (locales.length)
|
|
56
|
+
randomLang = locales[Math.floor(Math.random() * locales.length)]
|
|
57
|
+
log.debug(`Random language: ${randomLang}`)
|
|
58
|
+
|
|
59
|
+
return randomLang
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
async getMsgs(langCode = 'en') {
|
|
63
|
+
langCode = module.exports.formatCode(langCode)
|
|
64
|
+
if (env.msgs && langCode == cli.lang) return env.msgs // don't re-fetch same msgs
|
|
65
|
+
|
|
66
|
+
let msgs = data.flatten( // local ones
|
|
67
|
+
require(`../../${ env.modes.dev ? '../_locales/en/' : 'data/' }messages.json`))
|
|
68
|
+
|
|
69
|
+
if (!langCode.startsWith('en')) { // fetch non-English msgs from jsDelivr
|
|
70
|
+
const msgHostURL = `${require('./jsdelivr').commitURL(cli.commitHashes.locales)}/_locales/`
|
|
71
|
+
let msgHref = `${msgHostURL}${langCode}/messages.json`, msgFetchesTried = 0
|
|
72
|
+
while (msgFetchesTried < 3)
|
|
73
|
+
try { // fetch remote msgs
|
|
74
|
+
msgs = data.flatten(await (await data.fetch(msgHref)).json())
|
|
75
|
+
break
|
|
76
|
+
} catch (err) { // retry up to 2X (region-stripped + EN)
|
|
77
|
+
msgFetchesTried++ ; if (msgFetchesTried >= 3) break
|
|
78
|
+
log.debug(msgHref = langCode.includes('-') && msgFetchesTried == 1 ?
|
|
79
|
+
msgHref.replace(/([^_]*)_[^/]*(\/.*)/, '$1$2') // strip region before retrying
|
|
80
|
+
: `${msgHostURL}en/messages.json` // else use EN msgs
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return msgs
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
getSysLang() {
|
|
89
|
+
try {
|
|
90
|
+
if (process.platform == 'win32')
|
|
91
|
+
return require('child_process').execSync(
|
|
92
|
+
'(Get-Culture).TwoLetterISOLanguageName', { shell: 'powershell', encoding: 'utf-8' }
|
|
93
|
+
).trim()
|
|
94
|
+
else { // macOS/Linux
|
|
95
|
+
const pe = process.env
|
|
96
|
+
return (pe.LANG || pe.LANGUAGE || pe.LC_ALL || pe.LC_MESSAGES || pe.LC_NAME)
|
|
97
|
+
.split('.')[0] // strip encoding e.g. .UTF-8
|
|
98
|
+
}
|
|
99
|
+
} catch (err) {
|
|
100
|
+
log.error(`${cli.msgs.error_failedToFetchSysLang}:`, err.message)
|
|
101
|
+
return 'en'
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
validateLangCode(code) { return typeof code != 'string' ? false : /^[a-z]{2,8}(?:[-_][a-z]{2,3})?$/i.test(code) }
|
|
106
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const colors = require('./color'),
|
|
2
|
+
{ getDownloads, getVer } = require('./pkg'),
|
|
3
|
+
string = require('./string')
|
|
4
|
+
|
|
5
|
+
const nextMajVer = require('../../../package.json').version.replace(/^(\d+)\..*/, (_, major) => `${ +major +1 }.0.0`)
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
colors,
|
|
9
|
+
|
|
10
|
+
configURL() { this.info(`${cli.msgs.info_exampleValidConfigFile}: ${cli.urls.config}`) },
|
|
11
|
+
configURLandExit(...args) { this.error(...args); this.configURL(); process.exit(1) },
|
|
12
|
+
data(msg) { console.log(`\n${colors.bw}${msg}${colors.nc}`) },
|
|
13
|
+
dim(msg) { console.log(`${colors.gry}${msg}${colors.nc}`) },
|
|
14
|
+
error(...args) { console.error(`\n${colors.br}ERROR:`, ...args, colors.nc) },
|
|
15
|
+
errorAndExit(...args) { this.error(...args); this.helpDocsCmdsDocsURL(); process.exit(1) },
|
|
16
|
+
ifNotQuiet(msg) { if (!cli.config.quietMode) this.info(msg) },
|
|
17
|
+
info(msg) { console.info(`\n${colors.schemes.default[0]}${msg}${colors.nc}`) },
|
|
18
|
+
break() { console.log() },
|
|
19
|
+
tip(msg) { console.info(`${colors.by}TIP: ${msg}${colors.nc}`) },
|
|
20
|
+
success(msg) { console.log(`\n${colors.bg}${msg}${colors.nc}`) },
|
|
21
|
+
warn(...args) { console.warn(`\n${colors.bo}WARNING:`, ...args, colors.nc) },
|
|
22
|
+
|
|
23
|
+
argDoesNothing(arg) {
|
|
24
|
+
this.warn(`${cli.msgs.warn_option} ${arg} ${cli.msgs.warn_noLongerHasAnyEffect} ${
|
|
25
|
+
cli.msgs.warn_andWillBeRemoved} @ v${nextMajVer}`)
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
configKeyReplacedBy(oldKey, newKey, oldVal) {
|
|
29
|
+
if (!this[`${oldKey}Warned`]) {
|
|
30
|
+
this.warn(
|
|
31
|
+
`${cli.msgs.info_configFile} ${cli.msgs.warn_option.toLowerCase()} '${oldKey}: ${oldVal}' ${
|
|
32
|
+
cli.msgs.warn_hasBeenReplacedBy} '${
|
|
33
|
+
newKey}: ${ isNegKey(oldKey) != isNegKey(newKey) ? !oldVal : oldVal }' ${
|
|
34
|
+
cli.msgs.warn_andWillBeRemoved} @ v${nextMajVer}`
|
|
35
|
+
)
|
|
36
|
+
this[`${oldKey}Warned`] = true
|
|
37
|
+
function isNegKey(key) { return /^(?:no|disable|exclude)[A-Z]/.test(key) }
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
debug(msg) {
|
|
42
|
+
if (!env.modes.debug) return
|
|
43
|
+
this.argIdx ??= env.args.findIndex(arg => /^--?(?:V|debug(?:[-_]?mode)?)$/.test(arg))
|
|
44
|
+
if (this.argIdx +1 < env.args.length && !env.args[this.argIdx +1].startsWith('-')) // use --debug [targetKey]
|
|
45
|
+
this.key ??= env.args[this.argIdx +1].replace('-', '_')
|
|
46
|
+
if (this.key)
|
|
47
|
+
this.val = cli.config[this.key] || `cli.config key "${this.key}" ${cli.msgs.warn_notFound.toLowerCase()}`
|
|
48
|
+
else
|
|
49
|
+
this.val = cli.config
|
|
50
|
+
msg += `\n${colors.gry}${JSON.stringify(this.val)}${colors.nc}`
|
|
51
|
+
console.debug(`\n${colors.by}DEBUG:`, msg, colors.nc)
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
help(includeSections = ['header', 'usage', 'params', 'flags', 'cmds']) {
|
|
55
|
+
cli.prefix = `${this.colors.tlBG}${this.colors.blk}\x1b[30m ${cli.name} ${this.colors.nc} `
|
|
56
|
+
const helpSections = {
|
|
57
|
+
header: [
|
|
58
|
+
`\n├ ${cli.prefix}${cli.msgs.pkg_copyright}.`,
|
|
59
|
+
`${cli.prefix}${cli.msgs.prefix_source}: ${cli.urls.src}`
|
|
60
|
+
],
|
|
61
|
+
usage: [
|
|
62
|
+
`\n${this.colors.bw}o ${cli.msgs.helpSection_usage}:${this.colors.nc}`,
|
|
63
|
+
` ${this.colors.bw}» ${this.colors.bg}${cli.cmdFormat}${this.colors.nc}`
|
|
64
|
+
],
|
|
65
|
+
params: [
|
|
66
|
+
`\n${this.colors.bw}o ${cli.msgs.helpSection_params}:${this.colors.nc}`,
|
|
67
|
+
` --length=n ${cli.msgs.optionDesc_length}.`,
|
|
68
|
+
` --qty=n ${cli.msgs.optionDesc_qty}.`,
|
|
69
|
+
` --charset=chars ${cli.msgs.optionDesc_charset}.`,
|
|
70
|
+
` --exclude=chars ${cli.msgs.optionDesc_exclude}.`,
|
|
71
|
+
` --ui-lang="code" ${cli.msgs.optionDesc_uiLang}.`,
|
|
72
|
+
` --config="path/to/file" ${cli.msgs.optionDesc_config}.`
|
|
73
|
+
],
|
|
74
|
+
flags: [
|
|
75
|
+
`\n${this.colors.bw}o ${cli.msgs.helpSection_flags}:${this.colors.nc}`,
|
|
76
|
+
` -w, --weak ${cli.msgs.optionDesc_weak}.`,
|
|
77
|
+
` -b, --basic ${cli.msgs.optionDesc_basic}.`,
|
|
78
|
+
` -t, --strong ${cli.msgs.optionDesc_strong}.`,
|
|
79
|
+
` -N, --no-numbers ${cli.msgs.optionDesc_excludeNums}.`,
|
|
80
|
+
` -Y, --no-symbols ${cli.msgs.optionDesc_excludeSymbols}.`,
|
|
81
|
+
` -L, --no-lowercase ${cli.msgs.optionDesc_noLower}.`,
|
|
82
|
+
` -U, --no-uppercase ${cli.msgs.optionDesc_noUpper}.`,
|
|
83
|
+
` -s, --similar-chars ${cli.msgs.optionDesc_similarChars}.`,
|
|
84
|
+
` -S, --unstrict ${cli.msgs.optionDesc_unstrict}.`,
|
|
85
|
+
` -E, --no-entropy ${cli.msgs.optionDesc_noEntropy}.`,
|
|
86
|
+
` -q, --quiet ${cli.msgs.optionDesc_quiet}.`
|
|
87
|
+
],
|
|
88
|
+
cmds: [
|
|
89
|
+
`\n${this.colors.bw}o ${cli.msgs.helpSection_cmds}:${this.colors.nc}`,
|
|
90
|
+
` -i, --init ${cli.msgs.optionDesc_init}.`,
|
|
91
|
+
` -h, --help ${cli.msgs.optionDesc_help}.`,
|
|
92
|
+
` -v, --version ${cli.msgs.optionDesc_version}.`,
|
|
93
|
+
` -v, --stats ${cli.msgs.optionDesc_stats}.`,
|
|
94
|
+
` -V, --debug ${cli.msgs.optionDesc_debug}.`
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
includeSections.forEach(section => // print valid arg elems
|
|
98
|
+
helpSections[section]?.forEach(line => printHelpMsg(line, /header|usage/.test(section) ? 1 : 29)))
|
|
99
|
+
console.info(`\n${cli.msgs.info_moreHelp}, ${
|
|
100
|
+
cli.msgs.info_visit}: ${this.colors.bw}${cli.urls.cliDocs}${this.colors.nc}`)
|
|
101
|
+
|
|
102
|
+
function printHelpMsg(msg, indent) { // wrap msg + indent 2nd+ lines
|
|
103
|
+
const terminalWidth = process.stdout.columns || 80,
|
|
104
|
+
words = msg.match(/\S+|\s+/g),
|
|
105
|
+
lines = [], prefix = '| '
|
|
106
|
+
|
|
107
|
+
// Split msg into lines of appropriate lengths
|
|
108
|
+
let currentLine = ''
|
|
109
|
+
words.forEach(word => {
|
|
110
|
+
const lineLength = terminalWidth -( !lines.length ? 0 : indent )
|
|
111
|
+
if (currentLine.length + prefix.length + word.length > lineLength) { // cap/store it
|
|
112
|
+
lines.push(!lines.length ? currentLine : currentLine.trimStart())
|
|
113
|
+
currentLine = ''
|
|
114
|
+
}
|
|
115
|
+
currentLine += word
|
|
116
|
+
})
|
|
117
|
+
lines.push(!lines.length ? currentLine : currentLine.trimStart())
|
|
118
|
+
|
|
119
|
+
// Print formatted msg
|
|
120
|
+
lines.forEach((line, idx) => console.info(prefix +(
|
|
121
|
+
idx == 0 ? line // print 1st line unindented
|
|
122
|
+
: ' '.repeat(indent) + line // print subsequent lines indented
|
|
123
|
+
)))
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
helpDocsCmdsDocsURL() {
|
|
128
|
+
console.info(`\n${
|
|
129
|
+
cli.msgs.info_moreHelp}, ${cli.msgs.info_type} ${
|
|
130
|
+
colors.bw}${cli.name} --<docs|help>${colors.nc} ${
|
|
131
|
+
cli.msgs.info_or} ${cli.msgs.info_visit}\n${colors.by}${cli.urls.docs}${colors.nc}`
|
|
132
|
+
)
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
initCmd(invalidKey) {
|
|
136
|
+
if (invalidKey)
|
|
137
|
+
this.warn(
|
|
138
|
+
`${cli.msgs.error_invalidKey} '${invalidKey}' ${cli.msgs.error_foundIn}\n`
|
|
139
|
+
+ `${log.colors.gry}${cli.configPath}`
|
|
140
|
+
)
|
|
141
|
+
if (!this.initTipped) {
|
|
142
|
+
this.break()
|
|
143
|
+
this.tip(`${
|
|
144
|
+
string.toTitleCase(cli.msgs.info_type)} '${cli.name} init' ${
|
|
145
|
+
cli.msgs.info_toCreateDefaultConfig}`
|
|
146
|
+
)
|
|
147
|
+
this.initTipped = true
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
invalidConfigKey(key) { if (!this[`${key}Tipped`]) { this.initCmd(key) ; this[`${key}Tipped`] = true } },
|
|
152
|
+
|
|
153
|
+
async stats(pkgName = cli.name, options = { ecosystem: 'npm', maxDays: 8, maxVers: 5, scheme: 'default' }) {
|
|
154
|
+
const pkgStats = await getDownloads(pkgName, options),
|
|
155
|
+
schemeData = colors.schemes[options.scheme]
|
|
156
|
+
if (!schemeData) return this.error(`Scheme '${options.scheme}' not found!`)
|
|
157
|
+
const colorMap = Object.fromEntries(schemeData.map((hex, idx) => [`c${idx}`, hex])),
|
|
158
|
+
statsTable = new (require('console-table-printer').Table)({ colorMap })
|
|
159
|
+
pkgStats.forEach((row, idx) => // build colored rows
|
|
160
|
+
statsTable.addRow(row, { color: `c${Math.floor(idx / pkgStats.length * schemeData.length)}` }))
|
|
161
|
+
statsTable.printTable()
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
version() {
|
|
165
|
+
this.info(cli.name)
|
|
166
|
+
this.data(`${
|
|
167
|
+
cli.msgs.prefix_globalVer}: ${ getVer('global') || 'none' }\n${
|
|
168
|
+
cli.msgs.prefix_localVer }: ${ getVer('local') || 'none' }`
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const data = require('./data')
|
|
2
|
+
|
|
3
|
+
const endpoints = {
|
|
4
|
+
npmjsDLs: 'https://api.npmjs.org/downloads',
|
|
5
|
+
pepyProjects: 'https://pepy.tech/projects'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
|
|
10
|
+
async getDownloads(
|
|
11
|
+
pkgName, // e.g. some-npm-pkg, npm:@adamlui/minify.js, pypi:translate-messages
|
|
12
|
+
{ ecosystem = 'npm', maxDays = 10, maxVers = 10 } = {}
|
|
13
|
+
) {
|
|
14
|
+
if (pkgName.includes(':')) [ecosystem, pkgName] = pkgName.split(':')
|
|
15
|
+
|
|
16
|
+
if (/npm|node/i.test(ecosystem)) { // fetch from endpoints.npmjsDLs
|
|
17
|
+
function formatDate(date) { return date.toISOString().split('T')[0] }
|
|
18
|
+
const dates = { end: new Date(), start: new Date() }
|
|
19
|
+
dates.start.setMonth(dates.end.getMonth() -3)
|
|
20
|
+
const npmjsURL = `${endpoints.npmjsDLs}/range/${formatDate(dates.start)}:${formatDate(dates.end)}/${pkgName}`
|
|
21
|
+
log.info(`Fetching npm stats for ${pkgName}${
|
|
22
|
+
env.modes.debug ? ` from\n${log.colors.bw}${npmjsURL}` : '' }...\n`)
|
|
23
|
+
return (await (await data.fetch(npmjsURL)).json()).downloads // { downloads: [{ day, downloads }] }
|
|
24
|
+
.sort((a, b) => new Date(b.day) - new Date(a.day)) // new ⇅ old
|
|
25
|
+
.slice(0, maxDays) // cap rows
|
|
26
|
+
.map(({ day: date, downloads }) => ({ date, downloads }))
|
|
27
|
+
|
|
28
|
+
} else if (/^py/i.test(ecosystem)) { // fetch from endpoints.pepyProjects
|
|
29
|
+
let rows = []
|
|
30
|
+
const pepyURL = `${endpoints.pepyProjects}/${pkgName}`
|
|
31
|
+
log.info(`Fetching PyPI/mirror stats for ${pkgName}${
|
|
32
|
+
env.modes.debug ? ` from\n${log.colors.bw}${pepyURL}` : '' }...\n`)
|
|
33
|
+
const respText = await (await data.fetch(pepyURL)).text(),
|
|
34
|
+
rePush = /self\.__next_f\.push\(\[\d+,\s*"((?:\\.|[^"\\])*)"\]\)/g
|
|
35
|
+
let downloads = {}, match
|
|
36
|
+
while ((match = rePush.exec(respText))) {
|
|
37
|
+
try { // extract project.downloads
|
|
38
|
+
const inner = JSON.parse(`"${match[1]}"`),
|
|
39
|
+
data = JSON.parse(inner.substring(inner.indexOf(':') +1))
|
|
40
|
+
if (data[3]?.project) downloads = data[3].project.downloads
|
|
41
|
+
} catch (err) {}
|
|
42
|
+
}
|
|
43
|
+
rows = Object.entries(downloads)
|
|
44
|
+
.sort(([a], [b]) => new Date(b) - new Date(a)) // new ⇅ old
|
|
45
|
+
.slice(0, maxDays) // cap rows
|
|
46
|
+
.map(([date, data]) => ({ date, ...data }))
|
|
47
|
+
const activeVers = new Set()
|
|
48
|
+
rows.forEach(row => Object.keys(row).forEach(key => {
|
|
49
|
+
if (key != 'date' && row[key] > 0) activeVers.add(key) }))
|
|
50
|
+
const finalVers = [...activeVers]
|
|
51
|
+
.sort((a, b) => b.localeCompare(a, undefined, { numeric: true })) // new ⇆ old
|
|
52
|
+
.slice(0, maxVers) // cap columns
|
|
53
|
+
return rows.map(row => {
|
|
54
|
+
const result = { date: row.date }
|
|
55
|
+
finalVers.forEach(ver => result[ver] = row[ver] || 0)
|
|
56
|
+
return result
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
} else return log.debug(`${ecosystem} not supported.`)
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
getVer(type = 'any') { // or <'global'|'local'>
|
|
63
|
+
let pkgVer
|
|
64
|
+
if (type != 'global')
|
|
65
|
+
try { // get local ver
|
|
66
|
+
const localManifestPath = require('path').resolve(
|
|
67
|
+
process.cwd(), 'node_modules', cli.name, 'package.json')
|
|
68
|
+
pkgVer = require(localManifestPath).version
|
|
69
|
+
} catch (err) { log.debug(`${cli.msgs.error_readingLocalPkgVer}: ${err.message}`) }
|
|
70
|
+
if (type == 'global' || type == 'all' && !pkgVer)
|
|
71
|
+
try { // get global ver
|
|
72
|
+
pkgVer = require('child_process').execSync(
|
|
73
|
+
`npm view ${JSON.stringify(cli.name)} version`
|
|
74
|
+
).toString().trim()
|
|
75
|
+
} catch (err) { log.debug(`${cli.msgs.error_failedToFetchGlobalVer}: ${err.message}`) }
|
|
76
|
+
return pkgVer
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
const fs = require('fs'),
|
|
2
|
+
path = require('path')
|
|
3
|
+
|
|
4
|
+
;(globalThis.cli ??= {}).config = {}
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
configFilename: 'generate-pw.config.mjs',
|
|
8
|
+
configFileKeyWhitelist: ['strength'],
|
|
9
|
+
|
|
10
|
+
controls: {
|
|
11
|
+
length: { type: 'param', valType: 'positiveInt', defaultVal: 12, regex: /^--?length(?:[=\s].*|$)/},
|
|
12
|
+
qty: { type: 'param', valType: 'positiveInt', defaultVal: 1, regex: /^--?qu?a?n?ti?t?y(?:[=\s].*|$)/},
|
|
13
|
+
charset: { type: 'param', regex: /^--?char[-_]?se?t?(?:[=\s].*|$)/ },
|
|
14
|
+
excludeChars: { type: 'param', regex:/^--?exclude(?:[=\s].*|$)/ },
|
|
15
|
+
uiLang: { type: 'param', valType: 'langCode', regex: /^--?ui[-_]?lang(?:[=\s].*|$)/ },
|
|
16
|
+
config: { type: 'param', valType: 'filepath', regex: /^--?config(?:[=\s].*|$)/ },
|
|
17
|
+
weak: { type: 'flag', mode: true, regex: /^--?(?:w|weak)$/ },
|
|
18
|
+
basic: { type: 'flag', mode: true, regex: /^--?(?:b|basic)$/ },
|
|
19
|
+
strong: { type: 'flag', mode: true, regex: /^--?(?:t|strong)$/ },
|
|
20
|
+
excludeNums: { type: 'flag', regex: /^--?(?:N|(?:exclude|disable|no)[-_]?num(?:ber)?s?=?(?:true|1)?)$/ },
|
|
21
|
+
excludeSymbols: { type: 'flag', regex: /^--?(?:Y|(?:exclude|disable|no)[-_]?symbols?=?(?:true|1)?)$/ },
|
|
22
|
+
excludeLowerChars: {
|
|
23
|
+
type: 'flag',
|
|
24
|
+
regex: /^--?(?:L|(?:exclude|disable|no)[-_]?lower[-_]?(?:case)?|lower[-_]?(?:case)?=(?:false|0))$/
|
|
25
|
+
},
|
|
26
|
+
excludeUpperChars: {
|
|
27
|
+
type: 'flag',
|
|
28
|
+
regex: /^--?(?:U|(?:exclude|disable|no)[-_]?upper[-_]?(?:case)?|upper[-_]?(?:case)?=(?:false|0))$/
|
|
29
|
+
},
|
|
30
|
+
similarChars: { type: 'flag', regex: /^--?(?:s|(?:include[-_]?)?similar[-_]?chars?=?(?:true|1)?)$/ },
|
|
31
|
+
unstrict: { type: 'flag', regex: /^--?(?:S|(?:un[-_]?strict)?(?:[-_]?mode)?)$/ },
|
|
32
|
+
noEntropy: { type: 'flag', regex: /^--?(?:E|no[-_]?e(?:ntropy)?)$/ },
|
|
33
|
+
quietMode: { type: 'flag', regex: /^--?q(?:uiet)?(?:[-_]?mode)?$/ },
|
|
34
|
+
init: { type: 'cmd', regex: /^-{0,2}i(?:nit)?$/ },
|
|
35
|
+
help: { type: 'cmd', regex: /^--?h(?:elp)?$/ },
|
|
36
|
+
version: { type: 'cmd', regex: /^--?ve?r?s?i?o?n?$/ },
|
|
37
|
+
stats: { type: 'cmd', regex: /^--?stats?$/ },
|
|
38
|
+
entropy: { type: 'legacy', replacedBy: 'noEntropy', regex: /^--?e(?:ntropy)?$/ }
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
load(ctrlKeys = Object.keys(this.controls)) {
|
|
42
|
+
const inputCtrlKeys = [].concat(ctrlKeys) // force array
|
|
43
|
+
|
|
44
|
+
if (!cli.defaultsSet && !arguments.length) { // init all defaults on arg-less load()
|
|
45
|
+
inputCtrlKeys.forEach(key => {
|
|
46
|
+
const ctrl = this.controls[key] ; if (ctrl.mode || ctrl.type == 'legacy') return
|
|
47
|
+
cli.config[key] ??= ctrl.defaultVal ?? ( ctrl.type == 'param' ? '' : false )
|
|
48
|
+
})
|
|
49
|
+
cli.defaultsSet = true
|
|
50
|
+
log.debug('All cli.config default vals set!')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!cli.configPathTried) { // init config file path
|
|
54
|
+
const configArg = env.args.find(arg => this.controls.config.regex.test(arg))
|
|
55
|
+
|
|
56
|
+
if (configArg) { // resolve input path, then validate
|
|
57
|
+
if (!/=/.test(configArg))
|
|
58
|
+
log.errorAndExit(`[${configArg}] ${cli.msgs.error_mustIncludePath}`)
|
|
59
|
+
const inputPath = configArg.split('=')[1]
|
|
60
|
+
cli.configPath = path.isAbsolute(inputPath) ? inputPath : path.resolve(process.cwd(), inputPath)
|
|
61
|
+
if (!fs.existsSync(cli.configPath))
|
|
62
|
+
log.configURLandExit(`${cli.msgs.error_configFileNotFound}:`, cli.configPath)
|
|
63
|
+
|
|
64
|
+
} else // auto-discover .config.[mc]?js file
|
|
65
|
+
for (const configExt of ['.mjs', '.cjs', '.js']) {
|
|
66
|
+
const autoPath = path.resolve(process.cwd(), this.configFilename.replace(/\.[^.]+$/, configExt))
|
|
67
|
+
if (fs.existsSync(autoPath)) { cli.configPath = autoPath ; break }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
cli.configPathTried = true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (cli.configPath) // load from config file
|
|
74
|
+
try {
|
|
75
|
+
const mod = require(cli.configPath), fileConfig = mod?.default ?? mod
|
|
76
|
+
if (!fileConfig || typeof fileConfig != 'object')
|
|
77
|
+
log.configURLandExit(`${cli.msgs.error_invalidConfigFile}.`)
|
|
78
|
+
;(arguments.length ? inputCtrlKeys : Object.keys(fileConfig)).forEach(key => {
|
|
79
|
+
if (!(key in fileConfig)) return
|
|
80
|
+
const val = fileConfig[key], ctrl = this.controls[key]
|
|
81
|
+
if (!ctrl) {
|
|
82
|
+
if (this.configFileKeyWhitelist && !this.configFileKeyWhitelist.includes(key))
|
|
83
|
+
log.invalidConfigKey(key)
|
|
84
|
+
return
|
|
85
|
+
} else if (ctrl.type == 'legacy' && ctrl.replacedBy) {
|
|
86
|
+
if (key.toLowerCase().includes('no') != ctrl.replacedBy.toLowerCase().includes('no'))
|
|
87
|
+
cli.config[ctrl.replacedBy] = !val // assign opposite val to current key
|
|
88
|
+
else // assign direct val to current key
|
|
89
|
+
cli.config[ctrl.replacedBy] = val
|
|
90
|
+
return log.configKeyReplacedBy(key, ctrl.replacedBy, val)
|
|
91
|
+
}
|
|
92
|
+
cli.config[key] = val
|
|
93
|
+
})
|
|
94
|
+
if (!arguments.length) log.debug('Config file loaded!')
|
|
95
|
+
} catch (err) {
|
|
96
|
+
log.configURLandExit(`${cli.msgs.error_failedToLoadConfigFile}:`, cli.configPath, `\n${err.message}`) }
|
|
97
|
+
|
|
98
|
+
for (let i = 0 ; i < env.args.length ; i++) { // load from CLI arg (overriding config file loads)
|
|
99
|
+
const arg = env.args[i]
|
|
100
|
+
if (/^[^-]|--?(?:config|debug)/.test(arg) && arg != 'init') continue
|
|
101
|
+
const ctrlKey = Object.keys(this.controls).find(key => this.controls[key]?.regex?.test(arg))
|
|
102
|
+
if (!ctrlKey && cli.msgs) log.errorAndExit(`[${arg}] ${cli.msgs.error_notRecognized}.`)
|
|
103
|
+
if (!inputCtrlKeys.includes(ctrlKey)) return // don't process env.args when load() specific keys
|
|
104
|
+
const ctrl = this.controls[ctrlKey]
|
|
105
|
+
if (ctrl.type == 'legacy') { log.argDoesNothing(arg) ; continue }
|
|
106
|
+
if (ctrl.mode) // set cli.config.mode to mode name
|
|
107
|
+
cli.config.mode = ctrlKey.replace(/mode$/i, '').toLowerCase()
|
|
108
|
+
else { // init flag/param/cmd cli.config[ctrlKey] val
|
|
109
|
+
if (ctrl.type == 'param')
|
|
110
|
+
cli.config[ctrlKey] =
|
|
111
|
+
arg.includes('=') ? arg.split('=')[1]?.trim() || '' // =val
|
|
112
|
+
: (i +1 < env.args.length && !env.args[i +1].startsWith('-')) ? env.args[++i] // dashless val
|
|
113
|
+
: '' // val-less --param passed
|
|
114
|
+
else // flag/cmd
|
|
115
|
+
cli.config[ctrlKey] = true
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!arguments.length) log.debug('Args parsed!')
|
|
120
|
+
|
|
121
|
+
this.parseValidateConfig(inputCtrlKeys)
|
|
122
|
+
if (!arguments.length) log.debug('All cli.config vals parsed/validated!')
|
|
123
|
+
|
|
124
|
+
return inputCtrlKeys.length == 1 ? cli.config[inputCtrlKeys[0]] : cli.config
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
parseValidateConfig(ctrlKeys = Object.keys(this.controls)) {
|
|
128
|
+
const language = require('./language')
|
|
129
|
+
for (const key of [].concat(ctrlKeys)) {
|
|
130
|
+
const ctrl = this.controls[key], configVal = cli.config[key]
|
|
131
|
+
|
|
132
|
+
if (ctrl.parser && !ctrl.parsed) {
|
|
133
|
+
cli.config[key] = ctrl.parser(configVal) ; ctrl.parsed = true }
|
|
134
|
+
|
|
135
|
+
if (ctrl.valType) ({
|
|
136
|
+
positiveInt() {
|
|
137
|
+
const numVal = parseInt(configVal, 10)
|
|
138
|
+
if (isNaN(numVal) || numVal < 1)
|
|
139
|
+
log.errorAndExit(`[${key}] ${cli.msgs.error_nonPositiveNum}: ${configVal}`)
|
|
140
|
+
cli.config[key] = numVal
|
|
141
|
+
},
|
|
142
|
+
filepath() {
|
|
143
|
+
if (configVal && !fs.existsSync(configVal))
|
|
144
|
+
log.errorAndExit(`[${key}] ${cli.msgs.error_invalidFilepath}: ${configVal}`)
|
|
145
|
+
},
|
|
146
|
+
langCode() {
|
|
147
|
+
if (configVal && !language.validateLangCode(configVal))
|
|
148
|
+
log.errorAndExit(`[${key}] ${cli.msgs.error_invalidLangCode}: ${configVal}`)
|
|
149
|
+
}
|
|
150
|
+
})[ctrl.valType]()
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -23,10 +23,10 @@ export default {
|
|
|
23
23
|
similarChars: false, // include similar chars (e.g. o,0,O,i,l,1,\|) in password(s)
|
|
24
24
|
unstrict: false, // don't require 1+ char from each allowed charset in password(s)
|
|
25
25
|
charset: '', // only include chars in password(s)
|
|
26
|
-
|
|
26
|
+
excludeChars: '', // exclude chars from password(s)
|
|
27
27
|
|
|
28
28
|
// Info options
|
|
29
|
-
|
|
29
|
+
noEntropy: false, // calculate/log estimated entropy
|
|
30
30
|
quietMode: false, // suppress all logging except errors
|
|
31
31
|
uiLang: '' // ISO 639-1 code of language to display UI in
|
|
32
32
|
}
|
package/dist/data/messages.json
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"appCopyright": { "message": "© 2024–2026 Adam Lui & contributors under the MIT license" },
|
|
2
|
+
"pkg_copyright": { "message": "© 2024–2026 Adam Lui & contributors under the MIT license" },
|
|
4
3
|
"prefix_globalVer": { "message": "Global version" },
|
|
5
4
|
"prefix_localVer": { "message": "Local version" },
|
|
6
5
|
"prefix_source": { "message": "Source" },
|
|
@@ -11,6 +10,8 @@
|
|
|
11
10
|
"error_invalidLangCode": { "message": "is an invalid language code" },
|
|
12
11
|
"error_invalidURL": { "message": "Invalid URL" },
|
|
13
12
|
"error_invalidConfigFile": { "message": "Config file must export an object" },
|
|
13
|
+
"error_invalidKey": { "message": "Invalid key" },
|
|
14
|
+
"error_foundIn": { "message": "found in" },
|
|
14
15
|
"error_configFileNotFound": { "message": "Config file not found" },
|
|
15
16
|
"error_failedToLoadConfigFile": { "message": "Failed to load config file" },
|
|
16
17
|
"error_failedToFetchGlobalVer": { "message": "Failed to fetch global version" },
|
|
@@ -20,12 +21,19 @@
|
|
|
20
21
|
"warn_docLocalesFetchFailed": { "message": "Failed to fetch doc locales" },
|
|
21
22
|
"warn_remoteConfigNotFound": { "message": "Remote config file not found" },
|
|
22
23
|
"warn_remoteConfigFailed": { "message": "Failed to fetch remote config file" },
|
|
24
|
+
"warn_option": { "message": "Option" },
|
|
25
|
+
"warn_noLongerHasAnyEffect": { "message": "no longer has any effect" },
|
|
26
|
+
"warn_hasBeenReplacedBy": { "message": "has been replaced by" },
|
|
27
|
+
"warn_andWillBeRemoved": { "message": "and will be removed" },
|
|
28
|
+
"warn_notFound": { "message": "Not found" },
|
|
29
|
+
"info_configFile": { "message": "Config file" },
|
|
23
30
|
"info_exampleValidConfigFile": { "message": "Example valid config file" },
|
|
24
31
|
"info_copyingToClip": { "message": "Copying to clipboard" },
|
|
25
32
|
"info_moreHelp": { "message": "For more help" },
|
|
26
33
|
"info_type": { "message": "type" },
|
|
27
34
|
"info_or": { "message": "or" },
|
|
28
35
|
"info_visit": { "message": "visit" },
|
|
36
|
+
"info_toCreateDefaultConfig": { "message": "to create default config file" },
|
|
29
37
|
"info_configFileCreated": { "message": "Config file created" },
|
|
30
38
|
"info_fetchingRemoteConfigFrom": { "message": "Fetching remote config file from" },
|
|
31
39
|
"tip_editToSetDefaults": { "message": "Edit this file to customize defaults" },
|
|
@@ -49,9 +57,11 @@
|
|
|
49
57
|
"optionDesc_noUpper": { "message": "Disallow uppercase letters in password(s)" },
|
|
50
58
|
"optionDesc_similarChars": { "message": "Include similar characters in password(s)" },
|
|
51
59
|
"optionDesc_unstrict": { "message": "Don't require at least one character from each allowed character set in password(s)" },
|
|
52
|
-
"
|
|
60
|
+
"optionDesc_noEntropy": { "message": "Don't calculate/log estimated entropy" },
|
|
53
61
|
"optionDesc_quiet": { "message": "Suppress all logging except errors" },
|
|
54
62
|
"optionDesc_help": { "message": "Display help screen" },
|
|
55
63
|
"optionDesc_init": { "message": "Create config file (in project root)" },
|
|
56
|
-
"optionDesc_version": { "message": "Show version number" }
|
|
64
|
+
"optionDesc_version": { "message": "Show version number" },
|
|
65
|
+
"optionDesc_stats": { "message": "Show npm stats" },
|
|
66
|
+
"optionDesc_debug": { "message": "Show debug logs" }
|
|
57
67
|
}
|
package/dist/generate-pw.min.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* Source: https://github.com/adamlui/js-utils/tree/main/generate-pw/src
|
|
4
4
|
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-pw/docs
|
|
5
5
|
*/
|
|
6
|
-
function generatePassword(s={}){var e={verbose:!0,length:12,qty:1,strength:"",charset:"",exclude:"",numbers:!0,symbols:!0,lowercase:!0,uppercase:!0,similarChars:!1,strict:!0,entropy:!
|
|
6
|
+
function generatePassword(s={}){var e={verbose:!0,length:12,qty:1,strength:"",charset:"",exclude:"",numbers:!0,symbols:!0,lowercase:!0,uppercase:!0,similarChars:!1,strict:!0,entropy:!0};if(_log.prefix="generatePassword()",_validateOptions({options:s,defaultOptions:e,helpURL:"https://github.com/adamlui/js-utils/tree/main/generate-pw/docs/#generatepasswordoptions",exampleCall:"generatePassword({ verbose: false, numbers: true })"})){if(1<(s=(s={...e,...s}).strength&&(e=api.strengthPresets[s.strength.toLowerCase()])?{...s,...e}:s).qty){let{qty:e,...r}=s;return generatePasswords(e,r)}{var o,e="generatePasswords"==generatePassword.caller?.name;s.verbose&&!e&&_log.info("Initializing character set...");let r=s.charset?.toString()||(s.numbers?api.charsets.numbers:"")+(s.symbols?api.charsets.symbols:"")+(s.lowercase?api.charsets.lower:"")+(s.uppercase?api.charsets.upper:""),t=(""==r&&(r=api.charsets.lower+api.charsets.upper),s.exclude&&(s.verbose&&!e&&_log.info("Removing excluded characters..."),r=r.replace(new RegExp(`[${s.exclude}]`,"g"),"")),s.similarChars||(s.verbose&&!e&&_log.info("Excluding similar characters..."),r=r.replace(/[o0Oil1|]/g,"")),s.verbose&&!e&&_log.info("Generating password..."),"");for(let e=0;e<s.length;e++){var a=randomInt(0,r.length);t+=r[a]}return s.strict&&!s.charset&&(s.verbose&&!e&&_log.info("Enforcing strict mode..."),o=["numbers","symbols","lower","upper"].filter(e=>s[e]||s[e+"case"]),t=strictify(t,o)),s.verbose&&(e||(_log.info("Password generated!"),"undefined"!=typeof window&&_log.info("Check returned string.")),s.entropy)&&(e=(o=r.length)<2?0:Math.log2(o**t.length),_log.info(`Estimated entropy: ${e.toFixed(2)} bits (charset length: ${o})`)),t}}}function generatePasswords(r,t={}){var e="https://github.com/adamlui/js-utils/tree/main/generate-pw/docs/#generatepasswordsqty-options",s={verbose:!0,length:12,strength:"",charset:"",exclude:"",numbers:!0,symbols:!0,lowercase:!0,uppercase:!0,similarChars:!1,strict:!0,entropy:!0};if(_log.prefix="generatePasswords()",r=parseInt(r,10),(isNaN(r)||r<1)&&_log.errHelpURLandThrow({errMsg:"1st arg <qty> can only be an integer > 0.",helpURL:e}),_validateOptions({options:t,defaultOptions:s,helpURL:e,exampleCall:"generatePasswords(3, { verbose: false, symbols: true })"})){(t=(t={...s,...t}).strength&&(e=api.strengthPresets[t.strength.toLowerCase()])?{...t,...e}:t).verbose&&_log.info(`Generating password${1<r?"s":""}...`);var o=[];for(let e=0;e<r;e++)o.push(generatePassword(t));return t.verbose&&(_log.info(`Password${1<r?"s":""} generated!`),"undefined"!=typeof window)&&_log.info("Check returned array."),o}}function strictify(a,n=["numbers","symbols","lower","upper"],e={}){var r,t="https://github.com/adamlui/js-utils/tree/main/generate-pw/docs/#strictifypassword-requiredchartypes-options",i={verbose:!0},s=(_log.prefix="strictify()","string"!=typeof a&&_log.errHelpURLandThrow({errMsg:"1st arg <password> must be a string.",helpURL:t}),["numbers","symbols","lower","upper"]);for(r of n=[].concat(n))if(!s.includes(r))return _log.error(`2nd arg \`${r}\` is an invalid character type.`),void _log.info([`Valid character types: ['${s.join("', '")}']`,"Pass one as a string or more as an array, or all types will be required.","For more help, please visit "+t].join("\n"));if(a.length<n.length){for(;n.length>a.length;)n.splice(randomInt(0,n.length),1);_log.info("Reduced required char types to: "+n.join(", "))}if(_validateOptions({options:e,defaultOptions:i,helpURL:t,exampleCall:"strictify('pa55word', ['symbol', 'upper'], { verbose: false })"})){e={...i,...e};let r={},t=[];n.forEach(e=>r[e]=!1);for(let e=0;e<a.length;e++)for(var l of n)!r[l]&&api.charsets[l].includes(a[e])&&(r[l]=!0,t.push(e));e.verbose&&_log.info("Strictifying password...");var p,g=Math.min(a.length,n.length);let s=0,o=a;for(p of n)if(s<g&&!r[p]){let e;for(;e=randomInt(0,a.length),t.includes(e););t.push(e);var c=api.charsets[p]||api.charsets[p+"s"];o=o.substring(0,e)+c[randomInt(0,c.length)]+o.substring(e+1),s++}return e.verbose&&(0<s?(_log.info("Password is now strict!"),_log.info("Check returned string.")):(_log.info(`Password already includes ${n.join(" + ")} characters!`),_log.info("No modifications made."))),o}}function validateStrength(r,t={}){var e="https://github.com/adamlui/js-utils/tree/main/generate-pw/docs/#validatestrengthpassword-options",s={minlength:12,minLower:1,minUpper:1,minNumber:1,minSymbol:1},o={verbose:!0};if(_log.prefix="validateStrength()","string"!=typeof r&&_log.errHelpURLandThrow({errMsg:"1st arg <password> must be a string.",helpURL:e}),_validateOptions({options:t,defaultOptions:o,helpURL:e,exampleCall:"validateStrength('pa55word', { verbose: false })"})){(t={...o,...t}).verbose&&_log.info("Validating password strength...");var a,n={lower:0,upper:0,number:0,symbol:0};for(a of r)for(var i of Object.keys(n))(api.charsets[i]||api.charsets[i+"s"]).includes(a)&&n[i]++;var l,p,g=[];r.length<s.minLength&&g.push(`Make it at least ${s.minLength} characters long.`);for(l of Object.keys(n))n[l]<s["min"+l[0].toUpperCase()+l.slice(1)]&&g.push(`Include at least one ${l}${["upper","lower"].includes(l)?"case letter":""}.`);let e=0;e+=r.length>=s.minLength?20:0;for(p of Object.keys(n))e+=n[p]>=s["min"+p[0].toUpperCase()+p.slice(1)]?20:0;return t.verbose&&(_log.info("Password strength validated!"),_log.info("Check returned object for score/recommendations.")),{strengthScore:e,recommendations:g,isGood:80<=e}}}function randomInt(e,r){var t;return"undefined"==typeof require?(t=(window.crypto||window.msCrypto)?.getRandomValues(new Uint32Array(1))[0]/4294967295||Math.random(),Math.floor(t*(r-e))+e):require("crypto").randomInt(e,r)}function _validateOptions({options:e,defaultOptions:r,helpURL:t,exampleCall:s}){var o=Object.keys(r).filter(e=>"boolean"==typeof r[e]),a=Object.keys(r).filter(e=>Number.isInteger(r[e]));if("object"!=typeof e)return i=s.split(",").findIndex(e=>e.trim().startsWith("{"))+1,i+=["st","nd","rd"][i-1]||"th",_log.error(`${"0th"==i?"[O":i+" arg [o"}ptions] can only be an object of key/vals.`),_log.info("Example valid call:",s),_log.validOptions(r),_log.helpURL(t),!1;var n,i=["weak","basic","strong"];if("strength"in e&&e.strength&&!i.includes(e.strength.toLowerCase()))return _log.error("[strength] must be one of: "+i.join(", ")),_log.helpURL(t),!1;for(n in e){if(!Object.prototype.hasOwnProperty.call(r,n))return _log.error(`\`${n}\` is an invalid option.`),_log.validOptions(r),_log.helpURL(t),!1;if(o.includes(n)&&"boolean"!=typeof e[n])return _log.error(`[${n}] option can only be \`true\` or \`false\`.`),_log.helpURL(t),!1;if(a.includes(n)&&(e[n]=parseInt(e[n],10),isNaN(e[n])||e[n]<1))return _log.error(`[${n}] option can only be an integer > 0.`),_log.helpURL(t),!1}return!0}Object.assign(globalThis.api??={},{name:"generate-pw",regex:{generatePassword:/^gen(?:erate)?(?:password|pw)?$/i,generatePasswords:/^gen(?:erate)?(?:password|pw)s$/i,strictify:/^strictify$/i,validateStrength:/^validate(?:strength)?$/i},charsets:{lower:"abcdefghijklmnopqrstuvwxyz",upper:"ABCDEFGHIJKLMNOPQRSTUVWXYZ",numbers:"0123456789",symbols:"!@#$%^&*()-_=+[]{}/\\|;:'\",.<>?"},strengthPresets:{weak:{length:6,lowercase:!0,uppercase:!1,numbers:!1,symbols:!1,similarChars:!0,strict:!1},basic:{length:8,lowercase:!0,uppercase:!0,numbers:!0,symbols:!1,similarChars:!0,strict:!1},strong:{length:12,lowercase:!0,uppercase:!0,numbers:!0,symbols:!0,similarChars:!1,strict:!0}}});let _log={prefix:api.name,errHelpURLandThrow({errMsg:e,helpURL:r}){throw this.error(e),this.helpURL(r),new Error(e)},error(...e){console.error(this.prefix+" » ERROR:",...e)},helpURL(e=api.urls?.docs){this.info("For more help, please visit",e)},info(...e){console.info(this.prefix+" »",...e)},validOptions(e){var r=Object.keys(e).join(", "),e=JSON.stringify(e,null,2).replace(/"([^"]+)":/g,"$1:").replace(/"/g,"'").replace(/\n\s*/g," ");this.info(`Valid options: [${r}]`),this.info("If omitted, default settings are: "+e)}};api.exports=new Proxy({generatePassword:generatePassword,generatePasswords:generatePasswords,strictify:strictify,validateStrength:validateStrength},{get(e,r){for(var[t,s]of Object.entries(api.regex))if(s.test(r))return e[t]}});try{module.exports=api.exports}catch(e){}try{Object.assign(window,api.exports)}catch(e){}
|
package/docs/README.md
CHANGED
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
<img height=31 src="https://img.shields.io/npm/dm/generate-pw?logo=npm&color=af68ff&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
26
26
|
<a href="#%EF%B8%8F-mit-license">
|
|
27
27
|
<img height=31 src="https://img.shields.io/badge/License-MIT-orange.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
28
|
-
<a href="https://github.com/adamlui/js-utils/releases/tag/generate-pw-2.
|
|
29
|
-
<img height=31 src="https://img.shields.io/badge/Latest_Build-2.
|
|
28
|
+
<a href="https://github.com/adamlui/js-utils/releases/tag/generate-pw-2.2.0">
|
|
29
|
+
<img height=31 src="https://img.shields.io/badge/Latest_Build-2.2.0-44cc11.svg?logo=icinga&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
30
30
|
<a href="https://www.npmjs.com/package/generate-pw?activeTab=code">
|
|
31
31
|
<img height=31 src="https://img.shields.io/npm/unpacked-size/generate-pw?style=for-the-badge&logo=ebox&logoColor=white&labelColor=464646&color=blue"></a>
|
|
32
|
-
<a href="
|
|
33
|
-
<img height=31 src="https://img.shields.io/
|
|
32
|
+
<a href="#">
|
|
33
|
+
<img height=31 src="https://img.shields.io/bundlejs/size/generate-pw%402.1.2?label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
|
|
34
34
|
<a href="https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=adamlui_js-utils:generate-pw/src/generate-pw.js">
|
|
35
35
|
<img height=31 src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fsonarcloud.io%2Fapi%2Fmeasures%2Fcomponent%3Fcomponent%3Dadamlui_js-utils%3Agenerate-pw%2Fsrc%2Fgenerate-pw.js%26metricKeys%3Dvulnerabilities&query=%24.component.measures.0.value&style=for-the-badge&logo=sonarcloud&logoColor=white&labelColor=464646&label=Vulnerabilities&color=gold"></a>
|
|
36
36
|
<a href="https://github.com/toolleeo/cli-apps#password-managers">
|
|
@@ -94,14 +94,14 @@ const pw = require('generate-pw')
|
|
|
94
94
|
#### <> HTML script tag:
|
|
95
95
|
|
|
96
96
|
```html
|
|
97
|
-
<script src="https://cdn.jsdelivr.net/npm/generate-pw@2.
|
|
97
|
+
<script src="https://cdn.jsdelivr.net/npm/generate-pw@2.2.0/dist/generate-pw.min.js"></script>
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
#### ES6:
|
|
101
101
|
|
|
102
102
|
```js
|
|
103
103
|
(async () => {
|
|
104
|
-
await import('https://cdn.jsdelivr.net/npm/generate-pw@2.
|
|
104
|
+
await import('https://cdn.jsdelivr.net/npm/generate-pw@2.2.0/dist/generate-pw.min.js')
|
|
105
105
|
// Your code here...
|
|
106
106
|
})()
|
|
107
107
|
```
|
|
@@ -110,7 +110,7 @@ const pw = require('generate-pw')
|
|
|
110
110
|
|
|
111
111
|
```js
|
|
112
112
|
...
|
|
113
|
-
// @require https://cdn.jsdelivr.net/npm/generate-pw@2.
|
|
113
|
+
// @require https://cdn.jsdelivr.net/npm/generate-pw@2.2.0/dist/generate-pw.min.js
|
|
114
114
|
// ==/UserScript==
|
|
115
115
|
|
|
116
116
|
// Your code here...
|
|
@@ -118,7 +118,7 @@ const pw = require('generate-pw')
|
|
|
118
118
|
|
|
119
119
|
<br>
|
|
120
120
|
|
|
121
|
-
**💡 Note:** To always import the latest version (not recommended in production!) remove the `@2.
|
|
121
|
+
**💡 Note:** To always import the latest version (not recommended in production!) remove the `@2.2.0` version tag from the jsDelivr URL: `https://cdn.jsdelivr.net/npm/generate-pw/dist/generate-pw.min.js`
|
|
122
122
|
|
|
123
123
|
<br>
|
|
124
124
|
|
|
@@ -255,7 +255,7 @@ Name | Type | Description
|
|
|
255
255
|
`uppercase` | Boolean | Allow uppercase letters in password(s). | `true`
|
|
256
256
|
`similarChars` | Boolean | Include similar characters (e.g. o,0,O,i,l,1,\|) in password(s). | `false`
|
|
257
257
|
`strict` | Boolean | Require at least one character from each allowed character set in password(s). | `true`
|
|
258
|
-
`entropy` | Boolean | Calculate/log estimated entropy. | `
|
|
258
|
+
`entropy` | Boolean | Calculate/log estimated entropy. | `true`
|
|
259
259
|
|
|
260
260
|
##### _*Only available in [`generatePassword([options])`](#generatepasswordoptions) since [`generatePasswords(qty[, options])`](#generatepasswordsqty-options) takes a `qty` argument_
|
|
261
261
|
|
|
@@ -297,13 +297,15 @@ Boolean options:
|
|
|
297
297
|
-S, --similar-chars Include similar characters in password(s).
|
|
298
298
|
-S, --unstrict Don't require at least one character from
|
|
299
299
|
each allowed character set in password(s).
|
|
300
|
-
-
|
|
300
|
+
-E, --no-entropy Don't calculate/log estimated entropy.
|
|
301
301
|
-q, --quiet Suppress all logging except errors.
|
|
302
302
|
|
|
303
303
|
Commands:
|
|
304
304
|
-i, --init Create config file (in project root).
|
|
305
305
|
-h, --help Display help screen.
|
|
306
306
|
-v, --version Show version number.
|
|
307
|
+
--stats Show npm stats.
|
|
308
|
+
--debug [targetKey] Show debug logs.
|
|
307
309
|
```
|
|
308
310
|
|
|
309
311
|
#
|
|
@@ -327,7 +329,7 @@ export default {
|
|
|
327
329
|
excludeUpperChars: false, // disallow uppercase letters in password(s)
|
|
328
330
|
similarChars: false, // include similar chars in password(s)
|
|
329
331
|
unstrict: false, // don't require 1+ char from each allowed charset in password(s)
|
|
330
|
-
|
|
332
|
+
noEntropy: false, // don't calculate/log estimated entropy
|
|
331
333
|
quietMode: false // suppress all logging except errors
|
|
332
334
|
}
|
|
333
335
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "generate-pw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Randomly generate, strengthen, and validate cryptographically-secure passwords.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Adam Lui",
|
|
@@ -34,14 +34,15 @@
|
|
|
34
34
|
"!docs/*/"
|
|
35
35
|
],
|
|
36
36
|
"bin": {
|
|
37
|
-
"generatepw": "dist/cli/index.
|
|
38
|
-
"generate-pw": "dist/cli/index.
|
|
37
|
+
"generatepw": "dist/cli/index.js",
|
|
38
|
+
"generate-pw": "dist/cli/index.js"
|
|
39
39
|
},
|
|
40
40
|
"directories": {
|
|
41
41
|
"lib": "./dist",
|
|
42
42
|
"doc": "./docs"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
|
+
"dev": "npm run build && npm i -g && generate-pw --help",
|
|
45
46
|
"build": "node utils/build",
|
|
46
47
|
"build:js": "node utils/build --js",
|
|
47
48
|
"build:data": "node utils/build --data",
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"translate": "translate-messages",
|
|
51
52
|
"bump:patch": "bash utils/bump.sh patch",
|
|
52
53
|
"bump:minor": "bash utils/bump.sh minor",
|
|
54
|
+
"bump:feat": "npm run bump:minor",
|
|
53
55
|
"bump:major": "bash utils/bump.sh major"
|
|
54
56
|
},
|
|
55
57
|
"repository": {
|
|
@@ -75,6 +77,8 @@
|
|
|
75
77
|
"node-clipboardy": "^1.0.3"
|
|
76
78
|
},
|
|
77
79
|
"devDependencies": {
|
|
78
|
-
"@adamlui/minify.js": "^2.3.
|
|
80
|
+
"@adamlui/minify.js": "^2.3.1",
|
|
81
|
+
"console-table-printer": "^2.15.0",
|
|
82
|
+
"copyfiles": "^2.4.1"
|
|
79
83
|
}
|
|
80
84
|
}
|
package/dist/cli/index.min.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* © 2024–2026 Adam Lui & contributors under the MIT license.
|
|
4
|
-
* Source: https://github.com/adamlui/js-utils/tree/main/generate-pw/src
|
|
5
|
-
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-pw/docs
|
|
6
|
-
*/
|
|
7
|
-
(async()=>{globalThis.env={args:process.argv.slice(2),devMode:/[\\/]src(?:[\\/]|$)/i.test(__dirname)},env.debugMode=env.args.some(e=>/^--?debug(?:-?mode)?$/.test(e)),env.modExt=`${env.devMode?"":".min"}.js`;var e=require("node-clipboardy"),i=require("../generate-pw"+env.modExt).generatePassword,c=require("./lib/init"+env.modExt),o=require("./lib/log"+env.modExt);return await c.cli(),cli.config.init?c.configFile():cli.config.help?o.help():cli.config.version?o.version():(c={length:cli.config.length,qty:cli.config.qty,strength:cli.config.mode,charset:cli.config.charset,exclude:cli.config.excludeChars,numbers:!cli.config.excludeNums,symbols:!cli.config.excludeSymbols,lowercase:!cli.config.excludeLowerChars,uppercase:!cli.config.excludeUpperChars,similarChars:cli.config.similarChars,strict:!cli.config.unstrict,entropy:cli.config.entropy,verbose:!cli.config.quietMode},e.writeSync([].concat(i(c)).join("\n")),void o.ifNotQuiet(`
|
|
8
|
-
${cli.msgs.info_copyingToClip}...`))})();
|
package/dist/cli/lib/data.min.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* © 2024–2026 Adam Lui & contributors under the MIT license.
|
|
3
|
-
* Source: https://github.com/adamlui/js-utils/tree/main/generate-pw/src
|
|
4
|
-
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-pw/docs
|
|
5
|
-
*/
|
|
6
|
-
module.exports={atomicWrite(e,r,t="utf8"){var n=require("fs"),a=require("path"),a=a.join(a.dirname(e),`.${a.basename(e)}.tmp`);n.writeFileSync(a,r,t),n.renameSync(a,e)},fetch(n){return"undefined"==typeof fetch?new Promise((t,e)=>{var r=n.match(/^([^:]+):\/\//)[1];/^https?$/.test(r)||e(new Error(cli.msgs.error_invalidURL+".")),require(r).get(n,e=>{let r="";e.on("data",e=>r+=e),e.on("end",()=>t({json:()=>JSON.parse(r)}))}).on("error",e)}):fetch(n)},flatten(e,{key:r="message"}={}){var t,n={};for(t in e)n[t]="object"==typeof e[t]&&r in e[t]?e[t][r]:e[t];return n}};
|
package/dist/cli/lib/init.min.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* © 2024–2026 Adam Lui & contributors under the MIT license.
|
|
3
|
-
* Source: https://github.com/adamlui/js-utils/tree/main/generate-pw/src
|
|
4
|
-
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-pw/docs
|
|
5
|
-
*/
|
|
6
|
-
let language=require("./language"+env.modExt),log=require("./log"+env.modExt),settings=require("./settings"+env.modExt),dataPath="../../"+(env.devMode?"../":"data/");module.exports={async cli(){Object.assign(globalThis.cli??={},require(dataPath+"package-data.json")),cli.lang=settings.load("uiLang")||(env.debugMode?language.generateRandomLang({excludes:["en"]}):language.getSysLang()),cli.msgs=await language.getMsgs(cli.lang),cli.urls.cliDocs=cli.urls.docs+"/#-command-line-usage",cli.lang.startsWith("en")||(cli.docLocale=cli.lang.replace("_","-").toLowerCase(),cli.docLocales??=await language.getDocLocales(),cli.docLocales?.includes(cli.docLocale)&&log.debug(cli.urls.cliDocs=cli.urls.docs+`/${cli.docLocale}#readme`)),settings.load()},async configFile(e=settings.configFilename){var a=require("fs"),i=require("path"),t={target:i.resolve(process.cwd(),e)};if(a.existsSync(t.target))return log.warn(cli.msgs.warn_configFileExists+":",t.target);if(a.existsSync(t.src=i.resolve(__dirname,""+dataPath+e)))a.copyFileSync(t.src,t.target);else{i=require("./jsdelivr"+env.modExt).pkgVerURL+`/${e}/`;log.data(cli.msgs.info_fetchingRemoteConfigFrom+` ${i}...`);try{var l=require("./data"+env.modExt),s=await l.fetch(i);if(!s.ok)return log.warn(`${cli.msgs.warn_remoteConfigNotFound}: ${i} (${s.status})`);l.atomicWrite(t.target,await s.text())}catch(e){return log.warn(cli.msgs.warn_remoteConfigFailed+`: ${i} `+e.message)}}log.success(`${cli.msgs.info_configFileCreated}: ${t.target}\n`),log.tip(cli.msgs.tip_editToSetDefaults+"."),log.tip(cli.msgs.tip_cliArgsPrioritized+".")}};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* © 2024–2026 Adam Lui & contributors under the MIT license.
|
|
3
|
-
* Source: https://github.com/adamlui/js-utils/tree/main/generate-pw/src
|
|
4
|
-
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-pw/docs
|
|
5
|
-
*/
|
|
6
|
-
module.exports={pkgVerURL(e){e||=cli.version||=require("./pkg"+env.modExt).getVer("local")||"none";e=/^\d+\.\d+\.\d+$/.test(e)?cli.name+"-"+e:"latest";return cli.urls.jsdelivr+`@${e}/`+cli.name},commitURL(e="latest"){return cli.urls.jsdelivr+`@${e}/`+cli.name}};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* © 2024–2026 Adam Lui & contributors under the MIT license.
|
|
3
|
-
* Source: https://github.com/adamlui/js-utils/tree/main/generate-pw/src
|
|
4
|
-
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-pw/docs
|
|
5
|
-
*/
|
|
6
|
-
let data=require("./data"+env.modExt),log=require("./log"+env.modExt);module.exports={formatCode(e){return e.replace(/([a-z]{2,8})[-_]([a-z]{2})/i,(e,r,a)=>r.toLowerCase()+"_"+a.toUpperCase())},async getDocLocales(){cli.version||=require("./pkg"+env.modExt).getVer("local")||"none";var e=require("./jsdelivr"+env.modExt).pkgVerURL()+"/docs/",r=[];try{for(var a,t=await(await data.fetch(e)).text(),s=/href=".*\/docs\/([^/]+)\/"/g;a=s.exec(t);)r.push(a[1])}catch(e){log.warn(cli.msgs.warn_docLocalesFetchFailed+":",e.message)}return r},generateRandomLang({includes:e=[],excludes:r=[]}={}){let t=require("fs"),s=require("path"),a=e.length?e:(()=>{var e=s.join(__dirname,"..",".cache"),r=s.join(e,"locales.json");if(t.existsSync(r))try{return JSON.parse(t.readFileSync(r,"utf8"))}catch(e){}var a=s.resolve(process.cwd(),"_locales");return t.existsSync(a)?(a=t.readdirSync(a,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name).filter(e=>/^\w{2}[-_]?\w{0,2}$/.test(e)),t.mkdirSync(e,{recursive:!0}),data.atomicWrite(r,JSON.stringify(a,null,2)),a):["en"]})(),n=new Set(r),o="en";return(a=a.filter(e=>!n.has(e))).length&&(o=a[Math.floor(Math.random()*a.length)]),log.debug(`Random language: ${o}
|
|
7
|
-
`),o},async getMsgs(t="en"){if(t=module.exports.formatCode(t),env.msgs&&t==cli.lang)return env.msgs;let e=data.flatten(require(`../../${env.devMode?"../_locales/en/":"data/"}messages.json`));if(!t.startsWith("en")){var s=require("./jsdelivr"+env.modExt).commitURL(cli.commitHashes.locales)+"/_locales/";let r=s+t+"/messages.json",a=0;for(;a<3;)try{e=data.flatten(await(await data.fetch(r)).json());break}catch(e){if(3<=++a)break;log.debug(r=t.includes("-")&&1==a?r.replace(/([^_]*)_[^/]*(\/.*)/,"$1$2"):s+"en/messages.json")}}return e},getSysLang(){try{var e;return"win32"==process.platform?require("child_process").execSync("(Get-Culture).TwoLetterISOLanguageName",{shell:"powershell",encoding:"utf-8"}).trim():((e=process.env).LANG||e.LANGUAGE||e.LC_ALL||e.LC_MESSAGES||e.LC_NAME).split(".")[0]}catch(e){return log.error(cli.msgs.error_failedToFetchSysLang+":",e.message),"en"}},validateLangCode(e){return"string"==typeof e&&/^[a-z]{2,8}(?:[-_][a-z]{2,3})?$/i.test(e)}};
|
package/dist/cli/lib/log.min.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* © 2024–2026 Adam Lui & contributors under the MIT license.
|
|
3
|
-
* Source: https://github.com/adamlui/js-utils/tree/main/generate-pw/src
|
|
4
|
-
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-pw/docs
|
|
5
|
-
*/
|
|
6
|
-
module.exports={colors:{nc:"[0m",br:"[1;91m",by:"[1;33m",bo:"[38;5;214m",bg:"[1;92m",bw:"[1;97m",gry:"[90m",blk:"[30m",tlBG:"[106m"},configURL(){this.info(`
|
|
7
|
-
${cli.msgs.info_exampleValidConfigFile}: `+cli.urls.config)},configURLandExit(...s){this.error(...s),this.configURL(),process.exit(1)},data(s){console.log(`
|
|
8
|
-
`+this.colors.bw+s+this.colors.nc)},debug(s){env.debugMode&&console.debug(`
|
|
9
|
-
${this.colors.bo}DEBUG:`,s,this.colors.nc,"\n")},dim(s){console.log(""+this.colors.gry+s+this.colors.nc)},error(...s){console.error(`
|
|
10
|
-
${this.colors.br}ERROR:`,...s,this.colors.nc)},errorAndExit(...s){this.error(...s),this.helpCmdAndDocURL(),process.exit(1)},ifNotQuiet(s){cli.config.quietMode||console.info(s)},info(s){console.info(`
|
|
11
|
-
`+this.colors.by+s+this.colors.nc)},tip(s){console.info(this.colors.by+"TIP: "+s+this.colors.nc)},success(s){console.log(`
|
|
12
|
-
`+this.colors.bg+s+this.colors.nc)},warn(...s){console.warn(`
|
|
13
|
-
${this.colors.bo}WARNING:`,...s,this.colors.nc)},help(s=["header","usage","params","flags","cmds"]){cli.prefix=""+this.colors.tlBG+this.colors.blk+`[30m ${cli.name} ${this.colors.nc} `;let o={header:[`
|
|
14
|
-
├ ${cli.prefix}${cli.msgs.appCopyright}.`,""+cli.prefix+cli.msgs.prefix_source+": "+cli.urls.src],usage:[`
|
|
15
|
-
${this.colors.bw}o ${cli.msgs.helpSection_usage}:`+this.colors.nc,` ${this.colors.bw}» `+this.colors.bg+cli.cmdFormat+this.colors.nc],params:[`
|
|
16
|
-
${this.colors.bw}o ${cli.msgs.helpSection_params}:`+this.colors.nc,` --length=n ${cli.msgs.optionDesc_length}.`,` --qty=n ${cli.msgs.optionDesc_qty}.`,` --charset=chars ${cli.msgs.optionDesc_charset}.`,` --exclude=chars ${cli.msgs.optionDesc_exclude}.`,` --ui-lang="code" ${cli.msgs.optionDesc_uiLang}.`,` --config="path/to/file" ${cli.msgs.optionDesc_config}.`],flags:[`
|
|
17
|
-
${this.colors.bw}o ${cli.msgs.helpSection_flags}:`+this.colors.nc,` -w, --weak ${cli.msgs.optionDesc_weak}.`,` -b, --basic ${cli.msgs.optionDesc_basic}.`,` -t, --strong ${cli.msgs.optionDesc_strong}.`,` -N, --no-numbers ${cli.msgs.optionDesc_excludeNums}.`,` -Y, --no-symbols ${cli.msgs.optionDesc_excludeSymbols}.`,` -L, --no-lowercase ${cli.msgs.optionDesc_noLower}.`,` -U, --no-uppercase ${cli.msgs.optionDesc_noUpper}.`,` -s, --similar-chars ${cli.msgs.optionDesc_similarChars}.`,` -S, --unstrict ${cli.msgs.optionDesc_unstrict}.`,` -e, --entropy ${cli.msgs.optionDesc_entropy}.`,` -q, --quiet ${cli.msgs.optionDesc_quiet}.`],cmds:[`
|
|
18
|
-
${this.colors.bw}o ${cli.msgs.helpSection_cmds}:`+this.colors.nc,` -i, --init ${cli.msgs.optionDesc_init}.`,` -h, --help ${cli.msgs.optionDesc_help}.`,` -v, --version ${cli.msgs.optionDesc_version}.`]};s.forEach(t=>o[t]?.forEach(o=>{{var e=/header|usage/.test(t)?1:29;let i=process.stdout.columns||80,s=o.match(/\S+|\s+/g),c=[],l="";s.forEach(s=>{var o=i-(c.length?e:0);l.length+"| ".length+s.length>o&&(c.push(c.length?l.trimStart():l),l=""),l+=s}),c.push(c.length?l.trimStart():l),c.forEach((s,o)=>console.info("| "+(0==o?s:" ".repeat(e)+s)))}})),console.info(`
|
|
19
|
-
${cli.msgs.info_moreHelp}, ${cli.msgs.info_visit}: `+this.colors.bw+cli.urls.cliDocs+this.colors.nc)},helpCmdAndDocURL(){console.info(`
|
|
20
|
-
${cli.msgs.info_moreHelp}, ${cli.msgs.info_type} ${cli.name} --help' ${cli.msgs.info_or} ${cli.msgs.info_visit}
|
|
21
|
-
`+this.colors.bw+cli.urls.docs+this.colors.nc)},version(){var s=require("./pkg"+env.modExt).getVer;this.info(cli.name),this.data(`${cli.msgs.prefix_globalVer}: ${s("global")||"none"}
|
|
22
|
-
${cli.msgs.prefix_localVer}: `+(s("local")||"none"))}};
|
package/dist/cli/lib/pkg.min.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* © 2024–2026 Adam Lui & contributors under the MIT license.
|
|
3
|
-
* Source: https://github.com/adamlui/js-utils/tree/main/generate-pw/src
|
|
4
|
-
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-pw/docs
|
|
5
|
-
*/
|
|
6
|
-
let log=require("./log"+env.modExt);module.exports={getVer(e="any"){let r;if("global"!=e)try{var l=require("path").resolve(process.cwd(),"node_modules",cli.name,"package.json");r=require(l).version}catch(e){log.debug(cli.msgs.error_readingLocalPkgVer+": "+e.message)}if("global"==e||"all"==e&&!r)try{r=require("child_process").execSync(`npm view ${JSON.stringify(cli.name)} version`).toString().trim()}catch(e){log.debug(cli.msgs.error_failedToFetchGlobalVer+": "+e.message)}return r}};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* © 2024–2026 Adam Lui & contributors under the MIT license.
|
|
3
|
-
* Source: https://github.com/adamlui/js-utils/tree/main/generate-pw/src
|
|
4
|
-
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-pw/docs
|
|
5
|
-
*/
|
|
6
|
-
let fs=require("fs"),log=require("./log"+env.modExt),path=require("path");(globalThis.cli??={}).config={},module.exports={configFilename:"generate-pw.config.mjs",controls:{length:{type:"param",valType:"positiveInt",defaultVal:12,regex:/^--?length(?:=.*|$)/},qty:{type:"param",valType:"positiveInt",defaultVal:1,regex:/^--?qu?a?n?ti?t?y(?:=.*|$)/},charset:{type:"param",regex:/^--?charse?t?(?:=.*|$)/},excludeChars:{type:"param",regex:/^--?exclude(?:=.*|$)/},uiLang:{type:"param",valType:"langCode",regex:/^--?ui-?lang(?:=.*|$)/},config:{type:"param",valType:"filepath",regex:/^--?config(?:=.*|$)/},weak:{type:"flag",mode:!0,regex:/^--?(?:w|weak)$/},basic:{type:"flag",mode:!0,regex:/^--?(?:b|basic)$/},strong:{type:"flag",mode:!0,regex:/^--?(?:t|strong)$/},excludeNums:{type:"flag",regex:/^--?(?:N|(?:exclude|disable|no)-?num(?:ber)?s?=?(?:true|1)?)$/},excludeSymbols:{type:"flag",regex:/^--?(?:Y|(?:exclude|disable|no)-?symbols?=?(?:true|1)?)$/},excludeLowerChars:{type:"flag",regex:/^--?(?:L|(?:exclude|disable|no)-?lower-?(?:case)?|lower-?(?:case)?=(?:false|0))$/},excludeUpperChars:{type:"flag",regex:/^--?(?:U|(?:exclude|disable|no)-?upper-?(?:case)?|upper-?(?:case)?=(?:false|0))$/},similarChars:{type:"flag",regex:/^--?(?:s|(?:include-?)?similar-?chars?=?(?:true|1)?)$/},unstrict:{type:"flag",regex:/^--?(?:S|(?:un-?strict)?(?:-?mode)?)$/},entropy:{type:"flag",regex:/^--?e(?:ntropy)?$/},quietMode:{type:"flag",regex:/^--?q(?:uiet)?(?:-?mode)?$/},init:{type:"cmd",regex:/^-{0,2}i(?:nit)?$/},help:{type:"cmd",regex:/^--?h(?:elp)?$/},version:{type:"cmd",regex:/^--?ve?r?s?i?o?n?$/}},load(e=Object.keys(this.controls)){let r=[].concat(e);if(cli.defaultsSet||arguments.length||(r.forEach(e=>{var i=this.controls[e];i.mode||(cli.config[e]??=i.defaultVal??("param"==i.type&&""))}),cli.defaultsSet=!0),!cli.configPathTried){e=env.args.find(e=>this.controls.config.regex.test(e));if(e){/=/.test(e)||log.errorAndExit(`[${e}] `+cli.msgs.error_mustIncludePath);e=e.split("=")[1];cli.configPath=path.isAbsolute(e)?e:path.resolve(process.cwd(),e),fs.existsSync(cli.configPath)||log.configURLandExit(cli.msgs.error_configFileNotFound+":",cli.configPath)}else for(var i of[".mjs",".cjs",".js"]){i=path.resolve(process.cwd(),this.configFilename.replace(/\.[^.]+$/,i));if(fs.existsSync(i)){cli.configPath=i;break}}cli.configPathTried=!0}if(cli.configPath)try{let e=require(cli.configPath),t=e?.default??e;t&&"object"==typeof t||log.configURLandExit(cli.msgs.error_invalidConfigFile+"."),Object.assign(cli.config,arguments.length?r.reduce((e,i)=>t[i]?{...e,[i]:t[i]}:e,{}):t)}catch(e){log.configURLandExit(cli.msgs.error_failedToLoadConfigFile+":",cli.configPath,`
|
|
7
|
-
`+e.message)}return env.args.forEach(i=>{var e,t;/^[^-]|--?(?:config|debug)/.test(i)&&"init"!=i||(!(e=Object.keys(this.controls).find(e=>this.controls[e]?.regex?.test(i)))&&cli.msgs&&log.errorAndExit(`[${i}] ${cli.msgs.error_notRecognized}.`),r.includes(e)&&((t=this.controls[e]).mode?cli.config.mode=e.replace(/mode$/i,"").toLowerCase():cli.config[e]="param"!=t.type||(i.split("=")[1]?.trim()??"")))}),this.parseValidateConfig(r),1==r.length?cli.config[r[0]]:cli.config},parseValidateConfig(e=Object.keys(this.controls)){let r=require("./language"+env.modExt);for(let t of[].concat(e)){let e=this.controls[t],i=cli.config[t];e.parser&&!e.parsed&&(cli.config[t]=e.parser(i),e.parsed=!0),e.valType&&{positiveInt(){var e=parseInt(i,10);(isNaN(e)||e<1)&&log.errorAndExit(`[${t}] ${cli.msgs.error_nonPositiveNum}: `+i),cli.config[t]=e},filepath(){i&&!fs.existsSync(i)&&log.errorAndExit(`[${t}] ${cli.msgs.error_invalidFilepath}: `+i)},langCode(){i&&!r.validateLangCode(i)&&log.errorAndExit(`[${t}] ${cli.msgs.error_invalidLangCode}: `+i)}}[e.valType]()}}};
|