Skip to content
This repository was archived by the owner on Oct 29, 2024. It is now read-only.

Commit 23b17f9

Browse files
Copy implementation from ember-cached-decorator-polyfill and add types
Co-Authored-By: Jan Buschtöns <jan@buschtoens.me>
1 parent ee9fbf0 commit 23b17f9

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

packages/@glimmer/tracking/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export { cached } from './src/cached';
12
export { tracked } from './src/tracked';
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { DEBUG } from '@glimmer/env';
2+
import { createCache, getValue } from '@glimmer/validator';
3+
4+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5+
export const cached: PropertyDecorator = (...args: any[]) => {
6+
const [target, key, descriptor] = args;
7+
8+
// Error on `@cached()`, `@cached(...args)`, and `@cached propName = value;`
9+
if (DEBUG && target === undefined) throwCachedExtraneousParens();
10+
if (
11+
DEBUG &&
12+
(typeof target !== 'object' ||
13+
typeof key !== 'string' ||
14+
typeof descriptor !== 'object' ||
15+
args.length !== 3)
16+
) {
17+
throwCachedInvalidArgsError(args);
18+
}
19+
if (DEBUG && 'get' in descriptor && typeof descriptor.get !== 'function')
20+
throwCachedGetterOnlyError(key);
21+
22+
const caches = new WeakMap();
23+
const getter = descriptor.get;
24+
descriptor.get = function (): unknown {
25+
if (!caches.has(this)) caches.set(this, createCache(getter.bind(this)));
26+
return getValue(caches.get(this));
27+
};
28+
};
29+
30+
function throwCachedExtraneousParens(): never {
31+
throw new Error(
32+
'You attempted to use @cached(), which is not necessary nor supported. Remove the parentheses and you will be good to go!'
33+
);
34+
}
35+
36+
function throwCachedGetterOnlyError(key: string): never {
37+
throw new Error(`The @cached decorator must be applied to getters. '${key}' is not a getter.`);
38+
}
39+
40+
function throwCachedInvalidArgsError(args: unknown[]): never {
41+
throw new Error(
42+
`You attempted to use @cached on with ${
43+
args.length > 1 ? 'arguments' : 'an argument'
44+
} ( @cached(${args
45+
.map((d) => `'${d}'`)
46+
.join(
47+
', '
48+
)}), which is not supported. Dependencies are automatically tracked, so you can just use ${'`@cached`'}`
49+
);
50+
}

test/types/tracking-test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import { hasExactKeys } from './utils';
33

44
hasExactKeys<{
55
tracked: unknown;
6+
cached: unknown;
67
}>()(tracking);
78

89
// $ExpectType PropertyDecorator
910
tracking.tracked;
11+
// $ExpectType PropertyDecorator
12+
tracking.cached;

0 commit comments

Comments
 (0)