diff options
-rw-r--r-- | javascript/luhn/.eslintrc | 14 | ||||
-rw-r--r-- | javascript/luhn/.npmrc | 1 | ||||
-rw-r--r-- | javascript/luhn/HELP.md | 73 | ||||
-rw-r--r-- | javascript/luhn/LICENSE | 21 | ||||
-rw-r--r-- | javascript/luhn/README.md | 90 | ||||
-rw-r--r-- | javascript/luhn/babel.config.js | 15 | ||||
-rw-r--r-- | javascript/luhn/luhn.js | 34 | ||||
-rw-r--r-- | javascript/luhn/luhn.spec.js | 75 | ||||
-rw-r--r-- | javascript/luhn/package.json | 31 |
9 files changed, 354 insertions, 0 deletions
diff --git a/javascript/luhn/.eslintrc b/javascript/luhn/.eslintrc new file mode 100644 index 0000000..1d44460 --- /dev/null +++ b/javascript/luhn/.eslintrc @@ -0,0 +1,14 @@ +{ + "root": true, + "extends": "@exercism/eslint-config-javascript", + "env": { + "jest": true + }, + "overrides": [ + { + "files": [".meta/proof.ci.js", ".meta/exemplar.js", "*.spec.js"], + "excludedFiles": ["custom.spec.js"], + "extends": "@exercism/eslint-config-javascript/maintainers" + } + ] +} diff --git a/javascript/luhn/.npmrc b/javascript/luhn/.npmrc new file mode 100644 index 0000000..d26df80 --- /dev/null +++ b/javascript/luhn/.npmrc @@ -0,0 +1 @@ +audit=false diff --git a/javascript/luhn/HELP.md b/javascript/luhn/HELP.md new file mode 100644 index 0000000..1f29d65 --- /dev/null +++ b/javascript/luhn/HELP.md @@ -0,0 +1,73 @@ +# Help + +## Running the tests + +## Setup + +Go through the setup [instructions for JavaScript][docs-exercism-javascript] to install the necessary dependencies. + +## Requirements + +Install assignment dependencies: + +```shell +# Using npm +npm install + +# Alternatively using yarn +yarn +``` + +## Making the test suite pass + +All exercises come with a test suite to help you validate your solution before submitting. +You can execute these tests by opening a command prompt in the exercise's directory, and then running: + +```bash +# Using npm +npm test + +# Alternatively using yarn +yarn test +``` + +In some test suites all tests but the first have been skipped. + +Once you get a test passing, you can enable the next one by changing `xtest` to `test`. + +## Writing custom tests + +If you wish to write additional, custom, tests, create a new file `custom.spec.js`, and submit it with your solution together with the new file: + +```shell +exercism submit numbers.js custom.spec.js +``` + +[docs-exercism-javascript]: https://exercism.org/docs/tracks/javascript/installation + +## Submitting your solution + +You can submit your solution using the `exercism submit luhn.js` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [JavaScript track's documentation](https://exercism.org/docs/tracks/javascript) +- [Exercism's support channel on gitter](https://gitter.im/exercism/support) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [Gitter](https://gitter.im/exercism/support) is Exercism's Gitter room; go here to get support and ask questions if you face any issues with downloading or submitting your exercises. +- [/r/javascript](https://www.reddit.com/r/javascript) is the Javascript subreddit. +- [StackOverflow](https://stackoverflow.com/questions/tagged/javascript+exercism) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. +- [Github issue tracker](https://github.com/exercism/javascript/issues) is where we track our development and maintainance of Javascript exercises in exercism. But if none of the above links help you, feel free to post an issue here. \ No newline at end of file diff --git a/javascript/luhn/LICENSE b/javascript/luhn/LICENSE new file mode 100644 index 0000000..90e73be --- /dev/null +++ b/javascript/luhn/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Exercism + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/javascript/luhn/README.md b/javascript/luhn/README.md new file mode 100644 index 0000000..1fffedf --- /dev/null +++ b/javascript/luhn/README.md @@ -0,0 +1,90 @@ +# Luhn + +Welcome to Luhn on Exercism's JavaScript Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Given a number determine whether or not it is valid per the Luhn formula. + +The [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) is +a simple checksum formula used to validate a variety of identification +numbers, such as credit card numbers and Canadian Social Insurance +Numbers. + +The task is to check if a given string is valid. + +## Validating a Number + +Strings of length 1 or less are not valid. Spaces are allowed in the input, +but they should be stripped before checking. All other non-digit characters +are disallowed. + +## Example 1: valid credit card number + +```text +4539 3195 0343 6467 +``` + +The first step of the Luhn algorithm is to double every second digit, +starting from the right. We will be doubling + +```text +4_3_ 3_9_ 0_4_ 6_6_ +``` + +If doubling the number results in a number greater than 9 then subtract 9 +from the product. The results of our doubling: + +```text +8569 6195 0383 3437 +``` + +Then sum all of the digits: + +```text +8+5+6+9+6+1+9+5+0+3+8+3+3+4+3+7 = 80 +``` + +If the sum is evenly divisible by 10, then the number is valid. This number is valid! + +## Example 2: invalid credit card number + +```text +8273 1232 7352 0569 +``` + +Double the second digits, starting from the right + +```text +7253 2262 5312 0539 +``` + +Sum the digits + +```text +7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57 +``` + +57 is not evenly divisible by 10, so this number is not valid. + +## Source + +### Created by + +- @matthewmorgan + +### Contributed to by + +- @ankorGH +- @gabriel376 +- @ovidiu141 +- @rchavarria +- @ryanplusplus +- @SleeplessByte +- @tejasbubane +- @xarxziux + +### Based on + +The Luhn Algorithm on Wikipedia - http://en.wikipedia.org/wiki/Luhn_algorithm \ No newline at end of file diff --git a/javascript/luhn/babel.config.js b/javascript/luhn/babel.config.js new file mode 100644 index 0000000..5f1ec60 --- /dev/null +++ b/javascript/luhn/babel.config.js @@ -0,0 +1,15 @@ +module.exports = { + presets: [ + [ + '@babel/preset-env', + { + targets: { + node: 'current', + }, + useBuiltIns: 'entry', + corejs: '3.17', + }, + ], + ], + plugins: ['@babel/plugin-syntax-bigint'], +}; diff --git a/javascript/luhn/luhn.js b/javascript/luhn/luhn.js new file mode 100644 index 0000000..166a0bf --- /dev/null +++ b/javascript/luhn/luhn.js @@ -0,0 +1,34 @@ +'use strict'; + +export const valid = (input) => { + let filtered = []; + + // Filter the numbers out. Return false if we find anything other + // than numbers or spaces. + for (let idx = 0; idx < input.length; idx++) { + if (/^\d$/.test(input[idx])) + filtered.push(Number(input[idx])); + else if (!(/^\s$/.test(input[idx]))) + return false; + } + + // Invalid. + if (filtered.length < 2) + return false; + + // Reverse the filtered numbers. + filtered.reverse(); + + let sum = 0; + for (let idx = 0; idx < filtered.length; idx++) { + if ((idx % 2) !== 0) { + if ((filtered[idx] * 2) > 9) + sum += (filtered[idx] * 2) - 9; + else + sum += filtered[idx] * 2; + } else + sum += filtered[idx]; + } + + return (sum % 10 === 0); +}; diff --git a/javascript/luhn/luhn.spec.js b/javascript/luhn/luhn.spec.js new file mode 100644 index 0000000..614348e --- /dev/null +++ b/javascript/luhn/luhn.spec.js @@ -0,0 +1,75 @@ +import { valid } from './luhn'; + +describe('Luhn', () => { + test('single digit strings can not be valid', () => { + expect(valid('1')).toEqual(false); + }); + + test('a single zero is invalid', () => { + expect(valid('0')).toEqual(false); + }); + + test('a simple valid SIN that remains valid if reversed', () => { + expect(valid('059')).toEqual(true); + }); + + test('a simple valid SIN that becomes invalid if reversed', () => { + expect(valid('59')).toEqual(true); + }); + + test('a valid Canadian SIN', () => { + expect(valid('055 444 285')).toEqual(true); + }); + + test('invalid Canadian SIN', () => { + expect(valid('055 444 286')).toEqual(false); + }); + + test('invalid credit card', () => { + expect(valid('8273 1232 7352 0569')).toEqual(false); + }); + + test('invalid long number with an even remainder', () => { + expect(valid('1 2345 6789 1234 5678 9012')).toEqual(false); + }); + + test('valid number with an even number of digits', () => { + expect(valid('095 245 88')).toEqual(true); + }); + + test('valid number with an odd number of spaces', () => { + expect(valid('234 567 891 234')).toEqual(true); + }); + + test('valid strings with a non-digit added at the end invalid', () => { + expect(valid('059a')).toEqual(false); + }); + + test('valid strings with punctuation included become invalid', () => { + expect(valid('055-444-285')).toEqual(false); + }); + + test('valid strings with symbols included become invalid', () => { + expect(valid('055# 444$ 285')).toEqual(false); + }); + + test('single zero with space is invalid', () => { + expect(valid(' 0')).toEqual(false); + }); + + test('more than a single zero is valid', () => { + expect(valid('0000 0')).toEqual(true); + }); + + test('input digit 9 is correctly converted to output digit 9', () => { + expect(valid('091')).toEqual(true); + }); + + test("using ascii value for non-doubled non-digit isn't allowed", () => { + expect(valid('055b 444 285')).toEqual(false); + }); + + test("using ascii value for doubled non-digit isn't allowed", () => { + expect(valid(':9')).toEqual(false); + }); +}); diff --git a/javascript/luhn/package.json b/javascript/luhn/package.json new file mode 100644 index 0000000..7d358df --- /dev/null +++ b/javascript/luhn/package.json @@ -0,0 +1,31 @@ +{ + "name": "@exercism/javascript-luhn", + "description": "Exercism exercises in Javascript.", + "author": "Katrina Owen", + "private": true, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/exercism/javascript", + "directory": "exercises/practice/luhn" + }, + "devDependencies": { + "@babel/cli": "^7.15.4", + "@babel/core": "^7.15.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/preset-env": "^7.15.0", + "@exercism/eslint-config-javascript": "^0.4.0", + "@types/jest": "^27.0.1", + "@types/node": "^16.7.10", + "babel-jest": "^27.1.0", + "core-js": "^3.17.2", + "eslint": "^7.32.0", + "jest": "^26.6.3" + }, + "dependencies": {}, + "scripts": { + "test": "jest --no-cache ./*", + "watch": "jest --no-cache --watch ./*", + "lint": "eslint ." + } +} |