|
| 1 | +/** |
| 2 | + * @license |
| 3 | + * Copyright Google LLC All Rights Reserved. |
| 4 | + * |
| 5 | + * Use of this source code is governed by an MIT-style license that can be |
| 6 | + * found in the LICENSE file at https://angular.io/license |
| 7 | + */ |
| 8 | + |
| 9 | +/** |
| 10 | + * @fileoverview |
| 11 | + * Provides infrastructure for common caching functionality within the build system. |
| 12 | + */ |
| 13 | + |
| 14 | +/** |
| 15 | + * A backing data store for one or more Cache instances. |
| 16 | + * The interface is intentionally designed to support using a JavaScript |
| 17 | + * Map instance as a potential cache store. |
| 18 | + */ |
| 19 | +export interface CacheStore<V> { |
| 20 | + /** |
| 21 | + * Returns the specified value from the cache store or `undefined` if not found. |
| 22 | + * @param key The key to retrieve from the store. |
| 23 | + */ |
| 24 | + get(key: string): V | undefined | Promise<V | undefined>; |
| 25 | + |
| 26 | + /** |
| 27 | + * Returns whether the provided key is present in the cache store. |
| 28 | + * @param key The key to check from the store. |
| 29 | + */ |
| 30 | + has(key: string): boolean | Promise<boolean>; |
| 31 | + |
| 32 | + /** |
| 33 | + * Adds a new value to the cache store if the key is not present. |
| 34 | + * Updates the value for the key if already present. |
| 35 | + * @param key The key to associate with the value in the cache store. |
| 36 | + * @param value The value to add to the cache store. |
| 37 | + */ |
| 38 | + set(key: string, value: V): this | Promise<this>; |
| 39 | +} |
| 40 | + |
| 41 | +/** |
| 42 | + * A cache object that allows accessing and storing key/value pairs in |
| 43 | + * an underlying CacheStore. This class is the primary method for consumers |
| 44 | + * to use a cache. |
| 45 | + */ |
| 46 | +export class Cache<V, S extends CacheStore<V> = CacheStore<V>> { |
| 47 | + constructor( |
| 48 | + protected readonly store: S, |
| 49 | + readonly namespace?: string, |
| 50 | + ) {} |
| 51 | + |
| 52 | + /** |
| 53 | + * Prefixes a key with the cache namespace if present. |
| 54 | + * @param key A key string to prefix. |
| 55 | + * @returns A prefixed key if a namespace is present. Otherwise the provided key. |
| 56 | + */ |
| 57 | + protected withNamespace(key: string): string { |
| 58 | + if (this.namespace) { |
| 59 | + return `${this.namespace}:${key}`; |
| 60 | + } |
| 61 | + |
| 62 | + return key; |
| 63 | + } |
| 64 | + |
| 65 | + /** |
| 66 | + * Gets the value associated with a provided key if available. |
| 67 | + * Otherwise, creates a value using the factory creator function, puts the value |
| 68 | + * in the cache, and returns the new value. |
| 69 | + * @param key A key associated with the value. |
| 70 | + * @param creator A factory function for the value if no value is present. |
| 71 | + * @returns A value associated with the provided key. |
| 72 | + */ |
| 73 | + async getOrCreate(key: string, creator: () => V | Promise<V>): Promise<V> { |
| 74 | + const namespacedKey = this.withNamespace(key); |
| 75 | + let value = await this.store.get(namespacedKey); |
| 76 | + |
| 77 | + if (value === undefined) { |
| 78 | + value = await creator(); |
| 79 | + await this.store.set(namespacedKey, value); |
| 80 | + } |
| 81 | + |
| 82 | + return value; |
| 83 | + } |
| 84 | + |
| 85 | + /** |
| 86 | + * Gets the value associated with a provided key if available. |
| 87 | + * @param key A key associated with the value. |
| 88 | + * @returns A value associated with the provided key if present. Otherwise, `undefined`. |
| 89 | + */ |
| 90 | + async get(key: string): Promise<V | undefined> { |
| 91 | + const value = await this.store.get(this.withNamespace(key)); |
| 92 | + |
| 93 | + return value; |
| 94 | + } |
| 95 | + |
| 96 | + /** |
| 97 | + * Puts a value in the cache and associates it with the provided key. |
| 98 | + * If the key is already present, the value is updated instead. |
| 99 | + * @param key A key associated with the value. |
| 100 | + * @param value A value to put in the cache. |
| 101 | + */ |
| 102 | + async put(key: string, value: V): Promise<void> { |
| 103 | + await this.store.set(this.withNamespace(key), value); |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +/** |
| 108 | + * A lightweight in-memory cache implementation based on a JavaScript Map object. |
| 109 | + */ |
| 110 | +export class MemoryCache<V> extends Cache<V, Map<string, V>> { |
| 111 | + constructor() { |
| 112 | + super(new Map()); |
| 113 | + } |
| 114 | + |
| 115 | + /** |
| 116 | + * Removes all entries from the cache instance. |
| 117 | + */ |
| 118 | + clear() { |
| 119 | + this.store.clear(); |
| 120 | + } |
| 121 | + |
| 122 | + /** |
| 123 | + * Provides all the values currently present in the cache instance. |
| 124 | + * @returns An iterable of all values in the cache. |
| 125 | + */ |
| 126 | + values() { |
| 127 | + return this.store.values(); |
| 128 | + } |
| 129 | +} |
0 commit comments