{"id":16323103,"url":"https://github.com/danielstjules/pattern-emitter","last_synced_at":"2025-03-20T22:31:37.994Z","repository":{"id":14381457,"uuid":"17091640","full_name":"danielstjules/pattern-emitter","owner":"danielstjules","description":"Node event emitters with support for regular expressions","archived":false,"fork":false,"pushed_at":"2014-04-25T04:11:04.000Z","size":373,"stargazers_count":55,"open_issues_count":1,"forks_count":3,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-10-11T22:53:53.197Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/danielstjules.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2014-02-22T18:46:15.000Z","updated_at":"2024-07-12T11:09:47.000Z","dependencies_parsed_at":"2022-09-12T00:40:19.901Z","dependency_job_id":null,"html_url":"https://github.com/danielstjules/pattern-emitter","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielstjules%2Fpattern-emitter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielstjules%2Fpattern-emitter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielstjules%2Fpattern-emitter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielstjules%2Fpattern-emitter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielstjules","download_url":"https://codeload.github.com/danielstjules/pattern-emitter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244085015,"owners_count":20395523,"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":[],"created_at":"2024-10-10T22:53:57.409Z","updated_at":"2025-03-20T22:31:37.755Z","avatar_url":"https://github.com/danielstjules.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"pattern-emitter\n===============\n\nEvent emitters with support for regular expressions. Inherits from Node's\nEventEmitter.\n\n[![Build Status](https://travis-ci.org/danielstjules/pattern-emitter.png)](https://travis-ci.org/danielstjules/pattern-emitter)\n\n* [Installation](#installation)\n* [Overview](#overview)\n* [Compatibility](#compatibility)\n* [Class: PatternEmitter](#class-patternemitter)\n* [Instance Methods](#instance-methods)\n    * [emitter.addListener(event | pattern, listener)](#emitteraddlistenerevent--pattern-listener)\n    * [emitter.emit(event, \\[arg1\\], \\[arg2\\], \\[...\\])](#emitteremitevent-arg1-arg2-)\n    * [emitter.listeners(event)](#emitterlistenersevent)\n    * [emitter.matchingListeners(event)](#emittermatchinglistenersevent)\n    * [emitter.on(event | pattern, listener)](#emitteronevent--pattern-listener)\n    * [emitter.once(event | pattern, listener)](#emitteronceevent--pattern-listener)\n    * [emitter.patternListeners(pattern)](#emitterpatternlistenerspattern)\n    * [emitter.removeAllListeners(event | pattern)](#emitterremovealllistenersevent--pattern)\n    * [emitter.removeListener(event | pattern, listener)](#emitterremovelistenerevent--pattern-listener)\n    * [emitter.setMaxListeners(n)](#emittersetmaxlistenersn)\n* [Class Methods](#class-methods)\n    * [PatternEmitter.listenerCount(emitter, event)](#patternemitterlistenercountemitter-event)\n    * [PatternEmitter.matchingListenerCount(emitter, event)](#patternemittermatchinglistenercountemitter-event)\n    * [PatternEmitter.patternListenerCount(emitter, pattern)](#patternemitterpatternlistenercountemitter-pattern)\n* [Events](#events)\n    * [newListener](#newlistener)\n    * [removeListener](#removelistener)\n* [Performance](#performance)\n\n## Installation\n\nUsing npm, you can install pattern-emitter with `npm install pattern-emitter`.\nYou can also require it as a dependency in your `package.json` file:\n\n```\n\"dependencies\": {\n    \"pattern-emitter\": \"1.0.x\"\n}\n```\n\n## Overview\n\nThe PatternEmitter class both extends and is backwards compatible with\nEventEmitter when dealing with string event types. However, when registering\na listener to a RegExp, it has the added benefit of listening to all events\nmatching the expression, rather than that particular object. In addition, it\nexposes a new set of methods on top of the existing API for requesting details\non those patterns and their listeners. As a result, getting started with this\nlibrary is as simple as replacing instances of:\n\n``` javascript\nvar Emitter = require('events').EventEmitter; // Node 0.10.x\nvar Emitter = require('events');              // Node 0.12.x\n```\n\nwith:\n\n``` javascript\nvar Emitter = require('pattern-emitter');\n```\n\nAfterwards, you're ready to start listening to patterns.\n\n``` javascript\nvar emitter = new Emitter();\nvar result;\n\nemitter.on(/^example/, function(arg1, arg2) {\n  result = arg1 + ' ' + arg2;\n});\n\nemitter.emit('exampleEvent', \"It's\", 'that simple');\nconsole.log(result); // \"It's that simple\"\n```\n\n## Compatibility\n\nThe use of PatternEmitter is backwards compatible with EventEmitter for all\nwho haven't been registering listeners to instances of `RegExp`. I suspect\nthat this covers a great majority of event use.\n\n## Class: PatternEmitter\n\nAs with EventEmitter, when a PatternEmitter experiences an error, it emits\nan `error` event. If no listeners exist for the event, then by default, a stack\ntrace is printed and the program is closed.\n\nFurthermore, all PatternEmitters emit the `newListener` event when new listeners\nare added, and `removeListener` when removed.\n\nThese string events are treated like any other, and may be caught by a listener\nregistered to a matching pattern, e.g. `/.*/`.\n\n## Instance Methods\n\nIn the following examples, let `emitter` be an instance of `PatternEmitter`.\nFurthermore, let `pattern` refer to any instance of `RegExp`, and `event`\nall other values.\n\nWhen a listener is invoked, it's given the event name as a property, which is\naccessible via `this.event`.\n\n#### emitter.addListener(event | pattern, listener)\n\nGiven a RegExp event type, stores the regular expression and registers the\nlistener to any events matching the pattern. Otherwise, it behaves exactly\nas EventEmitter. As with EventEmitter.prototype.addListener, it emits a\nnewListener' event on success. Returns an instance of itself.\n\n``` javascript\nemitter.addListener('userCreated', function(object) {\n  console.log('Listener:', this.event);\n});\n\nemitter.addListener(/user/, function(object) {\n  console.log('Pattern Listener:', this.event);\n});\n\nemitter.emit('userCreated', {id: 10, username: 'Alice'});\n// Listener: userCreated\n// Pattern Listener: userCreated\n\nemitter.emit('userUpdated', {id: 19, username: 'Bob'});\n// Pattern Listener: userUpdated\n```\n\n#### emitter.emit(event, \\[arg1\\], \\[arg2\\], \\[...\\])\n\nEmits an event to all listeners for the specified type. In addition, if type\nis a string, emits the event to all listeners whose patterns match. Returns\ntrue if any listeners existed, false otherwise.\n\n``` javascript\nemitter.addListener(/^namespace:entry:1\\d{4}$/, function() {\n  // Handler for entries within the given range: 10000-19999\n});\n\nemitter.emit('namespace:entry:12345'); // true\nemitter.emit('namespace:entry:20000'); // false\n```\n\n#### emitter.listeners(event)\n\nReturns an array of listeners for the given event.\n\n``` javascript\nemitter.addListener('foo:1:newBar', function() {\n  console.log('event listener');\n});\n\nemitter.addListener(/^foo:[0-9]+:newBar$/, function() {\n  console.log('pattern listener');\n});\n\nvar listeners = emitter.listeners('foo:1:newBar');\nconsole.log(listeners.length); // 1\nlisteners[0]();                // 'event listener'\n```\n\n#### emitter.matchingListeners(event)\n\nReturns an array of listeners for the supplied event type, and whose\npatterns match the event if given a string.\n\n``` javascript\nemitter.addListener('foo:1:newBar', function() {\n  console.log('event listener');\n});\n\nemitter.addListener(/^foo:[0-9]+:newBar$/, function() {\n  console.log('pattern listener');\n});\n\nvar listeners = emitter.matchingListeners('foo:1:newBar');\nconsole.log(listeners.length); // 2\nlisteners[0]();                // 'event listener'\nlisteners[1]();                // 'pattern listener'\n```\n\n#### emitter.on(event | pattern, listener)\n\nAn alias for addListener.\n\n``` javascript\nemitter.on(/.*/, function() {\n  // Listen to all events, including 'error', 'newListener',\n  // and 'removeListener'\n});\n```\n\n#### emitter.once(event | pattern, listener)\n\nAdds a one time listener for an event or pattern. The listener is invoked only\nonce after an event is fired, after which it is removed.\n\n``` javascript\nvar counter = 0;\nemitter.once(/foo:[0-9]+:updated$/, function() {\n  counter++;\n});\n\nemitter.emit('app:foo:81:updated');\nemitter.emit('app:foo:92:updated');\nconsole.log(counter); // 1\n```\n\n#### emitter.patternListeners(pattern)\n\nReturns an array of pattern listeners for the specified RegExp.\n\n``` javascript\nemitter.on(/.*/, function() {\n  // Example pattern listener\n});\n\nemitter.on('/.*/', function() {\n // Won't be included in the results below\n});\n\nvar count = emitter.patternListeners(/.*/).length; // 1\n```\n\n#### emitter.removeAllListeners(event | pattern)\n\nRemoves all listeners for the specified event type. If given an instance of\nRegExp, it matches the RegExp object with the same expression. Emits a\n'removeListener' event for each removed listener. Returns an instance of\nitself.\n\n``` javascript\nemitter.addListener(/foo:.*[0-9]+/, function() {});\nemitter.addListener(/foo:.*[0-9]+/, function() {});\nemitter.addListener('/foo:.*[0-9]+/', function() {});\n\nvar count = emitter.patternListeners(/foo:.*[0-9]+/).length; // 2\n\nemitter.removeAllListeners(/foo:.*[0-9]+/);\ncount = emitter.patternListeners(/foo:.*[0-9]+/).length; // 0\n```\n\n#### emitter.removeListener(event | pattern, listener)\n\nRemoves the listener from the specified event type. If given an instance of\nRegExp, it matches any RegExp object with the same expression. Emits a\n'removeListener' event on success. Returns an instance of itself.\n\n``` javascript\nvar listener = function() {\n  // Example event listener\n};\n\nemitter.addListener(/foo:.*[0-9]+/, listener);\nemitter.addListener(/foo:.*[0-9]+/, function() {});\n\nvar count = emitter.patternListeners(/foo:.*[0-9]+/).length; // 2\n\nemitter.removeListener(/foo:.*[0-9]+/, listener);\ncount = emitter.patternListeners(/foo:.*[0-9]+/).length; // 1\n```\n\n#### emitter.setMaxListeners(n)\n\nBy default, PatternEmitters will print a warning once more than 10 listeners\nare added for a particular event. This may be used to modify that threshold.\nSetting to 0 will disable the threshold altogether.\n\n``` javascript\nemitter.setMaxListeners(1);\nemitter.on(/^foo.*/, function() {});\nemitter.on(/^foo.*/, function() {});\n\n// (node) warning: possible EventEmitter memory leak detected. 2 listeners\n// added. Use emitter.setMaxListeners() to increase limit.\n```\n\n## Class Methods\n\nIn the outline below, let `pattern` refer to any instance of `RegExp`, and\n`event` all other values.\n\n#### PatternEmitter.listenerCount(emitter, event)\n\nReturns the number of listeners for a given event. An alias for\nEventEmitter.listenerCount.\n\n``` javascript\nemitter.on('foo', function() {});\nemitter.on(/foo/, function() {});\n\nPatternEmitter.listenerCount(emitter, 'foo'); // 1\n```\n\n#### PatternEmitter.matchingListenerCount(emitter, event)\n\nReturns the number of listeners and pattern listeners registered to the\nemitter for the event type or a matching pattern.\n\n``` javascript\nemitter.on('foo', function() {});\nemitter.on(/foo/, function() {});\n\nPatternEmitter.matchingListenerCount(emitter, 'foo'); // 2\n```\n\n#### PatternEmitter.patternListenerCount(emitter, pattern)\n\nReturns the number of listeners registered to the emitter for the specified\npattern.\n\n``` javascript\nemitter.on('foo', function() {});\nemitter.on(/foo/, function() {});\n\nPatternEmitter.patternListenerCount(emitter, /foo/); // 1\n```\n\n## Events\n\nLike EventEmitter, instances of PatternEmitter emit events both when listeners\nare added and removed. The events can be matched by pattern listeners, and as\nsuch will include the name/type as a property, accessible via `this.event`.\n\n#### newListener\n\nThe event is emitted any time a new listener is added to the emitter. The event\nis emitted just prior to the listener being added, to prevent recursion.\n\n* `*` event | pattern\n* `function` listener\n\n``` javascript\nemitter.on(/Listener/, function(pattern, listener) {\n  // this.event will equal 'newListener' when a new listener is added\n});\n```\n\n#### removeListener\n\nThe event is emitted any time an existing listener is removed from the emitter.\nThe event is emitted just prior to the listener being removed, to prevent\nrecursion.\n\n* `*` event | pattern\n* `function` listener\n\n``` javascript\nemitter.on('removeListener', function(event, listener) {\n  // invoked when a listener is removed\n});\n```\n\n## Performance\n\n**TL;DR:** *Likely not an issue unless you're invoking in excess of 1,000,000\nlisteners per second*\n\nDespite the ease of replacing EventEmitter throughout your application,\nperformance should be considered for any event-heavy code. This implementation\nwas done in an attempt to avoid copying a majority of the source in\n`node/lib/events.js`, which resulted in a couple otherwise unnecessary\nassignments and function calls when dealing with EventEmitter's default\nbehaviour.\n\nTo illustrate, consider the performance difference between both modules when\nonly registering to string events, no regular expressions. Running\n[benchmarks/eventEmitting.js](https://github.com/danielstjules/pattern-emitter/blob/master/benchmarks/eventEmitting.js):\n\n```\n$ node benchmarks/eventEmitting.js\nEventEmitter x 208,424 ops/sec ±0.28% (102 runs sampled)\nPatternEmitter x 164,004 ops/sec ±0.45% (101 runs sampled)\n```\n\nEach operation in the above benchmark is invoking 100 listeners: 10 for each\nof 10 different events. That is, 20,842,400 vs 16,400,400 invocations a second\non my Macbook Air. So while a performance drop, it may not be a problem for\nyour average node instance.\n\nFor testing PatternEmitter with its pattern matching behaviour, a second\nnaive benchmark currently exists. With 100 pattern listeners, 10 for each\nof 10 different patterns,\n[benchmarks/patternEmitting.js](https://github.com/danielstjules/pattern-emitter/blob/master/benchmarks/patternEmitting.js)\ncan be used:\n\n```\n$ node benchmarks/patternEmitting.js\nPatternEmitter x 33,179 ops/sec ±0.26% (101 runs sampled)\n```\n\nStill, 3,317,900 invocations a second for simple, small regular expressions.\nOf course, your own numbers will vary depending on the complexity of the\npatterns.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielstjules%2Fpattern-emitter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielstjules%2Fpattern-emitter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielstjules%2Fpattern-emitter/lists"}