diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..140f92d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..ef58ff9 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "es5", + "tabWidth": 4, + "semi": false, + "singleQuote": true +} diff --git a/package.json b/package.json index a5b42cd..92943d8 100644 --- a/package.json +++ b/package.json @@ -2,14 +2,17 @@ "name": "frontend-exercise", "version": "0.1.0", "private": true, + "engines": { + "node": " >=18" + }, "dependencies": { - "@testing-library/jest-dom": "^5.11.4", - "@testing-library/react": "^11.1.0", - "@testing-library/user-event": "^12.1.10", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "react-scripts": "4.0.1", - "web-vitals": "^0.2.4" + "@testing-library/jest-dom": "^6.4.2", + "@testing-library/react": "^15.0.4", + "@testing-library/user-event": "^14.5.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1", + "web-vitals": "^3.5.2" }, "scripts": { "start": "react-scripts start", @@ -34,5 +37,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "prettier": "3.2.5" } } diff --git a/src/App.js b/src/App.js index 05d26cf..1f4e528 100644 --- a/src/App.js +++ b/src/App.js @@ -1,16 +1,28 @@ +import { useEffect, useState } from 'react' +import { numberFromWord } from './utils/numberFromWord' + function App() { - const text = '' + const [value, setValue] = useState('one hundred twenty and one') + const [result, setResult] = useState(0) + + useEffect(() => { + setResult(numberFromWord(value)) + }, [value]) - return ( -
- -
-

- Output: {text} -

-
-
- ) + return ( +
+ { + setValue(e.target.value) + }} + /> +
+

Output: {result}

+
+
+ ) } export default App diff --git a/src/App.test.js b/src/App.test.js deleted file mode 100644 index bad8e0c..0000000 --- a/src/App.test.js +++ /dev/null @@ -1,5 +0,0 @@ -describe('App', () => { - it('should convert number to text', () => { - expect(true).toBe(false) - }) -}) diff --git a/src/constants/words.js b/src/constants/words.js new file mode 100644 index 0000000..d5692bb --- /dev/null +++ b/src/constants/words.js @@ -0,0 +1,40 @@ +export const words = { + zero: 0, + one: 1, + two: 2, + three: 3, + four: 4, + five: 5, + six: 6, + seven: 7, + eight: 8, + nine: 9, + ten: 10, + eleven: 11, + twelve: 12, + thirteen: 13, + fourteen: 14, + fifteen: 15, + sixteen: 16, + seventeen: 17, + eighteen: 18, + nineteen: 19, + twenty: 20, + thirty: 30, + forty: 40, + fifty: 50, + sixty: 60, + seventy: 70, + eighty: 80, + ninety: 90, +} + +export const multipliers = { + hundred: 100, + thousand: 1000, + million: 1000000, + billion: 1000000000, +} + +export const max = 999999999 +export const min = 0 diff --git a/src/utils/numberFromWord.js b/src/utils/numberFromWord.js new file mode 100644 index 0000000..07233a2 --- /dev/null +++ b/src/utils/numberFromWord.js @@ -0,0 +1,52 @@ +import { + words as wordDictionary, + multipliers as multipliersDictionary, + min, + max, +} from '../constants/words' + +export const numberFromWord = (string) => { + string = string.toLowerCase().replace(/-|\s+and\s+/g, ' ') + let words = string.split(/\s+/) + let current = 0 + let result = 0 + let lastMultiplier = 1 + let lastWasNumber = false + let lastNumber = 0 + + for (let word of words) { + if (wordDictionary.hasOwnProperty(word)) { + // exception for wordDictionary[word] === 0 + let numberValue = wordDictionary[word] + if (lastWasNumber) { + if ( + !(lastNumber >= 20 && lastNumber < 100 && numberValue < 10) + ) { + return 'incorrect' + } + } + current = current + numberValue + lastWasNumber = true + lastNumber = numberValue + } else if (multipliersDictionary[word]) { + if (current === 0 && result === 0) { + return 'incorrect' + } + current = current * multipliersDictionary[word] + if (multipliersDictionary[word] > lastMultiplier) { + result = result + current + current = 0 + } + lastMultiplier = multipliersDictionary[word] + lastWasNumber = false + } else { + return 'incorrect' + } + } + + result = result + current + if (result < min || result > max) { + return 'incorrect' + } + return result +} diff --git a/src/utils/numberFromWord.test.js b/src/utils/numberFromWord.test.js new file mode 100644 index 0000000..90a3749 --- /dev/null +++ b/src/utils/numberFromWord.test.js @@ -0,0 +1,78 @@ +import { numberFromWord } from './numberFromWord' + +describe('numberFromWord', () => { + describe('test outputs', () => { + it('zero => 0', () => { + const test = numberFromWord('zero') + expect(test).toBe(0) + }) + + it('one => 1', () => { + const test = numberFromWord('one') + expect(test).toBe(1) + }) + + it('one hundred => 100', () => { + const test = numberFromWord('one hundred') + expect(test).toBe(100) + }) + it('one hundred twenty => 120', () => { + const test = numberFromWord('one hundred twenty') + expect(test).toBe(120) + }) + + it('three million one hundred thousand and ninety =≥ 3100090', () => { + const test = numberFromWord( + 'three million one hundred thousand and ninety' + ) + expect(test).toBe(3100090) + }) + + it('two thousand and forty five => 2045', () => { + const test = numberFromWord('two thousand and forty five') + expect(test).toBe(2045) + }) + + it('fifty four => 54', () => { + const test = numberFromWord('fifty four') + expect(test).toBe(54) + }) + }) + + describe('test edge cases', () => { + it('one hundred-twenty => 120', () => { + const test = numberFromWord('one hundred-twenty') + expect(test).toBe(120) + }) + + it('ONE HUNDRED-TWENTY => 120', () => { + const test = numberFromWord('ONE HUNDRED-TWENTY') + expect(test).toBe(120) + }) + + it('ONE HUNDRED and TWENTY => 120', () => { + const test = numberFromWord('ONE HUNDRED and TWENTY') + expect(test).toBe(120) + }) + + it('one one => incorrect', () => { + const test = numberFromWord('one one') + expect(test).toBe('incorrect') + }) + + it('one one => incorrect', () => { + const test = numberFromWord('one one') + expect(test).toBe('incorrect') + }) + + it('one billion => incorrect', () => { + const test = numberFromWord('one billion') + expect(test).toBe('incorrect') + }) + + it('one billion => incorrect', () => { + const test = numberFromWord('minus one') + expect(test).toBe('incorrect') + }) + }) +})