Closed peerreynders closed 3 months ago
It seems that some how https://github.com/exercism/typescript-test-runner/blob/main/package.json#L32-L33 aren't correctly moved/injected into the solution.
You should be able to use anything from @types/node
, so this is a bug.
@types/node
is only a type package, so this bug, if any, is in the test-runner. Moving this issue there.
Hello. Thanks for opening an issue on Exercism 🙂
At Exercism we use our Community Forum, not GitHub issues, as the primary place for discussion. That allows maintainers and contributors from across Exercism's ecosystem to discuss your problems/ideas/suggestions without them having to subscribe to hundreds of repositories.
This issue will be automatically closed. Please use this link;%0D%0A%20%20return%20mask;%0D%0A%7D)();%0D%0A%0D%0Aconst%20SCORE_MIN%20=%203;%0D%0Aconst%20SCORE_MAX%20=%20toScore(SCORE_MASK);%0D%0A%0D%0Afunction%20errorScoreIndex(index:%20number):%20Error%20%7B%0D%0A%20%20return%20new%20Error(%60'$%7Bindex%7D'%20is%20not%20a%20valid%20score%20index%60);%0D%0A%7D%0D%0A%0D%0Afunction%20toScore(value:%20number):%20number%20%7B%0D%0A%20%20return%20(SCORE_MASK%20&%20value)%20+%20SCORE_MIN;%0D%0A%7D%0D%0A%0D%0Afunction%20getScore(rollValues:%20AbilitiesRoll,%20index:%20number):%20number%20%7B%0D%0A%20%20if%20(index%20%3C%200%20%7C%7C%20SCORE_MAX_INDEX%20%3C%20index)%20throw%20errorScoreIndex(index);%0D%0A%0D%0A%20%20return%20toScore(rollValues%20%3E%3E%3E%20(index%20%20SCORE_BITS));%0D%0A%7D%0D%0A%0D%0Afunction%20rollToScores(rollValues:%20AbilitiesRoll):%20number%5B%5D%20%7B%0D%0A%20%20const%20scores:%20number%5B%5D%20=%20%5B%5D;%0D%0A%20%20for%20(%0D%0A%20%20%20%20let%20i%20=%200,%20values%20=%20rollValues%20as%20number;%0D%0A%20%20%20%20i%20%3C%20SCORE_COUNT;%0D%0A%20%20%20%20i%20+=%201,%20values%20%3E%3E%3E=%20SCORE_BITS%0D%0A%20%20)%0D%0A%20%20%20%20scores%5Bi%5D%20=%20toScore(values);%0D%0A%0D%0A%20%20return%20scores;%0D%0A%7D%0D%0A%0D%0Aconst%20targetBuffer%20=%20new%20Uint32Array(1);%0D%0A%0D%0Afunction%20roll():%20AbilitiesRoll%20%7B%0D%0A%20%20crypto.randomFillSync(targetBuffer);%0D%0A%20%20return%20targetBuffer%5B0%5D%20as%20AbilitiesRoll;%0D%0A%7D%0D%0A%0D%0Afunction%20toModifier(value:%20number):%20number%20%7B%0D%0A%20%20return%20(value%20-%2010)%20%3E%3E%201;%0D%0A%7D%0D%0A%0D%0Aexport%20%7B%0D%0A%20%20roll,%0D%0A%20%20rollToScores,%0D%0A%20%20SCORE_MIN,%0D%0A%20%20SCORE_MAX,%0D%0A%20%20toModifier,%0D%0A%20%20getScore,%0D%0A%20%20SCORE_MAX_INDEX,%0D%0A%7D;%0D%0A%60%60%60%0D%0A%0D%0A%3C/p%3E%0D%0A%3C/details%3E%0D%0A%0D%0A%3Cdetails%3E%3Csummary%3Ednd-character.ts%3C/summary%3E%0D%0A%3Cp%3E%0D%0A%0D%0A%60%60%60typescript%0D%0Aimport%20%20as%20AbilityScores%20from%20'./dnd-ability-scores';%0D%0Aconst%20%7B%20roll,%20rollToScores,%20toModifier%20%7D%20=%20AbilityScores;%0D%0A%0D%0Aconst%20HITPOINTS_INITIAL%20=%2010;%0D%0A%0D%0Aconst%20ABILITIES_ORDERED%20=%20%5B%0D%0A%20%20'strength',%0D%0A%20%20'dexterity',%0D%0A%20%20'constitution',%0D%0A%20%20'intelligence',%0D%0A%20%20'wisdom',%0D%0A%20%20'charisma',%0D%0A%5D%20as%20const;%0D%0A%0D%0Atype%20AbilityKey%20=%20typeof%20ABILITIES_ORDERED%5Bnumber%5D;%0D%0Atype%20Abilities%20=%20Record%3CAbilityKey,%20number%3E;%0D%0Atype%20AbilityTarget%20=%20Partial%3CAbilities%3E;%0D%0A%0D%0Afunction%20rollAbilities():%20Abilities%20%7B%0D%0A%20%20const%20scores%20=%20rollToScores(roll());%0D%0A%20%20return%20ABILITIES_ORDERED.reduce%3CAbilityTarget%3E((target,%20key,%20i)%20=%3E%20%7B%0D%0A%20%20%20%20target%5Bkey%5D%20=%20scores%5Bi%5D;%0D%0A%20%20%20%20return%20target;%0D%0A%20%20%7D,%20%7B%7D)%20as%20Abilities;%0D%0A%7D%0D%0A%0D%0Aclass%20DnDCharacter%20%7B%0D%0A%20%20#abilities:%20Abilities;%0D%0A%20%20#hitpoints:%20number;%0D%0A%0D%0A%20%20constructor()%20%7B%0D%0A%20%20%20%20const%20abilities%20=%20rollAbilities();%0D%0A%20%20%20%20this.#hitpoints%20=%20HITPOINTS_INITIAL%20+%20toModifier(abilities.constitution);%0D%0A%20%20%20%20this.#abilities%20=%20abilities;%0D%0A%20%20%7D%0D%0A%0D%0A%20%20get%20strength():%20number%20%7B%0D%0A%20%20%20%20return%20this.#abilities.strength;%0D%0A%20%20%7D%0D%0A%0D%0A%20%20get%20dexterity():%20number%20%7B%0D%0A%20%20%20%20return%20this.#abilities.dexterity;%0D%0A%20%20%7D%0D%0A%0D%0A%20%20get%20constitution():%20number%20%7B%0D%0A%20%20%20%20return%20this.#abilities.constitution;%0D%0A%20%20%7D%0D%0A%0D%0A%20%20get%20intelligence():%20number%20%7B%0D%0A%20%20%20%20return%20this.#abilities.intelligence;%0D%0A%20%20%7D%0D%0A%0D%0A%20%20get%20wisdom():%20number%20%7B%0D%0A%20%20%20%20return%20this.#abilities.wisdom;%0D%0A%20%20%7D%0D%0A%0D%0A%20%20get%20charisma():%20number%20%7B%0D%0A%20%20%20%20return%20this.#abilities.charisma;%0D%0A%20%20%7D%0D%0A%0D%0A%20%20get%20hitpoints():%20number%20%7B%0D%0A%20%20%20%20return%20this.#hitpoints;%0D%0A%20%20%7D%0D%0A%0D%0A%20%20static%20generateAbilityScore():%20number%20%7B%0D%0A%20%20%20%20return%20AbilityScores.getScore(roll(),%20AbilityScores.SCORE_MAX_INDEX);%0D%0A%20%20%7D%0D%0A%0D%0A%20%20static%20getModifierFor(abilityValue:%20number):%20number%20%7B%0D%0A%20%20%20%20return%20toModifier(abilityValue);%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0Aexport%20%7B%20DnDCharacter%20%7D;%0D%0A%60%60%60%0D%0A%0D%0A%3C/p%3E%0D%0A%3C/details%3E%0D%0A%0D%0AClearly%20the%20%60package.json%60%20downloaded%20with%20the%20CLI%20installs%20%60@types/node%60%20which%20is%20why%20no%20such%20error%20occurs%20locally.%0D%0A%0D%0A%60%60%60%0D%0A%20%20%20%20%22@types/node%22:%20%22%5E14.17.14%22,%0D%0A%60%60%60%0D%0A%0D%0A%3E%20Why%20the%20h@ll%20are%20you%20using%20%60crypto.randomDFillSync()%60%20in%20an%20easy%20exercise.%0D%0A%0D%0AI've%20stopped%20using%20%60Math.random()%60%20ever%20since%20I%20ran%20%5Binto%20this%5D(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random#content):%0D%0A%0D%0A%3E%20**Note:**%20%60Math.random()%60%20does%20not%20provide%20cryptographically%20secure%20random%20numbers.%20Do%20not%20use%20them%20for%20anything%20related%20to%20security.%20Use%20the%20Web%20Crypto%20API%20instead,%20and%20more%20precisely%20the%20%60window.crypto.getRandomValues()%60%20method.%0D%0A%0D%0Athat%20remark%20may%20as%20well%20be%20a%20deprecation%20notice%20-%20i.e.%20one%20needs%20to%20also%20know%20how%20to%20use%20%60crypto.getRandomValues()%60%20or%20%60crypto.randomFillSync()%60.%0D%0A%0D%0A---%0D%0A%0D%0AUpdate:%20Using%20%60crypto%60%20worked%20fine%209%20days%20ago%20with%20the%20%5BSimple%20Cipher%20exercise%5D(https://exercism.org/tracks/typescript/exercises/simple-cipher/solutions/peerreynders)&category=typescript ) to copy your GitHub Issue into a new topic on the forum, where we look forward to chatting with you!
If you're interested in learning more about this auto-responder, please read this blog post.
Caveat: I'm not sure whether I'm observing intended behaviour or not. It could be a "It Works On My Machine" kind of problem - perhaps it is not.
The symptoms suggest that platform side
@types/node
isn't installed when the tests are run (perhaps that is intentional).The error message is as follows:
Example solution affected.
dnd-abilities-scores.ts
```typescript import crypto from 'crypto'; declare const abilitiesRollBrand: unique symbol; type AbilitiesRoll = number & { [abilitiesRollBrand]: true; }; const SCORE_COUNT = 6; const SCORE_MAX_INDEX = SCORE_COUNT - 1; const SCORE_BITS = 4; const SCORE_MASK = ((): number => { let mask = 1; for (let i = 1; i < SCORE_BITS; i += 1, mask = (mask << 1) | 1); return mask; })(); const SCORE_MIN = 3; const SCORE_MAX = toScore(SCORE_MASK); function errorScoreIndex(index: number): Error { return new Error(`'${index}' is not a valid score index`); } function toScore(value: number): number { return (SCORE_MASK & value) + SCORE_MIN; } function getScore(rollValues: AbilitiesRoll, index: number): number { if (index < 0 || SCORE_MAX_INDEX < index) throw errorScoreIndex(index); return toScore(rollValues >>> (index * SCORE_BITS)); } function rollToScores(rollValues: AbilitiesRoll): number[] { const scores: number[] = []; for ( let i = 0, values = rollValues as number; i < SCORE_COUNT; i += 1, values >>>= SCORE_BITS ) scores[i] = toScore(values); return scores; } const targetBuffer = new Uint32Array(1); function roll(): AbilitiesRoll { crypto.randomFillSync(targetBuffer); return targetBuffer[0] as AbilitiesRoll; } function toModifier(value: number): number { return (value - 10) >> 1; } export { roll, rollToScores, SCORE_MIN, SCORE_MAX, toModifier, getScore, SCORE_MAX_INDEX, }; ```
dnd-character.ts
```typescript import * as AbilityScores from './dnd-ability-scores'; const { roll, rollToScores, toModifier } = AbilityScores; const HITPOINTS_INITIAL = 10; const ABILITIES_ORDERED = [ 'strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma', ] as const; type AbilityKey = typeof ABILITIES_ORDERED[number]; type Abilities = Record;
type AbilityTarget = Partial;
function rollAbilities(): Abilities {
const scores = rollToScores(roll());
return ABILITIES_ORDERED.reduce((target, key, i) => {
target[key] = scores[i];
return target;
}, {}) as Abilities;
}
class DnDCharacter {
#abilities: Abilities;
#hitpoints: number;
constructor() {
const abilities = rollAbilities();
this.#hitpoints = HITPOINTS_INITIAL + toModifier(abilities.constitution);
this.#abilities = abilities;
}
get strength(): number {
return this.#abilities.strength;
}
get dexterity(): number {
return this.#abilities.dexterity;
}
get constitution(): number {
return this.#abilities.constitution;
}
get intelligence(): number {
return this.#abilities.intelligence;
}
get wisdom(): number {
return this.#abilities.wisdom;
}
get charisma(): number {
return this.#abilities.charisma;
}
get hitpoints(): number {
return this.#hitpoints;
}
static generateAbilityScore(): number {
return AbilityScores.getScore(roll(), AbilityScores.SCORE_MAX_INDEX);
}
static getModifierFor(abilityValue: number): number {
return toModifier(abilityValue);
}
}
export { DnDCharacter };
```
Clearly the
package.json
downloaded with the CLI installs@types/node
which is why no such error occurs locally.I've stopped using
Math.random()
ever since I ran into this:that remark may as well be a deprecation notice - i.e. one needs to also know how to use
crypto.getRandomValues()
orcrypto.randomFillSync()
.Update: Using
crypto
worked fine 9 days ago with the Simple Cipher exercise