├── .babelrc ├── .eslintrc ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── dist ├── conditional-expression.min.js └── conditional-expression.min.js.map ├── index.d.ts ├── package-lock.json ├── package.json ├── src └── index.js ├── test └── index.test.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "@babel/preset-env" ] 3 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended" 9 | ], 10 | "parser": "babel-eslint", 11 | "parserOptions": { 12 | "ecmaVersion": 2018, 13 | "sourceType": "module" 14 | }, 15 | "globals": { 16 | "describe": true, 17 | "it": true 18 | }, 19 | "rules": { 20 | "indent": [ 21 | "error", 22 | 2 23 | ], 24 | "linebreak-style": [ 25 | "error", 26 | "unix" 27 | ], 28 | "quotes": [ 29 | "error", 30 | "single" 31 | ], 32 | "semi": [ 33 | "error", 34 | "always" 35 | ], 36 | "require-jsdoc": ["error", { 37 | "require": { 38 | "FunctionDeclaration": true, 39 | "MethodDefinition": true, 40 | "ClassDeclaration": true, 41 | "ArrowFunctionExpression": true, 42 | "FunctionExpression": true 43 | } 44 | }] 45 | } 46 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .sonarlint 3 | .idea 4 | .nyc_output -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # conditional-expression changelog 2 | 3 | ## 1.1.2 4 | 5 | - Fixed README 6 | 7 | ## 1.1.1 8 | 9 | - Added greaterThan({*}), lessThan({*}), atLeast({*}), atMost({*}) for comparing sizes 10 | - Fixed Node.js support 11 | - 100 % test coverage provided. 12 | 13 | ## 1.1.0 14 | 15 | - Matching now supports one level of nesting using "thenMatch" function. 16 | - Added more assertion to test the package and new functionality. 17 | - Changed the internal structure to promote more internal reusability of the code to add more matching functions in the future if needed. 18 | - 100 % test coverage provided. 19 | 20 | ## 1.0.1 21 | 22 | - "include" function to always returns false if matching over anything else than a string. 23 | - 100 % test coverage provided. 24 | 25 | ## 1.0.0 26 | 27 | - Initial version of conditional-expression providing matching without nesting using. 28 | - 100 % test coverage provided. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Martin Novak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # conditional-expression 2 | 3 | ![npm](https://img.shields.io/npm/v/conditional-expression.svg) 4 | ![NpmLicense](https://img.shields.io/npm/l/conditional-expression.svg) 5 | ![npm bundle size (minified)](https://img.shields.io/bundlephobia/min/conditional-expression.svg) 6 | ![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/conditional-expression.svg) 7 | 8 | Providing 'match' function as a JavaScript functional conditional 9 | expression to replace conditional statements 'if' and 'switch' 10 | as an alternative to ternary operator expression. 11 | 12 | GitHub repository: https://github.com/MartinGentleman/conditional-expression 13 | 14 | Medium article explaining motivation and use for the package: [How to replace switch and ternaries in functional JavaScript](https://medium.com/@martinnovk_22870/how-to-replace-switch-and-ternaries-in-functional-javascript-a011f0e93a31). 15 | 16 | ## Install 17 | 18 | 19 | ```sh 20 | npm install conditional-expression --save 21 | ``` 22 | 23 | Without ES6: 24 | 25 | ```js 26 | var match = require('conditional-expression').default; 27 | 28 | match(1) 29 | .equals(1).then(function () { 30 | console.log('hello world'); 31 | }).else(false); 32 | 33 | ``` 34 | 35 | With ES6: 36 | 37 | ```js 38 | import match from 'conditional-expression'; 39 | 40 | match(1) 41 | .equals(1).then(() => console.log('hello world')) 42 | .else(false); 43 | 44 | ``` 45 | 46 | ## Usage 47 | 48 | First you call match function on an expression that you want to match: 49 | 50 | ```js 51 | match('functional programming'); 52 | ``` 53 | 54 | Next you choose how you want to match the expression by choosing 55 | appropriate matching function. For example: 56 | 57 | ```js 58 | match('functional programming') 59 | .includes('programming'); 60 | ``` 61 | 62 | You follow up by calling 'then' function to tell it what to do in case 63 | of a positive match. You can pass a simple value as well as a function 64 | that will be automatically evaluated: 65 | 66 | ```js 67 | match('something') 68 | .with(/[a-z]/).then('awesome'); 69 | 70 | // or 71 | 72 | match('functional programming') 73 | .includes('programming').then(() => console.log('awesome')); 74 | ``` 75 | 76 | You have the option of chaining: 77 | 78 | ```js 79 | match(42) 80 | .typeOf('string').then('it is a string') 81 | .equals('42').then('Answer to the Ultimate Question of Life, the Universe, and Everything'); 82 | ``` 83 | 84 | And you finish everything by calling 'else' which is mandatory: 85 | 86 | ```js 87 | match('http://domain.tld') 88 | .on(url => url.substr(0, 5) === 'https').then('It is HTTPS indeed') 89 | .else('It is not HTTPS and that makes me sad :('); 90 | // returns 'It is not HTTPS and that makes me sad :(' 91 | ``` 92 | 93 | Once a match is found, no other matching is performed: 94 | 95 | ```js 96 | match('funny joke') 97 | .equals('sad').then('I am false') 98 | .with(/[a-z]/).then('I am true and I am the result') 99 | .includes('joke').then('I am true but I am not evaluated') 100 | .else('I just execute everything'); 101 | // returns 'I am true and I am the result' 102 | ``` 103 | 104 | ## Matching functions 105 | 106 | ### on({function}) 107 | Evaluates as true if passed function returns boolean true, every other 108 | result of a function evaluates as false. Given function is also passed 109 | the expression over which we are matching as a parameter. 110 | 111 | ```js 112 | match({ grumpy: 'cat' }) 113 | .on(x => x.grumpy === 'cat').then(true) 114 | .else(false); 115 | // returns true 116 | ``` 117 | 118 | Internally this function is used to implement or other matching 119 | functions. 120 | 121 | ### with({RegEx}) 122 | Evaluates as true based on passed regular expression. 123 | 124 | ```js 125 | match(73) 126 | .with(/[0-9]/).then(true) 127 | .else(false); 128 | // returns true 129 | ``` 130 | 131 | ### equals({*}) 132 | Evaluates as true based on strict equality ===. 133 | 134 | ```js 135 | match('tortoise') 136 | .equals('tortoise').then(true) 137 | .else(false); 138 | // returns true 139 | ``` 140 | 141 | ### includes({string}) 142 | Evaluates as true based on whether a substring is included. Always 143 | evaluates as false if not used to match on a string. 144 | 145 | ```js 146 | match('Martian') 147 | .includes('arti').then(true) 148 | .else(false); 149 | // returns true 150 | ``` 151 | 152 | ### typeOf({string}) 153 | Evaluates as true based a type. 154 | 155 | ```js 156 | match({}) 157 | .typeOf('object').then(true) 158 | .else(false); 159 | // returns true 160 | ``` 161 | 162 | ### greaterThan({*}), lessThan({*}), atLeast({*}), atMost({*}) 163 | Evaluates as true based on sizes. 164 | 165 | ```js 166 | match(2).greaterThan(1).then(true).else(false); 167 | // returns true 168 | 169 | match('ab').lessThan('abc').then(true).else(false); 170 | // returns true 171 | 172 | match(2).atLeast(2).then(true).else(false); 173 | // returns true 174 | 175 | match(2).atLeast(1).then(true).else(false); 176 | // returns true 177 | 178 | match(2).atMost(2).then(true).else(false); 179 | // returns true 180 | 181 | match(2).atMost(1).then(true).else(false); 182 | // returns true 183 | ``` 184 | 185 | ## thenMatch() nested matching 186 | 187 | You can use nested matching to create subbranches for evaluation. Only 188 | 1 level deep nest is directly supported using thenMatch function. 189 | 190 | ```js 191 | const param = 'this is string'; 192 | 193 | match(param) 194 | .includes('this').thenMatch(param) 195 | .includes('string').then(true) 196 | .else(false); 197 | .else(false); 198 | // returns true 199 | ``` 200 | 201 | Notice that thenMatch uses its own parameter and that else in the nested branch 202 | is still required. 203 | 204 | To support deeper branching, you can pass match evaluation as a parameter 205 | to then function. 206 | 207 | ```js 208 | const param = 'this is string'; 209 | 210 | match(param) 211 | .includes('this').thenMatch(param) 212 | .includes('is').then(() => match(param) 213 | .includes('string').then(true) 214 | .else(false)) 215 | .else(false); 216 | .else(false); 217 | // returns true 218 | ``` 219 | 220 | ## conditional-expression changelog 221 | 222 | ### 1.1.2 223 | 224 | - Fixed README 225 | 226 | ### 1.1.1 227 | 228 | - Added greaterThan({*}), lessThan({*}), atLeast({*}), atMost({*}) for comparing sizes 229 | - Fixed Node.js support 230 | - 100 % test coverage provided. 231 | 232 | ### 1.1.0 233 | 234 | - Matching now supports one level of nesting using "thenMatch" function. 235 | - Added more assertion to test the package and new functionality. 236 | - Changed the internal structure to promote more internal reusability of the code to add more matching functions in the future if needed. 237 | - 100 % test coverage provided. 238 | 239 | ### 1.0.1 240 | 241 | - "include" function to always returns false if matching over anything else than a string. 242 | - 100 % test coverage provided. 243 | 244 | ### 1.0.0 245 | 246 | - Initial version of conditional-expression providing matching without nesting using. 247 | - 100 % test coverage provided. 248 | 249 | ## Social 250 | 251 | Find me on Twitter: https://twitter.com/PerAsperaEU 252 | 253 | Find me on Medium: https://medium.com/@martinnovk_22870 -------------------------------------------------------------------------------- /dist/conditional-expression.min.js: -------------------------------------------------------------------------------- 1 | !function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.conditionalExpression=t():n.conditionalExpression=t()}(this,function(){return function(n){var t={};function e(r){if(t[r])return t[r].exports;var u=t[r]={i:r,l:!1,exports:{}};return n[r].call(u.exports,u,u.exports,e),u.l=!0,u.exports}return e.m=n,e.c=t,e.d=function(n,t,r){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:r})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(e.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var u in n)e.d(r,u,function(t){return n[t]}.bind(null,u));return r},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=0)}([function(n,t,e){"use strict";function r(n){for(var t=1;tr)},lessThan:function(r){return n(e)(t&&e=r)},atMost:function(r){return n(e)(t&&e<=r)}}}}},f=function(n){return r({},i(y)(!0)(n),{else:function(t){return p(t)(n)}})},c=function(n){return r({},i(d)(!0)(n),{else:function(t){return l(p(t)(n))}})},l=function(n){return r({},i(b)(!1)(n),{else:function(){return n}})},s=function(n){return r({},i(m)(!1)(n),{else:function(){return l(n)}})},a=function(n){return r({},i(h)(!1)(n),{else:function(){return f(n)}})},p=function(n){return function(t){return"function"==typeof n?n(t):n}},y=function(n){return function(t){return{then:function(e){return t?l(p(e)(n)):f(n)},thenMatch:function(e){return t?c(e):a(n)}}}},b=function(n){return function(){return{then:function(){return l(n)},thenMatch:function(){return s(n)}}}},d=function(n){return function(t){return{then:function(e){return t?s(p(e)(n)):c(n)}}}},m=function(n){return function(){return{then:function(){return s(n)}}}},h=function(n){return function(){return{then:function(){return a(n)}}}};t.default=f}])}); 2 | //# sourceMappingURL=conditional-expression.min.js.map -------------------------------------------------------------------------------- /dist/conditional-expression.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://conditionalExpression/webpack/universalModuleDefinition","webpack://conditionalExpression/webpack/bootstrap","webpack://conditionalExpression/./src/index.js"],"names":["root","factory","exports","module","define","amd","this","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","higherOrderMatch","onFunction","evaluate","x","on","y","with","test","equals","includes","typeOf","_typeof","isGreaterThan","lessThan","atLeast","atMost","match","_objectSpread","onMatch","else","express","nestedMatch","onNestedMatch","matched","onMatched","nestedMatched","onNestedMatched","ignoreNestedMatch","onIgnoreNestedMatch","evaluation","then","thenMatch"],"mappings":"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","file":"conditional-expression.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"conditionalExpression\"] = factory();\n\telse\n\t\troot[\"conditionalExpression\"] = factory();\n})(this, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","/**\n * Higher-order function to serve as prototype for other matching functions\n * @param {function} onFunction function to be used for matching functions\n * @param {boolean} evaluate whether condition should be evaluated\n * @param {*} x simple value to be matched\n * @returns {object} higherOrderMatch :: a -> b -> c {on: d -> e, with: d -> e, equals: d -> e, includes: d -> e, typeof: d -> e}\n */\nconst higherOrderMatch = onFunction => evaluate => x => ({\n on: y => onFunction(x)(evaluate && y(x) === true),\n with: y => onFunction(x)(evaluate && y.test(x)),\n equals: y => onFunction(x)(evaluate && x === y),\n includes: y => onFunction(x)(evaluate && typeof x === 'string' && x.includes(y)),\n typeOf: y => onFunction(x)(evaluate && typeof x === y),\n isGreaterThan: y => onFunction(x)(evaluate && x > y),\n lessThan: y => onFunction(x)(evaluate && x < y),\n atLeast: y => onFunction(x)(evaluate && x >= y),\n atMost: y => onFunction(x)(evaluate && x <= y)\n});\n\n/**\n * Matching function to replace imperative switch statement with advanced functional pattern matching expression\n * @param {*} x simple value to be matched\n * @returns {object} match: a -> {on: b -> c, with: b -> c, equals: b -> c, includes: b -> c, typeof: b -> c, else: b -> c}\n * @example\n * match(2)\n * .equals(1).then('number one')\n * .equals(2).then('number two')\n * .else('unknown number');\n */\nconst match = x => ({\n ...higherOrderMatch(onMatch)(true)(x),\n else: y => express(y)(x)\n});\n\n/**\n * Matching function to be used within nested branch\n * @param {*} x simple value to be matched\n * @returns {object} nestedMatch: a -> {on: b -> c, with: b -> c, equals: b -> c, includes: b -> c, typeof: b -> c, else: b -> c}\n */\nconst nestedMatch = x => ({\n ...higherOrderMatch(onNestedMatch)(true)(x),\n else: y => matched(express(y)(x))\n});\n\n/**\n * Once a match is made we are not processing any conditions anymore\n * @param {*} x simple value to be matched\n * @returns {object} matched: a -> {on: a -> b, with: a -> b, equals: a -> b, includes: a -> b, typeof: a -> b, else: () -> a}\n */\nconst matched = x => ({\n ...higherOrderMatch(onMatched)(false)(x),\n else: () => x\n});\n\n/**\n * Once a nested match is made we are not processing any conditions anymore\n * @param {*} x simple value to be matched\n * @returns {object} nestedMatched: a -> {on: a -> b, with: a -> b, equals: a -> b, includes: a -> b, typeof: a -> b, else: () -> a}\n */\nconst nestedMatched = x => ({\n ...higherOrderMatch(onNestedMatched)(false)(x),\n else: () => matched(x)\n});\n\n/**\n * If nested branch is under false condition match we want to ignore it\n * @param {*} x simple value to be matched\n * @returns {object} ignoreNestedMatch: a -> {on: a -> b, with: a -> b, equals: a -> b, includes: a -> b, typeof: a -> b, else: () -> a}\n */\nconst ignoreNestedMatch = x => ({\n ...higherOrderMatch(onIgnoreNestedMatch)(false)(x),\n else: () => match(x)\n});\n \n/**\n * Triggeres a function or just returns a value depending on type of passed expression\n * @param {*} y value or a function\n * @param {*} x in case of expression being a function, param is passed as its parameter\n * @returns {*} express: (function, x) -> function (x), express: function -> function (), express: x -> x\n * @example express('hello'); // return hello\n * @example express(() => console.log('hello')); // prints out 'hello' to console\n */\nconst express = y => x => typeof y === 'function' ? y(x) : y;\n \n/**\n * General function to evaluation matching based on a functional expression\n * @param {*} x simple value to be matched\n * @param {boolean} evaluation function used for matching\n * @returns {object} onMatch: a -> function -> {then: b -> c, thenMatch: b -> c}\n */\nconst onMatch = x => evaluation => ({\n then: y => evaluation ? matched(express(y)(x)) : match(x),\n thenMatch: y => evaluation ? nestedMatch(y) : ignoreNestedMatch(x)\n});\n\n/**\n * Makes sure that 'then' will be returning matched result\n * @param {*} x result of matching\n * @returns {object} onMatched: a -> () -> {then: () -> b, thenMatch: () -> b}\n */\nconst onMatched = x => () => ({\n then: () => matched(x),\n thenMatch: () => nestedMatched(x)\n});\n\n/**\n * General function to evaluate nested matches\n * @param {*} x simple value to be matched\n * @returns {object} onNestedMatch: a -> function -> {then: b -> c}\n */\nconst onNestedMatch = x => evaluation => ({\n then: y => evaluation ? nestedMatched(express(y)(x)) : nestedMatch(x)\n});\n\n/**\n * Makes sure that then will be returning result of nested match\n * @param {*} x result of matching\n * @returns {object} onNestedMatched: a -> () -> {then: () -> b}\n */\nconst onNestedMatched = x => () => ({\n then: () => nestedMatched(x)\n});\n\n/**\n * Makes sure that nested branch is not returning any result\n * @param {*} x simple value to be matched\n * @returns {object} onIgnoreNestedMatch: a -> () -> {then: () -> b}\n */\nconst onIgnoreNestedMatch = x => () => ({\n then: () => ignoreNestedMatch(x)\n});\n\nexport default match;"],"sourceRoot":""} -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "conditional-expression" { 2 | type TFunction = (value: T) => any; 3 | 4 | type TOnFunction = (value: T) => boolean; 5 | 6 | interface IHigherOrderMatchReturn { 7 | on: (func: TOnFunction) => IMachable; 8 | with: (value: string) => IMachable; 9 | equals: (value: T) => IMachable; 10 | includes: (value: string) => IMachable; 11 | typeOf: (value: string) => IMachable; 12 | isGreaterThan: (value: T) => IMachable; 13 | lessThan: (value: T) => IMachable; 14 | atLeast: (value: T) => IMachable; 15 | atMost: (value: T) => IMachable; 16 | } 17 | 18 | interface IMatched extends IHigherOrderMatchReturn { 19 | else: (value: T) => T; 20 | } 21 | 22 | interface INestedMatched extends IHigherOrderMatchReturn { 23 | else: (value: T) => IMatched; 24 | } 25 | 26 | interface IMachable extends IHigherOrderMatchReturn { 27 | then: (value: T | TFunction) => IMatched; 28 | thenMatched: (value: T | TFunction) => INestedMatched; 29 | } 30 | 31 | export default function match(value: T): IHigherOrderMatchReturn; 32 | } 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "conditional-expression", 3 | "version": "1.1.2", 4 | "description": "JavaScript functional conditional expression", 5 | "main": "dist/conditional-expression.min.js", 6 | "module": "src/index.js", 7 | "files": [ 8 | "dist/*", 9 | "src/*" 10 | ], 11 | "scripts": { 12 | "build": "webpack --progress --mode production", 13 | "lint": "eslint src test", 14 | "mocha": "NODE_ENV=test nyc mocha test/*.test.js --require @babel/register --require @babel/polyfill", 15 | "testdev": "lib=dev npm run mocha", 16 | "test": "npm run lint && npm run build && lib=prod npm run mocha" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/MartinGentleman/conditional-expression.git" 21 | }, 22 | "keywords": [ 23 | "functional", 24 | "conditional", 25 | "expression", 26 | "match", 27 | "pattern", 28 | "matching" 29 | ], 30 | "author": "Martin Novak ", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/MartinGentleman/conditional-expression/issues" 34 | }, 35 | "homepage": "https://github.com/MartinGentleman/conditional-expression#readme", 36 | "devDependencies": { 37 | "@babel/core": "^7.1.6", 38 | "@babel/polyfill": "^7.0.0", 39 | "@babel/preset-env": "^7.1.6", 40 | "@babel/register": "^7.0.0", 41 | "babel-loader": "^8.0.4", 42 | "chai": "^4.2.0", 43 | "mocha": "^5.2.0", 44 | "nyc": "^13.1.0", 45 | "path": "^0.12.7", 46 | "webpack": "^4.25.1", 47 | "webpack-cli": "^3.1.2" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Higher-order function to serve as prototype for other matching functions 3 | * @param {function} onFunction function to be used for matching functions 4 | * @param {boolean} evaluate whether condition should be evaluated 5 | * @param {*} x simple value to be matched 6 | * @returns {object} higherOrderMatch :: a -> b -> c {on: d -> e, with: d -> e, equals: d -> e, includes: d -> e, typeof: d -> e} 7 | */ 8 | const higherOrderMatch = onFunction => evaluate => x => ({ 9 | on: y => onFunction(x)(evaluate && y(x) === true), 10 | with: y => onFunction(x)(evaluate && y.test(x)), 11 | equals: y => onFunction(x)(evaluate && x === y), 12 | includes: y => onFunction(x)(evaluate && typeof x === 'string' && x.includes(y)), 13 | typeOf: y => onFunction(x)(evaluate && typeof x === y), 14 | isGreaterThan: y => onFunction(x)(evaluate && x > y), 15 | lessThan: y => onFunction(x)(evaluate && x < y), 16 | atLeast: y => onFunction(x)(evaluate && x >= y), 17 | atMost: y => onFunction(x)(evaluate && x <= y) 18 | }); 19 | 20 | /** 21 | * Matching function to replace imperative switch statement with advanced functional pattern matching expression 22 | * @param {*} x simple value to be matched 23 | * @returns {object} match: a -> {on: b -> c, with: b -> c, equals: b -> c, includes: b -> c, typeof: b -> c, else: b -> c} 24 | * @example 25 | * match(2) 26 | * .equals(1).then('number one') 27 | * .equals(2).then('number two') 28 | * .else('unknown number'); 29 | */ 30 | const match = x => ({ 31 | ...higherOrderMatch(onMatch)(true)(x), 32 | else: y => express(y)(x) 33 | }); 34 | 35 | /** 36 | * Matching function to be used within nested branch 37 | * @param {*} x simple value to be matched 38 | * @returns {object} nestedMatch: a -> {on: b -> c, with: b -> c, equals: b -> c, includes: b -> c, typeof: b -> c, else: b -> c} 39 | */ 40 | const nestedMatch = x => ({ 41 | ...higherOrderMatch(onNestedMatch)(true)(x), 42 | else: y => matched(express(y)(x)) 43 | }); 44 | 45 | /** 46 | * Once a match is made we are not processing any conditions anymore 47 | * @param {*} x simple value to be matched 48 | * @returns {object} matched: a -> {on: a -> b, with: a -> b, equals: a -> b, includes: a -> b, typeof: a -> b, else: () -> a} 49 | */ 50 | const matched = x => ({ 51 | ...higherOrderMatch(onMatched)(false)(x), 52 | else: () => x 53 | }); 54 | 55 | /** 56 | * Once a nested match is made we are not processing any conditions anymore 57 | * @param {*} x simple value to be matched 58 | * @returns {object} nestedMatched: a -> {on: a -> b, with: a -> b, equals: a -> b, includes: a -> b, typeof: a -> b, else: () -> a} 59 | */ 60 | const nestedMatched = x => ({ 61 | ...higherOrderMatch(onNestedMatched)(false)(x), 62 | else: () => matched(x) 63 | }); 64 | 65 | /** 66 | * If nested branch is under false condition match we want to ignore it 67 | * @param {*} x simple value to be matched 68 | * @returns {object} ignoreNestedMatch: a -> {on: a -> b, with: a -> b, equals: a -> b, includes: a -> b, typeof: a -> b, else: () -> a} 69 | */ 70 | const ignoreNestedMatch = x => ({ 71 | ...higherOrderMatch(onIgnoreNestedMatch)(false)(x), 72 | else: () => match(x) 73 | }); 74 | 75 | /** 76 | * Triggeres a function or just returns a value depending on type of passed expression 77 | * @param {*} y value or a function 78 | * @param {*} x in case of expression being a function, param is passed as its parameter 79 | * @returns {*} express: (function, x) -> function (x), express: function -> function (), express: x -> x 80 | * @example express('hello'); // return hello 81 | * @example express(() => console.log('hello')); // prints out 'hello' to console 82 | */ 83 | const express = y => x => typeof y === 'function' ? y(x) : y; 84 | 85 | /** 86 | * General function to evaluation matching based on a functional expression 87 | * @param {*} x simple value to be matched 88 | * @param {boolean} evaluation function used for matching 89 | * @returns {object} onMatch: a -> function -> {then: b -> c, thenMatch: b -> c} 90 | */ 91 | const onMatch = x => evaluation => ({ 92 | then: y => evaluation ? matched(express(y)(x)) : match(x), 93 | thenMatch: y => evaluation ? nestedMatch(y) : ignoreNestedMatch(x) 94 | }); 95 | 96 | /** 97 | * Makes sure that 'then' will be returning matched result 98 | * @param {*} x result of matching 99 | * @returns {object} onMatched: a -> () -> {then: () -> b, thenMatch: () -> b} 100 | */ 101 | const onMatched = x => () => ({ 102 | then: () => matched(x), 103 | thenMatch: () => nestedMatched(x) 104 | }); 105 | 106 | /** 107 | * General function to evaluate nested matches 108 | * @param {*} x simple value to be matched 109 | * @returns {object} onNestedMatch: a -> function -> {then: b -> c} 110 | */ 111 | const onNestedMatch = x => evaluation => ({ 112 | then: y => evaluation ? nestedMatched(express(y)(x)) : nestedMatch(x) 113 | }); 114 | 115 | /** 116 | * Makes sure that then will be returning result of nested match 117 | * @param {*} x result of matching 118 | * @returns {object} onNestedMatched: a -> () -> {then: () -> b} 119 | */ 120 | const onNestedMatched = x => () => ({ 121 | then: () => nestedMatched(x) 122 | }); 123 | 124 | /** 125 | * Makes sure that nested branch is not returning any result 126 | * @param {*} x simple value to be matched 127 | * @returns {object} onIgnoreNestedMatch: a -> () -> {then: () -> b} 128 | */ 129 | const onIgnoreNestedMatch = x => () => ({ 130 | then: () => ignoreNestedMatch(x) 131 | }); 132 | 133 | export default match; -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | 3 | const match = process.env.lib === 'prod' ? 4 | require('../dist/conditional-expression.min').default : 5 | require('../src').default; 6 | 7 | const param = 'this is string'; 8 | 9 | describe('Match function test.', () => { 10 | it('Match of anything should return an object.', () => { 11 | assert.isObject(match(1), 'Match is not an object.'); 12 | }); 13 | it('Then should be available on both successful and unsuccessful matches.', () => { 14 | assert.isFunction(match(1).on(() => true).then, 'On does not return then function on a match.'); 15 | assert.isFunction(match(1).on(() => false).then, 'On does not return then function without a match.'); 16 | }); 17 | it('Else should provide final evaluation result on both successful and unsuccessful matches.', () => { 18 | assert.isTrue(match(1).else(true), 'Using only else works.'); 19 | assert.isTrue(match(1).on(() => true).then(true).else(false), 'Else does not provide final evaluation on a match.'); 20 | assert.isTrue(match(1).on(() => true).then(true).else(() => false), 'Else does not provide final evaluation on a match.'); 21 | assert.isFalse(match(1).on(() => false).then(true).else(false), 'Else does not provide final evaluation without a match.'); 22 | assert.isFalse(match(1).on(() => false).then(true).else(() => false), 'Else does not provide final evaluation without a match.'); 23 | }); 24 | }); 25 | 26 | describe('\'On\' function test using evaluation based on functions.', () => { 27 | it('Then should be available on both successful and unsuccessful matches.', () => { 28 | assert.isFunction(match(1).on(x => x === 1).then, 'It does not return then function on a match.'); 29 | assert.isFunction(match(1).on(x => x === 2).then, 'It does not return then function without a match.'); 30 | }); 31 | it('\'On\' should match based on a provided function.', () => { 32 | assert.isTrue(match(1).on(x => x === 1).then(true).else(false), 'It does not correctly match.'); 33 | assert.isFalse(match(1).on(x => x === 2).then(true).else(false), 'It does not correctly match.'); 34 | }); 35 | it('\'On\' on a function returning anything but true should evaluate as false.', () => { 36 | assert.isFalse(match(1).on(() => 'string').then(true).else(false), 'It on string returns true.'); 37 | assert.isFalse(match(1).on(() => 1).then(true).else(false), 'It on number returns true.'); 38 | assert.isFalse(match(1).on(() => null).then(true).else(false), 'It on null returns true.'); 39 | }); 40 | }); 41 | 42 | describe('\'With\' function test using evaluation based on regular expressions.', () => { 43 | it('Then should be available on both successful and unsuccessful matches.', () => { 44 | assert.isFunction(match('string').with(/[a-z]/).then, 'It does not return then function on a match.'); 45 | assert.isFunction(match('string').with(/[0-9]/).then, 'It does not return then function without a match.'); 46 | }); 47 | it('\'With\' should match based on provided regular expression.', () => { 48 | assert.isTrue(match('string').with(/[a-z]/).then(true).else(false), 'It does not correctly match.'); 49 | assert.isFalse(match('string').with(/[0-9]/).then(true).else(false), 'It does not correctly match.'); 50 | }); 51 | }); 52 | 53 | describe('\'Equals\' function test using evaluation based on strict equal.', () => { 54 | it('Then should be available on both successful and unsuccessful matches.', () => { 55 | assert.isFunction(match('string').equals('string').then, 'It does not return then function on a match.'); 56 | assert.isFunction(match(1).equals(2).then, 'It does not return then function without a match.'); 57 | }); 58 | it('\'With\' should match based on provided regular expression.', () => { 59 | assert.isTrue(match('string').equals('string').then(true).else(false), 'It does not correctly match.'); 60 | assert.isFalse(match(1).equals(2).then(true).else(false), 'It does not correctly match.'); 61 | }); 62 | }); 63 | 64 | describe('\'Includes\' function test using evaluation based on strict equal.', () => { 65 | it('Then should be available on both successful and unsuccessful matches.', () => { 66 | assert.isFunction(match('string').includes('st').then, 'It does not return then function on a match.'); 67 | assert.isFunction(match('string').includes('petra').then, 'It does not return then function without a match.'); 68 | }); 69 | it('\'Includes\' should match based on provided string.', () => { 70 | assert.isTrue(match('string').includes('st').then(true).else(false), 'It does not correctly match.'); 71 | assert.isFalse(match('string').includes('martin').then(true).else(false), 'It does not correctly match.'); 72 | }); 73 | it('\'Includes\' always evaluates as false if a string is not provided to original match.', () => { 74 | assert.isFalse(match(1).includes('string').then(true).else(false), 'It does not evaluate as false if string is not provided.'); 75 | }); 76 | }); 77 | 78 | describe('\'TypeOf\' function test using evaluation based on strict equal.', () => { 79 | it('Then should be available on both successful and unsuccessful matches.', () => { 80 | assert.isFunction(match(1).typeOf('number').then, 'It does not return then function on a match.'); 81 | assert.isFunction(match(1).typeOf('string').then, 'It does not return then function without a match.'); 82 | }); 83 | it('\'TypeOf\' should match based on provided regular expression.', () => { 84 | assert.isTrue(match(1).typeOf('number').then(true).else(false), 'It does not correctly match.'); 85 | assert.isFalse(match(1).typeOf('string').then(true).else(false), 'It does not correctly match.'); 86 | }); 87 | }); 88 | 89 | describe('\'isGreaterThan\' function test comparing sizes.', () => { 90 | it('Then should be available on both successful and unsuccessful matches.', () => { 91 | assert.isFunction(match(2).isGreaterThan(1).then, 'It does not return then function on a match.'); 92 | assert.isFunction(match('abc').isGreaterThan('ab').then, 'It does not return then function without a match.'); 93 | }); 94 | it('\'isGreaterThan\' should match based on provided value.', () => { 95 | assert.isTrue(match(2).isGreaterThan(1).then(true).else(false), 'It does not correctly match.'); 96 | assert.isFalse(match(2).isGreaterThan(2).then(true).else(false), 'It does not correctly match.'); 97 | assert.isFalse(match(2).isGreaterThan(3).then(true).else(false), 'It does not correctly match.'); 98 | assert.isTrue(match('abc').isGreaterThan('ab').then(true).else(false), 'It does not correctly match.'); 99 | assert.isFalse(match('abc').isGreaterThan('abc').then(true).else(false), 'It does not correctly match.'); 100 | assert.isFalse(match('abc').isGreaterThan('abcd').then(true).else(false), 'It does not correctly match.'); 101 | }); 102 | }); 103 | 104 | describe('\'lessThan\' function test comparing sizes.', () => { 105 | it('Then should be available on both successful and unsuccessful matches.', () => { 106 | assert.isFunction(match(2).lessThan(1).then, 'It does not return then function on a match.'); 107 | assert.isFunction(match('abc').lessThan('ab').then, 'It does not return then function without a match.'); 108 | }); 109 | it('\'lessThan\' should match based on provided value.', () => { 110 | assert.isTrue(match(2).lessThan(3).then(true).else(false), 'It does not correctly match.'); 111 | assert.isFalse(match(2).lessThan(2).then(true).else(false), 'It does not correctly match.'); 112 | assert.isFalse(match(2).lessThan(1).then(true).else(false), 'It does not correctly match.'); 113 | assert.isTrue(match('abc').lessThan('abcd').then(true).else(false), 'It does not correctly match.'); 114 | assert.isFalse(match('abc').lessThan('abc').then(true).else(false), 'It does not correctly match.'); 115 | assert.isFalse(match('abc').lessThan('ab').then(true).else(false), 'It does not correctly match.'); 116 | }); 117 | }); 118 | 119 | describe('\'atLeast\' function test comparing sizes.', () => { 120 | it('Then should be available on both successful and unsuccessful matches.', () => { 121 | assert.isFunction(match(2).atLeast(1).then, 'It does not return then function on a match.'); 122 | assert.isFunction(match('abc').atLeast('ab').then, 'It does not return then function without a match.'); 123 | }); 124 | it('\'atLeast\' should match based on provided value.', () => { 125 | assert.isTrue(match(2).atLeast(2).then(true).else(false), 'It does not correctly match.'); 126 | assert.isTrue(match(2).atLeast(2).then(true).else(false), 'It does not correctly match.'); 127 | assert.isFalse(match(2).atLeast(3).then(true).else(false), 'It does not correctly match.'); 128 | assert.isTrue(match('abc').atLeast('ab').then(true).else(false), 'It does not correctly match.'); 129 | assert.isTrue(match('abc').atLeast('abc').then(true).else(false), 'It does not correctly match.'); 130 | assert.isFalse(match('abc').atLeast('abcd').then(true).else(false), 'It does not correctly match.'); 131 | }); 132 | }); 133 | 134 | describe('\'atMost\' function test comparing sizes.', () => { 135 | it('Then should be available on both successful and unsuccessful matches.', () => { 136 | assert.isFunction(match(2).atMost(1).then, 'It does not return then function on a match.'); 137 | assert.isFunction(match('abc').atMost('ab').then, 'It does not return then function without a match.'); 138 | }); 139 | it('\'atMost\' should match based on provided value.', () => { 140 | assert.isTrue(match(2).atMost(3).then(true).else(false), 'It does not correctly match.'); 141 | assert.isTrue(match(2).atMost(2).then(true).else(false), 'It does not correctly match.'); 142 | assert.isFalse(match(2).atMost(1).then(true).else(false), 'It does not correctly match.'); 143 | assert.isTrue(match('abc').atMost('abcd').then(true).else(false), 'It does not correctly match.'); 144 | assert.isTrue(match('abc').atMost('abc').then(true).else(false), 'It does not correctly match.'); 145 | assert.isFalse(match('abc').atMost('ab').then(true).else(false), 'It does not correctly match.'); 146 | }); 147 | }); 148 | 149 | describe('Various combinations with deep chains are possible.', () => { 150 | it('It should match correctly under different combinations.', () => { 151 | assert.strictEqual(match(1).typeOf('number').then('int').equals('string').then('str').else('na'), 152 | 'int', 'It does not evaluate correctly with chaining.'); 153 | }); 154 | it('It should return the first match and ignore correct matches afterwards.', () => { 155 | assert.strictEqual(match(1).typeOf('number').then('type').equals(1).then('equals').else('na'), 156 | 'type', 'It does not evaluate correctly with chaining.'); 157 | }); 158 | it('Getting result from match surrounded by false matches should work.', () => { 159 | assert.isTrue(match(param).includes('notstring').then(false).includes('this').then(true).includes('notstring').then(false).else(false)); 160 | }); 161 | }); 162 | 163 | describe('thenMatch allows for nesting.', () => { 164 | it('Getting result from nested else should work.', () => { 165 | assert.isTrue(match(param).includes('string').thenMatch(param).else(true).else(false)); 166 | }); 167 | it('Getting result from nested match should work.', () => { 168 | assert.isTrue(match(param).includes('string').thenMatch(param).includes('this').then(true).else(false).else(false)); 169 | }); 170 | it('Getting result from nested match sorounded by false matches should work.', () => { 171 | assert.isTrue(match(param).includes('string').thenMatch(param).includes('notstring').then(false).includes('this').then(true).includes('notstring').then(false).else(false).else(false)); 172 | }); 173 | it('Getting result from match afted false nested match branch should work.', () => { 174 | assert.isTrue(match(param).includes('notstring').thenMatch(param).includes('this').then(false).else(false).includes('string').then(true).else(false)); 175 | }); 176 | it('Getting result from positive match followed by positive nested match branch should work.', () => { 177 | assert.isTrue(match(param).includes('string').then(true).includes('this').thenMatch(param).includes('string').then(false).else(false).includes('string').then(false).else(false)); 178 | }); 179 | }); 180 | 181 | describe('Deeper nest matching through using match function as argument to then function.', () => { 182 | it('Passing result of another match as argument to then function works.', () => { 183 | assert.isTrue(match(param).includes('string').then(() => match(param).includes('this').then(true).else(false)).else(false)); 184 | assert.isTrue(match(param).includes('string').then(() => match(param).includes('notthis').then(false).else(true)).else(false)); 185 | assert.isTrue(match(param).includes('notstring').then(() => match(param).includes('this').then(false).else(false)).else(true)); 186 | }); 187 | it('Passing result of another match as argument to then function with thenMatch branch works.', () => { 188 | assert.isTrue(match(param).includes('string').thenMatch(param).includes('this').then(() => match(param).includes('string').then(true).else(false)).else(false).else(false)); 189 | }); 190 | }); -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: './src/index.js', 5 | output: { 6 | path: path.resolve(__dirname, 'dist'), 7 | filename: 'conditional-expression.min.js', 8 | library: 'conditionalExpression', 9 | libraryTarget: 'umd', 10 | globalObject: 'this' 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.js$/, 16 | exclude: /node_modules/, 17 | use: 'babel-loader' 18 | } 19 | ] 20 | }, 21 | devtool: 'source-map' 22 | }; --------------------------------------------------------------------------------