@stylable/core
Version:
CSS for Components
78 lines (68 loc) • 2.36 kB
text/typescript
export type processFn<T> = (fullpath: string, content: string) => T;
export interface CacheItem<T> {
value: T;
stat: { mtime: Date };
}
export interface MinimalFS {
statSync: (fullpath: string) => { mtime: Date };
readFileSync: (fullpath: string, encoding: 'utf8') => string;
readlinkSync(path: string): string;
}
export interface FileProcessor<T> {
process: (fullpath: string, ignoreCache?: boolean, context?: string) => T;
add: (fullpath: string, value: T) => void;
processContent: (content: string, fullpath: string) => T;
cache: Record<string, CacheItem<T>>;
postProcessors: Array<(value: T, path: string) => T>;
resolvePath: (path: string, context?: string) => string;
}
export function cachedProcessFile<T = any>(
processor: processFn<T>,
fs: MinimalFS,
resolvePath: (path: string, context?: string) => string
): FileProcessor<T> {
const cache: { [key: string]: CacheItem<T> } = {};
const postProcessors: Array<(value: T, path: string) => T> = [];
function process(fullpath: string, ignoreCache = false, context?: string) {
const resolvedPath = resolvePath(fullpath, context);
const stat = fs.statSync(resolvedPath);
const cached = cache[resolvedPath];
if (
ignoreCache ||
!cached ||
(cached && cached.stat.mtime.valueOf() !== stat.mtime.valueOf())
) {
const content = fs.readFileSync(resolvedPath, 'utf8');
const value = processContent(content, resolvedPath);
cache[resolvedPath] = { value, stat: { mtime: stat.mtime } };
}
return cache[resolvedPath].value;
}
function processContent(content: string, filePath: string): T {
return postProcessors.reduce<T>((value, postProcessor) => {
return postProcessor(value, filePath);
}, processor(filePath, content));
}
function add(fullpath: string, value: T) {
let mtime;
try {
mtime = fs.statSync(fullpath).mtime;
} catch (e) {
mtime = new Date();
}
cache[fullpath] = {
value,
stat: {
mtime,
},
};
}
return {
processContent,
postProcessors,
cache,
process,
add,
resolvePath,
};
}