|
1 | 1 | # indexed-string-variation |
2 | 2 |
|
3 | 3 | [](http://badge.fury.io/js/indexed-string-variation) |
4 | | -[](https://travis-ci.org/lmammino/indexed-string-variation) |
5 | | -[](https://codecov.io/gh/lmammino/indexed-string-variation) |
| 4 | +[](https://github.com/lmammino/indexed-string-variation/actions/workflows/ci.yml) |
| 5 | +[](https://codecov.io/gh/lmammino/indexed-string-variation) |
6 | 6 |
|
| 7 | +JavaScript module to generate all possible variations of strings over an |
| 8 | +alphabet using an n-ary virtual tree. |
7 | 9 |
|
8 | | -Experimental JavaScript module to generate all possible variations of strings over an alphabet using an n-ary virtual tree. |
| 10 | +## Requirements |
9 | 11 |
|
| 12 | +- Node.js >= 22 |
10 | 13 |
|
11 | 14 | ## Install |
12 | 15 |
|
13 | 16 | With NPM: |
14 | 17 |
|
15 | 18 | ```bash |
16 | | -npm install --save indexed-string-variation |
| 19 | +npm install indexed-string-variation |
17 | 20 | ``` |
18 | 21 |
|
19 | | - |
20 | 22 | ## Usage |
21 | 23 |
|
22 | | -Generally useful to create distributed brute-force password recovery tools or |
23 | | -other software that might require distributed generation of all possible |
24 | | -strings on a given alphabet. |
| 24 | +This library is ESM-only and written in TypeScript. You can import and use it as |
| 25 | +follows: |
25 | 26 |
|
26 | | -```javascript |
27 | | -const generator = require('indexed-string-variation').generator; |
28 | | -const variations = generator('abc1'); |
| 27 | +```js |
| 28 | +import isv from "indexed-string-variation"; |
29 | 29 |
|
30 | | -for (let i=0; i < 23; i++) { |
31 | | - console.log(i, variations(i)); // generates the i-th string in the alphabet 'abc1' |
| 30 | +// Basic usage: generate all variations for a given alphabet |
| 31 | +for ( |
| 32 | + const str of isv({ alphabet: "abc1", maxIterations: 23 }) |
| 33 | +) { |
| 34 | + console.log(str); |
32 | 35 | } |
33 | | -``` |
34 | | - |
35 | | -Will print: |
36 | | - |
37 | | -```bash |
38 | | -0 '' |
39 | | -1 'a' |
40 | | -2 'b' |
41 | | -3 'c' |
42 | | -4 '1' |
43 | | -5 'aa' |
44 | | -6 'ab' |
45 | | -7 'ac' |
46 | | -8 'a1' |
47 | | -9 'ba' |
48 | | -10 'bb' |
49 | | -11 'bc' |
50 | | -12 'b1' |
51 | | -13 'ca' |
52 | | -14 'cb' |
53 | | -15 'cc' |
54 | | -16 'c1' |
55 | | -17 '1a' |
56 | | -18 '1b' |
57 | | -19 '1c' |
58 | | -20 '11' |
59 | | -21 'aaa' |
60 | | -22 'aab' |
61 | | -``` |
62 | | - |
63 | 36 |
|
64 | | -## API |
| 37 | +// Generate variations from a specific index (using BigInt) |
| 38 | +for ( |
| 39 | + const str of isv({ |
| 40 | + alphabet: "abc1", |
| 41 | + from: 20n, |
| 42 | + maxIterations: 5, |
| 43 | + }) |
| 44 | +) { |
| 45 | + console.log(str); |
| 46 | +} |
65 | 47 |
|
66 | | -The module `indexed-string-variation` exposes the following components: |
67 | | - |
68 | | - * `generator` (also aliased as `default` for ES2015 modules): the |
69 | | - main generator function |
70 | | - * `defaultAlphabet`: a constant string that contains the sequence of |
71 | | - characters in the defaultAlphabet |
| 48 | +// Generate variations up to a maximum string length |
| 49 | +for (const str of isv({ alphabet: "abc1", maxLen: 2 })) { |
| 50 | + console.log(str); |
| 51 | +} |
72 | 52 |
|
73 | | -As you can see in the [usage example](#usage), the `generator` function takes as input the |
74 | | -alphabet string (which is optional and it will default to `defaultAlphabet` if |
75 | | -not provided) and returns a new function called `variations` which can be |
76 | | -used to retrieve the indexed variation on the given alphabet. `variations` takes |
77 | | -a non-negative integer as input which represents the index of the variations |
78 | | -that we want to generate: |
| 53 | +// endless variations (don't use a `for ... of` loop because it will never end!) |
| 54 | +const values = isv({ |
| 55 | + alphabet: "abc1", |
| 56 | +}); |
79 | 57 |
|
80 | | -```javascript |
81 | | -const variations = generator('XYZ'); |
82 | | -console.log(variations(7123456789)); // "XYYZYZZZYYYZYZYXYYYYX" |
| 58 | +console.log(values.next()); // { value: 'a', done: false } |
| 59 | +console.log(values.next()); // { value: 'b', done: false } |
| 60 | +//... |
83 | 61 | ``` |
84 | 62 |
|
| 63 | +## TypeScript |
85 | 64 |
|
86 | | -## How the algorithm works |
87 | | - |
88 | | -The way the generation algorithm work is using an n-ary tree where n is the size of the alphabet. |
89 | | -For example, if we have an alphabet containing only `a`, `b` and `c` and we want to generate all |
90 | | -the strings with a maximum length of 3 the algorithm will use the following tree: |
91 | | - |
92 | | - |
93 | | - |
94 | | -The tree is to be considered "virtual", because it's never generated in its integrity, so the |
95 | | -used space in memory is minimal. |
96 | | - |
97 | | -In brevity we can describe the algorithm as follows: |
| 65 | +Type definitions are included. You can use this library with full type safety in |
| 66 | +TypeScript projects. |
98 | 67 |
|
99 | | -> Given an index **i** over an alphabet of length **n** and it's corresponding n-ary tree, |
100 | | -the string associated to **i** corresponds to the string obtained by |
101 | | -concatenating all the characters found in the path that goes from the root node to the **i**-th node. |
| 68 | +## Testing |
102 | 69 |
|
103 | | -For example, with the alphabet in the image we can generate the following strings: |
| 70 | +This project uses [Vitest](https://vitest.dev/): |
104 | 71 |
|
105 | | -| i | generated string | |
106 | | -|---:|---| |
107 | | -|0|| |
108 | | -|1|a| |
109 | | -|2|b| |
110 | | -|3|c| |
111 | | -|4|aa| |
112 | | -|5|ab| |
113 | | -|6|ac| |
114 | | -|7|ba| |
115 | | -|8|bb| |
116 | | -|9|bc| |
117 | | -|10|ca| |
118 | | -|11|cb| |
119 | | -|12|cc| |
120 | | - |
121 | | - |
122 | | -Important note: The alphabet is always normalized (i.e. duplicates are removed) |
123 | | - |
124 | | - |
125 | | -## Use big-integer to avoid JavaScript big integers approximations |
126 | | - |
127 | | -Integers with more than 18 digits are approximated (e.g. `123456789012345680000 === 123456789012345678901`), so at some |
128 | | -point the generator will start to generate a lot of duplicated strings and it will start to miss many cases. |
129 | | - |
130 | | -To workaround this issue you can use indexes generated with the module [big-integer](https://www.npmjs.com/package/big-integer). |
131 | | -Internally the indexed-string-variation will take care of performing the correct |
132 | | -operations using the library. |
133 | | - |
134 | | -Let's see an example: |
135 | | - |
136 | | -```javascript |
137 | | -const bigInt = require('big-integer'); // install from https://npmjs.com/package/big-integer |
138 | | -const generator = require('indexed-string-variation').generator; |
139 | | -const variations = generator('JKWXYZ'); |
140 | | - |
141 | | -// generation using regular big numbers (same result) |
142 | | -console.log(variations(123456789012345678901)); // XJZJYXXXYYJKYZZJKZKYJWJJYW |
143 | | -console.log(variations(123456789012345680000)); // XJZJYXXXYYJKYZZJKZKYJWJJYW |
144 | | - |
145 | | -// generation using big-integer numbers (correct results) |
146 | | -console.log(variations(bigInt('123456789012345678901'))); // XJZJYXXXYYJKYZZJKZKXZKJZZJ |
147 | | -console.log(variations(bigInt('123456789012345680000'))); // XJZJYXXXYYJKYZZJKZKXZWJJWK |
| 72 | +```bash |
| 73 | +npm test |
148 | 74 | ``` |
149 | 75 |
|
150 | | -Anyway, keep in mind that big-integers might have a relevant performance impact, |
151 | | -so if you don't plan to use huge integers it's still recommended to use |
152 | | -plain JavaScript numbers as indexes. |
153 | | - |
| 76 | +## Development |
154 | 77 |
|
155 | | -## Contributing |
| 78 | +- Source code is in `src/` (TypeScript) |
| 79 | +- Build output is in `dist/` |
| 80 | +- Tests are in `src/test.ts` |
156 | 81 |
|
157 | | -Everyone is very welcome to contribute to this project. |
158 | | -You can contribute just by submitting bugs or suggesting improvements by |
159 | | -[opening an issue on GitHub](https://github.com/lmammino/indexed-string-variation/issues). |
| 82 | +## Migration notes |
160 | 83 |
|
| 84 | +- The library now uses native JavaScript `BigInt` instead of the `big-integer` |
| 85 | + dependency. |
| 86 | +- Only ESM is supported (no CommonJS `require`). |
| 87 | +- Node.js 22 or newer is required. |
161 | 88 |
|
162 | 89 | ## License |
163 | 90 |
|
|
0 commit comments