generate-ip 2.8.1 โ 2.8.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 +8 -8
- package/dist/cli/.cache/locales.json +102 -0
- package/dist/cli/index.js +35 -0
- package/dist/cli/lib/data.js +30 -0
- package/dist/cli/lib/init.js +44 -0
- package/dist/cli/lib/jsdelivr.js +10 -0
- package/dist/cli/lib/language.js +93 -0
- package/dist/cli/lib/log.js +106 -0
- package/dist/cli/lib/pkg.js +20 -0
- package/dist/cli/lib/settings.js +119 -0
- package/dist/data/generate-ip.config.mjs +18 -0
- package/dist/data/messages.json +50 -0
- package/dist/data/package-data.json +18 -0
- package/dist/generate-ip.min.js +6 -0
- package/docs/README.md +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
<a href="#%EF%B8%8F-mit-license">
|
|
12
12
|
<img height=31 src="https://img.shields.io/badge/License-MIT-orange.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
13
|
-
<a href="https://github.com/adamlui/js-utils/releases/tag/generate-ip-2.8.
|
|
14
|
-
<img height=31 src="https://img.shields.io/badge/Latest_Build-2.8.
|
|
13
|
+
<a href="https://github.com/adamlui/js-utils/releases/tag/generate-ip-2.8.2">
|
|
14
|
+
<img height=31 src="https://img.shields.io/badge/Latest_Build-2.8.2-44cc11.svg?logo=icinga&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
15
15
|
<a href="https://www.npmjs.com/package/generate-ip?activeTab=code">
|
|
16
16
|
<img height=31 src="https://img.shields.io/npm/unpacked-size/generate-ip?style=for-the-badge&logo=ebox&logoColor=white&labelColor=464646&color=blue"></a>
|
|
17
|
-
<a href="https://github.com/adamlui/js-utils/blob/generate-ip-2.8.
|
|
18
|
-
<img height=31 src="https://img.shields.io/github/size/adamlui/js-utils/generate-ip/dist/generate-ip.min.js?branch=generate-ip-2.8.
|
|
17
|
+
<a href="https://github.com/adamlui/js-utils/blob/generate-ip-2.8.2/generate-ip/dist/generate-ip.min.js">
|
|
18
|
+
<img height=31 src="https://img.shields.io/github/size/adamlui/js-utils/generate-ip/dist/generate-ip.min.js?branch=generate-ip-2.8.2&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
|
|
19
19
|
<a href="https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=adamlui_js-utils:generate-ip/src/generate-ip.js">
|
|
20
20
|
<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-ip%2Fsrc%2Fgenerate-ip.js%26metricKeys%3Dvulnerabilities&query=%24.component.measures.0.value&style=for-the-badge&logo=sonarcloud&logoColor=white&labelColor=464646&label=Vulnerabilities&color=gold"></a>
|
|
21
21
|
<a href="https://github.com/toolleeo/cli-apps#networking">
|
|
@@ -87,14 +87,14 @@ const { ipv4, ipv6, mac } = require('generate-ip')
|
|
|
87
87
|
#### <> HTML script tag:
|
|
88
88
|
|
|
89
89
|
```html
|
|
90
|
-
<script src="https://cdn.jsdelivr.net/npm/generate-ip@2.8.
|
|
90
|
+
<script src="https://cdn.jsdelivr.net/npm/generate-ip@2.8.2/dist/generate-ip.min.js"></script>
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
#### ES6:
|
|
94
94
|
|
|
95
95
|
```js
|
|
96
96
|
(async () => {
|
|
97
|
-
await import('https://cdn.jsdelivr.net/npm/generate-ip@2.8.
|
|
97
|
+
await import('https://cdn.jsdelivr.net/npm/generate-ip@2.8.2/dist/generate-ip.min.js')
|
|
98
98
|
// Your code here...
|
|
99
99
|
})()
|
|
100
100
|
```
|
|
@@ -103,7 +103,7 @@ const { ipv4, ipv6, mac } = require('generate-ip')
|
|
|
103
103
|
|
|
104
104
|
```js
|
|
105
105
|
...
|
|
106
|
-
// @require https://cdn.jsdelivr.net/npm/generate-ip@2.8.
|
|
106
|
+
// @require https://cdn.jsdelivr.net/npm/generate-ip@2.8.2/dist/generate-ip.min.js
|
|
107
107
|
// ==/UserScript==
|
|
108
108
|
|
|
109
109
|
// Your code here...
|
|
@@ -111,7 +111,7 @@ const { ipv4, ipv6, mac } = require('generate-ip')
|
|
|
111
111
|
|
|
112
112
|
<br>
|
|
113
113
|
|
|
114
|
-
๐ **Note:** To always import the latest version (not recommended in production!) remove the `@2.8.
|
|
114
|
+
๐ **Note:** To always import the latest version (not recommended in production!) remove the `@2.8.2` version tag from the jsDelivr URL: `https://cdn.jsdelivr.net/npm/generate-ip/dist/generate-ip.min.js`
|
|
115
115
|
|
|
116
116
|
<br>
|
|
117
117
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
[
|
|
2
|
+
"af",
|
|
3
|
+
"am",
|
|
4
|
+
"ar",
|
|
5
|
+
"az",
|
|
6
|
+
"be",
|
|
7
|
+
"bg",
|
|
8
|
+
"bn",
|
|
9
|
+
"bo",
|
|
10
|
+
"bs",
|
|
11
|
+
"ca",
|
|
12
|
+
"cs",
|
|
13
|
+
"cy",
|
|
14
|
+
"da",
|
|
15
|
+
"de",
|
|
16
|
+
"dv",
|
|
17
|
+
"dz",
|
|
18
|
+
"el",
|
|
19
|
+
"en",
|
|
20
|
+
"eo",
|
|
21
|
+
"es",
|
|
22
|
+
"et",
|
|
23
|
+
"eu",
|
|
24
|
+
"fa",
|
|
25
|
+
"fi",
|
|
26
|
+
"fo",
|
|
27
|
+
"fr",
|
|
28
|
+
"gd",
|
|
29
|
+
"gl",
|
|
30
|
+
"gu",
|
|
31
|
+
"he",
|
|
32
|
+
"hi",
|
|
33
|
+
"hr",
|
|
34
|
+
"ht",
|
|
35
|
+
"hu",
|
|
36
|
+
"hy",
|
|
37
|
+
"id",
|
|
38
|
+
"is",
|
|
39
|
+
"it",
|
|
40
|
+
"ja",
|
|
41
|
+
"ka",
|
|
42
|
+
"kk",
|
|
43
|
+
"km",
|
|
44
|
+
"kn",
|
|
45
|
+
"ko",
|
|
46
|
+
"ku",
|
|
47
|
+
"ky",
|
|
48
|
+
"la",
|
|
49
|
+
"lb",
|
|
50
|
+
"lo",
|
|
51
|
+
"lt",
|
|
52
|
+
"lv",
|
|
53
|
+
"mg",
|
|
54
|
+
"mi",
|
|
55
|
+
"mk",
|
|
56
|
+
"ml",
|
|
57
|
+
"mn",
|
|
58
|
+
"ms",
|
|
59
|
+
"mt",
|
|
60
|
+
"my",
|
|
61
|
+
"ne",
|
|
62
|
+
"nl",
|
|
63
|
+
"no",
|
|
64
|
+
"ny",
|
|
65
|
+
"pa",
|
|
66
|
+
"pl",
|
|
67
|
+
"ps",
|
|
68
|
+
"pt",
|
|
69
|
+
"ro",
|
|
70
|
+
"ru",
|
|
71
|
+
"rw",
|
|
72
|
+
"sg",
|
|
73
|
+
"si",
|
|
74
|
+
"sk",
|
|
75
|
+
"sl",
|
|
76
|
+
"sm",
|
|
77
|
+
"sn",
|
|
78
|
+
"so",
|
|
79
|
+
"sr",
|
|
80
|
+
"sv",
|
|
81
|
+
"sw",
|
|
82
|
+
"ta",
|
|
83
|
+
"te",
|
|
84
|
+
"tg",
|
|
85
|
+
"th",
|
|
86
|
+
"ti",
|
|
87
|
+
"tk",
|
|
88
|
+
"tn",
|
|
89
|
+
"tr",
|
|
90
|
+
"uk",
|
|
91
|
+
"ur",
|
|
92
|
+
"uz",
|
|
93
|
+
"vi",
|
|
94
|
+
"xh",
|
|
95
|
+
"yi",
|
|
96
|
+
"zh",
|
|
97
|
+
"zh_CN",
|
|
98
|
+
"zh_HK",
|
|
99
|
+
"zh_SG",
|
|
100
|
+
"zh_TW",
|
|
101
|
+
"zu"
|
|
102
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
(async () => {
|
|
4
|
+
'use strict'
|
|
5
|
+
|
|
6
|
+
globalThis.env = {
|
|
7
|
+
args: process.argv.slice(2),
|
|
8
|
+
devMode: /[\\/]src(?:[\\/]|$)/i.test(__dirname)
|
|
9
|
+
}
|
|
10
|
+
env.debugMode = env.args.some(arg => /^--?debug(?:-?mode)?$/.test(arg))
|
|
11
|
+
|
|
12
|
+
// Import LIBS
|
|
13
|
+
const clipboardy = require('node-clipboardy'),
|
|
14
|
+
generateIP = require(`../generate-ip${ env.devMode ? '' : '.min' }.js`),
|
|
15
|
+
init = require('./lib/init'),
|
|
16
|
+
log = require('./lib/log')
|
|
17
|
+
|
|
18
|
+
await init.cli()
|
|
19
|
+
|
|
20
|
+
// Exec CMD arg if passed
|
|
21
|
+
if (cli.config.init) return init.configFile()
|
|
22
|
+
else if (cli.config.help) return log.help()
|
|
23
|
+
else if (cli.config.version) return log.version()
|
|
24
|
+
|
|
25
|
+
// Log/copy random IP(s)
|
|
26
|
+
const genOptions = {
|
|
27
|
+
qty: cli.config.qty,
|
|
28
|
+
sequential: cli.config.sequential,
|
|
29
|
+
network: cli.config.network,
|
|
30
|
+
verbose: !cli.config.quietMode
|
|
31
|
+
}
|
|
32
|
+
clipboardy.writeSync([].concat(generateIP[cli.config.mode || 'ipv4'].generate(genOptions)).join('\n'))
|
|
33
|
+
log.ifNotQuiet(`\n${cli.msgs.info_copyingToClip}...`)
|
|
34
|
+
|
|
35
|
+
})()
|
|
@@ -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) }))
|
|
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,44 @@
|
|
|
1
|
+
const language = require('./language'),
|
|
2
|
+
log = require('./log'),
|
|
3
|
+
settings = require('./settings')
|
|
4
|
+
|
|
5
|
+
const dataPath = `../../${ env.devMode ? '../' : 'data/' }`
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
|
|
9
|
+
async cli() {
|
|
10
|
+
Object.assign(globalThis.cli ??= {}, require(`${dataPath}package-data.json`))
|
|
11
|
+
cli.lang = settings.load('uiLang') || (
|
|
12
|
+
env.debugMode ? language.generateRandomLang({ excludes: ['en'] }) : language.getSysLang() )
|
|
13
|
+
cli.msgs = await language.getMsgs(cli.lang)
|
|
14
|
+
cli.urls.cliDocs ||= `${cli.urls.docs}/#-command-line-usage`
|
|
15
|
+
settings.load() // all keys to cli.config
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
async configFile(filename = settings.configFilename) {
|
|
19
|
+
const fs = require('fs'),
|
|
20
|
+
path = require('path'),
|
|
21
|
+
paths = { target: path.resolve(process.cwd(), filename) }
|
|
22
|
+
|
|
23
|
+
if (fs.existsSync(paths.target)) // use existing config file
|
|
24
|
+
return log.warn(`${cli.msgs.warn_configFileExists}:`, paths.target)
|
|
25
|
+
if (fs.existsSync(paths.src = path.resolve(__dirname, `${dataPath}${filename}`)))
|
|
26
|
+
fs.copyFileSync(paths.src, paths.target) // use found template
|
|
27
|
+
|
|
28
|
+
else { // use jsDelivr copy
|
|
29
|
+
const jsdURL = `${require('./jsdelivr').pkgVerURL}/${filename}/`
|
|
30
|
+
log.data(`${cli.msgs.info_fetchingRemoteConfigFrom} ${jsdURL}...`)
|
|
31
|
+
try {
|
|
32
|
+
const data = require('./data'),
|
|
33
|
+
resp = await data.fetch(jsdURL)
|
|
34
|
+
if (resp.ok) data.atomicWrite(paths.target, await resp.text())
|
|
35
|
+
else return log.warn(`${cli.msgs.warn_remoteConfigNotFound}: ${jsdURL} (${resp.status})`)
|
|
36
|
+
} catch (err) {
|
|
37
|
+
return log.warn(`${cli.msgs.warn_remoteConfigFailed}: ${jsdURL} ${err.message}`) }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
log.success(`${cli.msgs.info_configFileCreated}: ${paths.target}\n`)
|
|
41
|
+
log.tip(`${cli.msgs.tip_editToSetDefaults}.`)
|
|
42
|
+
log.tip(`${cli.msgs.tip_cliArgsPrioritized}.`)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -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,93 @@
|
|
|
1
|
+
const data = require('./data'),
|
|
2
|
+
log = require('./log')
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
|
|
6
|
+
formatCode(langCode) { // to match locale dir name
|
|
7
|
+
return langCode.replace(
|
|
8
|
+
/([a-z]{2,8})[-_]([a-z]{2})/i, (_, lang, region) =>`${lang.toLowerCase()}_${region.toUpperCase()}`) },
|
|
9
|
+
|
|
10
|
+
generateRandomLang({ includes = [], excludes = [] } = {}) {
|
|
11
|
+
const fs = require('fs'),
|
|
12
|
+
path = require('path')
|
|
13
|
+
|
|
14
|
+
let locales = includes.length ? includes : (() => {
|
|
15
|
+
|
|
16
|
+
// Read cache if found
|
|
17
|
+
const cacheDir = path.join(__dirname, '..', '.cache'),
|
|
18
|
+
localeCache = path.join(cacheDir, 'locales.json')
|
|
19
|
+
if (fs.existsSync(localeCache))
|
|
20
|
+
try { return JSON.parse(fs.readFileSync(localeCache, 'utf8')) } catch (err) {}
|
|
21
|
+
|
|
22
|
+
// Discover pkg _locales
|
|
23
|
+
const localesDir = path.resolve(process.cwd(), '_locales')
|
|
24
|
+
if (!fs.existsSync(localesDir)) return ['en']
|
|
25
|
+
const locales = fs.readdirSync(localesDir, { withFileTypes: true })
|
|
26
|
+
.filter(entry => entry.isDirectory()).map(entry => entry.name)
|
|
27
|
+
.filter(name => /^\w{2}[-_]?\w{0,2}$/.test(name))
|
|
28
|
+
|
|
29
|
+
// Cache result
|
|
30
|
+
fs.mkdirSync(cacheDir, { recursive: true })
|
|
31
|
+
data.atomicWrite(localeCache, JSON.stringify(locales, null, 2))
|
|
32
|
+
|
|
33
|
+
return locales
|
|
34
|
+
})()
|
|
35
|
+
|
|
36
|
+
// Filter out excludes
|
|
37
|
+
const excludeSet = new Set(excludes)
|
|
38
|
+
locales = locales.filter(locale => !excludeSet.has(locale))
|
|
39
|
+
|
|
40
|
+
// Get random language
|
|
41
|
+
let randomLang = 'en'
|
|
42
|
+
if (locales.length)
|
|
43
|
+
randomLang = locales[Math.floor(Math.random() * locales.length)]
|
|
44
|
+
log.debug(`Random language: ${randomLang}\n`)
|
|
45
|
+
|
|
46
|
+
return randomLang
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
async getMsgs(langCode = 'en') {
|
|
50
|
+
langCode = module.exports.formatCode(langCode)
|
|
51
|
+
if (env.msgs && langCode == cli.lang) return env.msgs // don't re-fetch same msgs
|
|
52
|
+
|
|
53
|
+
let msgs = data.flatten( // local ones
|
|
54
|
+
require(`../../${ env.devMode ? '../_locales/en/' : 'data/' }messages.json`))
|
|
55
|
+
|
|
56
|
+
if (!langCode.startsWith('en')) { // fetch non-English msgs from jsDelivr
|
|
57
|
+
const msgHostURL = `${require('./jsdelivr').commitURL(cli.commitHashes.locales)}/_locales/`
|
|
58
|
+
let msgHref = `${msgHostURL}${langCode}/messages.json`, msgFetchesTried = 0
|
|
59
|
+
while (msgFetchesTried < 3)
|
|
60
|
+
try { // fetch remote msgs
|
|
61
|
+
msgs = data.flatten(await (await data.fetch(msgHref)).json())
|
|
62
|
+
break
|
|
63
|
+
} catch (err) { // retry up to 2X (region-stripped + EN)
|
|
64
|
+
msgFetchesTried++ ; if (msgFetchesTried >= 3) break
|
|
65
|
+
log.debug(msgHref = langCode.includes('-') && msgFetchesTried == 1 ?
|
|
66
|
+
msgHref.replace(/([^_]*)_[^/]*(\/.*)/, '$1$2') // strip region before retrying
|
|
67
|
+
: `${msgHostURL}en/messages.json` // else use EN msgs
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return msgs
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
getSysLang() {
|
|
76
|
+
try {
|
|
77
|
+
if (process.platform == 'win32')
|
|
78
|
+
return require('child_process').execSync(
|
|
79
|
+
'(Get-Culture).TwoLetterISOLanguageName', { shell: 'powershell', encoding: 'utf-8' }
|
|
80
|
+
).trim()
|
|
81
|
+
else { // macOS/Linux
|
|
82
|
+
const pe = process.env
|
|
83
|
+
return (pe.LANG || pe.LANGUAGE || pe.LC_ALL || pe.LC_MESSAGES || pe.LC_NAME)
|
|
84
|
+
.split('.')[0] // strip encoding e.g. .UTF-8
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
log.error(`${cli.msgs.error_failedToFetchSysLang}:`, err.message)
|
|
88
|
+
return 'en'
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
validateLangCode(code) { return typeof code != 'string' ? false : /^[a-z]{2,8}(?:[-_][a-z]{2,3})?$/i.test(code) }
|
|
93
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
|
|
3
|
+
colors: {
|
|
4
|
+
nc: '\x1b[0m', // no color
|
|
5
|
+
br: '\x1b[1;91m', // bright red
|
|
6
|
+
by: '\x1b[1;33m', // bright yellow
|
|
7
|
+
bo: '\x1b[38;5;214m', // bright orange
|
|
8
|
+
bg: '\x1b[1;92m', // bright green
|
|
9
|
+
bw: '\x1b[1;97m', // bright white
|
|
10
|
+
gry: '\x1b[90m', // gray
|
|
11
|
+
blk: '\x1b[30m', // black
|
|
12
|
+
tlBG: '\x1b[106m' // teal bg
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
configURL() { this.info(`\n${cli.msgs.info_exampleValidConfigFile}: ${cli.urls.config}`) },
|
|
16
|
+
configURLandExit(...args) { this.error(...args) ; this.configURL() ; process.exit(1) },
|
|
17
|
+
data(msg) { console.log(`\n${this.colors.bw}${msg}${this.colors.nc}`) },
|
|
18
|
+
debug(msg) { if (env.debugMode) console.debug(`\n${this.colors.bo}DEBUG:`, msg, this.colors.nc, '\n') },
|
|
19
|
+
dim(msg) { console.log(`${this.colors.gry}${msg}${this.colors.nc}`) },
|
|
20
|
+
error(...args) { console.error(`\n${this.colors.br}ERROR:`, ...args, this.colors.nc) },
|
|
21
|
+
errorAndExit(...args) { this.error(...args) ; this.helpCmdAndDocURL() ; process.exit(1) },
|
|
22
|
+
ifNotQuiet(msg) { if (!cli.config.quietMode) console.info(msg) },
|
|
23
|
+
info(msg) { console.info(`\n${this.colors.by}${msg}${this.colors.nc}`) },
|
|
24
|
+
tip(msg) { console.info(`${this.colors.by}TIP: ${msg}${this.colors.nc}`) },
|
|
25
|
+
success(msg) { console.log(`\n${this.colors.bg}${msg}${this.colors.nc}`) },
|
|
26
|
+
warn(...args) { console.warn(`\n${this.colors.bo}WARNING:`, ...args, this.colors.nc) },
|
|
27
|
+
|
|
28
|
+
help(includeSections = ['header', 'usage', 'params', 'flags', 'cmds']) {
|
|
29
|
+
cli.prefix = `${this.colors.tlBG}${this.colors.blk}\x1b[30m ${cli.name} ${this.colors.nc} `
|
|
30
|
+
const helpSections = {
|
|
31
|
+
header: [
|
|
32
|
+
`\nโ ${cli.prefix}${cli.msgs.appCopyright}.`,
|
|
33
|
+
`${cli.prefix}${cli.msgs.prefix_source}: ${cli.urls.src}`
|
|
34
|
+
],
|
|
35
|
+
usage: [
|
|
36
|
+
`\n${this.colors.bw}o ${cli.msgs.helpSection_usage}:${this.colors.nc}`,
|
|
37
|
+
` ${this.colors.bw}ยป ${this.colors.bg}${cli.cmdFormat}${this.colors.nc}`
|
|
38
|
+
],
|
|
39
|
+
params: [
|
|
40
|
+
`\n${this.colors.bw}o ${cli.msgs.helpSection_params}:${this.colors.nc}`,
|
|
41
|
+
` --qty=n ${cli.msgs.optionDesc_qty}.`,
|
|
42
|
+
` --ui-lang="code" ${cli.msgs.optionDesc_uiLang}.`,
|
|
43
|
+
` --config="path/to/file" ${cli.msgs.optionDesc_config}.`,
|
|
44
|
+
` --network="address" ${cli.msgs.optionDesc_network}.`
|
|
45
|
+
],
|
|
46
|
+
flags: [
|
|
47
|
+
`\n${this.colors.bw}o ${cli.msgs.helpSection_flags}:${this.colors.nc}`,
|
|
48
|
+
` -6, --ipv6 ${cli.msgs.optionDesc_ipv6}.`,
|
|
49
|
+
` -m, --mac ${cli.msgs.optionDesc_mac}.`,
|
|
50
|
+
` -s, --sequential ${cli.msgs.optionDesc_sequential}.`,
|
|
51
|
+
` -q, --quiet ${cli.msgs.optionDesc_quiet}.`
|
|
52
|
+
],
|
|
53
|
+
cmds: [
|
|
54
|
+
`\n${this.colors.bw}o ${cli.msgs.helpSection_cmds}:${this.colors.nc}`,
|
|
55
|
+
` -i, --init ${cli.msgs.optionDesc_init}.`,
|
|
56
|
+
` -h, --help ${cli.msgs.optionDesc_help}.`,
|
|
57
|
+
` -v, --version ${cli.msgs.optionDesc_version}.`
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
includeSections.forEach(section => // print valid arg elems
|
|
61
|
+
helpSections[section]?.forEach(line => printHelpMsg(line, /header|usage/.test(section) ? 1 : 29)))
|
|
62
|
+
console.info(`\n${cli.msgs.info_moreHelp}, ${
|
|
63
|
+
cli.msgs.info_visit}: ${this.colors.bw}${cli.urls.cliDocs}${this.colors.nc}`)
|
|
64
|
+
|
|
65
|
+
function printHelpMsg(msg, indent) { // wrap msg + indent 2nd+ lines
|
|
66
|
+
const terminalWidth = process.stdout.columns || 80,
|
|
67
|
+
words = msg.match(/\S+|\s+/g),
|
|
68
|
+
lines = [], prefix = '| '
|
|
69
|
+
|
|
70
|
+
// Split msg into lines of appropriate lengths
|
|
71
|
+
let currentLine = ''
|
|
72
|
+
words.forEach(word => {
|
|
73
|
+
const lineLength = terminalWidth -( !lines.length ? 0 : indent )
|
|
74
|
+
if (currentLine.length + prefix.length + word.length > lineLength) { // cap/store it
|
|
75
|
+
lines.push(!lines.length ? currentLine : currentLine.trimStart())
|
|
76
|
+
currentLine = ''
|
|
77
|
+
}
|
|
78
|
+
currentLine += word
|
|
79
|
+
})
|
|
80
|
+
lines.push(!lines.length ? currentLine : currentLine.trimStart())
|
|
81
|
+
|
|
82
|
+
// Print formatted msg
|
|
83
|
+
lines.forEach((line, idx) => console.info(prefix +(
|
|
84
|
+
idx == 0 ? line // print 1st line unindented
|
|
85
|
+
: ' '.repeat(indent) + line // print subsequent lines indented
|
|
86
|
+
)))
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
helpCmdAndDocURL() {
|
|
91
|
+
console.info(`\n${
|
|
92
|
+
cli.msgs.info_moreHelp}, ${cli.msgs.info_type} ${cli.name} --help' ${
|
|
93
|
+
cli.msgs.info_or} ${cli.msgs.info_visit}\n${
|
|
94
|
+
this.colors.bw}${cli.urls.docs}${this.colors.nc}`
|
|
95
|
+
)
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
version() {
|
|
99
|
+
const { getVer } = require('./pkg')
|
|
100
|
+
this.info(cli.name)
|
|
101
|
+
this.data(`${
|
|
102
|
+
cli.msgs.prefix_globalVer}: ${ getVer('global') || 'none' }\n${
|
|
103
|
+
cli.msgs.prefix_localVer }: ${ getVer('local') || 'none' }`
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const log = require('./log')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
getVer(type = 'any') { // or <'global'|'local'>
|
|
5
|
+
let pkgVer
|
|
6
|
+
if (type != 'global')
|
|
7
|
+
try { // get local ver
|
|
8
|
+
const localManifestPath = require('path').resolve(
|
|
9
|
+
process.cwd(), 'node_modules', cli.name, 'package.json')
|
|
10
|
+
pkgVer = require(localManifestPath).version
|
|
11
|
+
} catch (err) { log.debug(`${cli.msgs.error_readingLocalPkgVer}: ${err.message}`) }
|
|
12
|
+
if (type == 'global' || type == 'all' && !pkgVer)
|
|
13
|
+
try { // get global ver
|
|
14
|
+
pkgVer = require('child_process').execSync(
|
|
15
|
+
`npm view ${JSON.stringify(cli.name)} version`
|
|
16
|
+
).toString().trim()
|
|
17
|
+
} catch (err) { log.debug(`${cli.msgs.error_failedToFetchGlobalVer}: ${err.message}`) }
|
|
18
|
+
return pkgVer
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const fs = require('fs'),
|
|
2
|
+
log = require('./log'),
|
|
3
|
+
path = require('path')
|
|
4
|
+
|
|
5
|
+
;(globalThis.cli ??= {}).config = {}
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
configFilename: 'generate-ip.config.mjs',
|
|
9
|
+
|
|
10
|
+
controls: {
|
|
11
|
+
qty: { type: 'param', valType: 'positiveInt', defaultVal: 1, regex: /^--?qu?a?n?ti?t?y(?:=.*|$)/ },
|
|
12
|
+
network: { type: 'param', regex: /^--network(?:=.*|$)/ },
|
|
13
|
+
uiLang: { type: 'param', valType: 'langCode', regex: /^--?ui[-_]?lang(?:=.*|$)/ },
|
|
14
|
+
config: { type: 'param', valType: 'filepath', regex: /^--?config(?:=.*|$)/ },
|
|
15
|
+
ipv6mode: { type: 'flag', mode: true, regex: /^--?(?:ip)?v?6(?:[-_]?mode)?$/ },
|
|
16
|
+
macMode: { type: 'flag', mode: true, regex: /^--?m(?:ac)?(?:[-_]?mode)?$/ },
|
|
17
|
+
quietMode: { type: 'flag', regex: /^--?q(?:uiet)?(?:[-_]?mode)?$/ },
|
|
18
|
+
sequential: { type: 'flag', regex: /^--(?:s|equen(?:tial|ce))$/ },
|
|
19
|
+
init: { type: 'cmd', regex: /^-{0,2}i(?:nit)?$/ },
|
|
20
|
+
help: { type: 'cmd', regex: /^--?h(?:elp)?$/ },
|
|
21
|
+
version: { type: 'cmd', regex: /^--?ve?r?s?i?o?n?$/ }
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
load(ctrlKeys = Object.keys(this.controls)) {
|
|
25
|
+
const inputCtrlKeys = [].concat(ctrlKeys) // force array
|
|
26
|
+
|
|
27
|
+
if (!cli.defaultsSet && !arguments.length) { // init all defaults on arg-less load()
|
|
28
|
+
inputCtrlKeys.forEach(key => {
|
|
29
|
+
const ctrl = this.controls[key] ; if (ctrl.mode) return
|
|
30
|
+
cli.config[key] ??= ctrl.defaultVal ?? ( ctrl.type == 'param' ? '' : false )
|
|
31
|
+
})
|
|
32
|
+
cli.defaultsSet = true
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!cli.configPathTried) { // init config file path
|
|
36
|
+
const configArg = env.args.find(arg => this.controls.config.regex.test(arg))
|
|
37
|
+
|
|
38
|
+
if (configArg) { // resolve input path, then validate
|
|
39
|
+
if (!/=/.test(configArg))
|
|
40
|
+
log.errorAndExit(`[${configArg}] ${cli.msgs.error_mustIncludePath}`)
|
|
41
|
+
const inputPath = configArg.split('=')[1]
|
|
42
|
+
cli.configPath = path.isAbsolute(inputPath) ? inputPath : path.resolve(process.cwd(), inputPath)
|
|
43
|
+
if (!fs.existsSync(cli.configPath))
|
|
44
|
+
log.configURLandExit(`${cli.msgs.error_configFileNotFound}:`, cli.configPath)
|
|
45
|
+
|
|
46
|
+
} else // auto-discover .config.[mc]?js file
|
|
47
|
+
for (const configExt of ['.mjs', '.cjs', '.js']) {
|
|
48
|
+
const autoPath = path.resolve(process.cwd(), this.configFilename.replace(/\.[^.]+$/, configExt))
|
|
49
|
+
if (fs.existsSync(autoPath)) { cli.configPath = autoPath ; break }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
cli.configPathTried = true
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (cli.configPath) // load from config file
|
|
56
|
+
try {
|
|
57
|
+
const mod = require(cli.configPath), fileConfig = mod?.default ?? mod
|
|
58
|
+
if (!fileConfig || typeof fileConfig != 'object')
|
|
59
|
+
log.configURLandExit(`${cli.msgs.error_invalidConfigFile}.`)
|
|
60
|
+
Object.assign(cli.config, arguments.length ?
|
|
61
|
+
inputCtrlKeys.reduce((acc, key) => fileConfig[key] ? { ...acc, [key]: fileConfig[key] } : acc, {})
|
|
62
|
+
: fileConfig // whole file on arg-less load()
|
|
63
|
+
)
|
|
64
|
+
} catch (err) {
|
|
65
|
+
log.configURLandExit(`${cli.msgs.error_failedToLoadConfigFile}:`, cli.configPath, `\n${err.message}`) }
|
|
66
|
+
|
|
67
|
+
env.args.forEach(arg => { // load from CLI arg (overriding config file loads)
|
|
68
|
+
if (/^[^-]|--?(?:config|debug)/.test(arg) && arg != 'init') return
|
|
69
|
+
const ctrlKey = Object.keys(this.controls).find(key => this.controls[key]?.regex?.test(arg))
|
|
70
|
+
if (!ctrlKey && cli.msgs) log.errorAndExit(`[${arg}] ${cli.msgs.error_notRecognized}.`)
|
|
71
|
+
if (!inputCtrlKeys.includes(ctrlKey)) return // don't process env.args when load() specific keys
|
|
72
|
+
const ctrl = this.controls[ctrlKey]
|
|
73
|
+
if (ctrl.mode) // set cli.config.mode to mode name
|
|
74
|
+
cli.config.mode = ctrlKey.replace(/mode$/i, '').toLowerCase()
|
|
75
|
+
else // init flag/param/cmd cli.config[ctrlKey] val
|
|
76
|
+
cli.config[ctrlKey] = ctrl.type == 'param' ? arg.split('=')[1]?.trim() ?? '' : true
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
this.parseValidateConfig(inputCtrlKeys)
|
|
80
|
+
|
|
81
|
+
return inputCtrlKeys.length == 1 ? cli.config[inputCtrlKeys[0]] : cli.config
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
parseValidateConfig(ctrlKeys = Object.keys(this.controls)) {
|
|
85
|
+
const language = require('./language')
|
|
86
|
+
for (const key of [].concat(ctrlKeys)) {
|
|
87
|
+
const ctrl = this.controls[key], configVal = cli.config[key]
|
|
88
|
+
|
|
89
|
+
if (ctrl.parser && !ctrl.parsed) {
|
|
90
|
+
cli.config[key] = ctrl.parser(configVal) ; ctrl.parsed = true }
|
|
91
|
+
|
|
92
|
+
if (ctrl.valType) ({
|
|
93
|
+
positiveInt() {
|
|
94
|
+
const numVal = parseInt(configVal, 10)
|
|
95
|
+
if (isNaN(numVal) || numVal < 1)
|
|
96
|
+
log.errorAndExit(`[${key}] ${cli.msgs.error_nonPositiveNum}: ${configVal}`)
|
|
97
|
+
cli.config[key] = numVal
|
|
98
|
+
},
|
|
99
|
+
filepath() {
|
|
100
|
+
if (configVal && !fs.existsSync(configVal))
|
|
101
|
+
log.errorAndExit(`[${key}] ${cli.msgs.error_invalidFilepath}: ${configVal}`)
|
|
102
|
+
},
|
|
103
|
+
langCode() {
|
|
104
|
+
if (configVal && !language.validateLangCode(configVal))
|
|
105
|
+
log.errorAndExit(`[${key}] ${cli.msgs.error_invalidLangCode}: ${configVal}`)
|
|
106
|
+
}
|
|
107
|
+
})[ctrl.valType]?.()
|
|
108
|
+
|
|
109
|
+
if (cli.config.sequential) {
|
|
110
|
+
if (!cli.config.network)
|
|
111
|
+
log.errorAndExit(
|
|
112
|
+
`--network ${cli.msgs.error_isRequired} ${cli.msgs.error_whenPassing} --sequential.`)
|
|
113
|
+
else if (cli.config.qty <= 1)
|
|
114
|
+
log.errorAndExit(
|
|
115
|
+
`--qty ${cli.msgs.error_mustBeGreaterThanOne} ${cli.msgs.error_whenPassing} --sequential.`)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate-ip.config.mjs
|
|
3
|
+
*
|
|
4
|
+
* Optional config file for the generate-ip CLI.
|
|
5
|
+
* Copy this file to your project root to set default options.
|
|
6
|
+
* CLI arguments always override these values.
|
|
7
|
+
*
|
|
8
|
+
* Docs: https://github.com/adamlui/js-utils/tree/main/generate-ip/#-command-line-usage
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
mode: 'ipv4', // <ipv4|ipv6|mac> type of address to generate
|
|
13
|
+
qty: 1, // # of IPs to generate
|
|
14
|
+
sequential: false, // generate addresses in sequence
|
|
15
|
+
network: null, // starting network address (required for sequential mode)
|
|
16
|
+
quietMode: false, // suppress all logging except errors
|
|
17
|
+
uiLang: '' // ISO 639-1 code of language to display UI in
|
|
18
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"appName": { "message": "generate-ip" },
|
|
3
|
+
"appCopyright": { "message": "ยฉ 2024โ2026 Adam Lui & contributors under the MIT license" },
|
|
4
|
+
"prefix_globalVer": { "message": "Global version" },
|
|
5
|
+
"prefix_localVer": { "message": "Local version" },
|
|
6
|
+
"prefix_source": { "message": "Source" },
|
|
7
|
+
"error_readingLocalPkgVer": { "message": "Error reading local package version" },
|
|
8
|
+
"error_notRecognized": { "message": "not recognized" },
|
|
9
|
+
"error_nonPositiveNum": { "message": "argument can only be > 0" },
|
|
10
|
+
"error_invalidFilepath": { "message": "must be a valid existing file path. Got" },
|
|
11
|
+
"error_invalidLangCode": { "message": "is an invalid language code" },
|
|
12
|
+
"error_invalidURL": { "message": "Invalid URL" },
|
|
13
|
+
"error_invalidConfigFile": { "message": "Config file must export an object" },
|
|
14
|
+
"error_configFileNotFound": { "message": "Config file not found" },
|
|
15
|
+
"error_failedToLoadConfigFile": { "message": "Failed to load config file" },
|
|
16
|
+
"error_failedToFetchGlobalVer": { "message": "Failed to fetch global version" },
|
|
17
|
+
"error_failedToFetchSysLang": { "message": "Failed to fetch system language" },
|
|
18
|
+
"error_mustIncludePath": { "message": "must include =path" },
|
|
19
|
+
"error_isRequired": { "message": "is required" },
|
|
20
|
+
"error_whenPassing": { "message": "when passing" },
|
|
21
|
+
"error_mustBeGreaterThanOne": { "message": "must be > 1" },
|
|
22
|
+
"warn_configFileExists": { "message": "Config file already exists" },
|
|
23
|
+
"warn_remoteConfigNotFound": { "message": "Remote config file not found" },
|
|
24
|
+
"warn_remoteConfigFailed": { "message": "Failed to fetch remote config file" },
|
|
25
|
+
"info_exampleValidConfigFile": { "message": "Example valid config file" },
|
|
26
|
+
"info_copyingToClip": { "message": "Copying to clipboard" },
|
|
27
|
+
"info_moreHelp": { "message": "For more help" },
|
|
28
|
+
"info_type": { "message": "type" },
|
|
29
|
+
"info_or": { "message": "or" },
|
|
30
|
+
"info_visit": { "message": "visit" },
|
|
31
|
+
"info_configFileCreated": { "message": "Config file created" },
|
|
32
|
+
"info_fetchingRemoteConfigFrom": { "message": "Fetching remote config file from" },
|
|
33
|
+
"tip_editToSetDefaults": { "message": "Edit this file to customize defaults" },
|
|
34
|
+
"tip_cliArgsPrioritized": { "message": "CLI arguments always override these values" },
|
|
35
|
+
"helpSection_usage": { "message": "Usage" },
|
|
36
|
+
"helpSection_params": { "message": "Parameter options" },
|
|
37
|
+
"helpSection_flags": { "message": "Boolean options" },
|
|
38
|
+
"helpSection_cmds": { "message": "Commands" },
|
|
39
|
+
"optionDesc_uiLang": { "message": "ISO 639-1 code of language to display UI in" },
|
|
40
|
+
"optionDesc_qty": { "message": "Generate n IP address(es)" },
|
|
41
|
+
"optionDesc_config": { "message": "Load custom config file" },
|
|
42
|
+
"optionDesc_ipv6": { "message": "Generate IPv6 address" },
|
|
43
|
+
"optionDesc_mac": { "message": "Generate MAC address" },
|
|
44
|
+
"optionDesc_sequential": { "message": "Generate addresses in sequence" },
|
|
45
|
+
"optionDesc_network": { "message": "Starting network address (required for sequential mode)" },
|
|
46
|
+
"optionDesc_quiet": { "message": "Suppress all logging except errors" },
|
|
47
|
+
"optionDesc_init": { "message": "Create config file (in project root)" },
|
|
48
|
+
"optionDesc_help": { "message": "Display help screen" },
|
|
49
|
+
"optionDesc_version": { "message": "Show version number" }
|
|
50
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "generate-ip",
|
|
3
|
+
"author": "Adam Lui & contributors",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"copyrightYear": "2024โ2026",
|
|
6
|
+
"cmdFormat": "generate-[ip|ipv6|mac] [options|commands]",
|
|
7
|
+
"urls": {
|
|
8
|
+
"config": "https://github.com/adamlui/js-utils/blob/main/generate-ip/generate-ip.config.mjs",
|
|
9
|
+
"docs": "https://github.com/adamlui/js-utils/tree/main/generate-ip/docs",
|
|
10
|
+
"github": "https://github.com/adamlui/js-utils",
|
|
11
|
+
"jsdelivr": "https://cdn.jsdelivr.net/gh/adamlui/js-utils",
|
|
12
|
+
"npm": "https://www.npmjs.com/package/generate-ip",
|
|
13
|
+
"src": "https://github.com/adamlui/js-utils/tree/main/generate-ip/src"
|
|
14
|
+
},
|
|
15
|
+
"commitHashes": {
|
|
16
|
+
"locales": "6dc65c4"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ยฉ 2024โ2026 Adam Lui & contributors under the MIT license.
|
|
3
|
+
* Source: https://github.com/adamlui/js-utils/tree/main/generate-ip/src
|
|
4
|
+
* Documentation: https://github.com/adamlui/js-utils/tree/main/generate-ip/docs
|
|
5
|
+
*/
|
|
6
|
+
Object.assign(globalThis.api??={},{name:"generate-ip",aliases:{ipv4:["ipV4","IPv4","IPV4","Ipv4","IpV4","ip","IP","Ip"],ipv6:["ipV6","IPv6","IPV6","Ipv6","IpV6"],mac:["MAC","Mac","ethernet","Ethernet"]}});let ipv4={generate(t={}){var e="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv4generateoptions",r={verbose:!0,qty:1,sequential:!1,network:null};if(log.prefix="ipv4.generate()",validateOptions({options:t,defaultOptions:r,helpURL:e,exampleCall:"ipv4.generate({ verbose: false, qty: 3 })"})){(t={...r,...t}).verbose&&log.info(`Generating IPv4 address${1<t.qty?"es":""}...`);var o=[];if(t.sequential){t.network&&this.validate(t.network)?(!t.qty||t.qty<=1)&&log.errHelpURLandThrow({helpURL:e,errMsg:"options.qty must be > 1 when options.sequential is `true`."}):log.errHelpURLandThrow({helpURL:e,errMsg:"options.network must be a valid IP when options.sequential is `true`."});var[i,a,s,l]=t.network.split(".").map(Number);for(let e=0;e<t.qty;e++)o.push(i+`.${a}.${s}.`+(l+e))}else if(1<t.qty)for(let e=0;e<t.qty;e++)o.push(this.generate({...t,qty:1,verbose:!1}));else{var n=[];for(let e=0;e<4;e++)n.push(random.int(0,256));o.push(n.join("."))}r=1<t.qty?o:o[0];return t.verbose&&(log.info(`IPv4 address${1<t.qty?"es":""} generated!`),log.info(1==t.qty?r:r.join(", "))),r}},validate(e,t={}){var r="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv4validateaddress-options",o={verbose:!0};if(log.prefix="ipv4.validate()","string"!=typeof e&&log.errHelpURLandThrow({errMsg:"1st arg <address> must be a string.",helpURL:r}),validateOptions({options:t,defaultOptions:o,helpURL:r,exampleCall:"ipv4.validate('0.0.255.255', { verbose: false })"}))return(t={...o,...t}).verbose&&log.info(`Validating ${e}...`),o=!(4!=(r=e.split(".")).length||r.some(e=>!/^\d+$/.test(e)||parseInt(e,10)<0||255<parseInt(e,10))),t.verbose&&log.info(`IP is ${o?"":"in"}valid IPv4 address!`),o}},ipv6={generate(a={}){var e="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv6generateoptions",t={verbose:!0,qty:1,leadingZeros:!1,doubleColon:!0,sequential:!1,network:null};if(log.prefix="ipv6.generate()",validateOptions({options:a,defaultOptions:t,helpURL:e,exampleCall:"ipv6.generate({ leadingZeros: true, qty: 5 })"})){(a={...t,...a}).verbose&&log.info(`Generating IPv6 address${1<a.qty?"es":""}...`);var s=[];if(a.sequential){a.network&&this.validate(a.network)?(!a.qty||a.qty<=1)&&log.errHelpURLandThrow({helpURL:e,errMsg:"options.qty must be > 1 when options.sequential is `true`."}):log.errHelpURLandThrow({helpURL:e,errMsg:"options.network must be a valid IP when options.sequential is `true`."});var r=a.network.split(":").map(e=>parseInt(e,16)||0);for(let e=0;e<a.qty;e++){var o=r[7];r[7]=o+e,r[7]>o+1&&(r[7]=o+1),s.push(r.map(e=>e.toString(16).padStart(4,"0")).join(":"))}}else if(1<a.qty)for(let e=0;e<a.qty;e++)s.push(this.generate({...a,qty:1,verbose:!1}));else{let t=[],{qty:e,sequential:r,network:o,...i}=a;for(let e=0;e<8;e++)t.push(random.hex(4));s.push(this.format(t.join(":"),{...i,verbose:!1}))}t=1<a.qty?s:s[0];return a.verbose&&(log.info(`IPv6 address${1<a.qty?"es":""} generated!`),log.info(1==a.qty?t:t.join(", "))),t}},format(t,r={}){var o="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv6formatipv6address-options",i={verbose:!0,leadingZeros:!1,doubleColon:!0};if(log.prefix="ipv6.format()","string"!=typeof t&&log.errHelpURLandThrow({errMsg:"1st arg <ipv6address> must be a string.",helpURL:o}),this.validate(t,{verbose:!1})||log.errHelpURLandThrow({errMsg:t+" is not a valid IPv6 address.",helpURL:o}),validateOptions({options:r,defaultOptions:i,helpURL:o,exampleCall:"ipv6.format('0d::ffff:192.1.56.10/96', { leadingZeros: true, doubleColon: false })"})){r={...i,...r};let e=t;if(e=r.doubleColon?(r.verbose&&log.info("Replacing zero series w/ '::'..."),e.replace(/:(?:0+:)+/,"::")):(r.verbose&&log.info("Expanding '::' into zero series..."),o=e.split(":").filter(Boolean).length,i=r.leadingZeros?"0000":"0",o=Array(8-o).fill(i).join(":"),e.replace("::",`:${o}:`)),r.leadingZeros){r.verbose&&log.info("Adding leading zeros...");var a=e.split(":");for(let e=0;e<a.length;e++)for(;a[e].length<4;)a[e]="0"+a[e];e=a.join(":")}else r.verbose&&log.info("Stripping leading zeros..."),e=t.replace(/(^|(?<=:))0+(?!:)/g,"$1");return r.verbose&&(e!=t?log.info("IP formatted successfully!"):log.info("IP already formatted to specs."),log.info(e)),e}},validate(r,o={}){var i="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv6validateaddress-options",a={verbose:!0};if(log.prefix="ipv6.validate()","string"!=typeof r&&log.errHelpURLandThrow({errMsg:"1st arg <address> must be a string.",helpURL:i}),validateOptions({options:o,defaultOptions:a,helpURL:i,exampleCall:"ipv6.validate('0:0:0:0:0:ffff:192.1.56.10/96', { verbose: false })"})){(o={...a,...o}).verbose&&log.info(`Validating ${r}...`);let e=r.split(/::?/),t=e[e.length-1];i=!(r.includes("::")&&2<r.split("::").length||/:{3,}/.test(r)||e.length<2||8<e.length||e.some(e=>!(/^[\da-f]{1,4}$/i.test(e)||e==t&&ipv4.validate(t.replace(/\/(?:12[0-8]|[1-9]?\d)$/,""),{verbose:!1}))));return o.verbose&&log.info(`IP is ${i?"":"in"}valid IPv6 address!`),i}}},mac={generate(t={}){var e="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#macgenerateoptions",r={verbose:!0,qty:1,sequential:!1,network:null};if(log.prefix="mac.generate()",validateOptions({options:t,defaultOptions:r,helpURL:e,exampleCall:"mac.generate({ verbose: false, qty: 2 })"})){(t={...r,...t}).verbose&&log.info(`Generating MAC address${1<t.qty?"es":""}...`);var o=[];if(t.sequential){t.network&&this.validate(t.network)?(!t.qty||t.qty<=1)&&log.errHelpURLandThrow({helpURL:e,errMsg:"options.qty must be > 1 when options.sequential is `true`."}):log.errHelpURLandThrow({helpURL:e,errMsg:"options.network must be a valid MAC when options.sequential is `true`."});var i=t.network.split(":").map(e=>parseInt(e,16)||0);for(let e=0;e<t.qty;e++){var a=i[5];i[5]=a+e,i[5]>a+1&&(i[5]=a+1),o.push(i.map(e=>e.toString(16).padStart(2,"0")).join(":"))}}else if(1<t.qty)for(let e=0;e<t.qty;e++)o.push(this.generate({...t,qty:1,verbose:!1}));else{var[r,e]=Array.from({length:2},()=>{var t=[];for(let e=0;e<3;e++)t.push(random.hex(2));return t.join(":")});o.push(r+":"+e)}r=1<t.qty?o:o[0];return t.verbose&&(log.info(`MAC address${1<t.qty?"es":""} generated!`),log.info(1==t.qty?r:r.join(", "))),r}},validate(e,t={}){var r="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#macvalidateaddress-options",o={verbose:!0};if(log.prefix="mac.validate()","string"!=typeof e&&log.errHelpURLandThrow({errMsg:"1st arg <address> must be a string.",helpURL:r}),validateOptions({options:t,defaultOptions:o,helpURL:r,exampleCall:"mac.validate('00:1A:2B:3C:4D:5E', { verbose: false })"}))return(t={...o,...t}).verbose&&log.info(`Validating ${e}...`),r=/^(?:[\da-f]{2}[:-]){5}[\da-f]{2}$/i.test(e),t.verbose&&log.info(`Address is ${r?"":"in"}valid MAC address!`),r}};function validateOptions({options:e,defaultOptions:t,helpURL:r,exampleCall:o}){var i,a,s=Object.keys(t).filter(e=>"boolean"==typeof t[e]),l=Object.keys(t).filter(e=>Number.isInteger(t[e]));if("object"!=typeof e)return i=o.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:",o),log.validOptions(t),log.helpURL(r),!1;for(a in e){if(!Object.prototype.hasOwnProperty.call(t,a))return log.error(`\`${a}\` is an invalid option.`),log.validOptions(t),log.helpURL(r),!1;if(s.includes(a)&&"boolean"!=typeof e[a])return log.error(`[${a}] option can only be \`true\` or \`false\`.`),log.helpURL(r),!1;if(l.includes(a)&&(e[a]=parseInt(e[a],10),isNaN(e[a])||e[a]<1))return log.error(`[${a}] option can only be an integer > 0.`),log.helpURL(r),!1}return!0}let random={int(e,t){var r;return"undefined"==typeof require?(r=(window.crypto||window.msCrypto)?.getRandomValues(new Uint32Array(1))[0]/4294967295||Math.random(),Math.floor(r*(t-e))+e):require("crypto").randomInt(e,t)},hex(t){let r="";for(let e=0;e<t;e++)r+=random.int(0,16).toString(16);return r}},log={prefix:api.name,errHelpURLandThrow({errMsg:e,helpURL:t}){throw this.error(e),this.helpURL(t),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 t=Object.keys(e).join(", "),e=JSON.stringify(e,null,2).replace(/"([^"]+)":/g,"$1:").replace(/"/g,"'").replace(/\n\s*/g," ");this.info(`Valid options: [${t}]`),this.info("If omitted, default settings are: "+e)}};api.exports={ipv4:ipv4,ipv6:ipv6,mac:mac};try{module.exports={...api.exports}}catch(e){}try{Object.assign(window,api.exports)}catch(e){}for(let t in api.aliases)api.aliases[t].forEach(e=>{try{module.exports[e]??=module.exports[t]}catch(e){}try{window[e]??=window[t]}catch(e){}});
|
package/docs/README.md
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
<a href="#%EF%B8%8F-mit-license">
|
|
12
12
|
<img height=31 src="https://img.shields.io/badge/License-MIT-orange.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
13
|
-
<a href="https://github.com/adamlui/js-utils/releases/tag/generate-ip-2.8.
|
|
14
|
-
<img height=31 src="https://img.shields.io/badge/Latest_Build-2.8.
|
|
13
|
+
<a href="https://github.com/adamlui/js-utils/releases/tag/generate-ip-2.8.2">
|
|
14
|
+
<img height=31 src="https://img.shields.io/badge/Latest_Build-2.8.2-44cc11.svg?logo=icinga&logoColor=white&labelColor=464646&style=for-the-badge"></a>
|
|
15
15
|
<a href="https://www.npmjs.com/package/generate-ip?activeTab=code">
|
|
16
16
|
<img height=31 src="https://img.shields.io/npm/unpacked-size/generate-ip?style=for-the-badge&logo=ebox&logoColor=white&labelColor=464646&color=blue"></a>
|
|
17
|
-
<a href="https://github.com/adamlui/js-utils/blob/generate-ip-2.8.
|
|
18
|
-
<img height=31 src="https://img.shields.io/github/size/adamlui/js-utils/generate-ip/dist/generate-ip.min.js?branch=generate-ip-2.8.
|
|
17
|
+
<a href="https://github.com/adamlui/js-utils/blob/generate-ip-2.8.2/generate-ip/dist/generate-ip.min.js">
|
|
18
|
+
<img height=31 src="https://img.shields.io/github/size/adamlui/js-utils/generate-ip/dist/generate-ip.min.js?branch=generate-ip-2.8.2&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
|
|
19
19
|
<a href="https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=adamlui_js-utils:generate-ip/src/generate-ip.js">
|
|
20
20
|
<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-ip%2Fsrc%2Fgenerate-ip.js%26metricKeys%3Dvulnerabilities&query=%24.component.measures.0.value&style=for-the-badge&logo=sonarcloud&logoColor=white&labelColor=464646&label=Vulnerabilities&color=gold"></a>
|
|
21
21
|
<a href="https://github.com/toolleeo/cli-apps#networking">
|
|
@@ -87,14 +87,14 @@ const { ipv4, ipv6, mac } = require('generate-ip')
|
|
|
87
87
|
#### <> HTML script tag:
|
|
88
88
|
|
|
89
89
|
```html
|
|
90
|
-
<script src="https://cdn.jsdelivr.net/npm/generate-ip@2.8.
|
|
90
|
+
<script src="https://cdn.jsdelivr.net/npm/generate-ip@2.8.2/dist/generate-ip.min.js"></script>
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
#### ES6:
|
|
94
94
|
|
|
95
95
|
```js
|
|
96
96
|
(async () => {
|
|
97
|
-
await import('https://cdn.jsdelivr.net/npm/generate-ip@2.8.
|
|
97
|
+
await import('https://cdn.jsdelivr.net/npm/generate-ip@2.8.2/dist/generate-ip.min.js')
|
|
98
98
|
// Your code here...
|
|
99
99
|
})()
|
|
100
100
|
```
|
|
@@ -103,7 +103,7 @@ const { ipv4, ipv6, mac } = require('generate-ip')
|
|
|
103
103
|
|
|
104
104
|
```js
|
|
105
105
|
...
|
|
106
|
-
// @require https://cdn.jsdelivr.net/npm/generate-ip@2.8.
|
|
106
|
+
// @require https://cdn.jsdelivr.net/npm/generate-ip@2.8.2/dist/generate-ip.min.js
|
|
107
107
|
// ==/UserScript==
|
|
108
108
|
|
|
109
109
|
// Your code here...
|
|
@@ -111,7 +111,7 @@ const { ipv4, ipv6, mac } = require('generate-ip')
|
|
|
111
111
|
|
|
112
112
|
<br>
|
|
113
113
|
|
|
114
|
-
๐ **Note:** To always import the latest version (not recommended in production!) remove the `@2.8.
|
|
114
|
+
๐ **Note:** To always import the latest version (not recommended in production!) remove the `@2.8.2` version tag from the jsDelivr URL: `https://cdn.jsdelivr.net/npm/generate-ip/dist/generate-ip.min.js`
|
|
115
115
|
|
|
116
116
|
<br>
|
|
117
117
|
|