Skip to content

Commit 7063d21

Browse files
authored
Merge branch 'main' into main
2 parents fa10827 + 2bef184 commit 7063d21

12 files changed

+449
-108
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Fundamentally, the repository is a NodeJS project, so it contains the standard N
4343
* `/buildScripts/` — the folder containing the scripts used to build the bundled versions of the module and the module's documentation site, including its UML diagrams.
4444
* `/dist/` — the target folder into which the build scripts will publish the bundled versions of the module, ready for distribution. **Do not edit the contents of this folder directly!**
4545
* `/docs/` — the target folder into which the build scripts will publish the generated documentation. This folder's contents will be published at the project's website. **Do not edit the contents of this folder directly!**
46-
* `/docs-other/` — the folder containing the parts of the documentation that are not generated from documentation comments.
46+
* `/docs-other/` — the folder containing the parts of the documentation that are not generated from documentation comments. This folder also includes a **README** file that includes instructions on how to get started.
4747
* `/docs-other/diagrams/` — the target folder into which the build scripts will publish PNG versions of the project's UML diagrams. The source for these diagrams are the Mermaid files in `/src-diagrams/`. **Do not edit the contents of this folder directly!**
4848
* `/src/` — the folder containing the module's source code and test suite.
4949
* `/src-diagrams/` — the folder containing the source code for the UML diagrams describing the module. These files will be in Mermaid format and will be transformed into PNG files in `/docs-other/diagrams/` by a build script.
@@ -99,7 +99,7 @@ This module is versioned using the Semantic Versioning System, or [SemVer](https
9999
* Until the project reaches version 1.0.0 any contributions that make progress towards the initial implementation can be merged into the `main` branch
100100
* Once the project reaches version 1.0.0 all contributions must be *atomic*, i.e. must be a complete unit. For code contributions that means:
101101
1. All tests must pass
102-
2. News tests must be included to cover all new functionality
102+
2. New tests must be included to cover all new functionality
103103
3. The Doc Comments must be updated as appropriate
104104
4. The code must be in the project's style
105105

docs-other/README.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@ npm run cov # run the tests again but this time with test coverage. Coverage sho
1414

1515
## Hot build and reload
1616

17-
The easiest way to achieve this is opening 2 Terminal windows in the root directory of this project.
17+
The easiest way to achieve this is opening a Terminal window in the root directory of this project.
1818

19-
In one Terminal enter `npm run watch` to start the automatic build of Webpack. Webpack watches for changes in your files and automatically starts the build.
20-
In the other Terminal enter `npm run start` to start a local webserver that automatically restarts when there is a new build.
19+
In the Terminal enter `npm run start` to start a local webserver.
20+
This script will watch for any change in any file, and automatically start a
21+
a webpack build and restarts the server when there is a new build.
2122

2223
In your webbrowser enter `http://localhost:8080` to find the webapp.
24+
25+
## JS Docs
26+
27+
If you want to see the docs locally, run `npm run docs`.
28+
You will find them in /dist/docs and also through the webapp in the Actions menu.

src/index.html

+47-42
Large diffs are not rendered by default.

src/index.mjs

+11-1
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,15 @@ $(() => {
7878
(tooltipTriggerEl) => new Tooltip(tooltipTriggerEl));
7979

8080
XKP.init();
81-
});
8281

82+
// Now that the DOM is ready, find all the 'div' elements that
83+
// were identified to have the potential to flash unstyled content
84+
// as the page loads and make them visible.
85+
const foucElements = document.querySelectorAll('div[fouc=\'true\']');
86+
for (const fouc of foucElements) {
87+
if (fouc.style !== null) {
88+
// Make the element visible.
89+
fouc.style.visibility = 'visible';
90+
}
91+
}
92+
});

src/lib/dictionary.mjs

+30-1
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,20 @@
1111
*/
1212
class Dictionary {
1313
#wordListLength; // length of the word list, convenience variable
14+
#minWordLength; // shortest word length
15+
#maxWordLength; // longest word length
1416

1517
/**
1618
* Constructor for English Dictionary
1719
* @constructor
1820
*/
1921
constructor() {
20-
if (this.constructor == Dictionary) {
22+
if (this.constructor === Dictionary) {
2123
throw new Error('You cannot instantiate the abstract class');
2224
}
2325
this.#wordListLength = 0;
26+
this.#minWordLength = 0;
27+
this.#maxWordLength = 0;
2428
}
2529

2630

@@ -71,6 +75,31 @@ class Dictionary {
7175
__setLength(len) {
7276
this.#wordListLength = len;
7377
}
78+
79+
/**
80+
* set min and max word length
81+
*
82+
* @ private
83+
*/
84+
__setWordLength() {
85+
const list = this.wordList();
86+
let minlen = list[0].length;
87+
let maxlen = minlen;
88+
for (let i = 1 ; i < this.#wordListLength; i++) {
89+
minlen = Math.min(minlen, list[i].length);
90+
maxlen = Math.max(maxlen, list[i].length);
91+
}
92+
this.#minWordLength = minlen;
93+
this.#maxWordLength = maxlen;
94+
}
95+
96+
getMinWordLength() {
97+
return this.#minWordLength;
98+
}
99+
100+
getMaxWordLength() {
101+
return this.#maxWordLength;
102+
}
74103
}
75104

76105
export {Dictionary};

src/lib/dictionaryEN.mjs

+1
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,7 @@ class DictionaryEN extends Dictionary {
12851285
constructor() {
12861286
super();
12871287
super.__setLength(THE_WORDS.length);
1288+
super.__setWordLength();
12881289
}
12891290

12901291

src/lib/presets.mjs

+12-3
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,11 @@ class Presets {
245245
}
246246
}
247247
};
248+
249+
// fix the padding and separator alphabet
250+
this.#current.config.separator_alphabet = this.getSeparatorAlphabet();
251+
this.#current.config.padding_alphabet = this.getPaddingAlphabet();
252+
248253
log.trace(`Preset constructor set to ${this.#presetName}`);
249254
}
250255

@@ -309,10 +314,12 @@ class Presets {
309314
* @return {Array} the list of characters
310315
*/
311316
getSeparatorAlphabet() {
312-
const alphabet =
317+
let alphabet =
313318
(is.not.undefined(this.#current.config.separator_alphabet) ?
314319
this.#current.config.separator_alphabet :
315320
this.#current.config.symbol_alphabet);
321+
alphabet = ((is.undefined(alphabet) || (alphabet.length === 0)) ?
322+
thePresets.DEFAULT.config.symbol_alphabet : alphabet);
316323
return alphabet;
317324
}
318325

@@ -323,12 +330,14 @@ class Presets {
323330
* @return {Array} the list of characters
324331
*/
325332
getPaddingAlphabet() {
326-
const alphabet =
333+
let alphabet =
327334
(is.not.undefined(this.#current.config.padding_alphabet) ?
328335
this.#current.config.padding_alphabet :
329336
this.#current.config.symbol_alphabet);
337+
alphabet = ((is.undefined(alphabet) || (alphabet.length === 0)) ?
338+
thePresets.DEFAULT.config.symbol_alphabet : alphabet);
330339
return alphabet;
331340
}
332-
};
341+
}
333342

334343
export {Presets};

src/lib/randombasic.mjs

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class RandomBasic {
3030
/**
3131
* Generate a number of random digits
3232
*
33-
* @param {Integer} num - number of random digits to generate,
33+
* @param {number} num - number of random digits to generate,
3434
* defaults to empty string if not given
3535
* @return {Array} - array of random digits
3636
* @throws Exception when parameter is not a number
@@ -41,8 +41,8 @@ class RandomBasic {
4141
if (is.null(num) || is.undefined(num) || num <= 0) {
4242
return '';
4343
}
44-
if (is.not.integer(num)) {
45-
const errMsg = 'Parameter "num" is not an integer! [' + num + ']';
44+
if (is.not.number(num)) {
45+
const errMsg = 'Parameter "num" is not a number! [' + num + ']';
4646
// log.error('ERROR', errMsg);
4747
throw new Error(errMsg);
4848
}

src/lib/xkpasswd.mjs

+52-25
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,20 @@ class XKPasswd {
6262
getPreset() {
6363
return this.#preset;
6464
}
65+
6566
/**
6667
* Get all available presets
6768
*
6869
* @return {array} keys - names of the Presets
6970
*/
7071
getPresets() {
71-
const keys = new Presets().getPresets();
72-
return keys;
72+
return new Presets().getPresets();
7373
}
7474

7575
/**
7676
* Generate the password(s) and stats
7777
*
78-
* @param {integer} num - number of passwords to generate
78+
* @param {number} num - number of passwords to generate
7979
* @return {object} - contains the passwords and the stats
8080
*/
8181
generatePassword(num) {
@@ -104,11 +104,11 @@ class XKPasswd {
104104
// start by generating the needed parts of the password
105105
//
106106
log.trace('starting to generate random words');
107-
const words = this.__randomWords();
107+
let words = this.__randomWords();
108108
log.trace(`got random words = ${words}`);
109109

110-
this.__transformCase(words);
111-
this.__substituteCharacters(words);
110+
words = this.__transformCase(words);
111+
words = this.__substituteCharacters(words);
112112
const separator = this.__separator();
113113
log.trace(`got separator = ${separator}`);
114114

@@ -161,16 +161,17 @@ class XKPasswd {
161161

162162
/**
163163
* Generate the requested number of passwords
164-
* @param {integer} num - the number of passwords requested
164+
* @param {number} num - the number of passwords requested
165165
* @return {array} - the array with num passwords
166166
*/
167167
passwords(num) {
168168
if (is.undefined(num) || is.not.number(num) || num < 1) {
169169
num = 1;
170170
}
171-
172-
const passwords =
173-
new Array(num).fill('').map( () => this.password() );
171+
const passwords = [];
172+
for (let i = 0; i < num ; i++) {
173+
passwords.push(this.password());
174+
}
174175

175176
return passwords;
176177
}
@@ -180,16 +181,17 @@ class XKPasswd {
180181
* Pad the password with padChar until the given length
181182
*
182183
* @param {string} passwd - password to be padded
183-
* @param {character} padChar - padding character
184-
* @param {integer} maxLen - max length of password
184+
* @param {string} padChar - padding character
185+
* @param {number} maxLen - max length of password
185186
* @return {string} - padded password
186187
*
187188
* @private
188189
*/
189190
__adaptivePadding(passwd, padChar, maxLen) {
190191
const pwlen = passwd.length;
192+
padChar = (padChar.length === 0) ? ' ' : padChar;
191193
if (pwlen < maxLen) {
192-
// if the password is shorter than the target length, padd it out
194+
// if the password is shorter than the target length, pad it out
193195
while (passwd.length < maxLen) {
194196
passwd += padChar;
195197
}
@@ -219,6 +221,7 @@ class XKPasswd {
219221
}
220222

221223
const transformation = this.#config.case_transform;
224+
log.trace(`__transformCase: ${transformation} on ${words}`);
222225

223226
switch (transformation) {
224227
case 'NONE':
@@ -242,7 +245,7 @@ class XKPasswd {
242245

243246
case 'ALTERNATE':
244247
return words.map((el, index) =>
245-
el = (index % 2 == 0) ? el.toLowerCase() : el.toUpperCase(),
248+
el = ((index % 2) === 0) ? el.toLowerCase() : el.toUpperCase(),
246249
);
247250

248251
case 'RANDOM':
@@ -277,14 +280,32 @@ class XKPasswd {
277280
* @private
278281
*/
279282
__randomWords() {
283+
280284
const numWords = this.#config.num_words;
281285
const maxDict = this.#dictionary.getLength();
282286

283-
log.trace(`about to generate ${numWords} words`);
287+
log.trace(`__randomwords, mindict: ${this.#dictionary.getMinWordLength()}
288+
maxdict: ${this.#dictionary.getMaxWordLength()}`);
289+
// get the minimum of the 2 input variables and the longest dictionary word
290+
let minLength = Math.min(this.#config.word_length_min, this.#config.word_length_max, this.#dictionary.getMaxWordLength());
291+
292+
// get the maximum of the 2 input variables and the shortest dictionary word
293+
let maxLength = Math.max(this.#config.word_length_min, this.#config.word_length_max, this.#dictionary.getMinWordLength());
294+
295+
minLength = Math.max(minLength, this.#dictionary.getMinWordLength());
296+
maxLength = Math.min(maxLength, this.#dictionary.getMaxWordLength());
297+
298+
log.trace(`about to generate ${numWords} words ${minLength} - ${maxLength}`);
284299

285-
const list = new Array(numWords).fill('').map(
286-
() => this.#dictionary.word(this.#rng.randomInt(maxDict)),
287-
);
300+
const list = [];
301+
for (let i = 0; i < numWords; i++) {
302+
let word = '';
303+
do {
304+
word = this.#dictionary.word(this.#rng.randomInt(maxDict));
305+
}
306+
while (word.length < minLength || word.length > maxLength );
307+
list.push(word);
308+
};
288309
return list;
289310
}
290311

@@ -294,22 +315,25 @@ class XKPasswd {
294315
* Notes: The character returned is controlled by the config variable
295316
* `separator_character`
296317
*
297-
* @return {character} separator (could be an empty string)
318+
* @return {string} separator (could be an empty string)
298319
*
299320
* @private
300321
*/
301322
__separator() {
302323
// figure out the separator character
303324
const sep = this.#config.separator_character;
304325

305-
if (sep == 'NONE') {
326+
if (sep === 'NONE') {
306327
return '';
307328
}
308-
if (sep == 'RANDOM') {
329+
if (sep === 'RANDOM') {
309330
const alphabet = this.#preset.getSeparatorAlphabet();
310331
return this.#rng.randomChar(alphabet);
311332
}
312-
return '';
333+
if (sep.length > 1) {
334+
return '';
335+
}
336+
return sep;
313337
}
314338

315339
/**
@@ -319,9 +343,9 @@ class XKPasswd {
319343
* The character returned is determined by a combination of the
320344
* padding_type & padding_character config variables.
321345
*
322-
* @param {character} separator -
346+
* @param {string} separator -
323347
* the separator character being used to generate the password
324-
* @return {character} the padding character, could be an empty string
348+
* @return {string} the padding character, could be an empty string
325349
*
326350
* @private
327351
*/
@@ -339,7 +363,10 @@ class XKPasswd {
339363
const alphabet = this.#preset.getPaddingAlphabet();
340364
return this.#rng.randomChar(alphabet);
341365
default:
342-
return '';
366+
if (this.#config.padding_character.length > 1) {
367+
return '';
368+
}
369+
return this.#config.padding_character;
343370
}
344371
}
345372

0 commit comments

Comments
 (0)