@twardoch/namzy 1.0.19 → 1.0.21
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/dist/cli.js +19 -16
- package/dist/index.d.ts +7 -8
- package/dist/index.js +15 -21
- package/dist/mangle.d.ts +5 -14
- package/dist/mangle.js +30 -70
- package/dist/web.d.ts +1 -1
- package/dist/web.js +1 -1
- package/dist/wordlist.d.ts +2 -2
- package/dist/wordlist.js +200 -172
- package/package.json +1 -1
- package/src/cli.ts +20 -18
- package/src/index.ts +17 -25
- package/src/mangle.ts +30 -71
- package/src/web.ts +1 -1
- package/src/wordlist.ts +201 -172
package/dist/cli.js
CHANGED
|
@@ -2,22 +2,20 @@
|
|
|
2
2
|
// this_file: src/cli.ts
|
|
3
3
|
import { generate } from "./index.js";
|
|
4
4
|
const HELP = `
|
|
5
|
-
namzy — generate
|
|
5
|
+
namzy — generate compact, memorable, unique names
|
|
6
6
|
|
|
7
7
|
Usage:
|
|
8
8
|
namzy [options]
|
|
9
9
|
|
|
10
10
|
Options:
|
|
11
11
|
--count <N> Number of names to generate (default: 1)
|
|
12
|
+
--seed <N> Integer seed (default: current timestamp)
|
|
12
13
|
--help Show this help
|
|
13
|
-
|
|
14
|
-
Examples:
|
|
15
|
-
namzy
|
|
16
|
-
namzy --count 5
|
|
17
14
|
`.trimStart();
|
|
18
15
|
function parseArgs(argv) {
|
|
19
16
|
const args = argv.slice(2);
|
|
20
17
|
let count = 1;
|
|
18
|
+
let seed;
|
|
21
19
|
for (let i = 0; i < args.length; i++) {
|
|
22
20
|
const arg = args[i];
|
|
23
21
|
switch (arg) {
|
|
@@ -29,28 +27,33 @@ function parseArgs(argv) {
|
|
|
29
27
|
case "--count": {
|
|
30
28
|
const n = parseInt(args[++i], 10);
|
|
31
29
|
if (Number.isNaN(n) || n < 1) {
|
|
32
|
-
process.stderr.write(
|
|
30
|
+
process.stderr.write("--count must be a positive integer\n");
|
|
33
31
|
process.exit(1);
|
|
34
32
|
}
|
|
35
33
|
count = n;
|
|
36
34
|
break;
|
|
37
35
|
}
|
|
36
|
+
case "--seed": {
|
|
37
|
+
const n = parseInt(args[++i], 10);
|
|
38
|
+
if (Number.isNaN(n)) {
|
|
39
|
+
process.stderr.write("--seed must be an integer\n");
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
seed = n;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
38
45
|
default:
|
|
39
46
|
process.stderr.write(`Unknown flag: ${arg}\nRun namzy --help for usage.\n`);
|
|
40
47
|
process.exit(1);
|
|
41
48
|
}
|
|
42
49
|
}
|
|
43
|
-
return { count };
|
|
50
|
+
return { count, seed };
|
|
44
51
|
}
|
|
45
|
-
|
|
46
|
-
const { count } = parseArgs(process.argv);
|
|
47
|
-
const base = Date.now();
|
|
52
|
+
function main() {
|
|
53
|
+
const { count, seed } = parseArgs(process.argv);
|
|
54
|
+
const base = seed ?? Date.now();
|
|
48
55
|
for (let i = 0; i < count; i++) {
|
|
49
|
-
|
|
50
|
-
process.stdout.write(`${name}\n`);
|
|
56
|
+
process.stdout.write(`${generate({ seed: base + i * 2654435761 })}\n`);
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
|
-
main()
|
|
54
|
-
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
55
|
-
process.exit(1);
|
|
56
|
-
});
|
|
59
|
+
main();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { applyRotations, buildName, mulberry32 } from "./mangle.js";
|
|
2
2
|
export interface NamzyOptions {
|
|
3
3
|
seed?: number;
|
|
4
4
|
}
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export
|
|
10
|
-
export {
|
|
11
|
-
export { activeRotationMask, joinClean, mangle, mulberry32 };
|
|
5
|
+
/** Generate one namzy name. Default seed is the current timestamp. */
|
|
6
|
+
export declare function generate(opts?: NamzyOptions): string;
|
|
7
|
+
/** Generate `count` names. Distinct seeds derived from the base seed. */
|
|
8
|
+
export declare function generateMany(count: number, opts?: NamzyOptions): string[];
|
|
9
|
+
export { STEMS, ROTATIONS } from "./wordlist.js";
|
|
10
|
+
export { applyRotations, buildName, mulberry32 };
|
package/dist/index.js
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
// this_file: src/index.ts
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
function
|
|
5
|
-
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
6
|
-
}
|
|
7
|
-
function pick(arr, rng) {
|
|
8
|
-
return arr[Math.floor(rng() * arr.length)];
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Generate a single fused, mangled namzy name.
|
|
12
|
-
* Two raw words → junction-cleaned fusion → consonant rotation → capitalize.
|
|
13
|
-
*/
|
|
14
|
-
export async function generate(opts) {
|
|
2
|
+
import { applyRotations, buildName, mulberry32 } from "./mangle.js";
|
|
3
|
+
/** Generate one namzy name. Default seed is the current timestamp. */
|
|
4
|
+
export function generate(opts) {
|
|
15
5
|
const seed = opts?.seed ?? Date.now();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
6
|
+
return buildName(mulberry32(seed));
|
|
7
|
+
}
|
|
8
|
+
/** Generate `count` names. Distinct seeds derived from the base seed. */
|
|
9
|
+
export function generateMany(count, opts) {
|
|
10
|
+
const base = opts?.seed ?? Date.now();
|
|
11
|
+
const out = [];
|
|
12
|
+
for (let i = 0; i < count; i++) {
|
|
13
|
+
out.push(generate({ seed: base + i * 2654435761 }));
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
22
16
|
}
|
|
23
|
-
export {
|
|
24
|
-
export {
|
|
17
|
+
export { STEMS, ROTATIONS } from "./wordlist.js";
|
|
18
|
+
export { applyRotations, buildName, mulberry32 };
|
package/dist/mangle.d.ts
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Seeded mulberry32 RNG — yields [0,1) floats. */
|
|
2
2
|
export declare function mulberry32(seed: number): () => number;
|
|
3
|
-
|
|
4
|
-
export declare
|
|
5
|
-
/**
|
|
6
|
-
export declare function
|
|
7
|
-
/** Consonant rotation. Case-preserving. Defaults to all rules for direct helper use. */
|
|
8
|
-
export declare function mangle(s: string, activeMask?: number): string;
|
|
9
|
-
/**
|
|
10
|
-
* Fuse two lowercase words at a clean junction.
|
|
11
|
-
* Drops the first char of `b` while it duplicates the tail of `a`,
|
|
12
|
-
* or while the seam is vowel-vowel. Max two trims.
|
|
13
|
-
*/
|
|
14
|
-
export declare function joinClean(a: string, b: string): string;
|
|
15
|
-
export {};
|
|
3
|
+
/** Apply 1 or 2 rotations on randomly selected positions of the compound. */
|
|
4
|
+
export declare function applyRotations(compound: string, rng: () => number): string;
|
|
5
|
+
/** Build one name: any two stems, concatenated, lightly rotated, capitalized. */
|
|
6
|
+
export declare function buildName(rng: () => number): string;
|
package/dist/mangle.js
CHANGED
|
@@ -1,85 +1,45 @@
|
|
|
1
1
|
// this_file: src/mangle.ts
|
|
2
|
-
|
|
2
|
+
import { ROTATIONS, STEMS } from "./wordlist.js";
|
|
3
|
+
/** Seeded mulberry32 RNG — yields [0,1) floats. */
|
|
3
4
|
export function mulberry32(seed) {
|
|
4
5
|
let s = seed >>> 0;
|
|
5
6
|
return () => {
|
|
6
|
-
s
|
|
7
|
+
s = (s + 0x6d2b79f5) >>> 0;
|
|
7
8
|
let t = Math.imul(s ^ (s >>> 15), 1 | s);
|
|
8
9
|
t ^= t + Math.imul(t ^ (t >>> 7), 61 | t);
|
|
9
10
|
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
10
11
|
};
|
|
11
12
|
}
|
|
12
|
-
|
|
13
|
-
[
|
|
14
|
-
["f", "v"],
|
|
15
|
-
["k", "c"],
|
|
16
|
-
["q", "k"],
|
|
17
|
-
["s", "z"],
|
|
18
|
-
["z", "s"],
|
|
19
|
-
["v", "f"],
|
|
20
|
-
["w", "u"],
|
|
21
|
-
["b", "p"],
|
|
22
|
-
["p", "b"],
|
|
23
|
-
];
|
|
24
|
-
const ALL_ROTATIONS = (1 << ROTATION_RULES.length) - 1;
|
|
25
|
-
function rotationFor(lower, activeMask) {
|
|
26
|
-
for (let i = 0; i < ROTATION_RULES.length; i++) {
|
|
27
|
-
if ((activeMask & (1 << i)) === 0) {
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
const [from, to] = ROTATION_RULES[i];
|
|
31
|
-
if (lower === from) {
|
|
32
|
-
return to;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return undefined;
|
|
13
|
+
function pick(arr, rng) {
|
|
14
|
+
return arr[Math.floor(rng() * arr.length)];
|
|
36
15
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return
|
|
16
|
+
const ROT_MAP = new Map(ROTATIONS);
|
|
17
|
+
function rotateAt(s, pos) {
|
|
18
|
+
const ch = s[pos];
|
|
19
|
+
const lower = ch.toLowerCase();
|
|
20
|
+
const repl = ROT_MAP.get(lower);
|
|
21
|
+
if (repl === undefined)
|
|
22
|
+
return s;
|
|
23
|
+
const out = ch === lower ? repl : repl.toUpperCase();
|
|
24
|
+
return s.slice(0, pos) + out + s.slice(pos + 1);
|
|
46
25
|
}
|
|
47
|
-
/**
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
out += ch === lower ? repl : repl.toUpperCase();
|
|
58
|
-
}
|
|
26
|
+
/** Apply 1 or 2 rotations on randomly selected positions of the compound. */
|
|
27
|
+
export function applyRotations(compound, rng) {
|
|
28
|
+
if (compound.length === 0)
|
|
29
|
+
return compound;
|
|
30
|
+
const passes = rng() < 0.5 ? 1 : 2;
|
|
31
|
+
let out = compound;
|
|
32
|
+
for (let i = 0; i < passes; i++) {
|
|
33
|
+
out = rotateAt(out, Math.floor(rng() * out.length));
|
|
59
34
|
}
|
|
60
35
|
return out;
|
|
61
36
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
let tail = b;
|
|
71
|
-
for (let i = 0; i < 2 && head.length > 0 && tail.length > 0; i++) {
|
|
72
|
-
const last = head[head.length - 1].toLowerCase();
|
|
73
|
-
const first = tail[0].toLowerCase();
|
|
74
|
-
if (last === first) {
|
|
75
|
-
tail = tail.slice(1);
|
|
76
|
-
}
|
|
77
|
-
else if (VOWELS.has(last) && VOWELS.has(first)) {
|
|
78
|
-
tail = tail.slice(1);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return head + tail;
|
|
37
|
+
function capitalize(s) {
|
|
38
|
+
return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
|
|
39
|
+
}
|
|
40
|
+
/** Build one name: any two stems, concatenated, lightly rotated, capitalized. */
|
|
41
|
+
export function buildName(rng) {
|
|
42
|
+
const a = pick(STEMS, rng);
|
|
43
|
+
const b = pick(STEMS, rng);
|
|
44
|
+
return capitalize(applyRotations(a + b, rng));
|
|
85
45
|
}
|
package/dist/web.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { generate,
|
|
1
|
+
export { generate, generateMany, applyRotations, buildName, mulberry32, STEMS, ROTATIONS } from "./index.js";
|
|
2
2
|
export type { NamzyOptions } from "./index.js";
|
package/dist/web.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// this_file: src/web.ts
|
|
2
2
|
// Browser entry point — exposes namzy.generate() on window.namzy.
|
|
3
|
-
export { generate,
|
|
3
|
+
export { generate, generateMany, applyRotations, buildName, mulberry32, STEMS, ROTATIONS } from "./index.js";
|
package/dist/wordlist.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
export declare const
|
|
1
|
+
export declare const STEMS: readonly string[];
|
|
2
|
+
export declare const ROTATIONS: readonly (readonly [string, string])[];
|