https://github.com/poppinss/macroable
Extend classes from outside in using Macros and getters
https://github.com/poppinss/macroable
extend macroable
Last synced: 26 days ago
JSON representation
Extend classes from outside in using Macros and getters
- Host: GitHub
- URL: https://github.com/poppinss/macroable
- Owner: poppinss
- License: mit
- Created: 2017-06-01T07:44:09.000Z (over 8 years ago)
- Default Branch: 1.x
- Last Pushed: 2025-09-11T06:00:42.000Z (5 months ago)
- Last Synced: 2025-10-22T01:55:09.494Z (4 months ago)
- Topics: extend, macroable
- Language: TypeScript
- Homepage:
- Size: 837 KB
- Stars: 38
- Watchers: 6
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# @poppinss/macroable
> Extend classes from outside in using Macros and getters
[![gh-workflow-image]][gh-workflow-url] [![typescript-image]][typescript-url] [![npm-image]][npm-url] [![license-image]][license-url]
Macroable offers a simple API for adding properties and getters to the class prototype. You might not even need this package, if you are happy writing `Object.defineProperty` calls yourself.
## Usage
Install the package from npm packages registry as follows.
```sh
npm i @poppinss/macroable
# yarn lovers
yarn add @poppinss/macroable
```
And import the `Macroable` class.
```ts
import Macroable from '@poppinss/macroable'
export class Route extends Macroable {}
```
Now, you can add properties to the Route class from outside-in. This is usually needed, when you want the consumer of your classes to be able to extend them by adding custom properties.
## Macros
Getters are added to the class prototype directly.
```ts
Route.macro('head', function (uri, callback) {
return this.route(['HEAD'], uri, callback)
})
```
And now, you can will be use the `head` method from an instance of the `Route` class.
```ts
const route = new Route()
route.head('/', () => {})
```
Adding a macro is same as writing the following code in JavaScript.
```ts
Route.prototype.head = function () {
}
```
## Getters
Getters are added to the class prototype using the `Object.defineProperty`. The implementation of a getter is always a function.
```ts
Route.getter('version', function () {
return 'v1'
})
```
And now access the version as follows.
```ts
const route = new Route()
route.version // v1
```
Adding a getter is same as writing the following code in JavaScript.
```ts
Object.defineProperty(Route.prototype, 'version', {
get() {
const value = callback()
return value
},
configurable: false,
enumerable: false,
})
```
## Singleton getters
Singleton getters are also defined on the class prototype. However, their values are cached after the first access.
```ts
const singleton = true
Mysql.getter('version', function () {
return this.config.driver.split('-')[1]
}, singleton)
```
Adding a singleton getter is same as writing the following code in JavaScript.
```ts
Object.defineProperty(Mysql.prototype, 'version', {
get() {
const value = callback()
// Cache value on the class instance
Object.defineProperty(this, 'version', {
configurable: false,
enumerable: false,
value: value,
writable: false,
})
return value
},
configurable: false,
enumerable: false,
})
```
## TypeScript types
You will have to use [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) in order to define the types for the dynamically added properties.
## Contributing
One of our primary goals is to have a vibrant community of users and contributors who believes in the principles of the framework.
We encourage you to read the [contribution guide](https://github.com/poppinss/.github/blob/main/docs/CONTRIBUTING.md) before contributing to the framework.
## Code of Conduct
In order to ensure that the community is welcoming to all, please review and abide by the [Code of Conduct](https://github.com/poppinss/.github/blob/main/docs/CODE_OF_CONDUCT.md).
## License
Poppinss macroable is open-sourced software licensed under the [MIT license](LICENSE.md).
[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/poppinss/macroable/checks.yml?style=for-the-badge
[gh-workflow-url]: https://github.com/poppinss/macroable/actions/workflows/checks.yml "Github action"
[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
[typescript-url]: "typescript"
[npm-image]: https://img.shields.io/npm/v/@poppinss/macroable.svg?style=for-the-badge&logo=npm
[npm-url]: https://npmjs.org/package/@poppinss/macroable 'npm'
[license-image]: https://img.shields.io/npm/l/@poppinss/macroable?color=blueviolet&style=for-the-badge
[license-url]: LICENSE.md 'license'