Comparing version 3.0.0 to 4.0.0
@@ -6,17 +6,75 @@ declare type MacroableFn<T> = (this: T, ...args: any[]) => any; | ||
export interface MacroableConstructorContract<T extends any> { | ||
macro(name: string, callback: MacroableFn<T>): any; | ||
getter(name: string, callback: MacroableFn<T>, singleton?: boolean): any; | ||
hydrate(): any; | ||
macro(name: string, callback: MacroableFn<T>): void; | ||
getter(name: string, callback: MacroableFn<T>, singleton?: boolean): void; | ||
hydrate(): void; | ||
} | ||
/** | ||
* Macroable is an abstract class to add ability to extend your class | ||
* prototype using better syntax. | ||
* | ||
* Macroable has handful of benefits over using traditional `prototype` approach. | ||
* | ||
* 1. Methods or properties added dynamically to the class can be removed using `hydrate` method. | ||
* 2. Can define singleton getters. | ||
*/ | ||
export declare abstract class Macroable { | ||
protected static _macros: MacroableMap; | ||
protected static _getters: MacroableMap; | ||
protected static macros: MacroableMap; | ||
protected static getters: MacroableMap; | ||
constructor(); | ||
/** | ||
* Add a macro to the class. This method is a better to manually adding | ||
* to `class.prototype.method`. | ||
* | ||
* Also macros added using `Macroable.macro` can be cleared anytime | ||
* | ||
* @example | ||
* ```js | ||
* Macroable.macro('getUsername', function () { | ||
* return 'virk' | ||
* }) | ||
* ``` | ||
*/ | ||
static macro<T extends any = any>(name: string, callback: MacroableFn<T>): void; | ||
/** | ||
* Return the existing macro or null if it doesn't exists | ||
*/ | ||
static getMacro(name: string): MacroableFn<any> | undefined; | ||
/** | ||
* Returns a boolean telling if a macro exists | ||
*/ | ||
static hasMacro(name: string): boolean; | ||
/** | ||
* Define a getter, which is invoked everytime the value is accessed. This method | ||
* also allows adding single getters, whose value is cached after first time | ||
* | ||
* @example | ||
* ```js | ||
* Macroable.getter('time', function () { | ||
* return new Date().getTime() | ||
* }) | ||
* | ||
* console.log(new Macroable().time) | ||
* | ||
* // Singletons | ||
* Macroable.getter('time', function () { | ||
* return new Date().getTime() | ||
* }, true) | ||
* | ||
* console.log(new Macroable().time) | ||
* ``` | ||
*/ | ||
static getter<T extends any = any>(name: string, callback: MacroableFn<T>, singleton?: boolean): void; | ||
/** | ||
* Return the existing getter or null if it doesn't exists | ||
*/ | ||
static getGetter(name: string): MacroableFn<any> | undefined; | ||
/** | ||
* Returns a boolean telling if a getter exists | ||
*/ | ||
static hasGetter(name: string): boolean; | ||
/** | ||
* Cleanup getters and macros from the class | ||
*/ | ||
static hydrate(): void; | ||
} | ||
export {}; |
"use strict"; | ||
/* | ||
* @poppinss/macroable | ||
* | ||
* (c) Harminder Virk <virk@adonisjs.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
* Macroable is an abstract class to add ability to extend your class | ||
* prototype using better syntax. | ||
* | ||
* Macroable has handful of benefits over using traditional `prototype` approach. | ||
* | ||
* 1. Methods or properties added dynamically to the class can be removed using `hydrate` method. | ||
* 2. Can define singleton getters. | ||
*/ | ||
class Macroable { | ||
constructor() { | ||
if (!this.constructor.hasOwnProperty('macros') || !this.constructor.hasOwnProperty('getters')) { | ||
throw new Error('Set static properties "macros = {}" and "getters = {}" on the class for the macroable to work.'); | ||
} | ||
} | ||
/** | ||
* Add a macro to the class. This method is a better to manually adding | ||
* to `class.prototype.method`. | ||
* | ||
* Also macros added using `Macroable.macro` can be cleared anytime | ||
* | ||
* @example | ||
* ```js | ||
* Macroable.macro('getUsername', function () { | ||
* return 'virk' | ||
* }) | ||
* ``` | ||
*/ | ||
static macro(name, callback) { | ||
this._macros[name] = callback; | ||
this.macros[name] = callback; | ||
this.prototype[name] = callback; | ||
} | ||
/** | ||
* Return the existing macro or null if it doesn't exists | ||
*/ | ||
static getMacro(name) { | ||
return this._macros[name]; | ||
return this.macros[name]; | ||
} | ||
/** | ||
* Returns a boolean telling if a macro exists | ||
*/ | ||
static hasMacro(name) { | ||
return !!this.getMacro(name); | ||
} | ||
/** | ||
* Define a getter, which is invoked everytime the value is accessed. This method | ||
* also allows adding single getters, whose value is cached after first time | ||
* | ||
* @example | ||
* ```js | ||
* Macroable.getter('time', function () { | ||
* return new Date().getTime() | ||
* }) | ||
* | ||
* console.log(new Macroable().time) | ||
* | ||
* // Singletons | ||
* Macroable.getter('time', function () { | ||
* return new Date().getTime() | ||
* }, true) | ||
* | ||
* console.log(new Macroable().time) | ||
* ``` | ||
*/ | ||
static getter(name, callback, singleton = false) { | ||
@@ -20,3 +81,3 @@ const wrappedCallback = singleton ? function wrappedCallback() { | ||
} : callback; | ||
this._getters[name] = wrappedCallback; | ||
this.getters[name] = wrappedCallback; | ||
Object.defineProperty(this.prototype, name, { | ||
@@ -28,17 +89,26 @@ get: wrappedCallback, | ||
} | ||
/** | ||
* Return the existing getter or null if it doesn't exists | ||
*/ | ||
static getGetter(name) { | ||
return this._getters[name]; | ||
return this.getters[name]; | ||
} | ||
/** | ||
* Returns a boolean telling if a getter exists | ||
*/ | ||
static hasGetter(name) { | ||
return !!this.getGetter(name); | ||
} | ||
/** | ||
* Cleanup getters and macros from the class | ||
*/ | ||
static hydrate() { | ||
Object.keys(this._macros).forEach((key) => Reflect.deleteProperty(this.prototype, key)); | ||
Object.keys(this._getters).forEach((key) => Reflect.deleteProperty(this.prototype, key)); | ||
this._macros = {}; | ||
this._getters = {}; | ||
Object.keys(this.macros).forEach((key) => Reflect.deleteProperty(this.prototype, key)); | ||
Object.keys(this.getters).forEach((key) => Reflect.deleteProperty(this.prototype, key)); | ||
this.macros = {}; | ||
this.getters = {}; | ||
} | ||
} | ||
exports.Macroable = Macroable; | ||
Macroable._macros = {}; | ||
Macroable._getters = {}; | ||
Macroable.macros = {}; | ||
Macroable.getters = {}; |
{ | ||
"name": "macroable", | ||
"version": "3.0.0", | ||
"version": "4.0.0", | ||
"description": "A simple ES6 class that can be extended to provide macros and getters functionality", | ||
"main": "build/index.js", | ||
"files": [ | ||
"build/index.js", | ||
"build/index.d.ts" | ||
"build/index.d.ts", | ||
"build/index.js" | ||
], | ||
@@ -13,11 +13,11 @@ "scripts": { | ||
"pretest": "npm run lint", | ||
"test": "nyc node japaFile.js", | ||
"lint": "tslint --project tsconfig.json", | ||
"test": "node japaFile.js", | ||
"clean": "del build", | ||
"compile": "npm run lint && npm run clean && tsc", | ||
"build": "npm run compile", | ||
"coverage": "nyc report --reporter=text-lcov | coveralls", | ||
"commit": "git-cz", | ||
"release": "np", | ||
"version": "npm run build" | ||
"version": "npm run build", | ||
"lint": "eslint . --ext=.ts", | ||
"prepublishOnly": "npm run build" | ||
}, | ||
@@ -30,24 +30,20 @@ "keywords": [ | ||
"devDependencies": { | ||
"@adonisjs/mrm-preset": "^2.1.0", | ||
"@types/node": "^12.12.11", | ||
"@adonisjs/mrm-preset": "^2.2.3", | ||
"@types/node": "^12.12.21", | ||
"commitizen": "^4.0.3", | ||
"coveralls": "^3.0.8", | ||
"cz-conventional-changelog": "^3.0.2", | ||
"del-cli": "^3.0.0", | ||
"eslint": "^6.7.2", | ||
"eslint-plugin-adonis": "^1.0.4", | ||
"husky": "^3.1.0", | ||
"japa": "^3.0.1", | ||
"mrm": "^1.2.2", | ||
"np": "^5.1.3", | ||
"nyc": "^14.1.1", | ||
"ts-node": "^8.5.2", | ||
"tslint": "^5.20.1", | ||
"tslint-eslint-rules": "^5.4.0", | ||
"typescript": "^3.7.2" | ||
"mrm": "^2.0.2", | ||
"np": "^5.2.1", | ||
"ts-node": "^8.5.4", | ||
"typescript": "^3.7.3" | ||
}, | ||
"dependencies": { | ||
"node-exceptions": "^4.0.1" | ||
}, | ||
"dependencies": {}, | ||
"nyc": { | ||
"exclude": [ | ||
"test.ts" | ||
"test" | ||
], | ||
@@ -54,0 +50,0 @@ "extension": [ |
120
README.md
@@ -0,12 +1,15 @@ | ||
<div align="center"><img src="https://res.cloudinary.com/adonisjs/image/upload/q_100/v1557762307/poppinss_iftxlt.jpg" width="600px"></div> | ||
# Macroable | ||
> Extend `class` prototype in style 😎 | ||
[![travis-image]][travis-url] | ||
[![appveyor-image]][appveyor-url] | ||
[![coveralls-image]][coveralls-url] | ||
[![npm-image]][npm-url] | ||
![](https://img.shields.io/badge/Uses-Typescript-294E80.svg?style=flat-square&colorA=ddd) | ||
[![circleci-image]][circleci-url] [![typescript-image]][typescript-url] [![npm-image]][npm-url] [![license-image]][license-url] | ||
Macroable is a simple class that your classes can extend in order to expose an API for extending the class. Let's see how a class can be extended without Macroable first. | ||
Base class for exposing external API to extend the class prototype in a more declarative way. | ||
<!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
<!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
## Traditional approach | ||
@@ -35,3 +38,3 @@ | ||
## Using macroable it's simpler | ||
## Using macroable | ||
@@ -44,4 +47,4 @@ ```js | ||
Foo._macros = {} | ||
Foo._getters = {} | ||
Foo.macros = {} | ||
Foo.getters = {} | ||
@@ -63,30 +66,16 @@ module.exports = Foo | ||
You can see the API is simpler and less verbose. However, their are couple more benefits to using Macroable. | ||
You can see the API is simpler and less verbose. However, there are couple of extra benefits of using Macroable. | ||
1. You can add singleton getters, which are evaluated only once and then cached value is returned. | ||
2. Cleanup all `macros` and `getters` added using Macroable. | ||
### Defining singleton getters | ||
Singleton getters are evaluated only once and then cached value is returned. | ||
## Installation | ||
```bash | ||
npm i macroable | ||
``` | ||
## Usage | ||
```js | ||
const { Macroable } from 'macroable' | ||
class Foo extends Macroable { | ||
} | ||
Foo._macros = {} | ||
Foo._getters = {} | ||
module.exports = Foo | ||
Foo.getter('baseUrl', function () { | ||
return lazilyEvaluateAndReturnUrl() | ||
}, true) 👈 | ||
``` | ||
## API | ||
### Hydrating the class | ||
Using the `hydrate` method, you can remove macros and getters added on a given class. | ||
#### macro(name, callback) => void | ||
Add a function to the prototype | ||
```js | ||
@@ -96,67 +85,22 @@ Foo.macro('greet', function (name) { | ||
}) | ||
``` | ||
#### hasMacro(name) => boolean | ||
Find if macro exists. | ||
```js | ||
Foo.hasMacro('greet') | ||
``` | ||
#### getter(name, callback, isSingleton?) => void | ||
Add getter to the prototype and optionally make it singleton. | ||
```js | ||
Foo.getter('username', function () { | ||
return 'virk' | ||
}, true) | ||
``` | ||
}) | ||
#### hasGetter(name) => boolean | ||
Find if getter exists. | ||
```js | ||
Foo.hasGetter('greet') | ||
Foo.hydrate() 👈 | ||
Foo.greet // undefined | ||
Foo.username // undefined | ||
``` | ||
#### hydrate | ||
Remove all macros and getters added using `Macroable`. | ||
[circleci-image]: https://img.shields.io/circleci/project/github/poppinss/macroable/master.svg?style=for-the-badge&logo=circleci | ||
[circleci-url]: https://circleci.com/gh/poppinss/macroable "circleci" | ||
```js | ||
Foo.getter('username', function () { | ||
return 'virk' | ||
}, true) | ||
[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript | ||
[typescript-url]: "typescript" | ||
Foo.hydrate() | ||
[npm-image]: https://img.shields.io/npm/v/macroable.svg?style=for-the-badge&logo=npm | ||
[npm-url]: https://npmjs.org/package/macroable "npm" | ||
Foo.hasGetter('username') // false | ||
``` | ||
## Change log | ||
The change log can be found in the [CHANGELOG.md](CHANGELOG.md) file. | ||
## Contributing | ||
Everyone is welcome to contribute. Please go through the following guides, before getting started. | ||
1. [Contributing](https://adonisjs.com/contributing) | ||
2. [Code of conduct](https://adonisjs.com/code-of-conduct) | ||
## Authors & License | ||
[thetutlage](https://github.com/thetutlage) and [contributors](https://github.com/poppinss/macroable/graphs/contributors). | ||
MIT License, see the included [MIT](LICENSE.md) file. | ||
[travis-image]: https://img.shields.io/travis/poppinss/macroable/master.svg?style=flat-square&logo=travis | ||
[travis-url]: https://travis-ci.org/poppinss/macroable "travis" | ||
[appveyor-image]: https://img.shields.io/appveyor/ci/thetutlage/macroable/master.svg?style=flat-square&logo=appveyor | ||
[appveyor-url]: https://ci.appveyor.com/project/thetutlage/macroable "appveyor" | ||
[coveralls-image]: https://img.shields.io/coveralls/poppinss/macroable/master.svg?style=flat-square | ||
[coveralls-url]: https://coveralls.io/github/poppinss/macroable "coveralls" | ||
[npm-image]: https://img.shields.io/npm/v/macroable.svg?style=flat-square&logo=npm | ||
[npm-url]: https://npmjs.org/package/macroable "npm" | ||
[license-image]: https://img.shields.io/npm/l/macroable?color=blueviolet&style=for-the-badge | ||
[license-url]: LICENSE.md "license" |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12020
0
13
191
103
- Removednode-exceptions@^4.0.1
- Removednode-exceptions@4.0.1(transitive)