key-file-storage
Advanced tools
Comparing version 2.2.10 to 2.3.0
import { KeyFileStorage } from './src/key-file-storage'; | ||
/** | ||
* Returns an instance of `key-file-storage` to access the file system. | ||
* Returns an instance of `key-file-storage` store to access the file system. | ||
* @param path The root storage path on the file system: | ||
@@ -11,2 +11,4 @@ * * For example `'./the/path/to/data'` | ||
*/ | ||
export default function keyFileStorage(path: string, caching?: number | boolean): KeyFileStorage; | ||
declare function keyFileStorage<P = any>(path: string, caching?: number | boolean): KeyFileStorage<P>; | ||
export default keyFileStorage; | ||
export { keyFileStorage }; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.keyFileStorage = void 0; | ||
var create_cache_1 = require("./src/create-cache"); | ||
var key_file_storage_1 = require("./src/key-file-storage"); | ||
/** | ||
* Returns an instance of `key-file-storage` to access the file system. | ||
* Returns an instance of `key-file-storage` store to access the file system. | ||
* @param path The root storage path on the file system: | ||
@@ -16,5 +17,6 @@ * * For example `'./the/path/to/data'` | ||
var cache = create_cache_1.default(caching); | ||
var kfs = key_file_storage_1.default(path, cache); | ||
return kfs; | ||
var store = key_file_storage_1.default(path, cache); | ||
return store; | ||
} | ||
exports.keyFileStorage = keyFileStorage; | ||
exports.default = keyFileStorage; |
@@ -1,4 +0,4 @@ | ||
export interface KfsCache { | ||
export interface Cache { | ||
[key: string]: any; | ||
} | ||
export default function createCache(cacheConfig?: number | boolean): KfsCache; | ||
export default function createCache(cacheConfig?: number | boolean): Cache; |
@@ -15,4 +15,4 @@ export interface KeyFileBasic { | ||
} | ||
export default function keyFileBasic(kfsPath: string, cache: { | ||
export default function keyFileBasic(storagePath: string, cache: { | ||
[x: string]: any; | ||
}): KeyFileBasic; |
@@ -7,6 +7,6 @@ "use strict"; | ||
var recurFs = require('recur-fs'); | ||
function keyFileBasic(kfsPath, cache) { | ||
kfsPath = kfsPath || __dirname; // Current working folder by default. | ||
kfsPath = String(kfsPath); | ||
if (!isValidPath(kfsPath)) { | ||
function keyFileBasic(storagePath, cache) { | ||
storagePath = storagePath || __dirname; // Current working folder by default. | ||
storagePath = String(storagePath); | ||
if (!isValidPath(storagePath)) { | ||
throw new Error('Invalid stroage path.'); | ||
@@ -34,3 +34,3 @@ } | ||
key = validizeKey(key); | ||
var file = path_1.join(kfsPath, key); | ||
var file = path_1.join(storagePath, key); | ||
fs_extra_1.outputJsonSync(file, value, { spaces: 2 }); | ||
@@ -43,3 +43,3 @@ return (cache[key] = value); | ||
return cache[key]; | ||
var file = path_1.join(kfsPath, key); | ||
var file = path_1.join(storagePath, key); | ||
try { | ||
@@ -59,3 +59,3 @@ var status = fs_extra_1.statSync(file); | ||
return clearSync(); | ||
var file = path_1.join(kfsPath, key); | ||
var file = path_1.join(storagePath, key); | ||
fs_extra_1.removeSync(file); | ||
@@ -65,3 +65,3 @@ return delete cache[key]; | ||
function clearSync() { | ||
fs_extra_1.removeSync(kfsPath); | ||
fs_extra_1.removeSync(storagePath); | ||
return delete cache['*']; | ||
@@ -73,3 +73,3 @@ } | ||
return true; | ||
var file = path_1.join(kfsPath, key); | ||
var file = path_1.join(storagePath, key); | ||
try { | ||
@@ -90,7 +90,7 @@ var status = fs_extra_1.statSync(file); | ||
try { | ||
var collectionPath = path_1.join(kfsPath, collection); | ||
var collectionPath = path_1.join(storagePath, collection); | ||
var files = recurFs.readdir.sync(collectionPath, function (resource, status) { | ||
return status.isFile(); | ||
}); | ||
files = files.map(function (file) { return validizeKey(path_1.relative(kfsPath, file)); }); | ||
files = files.map(function (file) { return validizeKey(path_1.relative(storagePath, file)); }); | ||
return (cache[collection] = files || []); | ||
@@ -106,3 +106,3 @@ } | ||
key = validizeKey(key); | ||
var file = path_1.join(kfsPath, key); | ||
var file = path_1.join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
@@ -120,3 +120,3 @@ fs_extra_1.outputJson(file, value, { spaces: 2 }, function (err) { | ||
return Promise.resolve(cache[key]); | ||
var file = path_1.join(kfsPath, key); | ||
var file = path_1.join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
@@ -138,3 +138,3 @@ fs_extra_1.stat(file, function (err, status) { | ||
return clearAsync(); | ||
var file = path_1.join(kfsPath, key); | ||
var file = path_1.join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
@@ -150,3 +150,3 @@ fs_extra_1.remove(file, function (err) { | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.remove(kfsPath, function (err) { | ||
fs_extra_1.remove(storagePath, function (err) { | ||
if (err) | ||
@@ -162,3 +162,3 @@ return reject(err); | ||
return Promise.resolve(true); | ||
var file = path_1.join(kfsPath, key); | ||
var file = path_1.join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
@@ -183,7 +183,7 @@ fs_extra_1.stat(file, function (err, status) { | ||
// else { | ||
// resolve(resources.map(file => path.relative(kfsPath, file))); | ||
// resolve(resources.map(file => path.relative(storagePath, file))); | ||
// } | ||
// }); | ||
var fileList = [], jobNumber = 1, terminated = false; | ||
var collectionPath = path_1.join(kfsPath, collection); | ||
var collectionPath = path_1.join(storagePath, collection); | ||
fs_extra_1.stat(collectionPath, function (err, status) { | ||
@@ -203,3 +203,3 @@ if (err) { | ||
return; | ||
var folderPath = path_1.join(kfsPath, folder); | ||
var folderPath = path_1.join(storagePath, folder); | ||
fs_extra_1.readdir(folderPath, function (err, files) { | ||
@@ -230,3 +230,3 @@ if (terminated) | ||
if (status.isFile()) { | ||
fileList.push(validizeKey(path_1.relative(kfsPath, filePath))); | ||
fileList.push(validizeKey(path_1.relative(storagePath, filePath))); | ||
} | ||
@@ -233,0 +233,0 @@ else if (status.isDirectory()) { |
@@ -1,4 +0,4 @@ | ||
export interface KeyFileStorage { | ||
[key: string]: any; | ||
[index: number]: any; | ||
export interface KeyFileStorage<P> { | ||
[key: string]: P; | ||
[index: number]: P; | ||
<T, U = T>(key: string | number, value: T, callback?: (error: any) => U): Promise<U>; | ||
@@ -10,4 +10,4 @@ <T = any, U = T>(key: string | number, callback?: (error: any, value?: T) => U): Promise<U>; | ||
} | ||
export default function createKfs(kfsPath: string, cache: { | ||
[x: string]: any; | ||
}): KeyFileStorage; | ||
export default function createStore<P>(storagePath: string, cache: { | ||
[x: string]: P; | ||
}): KeyFileStorage<P>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var key_file_basic_1 = require("./key-file-basic"); | ||
function createKfs(kfsPath, cache) { | ||
var kfb = key_file_basic_1.default(kfsPath, cache); | ||
function createStore(storagePath, cache) { | ||
var kfb = key_file_basic_1.default(storagePath, cache); | ||
// The produced promise and callback function related to the latest async 'in' operator | ||
@@ -22,3 +22,3 @@ var hasAsyncHandler = null, hasAsyncPromise = null; | ||
}; | ||
var kfs = new Proxy(function () { | ||
var store = new Proxy(function () { | ||
var a1 = arguments[0], a2 = arguments[1], a3 = arguments[2]; | ||
@@ -127,3 +127,3 @@ switch (arguments.length) { | ||
}); | ||
return kfs; | ||
return store; | ||
function callbackizePromise(promise, callback) { | ||
@@ -140,2 +140,2 @@ if (typeof callback === 'function') { | ||
} | ||
exports.default = createKfs; | ||
exports.default = createStore; |
"use strict"; | ||
exports.__esModule = true; | ||
exports.keyFileStorage = void 0; | ||
var create_cache_1 = require("./src/create-cache"); | ||
var key_file_storage_1 = require("./src/key-file-storage"); | ||
/** | ||
* Returns an instance of `key-file-storage` to access the file system. | ||
* Returns an instance of `key-file-storage` store to access the file system. | ||
* @param path The root storage path on the file system: | ||
@@ -16,5 +17,6 @@ * * For example `'./the/path/to/data'` | ||
var cache = create_cache_1["default"](caching); | ||
var kfs = key_file_storage_1["default"](path, cache); | ||
return kfs; | ||
var store = key_file_storage_1["default"](path, cache); | ||
return store; | ||
} | ||
exports.keyFileStorage = keyFileStorage; | ||
exports["default"] = keyFileStorage; |
13
index.ts
import createCache from './src/create-cache'; | ||
import createKfs, { KeyFileStorage } from './src/key-file-storage'; | ||
import createStore, { KeyFileStorage } from './src/key-file-storage'; | ||
/** | ||
* Returns an instance of `key-file-storage` to access the file system. | ||
* Returns an instance of `key-file-storage` store to access the file system. | ||
* @param path The root storage path on the file system: | ||
@@ -13,6 +13,9 @@ * * For example `'./the/path/to/data'` | ||
*/ | ||
export default function keyFileStorage(path: string, caching?: number | boolean): KeyFileStorage { | ||
function keyFileStorage<P = any>(path: string, caching?: number | boolean): KeyFileStorage<P> { | ||
var cache = createCache(caching); | ||
var kfs = createKfs(path, cache); | ||
return kfs; | ||
var store = createStore<P>(path, cache); | ||
return store; | ||
} | ||
export default keyFileStorage; | ||
export { keyFileStorage }; |
{ | ||
"name": "key-file-storage", | ||
"version": "2.2.10", | ||
"version": "2.3.0", | ||
"description": "Simple key-value storage directly on file system, maps each key to a separate file.", | ||
@@ -10,3 +10,2 @@ "main": "dist/index.js", | ||
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"", | ||
"lint": "tslint -p tsconfig.json", | ||
"test": "tsc test.ts && node test" | ||
@@ -52,6 +51,4 @@ }, | ||
"rimraf": "^3.0.2", | ||
"tslint": "^5.20.1", | ||
"tslint-config-prettier": "^1.18.0", | ||
"typescript": "^4.3.2" | ||
} | ||
} |
133
README.md
@@ -12,16 +12,16 @@ # key-file-storage | ||
```javascript | ||
const kfs = require("key-file-storage")('my/storage/path') | ||
```ts | ||
const store = require("key-file-storage")('my/storage/path') | ||
// Write something to file 'my/storage/path/myfile' | ||
kfs.myfile = { x: 123 } | ||
store.myfile = { x: 123 } | ||
// Read contents of file 'my/storage/path/myfile' | ||
const x = kfs.myfile.x | ||
const x = store.myfile.x | ||
// Delete file 'my/storage/path/myfile' | ||
delete kfs.myfile | ||
delete store.myfile | ||
``` | ||
A very nice alternative for any of these node modules: [node-persist](https://www.npmjs.com/package/node-persist), [configstore](https://www.npmjs.com/package/configstore), [flat-cache](https://www.npmjs.com/package/flat-cache), [conf](https://www.npmjs.com/package/conf), [simple-store](https://www.npmjs.com/package/simple-store) and more... | ||
A nice alternative for any of these libraries: [node-persist](https://www.npmjs.com/package/node-persist), [configstore](https://www.npmjs.com/package/configstore), [flat-cache](https://www.npmjs.com/package/flat-cache), [conf](https://www.npmjs.com/package/conf), [simple-store](https://www.npmjs.com/package/simple-store), and more... | ||
@@ -38,6 +38,10 @@ ## Installation | ||
Initializing a key-file storage: | ||
```javascript | ||
const keyFileStorage = require("key-file-storage") | ||
```ts | ||
// ES Modules import style: | ||
import kfs from 'key-file-storage' | ||
const kfs = keyFileStorage('/storage/directory/path', caching) | ||
// CommonJS import style: | ||
const kfs = require("key-file-storage") | ||
const store = kfs('/storage/directory/path', caching) | ||
``` | ||
@@ -59,22 +63,22 @@ | ||
```javascript | ||
kfs['key'] = value // Write file | ||
```ts | ||
store['key'] = value // Write file | ||
``` | ||
```javascript | ||
kfs['key'] // Read file | ||
```ts | ||
store['key'] // Read file | ||
``` | ||
```javascript | ||
delete kfs['key'] // Delete file | ||
```ts | ||
delete store['key'] // Delete file | ||
``` | ||
```javascript | ||
delete kfs['*'] // Delete all storage files | ||
```ts | ||
delete store['*'] // Delete all storage files | ||
``` | ||
```javascript | ||
'key' in kfs // Check for file existence | ||
```ts | ||
'key' in store // Check for file existence | ||
//=> true or false | ||
``` | ||
- You can use `kfs.keyName` instead of `kfs['keyName']` anywhere if the key name allows. | ||
- You can use `store.keyName` instead of `store['keyName']` anywhere if the key name allows. | ||
- `undefined` is not supported as a savable value, but `null` is. Saving a key with value `undefined` is equivalent to remove it. So, you can use `kfs['key'] = undefined` or even `kfs['*'] = undefined` to delete files. | ||
- `undefined` is not supported as a savable value, but `null` is. Saving a key with value `undefined` is equivalent to remove it. So, you can use `store['key'] = undefined` or even `store['*'] = undefined` to delete files. | ||
@@ -87,45 +91,45 @@ - Synchronous API will throw an exception if any errors happen, so you shall handle it your way. | ||
```javascript | ||
kfs('key', value) // Write file | ||
```ts | ||
store('key', value) // Write file | ||
``` | ||
```javascript | ||
kfs('key') // Read file | ||
```ts | ||
store('key') // Read file | ||
``` | ||
```javascript | ||
new kfs('key') // Delete file | ||
```ts | ||
new store('key') // Delete file | ||
``` | ||
```javascript | ||
new kfs('*') /* or */ | ||
new kfs() /* or */ | ||
new kfs // Delete all storage files | ||
```ts | ||
new store('*') /* or */ | ||
new store() /* or */ | ||
new store // Delete all storage files | ||
``` | ||
```javascript | ||
('key' in kfs(), kfs()) // Check for file existence | ||
```ts | ||
('key' in store(), store()) // Check for file existence | ||
// Resolves to true or false | ||
``` | ||
- Once again, `undefined` is not supported as a savable value, but `null` is. Saving a key with value `undefined` is equivalent to remove it. So, you can use `kfs('key', undefined)` or even `kfs('*', undefined)` to delete files. | ||
- Once again, `undefined` is not supported as a savable value, but `null` is. Saving a key with value `undefined` is equivalent to remove it. So, you can use `store('key', undefined)` or even `store('*', undefined)` to delete files. | ||
### Asynchronous API with Callbacks | ||
The same as asynchronous with promises, but with callback function as the last input parameter of `kfs()` : | ||
The same as asynchronous with promises, but with callback function as the last input parameter of `store()` : | ||
```javascript | ||
kfs('key', value, cb) // Write file | ||
```ts | ||
store('key', value, cb) // Write file | ||
``` | ||
```javascript | ||
kfs('key', cb) // Read file | ||
```ts | ||
store('key', cb) // Read file | ||
``` | ||
```javascript | ||
new kfs('key', cb) // Delete file | ||
```ts | ||
new store('key', cb) // Delete file | ||
``` | ||
```javascript | ||
new kfs('*', cb) /* or */ | ||
new kfs(cb) // Delete all storage files | ||
```ts | ||
new store('*', cb) /* or */ | ||
new store(cb) // Delete all storage files | ||
``` | ||
```javascript | ||
'key' in kfs(cb) // Check for file existence | ||
```ts | ||
'key' in store(cb) // Check for file existence | ||
// without promise output | ||
/* or */ | ||
('key' in kfs(), kfs(cb)) | ||
('key' in store(), store(cb)) | ||
// Check for file existence | ||
@@ -135,3 +139,3 @@ // with promise output | ||
- These calls *still* return a promise on their output (except for `'key' in kfs(callback)` form of existence check). | ||
- These calls *still* return a promise on their output (except for `'key' in store(callback)` form of existence check). | ||
@@ -148,5 +152,5 @@ - The first input parameter of all callback functions is `err`, so you shall handle it within the callback. *Reading* and *Existence checking* callbacks provide the return values as their second input parameter. | ||
```javascript | ||
```ts | ||
try { | ||
const keys = kfs['col/path/'] | ||
const keys = store['col/path/'] | ||
// keys = ['col/path/key1', 'col/path/sub/key2', ... ] | ||
@@ -160,4 +164,4 @@ } catch (error) { | ||
```javascript | ||
kfs('col/path/') | ||
```ts | ||
store('col/path/') | ||
.then(keys => { | ||
@@ -173,4 +177,4 @@ // keys = ['col/path/key1', 'col/path/sub/key2', ... ] | ||
```javascript | ||
kfs('col/path/', (error, keys) => { | ||
```ts | ||
store('col/path/', (error, keys) => { | ||
if (error) { | ||
@@ -195,13 +199,20 @@ // handle error... | ||
- **NOTE 6 :** For _TypeScript_ developers, you may indicate the store's value type when creating it: `const store = kfs<DataType>(...)`. | ||
## Example | ||
```javascript | ||
const keyFileStorage = require("key-file-storage") | ||
```ts | ||
import kfs from "key-file-storage" | ||
interface User { | ||
readonly name: string | ||
readonly skills: Readonly<Partial<Record<string, number>>> | ||
} | ||
// Locate 'db' folder in the current directory as the storage path, | ||
// Require 100 latest accessed key-values to be cached: | ||
const kfs = keyFileStorage('./db', 100) | ||
const store = kfs<User>('./db', 100) | ||
// Create file './db/users/hessam' containing this user data, synchronously: | ||
kfs['users/hessam'] = ({ | ||
store['users/hessam'] = ({ | ||
name: "Hessam", | ||
@@ -215,3 +226,3 @@ skills: { | ||
// Read file './db/users/hessam' as a JSON object, asynchronously: | ||
kfs('users/hessam').then(hessam => { | ||
store('users/hessam').then(hessam => { | ||
console.log(`Hessam's java skill is ${hessam.skills.java}.`) | ||
@@ -221,3 +232,3 @@ }) | ||
// Check whether file './db/users/mahdiar' exists or not, asynchronously: | ||
'users/mahdiar' in kfs((error, exists) => { | ||
'users/mahdiar' in store((error, exists) => { | ||
if (exists) { | ||
@@ -229,3 +240,3 @@ console.log("User Mahdiar exists!") | ||
// List all the keys in './db/users/', synchronously: | ||
const allUsers = kfs['users/'] | ||
const allUsers = store['users/'] | ||
//=> ['users/hessam', 'users/mahdiar', ... ] | ||
@@ -232,0 +243,0 @@ ``` |
@@ -1,204 +0,186 @@ | ||
'use strict'; | ||
"use strict"; | ||
exports.__esModule = true; | ||
function createCache(cacheConfig) { | ||
if (cacheConfig === true || typeof cacheConfig === 'undefined') { | ||
// Unlimited cache by default | ||
return createCache_Unlimited(cacheConfig); | ||
} else if (cacheConfig === false) { | ||
// No cache | ||
return createCache_NoCache(cacheConfig); | ||
} else if (typeof cacheConfig === 'number' && cacheConfig > 0) { | ||
// Limited cache by the number of keys | ||
return createCache_LimitedByKeyCount(cacheConfig); | ||
} else { | ||
throw new Error('Invalid cache config.'); | ||
} | ||
function createCache_Unlimited(cacheConfig) { | ||
var collectionCache = {}; | ||
return new Proxy( | ||
{ | ||
if (cacheConfig === true || typeof cacheConfig === 'undefined') { | ||
// Unlimited cache by default | ||
return createCache_Unlimited(cacheConfig); | ||
} | ||
else if (cacheConfig === false) { | ||
// No cache | ||
return createCache_NoCache(cacheConfig); | ||
} | ||
else if (typeof cacheConfig === 'number' && cacheConfig > 0) { | ||
// Limited cache by the number of keys | ||
return createCache_LimitedByKeyCount(cacheConfig); | ||
} | ||
else { | ||
throw new Error('Invalid cache config.'); | ||
} | ||
function createCache_Unlimited(cacheConfig) { | ||
var collectionCache = {}; | ||
return new Proxy({ | ||
/*CACHE*/ | ||
}, | ||
{ | ||
set: function (target, property, value, receiver) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) { | ||
collectionCache[propertyName] = value; | ||
return true; | ||
} | ||
target[propertyName] = value; | ||
Object.keys(collectionCache) | ||
.filter(function (collection) { | ||
return keyInCollection(propertyName, collection); | ||
}) | ||
.forEach(function (collection) { | ||
return ( | ||
collectionCache[collection].includes(propertyName) || collectionCache[collection].push(propertyName) | ||
); | ||
}); | ||
return true; | ||
}, | ||
get: function (target, property, receiver) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) return collectionCache[propertyName]; | ||
return target[propertyName]; | ||
}, | ||
deleteProperty: function (target, property) { | ||
var propertyName = String(property); | ||
if (propertyName === '*') { | ||
collectionCache = {}; | ||
Object.keys(target).forEach(function (key) { | ||
return delete target[key]; | ||
}); | ||
return true; | ||
} | ||
if (propertyName.endsWith('/')) return delete collectionCache[propertyName]; | ||
Object.keys(collectionCache) | ||
.filter(function (collection) { | ||
return keyInCollection(propertyName, collection); | ||
}) | ||
.forEach(function (collection) { | ||
return ( | ||
collectionCache[collection].includes(propertyName) && | ||
collectionCache[collection].splice(collectionCache[collection].indexOf(propertyName), 1) | ||
); | ||
}); | ||
return delete target[propertyName]; | ||
}, | ||
has: function (target, property) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) return propertyName in collectionCache; | ||
return property in target; | ||
}, | ||
}, | ||
); | ||
} | ||
function createCache_NoCache(cacheConfig) { | ||
return new Proxy( | ||
{ | ||
}, { | ||
set: function (target, property, value, receiver) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) { | ||
collectionCache[propertyName] = value; | ||
return true; | ||
} | ||
target[propertyName] = value; | ||
Object.keys(collectionCache) | ||
.filter(function (collection) { return keyInCollection(propertyName, collection); }) | ||
.forEach(function (collection) { | ||
return collectionCache[collection].includes(propertyName) || collectionCache[collection].push(propertyName); | ||
}); | ||
return true; | ||
}, | ||
get: function (target, property, receiver) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) | ||
return collectionCache[propertyName]; | ||
return target[propertyName]; | ||
}, | ||
deleteProperty: function (target, property) { | ||
var propertyName = String(property); | ||
if (propertyName === '*') { | ||
collectionCache = {}; | ||
Object.keys(target).forEach(function (key) { return delete target[key]; }); | ||
return true; | ||
} | ||
if (propertyName.endsWith('/')) | ||
return delete collectionCache[propertyName]; | ||
Object.keys(collectionCache) | ||
.filter(function (collection) { return keyInCollection(propertyName, collection); }) | ||
.forEach(function (collection) { | ||
return collectionCache[collection].includes(propertyName) && | ||
collectionCache[collection].splice(collectionCache[collection].indexOf(propertyName), 1); | ||
}); | ||
return delete target[propertyName]; | ||
}, | ||
has: function (target, property) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) | ||
return propertyName in collectionCache; | ||
return property in target; | ||
} | ||
}); | ||
} | ||
function createCache_NoCache(cacheConfig) { | ||
return new Proxy({ | ||
/*CACHE*/ | ||
}, | ||
{ | ||
set: function (target, property, value, receiver) { | ||
return true; | ||
}, | ||
get: function (target, property, receiver) { | ||
return undefined; | ||
}, | ||
deleteProperty: function (target, property) { | ||
return true; | ||
}, | ||
has: function (target, property) { | ||
return false; | ||
}, | ||
}, | ||
); | ||
} | ||
function createCache_LimitedByKeyCount(cacheConfig) { | ||
var collectionCache = {}; | ||
var keyNumber = Math.ceil(cacheConfig), | ||
keys = Array(keyNumber), | ||
nextKeyIndex = 0, | ||
keyIndex; | ||
return new Proxy( | ||
{ | ||
}, { | ||
set: function (target, property, value, receiver) { | ||
return true; | ||
}, | ||
get: function (target, property, receiver) { | ||
return undefined; | ||
}, | ||
deleteProperty: function (target, property) { | ||
return true; | ||
}, | ||
has: function (target, property) { | ||
return false; | ||
} | ||
}); | ||
} | ||
function createCache_LimitedByKeyCount(cacheConfig) { | ||
var collectionCache = {}; | ||
var keyNumber = Math.ceil(cacheConfig), keys = Array(keyNumber), nextKeyIndex = 0, keyIndex; | ||
return new Proxy({ | ||
/*CACHE*/ | ||
}, | ||
{ | ||
set: function (target, property, value, receiver) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) { | ||
collectionCache[propertyName] = value; | ||
return true; | ||
} | ||
updateKeys(target, propertyName, 'SET'); | ||
target[propertyName] = value; | ||
Object.keys(collectionCache) | ||
.filter(function (collection) { | ||
return keyInCollection(propertyName, collection); | ||
}) | ||
.forEach(function (collection) { | ||
return ( | ||
collectionCache[collection].includes(propertyName) || collectionCache[collection].push(propertyName) | ||
); | ||
}); | ||
return true; | ||
}, | ||
get: function (target, property, receiver) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) return collectionCache[propertyName]; | ||
updateKeys(target, propertyName, 'GET'); | ||
return target[propertyName]; | ||
}, | ||
deleteProperty: function (target, property) { | ||
var propertyName = String(property); | ||
if (propertyName === '*') { | ||
collectionCache = {}; | ||
keys = Array(keyNumber); | ||
nextKeyIndex = 0; | ||
return true; | ||
} | ||
if (propertyName.endsWith('/')) return delete collectionCache[propertyName]; | ||
Object.keys(collectionCache) | ||
.filter(function (collection) { | ||
return keyInCollection(propertyName, collection); | ||
}) | ||
.forEach(function (collection) { | ||
return ( | ||
collectionCache[collection].includes(propertyName) && | ||
collectionCache[collection].splice(collectionCache[collection].indexOf(propertyName), 1) | ||
); | ||
}); | ||
updateKeys(target, propertyName, 'DELETE'); | ||
return delete target[propertyName]; | ||
}, | ||
has: function (target, property) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) return propertyName in collectionCache; | ||
return keys.indexOf(property) >= 0; | ||
}, | ||
}, | ||
); | ||
function realIndex(i) { | ||
return (i + keyNumber) % keyNumber; | ||
} | ||
function updateKeys(target, property, mode) { | ||
keyIndex = keys.indexOf(property); | ||
if (keyIndex < 0) { | ||
// Does not exist | ||
mode === 'SET' && addKey(); | ||
} else if (keyIndex === realIndex(nextKeyIndex - 1)) { | ||
// The latest key | ||
mode === 'DELETE' && removeKey(); | ||
} else { | ||
// Otherwise | ||
removeKey(); | ||
mode === 'DELETE' || addKey(); | ||
} | ||
function removeKey() { | ||
while (keyIndex !== nextKeyIndex && keys[keyIndex]) { | ||
keys[keyIndex] = keys[realIndex(keyIndex - 1)]; | ||
keyIndex = realIndex(keyIndex - 1); | ||
}, { | ||
set: function (target, property, value, receiver) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) { | ||
collectionCache[propertyName] = value; | ||
return true; | ||
} | ||
updateKeys(target, propertyName, 'SET'); | ||
target[propertyName] = value; | ||
Object.keys(collectionCache) | ||
.filter(function (collection) { return keyInCollection(propertyName, collection); }) | ||
.forEach(function (collection) { | ||
return collectionCache[collection].includes(propertyName) || collectionCache[collection].push(propertyName); | ||
}); | ||
return true; | ||
}, | ||
get: function (target, property, receiver) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) | ||
return collectionCache[propertyName]; | ||
updateKeys(target, propertyName, 'GET'); | ||
return target[propertyName]; | ||
}, | ||
deleteProperty: function (target, property) { | ||
var propertyName = String(property); | ||
if (propertyName === '*') { | ||
collectionCache = {}; | ||
keys = Array(keyNumber); | ||
nextKeyIndex = 0; | ||
return true; | ||
} | ||
if (propertyName.endsWith('/')) | ||
return delete collectionCache[propertyName]; | ||
Object.keys(collectionCache) | ||
.filter(function (collection) { return keyInCollection(propertyName, collection); }) | ||
.forEach(function (collection) { | ||
return collectionCache[collection].includes(propertyName) && | ||
collectionCache[collection].splice(collectionCache[collection].indexOf(propertyName), 1); | ||
}); | ||
updateKeys(target, propertyName, 'DELETE'); | ||
return delete target[propertyName]; | ||
}, | ||
has: function (target, property) { | ||
var propertyName = String(property); | ||
if (propertyName.endsWith('/')) | ||
return propertyName in collectionCache; | ||
return keys.indexOf(property) >= 0; | ||
} | ||
}); | ||
function realIndex(i) { | ||
return (i + keyNumber) % keyNumber; | ||
} | ||
keys[nextKeyIndex] = undefined; | ||
} | ||
function addKey() { | ||
if (keys[nextKeyIndex] !== property) { | ||
if (keys[nextKeyIndex] !== undefined) delete target[keys[nextKeyIndex]]; | ||
keys[nextKeyIndex] = property; | ||
function updateKeys(target, property, mode) { | ||
keyIndex = keys.indexOf(property); | ||
if (keyIndex < 0) { | ||
// Does not exist | ||
mode === 'SET' && addKey(); | ||
} | ||
else if (keyIndex === realIndex(nextKeyIndex - 1)) { | ||
// The latest key | ||
mode === 'DELETE' && removeKey(); | ||
} | ||
else { | ||
// Otherwise | ||
removeKey(); | ||
mode === 'DELETE' || addKey(); | ||
} | ||
function removeKey() { | ||
while (keyIndex !== nextKeyIndex && keys[keyIndex]) { | ||
keys[keyIndex] = keys[realIndex(keyIndex - 1)]; | ||
keyIndex = realIndex(keyIndex - 1); | ||
} | ||
keys[nextKeyIndex] = undefined; | ||
} | ||
function addKey() { | ||
if (keys[nextKeyIndex] !== property) { | ||
if (keys[nextKeyIndex] !== undefined) | ||
delete target[keys[nextKeyIndex]]; | ||
keys[nextKeyIndex] = property; | ||
} | ||
nextKeyIndex = realIndex(nextKeyIndex + 1); | ||
} | ||
} | ||
nextKeyIndex = realIndex(nextKeyIndex + 1); | ||
} | ||
} | ||
} | ||
function keyInCollection(key, collection) { | ||
collection = collection.startsWith('./') | ||
? collection.slice(1) | ||
: collection.startsWith('/') | ||
? collection | ||
: '/' + collection; | ||
key = key.startsWith('./') ? key.slice(1) : key.startsWith('/') ? key : '/' + key; | ||
return key.startsWith(collection); | ||
} | ||
function keyInCollection(key, collection) { | ||
collection = collection.startsWith('./') | ||
? collection.slice(1) | ||
: collection.startsWith('/') | ||
? collection | ||
: '/' + collection; | ||
key = key.startsWith('./') ? key.slice(1) : key.startsWith('/') ? key : '/' + key; | ||
return key.startsWith(collection); | ||
} | ||
} | ||
exports['default'] = createCache; | ||
exports["default"] = createCache; |
@@ -1,10 +0,10 @@ | ||
export interface KfsCache { | ||
export interface Cache { | ||
[key: string]: any; | ||
} | ||
interface KfsCollectionCache { | ||
interface CollectionCache { | ||
[collection: string]: string[]; | ||
} | ||
export default function createCache(cacheConfig?: number | boolean): KfsCache { | ||
export default function createCache(cacheConfig?: number | boolean): Cache { | ||
if (cacheConfig === true || typeof cacheConfig === 'undefined') { | ||
@@ -24,5 +24,5 @@ // Unlimited cache by default | ||
function createCache_Unlimited(cacheConfig: true | undefined) { | ||
let collectionCache: KfsCollectionCache = {}; | ||
let collectionCache: CollectionCache = {}; | ||
return new Proxy<KfsCache>( | ||
return new Proxy<Cache>( | ||
{ | ||
@@ -82,3 +82,3 @@ /*CACHE*/ | ||
function createCache_NoCache(cacheConfig: false) { | ||
return new Proxy<KfsCache>( | ||
return new Proxy<Cache>( | ||
{ | ||
@@ -108,3 +108,3 @@ /*CACHE*/ | ||
function createCache_LimitedByKeyCount(cacheConfig: number) { | ||
let collectionCache: KfsCollectionCache = {}; | ||
let collectionCache: CollectionCache = {}; | ||
let keyNumber = Math.ceil(cacheConfig), | ||
@@ -115,3 +115,3 @@ keys = Array(keyNumber), | ||
return new Proxy<KfsCache>( | ||
return new Proxy<Cache>( | ||
{ | ||
@@ -118,0 +118,0 @@ /*CACHE*/ |
@@ -1,215 +0,239 @@ | ||
'use strict'; | ||
"use strict"; | ||
exports.__esModule = true; | ||
var fs_extra_1 = require('fs-extra'); | ||
var path_1 = require('path'); | ||
var fs_extra_1 = require("fs-extra"); | ||
var path_1 = require("path"); | ||
var isValidPath = require('is-valid-path'); | ||
var recurFs = require('recur-fs'); | ||
function keyFileBasic(kfsPath, cache) { | ||
kfsPath = kfsPath || __dirname; // Current working folder by default. | ||
kfsPath = String(kfsPath); | ||
if (!isValidPath(kfsPath)) { | ||
throw new Error('Invalid stroage path.'); | ||
} | ||
return { | ||
// Synchronous | ||
setSync: setSync, | ||
getSync: getSync, | ||
deleteSync: deleteSync, | ||
clearSync: clearSync, | ||
hasSync: hasSync, | ||
// Asynchronous | ||
setAsync: setAsync, | ||
getAsync: getAsync, | ||
deleteAsync: deleteAsync, | ||
clearAsync: clearAsync, | ||
hasAsync: hasAsync, | ||
// Iterate | ||
querySync: querySync, | ||
queryAsync: queryAsync, | ||
}; | ||
function setSync(key, value) { | ||
if (value === undefined) return deleteSync(key); | ||
key = validizeKey(key); | ||
var file = path_1.join(kfsPath, key); | ||
fs_extra_1.outputJsonSync(file, value, { spaces: 2 }); | ||
return (cache[key] = value); | ||
} | ||
function getSync(key) { | ||
key = validizeKey(key); | ||
if (key in cache) return cache[key]; | ||
var file = path_1.join(kfsPath, key); | ||
try { | ||
var status = fs_extra_1.statSync(file); | ||
if (!status || !status.isFile()) return (cache[key] = null); | ||
} catch (err) { | ||
return (cache[key] = null); | ||
function keyFileBasic(storagePath, cache) { | ||
storagePath = storagePath || __dirname; // Current working folder by default. | ||
storagePath = String(storagePath); | ||
if (!isValidPath(storagePath)) { | ||
throw new Error('Invalid stroage path.'); | ||
} | ||
return (cache[key] = fs_extra_1.readJsonSync(file)); | ||
} | ||
function deleteSync(key) { | ||
key = validizeKey(key); | ||
if (key === '*') return clearSync(); | ||
var file = path_1.join(kfsPath, key); | ||
fs_extra_1.removeSync(file); | ||
return delete cache[key]; | ||
} | ||
function clearSync() { | ||
fs_extra_1.removeSync(kfsPath); | ||
return delete cache['*']; | ||
} | ||
function hasSync(key) { | ||
key = validizeKey(key); | ||
if (key in cache) return true; | ||
var file = path_1.join(kfsPath, key); | ||
try { | ||
var status = fs_extra_1.statSync(file); | ||
if (!status || !status.isFile()) return false; | ||
} catch (err) { | ||
return false; | ||
return { | ||
// Synchronous | ||
setSync: setSync, | ||
getSync: getSync, | ||
deleteSync: deleteSync, | ||
clearSync: clearSync, | ||
hasSync: hasSync, | ||
querySync: querySync, | ||
// Asynchronous | ||
setAsync: setAsync, | ||
getAsync: getAsync, | ||
deleteAsync: deleteAsync, | ||
clearAsync: clearAsync, | ||
hasAsync: hasAsync, | ||
queryAsync: queryAsync | ||
}; | ||
function setSync(key, value) { | ||
if (value === undefined) | ||
return deleteSync(key); | ||
key = validizeKey(key); | ||
var file = path_1.join(storagePath, key); | ||
fs_extra_1.outputJsonSync(file, value, { spaces: 2 }); | ||
return (cache[key] = value); | ||
} | ||
return true; | ||
} | ||
function setAsync(key, value) { | ||
if (value === undefined) return deleteAsync(key); | ||
key = validizeKey(key); | ||
var file = path_1.join(kfsPath, key); | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.outputJson(file, value, { spaces: 2 }, function (err) { | ||
if (err) return reject(err); | ||
resolve((cache[key] = value)); | ||
}); | ||
}); | ||
} | ||
function getAsync(key) { | ||
key = validizeKey(key); | ||
if (key in cache) return Promise.resolve(cache[key]); | ||
var file = path_1.join(kfsPath, key); | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.stat(file, function (err, status) { | ||
if (err || !status || !status.isFile()) return resolve((cache[key] = null)); | ||
fs_extra_1.readJson(file, function (err, value) { | ||
if (err) return reject(err); | ||
resolve((cache[key] = value)); | ||
}); | ||
}); | ||
}); | ||
} | ||
function deleteAsync(key) { | ||
key = validizeKey(key); | ||
if (key === '*') return clearAsync(); | ||
var file = path_1.join(kfsPath, key); | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.remove(file, function (err) { | ||
if (err) return reject(err); | ||
resolve(delete cache[key]); | ||
}); | ||
}); | ||
} | ||
function clearAsync() { | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.remove(kfsPath, function (err) { | ||
if (err) return reject(err); | ||
resolve(delete cache['*']); | ||
}); | ||
}); | ||
} | ||
function hasAsync(key) { | ||
key = validizeKey(key); | ||
if (key in cache) return Promise.resolve(true); | ||
var file = path_1.join(kfsPath, key); | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.stat(file, function (err, status) { | ||
resolve(!!(!err && status && status.isFile())); | ||
}); | ||
}); | ||
} | ||
function querySync(collection) { | ||
collection = validizeKey(collection); | ||
if (collection in cache) return cache[collection]; | ||
try { | ||
var collectionPath = path_1.join(kfsPath, collection); | ||
var files = recurFs.readdir.sync(collectionPath, function (resource, status) { | ||
return status.isFile(); | ||
}); | ||
files = files.map(function (file) { | ||
return validizeKey(path_1.relative(kfsPath, file)); | ||
}); | ||
return (cache[collection] = files || []); | ||
} catch (err) { | ||
return []; | ||
function getSync(key) { | ||
key = validizeKey(key); | ||
if (key in cache) | ||
return cache[key]; | ||
var file = path_1.join(storagePath, key); | ||
try { | ||
var status = fs_extra_1.statSync(file); | ||
if (!status || !status.isFile()) | ||
return (cache[key] = null); | ||
} | ||
catch (err) { | ||
return (cache[key] = null); | ||
} | ||
return (cache[key] = fs_extra_1.readJsonSync(file)); | ||
} | ||
} | ||
function queryAsync(collection) { | ||
collection = validizeKey(collection); | ||
if (collection in cache) return Promise.resolve(cache[collection]); | ||
return new Promise(function (resolve, reject) { | ||
//// This implementation does not work with empty folders: | ||
// recurFs.readdir(collection, function(resource, status, next) { | ||
// next(status.isFile()); | ||
// }, function(err, resources) { | ||
// if (err) { | ||
// reject(err); | ||
// } | ||
// else { | ||
// resolve(resources.map(file => path.relative(kfsPath, file))); | ||
// } | ||
// }); | ||
var fileList = [], | ||
jobNumber = 1, | ||
terminated = false; | ||
var collectionPath = path_1.join(kfsPath, collection); | ||
fs_extra_1.stat(collectionPath, function (err, status) { | ||
if (err) { | ||
if (err.code === 'ENOENT') resolve((cache[collection] = [])); | ||
else reject(err); | ||
} else { | ||
processFolder(collection); | ||
function deleteSync(key) { | ||
key = validizeKey(key); | ||
if (key === '*') | ||
return clearSync(); | ||
var file = path_1.join(storagePath, key); | ||
fs_extra_1.removeSync(file); | ||
return delete cache[key]; | ||
} | ||
function clearSync() { | ||
fs_extra_1.removeSync(storagePath); | ||
return delete cache['*']; | ||
} | ||
function hasSync(key) { | ||
key = validizeKey(key); | ||
if (key in cache) | ||
return true; | ||
var file = path_1.join(storagePath, key); | ||
try { | ||
var status = fs_extra_1.statSync(file); | ||
if (!status || !status.isFile()) | ||
return false; | ||
} | ||
}); | ||
function processFolder(folder) { | ||
if (terminated) return; | ||
var folderPath = path_1.join(kfsPath, folder); | ||
fs_extra_1.readdir(folderPath, function (err, files) { | ||
if (terminated) return; | ||
jobNumber--; | ||
if (err) { | ||
terminated = true; | ||
reject(err); | ||
} | ||
jobNumber += files.length; | ||
if (!jobNumber) { | ||
resolve((cache[collection] = fileList)); | ||
} | ||
files.forEach(function (file) { | ||
if (terminated) return; | ||
var filePath = path_1.join(folderPath, file); | ||
fs_extra_1.stat(filePath, function (err, status) { | ||
if (terminated) return; | ||
jobNumber--; | ||
if (err) { | ||
terminated = true; | ||
reject(err); | ||
} | ||
if (status.isFile()) { | ||
fileList.push(validizeKey(path_1.relative(kfsPath, filePath))); | ||
} else if (status.isDirectory()) { | ||
jobNumber++; | ||
processFolder(filePath); | ||
} | ||
if (!jobNumber) { | ||
resolve((cache[collection] = fileList)); | ||
} | ||
catch (err) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
function querySync(collection) { | ||
collection = validizeKey(collection); | ||
if (collection in cache) | ||
return cache[collection]; | ||
try { | ||
var collectionPath = path_1.join(storagePath, collection); | ||
var files = recurFs.readdir.sync(collectionPath, function (resource, status) { | ||
return status.isFile(); | ||
}); | ||
}); | ||
files = files.map(function (file) { return validizeKey(path_1.relative(storagePath, file)); }); | ||
return (cache[collection] = files || []); | ||
} | ||
catch (err) { | ||
return []; | ||
} | ||
} | ||
function setAsync(key, value) { | ||
if (value === undefined) | ||
return deleteAsync(key); | ||
key = validizeKey(key); | ||
var file = path_1.join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.outputJson(file, value, { spaces: 2 }, function (err) { | ||
if (err) | ||
return reject(err); | ||
resolve((cache[key] = value)); | ||
}); | ||
}); | ||
} | ||
}); | ||
} | ||
/////////////////////////////////////////////////// | ||
function validizeKey(key) { | ||
key = String(key).replace(/\\/g, '/'); | ||
if (key.includes('/..') || key.includes('../') || key === '..') throw new Error('Invalid key name.'); | ||
return key; | ||
} | ||
} | ||
function getAsync(key) { | ||
key = validizeKey(key); | ||
if (key in cache) | ||
return Promise.resolve(cache[key]); | ||
var file = path_1.join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.stat(file, function (err, status) { | ||
if (err || !status || !status.isFile()) | ||
return resolve((cache[key] = null)); | ||
fs_extra_1.readJson(file, function (err, value) { | ||
if (err) | ||
return reject(err); | ||
resolve((cache[key] = value)); | ||
}); | ||
}); | ||
}); | ||
} | ||
function deleteAsync(key) { | ||
key = validizeKey(key); | ||
if (key === '*') | ||
return clearAsync(); | ||
var file = path_1.join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.remove(file, function (err) { | ||
if (err) | ||
return reject(err); | ||
resolve(delete cache[key]); | ||
}); | ||
}); | ||
} | ||
function clearAsync() { | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.remove(storagePath, function (err) { | ||
if (err) | ||
return reject(err); | ||
resolve(delete cache['*']); | ||
}); | ||
}); | ||
} | ||
function hasAsync(key) { | ||
key = validizeKey(key); | ||
if (key in cache) | ||
return Promise.resolve(true); | ||
var file = path_1.join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
fs_extra_1.stat(file, function (err, status) { | ||
resolve(!!(!err && status && status.isFile())); | ||
}); | ||
}); | ||
} | ||
function queryAsync(collection) { | ||
collection = validizeKey(collection); | ||
if (collection in cache) | ||
return Promise.resolve(cache[collection]); | ||
return new Promise(function (resolve, reject) { | ||
//// This implementation does not work with empty folders: | ||
// recurFs.readdir(collection, function(resource, status, next) { | ||
// next(status.isFile()); | ||
// }, function(err, resources) { | ||
// if (err) { | ||
// reject(err); | ||
// } | ||
// else { | ||
// resolve(resources.map(file => path.relative(storagePath, file))); | ||
// } | ||
// }); | ||
var fileList = [], jobNumber = 1, terminated = false; | ||
var collectionPath = path_1.join(storagePath, collection); | ||
fs_extra_1.stat(collectionPath, function (err, status) { | ||
if (err) { | ||
if (err.code === 'ENOENT') | ||
resolve((cache[collection] = [])); | ||
else | ||
reject(err); | ||
} | ||
else { | ||
processFolder(collection); | ||
} | ||
}); | ||
function processFolder(folder) { | ||
if (terminated) | ||
return; | ||
var folderPath = path_1.join(storagePath, folder); | ||
fs_extra_1.readdir(folderPath, function (err, files) { | ||
if (terminated) | ||
return; | ||
jobNumber--; | ||
if (err) { | ||
terminated = true; | ||
reject(err); | ||
} | ||
jobNumber += files.length; | ||
if (!jobNumber) { | ||
resolve((cache[collection] = fileList)); | ||
} | ||
files.forEach(function (file) { | ||
if (terminated) | ||
return; | ||
var filePath = path_1.join(folderPath, file); | ||
fs_extra_1.stat(filePath, function (err, status) { | ||
if (terminated) | ||
return; | ||
jobNumber--; | ||
if (err) { | ||
terminated = true; | ||
reject(err); | ||
} | ||
if (status.isFile()) { | ||
fileList.push(validizeKey(path_1.relative(storagePath, filePath))); | ||
} | ||
else if (status.isDirectory()) { | ||
jobNumber++; | ||
processFolder(filePath); | ||
} | ||
if (!jobNumber) { | ||
resolve((cache[collection] = fileList)); | ||
} | ||
}); | ||
}); | ||
}); | ||
} | ||
}); | ||
} | ||
/////////////////////////////////////////////////// | ||
function validizeKey(key) { | ||
key = String(key).replace(/\\/g, '/'); | ||
if (key.includes('/..') || key.includes('../') || key === '..') | ||
throw new Error('Invalid key name.'); | ||
return key; | ||
} | ||
} | ||
exports['default'] = keyFileBasic; | ||
exports["default"] = keyFileBasic; |
import { | ||
outputJson, | ||
outputJsonSync, | ||
statSync, | ||
readJson, | ||
readJsonSync, | ||
readdir, | ||
remove, | ||
removeSync, | ||
outputJson, | ||
stat, | ||
readJson, | ||
remove, | ||
readdir, | ||
statSync, | ||
} from 'fs-extra'; | ||
@@ -33,6 +33,6 @@ import { join, relative } from 'path'; | ||
export default function keyFileBasic(kfsPath: string, cache: { [x: string]: any }): KeyFileBasic { | ||
kfsPath = kfsPath || __dirname; // Current working folder by default. | ||
kfsPath = String(kfsPath); | ||
if (!isValidPath(kfsPath)) { | ||
export default function keyFileBasic(storagePath: string, cache: { [x: string]: any }): KeyFileBasic { | ||
storagePath = storagePath || __dirname; // Current working folder by default. | ||
storagePath = String(storagePath); | ||
if (!isValidPath(storagePath)) { | ||
throw new Error('Invalid stroage path.'); | ||
@@ -62,3 +62,3 @@ } | ||
key = validizeKey(key); | ||
var file = join(kfsPath, key); | ||
var file = join(storagePath, key); | ||
outputJsonSync(file, value, { spaces: 2 }); | ||
@@ -71,3 +71,3 @@ return (cache[key] = value); | ||
if (key in cache) return cache[key]; | ||
var file = join(kfsPath, key); | ||
var file = join(storagePath, key); | ||
try { | ||
@@ -85,3 +85,3 @@ var status = statSync(file); | ||
if (key === '*') return clearSync(); | ||
var file = join(kfsPath, key); | ||
var file = join(storagePath, key); | ||
removeSync(file); | ||
@@ -92,3 +92,3 @@ return delete cache[key]; | ||
function clearSync() { | ||
removeSync(kfsPath); | ||
removeSync(storagePath); | ||
return delete cache['*']; | ||
@@ -100,3 +100,3 @@ } | ||
if (key in cache) return true; | ||
var file = join(kfsPath, key); | ||
var file = join(storagePath, key); | ||
try { | ||
@@ -115,7 +115,7 @@ var status = statSync(file); | ||
try { | ||
const collectionPath = join(kfsPath, collection); | ||
const collectionPath = join(storagePath, collection); | ||
var files = recurFs.readdir.sync(collectionPath, function (resource: any, status: { isFile: () => void }) { | ||
return status.isFile(); | ||
}); | ||
files = files.map((file: string) => validizeKey(relative(kfsPath, file))); | ||
files = files.map((file: string) => validizeKey(relative(storagePath, file))); | ||
return (cache[collection] = files || []); | ||
@@ -130,3 +130,3 @@ } catch (err) { | ||
key = validizeKey(key); | ||
var file = join(kfsPath, key); | ||
var file = join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
@@ -143,3 +143,3 @@ outputJson(file, value, { spaces: 2 }, function (err) { | ||
if (key in cache) return Promise.resolve(cache[key]); | ||
var file = join(kfsPath, key); | ||
var file = join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
@@ -159,3 +159,3 @@ stat(file, function (err, status) { | ||
if (key === '*') return clearAsync(); | ||
var file = join(kfsPath, key); | ||
var file = join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
@@ -171,3 +171,3 @@ remove(file, function (err) { | ||
return new Promise(function (resolve, reject) { | ||
remove(kfsPath, function (err) { | ||
remove(storagePath, function (err) { | ||
if (err) return reject(err); | ||
@@ -182,3 +182,3 @@ resolve(delete cache['*']); | ||
if (key in cache) return Promise.resolve(true); | ||
var file = join(kfsPath, key); | ||
var file = join(storagePath, key); | ||
return new Promise(function (resolve, reject) { | ||
@@ -204,3 +204,3 @@ stat(file, function (err, status) { | ||
// else { | ||
// resolve(resources.map(file => path.relative(kfsPath, file))); | ||
// resolve(resources.map(file => path.relative(storagePath, file))); | ||
// } | ||
@@ -213,3 +213,3 @@ // }); | ||
const collectionPath = join(kfsPath, collection); | ||
const collectionPath = join(storagePath, collection); | ||
stat(collectionPath, function (err, status) { | ||
@@ -226,3 +226,3 @@ if (err) { | ||
if (terminated) return; | ||
const folderPath = join(kfsPath, folder); | ||
const folderPath = join(storagePath, folder); | ||
readdir(folderPath, function (err, files) { | ||
@@ -250,3 +250,3 @@ if (terminated) return; | ||
if (status.isFile()) { | ||
fileList.push(validizeKey(relative(kfsPath, filePath))); | ||
fileList.push(validizeKey(relative(storagePath, filePath))); | ||
} else if (status.isDirectory()) { | ||
@@ -253,0 +253,0 @@ jobNumber++; |
@@ -1,135 +0,138 @@ | ||
'use strict'; | ||
"use strict"; | ||
exports.__esModule = true; | ||
var key_file_basic_1 = require('./key-file-basic'); | ||
function createKfs(kfsPath, cache) { | ||
var kfb = key_file_basic_1['default'](kfsPath, cache); | ||
// The produced promise and callback function related to the latest async 'in' operator | ||
var hasAsyncHandler = null, | ||
hasAsyncPromise = null; | ||
/* async has */ | ||
var hasAsyncWrap = { | ||
has: function (target, property) { | ||
var promise = kfb.hasAsync(property); | ||
if (hasAsyncHandler) { | ||
callbackizePromise(promise, hasAsyncHandler); | ||
hasAsyncHandler = null; | ||
} else { | ||
hasAsyncPromise = promise; | ||
} | ||
return false; // No synchronous answer. | ||
}, | ||
}; | ||
var kfs = new Proxy( | ||
function () { | ||
var a1 = arguments[0], | ||
a2 = arguments[1], | ||
a3 = arguments[2]; | ||
switch (arguments.length) { | ||
case 0: | ||
if (hasAsyncPromise) { | ||
a3 = hasAsyncPromise; | ||
hasAsyncPromise = null; | ||
return a3; | ||
} else { | ||
return new Proxy({}, hasAsyncWrap); | ||
} | ||
// break; | ||
case 1: | ||
if (typeof a1 === 'function') { | ||
if (hasAsyncPromise) { | ||
a3 = hasAsyncPromise; | ||
hasAsyncPromise = null; | ||
return callbackizePromise(a3, a1); | ||
} else { | ||
hasAsyncHandler = a1; | ||
return new Proxy({}, hasAsyncWrap); | ||
var key_file_basic_1 = require("./key-file-basic"); | ||
function createStore(storagePath, cache) { | ||
var kfb = key_file_basic_1["default"](storagePath, cache); | ||
// The produced promise and callback function related to the latest async 'in' operator | ||
var hasAsyncHandler = null, hasAsyncPromise = null; | ||
/* async has */ | ||
var hasAsyncWrap = { | ||
has: function (target, property) { | ||
var promise = kfb.hasAsync(property); | ||
if (hasAsyncHandler) { | ||
callbackizePromise(promise, hasAsyncHandler); | ||
hasAsyncHandler = null; | ||
} | ||
} else if (String(a1).slice(-1) === '/') { | ||
/* async query pr */ | ||
return kfb.queryAsync(String(a1)); | ||
} else { | ||
/* async get pr */ | ||
return kfb.getAsync(String(a1)); | ||
} | ||
// break; | ||
case 2: | ||
if (typeof a2 === 'function') { | ||
if (String(a1).slice(-1) === '/') { | ||
/* async query cb */ | ||
return callbackizePromise(kfb.queryAsync(String(a1)), a2); | ||
} else { | ||
/* async get cb */ | ||
return callbackizePromise(kfb.getAsync(String(a1)), a2); | ||
else { | ||
hasAsyncPromise = promise; | ||
} | ||
} else { | ||
/* async set pr */ | ||
return kfb.setAsync(String(a1), a2); | ||
} | ||
// break; | ||
case 3: | ||
if (typeof a3 === 'function') { | ||
/* async set cb */ | ||
return callbackizePromise(kfb.setAsync(String(a1), a2), a3); | ||
} | ||
// break; | ||
} | ||
throw new Error('Invalid input argument(s).'); | ||
}, | ||
{ | ||
/* sync set */ | ||
set: function (target, property, value, receiver) { | ||
kfb.setSync(String(property), value); | ||
return true; | ||
}, | ||
get: function (target, property, receiver) { | ||
if (String(property).slice(-1) === '/') { | ||
/* sync query */ | ||
return kfb.querySync(String(property)); | ||
} else { | ||
/* sync get */ | ||
return kfb.getSync(String(property)); | ||
return false; // No synchronous answer. | ||
} | ||
}, | ||
/* sync delete */ | ||
deleteProperty: function (target, property) { | ||
return kfb.deleteSync(String(property)); | ||
}, | ||
/* sync has */ | ||
has: function (target, property) { | ||
return kfb.hasSync(String(property)); | ||
}, | ||
/* async delete */ | ||
construct: function (target, argumentsList, newTarget) { | ||
var a1 = argumentsList[0], | ||
a2 = argumentsList[1]; | ||
switch (argumentsList.length) { | ||
case 0: | ||
return kfb.clearAsync(); | ||
// break; | ||
case 1: | ||
if (typeof a1 === 'function') { | ||
return callbackizePromise(kfb.clearAsync(), a1); | ||
} else { | ||
return kfb.deleteAsync(String(a1)); | ||
}; | ||
var store = new Proxy(function () { | ||
var a1 = arguments[0], a2 = arguments[1], a3 = arguments[2]; | ||
switch (arguments.length) { | ||
case 0: | ||
if (hasAsyncPromise) { | ||
a3 = hasAsyncPromise; | ||
hasAsyncPromise = null; | ||
return a3; | ||
} | ||
else { | ||
return new Proxy({}, hasAsyncWrap); | ||
} | ||
// break; | ||
case 1: | ||
if (typeof a1 === 'function') { | ||
if (hasAsyncPromise) { | ||
a3 = hasAsyncPromise; | ||
hasAsyncPromise = null; | ||
return callbackizePromise(a3, a1); | ||
} | ||
else { | ||
hasAsyncHandler = a1; | ||
return new Proxy({}, hasAsyncWrap); | ||
} | ||
} | ||
else if (String(a1).slice(-1) === '/') { | ||
/* async query pr */ | ||
return kfb.queryAsync(String(a1)); | ||
} | ||
else { | ||
/* async get pr */ | ||
return kfb.getAsync(String(a1)); | ||
} | ||
// break; | ||
case 2: | ||
if (typeof a2 === 'function') { | ||
if (String(a1).slice(-1) === '/') { | ||
/* async query cb */ | ||
return callbackizePromise(kfb.queryAsync(String(a1)), a2); | ||
} | ||
else { | ||
/* async get cb */ | ||
return callbackizePromise(kfb.getAsync(String(a1)), a2); | ||
} | ||
} | ||
else { | ||
/* async set pr */ | ||
return kfb.setAsync(String(a1), a2); | ||
} | ||
// break; | ||
case 3: | ||
if (typeof a3 === 'function') { | ||
/* async set cb */ | ||
return callbackizePromise(kfb.setAsync(String(a1), a2), a3); | ||
} | ||
// break; | ||
} | ||
throw new Error('Invalid input argument(s).'); | ||
}, { | ||
/* sync set */ | ||
set: function (target, property, value, receiver) { | ||
kfb.setSync(String(property), value); | ||
return true; | ||
}, | ||
get: function (target, property, receiver) { | ||
if (String(property).slice(-1) === '/') { | ||
/* sync query */ | ||
return kfb.querySync(String(property)); | ||
} | ||
// break; | ||
case 2: | ||
return callbackizePromise(kfb.deleteAsync(String(a1)), a2); | ||
// break; | ||
else { | ||
/* sync get */ | ||
return kfb.getSync(String(property)); | ||
} | ||
}, | ||
/* sync delete */ | ||
deleteProperty: function (target, property) { | ||
return kfb.deleteSync(String(property)); | ||
}, | ||
/* sync has */ | ||
has: function (target, property) { | ||
return kfb.hasSync(String(property)); | ||
}, | ||
/* async delete */ | ||
construct: function (target, argumentsList, newTarget) { | ||
var a1 = argumentsList[0], a2 = argumentsList[1]; | ||
switch (argumentsList.length) { | ||
case 0: | ||
return kfb.clearAsync(); | ||
// break; | ||
case 1: | ||
if (typeof a1 === 'function') { | ||
return callbackizePromise(kfb.clearAsync(), a1); | ||
} | ||
else { | ||
return kfb.deleteAsync(String(a1)); | ||
} | ||
// break; | ||
case 2: | ||
return callbackizePromise(kfb.deleteAsync(String(a1)), a2); | ||
// break; | ||
} | ||
throw new Error('Invalid input argument(s).'); | ||
} | ||
throw new Error('Invalid input argument(s).'); | ||
}, | ||
}, | ||
); | ||
return kfs; | ||
function callbackizePromise(promise, callback) { | ||
if (typeof callback === 'function') { | ||
return promise.then(function (data) { | ||
return callback(undefined, data); | ||
}, callback); | ||
} else { | ||
return promise; | ||
}); | ||
return store; | ||
function callbackizePromise(promise, callback) { | ||
if (typeof callback === 'function') { | ||
return promise.then(function (data) { | ||
return callback(undefined, data); | ||
}, callback); | ||
} | ||
else { | ||
return promise; | ||
} | ||
} | ||
} | ||
} | ||
exports['default'] = createKfs; | ||
exports["default"] = createStore; |
import keyFileBasic from './key-file-basic'; | ||
export interface KeyFileStorage { | ||
[key: string]: any; | ||
[index: number]: any; | ||
export interface KeyFileStorage<P> { | ||
[key: string]: P; | ||
[index: number]: P; | ||
@@ -14,4 +14,4 @@ <T, U = T>(key: string | number, value: T, callback?: (error: any) => U): Promise<U>; | ||
export default function createKfs(kfsPath: string, cache: { [x: string]: any }): KeyFileStorage { | ||
var kfb = keyFileBasic(kfsPath, cache); | ||
export default function createStore<P>(storagePath: string, cache: { [x: string]: P }): KeyFileStorage<P> { | ||
var kfb = keyFileBasic(storagePath, cache); | ||
@@ -36,3 +36,3 @@ // The produced promise and callback function related to the latest async 'in' operator | ||
var kfs = new Proxy( | ||
var store = new Proxy( | ||
function () { | ||
@@ -153,3 +153,3 @@ var a1 = arguments[0], | ||
return kfs as any; | ||
return store as any; | ||
@@ -156,0 +156,0 @@ function callbackizePromise(promise: Promise<unknown>, callback: any) { |
51
test.js
"use strict"; | ||
exports.__esModule = true; | ||
var index_1 = require("./index"); | ||
var kfs = index_1["default"]('../data'); | ||
delete kfs['*']; | ||
console.log("(kfs.a = 'a') >> ", (kfs.a = 'a')); | ||
console.log('kfs.a, kfs.b >> ', kfs.a, kfs.b); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log("(kfs.b = 'b') >> ", (kfs.b = 'b')); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log('delete kfs.a >> ', delete kfs.a); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
var store = index_1["default"]('../data'); | ||
delete store['*']; | ||
console.log('..............................................'); | ||
console.log(kfs['a/b/c/']); | ||
console.log((kfs['a/b/c/x'] = 0)); | ||
console.log(kfs['a/b/c/']); | ||
console.log((kfs['a/b/c/y'] = 0)); | ||
console.log((kfs['a/b/c/z'] = 0)); | ||
console.log(kfs['a/b/c/']); | ||
console.log(kfs['a/b/c/']); | ||
console.log(delete kfs['a/b/c/y']); | ||
console.log(kfs['a/b/c/']); | ||
console.log(kfs['a/b/c/']); | ||
console.log("(store.a = 'a') >> ", (store.a = 'a')); | ||
console.log('store.a, store.b >> ', store.a, store.b); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log("(store.b = 'b') >> ", (store.b = 'b')); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log('delete store.a >> ', delete store.a); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log('..............................................'); | ||
console.log(store['a/b/c/']); | ||
console.log((store['a/b/c/x'] = 0)); | ||
console.log(store['a/b/c/']); | ||
console.log((store['a/b/c/y'] = 0)); | ||
console.log((store['a/b/c/z'] = 0)); | ||
console.log(store['a/b/c/']); | ||
console.log(store['a/b/c/']); | ||
console.log(delete store['a/b/c/y']); | ||
console.log(store['a/b/c/']); | ||
console.log(store['a/b/c/']); | ||
console.log('..............................................'); | ||
Promise.resolve() | ||
.then(function (x) { return kfs('qq/qqq', { data: 123 }); }) | ||
.then(function (x) { return kfs('qq/www', { data: 456 }); }) | ||
.then(function (x) { return kfs('qq/'); }) | ||
.then(function (x) { return store('qq/qqq', { data: 123 }); }) | ||
.then(function (x) { return store('qq/www', { data: 456 }); }) | ||
.then(function (x) { return store('qq/'); }) | ||
.then(function (x) { return console.log(x); }); |
54
test.ts
@@ -1,31 +0,31 @@ | ||
import keyFileStorage from './index'; | ||
import kfs from './index'; | ||
const kfs = keyFileStorage('../data'); | ||
delete kfs['*']; | ||
const store = kfs('../data'); | ||
delete store['*']; | ||
console.log('..............................................'); | ||
console.log("(kfs.a = 'a') >> ", (kfs.a = 'a')); | ||
console.log('kfs.a, kfs.b >> ', kfs.a, kfs.b); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log("(kfs.b = 'b') >> ", (kfs.b = 'b')); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log('delete kfs.a >> ', delete kfs.a); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log("kfs['/'] >> ", kfs['/']); | ||
console.log("(store.a = 'a') >> ", (store.a = 'a')); | ||
console.log('store.a, store.b >> ', store.a, store.b); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log("(store.b = 'b') >> ", (store.b = 'b')); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log('delete store.a >> ', delete store.a); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log("store['/'] >> ", store['/']); | ||
console.log('..............................................'); | ||
console.log(kfs['a/b/c/']); | ||
console.log((kfs['a/b/c/x'] = 0)); | ||
console.log(kfs['a/b/c/']); | ||
console.log((kfs['a/b/c/y'] = 0)); | ||
console.log((kfs['a/b/c/z'] = 0)); | ||
console.log(kfs['a/b/c/']); | ||
console.log(kfs['a/b/c/']); | ||
console.log(delete kfs['a/b/c/y']); | ||
console.log(kfs['a/b/c/']); | ||
console.log(kfs['a/b/c/']); | ||
console.log(store['a/b/c/']); | ||
console.log((store['a/b/c/x'] = 0)); | ||
console.log(store['a/b/c/']); | ||
console.log((store['a/b/c/y'] = 0)); | ||
console.log((store['a/b/c/z'] = 0)); | ||
console.log(store['a/b/c/']); | ||
console.log(store['a/b/c/']); | ||
console.log(delete store['a/b/c/y']); | ||
console.log(store['a/b/c/']); | ||
console.log(store['a/b/c/']); | ||
@@ -35,5 +35,5 @@ console.log('..............................................'); | ||
Promise.resolve() | ||
.then(x => kfs('qq/qqq', { data: 123 })) | ||
.then(x => kfs('qq/www', { data: 456 })) | ||
.then(x => kfs('qq/')) | ||
.then(x => console.log(x)); | ||
.then((x) => store('qq/qqq', { data: 123 })) | ||
.then((x) => store('qq/www', { data: 456 })) | ||
.then((x) => store('qq/')) | ||
.then((x) => console.log(x)); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
80517
4
1881
239