summary refs log tree commit diff stats
path: root/javascript/luhn
diff options
context:
space:
mode:
Diffstat (limited to 'javascript/luhn')
-rw-r--r--javascript/luhn/.eslintrc14
-rw-r--r--javascript/luhn/.npmrc1
-rw-r--r--javascript/luhn/HELP.md73
-rw-r--r--javascript/luhn/LICENSE21
-rw-r--r--javascript/luhn/README.md90
-rw-r--r--javascript/luhn/babel.config.js15
-rw-r--r--javascript/luhn/luhn.js34
-rw-r--r--javascript/luhn/luhn.spec.js75
-rw-r--r--javascript/luhn/package.json31
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 ."
+  }
+}