this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

improve validation and clarity

Co-authored-by: Copilot <copilot@github.com>

+109 -35
+12
source/check-number.ts
··· 1 + /** @internal */ 2 + export default function checkNumber(input: unknown): asserts input is number { 3 + if (typeof input !== 'number') { 4 + throw new TypeError(`Expected number, got \`${String(input)}\``); 5 + } 6 + 7 + if (!Number.isInteger(input) || input < 1) { 8 + throw new RangeError( 9 + `Expected number to be a positive integer, got \`${input}\``, 10 + ); 11 + } 12 + }
+14
source/check-string.ts
··· 1 + const allowedStringPattern = /^[A-Z]+$/v; 2 + 3 + /** @internal */ 4 + export default function checkString(input: unknown): asserts input is string { 5 + if (typeof input !== 'string') { 6 + throw new TypeError(`Expected string, got \`${String(input)}\``); 7 + } 8 + 9 + if (!allowedStringPattern.test(input)) { 10 + throw new RangeError( 11 + `Expected non-empty uppercase-only string, got \`${input}\``, 12 + ); 13 + } 14 + }
+3
source/increment.ts
··· 1 + import checkString from './check-string.js'; 1 2 import toBb26 from './to-bb26.js'; 2 3 import toDecimal from './to-decimal.js'; 3 4 ··· 7 8 * @return Incremented string 8 9 */ 9 10 export default function increment(string: string): string { 11 + checkString(string); 12 + 10 13 return toBb26(toDecimal(string) + 1); 11 14 }
+10 -6
source/random.ts
··· 1 + import checkString from './check-string.js'; 1 2 import toBb26 from './to-bb26.js'; 2 3 import toDecimal from './to-decimal.js'; 3 4 ··· 13 14 export default function random(upper: string): string; 14 15 export default function random(lower: string, upper: string): string; 15 16 export default function random(lower: string, upper?: string): string { 16 - const lowerDecimal = upper === undefined ? 1 : toDecimal(lower); 17 - const upperDecimal = 18 - upper === undefined ? toDecimal(lower) : toDecimal(upper); 17 + if (upper === undefined) { 18 + upper = lower; 19 + lower = 'A'; 20 + } 21 + 22 + for (const string of [lower, upper]) checkString(string); 19 23 20 - const randomDecimal = randomInteger(lowerDecimal, upperDecimal); 24 + const randomInteger = getRandomInteger(toDecimal(lower), toDecimal(upper)); 21 25 22 - return toBb26(randomDecimal); 26 + return toBb26(randomInteger); 23 27 } 24 28 25 - function randomInteger(minimum: number, maximum: number): number { 29 + function getRandomInteger(minimum: number, maximum: number): number { 26 30 return Math.floor(Math.random() * (maximum - minimum + 1) + minimum); 27 31 }
+4 -1
source/range.ts
··· 1 + import checkString from './check-string.js'; 1 2 import toBb26 from './to-bb26.js'; 2 3 import toDecimal from './to-decimal.js'; 3 4 ··· 13 14 export default function range(end: string): string[]; 14 15 export default function range(start: string, end: string): string[]; 15 16 export default function range(start: string, end?: string): string[] { 16 - if (!end) { 17 + if (end === undefined) { 17 18 end = start; 18 19 start = 'A'; 19 20 } 21 + 22 + for (const string of [start, end]) checkString(string); 20 23 21 24 const range: string[] = []; 22 25 const startDecimal = toDecimal(start);
+5 -11
source/to-bb26.ts
··· 1 + import checkNumber from './check-number.js'; 2 + 1 3 /** 2 4 * Converts a decimal number to a bijective base-26 string. 3 5 * 4 6 * @param number 5 7 */ 6 8 export default function toBb26(number: number): string { 7 - if (typeof number !== 'number') { 8 - throw new TypeError(`Expected number, got \`${String(number)}\``); 9 - } 10 - 11 - if (!Number.isInteger(number) || number < 1) { 12 - throw new RangeError( 13 - `Expected number to be a positive integer, got \`${number}\``, 14 - ); 15 - } 9 + checkNumber(number); 16 10 17 11 let string = ''; 18 12 19 13 while (number > 0) { 20 - string = toChar(number % 26 || 26) + string; 14 + string = decimalToCharacter(number % 26 || 26) + string; 21 15 number = Math.floor((number - 1) / 26); 22 16 } 23 17 24 18 return string; 25 19 } 26 20 27 - function toChar(number: number) { 21 + function decimalToCharacter(number: number) { 28 22 return String.fromCodePoint('A'.codePointAt(0)! - 1 + number); 29 23 }
+7 -15
source/to-decimal.ts
··· 1 - function charToDecimal(letter: string) { 2 - return letter.codePointAt(0)! - 'A'.codePointAt(0)! + 1; 3 - } 4 - 5 - const allowedStringPattern = /^[A-Z]+$/v; 1 + import checkString from './check-string.js'; 6 2 7 3 /** 8 4 * Converts a bijective base-26 string to a decimal number. ··· 10 6 * @param string 11 7 */ 12 8 export default function toDecimal(string: string): number { 13 - if (typeof string !== 'string') { 14 - throw new TypeError(`Expected string, got \`${String(string)}\``); 15 - } 16 - 17 - if (!allowedStringPattern.test(string)) { 18 - throw new RangeError( 19 - `Expected string to only contain upper-case letters, got \`${string}\``, 20 - ); 21 - } 9 + checkString(string); 22 10 23 11 let number = 0; 24 12 25 13 for (let i = 0; i < string.length; i++) { 26 14 const char = string[string.length - i - 1]!; 27 15 28 - number += 26 ** i * charToDecimal(char); 16 + number += 26 ** i * characterToDecimal(char); 29 17 } 30 18 31 19 return number; 32 20 } 21 + 22 + function characterToDecimal(letter: string) { 23 + return letter.codePointAt(0)! - 'A'.codePointAt(0)! + 1; 24 + }
+13
test/increment.ts
··· 22 22 expect(increment(from)).toBe(to); 23 23 }); 24 24 } 25 + 26 + test('throws TypeError for non-string input', () => { 27 + expect(() => { 28 + // @ts-expect-error test 29 + increment(1); 30 + }).toThrow(TypeError); 31 + }); 32 + 33 + test('throws RangeError for invalid bijective base-26 strings', () => { 34 + expect(() => increment('')).toThrow(RangeError); 35 + expect(() => increment('a')).toThrow(RangeError); 36 + expect(() => increment('A1')).toThrow(RangeError); 37 + });
+21
test/random.ts
··· 17 17 expect(validLetters.includes(random('AA', 'ZZ'))).toBe(true); 18 18 } 19 19 }); 20 + 21 + test('throws TypeError for non-string input', () => { 22 + expect(() => { 23 + // @ts-expect-error test 24 + random(1); 25 + }).toThrow(TypeError); 26 + 27 + expect(() => { 28 + // @ts-expect-error test 29 + random('A', 1); 30 + }).toThrow(TypeError); 31 + }); 32 + 33 + test('throws RangeError for invalid bijective base-26 strings', () => { 34 + expect(() => random('')).toThrow(RangeError); 35 + expect(() => random('a')).toThrow(RangeError); 36 + expect(() => random('A1')).toThrow(RangeError); 37 + expect(() => random('A', '')).toThrow(RangeError); 38 + expect(() => random('A', 'a')).toThrow(RangeError); 39 + expect(() => random('A', 'A1')).toThrow(RangeError); 40 + });
+19 -2
test/range.ts
··· 15 15 expect(range('ZZ', 'AAC')).toEqual(['ZZ', 'AAA', 'AAB']); 16 16 }); 17 17 18 - test('throws if given a string with a non-upper-case letter', () => { 19 - expect(() => range('a')).toThrow(); 18 + test('throws TypeError for non-string input', () => { 19 + expect(() => { 20 + // @ts-expect-error test 21 + range(1); 22 + }).toThrow(TypeError); 23 + 24 + expect(() => { 25 + // @ts-expect-error test 26 + range('A', 1); 27 + }).toThrow(TypeError); 28 + }); 29 + 30 + test('throws RangeError for invalid bijective base-26 strings', () => { 31 + expect(() => range('')).toThrow(RangeError); 32 + expect(() => range('a')).toThrow(RangeError); 33 + expect(() => range('A1')).toThrow(RangeError); 34 + expect(() => range('A', '')).toThrow(RangeError); 35 + expect(() => range('A', 'a')).toThrow(RangeError); 36 + expect(() => range('A', 'A1')).toThrow(RangeError); 20 37 });
+1
tsconfig.json
··· 6 6 "outDir": "distribution", 7 7 "declaration": true, 8 8 "incremental": true, 9 + "stripInternal": true, 9 10 10 11 // more strictness 11 12 "forceConsistentCasingInFileNames": true,