@twardoch/namzy 0.1.0 → 1.0.11
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 -37
- package/dist/cli.js +5 -11
- package/dist/index.d.ts +3 -4
- package/dist/index.js +8 -32
- package/dist/wordlist.d.ts +2 -2
- package/dist/wordlist.js +102 -12
- package/package.json +2 -2
- package/src/cli.ts +6 -13
- package/src/index.ts +16 -39
- package/src/wordlist.ts +102 -12
package/README.md
CHANGED
|
@@ -1,71 +1,47 @@
|
|
|
1
1
|
# namzy
|
|
2
2
|
|
|
3
|
-
Generates fun, human-friendly project names
|
|
4
|
-
fresh names every run — but pass `--seed` for reproducibility.
|
|
3
|
+
Generates fun, human-friendly fused project names from a bundled local wordlist.
|
|
5
4
|
|
|
6
5
|
## Install
|
|
7
6
|
|
|
8
7
|
```sh
|
|
9
|
-
npm install namzy
|
|
8
|
+
npm install @twardoch/namzy
|
|
10
9
|
# or run without installing:
|
|
11
|
-
npx namzy
|
|
10
|
+
npx @twardoch/namzy
|
|
12
11
|
```
|
|
13
12
|
|
|
14
13
|
## CLI
|
|
15
14
|
|
|
16
15
|
```sh
|
|
17
|
-
|
|
18
|
-
namzy
|
|
19
|
-
|
|
20
|
-
# PascalCase two-word name
|
|
21
|
-
namzy --shape joined
|
|
22
|
-
|
|
23
|
-
# Space-separated two words
|
|
24
|
-
namzy --shape spaced
|
|
16
|
+
npx @twardoch/namzy
|
|
25
17
|
|
|
26
18
|
# Generate 5 names
|
|
27
|
-
namzy --count 5
|
|
28
|
-
|
|
29
|
-
# Fetch words from the web (falls back to offline on failure)
|
|
30
|
-
namzy --online --shape spaced
|
|
19
|
+
npx @twardoch/namzy --count 5
|
|
31
20
|
|
|
32
21
|
# Help
|
|
33
|
-
namzy --help
|
|
22
|
+
npx @twardoch/namzy --help
|
|
34
23
|
```
|
|
35
24
|
|
|
36
25
|
## Library
|
|
37
26
|
|
|
38
27
|
```ts
|
|
39
|
-
import { generate } from "namzy";
|
|
28
|
+
import { generate } from "@twardoch/namzy";
|
|
40
29
|
|
|
41
|
-
// Single word (default)
|
|
42
30
|
const name = await generate();
|
|
43
31
|
|
|
44
|
-
//
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
// Spaced, seeded for reproducibility
|
|
48
|
-
const seeded = await generate({ shape: "spaced", seed: 42 });
|
|
49
|
-
|
|
50
|
-
// Online mode (falls back to offline)
|
|
51
|
-
const online = await generate({ online: true, shape: "joined" });
|
|
32
|
+
// Seeded for reproducibility
|
|
33
|
+
const seeded = await generate({ seed: 42 });
|
|
52
34
|
|
|
53
|
-
console.log(name,
|
|
35
|
+
console.log(name, seeded);
|
|
54
36
|
```
|
|
55
37
|
|
|
56
|
-
##
|
|
38
|
+
## Wordlist
|
|
57
39
|
|
|
58
|
-
|
|
59
|
-
|------|-------------|
|
|
60
|
-
| `--offline` | Uses bundled wordlist (default, always works) |
|
|
61
|
-
| `--online` | Fetches from `random-word-api.herokuapp.com`, falls back offline |
|
|
40
|
+
Namzy uses the shared bundled wordlists of 300 geographic words and 300 common words. Each pair may be joined in either order, for 180,000 raw ordered pairings before seam cleanup and mangling.
|
|
62
41
|
|
|
63
42
|
## How it works
|
|
64
43
|
|
|
65
|
-
Picks
|
|
66
|
-
words (ember, flint, willow…), then applies a small phonetic mangling pass
|
|
67
|
-
(e.g. `s→z`, `ph→f`, `oo→u`) for a playful feel. Results are deterministic
|
|
68
|
-
for a given seed.
|
|
44
|
+
Picks one geographic name and one evocative common word, joins them in either order, cleans awkward seams, and applies the consonant rotation `c→q · f→v · k→c · q→k · s→z · z→s · v→f · w→u`. Results are deterministic for a given seed.
|
|
69
45
|
|
|
70
46
|
## License
|
|
71
47
|
|
package/dist/cli.js
CHANGED
|
@@ -8,18 +8,15 @@ Usage:
|
|
|
8
8
|
namzy [options]
|
|
9
9
|
|
|
10
10
|
Options:
|
|
11
|
-
--online Fetch words from a public API (falls back to offline)
|
|
12
11
|
--count <N> Number of names to generate (default: 1)
|
|
13
12
|
--help Show this help
|
|
14
13
|
|
|
15
14
|
Examples:
|
|
16
15
|
namzy
|
|
17
16
|
namzy --count 5
|
|
18
|
-
namzy --online --count 3
|
|
19
17
|
`.trimStart();
|
|
20
18
|
function parseArgs(argv) {
|
|
21
19
|
const args = argv.slice(2);
|
|
22
|
-
const opts = {};
|
|
23
20
|
let count = 1;
|
|
24
21
|
for (let i = 0; i < args.length; i++) {
|
|
25
22
|
const arg = args[i];
|
|
@@ -29,12 +26,9 @@ function parseArgs(argv) {
|
|
|
29
26
|
process.stdout.write(HELP);
|
|
30
27
|
process.exit(0);
|
|
31
28
|
break;
|
|
32
|
-
case "--online":
|
|
33
|
-
opts.online = true;
|
|
34
|
-
break;
|
|
35
29
|
case "--count": {
|
|
36
30
|
const n = parseInt(args[++i], 10);
|
|
37
|
-
if (isNaN(n) || n < 1) {
|
|
31
|
+
if (Number.isNaN(n) || n < 1) {
|
|
38
32
|
process.stderr.write(`--count must be a positive integer\n`);
|
|
39
33
|
process.exit(1);
|
|
40
34
|
}
|
|
@@ -46,14 +40,14 @@ function parseArgs(argv) {
|
|
|
46
40
|
process.exit(1);
|
|
47
41
|
}
|
|
48
42
|
}
|
|
49
|
-
return {
|
|
43
|
+
return { count };
|
|
50
44
|
}
|
|
51
45
|
async function main() {
|
|
52
|
-
const {
|
|
46
|
+
const { count } = parseArgs(process.argv);
|
|
53
47
|
const base = Date.now();
|
|
54
48
|
for (let i = 0; i < count; i++) {
|
|
55
|
-
const name = await generate({
|
|
56
|
-
process.stdout.write(name
|
|
49
|
+
const name = await generate({ seed: base + i * 1337 });
|
|
50
|
+
process.stdout.write(`${name}\n`);
|
|
57
51
|
}
|
|
58
52
|
}
|
|
59
53
|
main().catch((err) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { mangle, mulberry32
|
|
1
|
+
import { joinClean, mangle, mulberry32 } from "./mangle.js";
|
|
2
2
|
export interface NamzyOptions {
|
|
3
|
-
online?: boolean;
|
|
4
3
|
seed?: number;
|
|
5
4
|
}
|
|
6
5
|
/**
|
|
@@ -8,5 +7,5 @@ export interface NamzyOptions {
|
|
|
8
7
|
* Two raw words → junction-cleaned fusion → consonant rotation → capitalize.
|
|
9
8
|
*/
|
|
10
9
|
export declare function generate(opts?: NamzyOptions): Promise<string>;
|
|
11
|
-
export {
|
|
12
|
-
export {
|
|
10
|
+
export { COMMON, GEO } from "./wordlist.js";
|
|
11
|
+
export { joinClean, mangle, mulberry32 };
|
package/dist/index.js
CHANGED
|
@@ -1,48 +1,24 @@
|
|
|
1
1
|
// this_file: src/index.ts
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { joinClean, mangle, mulberry32 } from "./mangle.js";
|
|
3
|
+
import { COMMON, GEO } from "./wordlist.js";
|
|
4
4
|
function capitalize(s) {
|
|
5
5
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
6
6
|
}
|
|
7
7
|
function pick(arr, rng) {
|
|
8
8
|
return arr[Math.floor(rng() * arr.length)];
|
|
9
9
|
}
|
|
10
|
-
async function fetchOnlineWords() {
|
|
11
|
-
const url = `https://random-word-api.herokuapp.com/word?number=2&length=6`;
|
|
12
|
-
const resp = await fetch(url);
|
|
13
|
-
if (!resp.ok)
|
|
14
|
-
throw new Error(`HTTP ${resp.status}`);
|
|
15
|
-
const data = (await resp.json());
|
|
16
|
-
if (!Array.isArray(data) || data.length < 2)
|
|
17
|
-
throw new Error("Bad response");
|
|
18
|
-
return data.slice(0, 2).map((w) => w.toLowerCase().replace(/[^a-z]/g, ""));
|
|
19
|
-
}
|
|
20
10
|
/**
|
|
21
11
|
* Generate a single fused, mangled namzy name.
|
|
22
12
|
* Two raw words → junction-cleaned fusion → consonant rotation → capitalize.
|
|
23
13
|
*/
|
|
24
14
|
export async function generate(opts) {
|
|
25
|
-
const online = opts?.online ?? false;
|
|
26
15
|
const seed = opts?.seed ?? Date.now();
|
|
27
16
|
const rng = mulberry32(seed);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const words = await fetchOnlineWords();
|
|
33
|
-
[w1, w2] = words;
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
w1 = pick(GEO, rng).toLowerCase();
|
|
37
|
-
w2 = pick(COMMON, rng).toLowerCase();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
w1 = pick(GEO, rng).toLowerCase();
|
|
42
|
-
w2 = pick(COMMON, rng).toLowerCase();
|
|
43
|
-
}
|
|
44
|
-
const fused = joinClean(w1, w2);
|
|
17
|
+
const w1 = pick(GEO, rng).toLowerCase();
|
|
18
|
+
const w2 = pick(COMMON, rng).toLowerCase();
|
|
19
|
+
const [first, second] = rng() < 0.5 ? [w1, w2] : [w2, w1];
|
|
20
|
+
const fused = joinClean(first, second);
|
|
45
21
|
return capitalize(mangle(fused));
|
|
46
22
|
}
|
|
47
|
-
export {
|
|
48
|
-
export {
|
|
23
|
+
export { COMMON, GEO } from "./wordlist.js";
|
|
24
|
+
export { joinClean, mangle, mulberry32 };
|
package/dist/wordlist.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Geographic names (A-Za-z only, no diacritics) */
|
|
1
|
+
/** Geographic names (A-Za-z only, no diacritics). Shared across all implementations. */
|
|
2
2
|
export declare const GEO: string[];
|
|
3
|
-
/** Common evocative English words */
|
|
3
|
+
/** Common evocative English words. Shared across all implementations. */
|
|
4
4
|
export declare const COMMON: string[];
|
package/dist/wordlist.js
CHANGED
|
@@ -1,17 +1,107 @@
|
|
|
1
1
|
// this_file: src/wordlist.ts
|
|
2
|
-
/** Geographic names (A-Za-z only, no diacritics) */
|
|
2
|
+
/** Geographic names (A-Za-z only, no diacritics). Shared across all implementations. */
|
|
3
3
|
export const GEO = [
|
|
4
|
-
"tokyo", "paris", "oslo", "berlin", "lagos", "lima",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
4
|
+
"tokyo", "paris", "oslo", "berlin", "lagos", "lima",
|
|
5
|
+
"boston", "vienna", "cairo", "kyoto", "dubai", "seoul",
|
|
6
|
+
"milan", "tunis", "perth", "genoa", "porto", "bruges",
|
|
7
|
+
"ghent", "brest", "minsk", "sofia", "riga", "lyon",
|
|
8
|
+
"basel", "natal", "recife", "darwin", "hobart", "odessa",
|
|
9
|
+
"varna", "split", "kotor", "tirana", "skopje", "bitola",
|
|
10
|
+
"plovdiv", "gabrovo", "ruse", "delhi", "rome", "athens",
|
|
11
|
+
"nairobi", "bali", "havana", "lisbon", "bogota", "dakar",
|
|
12
|
+
"quito", "vilnius", "vaduz", "bern", "accra", "kigali",
|
|
13
|
+
"abuja", "bamako", "niamey", "lome", "prague", "dublin",
|
|
14
|
+
"naples", "tulum", "tbilisi", "yerevan", "astana", "lusaka",
|
|
15
|
+
"harare", "asmara", "manaus", "cuenca", "merida", "geneva",
|
|
16
|
+
"zurich", "venice", "sydney", "denver", "austin", "phoenix",
|
|
17
|
+
"tucson", "reno", "boise", "fargo", "tulsa", "tampa",
|
|
18
|
+
"miami", "salem", "dover", "trenton", "helena", "juneau",
|
|
19
|
+
"topeka", "albany", "amsterdam", "antwerp", "arusha", "aspen",
|
|
20
|
+
"atlanta", "auckland", "baghdad", "baku", "bangkok", "barcelona",
|
|
21
|
+
"beijing", "beirut", "belfast", "belgrade", "bergen", "bilbao",
|
|
22
|
+
"bordeaux", "braga", "brisbane", "bristol", "brussels", "bucharest",
|
|
23
|
+
"budapest", "calgary", "canberra", "cardiff", "casablanca", "chicago",
|
|
24
|
+
"cologne", "colombo", "copenhagen", "cork", "dresden", "durban",
|
|
25
|
+
"edinburgh", "florence", "frankfurt", "gdansk", "glasgow", "granada",
|
|
26
|
+
"guangzhou", "hamburg", "hanoi", "helsinki", "houston", "jakarta",
|
|
27
|
+
"jerusalem", "karachi", "krakow", "kuwait", "leipzig", "lille",
|
|
28
|
+
"london", "luanda", "lucerne", "madrid", "malaga", "manila",
|
|
29
|
+
"marrakesh", "marseille", "melbourne", "memphis", "montreal", "moscow",
|
|
30
|
+
"munich", "nagoya", "nantes", "napier", "nashville", "orlando",
|
|
31
|
+
"osaka", "ottawa", "palermo", "panama", "phuket", "pisa",
|
|
32
|
+
"poznan", "quebec", "reykjavik", "rotterdam", "sarajevo", "sapporo",
|
|
33
|
+
"sevilla", "shanghai", "stockholm", "suzhou", "swansea", "taipei",
|
|
34
|
+
"tallinn", "tangier", "tehran", "thimphu", "toronto", "toulouse",
|
|
35
|
+
"trieste", "valencia", "vancouver", "verona", "warsaw", "winnipeg",
|
|
36
|
+
"wroclaw", "zagreb", "aarhus", "abidjan", "adelaide", "alger",
|
|
37
|
+
"annaba", "ankara", "antalya", "arezzo", "asuncion", "avignon",
|
|
38
|
+
"baltimore", "banjul", "belem", "bologna", "bremen", "cancun",
|
|
39
|
+
"caracas", "cartagena", "catania", "charlotte", "chennai", "chiangmai",
|
|
40
|
+
"cleveland", "cordoba", "curitiba", "cusco", "dallas", "damascus",
|
|
41
|
+
"dundee", "espoo", "fez", "freetown", "fukuoka", "funchal",
|
|
42
|
+
"gothenburg", "guayaquil", "haifa", "halifax", "hamilton", "honolulu",
|
|
43
|
+
"ibadan", "innsbruck", "izmir", "jaipur", "jeddah", "kampala",
|
|
44
|
+
"kansas", "kashgar", "kathmandu", "khartoum", "kingston", "kinshasa",
|
|
45
|
+
"koblenz", "kortrijk", "lahti", "lausanne", "leeds", "leuven",
|
|
46
|
+
"liege", "liverpool", "ljubljana", "lodz", "luxor", "macao",
|
|
47
|
+
"madison", "malmo", "manchester", "mandalay", "maputo", "mendoza",
|
|
48
|
+
"monterrey", "montevideo", "nicosia", "noumea", "nuremberg", "okinawa",
|
|
49
|
+
"omaha", "padua", "penang", "peshawar", "portland", "pretoria",
|
|
50
|
+
"rabat", "raleigh", "rennes", "richmond", "salzburg", "samarkand",
|
|
51
|
+
"santander", "santiago", "sendai", "singapore", "skagen", "stavanger",
|
|
52
|
+
"stuttgart", "surabaya", "suva", "tampere", "taranto", "tarragona",
|
|
53
|
+
"tiruchirappalli", "trondheim", "utrecht", "valletta", "victoria", "vigo",
|
|
9
54
|
];
|
|
10
|
-
/** Common evocative English words */
|
|
55
|
+
/** Common evocative English words. Shared across all implementations. */
|
|
11
56
|
export const COMMON = [
|
|
12
|
-
"river", "stone", "ember", "frost", "harbor", "willow",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
57
|
+
"river", "stone", "ember", "frost", "harbor", "willow",
|
|
58
|
+
"copper", "marble", "anchor", "lantern", "cedar", "falcon",
|
|
59
|
+
"coral", "dagger", "flint", "grove", "haven", "iron",
|
|
60
|
+
"jasper", "kelp", "larch", "mast", "nettle", "oak",
|
|
61
|
+
"pine", "quill", "reed", "sage", "thorn", "umber",
|
|
62
|
+
"vale", "wren", "yarrow", "zenith", "amber", "birch",
|
|
63
|
+
"cliff", "drift", "forge", "glade", "mesa", "canyon",
|
|
64
|
+
"basin", "fern", "gale", "peak", "ridge", "shore",
|
|
65
|
+
"tide", "bluff", "brook", "crest", "delta", "glen",
|
|
66
|
+
"helm", "inlet", "jetty", "knoll", "loft", "moor",
|
|
67
|
+
"notch", "orbit", "prism", "thunder", "silver", "meadow",
|
|
68
|
+
"basalt", "summit", "valley", "bridge", "beacon", "ranger",
|
|
69
|
+
"timber", "clover", "pebble", "ripple", "canopy", "chimney",
|
|
70
|
+
"cinder", "comet", "ferret", "glider", "jaguar", "kernel",
|
|
71
|
+
"lancer", "mortar", "nebula", "osprey", "patrol", "quartz",
|
|
72
|
+
"rafter", "sparrow", "granite", "hazel", "kindle", "laurel",
|
|
73
|
+
"mossy", "nimble", "ochre", "russet", "sable", "vapor",
|
|
74
|
+
"wicker", "cobalt", "dune", "hollow", "ivy", "juniper",
|
|
75
|
+
"linden", "mist", "oyster", "acorn", "anvil", "apron",
|
|
76
|
+
"arrow", "ash", "atlas", "autumn", "badge", "banner",
|
|
77
|
+
"beryl", "blossom", "boulder", "bramble", "brass", "breeze",
|
|
78
|
+
"briar", "bronze", "brooklet", "buckle", "burl", "cairn",
|
|
79
|
+
"candle", "canvas", "cavern", "chalk", "charm", "citrine",
|
|
80
|
+
"cloud", "cloverleaf", "cobaltcore", "compass", "copperleaf", "cradle",
|
|
81
|
+
"cricket", "crystal", "daisy", "dale", "dawn", "deerden",
|
|
82
|
+
"desert", "dew", "diamond", "dovetail", "dragonfly", "dream",
|
|
83
|
+
"drifter", "dunecrest", "dusk", "echo", "elm", "fernleaf",
|
|
84
|
+
"firefly", "fjord", "flame", "flower", "flume", "forest",
|
|
85
|
+
"foxglove", "garden", "garnet", "geode", "glacier", "glimmer",
|
|
86
|
+
"goldfinch", "gravel", "greenwood", "griffin", "harborlight", "hearth",
|
|
87
|
+
"heather", "heron", "hill", "honey", "horizon", "icicle",
|
|
88
|
+
"ivory", "jewel", "kestrel", "lagoon", "laurelwood", "leaf",
|
|
89
|
+
"lighthouse", "lilac", "lotus", "meadowlark", "moon", "moss",
|
|
90
|
+
"myrtle", "nectar", "nightingale", "obsidian", "olive", "opal",
|
|
91
|
+
"orchard", "otter", "pebblebrook", "petal", "plume", "prairie",
|
|
92
|
+
"rain", "raven", "redwood", "reef", "ribbon", "root",
|
|
93
|
+
"rose", "ruby", "sail", "salt", "sapphire", "scarlet",
|
|
94
|
+
"seabird", "sequoia", "shadow", "shale", "shell", "shimmer",
|
|
95
|
+
"skylark", "slate", "smoke", "snow", "sparrowhawk", "spindle",
|
|
96
|
+
"spirit", "spring", "spruce", "star", "starlight", "storm",
|
|
97
|
+
"stream", "sunbeam", "sunset", "sycamore", "talon", "thicket",
|
|
98
|
+
"thistle", "thunderhead", "tidepool", "topaz", "trail", "valleyfield",
|
|
99
|
+
"velvet", "violet", "walnut", "waterfall", "wave", "wind",
|
|
100
|
+
"winter", "wolfram", "woodland", "zephyr", "ashwood", "bell",
|
|
101
|
+
"bird", "bloom", "branch", "bright", "brookside", "camp",
|
|
102
|
+
"campfire", "castle", "chime", "clay", "cloudbank", "coast",
|
|
103
|
+
"copperwood", "creek", "crown", "emberfall", "field", "firestone",
|
|
104
|
+
"flag", "fog", "fox", "gardenia", "gate", "glow",
|
|
105
|
+
"grass", "grovewood", "harborstone", "hilltop", "honeycomb", "island",
|
|
106
|
+
"kestrelwing", "lake", "leafwing", "marigold", "moonstone", "morning",
|
|
17
107
|
];
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twardoch/namzy",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "Generates fun fused human-friendly project names",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"bin": {
|
|
10
|
-
"namzy": "
|
|
10
|
+
"namzy": "dist/cli.js"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"dist",
|
package/src/cli.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// this_file: src/cli.ts
|
|
3
3
|
|
|
4
4
|
import { generate } from "./index.js";
|
|
5
|
-
import type { NamzyOptions } from "./index.js";
|
|
6
5
|
|
|
7
6
|
const HELP = `
|
|
8
7
|
namzy — generate fun fused project names
|
|
@@ -11,19 +10,16 @@ Usage:
|
|
|
11
10
|
namzy [options]
|
|
12
11
|
|
|
13
12
|
Options:
|
|
14
|
-
--online Fetch words from a public API (falls back to offline)
|
|
15
13
|
--count <N> Number of names to generate (default: 1)
|
|
16
14
|
--help Show this help
|
|
17
15
|
|
|
18
16
|
Examples:
|
|
19
17
|
namzy
|
|
20
18
|
namzy --count 5
|
|
21
|
-
namzy --online --count 3
|
|
22
19
|
`.trimStart();
|
|
23
20
|
|
|
24
|
-
function parseArgs(argv: string[]): {
|
|
21
|
+
function parseArgs(argv: string[]): { count: number } {
|
|
25
22
|
const args = argv.slice(2);
|
|
26
|
-
const opts: NamzyOptions = {};
|
|
27
23
|
let count = 1;
|
|
28
24
|
|
|
29
25
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -34,12 +30,9 @@ function parseArgs(argv: string[]): { opts: NamzyOptions; count: number } {
|
|
|
34
30
|
process.stdout.write(HELP);
|
|
35
31
|
process.exit(0);
|
|
36
32
|
break;
|
|
37
|
-
case "--online":
|
|
38
|
-
opts.online = true;
|
|
39
|
-
break;
|
|
40
33
|
case "--count": {
|
|
41
34
|
const n = parseInt(args[++i], 10);
|
|
42
|
-
if (isNaN(n) || n < 1) {
|
|
35
|
+
if (Number.isNaN(n) || n < 1) {
|
|
43
36
|
process.stderr.write(`--count must be a positive integer\n`);
|
|
44
37
|
process.exit(1);
|
|
45
38
|
}
|
|
@@ -51,15 +44,15 @@ function parseArgs(argv: string[]): { opts: NamzyOptions; count: number } {
|
|
|
51
44
|
process.exit(1);
|
|
52
45
|
}
|
|
53
46
|
}
|
|
54
|
-
return {
|
|
47
|
+
return { count };
|
|
55
48
|
}
|
|
56
49
|
|
|
57
50
|
async function main(): Promise<void> {
|
|
58
|
-
const {
|
|
51
|
+
const { count } = parseArgs(process.argv);
|
|
59
52
|
const base = Date.now();
|
|
60
53
|
for (let i = 0; i < count; i++) {
|
|
61
|
-
const name = await generate({
|
|
62
|
-
process.stdout.write(name
|
|
54
|
+
const name = await generate({ seed: base + i * 1337 });
|
|
55
|
+
process.stdout.write(`${name}\n`);
|
|
63
56
|
}
|
|
64
57
|
}
|
|
65
58
|
|
package/src/index.ts
CHANGED
|
@@ -1,28 +1,18 @@
|
|
|
1
1
|
// this_file: src/index.ts
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { joinClean, mangle, mulberry32 } from "./mangle.js";
|
|
4
|
+
import { COMMON, GEO } from "./wordlist.js";
|
|
5
5
|
|
|
6
6
|
export interface NamzyOptions {
|
|
7
|
-
|
|
8
|
-
seed?: number;
|
|
7
|
+
seed?: number;
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
function capitalize(s: string): string {
|
|
12
|
-
|
|
11
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
function pick<T>(arr: T[], rng: () => number): T {
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async function fetchOnlineWords(): Promise<string[]> {
|
|
20
|
-
const url = `https://random-word-api.herokuapp.com/word?number=2&length=6`;
|
|
21
|
-
const resp = await fetch(url);
|
|
22
|
-
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
23
|
-
const data = (await resp.json()) as string[];
|
|
24
|
-
if (!Array.isArray(data) || data.length < 2) throw new Error("Bad response");
|
|
25
|
-
return data.slice(0, 2).map((w) => w.toLowerCase().replace(/[^a-z]/g, ""));
|
|
15
|
+
return arr[Math.floor(rng() * arr.length)];
|
|
26
16
|
}
|
|
27
17
|
|
|
28
18
|
/**
|
|
@@ -30,29 +20,16 @@ async function fetchOnlineWords(): Promise<string[]> {
|
|
|
30
20
|
* Two raw words → junction-cleaned fusion → consonant rotation → capitalize.
|
|
31
21
|
*/
|
|
32
22
|
export async function generate(opts?: NamzyOptions): Promise<string> {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const words = await fetchOnlineWords();
|
|
43
|
-
[w1, w2] = words;
|
|
44
|
-
} catch {
|
|
45
|
-
w1 = pick(GEO, rng).toLowerCase();
|
|
46
|
-
w2 = pick(COMMON, rng).toLowerCase();
|
|
47
|
-
}
|
|
48
|
-
} else {
|
|
49
|
-
w1 = pick(GEO, rng).toLowerCase();
|
|
50
|
-
w2 = pick(COMMON, rng).toLowerCase();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const fused = joinClean(w1, w2);
|
|
54
|
-
return capitalize(mangle(fused));
|
|
23
|
+
const seed = opts?.seed ?? Date.now();
|
|
24
|
+
const rng = mulberry32(seed);
|
|
25
|
+
|
|
26
|
+
const w1 = pick(GEO, rng).toLowerCase();
|
|
27
|
+
const w2 = pick(COMMON, rng).toLowerCase();
|
|
28
|
+
const [first, second] = rng() < 0.5 ? [w1, w2] : [w2, w1];
|
|
29
|
+
|
|
30
|
+
const fused = joinClean(first, second);
|
|
31
|
+
return capitalize(mangle(fused));
|
|
55
32
|
}
|
|
56
33
|
|
|
57
|
-
export {
|
|
58
|
-
export {
|
|
34
|
+
export { COMMON, GEO } from "./wordlist.js";
|
|
35
|
+
export { joinClean, mangle, mulberry32 };
|
package/src/wordlist.ts
CHANGED
|
@@ -1,19 +1,109 @@
|
|
|
1
1
|
// this_file: src/wordlist.ts
|
|
2
2
|
|
|
3
|
-
/** Geographic names (A-Za-z only, no diacritics) */
|
|
3
|
+
/** Geographic names (A-Za-z only, no diacritics). Shared across all implementations. */
|
|
4
4
|
export const GEO: string[] = [
|
|
5
|
-
"tokyo", "paris", "oslo", "berlin", "lagos", "lima",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
5
|
+
"tokyo", "paris", "oslo", "berlin", "lagos", "lima",
|
|
6
|
+
"boston", "vienna", "cairo", "kyoto", "dubai", "seoul",
|
|
7
|
+
"milan", "tunis", "perth", "genoa", "porto", "bruges",
|
|
8
|
+
"ghent", "brest", "minsk", "sofia", "riga", "lyon",
|
|
9
|
+
"basel", "natal", "recife", "darwin", "hobart", "odessa",
|
|
10
|
+
"varna", "split", "kotor", "tirana", "skopje", "bitola",
|
|
11
|
+
"plovdiv", "gabrovo", "ruse", "delhi", "rome", "athens",
|
|
12
|
+
"nairobi", "bali", "havana", "lisbon", "bogota", "dakar",
|
|
13
|
+
"quito", "vilnius", "vaduz", "bern", "accra", "kigali",
|
|
14
|
+
"abuja", "bamako", "niamey", "lome", "prague", "dublin",
|
|
15
|
+
"naples", "tulum", "tbilisi", "yerevan", "astana", "lusaka",
|
|
16
|
+
"harare", "asmara", "manaus", "cuenca", "merida", "geneva",
|
|
17
|
+
"zurich", "venice", "sydney", "denver", "austin", "phoenix",
|
|
18
|
+
"tucson", "reno", "boise", "fargo", "tulsa", "tampa",
|
|
19
|
+
"miami", "salem", "dover", "trenton", "helena", "juneau",
|
|
20
|
+
"topeka", "albany", "amsterdam", "antwerp", "arusha", "aspen",
|
|
21
|
+
"atlanta", "auckland", "baghdad", "baku", "bangkok", "barcelona",
|
|
22
|
+
"beijing", "beirut", "belfast", "belgrade", "bergen", "bilbao",
|
|
23
|
+
"bordeaux", "braga", "brisbane", "bristol", "brussels", "bucharest",
|
|
24
|
+
"budapest", "calgary", "canberra", "cardiff", "casablanca", "chicago",
|
|
25
|
+
"cologne", "colombo", "copenhagen", "cork", "dresden", "durban",
|
|
26
|
+
"edinburgh", "florence", "frankfurt", "gdansk", "glasgow", "granada",
|
|
27
|
+
"guangzhou", "hamburg", "hanoi", "helsinki", "houston", "jakarta",
|
|
28
|
+
"jerusalem", "karachi", "krakow", "kuwait", "leipzig", "lille",
|
|
29
|
+
"london", "luanda", "lucerne", "madrid", "malaga", "manila",
|
|
30
|
+
"marrakesh", "marseille", "melbourne", "memphis", "montreal", "moscow",
|
|
31
|
+
"munich", "nagoya", "nantes", "napier", "nashville", "orlando",
|
|
32
|
+
"osaka", "ottawa", "palermo", "panama", "phuket", "pisa",
|
|
33
|
+
"poznan", "quebec", "reykjavik", "rotterdam", "sarajevo", "sapporo",
|
|
34
|
+
"sevilla", "shanghai", "stockholm", "suzhou", "swansea", "taipei",
|
|
35
|
+
"tallinn", "tangier", "tehran", "thimphu", "toronto", "toulouse",
|
|
36
|
+
"trieste", "valencia", "vancouver", "verona", "warsaw", "winnipeg",
|
|
37
|
+
"wroclaw", "zagreb", "aarhus", "abidjan", "adelaide", "alger",
|
|
38
|
+
"annaba", "ankara", "antalya", "arezzo", "asuncion", "avignon",
|
|
39
|
+
"baltimore", "banjul", "belem", "bologna", "bremen", "cancun",
|
|
40
|
+
"caracas", "cartagena", "catania", "charlotte", "chennai", "chiangmai",
|
|
41
|
+
"cleveland", "cordoba", "curitiba", "cusco", "dallas", "damascus",
|
|
42
|
+
"dundee", "espoo", "fez", "freetown", "fukuoka", "funchal",
|
|
43
|
+
"gothenburg", "guayaquil", "haifa", "halifax", "hamilton", "honolulu",
|
|
44
|
+
"ibadan", "innsbruck", "izmir", "jaipur", "jeddah", "kampala",
|
|
45
|
+
"kansas", "kashgar", "kathmandu", "khartoum", "kingston", "kinshasa",
|
|
46
|
+
"koblenz", "kortrijk", "lahti", "lausanne", "leeds", "leuven",
|
|
47
|
+
"liege", "liverpool", "ljubljana", "lodz", "luxor", "macao",
|
|
48
|
+
"madison", "malmo", "manchester", "mandalay", "maputo", "mendoza",
|
|
49
|
+
"monterrey", "montevideo", "nicosia", "noumea", "nuremberg", "okinawa",
|
|
50
|
+
"omaha", "padua", "penang", "peshawar", "portland", "pretoria",
|
|
51
|
+
"rabat", "raleigh", "rennes", "richmond", "salzburg", "samarkand",
|
|
52
|
+
"santander", "santiago", "sendai", "singapore", "skagen", "stavanger",
|
|
53
|
+
"stuttgart", "surabaya", "suva", "tampere", "taranto", "tarragona",
|
|
54
|
+
"tiruchirappalli", "trondheim", "utrecht", "valletta", "victoria", "vigo",
|
|
10
55
|
];
|
|
11
56
|
|
|
12
|
-
/** Common evocative English words */
|
|
57
|
+
/** Common evocative English words. Shared across all implementations. */
|
|
13
58
|
export const COMMON: string[] = [
|
|
14
|
-
"river", "stone", "ember", "frost", "harbor", "willow",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
59
|
+
"river", "stone", "ember", "frost", "harbor", "willow",
|
|
60
|
+
"copper", "marble", "anchor", "lantern", "cedar", "falcon",
|
|
61
|
+
"coral", "dagger", "flint", "grove", "haven", "iron",
|
|
62
|
+
"jasper", "kelp", "larch", "mast", "nettle", "oak",
|
|
63
|
+
"pine", "quill", "reed", "sage", "thorn", "umber",
|
|
64
|
+
"vale", "wren", "yarrow", "zenith", "amber", "birch",
|
|
65
|
+
"cliff", "drift", "forge", "glade", "mesa", "canyon",
|
|
66
|
+
"basin", "fern", "gale", "peak", "ridge", "shore",
|
|
67
|
+
"tide", "bluff", "brook", "crest", "delta", "glen",
|
|
68
|
+
"helm", "inlet", "jetty", "knoll", "loft", "moor",
|
|
69
|
+
"notch", "orbit", "prism", "thunder", "silver", "meadow",
|
|
70
|
+
"basalt", "summit", "valley", "bridge", "beacon", "ranger",
|
|
71
|
+
"timber", "clover", "pebble", "ripple", "canopy", "chimney",
|
|
72
|
+
"cinder", "comet", "ferret", "glider", "jaguar", "kernel",
|
|
73
|
+
"lancer", "mortar", "nebula", "osprey", "patrol", "quartz",
|
|
74
|
+
"rafter", "sparrow", "granite", "hazel", "kindle", "laurel",
|
|
75
|
+
"mossy", "nimble", "ochre", "russet", "sable", "vapor",
|
|
76
|
+
"wicker", "cobalt", "dune", "hollow", "ivy", "juniper",
|
|
77
|
+
"linden", "mist", "oyster", "acorn", "anvil", "apron",
|
|
78
|
+
"arrow", "ash", "atlas", "autumn", "badge", "banner",
|
|
79
|
+
"beryl", "blossom", "boulder", "bramble", "brass", "breeze",
|
|
80
|
+
"briar", "bronze", "brooklet", "buckle", "burl", "cairn",
|
|
81
|
+
"candle", "canvas", "cavern", "chalk", "charm", "citrine",
|
|
82
|
+
"cloud", "cloverleaf", "cobaltcore", "compass", "copperleaf", "cradle",
|
|
83
|
+
"cricket", "crystal", "daisy", "dale", "dawn", "deerden",
|
|
84
|
+
"desert", "dew", "diamond", "dovetail", "dragonfly", "dream",
|
|
85
|
+
"drifter", "dunecrest", "dusk", "echo", "elm", "fernleaf",
|
|
86
|
+
"firefly", "fjord", "flame", "flower", "flume", "forest",
|
|
87
|
+
"foxglove", "garden", "garnet", "geode", "glacier", "glimmer",
|
|
88
|
+
"goldfinch", "gravel", "greenwood", "griffin", "harborlight", "hearth",
|
|
89
|
+
"heather", "heron", "hill", "honey", "horizon", "icicle",
|
|
90
|
+
"ivory", "jewel", "kestrel", "lagoon", "laurelwood", "leaf",
|
|
91
|
+
"lighthouse", "lilac", "lotus", "meadowlark", "moon", "moss",
|
|
92
|
+
"myrtle", "nectar", "nightingale", "obsidian", "olive", "opal",
|
|
93
|
+
"orchard", "otter", "pebblebrook", "petal", "plume", "prairie",
|
|
94
|
+
"rain", "raven", "redwood", "reef", "ribbon", "root",
|
|
95
|
+
"rose", "ruby", "sail", "salt", "sapphire", "scarlet",
|
|
96
|
+
"seabird", "sequoia", "shadow", "shale", "shell", "shimmer",
|
|
97
|
+
"skylark", "slate", "smoke", "snow", "sparrowhawk", "spindle",
|
|
98
|
+
"spirit", "spring", "spruce", "star", "starlight", "storm",
|
|
99
|
+
"stream", "sunbeam", "sunset", "sycamore", "talon", "thicket",
|
|
100
|
+
"thistle", "thunderhead", "tidepool", "topaz", "trail", "valleyfield",
|
|
101
|
+
"velvet", "violet", "walnut", "waterfall", "wave", "wind",
|
|
102
|
+
"winter", "wolfram", "woodland", "zephyr", "ashwood", "bell",
|
|
103
|
+
"bird", "bloom", "branch", "bright", "brookside", "camp",
|
|
104
|
+
"campfire", "castle", "chime", "clay", "cloudbank", "coast",
|
|
105
|
+
"copperwood", "creek", "crown", "emberfall", "field", "firestone",
|
|
106
|
+
"flag", "fog", "fox", "gardenia", "gate", "glow",
|
|
107
|
+
"grass", "grovewood", "harborstone", "hilltop", "honeycomb", "island",
|
|
108
|
+
"kestrelwing", "lake", "leafwing", "marigold", "moonstone", "morning",
|
|
19
109
|
];
|