exercism / typescript-test-runner

GNU Affero General Public License v3.0
1 stars 4 forks source link

Exercise DnD Character - Cannot find module 'crypto' or its corresponding type declarations #71

Closed peerreynders closed 3 months ago

peerreynders commented 3 years ago

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:

We received the following error when we ran your code: The submitted code didn't compile. We have collected the errors encountered during compilation. At this moment the error messages are not very read-friendly, but it's a start. We are working on a more helpful output.


dnd-ability-scores.ts(1,20): error TS2307: Cannot find module 'crypto' or its corresponding type declarations.

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.

    "@types/node": "^14.17.14",

Why the h@ll are you using crypto.randomDFillSync() in an easy exercise.

I've stopped using Math.random() ever since I ran into this:

Note: Math.random() does not provide cryptographically secure random numbers. Do not use them for anything related to security. Use the Web Crypto API instead, and more precisely the window.crypto.getRandomValues() method.

that remark may as well be a deprecation notice - i.e. one needs to also know how to use crypto.getRandomValues() or crypto.randomFillSync().


Update: Using crypto worked fine 9 days ago with the Simple Cipher exercise

SleeplessByte commented 3 years 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.

SleeplessByte commented 3 months ago

@types/node is only a type package, so this bug, if any, is in the test-runner. Moving this issue there.

github-actions[bot] commented 3 months ago

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.

SleeplessByte commented 3 months ago

Fixed in https://github.com/exercism/typescript-test-runner/pull/72/commits/62f68082477b4328b2fd08ecdd477ef520c49f27