@zenfs/core 1.9.5 → 1.10.1

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.
@@ -1,7 +1,7 @@
1
1
  import { Stats } from '../stats.js';
2
2
  import { type File } from './file.js';
3
3
  import { Index } from './file_index.js';
4
- import { FileSystem, type CreationOptions, type PureCreationOptions } from './filesystem.js';
4
+ import { FileSystem, type CreationOptions, type PureCreationOptions, type UsageInfo } from './filesystem.js';
5
5
  import { Inode, type InodeLike } from './inode.js';
6
6
  /**
7
7
  * A file system that uses an `Index` for metadata.
@@ -11,6 +11,7 @@ import { Inode, type InodeLike } from './inode.js';
11
11
  export declare abstract class IndexFS extends FileSystem {
12
12
  readonly index: Index;
13
13
  constructor(id: number, name: string, index?: Index);
14
+ usage(): UsageInfo;
14
15
  /**
15
16
  * @deprecated
16
17
  */
@@ -18,6 +18,9 @@ export class IndexFS extends FileSystem {
18
18
  super(id, name);
19
19
  this.index = index;
20
20
  }
21
+ usage() {
22
+ return this.index.usage();
23
+ }
21
24
  /* node:coverage disable */
22
25
  /**
23
26
  * @deprecated
@@ -21,6 +21,14 @@ export interface InodeLike extends StatsLike<number>, InodeFields {
21
21
  * @internal @hidden
22
22
  */
23
23
  export declare const _inode_fields: readonly ["ino", "data", "size", "mode", "flags", "nlink", "uid", "gid", "atimeMs", "birthtimeMs", "mtimeMs", "ctimeMs"];
24
+ /**
25
+ * Represents which version of the `Inode` format we are on.
26
+ * 1. 58 bytes. The first member was called `ino` but used as the ID for data.
27
+ * 2. 66 bytes. Renamed the first member from `ino` to `data` and added a separate `ino` field
28
+ * 3. (current) 72 bytes. Changed the ID fields from 64 to 32 bits and added `flags`.
29
+ * @internal @hidden
30
+ */
31
+ export declare const _inode_version = 3;
24
32
  /**
25
33
  * Generic inode definition that can easily be serialized.
26
34
  * @category Internals
@@ -49,6 +49,14 @@ export const rootIno = 0;
49
49
  * @internal @hidden
50
50
  */
51
51
  export const _inode_fields = ['ino', 'data', 'size', 'mode', 'flags', 'nlink', 'uid', 'gid', 'atimeMs', 'birthtimeMs', 'mtimeMs', 'ctimeMs'];
52
+ /**
53
+ * Represents which version of the `Inode` format we are on.
54
+ * 1. 58 bytes. The first member was called `ino` but used as the ID for data.
55
+ * 2. 66 bytes. Renamed the first member from `ino` to `data` and added a separate `ino` field
56
+ * 3. (current) 72 bytes. Changed the ID fields from 64 to 32 bits and added `flags`.
57
+ * @internal @hidden
58
+ */
59
+ export const _inode_version = 3;
52
60
  /**
53
61
  * Generic inode definition that can easily be serialized.
54
62
  * @category Internals
@@ -88,16 +88,17 @@ export declare function log_deprecated(symbol: string): void;
88
88
  */
89
89
  export declare const formats: {
90
90
  /** Format with a timestamp and the level, colorized with ANSI escape codes */
91
- readonly ansi_level: (this: void, entry: Entry) => string;
91
+ readonly ansi_level: (this: void, entry: Entry) => string[];
92
92
  /**
93
93
  * Format with a timestamp and colorize the message with ANSI escape codes.
94
94
  * For EMERG and ALERT, the levels are included
95
95
  */
96
96
  readonly ansi_message: (this: void, entry: Entry) => string;
97
- /** Uncolored format with a timestamp */
97
+ readonly css_level: (this: void, entry: Entry) => string[];
98
+ readonly css_message: (this: void, entry: Entry) => string[];
98
99
  readonly default: (this: void, entry: Entry) => string;
99
100
  };
100
- export declare function format(entry: Entry): string;
101
+ export declare function format(entry: Entry): string[];
101
102
  /** Whether log entries are being recorded */
102
103
  export declare let isEnabled: boolean;
103
104
  export interface LogConfiguration {
@@ -115,12 +116,12 @@ export interface LogConfiguration {
115
116
  * Formats a log entry into a string
116
117
  * @default `[${ms / 1000}] ${message}`
117
118
  */
118
- format?(this: void, entry: Entry): string;
119
+ format?(this: void, entry: Entry): string | string[];
119
120
  /**
120
121
  * Outputs a log message
121
122
  * @default console.error()
122
123
  */
123
- output?(this: void, message: string): unknown;
124
+ output?(this: void, ...message: string[]): unknown;
124
125
  /**
125
126
  * If set, output() all current entries after `configure` is done
126
127
  * @default false
@@ -97,9 +97,16 @@ export function log_deprecated(symbol) {
97
97
  function ansi(text, format) {
98
98
  return `\x1b[${format}m${text}\x1b[0m`;
99
99
  }
100
- function _prettyMs(entry, useANSI = false) {
100
+ function _prettyMs(entry, style) {
101
101
  const text = '[' + (entry.elapsedMs / 1000).toFixed(3).padStart(10) + '] ';
102
- return useANSI ? ansi(text, '2;37') : text;
102
+ switch (style) {
103
+ case 'ansi':
104
+ return ansi(text, '2;37');
105
+ case 'css':
106
+ return ['%c' + text, 'opacity: 0.8; color: white;'];
107
+ default:
108
+ return text;
109
+ }
103
110
  }
104
111
  const _ansiLevelColor = {
105
112
  [Level.EMERG]: '1;4;37;41',
@@ -121,6 +128,26 @@ const _ansiMessageColor = {
121
128
  [Level.INFO]: '37',
122
129
  [Level.DEBUG]: '2;37',
123
130
  };
131
+ const _cssLevelColor = {
132
+ [Level.EMERG]: 'font-weight: bold; text-decoration: underline; color: white; background-color: red;',
133
+ [Level.ALERT]: 'font-weight: bold; color: white; background-color: red;',
134
+ [Level.CRIT]: 'font-weight: bold; color: magenta;',
135
+ [Level.ERR]: 'font-weight: bold; color: red;',
136
+ [Level.WARN]: 'font-weight: bold; color: yellow;',
137
+ [Level.NOTICE]: 'font-weight: bold; color: cyan;',
138
+ [Level.INFO]: 'font-weight: bold; color: white;',
139
+ [Level.DEBUG]: 'opacity: 0.8; color: white;',
140
+ };
141
+ const _cssMessageColor = {
142
+ [Level.EMERG]: 'font-weight: bold; color: red;',
143
+ [Level.ALERT]: 'font-weight: bold; color: red;',
144
+ [Level.CRIT]: 'font-weight: bold; color: red;',
145
+ [Level.ERR]: 'color: red;',
146
+ [Level.WARN]: 'color: yellow;',
147
+ [Level.NOTICE]: 'font-weight: bold; color: white;',
148
+ [Level.INFO]: 'color: white;',
149
+ [Level.DEBUG]: 'opacity: 0.8; color: white;',
150
+ };
124
151
  /**
125
152
  * Various format functions included to make using the logger easier.
126
153
  * These are not the only formats you can use.
@@ -129,34 +156,48 @@ export const formats = {
129
156
  /** Format with a timestamp and the level, colorized with ANSI escape codes */
130
157
  ansi_level(entry) {
131
158
  const levelText = ansi(levels[entry.level].toUpperCase(), _ansiLevelColor[entry.level]);
132
- return [_prettyMs(entry, true), levelText, entry.message].join(' ');
159
+ return [_prettyMs(entry, 'ansi'), levelText, entry.message];
133
160
  },
134
161
  /**
135
162
  * Format with a timestamp and colorize the message with ANSI escape codes.
136
163
  * For EMERG and ALERT, the levels are included
137
164
  */
138
165
  ansi_message(entry) {
139
- let msg = _prettyMs(entry, true);
166
+ let msg = _prettyMs(entry, 'ansi');
140
167
  const isImportant = entry.level < Level.CRIT;
141
168
  if (isImportant)
142
169
  msg += ansi(levels[entry.level].toUpperCase(), _ansiLevelColor[entry.level]) + ': ';
143
170
  msg += ansi(entry.message, _ansiMessageColor[entry.level]);
144
171
  return msg;
145
172
  },
146
- /** Uncolored format with a timestamp */
173
+ css_level(entry) {
174
+ const levelLabel = levels[entry.level].toUpperCase();
175
+ return [..._prettyMs(entry, 'css'), `%c${levelLabel}%c ${entry.message}`, _cssLevelColor[entry.level], ''];
176
+ },
177
+ css_message(entry) {
178
+ const text = _prettyMs(entry, 'css');
179
+ const isImportant = entry.level < Level.CRIT;
180
+ if (isImportant) {
181
+ const levelLabel = levels[entry.level].toUpperCase();
182
+ text.push(`%c${levelLabel}%c:`, _cssLevelColor[entry.level], '');
183
+ }
184
+ text.push('%c' + entry.message, _cssMessageColor[entry.level]);
185
+ return text;
186
+ },
147
187
  default(entry) {
148
188
  return `[${_prettyMs(entry)}] ${entry.message}`;
149
189
  },
150
190
  };
151
191
  let _format = formats.default;
152
192
  export function format(entry) {
153
- return _format(entry);
193
+ const formatted = _format(entry);
194
+ return Array.isArray(formatted) ? formatted : [formatted];
154
195
  }
155
196
  let _output = console.error;
156
197
  function output(entry) {
157
198
  if (entry.level > minLevel)
158
199
  return;
159
- _output(format(entry));
200
+ _output(...format(entry));
160
201
  }
161
202
  let minLevel = Level.ALERT;
162
203
  // Configuration
package/dist/stats.js CHANGED
@@ -233,11 +233,11 @@ export class BigIntStats extends StatsCommon {
233
233
  * @internal
234
234
  */
235
235
  export function isStatsEqual(left, right) {
236
- return (left.size == right.size &&
237
- +left.atime == +right.atime &&
238
- +left.mtime == +right.mtime &&
239
- +left.ctime == +right.ctime &&
240
- left.mode == right.mode);
236
+ return (left.size == right.size
237
+ && +left.atime == +right.atime
238
+ && +left.mtime == +right.mtime
239
+ && +left.ctime == +right.ctime
240
+ && left.mode == right.mode);
241
241
  }
242
242
  /** @internal */
243
243
  export const ZenFsType = 0x7a656e6673; // 'z' 'e' 'n' 'f' 's'
package/dist/vfs/path.js CHANGED
@@ -338,12 +338,12 @@ export function extname(path) {
338
338
  preDotState = -1;
339
339
  }
340
340
  }
341
- if (startDot === -1 ||
342
- end === -1 ||
341
+ if (startDot === -1
342
+ || end === -1
343
343
  // We saw a non-dot character immediately before the dot
344
- preDotState === 0 ||
344
+ || preDotState === 0
345
345
  // The (right-most) trimmed path component is exactly '..'
346
- (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {
346
+ || (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {
347
347
  return '';
348
348
  }
349
349
  return path.slice(startDot, end);
@@ -403,11 +403,11 @@ export function parse(path) {
403
403
  }
404
404
  if (end !== -1) {
405
405
  const start = startPart === 0 && isAbsolute ? 1 : startPart;
406
- if (startDot === -1 ||
406
+ if (startDot === -1
407
407
  // We saw a non-dot character immediately before the dot
408
- preDotState === 0 ||
408
+ || preDotState === 0
409
409
  // The (right-most) trimmed path component is exactly '..'
410
- (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {
410
+ || (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) {
411
411
  ret.base = ret.name = path.slice(start, end);
412
412
  }
413
413
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "1.9.5",
3
+ "version": "1.10.1",
4
4
  "description": "A filesystem, anywhere",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -70,7 +70,7 @@
70
70
  "buffer": "^6.0.3",
71
71
  "eventemitter3": "^5.0.1",
72
72
  "readable-stream": "^4.5.2",
73
- "utilium": "^1.2.10"
73
+ "utilium": "^1.3.1"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@eslint/js": "^9.8.0",
package/readme.md CHANGED
@@ -1,7 +1,3 @@
1
- ---
2
- title: Overview
3
- ---
4
-
5
1
  # ZenFS
6
2
 
7
3
  ZenFS is a cross-platform library that emulates the [NodeJS filesystem API](http://nodejs.org/api/fs.html). It works using a system of backends, which are used by ZenFS to store and retrieve data. ZenFS can also integrate with other tools.
@@ -15,6 +11,7 @@ ZenFS is modular and extensible. The core includes some built-in backends:
15
11
  - `Fetch`: Downloads files over HTTP with the `fetch` API
16
12
  - `Port`: Interacts with a remote over a `MessagePort`-like interface (e.g. a worker)
17
13
  - `Passthrough`: Use an existing `node:fs` interface with ZenFS
14
+ - `SingleBuffer`: A backend contained within a single buffer. Can be used for synchronous multi-threaded operations using `SharedArrayBuffer`
18
15
 
19
16
  ZenFS supports a number of other backends. Many are provided as separate packages under `@zenfs`. More backends can be defined by separate libraries by extending the `FileSystem` class and providing a `Backend` object.
20
17
 
@@ -0,0 +1,9 @@
1
+ import { SingleBuffer, configureSingle } from '../../dist/index.js';
2
+ import { copySync, data } from '../setup.js';
3
+
4
+ await configureSingle({
5
+ backend: SingleBuffer,
6
+ buffer: new ArrayBuffer(0x100000),
7
+ });
8
+
9
+ copySync(data);