{"id":22903039,"url":"https://github.com/amekusa/flex-params","last_synced_at":"2025-04-01T07:20:05.279Z","repository":{"id":57238211,"uuid":"275195137","full_name":"amekusa/flex-params","owner":"amekusa","description":"Multiple signatures for a function","archived":false,"fork":false,"pushed_at":"2021-06-28T03:07:43.000Z","size":101,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-07T10:38:43.565Z","etag":null,"topics":["function","function-signatures","npm","overloading","parameters"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amekusa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-06-26T16:01:36.000Z","updated_at":"2021-06-28T03:07:46.000Z","dependencies_parsed_at":"2022-08-26T15:11:48.525Z","dependency_job_id":null,"html_url":"https://github.com/amekusa/flex-params","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amekusa%2Fflex-params","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amekusa%2Fflex-params/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amekusa%2Fflex-params/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amekusa%2Fflex-params/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amekusa","download_url":"https://codeload.github.com/amekusa/flex-params/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246598189,"owners_count":20802975,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["function","function-signatures","npm","overloading","parameters"],"created_at":"2024-12-14T02:31:25.523Z","updated_at":"2025-04-01T07:20:05.250Z","avatar_url":"https://github.com/amekusa.png","language":"JavaScript","readme":"- **v3.1.0**\n\t- Support simpler syntax\n\t- Support pipe separated multiple types\n- **v3.0.1** [Fix] Broken ES module loading since 3.0.0 has been fixed.\n- **v3.0.0** The error handling API changed.\n\n---\n\n[![Build Status](https://travis-ci.com/amekusa/flex-params.svg?branch=master)](https://travis-ci.com/amekusa/flex-params) [![npm](https://img.shields.io/badge/dynamic/json?label=npm%0Apackage\u0026query=%24%5B%27dist-tags%27%5D%5B%27latest%27%5D\u0026url=https%3A%2F%2Fregistry.npmjs.org%2Fflex-params%2F)](https://www.npmjs.com/package/flex-params)\n\n**flex-params** is a tiny, but powerful utility for writing a function that has **multiple signatures**.\n\nAs you know, JavaScript doesn't support **function overloading** like this:\n```js\nfunction foo(X)    { /* ... */ }\nfunction foo(X, Y) { /* ... */ } // This makes the 1st foo() not callable\n```\n\nYes, still you can do the same kind of thing with default parameters most of the time. But if you want more flexibility or scalability, flex-params allows you to define **multiple combinations of parameters** for a single function.\n\n- [Getting Started](#getting-started)\n- [Usage](#usage)\n  - [Defining a pattern of parameters](#defining-a-pattern-of-parameters)\n    - [Default Values](#default-values)\n  - [Let's see how it works](#lets-see-how-it-works)\n  - [More Example](#more-example)\n  - [Advanced Usage](#advanced-usage)\n  - [Error Handling](#error-handling)\n- [Appendix: Extra Types](#appendix-extra-types)\n\n## Getting Started\nInstall it with NPM:\n```sh\nnpm i flex-params\n```\n\nAnd `require()` it:\n\n```js\nconst flexParams = require('flex-params');\n```\n\nor `import` it as an ES module:\n\n```js\nimport flexParams from 'flex-params';\n```\n\n## Usage\n\nIn your function, pass an array of the arguments to `flexParams()` with any number of **patterns of parameters (a.k.a. \"signatures\")** you desired.\n\n```js\n// Example Code\nfunction foo(...args) {\n  var result = {};\n\n  flexParams(args, [\n    { X:'string', Y:'int' },           // pattern #0\n    { X:'string', Z:'bool', Y:'int' }, // pattern #1\n    { Z:'bool', Y:'int', X:'string' }, // pattern #2\n    ...                                // more patterns\n  ], result);\n\n  return result;\n}\n\nvar r = foo('blah', 42);          // { X:'blah',   Y:42 }\nvar r = foo('blahh', true, 7);    // { X:'blahh',  Y:7,  Z:true }\nvar r = foo(false, 11, 'blaahh'); // { X:'blaahh', Y:11, Z:false }\n```\nIn the code above, `args` is the array of arguments.\n\nThe 2nd parameter of `flexParams()` is an array of the *patterns*.  \n`flexParams()` tries to find **the most suitable pattern** in the array for `args` by comparing the type strings defined in each pattern with actual types of `args`.\n\nOnce it is found, each value of `args` is stored into `result` \u003csmall\u003e( the 3rd parameter )\u003c/small\u003e as its properties.\n\nIf you prefer simpler syntax, you can also write like this:\n\n```js\nvar result = flexParams(args, [\n  ... // patterns\n]);\n```\n\n### Defining a pattern of parameters\nEach pattern must be a plain object that has one of some specific formats.  \nThe most basic format is like this:\n\n```js\n// Pattern Definition\n{\n  param_1st: '\u003ctype\u003e',\n  param_2nd: '\u003ctype\u003e',\n  ...\n  param_nth: '\u003ctype\u003e'\n}\n```\n\n`'\u003ctype\u003e'` is a string representation of *datatype* (ex. `'bool'`, `'string'`, `'array'`, `'object'`, etc. ) for each param, like this:\n\n```js\n{ foo:'string', bar:'boolean' }\n```\n\nThis pattern means:\n- The 1st param is `foo`, and it must be a string\n- The 2nd param is `bar`, and it must be a boolean\n\nYou can also write **multiple types** separated by `|` (pipe) likes this:\n\n```js\n{ foo:'string|number|boolean' }\n```\n\nThis parameter matches with a string, a number or a boolean.\n\n#### Default Values\nInstead of just a type string, you can also use an **array** to define the default value:\n\n```js\n{ foo:'string', bar:['boolean', false] }\n```\n\nNow the 2nd param `bar` turned to **optional**. The default value is `false`.\n\nThe pattern that contains optional parameters can be considered suitable even if **a fewer number of arguments** supplied. And the missing arguments will be filled with the default values of respective params.\n\n### How does it work?\n```js\n// Example Code #1\nfunction foo(...args) {\n  let result = {};\n\n  flexParams(args, [\n    { flag:['boolean', false] },         // pattern #0\n    { str:'string', num:['number', 1] }, // pattern #1\n    { num:'number', flag:'boolean' }     // pattern #2\n  ], result);\n\n  return result;\n}\n```\n\nYou can see 3 patterns in the above example.  \nLet's test it by passing various combinations of arguments:\n```js\nlet test1 = foo();        // No argument\nlet test2 = foo('ABC');   // A string\nlet test3 = foo(8, true); // A number, A boolean\n\nconsole.log('Test 1:', test1);\nconsole.log('Test 2:', test2);\nconsole.log('Test 3:', test3);\n```\n\nAnd these are the resulting objects:\n```js\nTest 1: { flag: false }\nTest 2: { str: 'ABC', num: 1 }\nTest 3: { num: 8, flag: true }\n```\n\nNow you can see:\n- The test1 matched with pattern #0\n- The test2 matched with pattern #1\n- The test3 matched with pattern #2\n\n### More Example\n```js\n// Example Code #2\nconst flexParams = require('flex-params');\n\nclass User {\n  constructor(...args) {\n    flexParams(args, [\n      // patterns\n      { firstName:'string', age:'int' },\n      { firstName:'string', lastName:'string', age:'int' },\n      { id:'int' },\n      { login:'string', pass:Password }\n\n    ], this); // Stores the args into 'this'\n  }\n}\n\nclass Password {\n  constructor(key) {\n    this.key = key;\n  }\n}\n\n//// Test ////////////\nlet thomas = new User('Thomas', 20);\nlet john   = new User('John', 'Doe', 30);\nlet user1  = new User(1000);\nlet user2  = new User('d4rk10rd', new Password('asdf'));\n\nconsole.log(thomas);\nconsole.log(john);\nconsole.log(user1);\nconsole.log(user2);\n```\n\nConsole outputs:\n```js\nUser { firstName: 'Thomas', age: 20 }\nUser { firstName: 'John', lastName: 'Doe', age: 30 }\nUser { id: 1000 }\nUser { login: 'd4rk10rd', pass: Password { key: 'asdf' } }\n```\n\nAs you can see this example, you can pass `this` to the 3rd parameter of `flexParams()`. This way is useful for **initializing the instance** in the class constructor.\n\n### Advanced Usage\n\nAbout the 3rd parameter of `flexParams()`, it accepts not only an object but also a **function**.  \n\n```js\nfunction foo(...args) {\n  flexParams(args, [\n    { flag:['boolean', false] },         // pattern #0\n    { str:'string', num:['number', 1] }, // pattern #1\n    { num:'number', flag:'boolean' }     // pattern #2\n\n  ], (result, pattern) =\u003e { // Receiver Callback\n    console.log('result:',  result);\n    console.log('pattern:', pattern);\n  });\n  // Test ////////\n  foo('XYZ', 512);\n}\n```\n\nConsole outputs:\n\n```js\nresult: { str: 'XYZ', num: 512 }\npattern: 1\n```\n\nLet's call this function a **receiver callback**. Receiver callback runs immediately after `flexParams()` finished processing `args`.\n\nReceiver callback takes 2 parameters: `result` and `pattern`.  \n `result` is an object that contains all the `args` as its properties. `pattern` is **the index number of the matched pattern**, which is `1` \u003csmall\u003e( means pattern #1 )\u003c/small\u003e at this time.  \nThis index is useful if you want to do some different things for each pattern with `switch-case` or `if-else-if`, like this:\n\n```js\nfunction foo(...args) {\n  return flexParams(args, [\n    { flag:['boolean', false] },         // pattern #0\n    { str:'string', num:['number', 1] }, // pattern #1\n    { num:'number', flag:'boolean' }     // pattern #2\n\n  ], (result, pattern) =\u003e { // Receiver Callback\n    switch (pattern) { // Do stuff for each pattern\n      case 0: return 'The first pattern matched.';\n      case 1: return 'The second pattern matched.';\n      case 2: return 'The last pattern matched.';\n    }\n  });\n}\n//// Test ////////\nconsole.log( foo('XYZ', 512)   ); // 'The second pattern matched.'\nconsole.log( foo(65535, false) ); // 'The last pattern matched.'\nconsole.log( foo()             ); // 'The first pattern matched.'\n```\n\n### Error Handling\n\nIf all the given patterns didn't match for the arguments, `flexParams()` returns `false`. But there is also another way to handle this situation. **The 4th parameter: `fallback`**.\n\n`fallback` can be:\n\n- a) **a callback**,  \n- b) **an object**, or  \n- c) **any other type of value** \u003csmall\u003e( except for `undefined` )\u003c/small\u003e.\n\na) If you passed a callback, it is called when all the given patterns mismatched.  \nTha callback receives **an object** as its parameter with these properties:\n- **args**: The original array of arguments\n- **patterns**: The array of all the patterns\n- **receiver**: The receiver object or function passed to the 3rd parameter\n- **error**: An Exception object ( `flexParams.InvalidArgument` )\n\nb) You can pass an plain object as the `fallback` with these optional properties:\n- **log**: A string to be sent to `console.log()`\n- **warn**: A string to be sent to `console.warn()`\n- **error**: A string to be sent to `console.error()`\n- **throw**: Any type of value to be thrown as an exception\n  - If you set `true` , an Exception object is thrown ( `flexParams.InvalidArgument` )\n\nc) Any other type of value as the `fallback` , is returned straightly by `flexParams()` if all the given patterns mismatched.\n\n## Appendix: Extra Types\n\nflex-params supports some special types in addition to [JavaScript's builtin datatypes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures).\n\n| Type | Description |\n|-----:|:------------|\n| `bool` | Alias of `boolean` |\n| `int`, `integer` | Matches for an integer |\n| `float`, `double` | Alias of `number` |\n| `array` | Matches for an array |\n| `iterable` | Matches for an array or an array-like object |\n| `primitive` | Matches for a primitive type value |\n| `any`, `mixed` | Matches for any type of value |\n| A class constructor | Matches for the class instances |\n\n---\n\n\u0026copy; 2020 [amekusa](https://amekusa.com)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famekusa%2Fflex-params","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famekusa%2Fflex-params","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famekusa%2Fflex-params/lists"}