UNPKG

@kv-systems/ng-packagr

Version:

Compile and package Angular libraries in Angular Package Format (APF)

86 lines (72 loc) 2.51 kB
import type { OnLoadResult, PluginBuild } from 'esbuild'; import { normalize } from 'node:path'; export interface LoadResultCache { get(path: string): OnLoadResult | undefined; put(path: string, result: OnLoadResult): Promise<void>; readonly watchFiles: ReadonlyArray<string>; } export function createCachedLoad( cache: LoadResultCache | undefined, callback: Parameters<PluginBuild['onLoad']>[1], ): Parameters<PluginBuild['onLoad']>[1] { if (cache === undefined) { return callback; } return async (args) => { const loadCacheKey = `${args.namespace}:${args.path}`; let result: OnLoadResult | null | undefined = cache.get(loadCacheKey); if (result === undefined) { result = await callback(args); // Do not cache null or undefined if (result) { // Ensure requested path is included if it was a resolved file if (args.namespace === 'file') { result.watchFiles ??= []; result.watchFiles.push(args.path); } await cache.put(loadCacheKey, result); } } return result; }; } export class MemoryLoadResultCache implements LoadResultCache { #loadResults = new Map<string, OnLoadResult>(); #fileDependencies = new Map<string, Set<string>>(); get(path: string): OnLoadResult | undefined { return this.#loadResults.get(path); } async put(path: string, result: OnLoadResult): Promise<void> { this.#loadResults.set(path, result); if (result.watchFiles) { for (const watchFile of result.watchFiles) { // Normalize the watch file path to ensure OS consistent paths const normalizedWatchFile = normalize(watchFile); let affected = this.#fileDependencies.get(normalizedWatchFile); if (affected === undefined) { affected = new Set(); this.#fileDependencies.set(normalizedWatchFile, affected); } affected.add(path); } } } invalidate(path: string): boolean { const affectedPaths = this.#fileDependencies.get(path); let found = false; if (affectedPaths) { for (const affected of affectedPaths) { if (this.#loadResults.delete(affected)) { found = true; } } this.#fileDependencies.delete(path); } return found; } get watchFiles(): string[] { // this.#loadResults.keys() is not included here because the keys // are namespaced request paths and not disk-based file paths. return [...this.#fileDependencies.keys()]; } }