{"id":17508175,"url":"https://github.com/rse/ducky","last_synced_at":"2025-04-13T15:53:22.351Z","repository":{"id":12841307,"uuid":"15516893","full_name":"rse/ducky","owner":"rse","description":"Duck-Typed Value Handling for JavaScript","archived":false,"fork":false,"pushed_at":"2023-01-22T16:59:13.000Z","size":22708,"stargazers_count":72,"open_issues_count":2,"forks_count":7,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-06T00:43:00.852Z","etag":null,"topics":["duck","javascript","json","parameter","query","select","typing"],"latest_commit_sha":null,"homepage":"http://duckyjs.com/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-12-29T23:44:41.000Z","updated_at":"2023-08-23T09:06:39.000Z","dependencies_parsed_at":"2023-02-12T16:31:20.855Z","dependency_job_id":null,"html_url":"https://github.com/rse/ducky","commit_stats":null,"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rse%2Fducky","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rse%2Fducky/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rse%2Fducky/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rse%2Fducky/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rse","download_url":"https://codeload.github.com/rse/ducky/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248621489,"owners_count":21134863,"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":["duck","javascript","json","parameter","query","select","typing"],"created_at":"2024-10-20T04:12:38.173Z","updated_at":"2025-04-13T15:53:22.300Z","avatar_url":"https://github.com/rse.png","language":"JavaScript","readme":"\nDucky \u0026mdash; [duckyjs.com](http://duckyjs.com/)\n================================================\n\n**Duck-Typed Value Handling for JavaScript**\n\n\u003cp/\u003e\n\u003cimg src=\"https://nodei.co/npm/ducky.png?downloads=true\u0026stars=true\" alt=\"\"/\u003e\n\n\u003cp/\u003e\n\u003cimg src=\"https://david-dm.org/rse/ducky.png\" alt=\"\"/\u003e\n\nAbstract\n--------\n\nDucky is a small Open-Source JavaScript library, providing Duck-Typed\nValue Validation, Value Selection and Flexible Function Parameter\nHandling. It can be used in [Node.js](http://nodejs.org/) based server\nand browser based client environments.\n\nGetting Ducky\n----------------\n\nYou can conveniently get Ducky in various ways:\n\n- NPM: install as server component via the Node Package Manager:\u003cbr/\u003e\n  `$ npm install ducky`\n\n- Git: directly clone the official repository:\u003cbr/\u003e\n  `$ git clone https://github.com/rse/ducky.git`\n\n- cURL: download only the main file from the repository:\u003cbr/\u003e\n  `$ curl -O https://raw.github.com/rse/ducky/master/lib/ducky.browser.js`\n\nAPI\n---\n\nDucky provides the following API:\n\n#### ducky.version = { major: Number, minor: Number, micro: Number, date: Number }\n\nThe version of Ducky, provided as a tuple of separate pieces, for easy comparison.\n\n    if (!(ducky.version.major \u003e= 2 \u0026\u0026 ducky.version.minor \u003e= 0))\n        throw new Error(\"need at least Ducky 2.0.0\");\n\n#### ducky.register(name: String, type: Function): void\n\nRegister under `name` an additional host or application type,\nrepresented by the constructor function `type`. This allows\n`ducky.validate()` and `ducky.params()` to validate objects\nwhich are instances of the type.\n\n    var Foo = function () { ... };\n    ducky.register(\"app.Foo\", Foo);\n    ducky.validate(new Foo(), \"app.Foo\");\n\nThe following host types are pre-registered by default (if actually\nexisting in the particular native or \"polyfilled\" host environment):\n`Object`, `Boolean`, `Number`, `String`, `Function`, `RegExp`, `Array`,\n`Date`, `Error`, `Set`, `Map`, `WeakMap`, `Promise`, `Proxy` and\n`Iterator`.\n\n#### ducky.unregister(name: String): void\n\nUnregisters the additional host or application type, which was previously\nregistered under `name` with `ducky.register()`.\n\n    ducky.unregister(\"app.Foo\");\n\n#### ducky.select(object: Object, path: String, value?: Object): Object\n\nDereference into (and this way subset) `object` according to the\n`path` specification and either return the dereferenced value or\nset a new `value`. Object has to be a hash or array object. The\n`path` argument has to follow the following grammar (which is a\ndirect JavaScript dereferencing syntax):\n\nLHS          |     | RHS\n------------ | --- | -----------------------------\npath         | ::= | segment segment\\*\nsegment      | ::= | bybareword \u0026#124; bykey\nbybareword   | ::= | `\".\"`? identifier\nbykey        | ::= | `\"[\"` key `\"]\"`\nidentifier   | ::= | `/[_a-zA-Z$][_a-zA-Z$0-9]*\u003e/`\nkey          | ::= | number \u0026#124; squote \u0026#124; dquote\nnumber       | ::= | `/[0-9]+/`\ndquote       | ::= | `/\"(?:\\\\\"|.)*?\"/`\nsquote       | ::= | `/'(?:\\\\'|.)*?'/`\n\nSetting the `value` to `undefined` effectively removes the\ndereferenced value. If the dereferenced parent object is a hash, this\nmeans the value is `delete`'ed from it. If the dereferenced parent\nobject is an array, this means the value is `splice`'ed out of it.\n\n    ducky.select({ foo: { bar: { baz: [ 42, 7, \"Quux\" ] } } },\n        \"foo['bar'].baz[2]\") // \u0026rarr; \"Quux\"\n\nIn case caching of the internally compiled Abstract Syntax Tree (AST)\nis not wishes, you can perform the compile and execute steps\nof `ducky.select` individually:\n\n##### ducky.select.compile(path: String): Object\n\nCompile the selection specification `path` into an AST.\n\n##### ducky.select.execute(object: Object, ast: Object, value?: Object): Object\n\nSelect from `object` a value via `ast` and either return it or set it to the new value `value`.\n\n#### ducky.validate(object: Object, spec: String, errors?: String[]): Boolean\n\nValidate an arbitrary nested JavaScript object `object` against the\nspecification `spec`. The specification `spec` has to be a string\nfollowing the following grammar (which is a mixture of JSON-like\nstructure and RegExp-like quantifiers):\n\nLHS          |     | RHS\n------------ | --- | -----------------------------\nspec         | ::= | not \u0026#124; alt \u0026#124; hash \u0026#124; array \u0026#124; any \u0026#124; regexp \u0026#124; primary \u0026#124; class\nnot          | ::= | `\"!\"` spec\nalt          | ::= | `\"(\"` spec (`\"`\u0026#124;`\"` spec)\\* `\")\"`\nhash         | ::= | `\"{\"` (key arity? `\":\"` spec (`\",\"` key arity? `\":\"` spec)\\*)? `\"}\"`\narray        | ::= | `\"[\"` (spec arity? (`\",\"` spec arity?)\\*)? `\"]\"`\narity        | ::= | `\"?\"` \u0026#124; `\"*\"` \u0026#124; `\"+\"` \u0026#124; `\"{\"` number `\",\"` (number \u0026#124; `\"oo\"`) `\"}\"`\nnumber       | ::= | `/^[0-9]+$/`\nkey          | ::= | `/^[_a-zA-Z$][_a-zA-Z$0-9]*$/` \u0026#124; `\"@\"`\nany          | ::= | `\"any\"`\nregexp       | ::= | `/^\\/(?:\\\\\\/|.)*\\/$/`\nprimary      | ::= | `/^(?:null|undefined|boolean|number|string|function|object)$/`\nclass        | ::= | `/^[_a-zA-Z$][_a-zA-Z$0-9]\\*(?:\\.[_a-zA-Z$][_a-zA-Z$0-9]\\*)\\*$/`\n\nThe special key `@` can be used to match an arbitrary hash element key.\n\n    ducky.validate({ foo: \"Foo\", bar: \"Bar\", baz: [ 42, 7, \"Quux\" ] },\n        \"{ foo: string, bar: any, baz: [ number+, string* ], quux?: any }\") // \u0026arr; true\n\nIf an empty `errors` array is given, use it to assemble detailed error\nmessages in case of a validation failure.\n\nIn case caching of the internally compiled Abstract Syntax Tree (AST)\nis not wishes, you can perform the compile and execute steps\nof `ducky.validate` individually:\n\n##### ducky.validate.compile(spec: String): Object\n\nCompile the validation specification `spec` into an AST.\n\n##### ducky.validate.execute(object: Object, ast: Object, errors?: String[]): Boolean\n\nValidate `object` against `ast` and return `true` in case it validates.\nIf an empty `errors` array is given, use it to assemble detailed error\nmessages in case of a validation failure.\n\n#### ducky.params(name: String, args: Object[], spec: Object): Object\n\nHandle positional and named function parameters by processing a\nfunction's `arguments` array. Parameter `name` is the name of the\nfunction for use in exceptions in case of invalid parameters. Parameter\n`args` usually is the JavaScript `arguments` pseudo-array of a function.\nParameter `spec` is the parameter specification: each key is the name\nof a parameter and the value has to be an `Object` with the following\npossible fields: `pos` for the optional position in case of positional\nusage, `def` for the default value (of not required and hence optional\nparameters), `req` to indicate whether the parameter is required and\n`valid` for type validation (a validation specification string accepted\nby the `validate\u003e()` method).\n\n    function config () {\n        var params = ducky.params(\"config\", arguments, {\n            scope: { pos: 0, req: true,      valid: \"boolean\"           },\n            key:   { pos: 1, req: true,      valid: /^[a-z][a-z0-9_]*$/ },\n            value: { pos: 2, def: undefined, valid: \"object\"            },\n            force: {         def: false,     valid: \"boolean\"           }\n        });\n        var result = cfg_get(params.scope, params.key);\n        if (typeof params.value !== \"undefined\")\n            cfg_set(params.scope, params.key, params.value, params.force);\n        return result;\n    }\n    var value = config(\"foo\", \"bar\");\n    config(\"foo\", \"bar\", \"quux\");\n    config({ scope: \"foo\", key: \"bar\", value: \"quux\", force: true });\n\n#### ducky.options(spec: Object, options?: Object): Object\n\nManage configuration option objects. Parameter `spec` is the option\nobject specification: each key is the name of a parameter (or a\nsub-path) and the value has to be an `Array` with a type specification\naccepted by the `validate()` method as its first element and optionally\na default value as the second element. If no default value is given\nfor an option, it has to exist on initial value merging. Value\nmerging is performed either when the `options` parameter is\ngiven or method `merge(options: Object): Object` is called\non the resulting option object.\n\n    function config (options) {\n        var options = ducky.options({\n            foo:      [ \"string\"           ],\n            bar:      [ \"boolean\", false   ],\n            quux:     [ \"number\",  1.2     ],\n            sub: {\n                foo:  [ \"string\",  \"dummy\" ],\n                bar:  [ \"boolean\", false   ],\n                quux: [ \"number\",  2.4     ]\n            }\n        });\n        options.merge({ foo: \"bar\", sub: { bar: true } })\n        options.merge({ sub: { quux: 4.8 } })\n    }\n\nLicense\n-------\n\nCopyright (c) 2010-2023 Dr. Ralf S. Engelschall (http://engelschall.com/)\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frse%2Fducky","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frse%2Fducky","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frse%2Fducky/lists"}