@dxtmisha/scripts
Version:
Development scripts and CLI tools for DXT UI projects - automated component generation, library building and project management tools
248 lines (218 loc) • 7.52 kB
text/typescript
import { toArray } from '@dxtmisha/functional'
import {
PropertiesFile,
type PropertiesFilePath,
type PropertiesFileValue
} from './PropertiesFile'
const DIR_CACHE = ['.cache']
const DIR_STEP = ['step']
const FILE_SYSTEM = 'system'
type PropertiesCacheList = Record<string, string[]>
type PropertiesCacheSystem = {
time: number
files: PropertiesCacheList
sizes: PropertiesCacheList
}
/**
* Processing for storing temporary files.
*
* Обработка для хранения временных файлов.
*/
export class PropertiesCache {
private static time = 0
private static readonly files: PropertiesCacheList = {}
private static readonly sizes: PropertiesCacheList = {}
private static readonly listenerName: string[] = ['global']
/**
* Reads data from the cache or updates the cache if the data is outdated.
*
* Читает данные из кэша или обновляет кэш, если данные устарели.
* @param path path to the file/ путь к файлу
* @param name file name/ название файла
* @param callback if the file is not found, the callback function is called
* and its result is saved in the current file /
* если файл не найден, вызывается функция обратного вызова (callback) и её
* результат сохраняется в текущем файле
* @param extension file extension by default is json/ расширение файла по умолчанию - json
*/
static get<T extends PropertiesFileValue>(
path: PropertiesFilePath,
name: string,
callback: () => T,
extension = 'json'
): T {
if (
this.is(path, name, extension)
&& this.isBySystem(name)
) {
return this.readFile<T>(path, name, extension) as T
}
this.listenerName.push(name)
const value = callback()
this.writeFile(path, name, value, extension)
this.listenerName.pop()
this.writeSystem()
return value
}
/**
* Returns the content of the file by the specified path
*
* Возвращает содержимое файла по указанному пути.
* @param path filename/ имя файла
*/
static read<R>(path: PropertiesFilePath): R | undefined {
if (PropertiesFile.is(path)) {
const value = PropertiesFile.joinPath(path)
this.listenerName.forEach((name) => {
if (!(name in this.files)) {
this.files[name] = [value]
} else if (this.files?.[name]?.indexOf(value) === -1) {
this.files[name].push(value)
}
})
}
return PropertiesFile.readFile<R>(path)
}
/**
* Saves intermediate data
*
* Сохраняет промежуточные данные.
* @param name file name/ название файла
* @param value values for storage/ значения для хранения
*/
static write<T extends PropertiesFileValue>(name: string, value: T): void {
this.writeFile<T>(DIR_STEP, name, value)
}
/**
* Clear cached data
*
* Очистить кешированные данные.
*/
static clear(): void {
PropertiesFile.removeDir(this.getPath([]))
}
/**
* Checks if there are files to read
*
* Проверяет наличие файлов для чтения.
* @param path path to the file/ путь к файлу
* @param name file name/ название файла
* @param extension file extension by default is json/ расширение файла по умолчанию - json
*/
private static is(
path: PropertiesFilePath,
name: string,
extension = 'json'
): boolean {
return PropertiesFile.is(this.getPathName(path, name, extension))
}
/**
* Checks if there are updated files
*
* Проверяет, есть ли обновленные файлы.
* @param name the name of the cache/ название кэша
*/
private static isBySystem(name = 'global'): boolean {
let notUpdate = true
if (name in this.files) {
this.files?.[name]?.forEach((path) => {
const stat = PropertiesFile.stat(path)
if (stat && stat.mtimeMs > this.time) {
notUpdate = false
this.console(`Modified file: ${name}, ${path}`)
}
})
}
return notUpdate
}
/**
* Returns the path to the file
*
* Возвращает путь к файлу.
* @param path path to the file/ путь к файлу
*/
private static getPath(path: PropertiesFilePath): string[] {
return [PropertiesFile.getRoot(), ...DIR_CACHE, ...toArray(path)]
}
/**
* Returns the full path to the file
*
* Возвращает полный путь к файлу.
* @param path path to the file/ путь к файлу
* @param name file name/ название файла
* @param extension file extension by default is json/ расширение файла по умолчанию - json
*/
private static getPathName(
path: PropertiesFilePath,
name: string,
extension = 'json'
): string[] {
return PropertiesFile.getPathFile(this.getPath(path), name, extension)
}
/**
* Reads the content of the file
*
* Читает содержимое файла.
* @param path path to the file/ путь к файлу
* @param name file name/ название файла
* @param extension file extension by default is json/ расширение файла по умолчанию - json
*/
private static readFile<R>(
path: PropertiesFilePath,
name: string,
extension = 'json'
): R | undefined {
return PropertiesFile.readFile<R>(this.getPathName(path, name, extension))
}
/**
* Writing data to a file
*
* Запись данных в файл.
* @param path path to the file/ путь к файлу
* @param name file name/ название файла
* @param value values for storage/ значения для хранения
* @param extension file extension by default is json/ расширение файла по умолчанию - json
*/
private static writeFile<T extends PropertiesFileValue>(
path: PropertiesFilePath,
name: string,
value: T,
extension = 'json'
): void {
PropertiesFile.write(this.getPath(path), name, value, extension)
}
/**
* Updates the system data and writes them. Executes after saving the cache
*
* Обновляет системные данные и записывает их. Выполняется после сохранения кэша.
*/
private static writeSystem(): void {
if (this.listenerName.length < 2) {
this.time = new Date().getTime()
const data: PropertiesCacheSystem = {
time: this.time,
files: this.files,
sizes: this.sizes
}
this.writeFile([], FILE_SYSTEM, data)
this.console('Writes the system data')
}
}
/**
* Adding a new message to the console
*
* Добавление нового сообщения в консоли.
* @param text text of the message/ текст сообщения
*/
private static console(text: string): void {
console.info('[Cache]', text)
}
static {
const system = this.readFile<PropertiesCacheSystem>([], FILE_SYSTEM)
if (system) {
this.time = system.time
Object.assign(this.files, system.files)
Object.assign(this.sizes, system.sizes)
}
}
}