-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerateCalculator.js
90 lines (76 loc) · 2.4 KB
/
generateCalculator.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// @ts-check
const fs = require('fs');
/**
* Generated calculator will go from 0 to this number
*/
const maxNumber = 50;
/**
* An operation type-literal token, and a function that does said operation
* @typedef {{ token: string; exec: (a: number, b: number) => number | string }} Operation
*/
/**
* List of operation type-literal tokens, and how to do them
* @type {Operation[]}
* */
const operations = [
{ token: '\'+\'', exec: (a, b) => a + b },
{ token: '\'-\'', exec: (a, b) => a - b },
{ token: '\'*\'', exec: (a, b) => a * b },
{ token: '\'/\'', exec: (a, b) => b === 0 ? '\'Infinity\'' : a / b },
];
const preamble = `/*
* Welcome to this calculator!
* It can add, subtract, multiply and divide whole numbers from 0 to ${maxNumber}
* Use it like this: type myNumber = MyFirstCalculator<3, '+', 5>;
*/
// todo: submit to DefinitelyTyped`;
const allowedNumbers = [];
for (let i = 0; i <= maxNumber; i++) allowedNumbers.push(i);
/**
* String like "1 | 2 | 3 | 4 ... maxNumber"
*/
let renderedAllowedNumbers = allowedNumbers.join(' | ');
/**
* String like "'+' | '-' ..." for all operations
*/
let renderedAllowedOperations = operations.map(({ token }) => token).join(' | ');
/**
* Render the line for Num1 (operaion) Num2
* @param {number} num1
* @param {number} num2
* @param {Operation} operation
*/
function renderNum2(num1, num2, operation) {
return ` Num2 extends ${num2} ? ${operation.exec(num1, num2)} :`;
}
/**
* Render all lines relevant to a given Num1 within a given operation
* @param {number} num1
* @param {Operation} operation
*/
function renderNum1(num1, operation) {
const renderedNum2s = allowedNumbers.map(num2 => renderNum2(num1, num2, operation)).join('\n')
return ` Num1 extends ${num1} ?
${renderedNum2s}
never :`;
}
/**
* Render all lines of a given operation
* @param {Operation} operation
* */
function renderOperation(operation) {
const renderedNum1s = allowedNumbers.map(num1 => renderNum1(num1, operation)).join('\n');
return ` Operation extends ${operation.token} ?
${renderedNum1s}
never :`;
}
const renderedOperations = operations.map(renderOperation).join('\n');
let out = `${preamble}
type MyFirstCalculator<
Num1 extends ${renderedAllowedNumbers},
Operation extends ${renderedAllowedOperations},
Num2 extends ${renderedAllowedNumbers}
> =
${renderedOperations}
never;`;
fs.writeFile('./my_first_calculator.d.ts', out, () => {});