Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"scripts": {
"start": "npx webpack-dev-server --mode development --open --hot",
"test": "npx jest",
"build": "npx webpack --mode production"
"build": "npx webpack --mode production",
"calc": "npx ts-node src/lesson2"
},
"keywords": [
"calculation",
Expand All @@ -30,6 +31,7 @@
"html-webpack-plugin": "^4.3.0",
"jest": "^25.5.4",
"prettier": "^2.0.5",
"ts-node": "^8.10.2",
"typescript": "^3.9.5",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
Expand Down
11 changes: 11 additions & 0 deletions src/lesson2/calc.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { calc } from './calc';

test.each`
input | expected
${'2 + 2 + 2'} | ${6}
${'2** + 2 + 2'} | ${8}
${'4! + 2 + 2'} | ${28}
${'4^2 + 2 + 2'} | ${20}
`('receive $expected submit functions calc($input)', ({ input, expected }) => {
expect(calc(input)).toEqual(expected);
});
18 changes: 18 additions & 0 deletions src/lesson2/calc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { parser } from './parser';

import { firstPrioritiesCalc, secondPrioritiesCalc, degreeСalc } from './logic';

export const calc = (extention: string): number => {
const parserExtention = parser(extention);

const firstPrioritiesRes =
parserExtention.includes('**') || parserExtention.includes('!')
? degreeСalc(parserExtention)
: firstPrioritiesCalc(parserExtention);

if (firstPrioritiesRes.length === 1) {
return Number(firstPrioritiesRes[0]);
}

return secondPrioritiesCalc(firstPrioritiesRes);
};
9 changes: 9 additions & 0 deletions src/lesson2/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type parserType = (string | number)[];

export function isNumeric(params: string | number): boolean {
if (!isNaN(Number(params))) {
return true;
} else {
return false;
}
}
30 changes: 30 additions & 0 deletions src/lesson2/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { createInterface } from 'readline';

import { calc } from './calc';

const rl = createInterface({
input: process.stdin,
output: process.stdout,
});

const question = (): Promise<null> =>
new Promise((resolve) => {
rl.question('> ', (answer: string) => {
const result = calc(answer);

if (result) {
// eslint-disable-next-line no-console
console.log(`Result: ${result}`);
}

resolve();
});
});

async function app(): Promise<null> {
while (true) {
await question();
}
}

app();
35 changes: 35 additions & 0 deletions src/lesson2/logic.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { degreeСalc, firstPrioritiesCalc, secondPrioritiesCalc } from './logic';

test.each`
input | expected
${[11, '**', '+', 3]} | ${[121, '+', 3]}
${[4, '!', '+', 3]} | ${[24, '+', 3]}
`(
'receive $expected submit functions degreeСalc($input)',
({ input, expected }) => {
expect(degreeСalc(input)).toEqual(expected);
},
);

test.each`
input | expected
${[4, '^', 2, '+', 6]} | ${[16, '+', 6]}
${[4, '*', 5, '+', 6]} | ${[20, '+', 6]}
`(
'receive $expected submit functions firstPrioritiesCalc($input)',
({ input, expected }) => {
expect(firstPrioritiesCalc(input)).toEqual(expected);
},
);

test.each`
input | expected
${[4, '+', 5, '+', 6]} | ${15}
${[9, '+', 1, '+', 10]} | ${20}
${[9, '+', 1, '-', 5]} | ${5}
`(
'receive $expected submit functions secondPrioritiesCalc($input)',
({ input, expected }) => {
expect(secondPrioritiesCalc(input)).toBe(expected);
},
);
45 changes: 45 additions & 0 deletions src/lesson2/logic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { operators, operatorsPriorities, priorites } from './operators';
import { parserType } from './common';

const [FIRST, SECOND] = priorites;

export const degreeСalc = (extention: parserType): parserType =>
extention.reduce<parserType>((result, item, key, arr) => {
const operandLeft = result[result.length - 1];

if (item === '**' || item === '!') {
result = [
...result.slice(0, -1),
operators[item](Number(operandLeft), Number(operandLeft)),
];
} else {
result.push(item);
}
return result;
}, []);

export const firstPrioritiesCalc = (extention: parserType): parserType =>
extention.reduce<parserType>((arr, operandRight) => {
const operandLeft = arr[arr.length - 2];
const operand = arr[arr.length - 1];

if (operatorsPriorities[operand] === FIRST) {
arr = [
...arr.slice(0, -2),
operators[operand](Number(operandLeft), Number(operandRight)),
];
} else {
arr.push(operandRight);
}
return arr;
}, []);

export const secondPrioritiesCalc = (extention: parserType): number =>
extention.reduce<number>((result, nextItem, key) => {
const operand = extention[key - 1];

if (operatorsPriorities[operand] === SECOND) {
result = operators[operand](Number(result), Number(nextItem));
}
return result;
}, Number(extention[0]));
40 changes: 40 additions & 0 deletions src/lesson2/operators.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
division,
multiplication,
addition,
subtraction,
power,
powerto,
factorial,
} from './operators';

test.each`
input | expected | textinput
${multiplication(2, 2)} | ${4} | ${'multiplication(2, 2)'}
${division(8, 2)} | ${4} | ${'division(8, 2)'}
${addition(5, 2)} | ${7} | ${'addition(5, 2)'}
${subtraction(5, 2)} | ${3} | ${'subtraction(5, 2)'}
${power(5)} | ${25} | ${'power(5)'}
${powerto(5, 3)} | ${125} | ${'powerto(5, 3)'}
${factorial(5)} | ${120} | ${'factorial(5)'}
${factorial(1)} | ${1} | ${'factorial(1)'}
`('receive $expected submit functions $textinput', ({ input, expected }) => {
expect(input).toBe(expected);
});

test.each`
input | expected | textinput
${multiplication(2, 2)} | ${6} | ${'multiplication(2, 2)'}
${division(8, 2)} | ${5} | ${'division(8, 2)'}
${addition(5, 2)} | ${8} | ${'addition(5, 2)'}
${subtraction(5, 2)} | ${4} | ${'subtraction(5, 2)'}
${power(5)} | ${24} | ${'power(5)'}
${powerto(5, 3)} | ${123} | ${'powerto(5, 3)'}
${factorial(5)} | ${121} | ${'factorial(5)'}
${factorial(1)} | ${2} | ${'factorial(1)'}
`(
'receive shouldn`t be $expected submit functions $textinput',
({ input, expected }) => {
expect(input).not.toBe(expected);
},
);
69 changes: 69 additions & 0 deletions src/lesson2/operators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
type typeOperators = (first: number, second: number) => number;
type oneParametrsType = (value: number) => number;

export const addition: typeOperators = (
first: number,
second: number,
): number => first + second;

export const subtraction: typeOperators = (
first: number,
second: number,
): number => first - second;

export const multiplication: typeOperators = (
first: number,
second: number,
): number => first * second;

export const division: typeOperators = (
first: number,
second: number,
): number => first / second;

export const power: oneParametrsType = (first: number): number =>
(first *= first);

export const powerto: typeOperators = (
first: number,
second: number,
): number => {
let result = first;
for (let pow = 1; pow < second; pow++) {
result *= first;
}
return result;
};

export const factorial: oneParametrsType = (value: number): number => {
if (value === 1) {
return 1;
}
return value * factorial(value - 1);
};

export const operators: {
[key: string]: typeOperators;
} = {
'/': division,
'*': multiplication,
'+': addition,
'-': subtraction,
'**': power,
'^': powerto,
'!': factorial,
};

export const priorites = [1, 2];

const [FIRST, SECOND] = priorites;

export const operatorsPriorities: { [key: string]: number } = {
'!': FIRST,
'*': FIRST,
'/': FIRST,
'**': FIRST,
'^': FIRST,
'+': SECOND,
'-': SECOND,
};
27 changes: 27 additions & 0 deletions src/lesson2/parser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { parser } from './parser';

test.each`
input | expected
${'1 + + 33 - 2'} | ${'Unexpected string'}
${'1 ! 33 - 2'} | ${'Unexpected string'}
`(
'receive $expected after parsing the string $input',
({ input, expected }) => {
expect(() => parser(input)).toThrow(TypeError(expected));
},
);

test.each`
input | expected
${'2 + 2'} | ${[2, '+', 2]}
${'2 + 2 + 5 + 7'} | ${[2, '+', 2, '+', 5, '+', 7]}
${'11 + 3 * 22'} | ${[11, '+', 3, '*', 22]}
${'11** + 3 * 22'} | ${[11, '**', '+', 3, '*', 22]}
${'2** + 2 + 2'} | ${[2, '**', '+', 2, '+', 2]}
${'2** + 2 + 2 + 2!'} | ${[2, '**', '+', 2, '+', 2, '+', 2, '!']}
`(
'receive $expected after parsing the string $input',
({ input, expected }) => {
expect(parser(input)).toEqual(expected);
},
);
36 changes: 36 additions & 0 deletions src/lesson2/parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { parserType, isNumeric } from './common';
export const parser = (extention: string): parserType => {
const parserExtention = extention.split(' ');

return parserExtention.reduce<parserType>((arr, item) => {
if (
item.match(/((\d+)(\*\*))?((\d+)(\!))?((\d+)(\^)(\d*))?$/)![0]
.length > 1
) {
item.match(/((\d+)(\*\*))?((\d+)(\!))?((\d+)(\^)(\d+))?$/)!
.filter((value) => {
return (
value != undefined &&
!value.match(/\d+(\!|\^|\*\*)(\d*)?$/)
);
})
.forEach((value) => {
const typeValue = isNumeric(value)
? Number(value)
: String(value);
arr.push(typeValue);
});
} else if (item.match(/^-{0,1}\d+$/)) {
arr.push(Number(item));
} else if (
['-', '+', '/', '*'].includes(item) &&
arr.indexOf(item, arr.length - 1) == -1
) {
arr.push(item);
} else {
throw new TypeError('Unexpected string');
}

return arr;
}, []);
};
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"target": "ES2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */
"allowJs": true, /* Allow javascript files to be compiled. */
"checkJs": true, /* Report errors in .js files. */
"allowJs": true /* Allow javascript files to be compiled. */,
"checkJs": true /* Report errors in .js files. */,
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
Expand Down