chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import fs from 'fs'
|
||||
import pathlib from 'path'
|
||||
import * as json from './json-utils'
|
||||
|
||||
export class FSKeyValueCache<T extends Object> {
|
||||
private _initialized = false
|
||||
|
||||
public constructor(private _filepath: string) {}
|
||||
|
||||
public async init(): Promise<void> {
|
||||
if (this._initialized) {
|
||||
return
|
||||
}
|
||||
const dirname = pathlib.dirname(this._filepath)
|
||||
if (!fs.existsSync(dirname)) {
|
||||
await fs.promises.mkdir(dirname, { recursive: true })
|
||||
}
|
||||
if (!fs.existsSync(this._filepath)) {
|
||||
await this._writeJSON(this._filepath, {})
|
||||
}
|
||||
this._initialized = true
|
||||
}
|
||||
|
||||
public async sync<K extends keyof T>(
|
||||
key: K,
|
||||
value: T[K] | undefined,
|
||||
prompt: (initial?: T[K]) => Promise<T[K]>
|
||||
): Promise<T[K]> {
|
||||
await this.init()
|
||||
if (value) {
|
||||
await this.set(key, value)
|
||||
return value
|
||||
}
|
||||
const data = await this.get(key)
|
||||
const newValue = await prompt(data)
|
||||
await this.set(key, newValue)
|
||||
return newValue
|
||||
}
|
||||
|
||||
public async has<K extends keyof T>(key: K): Promise<boolean> {
|
||||
await this.init()
|
||||
const data = await this._readJSON(this._filepath)
|
||||
return data[key] !== undefined
|
||||
}
|
||||
|
||||
public async get<K extends keyof T>(key: K): Promise<T[K] | undefined> {
|
||||
await this.init()
|
||||
const data: T = await this._readJSON(this._filepath)
|
||||
return data[key]
|
||||
}
|
||||
|
||||
public async set<K extends keyof T>(key: K, value: T[K]): Promise<void> {
|
||||
await this.init()
|
||||
const data: T = await this._readJSON(this._filepath)
|
||||
data[key] = value
|
||||
return this._writeJSON(this._filepath, data)
|
||||
}
|
||||
|
||||
public async rm<K extends keyof T>(key: K): Promise<void> {
|
||||
await this.init()
|
||||
const data: T = await this._readJSON(this._filepath)
|
||||
delete data[key]
|
||||
return this._writeJSON(this._filepath, data)
|
||||
}
|
||||
|
||||
public async clear(): Promise<void> {
|
||||
await this.init()
|
||||
return this._writeJSON(this._filepath, {})
|
||||
}
|
||||
|
||||
private _writeJSON = (filepath: string, data: any) => {
|
||||
const fileContent = JSON.stringify(data, null, 2)
|
||||
return fs.promises.writeFile(filepath, fileContent)
|
||||
}
|
||||
|
||||
private _readJSON = async (filepath: string) => {
|
||||
const fileContent = await fs.promises.readFile(filepath, 'utf8')
|
||||
const parseResult = json.safeParseJson(fileContent)
|
||||
if (!parseResult.success) {
|
||||
throw new Error(`Failed to parse JSON file at ${filepath}: ${parseResult.error.message}`)
|
||||
}
|
||||
return parseResult.data as T
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user