@zenfs/core 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/ApiError.d.ts +51 -14
  2. package/dist/ApiError.js +60 -34
  3. package/dist/FileIndex.d.ts +32 -35
  4. package/dist/FileIndex.js +93 -109
  5. package/dist/backends/AsyncMirror.d.ts +42 -43
  6. package/dist/backends/AsyncMirror.js +146 -133
  7. package/dist/backends/AsyncStore.d.ts +29 -28
  8. package/dist/backends/AsyncStore.js +139 -189
  9. package/dist/backends/InMemory.d.ts +16 -13
  10. package/dist/backends/InMemory.js +29 -14
  11. package/dist/backends/Locked.d.ts +8 -28
  12. package/dist/backends/Locked.js +44 -148
  13. package/dist/backends/OverlayFS.d.ts +26 -34
  14. package/dist/backends/OverlayFS.js +208 -371
  15. package/dist/backends/SyncStore.d.ts +54 -72
  16. package/dist/backends/SyncStore.js +159 -161
  17. package/dist/backends/backend.d.ts +45 -29
  18. package/dist/backends/backend.js +83 -13
  19. package/dist/backends/index.d.ts +6 -7
  20. package/dist/backends/index.js +5 -6
  21. package/dist/browser.min.js +5 -7
  22. package/dist/browser.min.js.map +4 -4
  23. package/dist/emulation/callbacks.d.ts +36 -67
  24. package/dist/emulation/callbacks.js +90 -46
  25. package/dist/emulation/constants.js +1 -1
  26. package/dist/emulation/promises.d.ts +228 -129
  27. package/dist/emulation/promises.js +414 -172
  28. package/dist/emulation/shared.d.ts +10 -10
  29. package/dist/emulation/shared.js +18 -20
  30. package/dist/emulation/sync.d.ts +25 -25
  31. package/dist/emulation/sync.js +187 -73
  32. package/dist/file.d.ts +166 -170
  33. package/dist/file.js +199 -218
  34. package/dist/filesystem.d.ts +68 -241
  35. package/dist/filesystem.js +59 -383
  36. package/dist/index.d.ts +7 -44
  37. package/dist/index.js +13 -52
  38. package/dist/inode.d.ts +37 -28
  39. package/dist/inode.js +123 -65
  40. package/dist/stats.d.ts +21 -19
  41. package/dist/stats.js +35 -56
  42. package/dist/utils.d.ts +26 -9
  43. package/dist/utils.js +73 -102
  44. package/package.json +4 -3
@@ -1,17 +1,18 @@
1
- import type { TwoArgCallback, FileSystem } from '../filesystem.js';
1
+ import { FileSystem } from '../filesystem.js';
2
+ type OptionType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function';
2
3
  /**
3
4
  * Describes a file system option.
4
5
  */
5
- export interface BackendOption<T> {
6
+ export interface OptionConfig<T> {
6
7
  /**
7
8
  * The basic JavaScript type(s) for this option.
8
9
  */
9
- type: string | string[];
10
+ type: OptionType | OptionType[];
10
11
  /**
11
- * Whether or not the option is optional (e.g., can be set to null or undefined).
12
- * Defaults to `false`.
12
+ * Whether or not the option is required (optional can be set to null or undefined).
13
+ * Defaults to false.
13
14
  */
14
- optional?: boolean;
15
+ required?: boolean;
15
16
  /**
16
17
  * Description of the option. Used in error messages and documentation.
17
18
  */
@@ -26,22 +27,23 @@ export interface BackendOption<T> {
26
27
  /**
27
28
  * Describes all of the options available in a file system.
28
29
  */
29
- export interface BackendOptions {
30
- [name: string]: BackendOption<unknown>;
31
- }
30
+ type BackendOptionsConfig = Record<string, OptionConfig<unknown>>;
32
31
  /**
33
- * Contains types for static functions on a backend.
32
+ * A backend
34
33
  */
35
- export interface BaseBackendConstructor<FS extends typeof FileSystem = typeof FileSystem> {
36
- new (...params: ConstructorParameters<FS>): InstanceType<FS>;
34
+ export interface Backend<FS extends FileSystem = FileSystem, OC extends BackendOptionsConfig = BackendOptionsConfig> {
35
+ /**
36
+ * Create a new instance of the backend
37
+ */
38
+ create(options: object): FS;
37
39
  /**
38
40
  * A name to identify the backend.
39
41
  */
40
- Name: string;
42
+ name: string;
41
43
  /**
42
44
  * Describes all of the options available for this backend.
43
45
  */
44
- Options: BackendOptions;
46
+ options: OC;
45
47
  /**
46
48
  * Whether the backend is available in the current environment.
47
49
  * It supports checking synchronously and asynchronously
@@ -55,20 +57,34 @@ export interface BaseBackendConstructor<FS extends typeof FileSystem = typeof Fi
55
57
  isAvailable(): boolean;
56
58
  }
57
59
  /**
58
- * Contains types for static functions on a backend.
60
+ * @internal
59
61
  */
60
- export interface BackendConstructor<FS extends typeof FileSystem = typeof FileSystem> extends BaseBackendConstructor<FS> {
61
- /**
62
- * Creates backend of this given type with the given
63
- * options, and either returns the result in a promise or callback.
64
- */
65
- Create(): Promise<InstanceType<FS>>;
66
- Create(options: object): Promise<InstanceType<FS>>;
67
- Create(cb: TwoArgCallback<InstanceType<FS>>): void;
68
- Create(options: object, cb: TwoArgCallback<InstanceType<FS>>): void;
69
- Create(options: object, cb?: TwoArgCallback<InstanceType<FS>>): Promise<InstanceType<FS>> | void;
62
+ export declare function isBackend(arg: unknown): arg is Backend;
63
+ /**
64
+ * Checks that the given options object is valid for the file system options.
65
+ * @internal
66
+ */
67
+ export declare function checkOptions(backend: Backend, opts: object): Promise<void>;
68
+ export declare function createBackend<B extends Backend>(backend: B, options?: object): Promise<ReturnType<B['create']>>;
69
+ /**
70
+ * Specifies a file system backend type and its options.
71
+ *
72
+ * Individual options can recursively contain BackendConfig objects for
73
+ * option values that require file systems.
74
+ *
75
+ * The option object for each file system corresponds to that file system's option object passed to its `Create()` method.
76
+ */
77
+ export interface BackendConfig {
78
+ backend: Backend;
79
+ [key: string]: unknown;
70
80
  }
71
- export declare function CreateBackend<FS extends BaseBackendConstructor>(this: FS): Promise<InstanceType<FS>>;
72
- export declare function CreateBackend<FS extends BaseBackendConstructor>(this: FS, options: BackendOptions): Promise<InstanceType<FS>>;
73
- export declare function CreateBackend<FS extends BaseBackendConstructor>(this: FS, cb: TwoArgCallback<InstanceType<FS>>): void;
74
- export declare function CreateBackend<FS extends BaseBackendConstructor>(this: FS, options: BackendOptions, cb: TwoArgCallback<InstanceType<FS>>): void;
81
+ /**
82
+ * @internal
83
+ */
84
+ export declare function isBackendConfig(arg: unknown): arg is BackendConfig;
85
+ /**
86
+ * Retrieve a file system with the given configuration.
87
+ * @param config A BackendConfig object.
88
+ */
89
+ export declare function resolveBackendConfig(options: BackendConfig): Promise<FileSystem>;
90
+ export {};
@@ -1,14 +1,84 @@
1
- import { checkOptions } from '../utils.js';
2
- export function CreateBackend(options, cb) {
3
- cb = typeof options === 'function' ? options : cb;
4
- checkOptions(this, options);
5
- const fs = new this(typeof options === 'function' ? {} : options);
6
- // Promise
7
- if (typeof cb != 'function') {
8
- return fs.whenReady();
9
- }
10
- // Callback
11
- fs.whenReady()
12
- .then(fs => cb(null, fs))
13
- .catch(err => cb(err));
1
+ import { ApiError, ErrorCode } from '../ApiError.js';
2
+ import { levenshtein } from '../utils.js';
3
+ /**
4
+ * @internal
5
+ */
6
+ export function isBackend(arg) {
7
+ return arg != null && typeof arg == 'object' && 'isAvailable' in arg && typeof arg.isAvailable == 'function' && 'create' in arg && typeof arg.create == 'function';
8
+ }
9
+ /**
10
+ * Checks that the given options object is valid for the file system options.
11
+ * @internal
12
+ */
13
+ export async function checkOptions(backend, opts) {
14
+ if (typeof opts != 'object' || opts === null) {
15
+ throw new ApiError(ErrorCode.EINVAL, 'Invalid options');
16
+ }
17
+ // Check for required options.
18
+ for (const [optName, opt] of Object.entries(backend.options)) {
19
+ const providedValue = opts && opt;
20
+ if (providedValue === undefined || providedValue === null) {
21
+ if (!opt.required) {
22
+ continue;
23
+ }
24
+ /* Required option not provided.
25
+ if any incorrect options provided, which ones are close to the provided one?
26
+ (edit distance 5 === close)*/
27
+ const incorrectOptions = Object.keys(opts)
28
+ .filter(o => !(o in backend.options))
29
+ .map((a) => {
30
+ return { str: a, distance: levenshtein(optName, a) };
31
+ })
32
+ .filter(o => o.distance < 5)
33
+ .sort((a, b) => a.distance - b.distance);
34
+ throw new ApiError(ErrorCode.EINVAL, `${backend.name}: Required option '${optName}' not provided.${incorrectOptions.length > 0 ? ` You provided '${incorrectOptions[0].str}', did you mean '${optName}'.` : ''}`);
35
+ }
36
+ // Option provided, check type.
37
+ const typeMatches = Array.isArray(opt.type) ? opt.type.indexOf(typeof providedValue) != -1 : typeof providedValue == opt.type;
38
+ if (!typeMatches) {
39
+ throw new ApiError(ErrorCode.EINVAL, `${backend.name}: Value provided for option ${optName} is not the proper type. Expected ${Array.isArray(opt.type) ? `one of {${opt.type.join(', ')}}` : opt.type}, but received ${typeof providedValue}\nOption description: ${opt.description}`);
40
+ }
41
+ if (opt.validator) {
42
+ await opt.validator(providedValue);
43
+ }
44
+ // Otherwise: All good!
45
+ }
46
+ }
47
+ export function createBackend(backend, options) {
48
+ checkOptions(backend, options);
49
+ const fs = backend.create(options);
50
+ return fs.ready();
51
+ }
52
+ /**
53
+ * @internal
54
+ */
55
+ export function isBackendConfig(arg) {
56
+ return arg != null && typeof arg == 'object' && 'backend' in arg;
57
+ }
58
+ /**
59
+ * Retrieve a file system with the given configuration.
60
+ * @param config A BackendConfig object.
61
+ */
62
+ export async function resolveBackendConfig(options) {
63
+ const { backend } = options;
64
+ if (!backend) {
65
+ throw new ApiError(ErrorCode.EPERM, 'Missing backend');
66
+ }
67
+ if (typeof options !== 'object' || options == null) {
68
+ throw new ApiError(ErrorCode.EINVAL, 'Invalid options on configuration object.');
69
+ }
70
+ const props = Object.keys(options).filter(k => k != 'backend');
71
+ for (const prop of props) {
72
+ let option = options[prop];
73
+ if (isBackend(option)) {
74
+ option = { backend: option };
75
+ }
76
+ if (isBackendConfig(option)) {
77
+ options[prop] = await resolveBackendConfig(option);
78
+ }
79
+ }
80
+ if (!backend) {
81
+ throw new ApiError(ErrorCode.EPERM, `Backend "${backend}" is not available`);
82
+ }
83
+ return backend.create(options);
14
84
  }
@@ -1,11 +1,10 @@
1
1
  import { AsyncMirror } from './AsyncMirror.js';
2
- import { FolderAdapter } from './FolderAdapter.js';
3
- import { InMemoryFileSystem as InMemory } from './InMemory.js';
4
- import { OverlayFS } from './OverlayFS.js';
5
- import { BackendConstructor } from './backend.js';
2
+ import { InMemory } from './InMemory.js';
3
+ import { Overlay } from './OverlayFS.js';
4
+ import { Backend } from './backend.js';
6
5
  export declare const backends: {
7
- [backend: string]: BackendConstructor;
6
+ [backend: string]: Backend;
8
7
  };
9
8
  export default backends;
10
- export { AsyncMirror, FolderAdapter, InMemory, OverlayFS };
11
- export declare function registerBackend(..._backends: BackendConstructor[]): void;
9
+ export { AsyncMirror, InMemory, Overlay };
10
+ export declare function registerBackend(..._backends: Backend[]): void;
@@ -1,13 +1,12 @@
1
1
  import { AsyncMirror } from './AsyncMirror.js';
2
- import { FolderAdapter } from './FolderAdapter.js';
3
- import { InMemoryFileSystem as InMemory } from './InMemory.js';
4
- import { OverlayFS } from './OverlayFS.js';
2
+ import { InMemory } from './InMemory.js';
3
+ import { Overlay } from './OverlayFS.js';
5
4
  export const backends = {};
6
5
  export default backends;
7
- export { AsyncMirror, FolderAdapter, InMemory, OverlayFS };
6
+ export { AsyncMirror, InMemory, Overlay };
8
7
  export function registerBackend(..._backends) {
9
8
  for (const backend of _backends) {
10
- backends[backend.Name] = backend;
9
+ backends[backend.name] = backend;
11
10
  }
12
11
  }
13
- registerBackend(AsyncMirror, FolderAdapter, InMemory, OverlayFS);
12
+ registerBackend(AsyncMirror, InMemory, Overlay);