lazy-get-decorator
Advanced tools
Comparing version 2.2.1 to 3.0.0
{ | ||
"name": "lazy-get-decorator", | ||
"version": "2.2.1", | ||
"version": "3.0.0", | ||
"description": "Lazily evaluates a getter on an object and caches the returned value", | ||
"main": "LazyGetter.js", | ||
"main": "cjs/index.js", | ||
"module": "es/index.js", | ||
"types": "index.d.ts", | ||
"exports": { | ||
"./package.json": { | ||
"default": "./package.json" | ||
}, | ||
".": { | ||
"types": "./index.d.ts", | ||
"esm": "./es/index.js", | ||
"module": "./es/index.js", | ||
"import": "./es/index.js", | ||
"node": "./cjs/index.js", | ||
"default": "./cjs/index.js" | ||
} | ||
}, | ||
"scripts": { | ||
"clean": "rm -rfv dist && mkdir dist", | ||
"build": "concurrently npm:build:*", | ||
"build:es": "tsc --outDir dist/es", | ||
"build:cjs": "tsc --outDir dist/cjs --module commonjs", | ||
"build:dts": "tsc --outDir dist --declaration --emitDeclarationOnly", | ||
"build:cp": "cp -v LICENSE README.md package.json .npmrc dist/", | ||
"watch": "npm --scripts-prepend-node-path=auto run clean && tsc --watch", | ||
"prewatch": "npm --scripts-prepend-node-path=auto run clean", | ||
"prebuild": "npm --scripts-prepend-node-path=auto run clean", | ||
"doctoc": "doctoc --github README.md", | ||
"test:es2022": "TS_NODE_PROJECT=tsconfig.test.json nyc --report-dir coverage/es2022 mocha src/test.ts", | ||
"test:es2017": "TS_NODE_COMPILER_OPTIONS=\"{\\\"target\\\":\\\"ES2017\\\"}\" TS_NODE_PROJECT=tsconfig.test.json nyc --report-dir coverage/es2017 mocha src/test.ts", | ||
"test:watch": "npm --scripts-prepend-node-path=auto run test:es2022 -- --watch", | ||
"lint": "eslint src --ext .ts", | ||
"lint:fix": "npm --scripts-prepend-node-path=auto run lint -- --fix" | ||
}, | ||
"repository": { | ||
@@ -12,3 +44,2 @@ "type": "git", | ||
"typescript", | ||
"babel", | ||
"lazy get", | ||
@@ -25,7 +56,7 @@ "lazy getter", | ||
"author": { | ||
"name": "Arturas Molcanovas", | ||
"name": "Artūras Molčanovas", | ||
"url": "https://alorel.github.io", | ||
"email": "a.molcanovas@gmail.com" | ||
"email": "amolc@pm.me" | ||
}, | ||
"license": "MIT", | ||
"license": "LGPL-3.0-only", | ||
"bugs": { | ||
@@ -35,12 +66,20 @@ "url": "https://github.com/Alorel/typescript-lazy-get-decorator/issues" | ||
"homepage": "https://github.com/Alorel/typescript-lazy-get-decorator", | ||
"es2015": "_bundle/fesm2015.js", | ||
"browser": "_bundle/umd.js", | ||
"jsdelivr": "_bundle/umd.min.js", | ||
"fesm5": "_bundle/fesm5.js", | ||
"esm5": "_bundle/fesm5.js", | ||
"fesm2015": "_bundle/fesm2015.js", | ||
"esm2015": "_bundle/fesm5.js", | ||
"types": "LazyGetter.d.ts", | ||
"module": "_bundle/fesm5.js", | ||
"typings": "LazyGetter.d.ts" | ||
"devDependencies": { | ||
"@alorel/eslint-config-base": "^1.0.18", | ||
"@alorel/eslint-config-typescript": "^1.0.17", | ||
"@types/chai": "^4.3.8", | ||
"@types/mocha": "^10.0.2", | ||
"@types/node": "^20.8.5", | ||
"@typescript-eslint/eslint-plugin": "^6.7.5", | ||
"@typescript-eslint/parser": "^6.7.5", | ||
"chai": "^4.3.10", | ||
"concurrently": "^8.2.1", | ||
"doctoc": "^2.2.1", | ||
"eslint": "^8.51.0", | ||
"mocha": "^10.2.0", | ||
"nyc": "^15.1.0", | ||
"source-map-support": "^0.5.21", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^5.2.2" | ||
} | ||
} |
196
README.md
# Lazy Get decorator | ||
[![Build Status](https://travis-ci.org/Alorel/typescript-lazy-get-decorator.png?branch=2.2.1)](https://travis-ci.org/Alorel/typescript-lazy-get-decorator) | ||
[![Coverage Status](https://coveralls.io/repos/github/Alorel/typescript-lazy-get-decorator/badge.svg?branch=2.2.1)](https://coveralls.io/github/Alorel/typescript-lazy-get-decorator?branch=2.2.1) | ||
[![Greenkeeper badge](https://badges.greenkeeper.io/Alorel/typescript-lazy-get-decorator.svg)](https://greenkeeper.io/) | ||
Getter decorator that memoises the return value | ||
[![NPM](https://nodei.co/npm/lazy-get-decorator.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/lazy-get-decorator) | ||
[![MASTER CI status](https://github.com/Alorel/typescript-lazy-get-decorator/actions/workflows/core.yml/badge.svg)](https://github.com/Alorel/typescript-lazy-get-decorator/actions/workflows/core.yml?query=branch%3Amaster) | ||
[![NPM badge](https://img.shields.io/npm/v/lazy-get-decorator)](https://www.npmjs.com/package/lazy-get-decorator) | ||
[![dependencies badge](https://img.shields.io/librariesio/release/npm/lazy-get-decorator)](https://libraries.io/npm/lazy-get-decorator) | ||
[![Coverage Status](https://coveralls.io/repos/github/Alorel/typescript-lazy-get-decorator/badge.svg)](https://coveralls.io/github/Alorel/typescript-lazy-get-decorator) | ||
Previously known as [typescript-lazy-get-decorator](https://www.npmjs.com/package/lazy-get-decorator). | ||
<!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
# Compatibility | ||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [Options](#options) | ||
- [Using the result selector](#using-the-result-selector) | ||
- [Compatibility](#compatibility) | ||
- [Migrating from v2](#migrating-from-v2) | ||
- Typescript - full | ||
- Spec-compliant decorator proposal - full | ||
- Babel (current proposal) - full | ||
- Babel (legacy) - full | ||
<!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
# API | ||
# Installation | ||
```typescript | ||
/** | ||
* Evaluate the getter function and cache the result | ||
* @param {boolean} [setProto=false] Set the value on the class prototype as well. Only applies to non-static getters. | ||
* @param {boolean} [makeNonConfigurable=false] Set to true to make the resolved property non-configurable | ||
* @param {ResultSelectorFn} [resultSelector] A filter function that must return true for the value to cached | ||
* @return A Typescript decorator function | ||
*/ | ||
function LazyGetter(setProto?: boolean, makeNonConfigurable?: boolean, resultSelector?: (value: any) => boolean): MethodDecorator; | ||
```shell | ||
npm install lazy-get-decorator | ||
``` | ||
@@ -36,138 +33,81 @@ | ||
class AClass { | ||
@LazyGetter() | ||
get lazyNoProto(): string { | ||
console.log('Evaluating lazyNoProto'); | ||
return 'lazyNoProtoValue'; | ||
} | ||
@LazyGetter(true) | ||
get lazyWithProto(): string { | ||
console.log('Evaluating lazyWithProto'); | ||
return 'lazyWithProtoValue'; | ||
} | ||
class MyClass { | ||
@LazyGetter(/* optional config */) | ||
get foo(): number { | ||
// ... | ||
} | ||
@LazyGetter(/* optional config */) | ||
static get bar(): string { | ||
// ... | ||
} | ||
} | ||
const inst1 = new AClass(); | ||
console.log('==== inst 1 ====\n'); | ||
console.log(inst1.lazyNoProto); | ||
console.log(inst1.lazyNoProto); | ||
console.log(inst1.lazyWithProto); | ||
console.log(inst1.lazyWithProto); | ||
const inst2 = new AClass(); | ||
console.log('\n\n==== inst 2 ====\n'); | ||
console.log(inst2.lazyNoProto); | ||
console.log(inst2.lazyNoProto); | ||
console.log(inst2.lazyWithProto); | ||
console.log(inst2.lazyWithProto); | ||
``` | ||
Output: | ||
## Options | ||
==== inst 1 ==== | ||
All options are optional | ||
Evaluating lazyNoProto | ||
lazyNoProtoValue | ||
lazyNoProtoValue | ||
Evaluating lazyWithProto | ||
lazyWithProtoValue | ||
lazyWithProtoValue | ||
| Name | Type | Default | Description | | ||
|----------|----------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| `global` | `boolean` | `false` | If set to true, the lazy getter triggering on one class instance will end up saving the returned value on all class instances, current and future. Has no effect on static getters. | | ||
| `select` | `<T, R>(this: T, output: R, self: T) => any` | | A function to determine whether we should save the results (returning a truthy value) or continue calling the original getter (returning a falsy value). The default behaviour is to always save the 1st result. | | ||
## Using the result selector | ||
==== inst 2 ==== | ||
The following example will save the value only if the counter is `10` or above. The selector executes after the getter | ||
function, hence the offset of 1: the current value of 9 is returned and passed on to the result selector, but the | ||
counter value is already incremented at this point. | ||
Evaluating lazyNoProto | ||
lazyNoProtoValue | ||
lazyNoProtoValue | ||
lazyWithProtoValue | ||
lazyWithProtoValue | ||
# Using the result selector | ||
```typescript | ||
import {LazyGetter} from 'lazy-get-decorator'; | ||
class MyClass { | ||
public readonly someCondition = 10; | ||
#counter = 0; | ||
@LazyGetter(false, false, (v: number) => v === 10) | ||
public get prop1(): number { | ||
// This will get cached | ||
return this.someCondition; | ||
@LazyGetter({select: v => v === 9}) | ||
get timesAccessed(): number { | ||
return this.#counter++; | ||
} | ||
@LazyGetter(false, false, (v: number) => v === 1) | ||
public get prop2(): number { | ||
// This won't get cached | ||
return this.someCondition; | ||
} | ||
} | ||
``` | ||
# Resetting LazyGetter | ||
# Compatibility | ||
The cached value can be reset if the decorator does not modify the class prototype, | ||
i.e. is not called as `@LazyGetter(true)`: | ||
The library's only goal is to be compatible with Typescript 5 decorators which, at the time of writing, use the [2022-03 stage 3 decorators proposal](https://2ality.com/2022/10/javascript-decorators.html). | ||
If you need experimental TS decorators or can't use a suitable Babel transform just stick to v2 - there are no new features in this release. | ||
```typescript | ||
import {LazyGetter} from 'lazy-get-decorator'; | ||
Typescript has further gotchas depending on the compiler target you've set. | ||
const instanceDec = LazyGetter(); | ||
const staticDec = LazyGetter(); | ||
ES2022 and higher allows you to use a class' method as a result selector: | ||
```typescript | ||
class MyClass { | ||
public instanceCount = 0; | ||
public static staticCount = 0; | ||
static shouldMemoiseStatic = false; | ||
shouldMemoiseInstance = true; | ||
@instanceDec | ||
public get count(): number { | ||
return this.instanceCount++; | ||
@LazyGetter({select: MyClass.bar}) | ||
static get foo() {} | ||
@LazyGetter({select: MyClass.prototype.bar2}) | ||
get foo2() {} | ||
static bar() { | ||
return this.shouldMemoiseStatic; | ||
} | ||
@staticDec | ||
public static get count(): number { | ||
return MyClass.staticCount++; | ||
bar2() { | ||
return this.shouldMemoiseInstance; | ||
} | ||
} | ||
const inst = new MyClass(); | ||
console.log(inst.count); // 0 | ||
console.log(inst.count); // 0 | ||
instanceDec.reset(inst); | ||
console.log(inst.count); // 1 | ||
console.log(MyClass.count); // 0 | ||
console.log(MyClass.count); // 0 | ||
staticDec.reset(MyClass); | ||
console.log(MyClass.count); // 1 | ||
``` | ||
Resetting the decoration performs the following steps: | ||
Attempting to do this on ES2021 or lower will result in a runtime error as of Typescript 5.2. | ||
1. Resets the property descriptor to its state before the decoration | ||
1. Re-applies the decorator | ||
# Migrating from v2 | ||
This means that any descriptor changes made by other decorators may be lost, therefore you | ||
should ensure `LazyGetter` is applied last if you intend on resetting it, i.e. place it | ||
at the very top of your decorators list: | ||
```typescript | ||
class MyClass { | ||
@LazyGetter() | ||
@decorator2 | ||
@decorator1 | ||
get getter() { | ||
return 1; | ||
} | ||
} | ||
``` | ||
- The function signature has changed to accept an object instead of multiple arguments | ||
- `makeNonConfigurable` option removed | ||
- `setProto` option renamed to `global` | ||
- The only officially supported version is now the non-experimental decorators of Typescript 5 - see [compatibility](#compatibility) | ||
- The ability to reset a memoised getter has been removed. | ||
- If you need to do this as part of your unit tests, use a different class every time. The library's test suites have a few variations of this pattern - creating classes through a helper function, running similar tests through a helper function that accepts a class | ||
- If you need this at runtime then it's not a lazy getter you have - add whatever checks you need in your getter's logic and don't decorate it |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found
Found 1 instance in 1 package
23909
16
9
2
70
262
113
1