{"id":19727354,"url":"https://github.com/noeldemartin/utils","last_synced_at":"2025-09-02T16:40:21.039Z","repository":{"id":57131723,"uuid":"313412946","full_name":"NoelDeMartin/utils","owner":"NoelDeMartin","description":"My JavaScript utilities","archived":false,"fork":false,"pushed_at":"2024-10-06T03:36:53.000Z","size":1162,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-13T14:44:23.753Z","etag":null,"topics":["javascript-utilities"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NoelDeMartin.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-16T19:59:00.000Z","updated_at":"2024-08-13T08:37:30.000Z","dependencies_parsed_at":"2024-06-09T09:46:55.137Z","dependency_job_id":"25ff5e26-b590-4b4d-bac4-7856ba95c519","html_url":"https://github.com/NoelDeMartin/utils","commit_stats":{"total_commits":188,"total_committers":2,"mean_commits":94.0,"dds":0.3085106382978723,"last_synced_commit":"318128e0b54bb59e069db2b3df0e23f8b993d53b"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoelDeMartin%2Futils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoelDeMartin%2Futils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoelDeMartin%2Futils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoelDeMartin%2Futils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NoelDeMartin","download_url":"https://codeload.github.com/NoelDeMartin/utils/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224193153,"owners_count":17271238,"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":["javascript-utilities"],"created_at":"2024-11-11T23:38:19.295Z","updated_at":"2025-04-30T00:32:51.894Z","avatar_url":"https://github.com/NoelDeMartin.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JavaScript Utilities ![CI](https://github.com/NoelDeMartin/utils/actions/workflows/ci.yml/badge.svg)\n\nThese are some JavaScript utilities I use in different projects. If you want to use them as well, you're most welcome. You can install the package with:\n\n```sh\nnpm install @noeldemartin/utils\n```\n\n## Helpers\n\nThere is a bunch of helpers I've been reusing across projects, and I wanted to get them in one place to abide by the DRY principle (Don't Repeat Yourself). They consist of simple operations such as converting a string to camelCase, checking if an element exists within an array, etc.\n\nThe best way to check these out is by looking at the test files within the [src/helpers/](src/helpers/) folder.\n\n### MagicObject\n\nOne particularly interesting helper is `MagicObject`. I've found myself using this pattern ever more often, so I encapsulated it in this class. The idea is that taking advantage of [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) objects, and a using [an obscure property of JavaScript constructors](https://262.ecma-international.org/5.1/#sec-13.2.2), we can use [PHP's Magic Methods](https://www.php.net/manual/en/language.oop5.magic.php) in JavaScript:\n\n```js\nclass MyClass extends MagicObject {\n\n    protected __get(property: string) {\n        if (property === 'foo') {\n            return 'Foo works!';\n        }\n\n        return undefined;\n    }\n\n}\n\nconst myObject = new MyClass();\n\nconsole.log(myObject.foo); // prints \"Foo works!\"\nconsole.log(myObject.bar); // prints undefined\n```\n\nTake a look at the [source code](./src/helpers/MagicObject.ts) and [tests](./src/helpers/MagicObject.test.ts) if you're interested to learn more!\n\n## Fluent API\n\nI strive to write readable code, and I wasn't happy with combining my own helpers with built-in methods. There is nothing in the fluent API that's not implemented in some helper, this is all about readability.\n\nFor example, this is the kind of code I'd write often:\n\n```js\nconst items = ['my', 'array', 'of', 'cool', 'array', 'items'];\n\nreturn arrayUnique(items.filter((item) =\u003e item.startsWith('a')));\n```\n\nWhere `arrayUnique` is a custom helper (which you can find in this package), and `Array.filter` is a native method. My only option was to combine method chaining with nesting function calls. And the end result wasn't too readable.\n\nNow, with the fluent API I created in this package, I can write it like this:\n\n```js\nreturn fluent(['my', 'array', 'of', 'cool', 'array', 'items']) // or, to be explicit, arr([...])\n    .filter((item) =\u003e item.startsWith('a'))\n    .unique()\n    .toArray(); // returns ['array']\n```\n\nLike this, I'm able to combine native methods with custom helpers using method chaining.\n\nAnd that's not only with arrays, for example with strings I can do:\n\n```js\nreturn fluent('foo-bar') // or, to be explicit, str('...')\n    .replace('foo', 'hello')\n    .replace('bar', 'world')\n    .toStudlyCase()\n    .toString(); // returns \"HelloWorld\"\n```\n\nAnd all of this works properly with TypeScript! So when I create a variable with `fluent('foo')`, I get auto-completion for both my custom helpers and native methods - along the complete method chain!\n\n### tap\n\nI also included my own port of [Laravel's tap helper](https://medium.com/@taylorotwell/tap-tap-tap-1fc6fc1f93a6). This allows me to rewrite this kind of code:\n\n```js\nconst foo = new Foo();\n\nfoo.bar = 'bar';\n\nreturn foo;\n```\n\nLike this:\n\n```js\nreturn tap(new Foo(), (foo) =\u003e {\n    foo.bar = 'bar';\n});\n```\n\n### facade\n\nSomething else Laravel-inspired are [facades](https://laravel.com/docs/10.x/facades#main-content). Unlike Laravel, there is no underlying service container, these facades just hold static proxies to an instance:\n\n```js\n// UsersService.ts\nexport default class UsersService {\n\n    async all() {\n        const response = await fetch('/users');\n        const json = await response.json();\n\n        return json.map(userJson =\u003e User.fromJson(userJson));\n    }\n\n}\n\n// Users.ts\nimport UsersService from './UsersService';\n\nexport default facade(new UsersService());\n\n// Anywhere in your app...\nimport Users from './Users';\n\nconst users = await Users.all();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoeldemartin%2Futils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnoeldemartin%2Futils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoeldemartin%2Futils/lists"}