Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
Generated Vendored
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2023 Vadim @streamich Dalecky <vadimsdaleckis@gmail.com> and other contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+54
View File
@@ -0,0 +1,54 @@
# memfs
[![][chat-badge]][chat] [![][npm-badge]][npm-url]
[chat]: https://onp4.com/@vadim/~memfs
[chat-badge]: https://img.shields.io/badge/Chat-%F0%9F%92%AC-green?style=flat&logo=chat&link=https://onp4.com/@vadim/~memfs
[npm-url]: https://www.npmjs.com/package/memfs
[npm-badge]: https://img.shields.io/npm/v/memfs.svg
JavaScript file system utilities for Node.js and browser.
## Install
```shell
npm i memfs
```
## Resources
- Documentation
- [In-memory Node.js `fs` API](./docs/node/index.md)
- `experimental` [`fs` to File System Access API adapter](./docs/fsa/fs-to-fsa.md)
- `experimental` [File System Access API to `fs` adapter](./docs/fsa/fsa-to-fs.md)
- `experimental` [`crudfs` a CRUD-like file system abstraction](./docs/crudfs/index.md)
- `experimental` [`casfs` Content Addressable Storage file system abstraction](./docs/casfs/index.md)
- [Directory `snapshot` utility](./docs/snapshot/index.md)
- [`print` directory tree to terminal](./docs/print/index.md)
- [Code reference](https://streamich.github.io/memfs/)
- [Test coverage](https://streamich.github.io/memfs/coverage/lcov-report/)
## Demos
- [Git in browser, which writes to a real folder](demo/git-fsa/README.md)
- [Git in browser, which writes to OPFS file system](demo/git-opfs/README.md)
- [Git on in-memory file system](demo/git/README.md)
- [`fs` in browser, creates a `.tar` file in real folder](demo/fsa-to-node-zipfile/README.md)
- [`fs` in browser, synchronous API, writes to real folder](demo/fsa-to-node-sync-tests/README.md)
- [`crudfs` and `casfs` in browser and Node.js interoperability](demo/crud-and-cas/README.md)
## See also
- [`unionfs`][unionfs] - creates a union of multiple filesystem volumes
- [`fs-monkey`][fs-monkey] - monkey-patches Node's `fs` module and `require` function
- [`linkfs`][linkfs] - redirects filesystem paths
- [`spyfs`][spyfs] - spies on filesystem actions
[unionfs]: https://github.com/streamich/unionfs
[fs-monkey]: https://github.com/streamich/fs-monkey
[linkfs]: https://github.com/streamich/linkfs
[spyfs]: https://github.com/streamich/spyfs
## License
Apache 2.0
+5
View File
@@ -0,0 +1,5 @@
const { fs } = require('memfs');
fs.writeFileSync('/hello.txt', 'Hello World');
console.log(fs.readFileSync('/hello.txt', 'utf8'));
+27
View File
@@ -0,0 +1,27 @@
import { Link } from './node';
import * as opts from './node/types/options';
import type { IDir, IDirent } from './node/types/misc';
/**
* A directory stream, like `fs.Dir`.
*/
export declare class Dir implements IDir {
protected readonly link: Link;
protected options: opts.IOpendirOptions;
private iteratorInfo;
constructor(link: Link, options: opts.IOpendirOptions);
private wrapAsync;
private isFunction;
private promisify;
private closeBase;
private readBase;
readonly path: string;
closeBaseAsync(callback: (err?: Error) => void): void;
close(): Promise<void>;
close(callback?: (err?: Error) => void): void;
closeSync(): void;
readBaseAsync(callback: (err: Error | null, dir?: IDirent | null) => void): void;
read(): Promise<IDirent | null>;
read(callback?: (err: Error | null, dir?: IDirent | null) => void): void;
readSync(): IDirent | null;
[Symbol.asyncIterator](): AsyncIterableIterator<IDirent>;
}
+137
View File
@@ -0,0 +1,137 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Dir = void 0;
const util_1 = require("./node/util");
const Dirent_1 = require("./Dirent");
/**
* A directory stream, like `fs.Dir`.
*/
class Dir {
constructor(link, options) {
this.link = link;
this.options = options;
this.iteratorInfo = [];
this.path = link.getParentPath();
this.iteratorInfo.push(link.children[Symbol.iterator]());
}
wrapAsync(method, args, callback) {
(0, util_1.validateCallback)(callback);
setImmediate(() => {
let result;
try {
result = method.apply(this, args);
}
catch (err) {
callback(err);
return;
}
callback(null, result);
});
}
isFunction(x) {
return typeof x === 'function';
}
promisify(obj, fn) {
return (...args) => new Promise((resolve, reject) => {
if (this.isFunction(obj[fn])) {
obj[fn].bind(obj)(...args, (error, result) => {
if (error)
reject(error);
resolve(result);
});
}
else {
reject('Not a function');
}
});
}
closeBase() { }
readBase(iteratorInfo) {
let done;
let value;
let name;
let link;
do {
do {
({ done, value } = iteratorInfo[iteratorInfo.length - 1].next());
if (!done) {
[name, link] = value;
}
else {
break;
}
} while (name === '.' || name === '..');
if (done) {
iteratorInfo.pop();
if (iteratorInfo.length === 0) {
break;
}
else {
done = false;
}
}
else {
if (this.options.recursive && link.children.size) {
iteratorInfo.push(link.children[Symbol.iterator]());
}
return Dirent_1.default.build(link, this.options.encoding);
}
} while (!done);
return null;
}
closeBaseAsync(callback) {
this.wrapAsync(this.closeBase, [], callback);
}
close(callback) {
if (typeof callback === 'function') {
this.closeBaseAsync(callback);
}
else {
return this.promisify(this, 'closeBaseAsync')();
}
}
closeSync() {
this.closeBase();
}
readBaseAsync(callback) {
this.wrapAsync(this.readBase, [this.iteratorInfo], callback);
}
read(callback) {
if (typeof callback === 'function') {
this.readBaseAsync(callback);
}
else {
return this.promisify(this, 'readBaseAsync')();
}
}
readSync() {
return this.readBase(this.iteratorInfo);
}
[Symbol.asyncIterator]() {
const iteratorInfo = [];
const _this = this;
iteratorInfo.push(_this.link.children[Symbol.iterator]());
// auxiliary object so promisify() can be used
const o = {
readBaseAsync(callback) {
_this.wrapAsync(_this.readBase, [iteratorInfo], callback);
},
};
return {
async next() {
const dirEnt = await _this.promisify(o, 'readBaseAsync')();
if (dirEnt !== null) {
return { done: false, value: dirEnt };
}
else {
return { done: true, value: undefined };
}
},
[Symbol.asyncIterator]() {
throw new Error('Not implemented');
},
};
}
}
exports.Dir = Dir;
//# sourceMappingURL=Dir.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Dir.js","sourceRoot":"","sources":["../src/Dir.ts"],"names":[],"mappings":"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"}
+22
View File
@@ -0,0 +1,22 @@
import { Link } from './node';
import { TEncodingExtended, TDataOut } from './encoding';
import type { IDirent } from './node/types/misc';
/**
* A directory entry, like `fs.Dirent`.
*/
export declare class Dirent implements IDirent {
static build(link: Link, encoding: TEncodingExtended | undefined): Dirent;
name: TDataOut;
path: string;
parentPath: string;
private mode;
private _checkModeProperty;
isDirectory(): boolean;
isFile(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
}
export default Dirent;
+53
View File
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Dirent = void 0;
const constants_1 = require("./constants");
const encoding_1 = require("./encoding");
const { S_IFMT, S_IFDIR, S_IFREG, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, S_IFSOCK } = constants_1.constants;
/**
* A directory entry, like `fs.Dirent`.
*/
class Dirent {
constructor() {
this.name = '';
this.path = '';
this.parentPath = '';
this.mode = 0;
}
static build(link, encoding) {
const dirent = new Dirent();
const { mode } = link.getNode();
dirent.name = (0, encoding_1.strToEncoding)(link.getName(), encoding);
dirent.mode = mode;
dirent.path = link.getParentPath();
dirent.parentPath = dirent.path;
return dirent;
}
_checkModeProperty(property) {
return (this.mode & S_IFMT) === property;
}
isDirectory() {
return this._checkModeProperty(S_IFDIR);
}
isFile() {
return this._checkModeProperty(S_IFREG);
}
isBlockDevice() {
return this._checkModeProperty(S_IFBLK);
}
isCharacterDevice() {
return this._checkModeProperty(S_IFCHR);
}
isSymbolicLink() {
return this._checkModeProperty(S_IFLNK);
}
isFIFO() {
return this._checkModeProperty(S_IFIFO);
}
isSocket() {
return this._checkModeProperty(S_IFSOCK);
}
}
exports.Dirent = Dirent;
exports.default = Dirent;
//# sourceMappingURL=Dirent.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Dirent.js","sourceRoot":"","sources":["../src/Dirent.ts"],"names":[],"mappings":";;;AACA,2CAAwC;AACxC,yCAAwE;AAGxE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,qBAAS,CAAC;AAE7F;;GAEG;AACH,MAAa,MAAM;IAAnB;QAaE,SAAI,GAAa,EAAE,CAAC;QACpB,SAAI,GAAG,EAAE,CAAC;QACV,eAAU,GAAG,EAAE,CAAC;QACR,SAAI,GAAW,CAAC,CAAC;IAiC3B,CAAC;IAhDC,MAAM,CAAC,KAAK,CAAC,IAAU,EAAE,QAAuC;QAC9D,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAEhC,MAAM,CAAC,IAAI,GAAG,IAAA,wBAAa,EAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACnC,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;QAEhC,OAAO,MAAM,CAAC;IAChB,CAAC;IAOO,kBAAkB,CAAC,QAAgB;QACzC,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,QAAQ,CAAC;IAC3C,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;CACF;AAjDD,wBAiDC;AAED,kBAAe,MAAM,CAAC"}
+41
View File
@@ -0,0 +1,41 @@
import { Node } from './node';
export type TStatNumber = number | bigint;
/**
* Statistics about a file/directory, like `fs.Stats`.
*/
export declare class Stats<T = TStatNumber> {
static build(node: Node, bigint: false): Stats<number>;
static build(node: Node, bigint: true): Stats<bigint>;
static build(node: Node, bigint?: boolean): Stats<TStatNumber>;
uid: T;
gid: T;
rdev: T;
blksize: T;
ino: T;
size: T;
blocks: T;
atime: Date;
mtime: Date;
ctime: Date;
birthtime: Date;
atimeMs: T;
mtimeMs: T;
ctimeMs: T;
birthtimeMs: T;
atimeNs: T extends bigint ? T : undefined;
mtimeNs: T extends bigint ? T : undefined;
ctimeNs: T extends bigint ? T : undefined;
birthtimeNs: T extends bigint ? T : undefined;
dev: T;
mode: T;
nlink: T;
private _checkModeProperty;
isDirectory(): boolean;
isFile(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
}
export default Stats;
+72
View File
@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Stats = void 0;
const constants_1 = require("./constants");
const { S_IFMT, S_IFDIR, S_IFREG, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, S_IFSOCK } = constants_1.constants;
/**
* Statistics about a file/directory, like `fs.Stats`.
*/
class Stats {
static build(node, bigint = false) {
const stats = new Stats();
const { uid, gid, atime, mtime, ctime } = node;
const getStatNumber = !bigint ? number => number : number => BigInt(number);
// Copy all values on Stats from Node, so that if Node values
// change, values on Stats would still be the old ones,
// just like in Node fs.
stats.uid = getStatNumber(uid);
stats.gid = getStatNumber(gid);
stats.rdev = getStatNumber(node.rdev);
stats.blksize = getStatNumber(4096);
stats.ino = getStatNumber(node.ino);
stats.size = getStatNumber(node.getSize());
stats.blocks = getStatNumber(1);
stats.atime = atime;
stats.mtime = mtime;
stats.ctime = ctime;
stats.birthtime = ctime;
stats.atimeMs = getStatNumber(atime.getTime());
stats.mtimeMs = getStatNumber(mtime.getTime());
const ctimeMs = getStatNumber(ctime.getTime());
stats.ctimeMs = ctimeMs;
stats.birthtimeMs = ctimeMs;
if (bigint) {
stats.atimeNs = BigInt(atime.getTime()) * BigInt(1000000);
stats.mtimeNs = BigInt(mtime.getTime()) * BigInt(1000000);
const ctimeNs = BigInt(ctime.getTime()) * BigInt(1000000);
stats.ctimeNs = ctimeNs;
stats.birthtimeNs = ctimeNs;
}
stats.dev = getStatNumber(0);
stats.mode = getStatNumber(node.mode);
stats.nlink = getStatNumber(node.nlink);
return stats;
}
_checkModeProperty(property) {
return (Number(this.mode) & S_IFMT) === property;
}
isDirectory() {
return this._checkModeProperty(S_IFDIR);
}
isFile() {
return this._checkModeProperty(S_IFREG);
}
isBlockDevice() {
return this._checkModeProperty(S_IFBLK);
}
isCharacterDevice() {
return this._checkModeProperty(S_IFCHR);
}
isSymbolicLink() {
return this._checkModeProperty(S_IFLNK);
}
isFIFO() {
return this._checkModeProperty(S_IFIFO);
}
isSocket() {
return this._checkModeProperty(S_IFSOCK);
}
}
exports.Stats = Stats;
exports.default = Stats;
//# sourceMappingURL=Stats.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Stats.js","sourceRoot":"","sources":["../src/Stats.ts"],"names":[],"mappings":"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"}
+10
View File
@@ -0,0 +1,10 @@
import type { CrudResourceInfo } from '../crud/types';
export interface CasApi<Hash> {
put(blob: Uint8Array): Promise<Hash>;
get(hash: Hash, options?: CasGetOptions): Promise<Uint8Array>;
del(hash: Hash, silent?: boolean): Promise<void>;
info(hash: Hash): Promise<CrudResourceInfo>;
}
export interface CasGetOptions {
skipVerification?: boolean;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cas/types.ts"],"names":[],"mappings":""}
+63
View File
@@ -0,0 +1,63 @@
export declare const constants: {
O_RDONLY: number;
O_WRONLY: number;
O_RDWR: number;
S_IFMT: number;
S_IFREG: number;
S_IFDIR: number;
S_IFCHR: number;
S_IFBLK: number;
S_IFIFO: number;
S_IFLNK: number;
S_IFSOCK: number;
O_CREAT: number;
O_EXCL: number;
O_NOCTTY: number;
O_TRUNC: number;
O_APPEND: number;
O_DIRECTORY: number;
O_NOATIME: number;
O_NOFOLLOW: number;
O_SYNC: number;
O_SYMLINK: number;
O_DIRECT: number;
O_NONBLOCK: number;
S_IRWXU: number;
S_IRUSR: number;
S_IWUSR: number;
S_IXUSR: number;
S_IRWXG: number;
S_IRGRP: number;
S_IWGRP: number;
S_IXGRP: number;
S_IRWXO: number;
S_IROTH: number;
S_IWOTH: number;
S_IXOTH: number;
F_OK: number;
R_OK: number;
W_OK: number;
X_OK: number;
UV_FS_SYMLINK_DIR: number;
UV_FS_SYMLINK_JUNCTION: number;
UV_FS_COPYFILE_EXCL: number;
UV_FS_COPYFILE_FICLONE: number;
UV_FS_COPYFILE_FICLONE_FORCE: number;
COPYFILE_EXCL: number;
COPYFILE_FICLONE: number;
COPYFILE_FICLONE_FORCE: number;
};
export declare const enum S {
ISUID = 2048,// (04000) set-user-ID (set process effective user ID on execve(2))
ISGID = 1024,// (02000) set-group-ID (set process effective group ID on execve(2); mandatory locking, as described in fcntl(2); take a new file's group from parent directory, as described in chown(2) and mkdir(2))
ISVTX = 512,// (01000) sticky bit (restricted deletion flag, as described in unlink(2))
IRUSR = 256,// (00400) read by owner
IWUSR = 128,// (00200) write by owner
IXUSR = 64,// (00100) execute/search by owner
IRGRP = 32,// (00040) read by group
IWGRP = 16,// (00020) write by group
IXGRP = 8,// (00010) execute/search by group
IROTH = 4,// (00004) read by others
IWOTH = 2,// (00002) write by others
IXOTH = 1
}
+53
View File
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.constants = void 0;
exports.constants = {
O_RDONLY: 0,
O_WRONLY: 1,
O_RDWR: 2,
S_IFMT: 61440,
S_IFREG: 32768,
S_IFDIR: 16384,
S_IFCHR: 8192,
S_IFBLK: 24576,
S_IFIFO: 4096,
S_IFLNK: 40960,
S_IFSOCK: 49152,
O_CREAT: 64,
O_EXCL: 128,
O_NOCTTY: 256,
O_TRUNC: 512,
O_APPEND: 1024,
O_DIRECTORY: 65536,
O_NOATIME: 262144,
O_NOFOLLOW: 131072,
O_SYNC: 1052672,
O_SYMLINK: 2097152,
O_DIRECT: 16384,
O_NONBLOCK: 2048,
S_IRWXU: 448,
S_IRUSR: 256,
S_IWUSR: 128,
S_IXUSR: 64,
S_IRWXG: 56,
S_IRGRP: 32,
S_IWGRP: 16,
S_IXGRP: 8,
S_IRWXO: 7,
S_IROTH: 4,
S_IWOTH: 2,
S_IXOTH: 1,
F_OK: 0,
R_OK: 4,
W_OK: 2,
X_OK: 1,
UV_FS_SYMLINK_DIR: 1,
UV_FS_SYMLINK_JUNCTION: 2,
UV_FS_COPYFILE_EXCL: 1,
UV_FS_COPYFILE_FICLONE: 2,
UV_FS_COPYFILE_FICLONE_FORCE: 4,
COPYFILE_EXCL: 1,
COPYFILE_FICLONE: 2,
COPYFILE_FICLONE_FORCE: 4,
};
//# sourceMappingURL=constants.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,SAAS,GAAG;IACvB,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,EAAE;IACX,MAAM,EAAE,GAAG;IACX,QAAQ,EAAE,GAAG;IACb,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE,IAAI;IACd,WAAW,EAAE,KAAK;IAClB,SAAS,EAAE,MAAM;IACjB,UAAU,EAAE,MAAM;IAClB,MAAM,EAAE,OAAO;IACf,SAAS,EAAE,OAAO;IAClB,QAAQ,EAAE,KAAK;IACf,UAAU,EAAE,IAAI;IAChB,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IAEV,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IAEP,iBAAiB,EAAE,CAAC;IACpB,sBAAsB,EAAE,CAAC;IAEzB,mBAAmB,EAAE,CAAC;IACtB,sBAAsB,EAAE,CAAC;IACzB,4BAA4B,EAAE,CAAC;IAC/B,aAAa,EAAE,CAAC;IAChB,gBAAgB,EAAE,CAAC;IACnB,sBAAsB,EAAE,CAAC;CAC1B,CAAC"}
+9
View File
@@ -0,0 +1,9 @@
export declare const enum AMODE {
F_OK = 0,
/** Tests for Execute or Search permissions. */
X_OK = 1,
/** Tests for Write permission. */
W_OK = 2,
/** Tests for Read permission. */
R_OK = 4
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=AMODE.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"AMODE.js","sourceRoot":"","sources":["../../src/consts/AMODE.ts"],"names":[],"mappings":""}
+28
View File
@@ -0,0 +1,28 @@
/**
* Constants used in `open` system calls, see [open(2)](http://man7.org/linux/man-pages/man2/open.2.html).
*
* @see http://man7.org/linux/man-pages/man2/open.2.html
* @see https://www.gnu.org/software/libc/manual/html_node/Open_002dtime-Flags.html
*/
export declare const enum FLAG {
O_RDONLY = 0,
O_WRONLY = 1,
O_RDWR = 2,
O_ACCMODE = 3,
O_CREAT = 64,
O_EXCL = 128,
O_NOCTTY = 256,
O_TRUNC = 512,
O_APPEND = 1024,
O_NONBLOCK = 2048,
O_DSYNC = 4096,
FASYNC = 8192,
O_DIRECT = 16384,
O_LARGEFILE = 0,
O_DIRECTORY = 65536,
O_NOFOLLOW = 131072,
O_NOATIME = 262144,
O_CLOEXEC = 524288,
O_SYNC = 1052672,
O_NDELAY = 2048
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=FLAG.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FLAG.js","sourceRoot":"","sources":["../../src/consts/FLAG.ts"],"names":[],"mappings":""}
+10
View File
@@ -0,0 +1,10 @@
import { CrudCasBase } from './CrudCasBase';
import type { CrudApi } from '../crud/types';
export interface CrudCasOptions {
hash: (blob: Uint8Array) => Promise<string>;
}
export declare class CrudCas extends CrudCasBase<string> {
protected readonly crud: CrudApi;
protected readonly options: CrudCasOptions;
constructor(crud: CrudApi, options: CrudCasOptions);
}
+15
View File
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrudCas = void 0;
const util_1 = require("./util");
const CrudCasBase_1 = require("./CrudCasBase");
const hashEqual = (h1, h2) => h1 === h2;
class CrudCas extends CrudCasBase_1.CrudCasBase {
constructor(crud, options) {
super(crud, options.hash, util_1.hashToLocation, hashEqual);
this.crud = crud;
this.options = options;
}
}
exports.CrudCas = CrudCas;
//# sourceMappingURL=CrudCas.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CrudCas.js","sourceRoot":"","sources":["../../src/crud-to-cas/CrudCas.ts"],"names":[],"mappings":";;;AAAA,iCAAwC;AACxC,+CAA4C;AAO5C,MAAM,SAAS,GAAG,CAAC,EAAU,EAAE,EAAU,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;AAExD,MAAa,OAAQ,SAAQ,yBAAmB;IAC9C,YACqB,IAAa,EACb,OAAuB;QAE1C,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,qBAAc,EAAE,SAAS,CAAC,CAAC;QAHlC,SAAI,GAAJ,IAAI,CAAS;QACb,YAAO,GAAP,OAAO,CAAgB;IAG5C,CAAC;CACF;AAPD,0BAOC"}
+14
View File
@@ -0,0 +1,14 @@
import type { CasApi, CasGetOptions } from '../cas/types';
import type { CrudApi, CrudResourceInfo } from '../crud/types';
import type { FsLocation } from '../fsa-to-node/types';
export declare class CrudCasBase<Hash> implements CasApi<Hash> {
protected readonly crud: CrudApi;
protected readonly hash: (blob: Uint8Array) => Promise<Hash>;
protected readonly hash2Loc: (hash: Hash) => FsLocation;
protected readonly hashEqual: (h1: Hash, h2: Hash) => boolean;
constructor(crud: CrudApi, hash: (blob: Uint8Array) => Promise<Hash>, hash2Loc: (hash: Hash) => FsLocation, hashEqual: (h1: Hash, h2: Hash) => boolean);
readonly put: (blob: Uint8Array) => Promise<Hash>;
readonly get: (hash: Hash, options?: CasGetOptions) => Promise<Uint8Array>;
readonly del: (hash: Hash, silent?: boolean) => Promise<void>;
readonly info: (hash: Hash) => Promise<CrudResourceInfo>;
}
+58
View File
@@ -0,0 +1,58 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrudCasBase = void 0;
const normalizeErrors = async (code) => {
try {
return await code();
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'ResourceNotFound':
case 'CollectionNotFound':
throw new DOMException(error.message, 'BlobNotFound');
}
}
throw error;
}
};
class CrudCasBase {
constructor(crud, hash, hash2Loc, hashEqual) {
this.crud = crud;
this.hash = hash;
this.hash2Loc = hash2Loc;
this.hashEqual = hashEqual;
this.put = async (blob) => {
const digest = await this.hash(blob);
const [collection, resource] = this.hash2Loc(digest);
await this.crud.put(collection, resource, blob);
return digest;
};
this.get = async (hash, options) => {
const [collection, resource] = this.hash2Loc(hash);
return await normalizeErrors(async () => {
const blob = await this.crud.get(collection, resource);
if (!(options === null || options === void 0 ? void 0 : options.skipVerification)) {
const digest = await this.hash(blob);
if (!this.hashEqual(digest, hash))
throw new DOMException('Blob contents does not match hash', 'Integrity');
}
return blob;
});
};
this.del = async (hash, silent) => {
const [collection, resource] = this.hash2Loc(hash);
await normalizeErrors(async () => {
return await this.crud.del(collection, resource, silent);
});
};
this.info = async (hash) => {
const [collection, resource] = this.hash2Loc(hash);
return await normalizeErrors(async () => {
return await this.crud.info(collection, resource);
});
};
}
}
exports.CrudCasBase = CrudCasBase;
//# sourceMappingURL=CrudCasBase.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CrudCasBase.js","sourceRoot":"","sources":["../../src/crud-to-cas/CrudCasBase.ts"],"names":[],"mappings":";;;AAIA,MAAM,eAAe,GAAG,KAAK,EAAK,IAAsB,EAAc,EAAE;IACtE,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;gBACnB,KAAK,kBAAkB,CAAC;gBACxB,KAAK,oBAAoB;oBACvB,MAAM,IAAI,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAa,WAAW;IACtB,YACqB,IAAa,EACb,IAAyC,EACzC,QAAoC,EACpC,SAA0C;QAH1C,SAAI,GAAJ,IAAI,CAAS;QACb,SAAI,GAAJ,IAAI,CAAqC;QACzC,aAAQ,GAAR,QAAQ,CAA4B;QACpC,cAAS,GAAT,SAAS,CAAiC;QAG/C,QAAG,GAAG,KAAK,EAAE,IAAgB,EAAiB,EAAE;YAC9D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACrD,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEc,QAAG,GAAG,KAAK,EAAE,IAAU,EAAE,OAAuB,EAAuB,EAAE;YACvF,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnD,OAAO,MAAM,eAAe,CAAC,KAAK,IAAI,EAAE;gBACtC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACvD,IAAI,CAAC,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,CAAA,EAAE,CAAC;oBAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACrC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC;wBAAE,MAAM,IAAI,YAAY,CAAC,mCAAmC,EAAE,WAAW,CAAC,CAAC;gBAC9G,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEc,QAAG,GAAG,KAAK,EAAE,IAAU,EAAE,MAAgB,EAAiB,EAAE;YAC1E,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnD,MAAM,eAAe,CAAC,KAAK,IAAI,EAAE;gBAC/B,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC3D,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEc,SAAI,GAAG,KAAK,EAAE,IAAU,EAA6B,EAAE;YACrE,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnD,OAAO,MAAM,eAAe,CAAC,KAAK,IAAI,EAAE;gBACtC,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACpD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;IAjCC,CAAC;CAkCL;AAxCD,kCAwCC"}
+1
View File
@@ -0,0 +1 @@
export { CrudCas, CrudCasOptions } from './CrudCas';
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrudCas = void 0;
var CrudCas_1 = require("./CrudCas");
Object.defineProperty(exports, "CrudCas", { enumerable: true, get: function () { return CrudCas_1.CrudCas; } });
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crud-to-cas/index.ts"],"names":[],"mappings":";;;AAAA,qCAAoD;AAA3C,kGAAA,OAAO,OAAA"}
+2
View File
@@ -0,0 +1,2 @@
import type { FsLocation } from '../fsa-to-node/types';
export declare const hashToLocation: (hash: string) => FsLocation;
+13
View File
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hashToLocation = void 0;
const hashToLocation = (hash) => {
if (hash.length < 20)
throw new TypeError('Hash is too short');
const lastTwo = hash.slice(-2);
const twoBeforeLastTwo = hash.slice(-4, -2);
const folder = [lastTwo, twoBeforeLastTwo];
return [folder, hash];
};
exports.hashToLocation = hashToLocation;
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/crud-to-cas/util.ts"],"names":[],"mappings":";;;AAEO,MAAM,cAAc,GAAG,CAAC,IAAY,EAAc,EAAE;IACzD,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAC3C,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACxB,CAAC,CAAC;AANW,QAAA,cAAc,kBAMzB"}
+83
View File
@@ -0,0 +1,83 @@
export interface CrudApi {
/**
* Creates a new resource, or overwrites an existing one.
*
* @param collection Type of the resource, collection name.
* @param id Id of the resource, document name.
* @param data Blob content of the resource.
* @param options Write behavior options.
*/
put: (collection: CrudCollection, id: string, data: Uint8Array, options?: CrudPutOptions) => Promise<void>;
/**
* Retrieves the content of a resource.
*
* @param collection Type of the resource, collection name.
* @param id Id of the resource, document name.
* @returns Blob content of the resource.
*/
get: (collection: CrudCollection, id: string) => Promise<Uint8Array>;
/**
* Deletes a resource.
*
* @param collection Type of the resource, collection name.
* @param id Id of the resource, document name.
* @param silent When true, does not throw an error if the collection or
* resource does not exist. Default is false.
*/
del: (collection: CrudCollection, id: string, silent?: boolean) => Promise<void>;
/**
* Fetches information about a resource.
*
* @param collection Type of the resource, collection name.
* @param id Id of the resource, document name, if any.
* @returns Information about the resource.
*/
info: (collection: CrudCollection, id?: string) => Promise<CrudResourceInfo>;
/**
* Deletes all resources of a collection, and deletes recursively all sub-collections.
*
* @param collection Type of the resource, collection name.
* @param silent When true, does not throw an error if the collection or
* resource does not exist. Default is false.
*/
drop: (collection: CrudCollection, silent?: boolean) => Promise<void>;
/**
* Iterates over all resources of a collection.
*
* @param collection Type of the resource, collection name.
* @returns Iterator of resources of the given type.
*/
scan: (collection: CrudCollection) => AsyncIterableIterator<CrudCollectionEntry>;
/**
* Fetches a list of resources of a collection, and sub-collections.
*
* @param collection Type of the resource, collection name.
* @returns List of resources of the given type, and sub-types.
*/
list: (collection: CrudCollection) => Promise<CrudCollectionEntry[]>;
/**
* Creates a new CrudApi instance, with the given collection as root.
*
* @param collection Type of the resource, collection name.
* @returns A new CrudApi instance, with the given collection as root.
*/
from: (collection: CrudCollection) => Promise<CrudApi>;
}
export type CrudCollection = string[];
export interface CrudPutOptions {
throwIf?: 'exists' | 'missing';
}
export interface CrudCollectionEntry {
/** Kind of the resource, type or item. */
type: 'resource' | 'collection';
/** Name of the resource. */
id: string;
}
export interface CrudResourceInfo extends CrudCollectionEntry {
/** Size of the resource in bytes. */
size?: number;
/** Timestamp when the resource last modified. */
modified?: number;
/** Timestamp when the resource was created. */
created?: number;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/crud/types.ts"],"names":[],"mappings":""}
+2
View File
@@ -0,0 +1,2 @@
import { CrudCollection } from './types';
export declare const assertType: (type: CrudCollection, method: string, klass: string) => void;
+11
View File
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.assertType = void 0;
const util_1 = require("../node-to-fsa/util");
const assertType = (type, method, klass) => {
const length = type.length;
for (let i = 0; i < length; i++)
(0, util_1.assertName)(type[i], method, klass);
};
exports.assertType = assertType;
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/crud/util.ts"],"names":[],"mappings":";;;AACA,8CAAiD;AAE1C,MAAM,UAAU,GAAG,CAAC,IAAoB,EAAE,MAAc,EAAE,KAAa,EAAQ,EAAE;IACtF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE;QAAE,IAAA,iBAAU,EAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AACtE,CAAC,CAAC;AAHW,QAAA,UAAU,cAGrB"}
+5
View File
@@ -0,0 +1,5 @@
export type TDataOut = string | Buffer;
export type TEncodingExtended = BufferEncoding | 'buffer';
export declare const ENCODING_UTF8: BufferEncoding;
export declare function assertEncoding(encoding: string | undefined): void;
export declare function strToEncoding(str: string, encoding?: TEncodingExtended): TDataOut;
+20
View File
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ENCODING_UTF8 = void 0;
exports.assertEncoding = assertEncoding;
exports.strToEncoding = strToEncoding;
const buffer_1 = require("./internal/buffer");
const errors = require("./internal/errors");
exports.ENCODING_UTF8 = 'utf8';
function assertEncoding(encoding) {
if (encoding && !buffer_1.Buffer.isEncoding(encoding))
throw new errors.TypeError('ERR_INVALID_OPT_VALUE_ENCODING', encoding);
}
function strToEncoding(str, encoding) {
if (!encoding || encoding === exports.ENCODING_UTF8)
return str; // UTF-8
if (encoding === 'buffer')
return new buffer_1.Buffer(str); // `buffer` encoding
return new buffer_1.Buffer(str).toString(encoding); // Custom encoding
}
//# sourceMappingURL=encoding.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":";;;AAQA,wCAEC;AAED,sCAIC;AAhBD,8CAA2C;AAC3C,4CAA4C;AAK/B,QAAA,aAAa,GAAmB,MAAM,CAAC;AAEpD,SAAgB,cAAc,CAAC,QAA4B;IACzD,IAAI,QAAQ,IAAI,CAAC,eAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC,gCAAgC,EAAE,QAAQ,CAAC,CAAC;AACvH,CAAC;AAED,SAAgB,aAAa,CAAC,GAAW,EAAE,QAA4B;IACrE,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,qBAAa;QAAE,OAAO,GAAG,CAAC,CAAC,QAAQ;IACjE,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,eAAM,CAAC,GAAG,CAAC,CAAC,CAAC,oBAAoB;IACvE,OAAO,IAAI,eAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,kBAAkB;AAC/D,CAAC"}
+16
View File
@@ -0,0 +1,16 @@
import type * as crud from '../crud/types';
import type * as fsa from '../fsa/types';
export declare class FsaCrud implements crud.CrudApi {
protected readonly root: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>;
constructor(root: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>);
protected getDir(collection: crud.CrudCollection, create: boolean): Promise<[dir: fsa.IFileSystemDirectoryHandle, parent: fsa.IFileSystemDirectoryHandle | undefined]>;
protected getFile(collection: crud.CrudCollection, id: string): Promise<[dir: fsa.IFileSystemDirectoryHandle, file: fsa.IFileSystemFileHandle]>;
readonly put: (collection: crud.CrudCollection, id: string, data: Uint8Array, options?: crud.CrudPutOptions) => Promise<void>;
readonly get: (collection: crud.CrudCollection, id: string) => Promise<Uint8Array>;
readonly del: (collection: crud.CrudCollection, id: string, silent?: boolean) => Promise<void>;
readonly info: (collection: crud.CrudCollection, id?: string) => Promise<crud.CrudResourceInfo>;
readonly drop: (collection: crud.CrudCollection, silent?: boolean) => Promise<void>;
readonly scan: (collection: crud.CrudCollection) => AsyncIterableIterator<crud.CrudCollectionEntry>;
readonly list: (collection: crud.CrudCollection) => Promise<crud.CrudCollectionEntry[]>;
readonly from: (collection: crud.CrudCollection) => Promise<crud.CrudApi>;
}
+211
View File
@@ -0,0 +1,211 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaCrud = void 0;
const tslib_1 = require("tslib");
const util_1 = require("../node-to-fsa/util");
const util_2 = require("../crud/util");
const util_3 = require("./util");
class FsaCrud {
constructor(root) {
this.root = root;
this.put = async (collection, id, data, options) => {
(0, util_2.assertType)(collection, 'put', 'crudfs');
(0, util_1.assertName)(id, 'put', 'crudfs');
const [dir] = await this.getDir(collection, true);
let file;
switch (options === null || options === void 0 ? void 0 : options.throwIf) {
case 'exists': {
try {
file = await dir.getFileHandle(id, { create: false });
throw (0, util_3.newExistsError)();
}
catch (e) {
if (e.name !== 'NotFoundError')
throw e;
file = await dir.getFileHandle(id, { create: true });
}
break;
}
case 'missing': {
try {
file = await dir.getFileHandle(id, { create: false });
}
catch (e) {
if (e.name === 'NotFoundError')
throw (0, util_3.newMissingError)();
throw e;
}
break;
}
default: {
file = await dir.getFileHandle(id, { create: true });
}
}
const writable = await file.createWritable();
await writable.write(data);
await writable.close();
};
this.get = async (collection, id) => {
(0, util_2.assertType)(collection, 'get', 'crudfs');
(0, util_1.assertName)(id, 'get', 'crudfs');
const [, file] = await this.getFile(collection, id);
const blob = await file.getFile();
const buffer = await blob.arrayBuffer();
return new Uint8Array(buffer);
};
this.del = async (collection, id, silent) => {
(0, util_2.assertType)(collection, 'del', 'crudfs');
(0, util_1.assertName)(id, 'del', 'crudfs');
try {
const [dir] = await this.getFile(collection, id);
await dir.removeEntry(id, { recursive: false });
}
catch (error) {
if (!silent)
throw error;
}
};
this.info = async (collection, id) => {
(0, util_2.assertType)(collection, 'info', 'crudfs');
if (id) {
(0, util_1.assertName)(id, 'info', 'crudfs');
const [, file] = await this.getFile(collection, id);
const blob = await file.getFile();
return {
type: 'resource',
id,
size: blob.size,
modified: blob.lastModified,
};
}
else {
await this.getDir(collection, false);
return {
type: 'collection',
id: '',
};
}
};
this.drop = async (collection, silent) => {
var _a, e_1, _b, _c;
(0, util_2.assertType)(collection, 'drop', 'crudfs');
try {
const [dir, parent] = await this.getDir(collection, false);
if (parent) {
await parent.removeEntry(dir.name, { recursive: true });
}
else {
const root = await this.root;
try {
for (var _d = true, _e = tslib_1.__asyncValues(root.keys()), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
_c = _f.value;
_d = false;
const name = _c;
await root.removeEntry(name, { recursive: true });
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
}
finally { if (e_1) throw e_1.error; }
}
}
}
catch (error) {
if (!silent)
throw error;
}
};
this.scan = function (collection) {
return tslib_1.__asyncGenerator(this, arguments, function* () {
var _a, e_2, _b, _c;
(0, util_2.assertType)(collection, 'scan', 'crudfs');
const [dir] = yield tslib_1.__await(this.getDir(collection, false));
try {
for (var _d = true, _e = tslib_1.__asyncValues(dir.entries()), _f; _f = yield tslib_1.__await(_e.next()), _a = _f.done, !_a; _d = true) {
_c = _f.value;
_d = false;
const [id, handle] = _c;
if (handle.kind === 'file') {
yield yield tslib_1.__await({
type: 'resource',
id,
});
}
else if (handle.kind === 'directory') {
yield yield tslib_1.__await({
type: 'collection',
id,
});
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (!_d && !_a && (_b = _e.return)) yield tslib_1.__await(_b.call(_e));
}
finally { if (e_2) throw e_2.error; }
}
});
};
this.list = async (collection) => {
var _a, e_3, _b, _c;
const entries = [];
try {
for (var _d = true, _e = tslib_1.__asyncValues(this.scan(collection)), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
_c = _f.value;
_d = false;
const entry = _c;
entries.push(entry);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
}
finally { if (e_3) throw e_3.error; }
}
return entries;
};
this.from = async (collection) => {
(0, util_2.assertType)(collection, 'from', 'crudfs');
const [dir] = await this.getDir(collection, true);
return new FsaCrud(dir);
};
}
async getDir(collection, create) {
let parent = undefined;
let dir = await this.root;
try {
for (const name of collection) {
const child = await dir.getDirectoryHandle(name, { create });
parent = dir;
dir = child;
}
return [dir, parent];
}
catch (error) {
if (error.name === 'NotFoundError')
throw (0, util_3.newFolder404Error)(collection);
throw error;
}
}
async getFile(collection, id) {
const [dir] = await this.getDir(collection, false);
try {
const file = await dir.getFileHandle(id, { create: false });
return [dir, file];
}
catch (error) {
if (error.name === 'NotFoundError')
throw (0, util_3.newFile404Error)(collection, id);
throw error;
}
}
}
exports.FsaCrud = FsaCrud;
//# sourceMappingURL=FsaCrud.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export { FsaCrud } from './FsaCrud';
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaCrud = void 0;
var FsaCrud_1 = require("./FsaCrud");
Object.defineProperty(exports, "FsaCrud", { enumerable: true, get: function () { return FsaCrud_1.FsaCrud; } });
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fsa-to-crud/index.ts"],"names":[],"mappings":";;;AAAA,qCAAoC;AAA3B,kGAAA,OAAO,OAAA"}
+5
View File
@@ -0,0 +1,5 @@
import type * as crud from '../crud/types';
export declare const newFile404Error: (collection: crud.CrudCollection, id: string) => DOMException;
export declare const newFolder404Error: (collection: crud.CrudCollection) => DOMException;
export declare const newExistsError: () => DOMException;
export declare const newMissingError: () => DOMException;
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.newMissingError = exports.newExistsError = exports.newFolder404Error = exports.newFile404Error = void 0;
const newFile404Error = (collection, id) => new DOMException(`Resource "${id}" in /${collection.join('/')} not found`, 'ResourceNotFound');
exports.newFile404Error = newFile404Error;
const newFolder404Error = (collection) => new DOMException(`Collection /${collection.join('/')} does not exist`, 'CollectionNotFound');
exports.newFolder404Error = newFolder404Error;
const newExistsError = () => new DOMException('Resource already exists', 'Exists');
exports.newExistsError = newExistsError;
const newMissingError = () => new DOMException('Resource is missing', 'Missing');
exports.newMissingError = newMissingError;
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/fsa-to-crud/util.ts"],"names":[],"mappings":";;;AAEO,MAAM,eAAe,GAAG,CAAC,UAA+B,EAAE,EAAU,EAAE,EAAE,CAC7E,IAAI,YAAY,CAAC,aAAa,EAAE,SAAS,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;AADpF,QAAA,eAAe,mBACqE;AAE1F,MAAM,iBAAiB,GAAG,CAAC,UAA+B,EAAE,EAAE,CACnE,IAAI,YAAY,CAAC,eAAe,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAC;AADlF,QAAA,iBAAiB,qBACiE;AAExF,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,IAAI,YAAY,CAAC,yBAAyB,EAAE,QAAQ,CAAC,CAAC;AAA7E,QAAA,cAAc,kBAA+D;AAEnF,MAAM,eAAe,GAAG,GAAG,EAAE,CAAC,IAAI,YAAY,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAC;AAA3E,QAAA,eAAe,mBAA4D"}
+33
View File
@@ -0,0 +1,33 @@
import { FsaNodeFsOpenFile } from './FsaNodeFsOpenFile';
import type * as fsa from '../fsa/types';
import type * as misc from '../node/types/misc';
import type { FsaNodeSyncAdapter } from './types';
export declare class FsaNodeCore {
protected readonly root: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>;
syncAdapter?: FsaNodeSyncAdapter | undefined;
protected static fd: number;
protected readonly fds: Map<number, FsaNodeFsOpenFile>;
constructor(root: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>, syncAdapter?: FsaNodeSyncAdapter | undefined);
protected getSyncAdapter(): FsaNodeSyncAdapter;
/**
* A list of reusable (opened and closed) file descriptors, that should be
* used first before creating a new file descriptor.
*/
releasedFds: number[];
protected newFdNumber(): number;
/**
* @param path Path from root to the new folder.
* @param create Whether to create the folders if they don't exist.
*/
protected getDir(path: string[], create: boolean, funcName?: string): Promise<fsa.IFileSystemDirectoryHandle>;
protected getFile(path: string[], name: string, funcName?: string, create?: boolean): Promise<fsa.IFileSystemFileHandle>;
protected getFileOrDir(path: string[], name: string, funcName?: string): Promise<fsa.IFileSystemFileHandle | fsa.IFileSystemDirectoryHandle>;
protected getFileByFd(fd: number, funcName?: string): FsaNodeFsOpenFile;
protected getFileByFdAsync(fd: number, funcName?: string): Promise<FsaNodeFsOpenFile>;
__getFileById(id: misc.TFileId, funcName?: string): Promise<fsa.IFileSystemFileHandle>;
protected getFileByIdOrCreate(id: misc.TFileId, funcName?: string): Promise<fsa.IFileSystemFileHandle>;
protected __open(filename: string, flags: number, mode: number): Promise<FsaNodeFsOpenFile>;
protected __open2(fsaFile: fsa.IFileSystemFileHandle, filename: string, flags: number, mode: number): FsaNodeFsOpenFile;
protected __close(fd: number): Promise<void>;
protected getFileName(id: misc.TFileId): string;
}
+190
View File
@@ -0,0 +1,190 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeCore = void 0;
const util_1 = require("../node/util");
const util_2 = require("./util");
const constants_1 = require("../node/constants");
const FsaNodeFsOpenFile_1 = require("./FsaNodeFsOpenFile");
const util = require("../node/util");
class FsaNodeCore {
constructor(root, syncAdapter) {
this.root = root;
this.syncAdapter = syncAdapter;
this.fds = new Map();
/**
* A list of reusable (opened and closed) file descriptors, that should be
* used first before creating a new file descriptor.
*/
this.releasedFds = [];
if (root instanceof Promise) {
root
.then(root => {
this.root = root;
})
.catch(error => { });
}
}
getSyncAdapter() {
const adapter = this.syncAdapter;
if (!adapter)
throw new Error('No sync adapter');
return adapter;
}
newFdNumber() {
const releasedFd = this.releasedFds.pop();
return typeof releasedFd === 'number' ? releasedFd : FsaNodeCore.fd--;
}
/**
* @param path Path from root to the new folder.
* @param create Whether to create the folders if they don't exist.
*/
async getDir(path, create, funcName) {
let curr = await this.root;
const options = { create };
try {
for (const name of path) {
curr = await curr.getDirectoryHandle(name, options);
}
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
throw (0, util_1.createError)('ENOTDIR', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
}
}
throw error;
}
return curr;
}
async getFile(path, name, funcName, create) {
const dir = await this.getDir(path, false, funcName);
const file = await dir.getFileHandle(name, { create });
return file;
}
async getFileOrDir(path, name, funcName) {
const dir = await this.getDir(path, false, funcName);
if (!name)
return dir;
try {
const file = await dir.getFileHandle(name);
return file;
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
try {
return await dir.getDirectoryHandle(name);
}
catch (error2) {
if (error2 && typeof error2 === 'object') {
switch (error2.name) {
case 'TypeMismatchError':
throw (0, util_1.createError)('ENOTDIR', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
}
}
}
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
}
}
throw error;
}
}
getFileByFd(fd, funcName) {
if (!(0, util_1.isFd)(fd))
throw TypeError(constants_1.ERRSTR.FD);
const file = this.fds.get(fd);
if (!file)
throw (0, util_1.createError)('EBADF', funcName);
return file;
}
async getFileByFdAsync(fd, funcName) {
return this.getFileByFd(fd, funcName);
}
async __getFileById(id, funcName) {
if (typeof id === 'number')
return (await this.getFileByFd(id, funcName)).file;
const filename = (0, util_1.pathToFilename)(id);
const [folder, name] = (0, util_2.pathToLocation)(filename);
return await this.getFile(folder, name, funcName);
}
async getFileByIdOrCreate(id, funcName) {
if (typeof id === 'number')
return (await this.getFileByFd(id, funcName)).file;
const filename = (0, util_1.pathToFilename)(id);
const [folder, name] = (0, util_2.pathToLocation)(filename);
const dir = await this.getDir(folder, false, funcName);
return await dir.getFileHandle(name, { create: true });
}
async __open(filename, flags, mode) {
const [folder, name] = (0, util_2.pathToLocation)(filename);
const throwIfExists = !!(flags & 128 /* FLAG.O_EXCL */);
if (throwIfExists) {
try {
await this.getFile(folder, name, 'open', false);
throw util.createError('EEXIST', 'writeFile');
}
catch (error) {
const file404 = error && typeof error === 'object' && (error.code === 'ENOENT' || error.name === 'NotFoundError');
if (!file404) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
throw (0, util_1.createError)('ENOTDIR', 'open', filename);
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', 'open', filename);
}
}
throw error;
}
}
}
try {
const createIfMissing = !!(flags & 64 /* FLAG.O_CREAT */);
const fsaFile = await this.getFile(folder, name, 'open', createIfMissing);
return this.__open2(fsaFile, filename, flags, mode);
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
throw (0, util_1.createError)('ENOTDIR', 'open', filename);
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', 'open', filename);
}
}
throw error;
}
}
__open2(fsaFile, filename, flags, mode) {
const fd = this.newFdNumber();
const file = new FsaNodeFsOpenFile_1.FsaNodeFsOpenFile(fd, mode, flags, fsaFile, filename);
this.fds.set(fd, file);
return file;
}
async __close(fd) {
const openFile = await this.getFileByFdAsync(fd, 'close');
await openFile.close();
const deleted = this.fds.delete(fd);
if (deleted)
this.releasedFds.push(fd);
}
getFileName(id) {
if (typeof id === 'number') {
const openFile = this.fds.get(id);
if (!openFile)
throw (0, util_1.createError)('EBADF', 'readFile');
return openFile.filename;
}
return (0, util_1.pathToFilename)(id);
}
}
exports.FsaNodeCore = FsaNodeCore;
FsaNodeCore.fd = 0x7fffffff;
//# sourceMappingURL=FsaNodeCore.js.map
File diff suppressed because one or more lines are too long
+13
View File
@@ -0,0 +1,13 @@
import type { IDirent, TDataOut } from '../node/types/misc';
export declare class FsaNodeDirent implements IDirent {
readonly name: TDataOut;
protected readonly kind: 'file' | 'directory';
constructor(name: TDataOut, kind: 'file' | 'directory');
isDirectory(): boolean;
isFile(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
}
+32
View File
@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeDirent = void 0;
class FsaNodeDirent {
constructor(name, kind) {
this.name = name;
this.kind = kind;
}
isDirectory() {
return this.kind === 'directory';
}
isFile() {
return this.kind === 'file';
}
isBlockDevice() {
return false;
}
isCharacterDevice() {
return false;
}
isSymbolicLink() {
return false;
}
isFIFO() {
return false;
}
isSocket() {
return false;
}
}
exports.FsaNodeDirent = FsaNodeDirent;
//# sourceMappingURL=FsaNodeDirent.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeDirent.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeDirent.ts"],"names":[],"mappings":";;;AAEA,MAAa,aAAa;IACxB,YACkB,IAAc,EACX,IAA0B;QAD7B,SAAI,GAAJ,IAAI,CAAU;QACX,SAAI,GAAJ,IAAI,CAAsB;IAC5C,CAAC;IAEG,WAAW;QAChB,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC;IACnC,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;IAC9B,CAAC;IAEM,aAAa;QAClB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,iBAAiB;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,cAAc;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,MAAM;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,QAAQ;QACb,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAjCD,sCAiCC"}
+184
View File
@@ -0,0 +1,184 @@
import { FsaNodeDirent } from './FsaNodeDirent';
import { FsaNodeStats } from './FsaNodeStats';
import { FsSynchronousApi } from '../node/types/FsSynchronousApi';
import { FsaNodeWriteStream } from './FsaNodeWriteStream';
import { FsaNodeReadStream } from './FsaNodeReadStream';
import { FsaNodeCore } from './FsaNodeCore';
import type { FsCallbackApi, FsPromisesApi } from '../node/types';
import type { FsCommonObjects } from '../node/types/FsCommonObjects';
/**
* Constructs a Node.js `fs` API from a File System Access API
* [`FileSystemDirectoryHandle` object](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle).
*/
export declare class FsaNodeFs extends FsaNodeCore implements FsCallbackApi, FsSynchronousApi, FsCommonObjects {
readonly promises: FsPromisesApi;
readonly open: FsCallbackApi['open'];
readonly close: FsCallbackApi['close'];
readonly read: FsCallbackApi['read'];
readonly readFile: FsCallbackApi['readFile'];
readonly write: FsCallbackApi['write'];
readonly writev: FsCallbackApi['writev'];
readonly writeFile: FsCallbackApi['writeFile'];
readonly copyFile: FsCallbackApi['copyFile'];
/**
* @todo There is a proposal for native "self remove" operation.
* @see https://github.com/whatwg/fs/blob/main/proposals/Remove.md
*/
readonly unlink: FsCallbackApi['unlink'];
readonly realpath: FsCallbackApi['realpath'];
readonly stat: FsCallbackApi['stat'];
readonly lstat: FsCallbackApi['lstat'];
readonly fstat: FsCallbackApi['fstat'];
private getHandleStats;
/**
* @todo There is a proposal for native move support.
* @see https://github.com/whatwg/fs/blob/main/proposals/MovingNonOpfsFiles.md
*/
readonly rename: FsCallbackApi['rename'];
readonly exists: FsCallbackApi['exists'];
readonly access: FsCallbackApi['access'];
readonly appendFile: FsCallbackApi['appendFile'];
readonly readdir: FsCallbackApi['readdir'];
readonly readlink: FsCallbackApi['readlink'];
/** @todo Could this use `FileSystemSyncAccessHandle.flush` through a Worker thread? */
readonly fsync: FsCallbackApi['fsync'];
readonly fdatasync: FsCallbackApi['fdatasync'];
readonly ftruncate: FsCallbackApi['ftruncate'];
readonly truncate: FsCallbackApi['truncate'];
readonly futimes: FsCallbackApi['futimes'];
readonly utimes: FsCallbackApi['utimes'];
readonly mkdir: FsCallbackApi['mkdir'];
readonly mkdtemp: FsCallbackApi['mkdtemp'];
private rmAll;
readonly rmdir: FsCallbackApi['rmdir'];
readonly rm: FsCallbackApi['rm'];
readonly fchmod: FsCallbackApi['fchmod'];
readonly chmod: FsCallbackApi['chmod'];
readonly lchmod: FsCallbackApi['lchmod'];
readonly fchown: FsCallbackApi['fchown'];
readonly chown: FsCallbackApi['chown'];
readonly lchown: FsCallbackApi['lchown'];
readonly createWriteStream: FsCallbackApi['createWriteStream'];
readonly createReadStream: FsCallbackApi['createReadStream'];
readonly cp: FsCallbackApi['cp'];
readonly lutimes: FsCallbackApi['lutimes'];
readonly openAsBlob: FsCallbackApi['openAsBlob'];
readonly opendir: FsCallbackApi['opendir'];
readonly readv: FsCallbackApi['readv'];
readonly statfs: FsCallbackApi['statfs'];
/**
* @todo Watchers could be implemented in the future on top of `FileSystemObserver`,
* which is currently a proposal.
* @see https://github.com/whatwg/fs/blob/main/proposals/FileSystemObserver.md
*/
readonly watchFile: FsCallbackApi['watchFile'];
readonly unwatchFile: FsCallbackApi['unwatchFile'];
readonly watch: FsCallbackApi['watch'];
readonly symlink: FsCallbackApi['symlink'];
readonly link: FsCallbackApi['link'];
readonly statSync: FsSynchronousApi['statSync'];
readonly lstatSync: FsSynchronousApi['lstatSync'];
readonly fstatSync: FsSynchronousApi['fstatSync'];
readonly accessSync: FsSynchronousApi['accessSync'];
readonly readFileSync: FsSynchronousApi['readFileSync'];
readonly writeFileSync: FsSynchronousApi['writeFileSync'];
readonly appendFileSync: FsSynchronousApi['appendFileSync'];
readonly closeSync: FsSynchronousApi['closeSync'];
readonly existsSync: FsSynchronousApi['existsSync'];
readonly copyFileSync: FsSynchronousApi['copyFileSync'];
readonly renameSync: FsSynchronousApi['renameSync'];
readonly rmdirSync: FsSynchronousApi['rmdirSync'];
readonly rmSync: FsSynchronousApi['rmSync'];
readonly mkdirSync: FsSynchronousApi['mkdirSync'];
readonly mkdtempSync: FsSynchronousApi['mkdtempSync'];
readonly readlinkSync: FsSynchronousApi['readlinkSync'];
readonly truncateSync: FsSynchronousApi['truncateSync'];
readonly ftruncateSync: FsSynchronousApi['ftruncateSync'];
readonly unlinkSync: FsSynchronousApi['unlinkSync'];
readonly readdirSync: FsSynchronousApi['readdirSync'];
readonly realpathSync: FsSynchronousApi['realpathSync'];
readonly readSync: FsSynchronousApi['readSync'];
readonly writeSync: FsSynchronousApi['writeSync'];
readonly openSync: FsSynchronousApi['openSync'];
readonly writevSync: FsSynchronousApi['writevSync'];
readonly fdatasyncSync: FsSynchronousApi['fdatasyncSync'];
readonly fsyncSync: FsSynchronousApi['fsyncSync'];
readonly chmodSync: FsSynchronousApi['chmodSync'];
readonly chownSync: FsSynchronousApi['chownSync'];
readonly fchmodSync: FsSynchronousApi['fchmodSync'];
readonly fchownSync: FsSynchronousApi['fchownSync'];
readonly futimesSync: FsSynchronousApi['futimesSync'];
readonly lchmodSync: FsSynchronousApi['lchmodSync'];
readonly lchownSync: FsSynchronousApi['lchownSync'];
readonly utimesSync: FsSynchronousApi['utimesSync'];
readonly lutimesSync: FsSynchronousApi['lutimesSync'];
readonly cpSync: FsSynchronousApi['cpSync'];
readonly opendirSync: FsSynchronousApi['opendirSync'];
readonly statfsSync: FsSynchronousApi['statfsSync'];
readonly readvSync: FsSynchronousApi['readvSync'];
readonly symlinkSync: FsSynchronousApi['symlinkSync'];
readonly linkSync: FsSynchronousApi['linkSync'];
readonly F_OK: number;
readonly R_OK: number;
readonly W_OK: number;
readonly X_OK: number;
readonly constants: {
O_RDONLY: number;
O_WRONLY: number;
O_RDWR: number;
S_IFMT: number;
S_IFREG: number;
S_IFDIR: number;
S_IFCHR: number;
S_IFBLK: number;
S_IFIFO: number;
S_IFLNK: number;
S_IFSOCK: number;
O_CREAT: number;
O_EXCL: number;
O_NOCTTY: number;
O_TRUNC: number;
O_APPEND: number;
O_DIRECTORY: number;
O_NOATIME: number;
O_NOFOLLOW: number;
O_SYNC: number;
O_SYMLINK: number;
O_DIRECT: number;
O_NONBLOCK: number;
S_IRWXU: number;
S_IRUSR: number;
S_IWUSR: number;
S_IXUSR: number;
S_IRWXG: number;
S_IRGRP: number;
S_IWGRP: number;
S_IXGRP: number;
S_IRWXO: number;
S_IROTH: number;
S_IWOTH: number;
S_IXOTH: number;
F_OK: number;
R_OK: number;
W_OK: number;
X_OK: number;
UV_FS_SYMLINK_DIR: number;
UV_FS_SYMLINK_JUNCTION: number;
UV_FS_COPYFILE_EXCL: number;
UV_FS_COPYFILE_FICLONE: number;
UV_FS_COPYFILE_FICLONE_FORCE: number;
COPYFILE_EXCL: number;
COPYFILE_FICLONE: number;
COPYFILE_FICLONE_FORCE: number;
};
readonly Dirent: typeof FsaNodeDirent;
readonly Stats: {
new (isBigInt: boolean, size: any, kind: "file" | "directory"): FsaNodeStats<any>;
};
readonly WriteStream: typeof FsaNodeWriteStream;
readonly ReadStream: typeof FsaNodeReadStream;
readonly StatFs: any;
readonly Dir: any;
readonly StatsWatcher: any;
readonly FSWatcher: any;
}
+856
View File
@@ -0,0 +1,856 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeFs = void 0;
const tslib_1 = require("tslib");
const optHelpers = require("../node/options");
const util = require("../node/util");
const buffer_1 = require("../internal/buffer");
const FsPromises_1 = require("../node/FsPromises");
const util_1 = require("./util");
const constants_1 = require("../node/constants");
const encoding_1 = require("../encoding");
const FsaNodeDirent_1 = require("./FsaNodeDirent");
const constants_2 = require("../constants");
const FsaNodeStats_1 = require("./FsaNodeStats");
const queueMicrotask_1 = require("../queueMicrotask");
const FsaNodeWriteStream_1 = require("./FsaNodeWriteStream");
const FsaNodeReadStream_1 = require("./FsaNodeReadStream");
const FsaNodeCore_1 = require("./FsaNodeCore");
const FileHandle_1 = require("../node/FileHandle");
const notSupported = () => {
throw new Error('Method not supported by the File System Access API.');
};
const notImplemented = () => {
throw new Error('Not implemented');
};
const noop = () => { };
/**
* Constructs a Node.js `fs` API from a File System Access API
* [`FileSystemDirectoryHandle` object](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle).
*/
class FsaNodeFs extends FsaNodeCore_1.FsaNodeCore {
constructor() {
// ------------------------------------------------------------ FsPromisesApi
super(...arguments);
this.promises = new FsPromises_1.FsPromises(this, FileHandle_1.FileHandle);
// ------------------------------------------------------------ FsCallbackApi
this.open = (path, flags, a, b) => {
let mode = a;
let callback = b;
if (typeof a === 'function') {
mode = 438 /* MODE.DEFAULT */;
callback = a;
}
mode = mode || 438 /* MODE.DEFAULT */;
const modeNum = util.modeToNumber(mode);
const filename = util.pathToFilename(path);
const flagsNum = util.flagsToNumber(flags);
this.__open(filename, flagsNum, modeNum).then(openFile => callback(null, openFile.fd), error => callback(error));
};
this.close = (fd, callback) => {
util.validateFd(fd);
this.__close(fd).then(() => callback(null), error => callback(error));
};
this.read = (fd, buffer, offset, length, position, callback) => {
util.validateCallback(callback);
// This `if` branch is from Node.js
if (length === 0) {
return (0, queueMicrotask_1.default)(() => {
if (callback)
callback(null, 0, buffer);
});
}
(async () => {
const openFile = await this.getFileByFd(fd, 'read');
const file = await openFile.file.getFile();
const src = await file.arrayBuffer();
const slice = new Uint8Array(src, Number(position), Number(length));
const dest = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, slice.length);
dest.set(slice, 0);
return slice.length;
})().then(bytesWritten => callback(null, bytesWritten, buffer), error => callback(error));
};
this.readFile = (id, a, b) => {
const [opts, callback] = optHelpers.optsAndCbGenerator(optHelpers.getReadFileOptions)(a, b);
const flagsNum = util.flagsToNumber(opts.flag);
(async () => {
let fd = typeof id === 'number' ? id : -1;
const originalFd = fd;
try {
if (fd === -1) {
const filename = util.pathToFilename(id);
fd = (await this.__open(filename, flagsNum, 0)).fd;
}
const handle = await this.__getFileById(fd, 'readFile');
const file = await handle.getFile();
const buffer = buffer_1.Buffer.from(await file.arrayBuffer());
return util.bufferToEncoding(buffer, opts.encoding);
}
finally {
try {
const idWasFd = typeof originalFd === 'number' && originalFd >= 0;
if (idWasFd)
await this.__close(originalFd);
}
catch (_a) { }
}
})()
.then(data => callback(null, data))
.catch(error => callback(error));
};
this.write = (fd, a, b, c, d, e) => {
const [, asStr, buf, offset, length, position, cb] = util.getWriteArgs(fd, a, b, c, d, e);
(async () => {
const openFile = await this.getFileByFd(fd, 'write');
const data = buf.subarray(offset, offset + length);
await openFile.write(data, position);
return length;
})().then(bytesWritten => cb(null, bytesWritten, asStr ? a : buf), error => cb(error));
};
this.writev = (fd, buffers, a, b) => {
util.validateFd(fd);
let position = null;
let callback;
if (typeof a === 'function') {
callback = a;
}
else {
position = Number(a);
callback = b;
}
util.validateCallback(callback);
(async () => {
const openFile = await this.getFileByFd(fd, 'writev');
const length = buffers.length;
let bytesWritten = 0;
for (let i = 0; i < length; i++) {
const data = buffers[i];
await openFile.write(data, position);
bytesWritten += data.byteLength;
position = null;
}
return bytesWritten;
})().then(bytesWritten => callback(null, bytesWritten, buffers), error => callback(error));
};
this.writeFile = (id, data, a, b) => {
let options = a;
let callback = b;
if (typeof a === 'function') {
options = optHelpers.writeFileDefaults;
callback = a;
}
const cb = util.validateCallback(callback);
const opts = optHelpers.getWriteFileOptions(options);
const flagsNum = util.flagsToNumber(opts.flag);
const modeNum = util.modeToNumber(opts.mode);
const buf = util.dataToBuffer(data, opts.encoding);
(async () => {
let fd = typeof id === 'number' ? id : -1;
const originalFd = fd;
try {
if (fd === -1) {
const filename = util.pathToFilename(id);
fd = (await this.__open(filename, flagsNum, modeNum)).fd;
}
const file = await this.__getFileById(fd, 'writeFile');
const writable = await file.createWritable({ keepExistingData: false });
await writable.write(buf);
await writable.close();
}
finally {
try {
const idWasFd = typeof originalFd === 'number' && originalFd >= 0;
if (idWasFd)
await this.__close(originalFd);
}
catch (_a) { }
}
})().then(() => cb(null), error => cb(error));
};
this.copyFile = (src, dest, a, b) => {
const srcFilename = util.pathToFilename(src);
const destFilename = util.pathToFilename(dest);
let flags;
let callback;
if (typeof a === 'function') {
flags = 0;
callback = a;
}
else {
flags = a;
callback = b;
}
util.validateCallback(callback);
const [oldFolder, oldName] = (0, util_1.pathToLocation)(srcFilename);
const [newFolder, newName] = (0, util_1.pathToLocation)(destFilename);
(async () => {
const oldFile = await this.getFile(oldFolder, oldName, 'copyFile');
const newDir = await this.getDir(newFolder, false, 'copyFile');
const newFile = await newDir.getFileHandle(newName, { create: true });
const writable = await newFile.createWritable({ keepExistingData: false });
const oldData = await oldFile.getFile();
await writable.write(await oldData.arrayBuffer());
await writable.close();
})().then(() => callback(null), error => callback(error));
};
/**
* @todo There is a proposal for native "self remove" operation.
* @see https://github.com/whatwg/fs/blob/main/proposals/Remove.md
*/
this.unlink = (path, callback) => {
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
this.getDir(folder, false, 'unlink')
.then(dir => dir.removeEntry(name))
.then(() => callback(null), error => {
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
callback(util.createError('ENOENT', 'unlink', filename));
return;
}
case 'InvalidModificationError': {
callback(util.createError('EISDIR', 'unlink', filename));
return;
}
}
}
callback(error);
});
};
this.realpath = (path, a, b) => {
const [opts, callback] = optHelpers.getRealpathOptsAndCb(a, b);
let pathFilename = util.pathToFilename(path);
if (pathFilename[0] !== "/" /* FsaToNodeConstants.Separator */)
pathFilename = "/" /* FsaToNodeConstants.Separator */ + pathFilename;
callback(null, (0, encoding_1.strToEncoding)(pathFilename, opts.encoding));
};
this.stat = (path, a, b) => {
const [{ bigint = false, throwIfNoEntry = true }, callback] = optHelpers.getStatOptsAndCb(a, b);
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
(async () => {
const handle = await this.getFileOrDir(folder, name, 'stat');
return await this.getHandleStats(bigint, handle);
})().then(stats => callback(null, stats), error => callback(error));
};
this.lstat = this.stat;
this.fstat = (fd, a, b) => {
const [{ bigint = false, throwIfNoEntry = true }, callback] = optHelpers.getStatOptsAndCb(a, b);
(async () => {
const openFile = await this.getFileByFd(fd, 'fstat');
return await this.getHandleStats(bigint, openFile.file);
})().then(stats => callback(null, stats), error => callback(error));
};
/**
* @todo There is a proposal for native move support.
* @see https://github.com/whatwg/fs/blob/main/proposals/MovingNonOpfsFiles.md
*/
this.rename = (oldPath, newPath, callback) => {
const oldPathFilename = util.pathToFilename(oldPath);
const newPathFilename = util.pathToFilename(newPath);
const [oldFolder, oldName] = (0, util_1.pathToLocation)(oldPathFilename);
const [newFolder, newName] = (0, util_1.pathToLocation)(newPathFilename);
(async () => {
const oldFile = await this.getFile(oldFolder, oldName, 'rename');
const newDir = await this.getDir(newFolder, false, 'rename');
const newFile = await newDir.getFileHandle(newName, { create: true });
const writable = await newFile.createWritable({ keepExistingData: false });
const oldData = await oldFile.getFile();
await writable.write(await oldData.arrayBuffer());
await writable.close();
const oldDir = await this.getDir(oldFolder, false, 'rename');
await oldDir.removeEntry(oldName);
})().then(() => callback(null), error => callback(error));
};
this.exists = (path, callback) => {
const filename = util.pathToFilename(path);
if (typeof callback !== 'function')
throw Error(constants_1.ERRSTR.CB);
this.access(path, 0 /* AMODE.F_OK */, error => callback(!error));
};
this.access = (path, a, b) => {
let mode = 0 /* AMODE.F_OK */;
let callback;
if (typeof a !== 'function') {
mode = a | 0; // cast to number
callback = util.validateCallback(b);
}
else {
callback = a;
}
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
(async () => {
const node = folder.length || name ? await this.getFileOrDir(folder, name, 'access') : await this.root;
const checkIfCanExecute = mode & 1 /* AMODE.X_OK */;
if (checkIfCanExecute)
throw util.createError('EACCESS', 'access', filename);
const checkIfCanWrite = mode & 2 /* AMODE.W_OK */;
switch (node.kind) {
case 'file': {
if (checkIfCanWrite) {
try {
const file = node;
const writable = await file.createWritable();
await writable.close();
}
catch (_a) {
throw util.createError('EACCESS', 'access', filename);
}
}
break;
}
case 'directory': {
if (checkIfCanWrite) {
const dir = node;
const canWrite = await (0, util_1.testDirectoryIsWritable)(dir);
if (!canWrite)
throw util.createError('EACCESS', 'access', filename);
}
break;
}
default: {
throw util.createError('EACCESS', 'access', filename);
}
}
})().then(() => callback(null), error => callback(error));
};
this.appendFile = (id, data, a, b) => {
const [opts, callback] = optHelpers.getAppendFileOptsAndCb(a, b);
const buffer = util.dataToBuffer(data, opts.encoding);
this.getFileByIdOrCreate(id, 'appendFile')
.then(file => (async () => {
const blob = await file.getFile();
const writable = await file.createWritable({ keepExistingData: true });
await writable.write({
type: 'write',
data: buffer,
position: blob.size,
});
await writable.close();
})())
.then(() => callback(null), error => callback(error));
};
this.readdir = (path, a, b) => {
const [options, callback] = optHelpers.getReaddirOptsAndCb(a, b);
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
if (name)
folder.push(name);
this.getDir(folder, false, 'readdir')
.then(dir => (async () => {
var _a, e_1, _b, _c, _d, e_2, _e, _f;
if (options.withFileTypes) {
const list = [];
try {
for (var _g = true, _h = tslib_1.__asyncValues(dir.entries()), _j; _j = await _h.next(), _a = _j.done, !_a; _g = true) {
_c = _j.value;
_g = false;
const [name, handle] = _c;
const dirent = new FsaNodeDirent_1.FsaNodeDirent(name, handle.kind);
list.push(dirent);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_g && !_a && (_b = _h.return)) await _b.call(_h);
}
finally { if (e_1) throw e_1.error; }
}
if (!util.isWin && options.encoding !== 'buffer')
list.sort((a, b) => {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
});
return list;
}
else {
const list = [];
try {
for (var _k = true, _l = tslib_1.__asyncValues(dir.keys()), _m; _m = await _l.next(), _d = _m.done, !_d; _k = true) {
_f = _m.value;
_k = false;
const key = _f;
list.push(key);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (!_k && !_d && (_e = _l.return)) await _e.call(_l);
}
finally { if (e_2) throw e_2.error; }
}
if (!util.isWin && options.encoding !== 'buffer')
list.sort();
return list;
}
})())
.then(res => callback(null, res), err => callback(err));
};
this.readlink = (path, a, b) => {
const [opts, callback] = optHelpers.getDefaultOptsAndCb(a, b);
const filename = util.pathToFilename(path);
const buffer = buffer_1.Buffer.from(filename);
callback(null, util.bufferToEncoding(buffer, opts.encoding));
};
/** @todo Could this use `FileSystemSyncAccessHandle.flush` through a Worker thread? */
this.fsync = (fd, callback) => {
callback(null);
};
this.fdatasync = (fd, callback) => {
callback(null);
};
this.ftruncate = (fd, a, b) => {
const len = typeof a === 'number' ? a : 0;
const callback = util.validateCallback(typeof a === 'number' ? b : a);
this.getFileByFdAsync(fd)
.then(file => file.file.createWritable({ keepExistingData: true }))
.then(writable => writable.truncate(len).then(() => writable.close()))
.then(() => callback(null), error => callback(error));
};
this.truncate = (path, a, b) => {
const len = typeof a === 'number' ? a : 0;
const callback = util.validateCallback(typeof a === 'number' ? b : a);
this.open(path, 'r+', (error, fd) => {
if (error)
callback(error);
else {
this.ftruncate(fd, len, error => {
if (error)
this.close(fd, () => callback(error));
else
this.close(fd, callback);
});
}
});
};
this.futimes = (fd, atime, mtime, callback) => {
callback(null);
};
this.utimes = (path, atime, mtime, callback) => {
callback(null);
};
this.mkdir = (path, a, b) => {
var _a;
const opts = optHelpers.getMkdirOptions(a);
const callback = util.validateCallback(typeof a === 'function' ? a : b);
// const modeNum = modeToNumber(opts.mode, 0o777);
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
// TODO: need to throw if directory already exists
this.getDir(folder, (_a = opts.recursive) !== null && _a !== void 0 ? _a : false)
.then(dir => dir.getDirectoryHandle(name, { create: true }))
.then(() => callback(null), error => {
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
const err = util.createError('ENOENT', 'mkdir', folder.join('/'));
callback(err);
return;
}
}
}
callback(error);
});
};
this.mkdtemp = (prefix, a, b) => {
const [{ encoding }, callback] = optHelpers.getDefaultOptsAndCb(a, b);
if (!prefix || typeof prefix !== 'string')
throw new TypeError('filename prefix is required');
if (!util.nullCheck(prefix))
return;
const filename = prefix + util.genRndStr6();
this.mkdir(filename, 511 /* MODE.DIR */, err => {
if (err)
callback(err);
else
callback(null, (0, encoding_1.strToEncoding)(filename, encoding));
});
};
this.rmdir = (path, a, b) => {
const options = optHelpers.getRmdirOptions(a);
const callback = util.validateCallback(typeof a === 'function' ? a : b);
const [folder, name] = (0, util_1.pathToLocation)(util.pathToFilename(path));
if (!name && options.recursive)
return this.rmAll(callback);
this.getDir(folder, false, 'rmdir')
.then(dir => dir.getDirectoryHandle(name).then(() => dir))
.then(dir => { var _a; return dir.removeEntry(name, { recursive: (_a = options.recursive) !== null && _a !== void 0 ? _a : false }); })
.then(() => callback(null), error => {
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
const err = util.createError('ENOENT', 'rmdir', folder.join('/'));
callback(err);
return;
}
case 'InvalidModificationError': {
const err = util.createError('ENOTEMPTY', 'rmdir', folder.join('/'));
callback(err);
return;
}
}
}
callback(error);
});
};
this.rm = (path, a, b) => {
const [options, callback] = optHelpers.getRmOptsAndCb(a, b);
const [folder, name] = (0, util_1.pathToLocation)(util.pathToFilename(path));
if (!name && options.recursive)
return this.rmAll(callback);
this.getDir(folder, false, 'rmdir')
.then(dir => { var _a; return dir.removeEntry(name, { recursive: (_a = options.recursive) !== null && _a !== void 0 ? _a : false }); })
.then(() => callback(null), error => {
if (options.force) {
callback(null);
return;
}
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
const err = util.createError('ENOENT', 'rmdir', folder.join('/'));
callback(err);
return;
}
case 'InvalidModificationError': {
const err = util.createError('ENOTEMPTY', 'rmdir', folder.join('/'));
callback(err);
return;
}
}
}
callback(error);
});
};
this.fchmod = (fd, mode, callback) => {
callback(null);
};
this.chmod = (path, mode, callback) => {
callback(null);
};
this.lchmod = (path, mode, callback) => {
callback(null);
};
this.fchown = (fd, uid, gid, callback) => {
callback(null);
};
this.chown = (path, uid, gid, callback) => {
callback(null);
};
this.lchown = (path, uid, gid, callback) => {
callback(null);
};
this.createWriteStream = (path, options) => {
var _a;
const defaults = {
encoding: 'utf8',
flags: 'w',
autoClose: true,
emitClose: true,
};
const optionsObj = optHelpers.getOptions(defaults, options);
const filename = util.pathToFilename(path);
const flags = util.flagsToNumber((_a = optionsObj.flags) !== null && _a !== void 0 ? _a : 'w');
const fd = optionsObj.fd ? (typeof optionsObj.fd === 'number' ? optionsObj.fd : optionsObj.fd.fd) : 0;
const handle = fd ? this.getFileByFdAsync(fd) : this.__open(filename, flags, 0);
const stream = new FsaNodeWriteStream_1.FsaNodeWriteStream(handle, filename, optionsObj);
if (optionsObj.autoClose) {
stream.once('finish', () => {
handle.then(file => this.close(file.fd, () => { }));
});
stream.once('error', () => {
handle.then(file => this.close(file.fd, () => { }));
});
}
return stream;
};
this.createReadStream = (path, options) => {
const defaults = {
flags: 'r',
fd: null,
mode: 0o666,
autoClose: true,
emitClose: true,
start: 0,
end: Infinity,
highWaterMark: 64 * 1024,
fs: null,
signal: null,
};
const optionsObj = optHelpers.getOptions(defaults, options);
const filename = util.pathToFilename(path);
const flags = util.flagsToNumber(optionsObj.flags);
const fd = optionsObj.fd ? (typeof optionsObj.fd === 'number' ? optionsObj.fd : optionsObj.fd.fd) : 0;
const handle = fd ? this.getFileByFdAsync(fd) : this.__open(filename, flags, 0);
const stream = new FsaNodeReadStream_1.FsaNodeReadStream(this, handle, filename, optionsObj);
return stream;
};
this.cp = notImplemented;
this.lutimes = notImplemented;
this.openAsBlob = notImplemented;
this.opendir = notImplemented;
this.readv = notImplemented;
this.statfs = notImplemented;
/**
* @todo Watchers could be implemented in the future on top of `FileSystemObserver`,
* which is currently a proposal.
* @see https://github.com/whatwg/fs/blob/main/proposals/FileSystemObserver.md
*/
this.watchFile = notSupported;
this.unwatchFile = notSupported;
this.watch = notSupported;
this.symlink = notSupported;
this.link = notSupported;
// --------------------------------------------------------- FsSynchronousApi
this.statSync = (path, options) => {
var _a;
const { bigint = true, throwIfNoEntry = true } = optHelpers.getStatOptions(options);
const filename = util.pathToFilename(path);
const location = (0, util_1.pathToLocation)(filename);
const adapter = this.getSyncAdapter();
const res = adapter.call('stat', location);
const stats = new FsaNodeStats_1.FsaNodeStats(bigint, (_a = res.size) !== null && _a !== void 0 ? _a : 0, res.kind);
return stats;
};
this.lstatSync = this.statSync;
this.fstatSync = (fd, options) => {
const filename = this.getFileName(fd);
return this.statSync(filename, options);
};
this.accessSync = (path, mode = 0 /* AMODE.F_OK */) => {
const filename = util.pathToFilename(path);
mode = mode | 0;
const adapter = this.getSyncAdapter();
adapter.call('access', [filename, mode]);
};
this.readFileSync = (id, options) => {
const opts = optHelpers.getReadFileOptions(options);
const flagsNum = util.flagsToNumber(opts.flag);
const filename = this.getFileName(id);
const adapter = this.getSyncAdapter();
const uint8 = adapter.call('readFile', [filename, opts]);
const buffer = buffer_1.Buffer.from(uint8.buffer, uint8.byteOffset, uint8.byteLength);
return util.bufferToEncoding(buffer, opts.encoding);
};
this.writeFileSync = (id, data, options) => {
const opts = optHelpers.getWriteFileOptions(options);
const flagsNum = util.flagsToNumber(opts.flag);
const modeNum = util.modeToNumber(opts.mode);
const buf = util.dataToBuffer(data, opts.encoding);
const filename = this.getFileName(id);
const adapter = this.getSyncAdapter();
adapter.call('writeFile', [filename, util.bufToUint8(buf), opts]);
};
this.appendFileSync = (id, data, options) => {
const opts = optHelpers.getAppendFileOpts(options);
if (!opts.flag || util.isFd(id))
opts.flag = 'a';
const filename = this.getFileName(id);
const buf = util.dataToBuffer(data, opts.encoding);
const adapter = this.getSyncAdapter();
adapter.call('appendFile', [filename, util.bufToUint8(buf), opts]);
};
this.closeSync = (fd) => {
util.validateFd(fd);
const file = this.getFileByFd(fd, 'close');
file.close().catch(() => { });
this.fds.delete(fd);
this.releasedFds.push(fd);
};
this.existsSync = (path) => {
try {
this.statSync(path);
return true;
}
catch (_a) {
return false;
}
};
this.copyFileSync = (src, dest, flags) => {
const srcFilename = util.pathToFilename(src);
const destFilename = util.pathToFilename(dest);
const adapter = this.getSyncAdapter();
adapter.call('copy', [srcFilename, destFilename, flags]);
};
this.renameSync = (oldPath, newPath) => {
const srcFilename = util.pathToFilename(oldPath);
const destFilename = util.pathToFilename(newPath);
const adapter = this.getSyncAdapter();
adapter.call('move', [srcFilename, destFilename]);
};
this.rmdirSync = (path, opts) => {
const filename = util.pathToFilename(path);
const adapter = this.getSyncAdapter();
adapter.call('rmdir', [filename, opts]);
};
this.rmSync = (path, options) => {
const filename = util.pathToFilename(path);
const adapter = this.getSyncAdapter();
adapter.call('rm', [filename, options]);
};
this.mkdirSync = (path, options) => {
const opts = optHelpers.getMkdirOptions(options);
const modeNum = util.modeToNumber(opts.mode, 0o777);
const filename = util.pathToFilename(path);
return this.getSyncAdapter().call('mkdir', [filename, options]);
};
this.mkdtempSync = (prefix, options) => {
const { encoding } = optHelpers.getDefaultOpts(options);
if (!prefix || typeof prefix !== 'string')
throw new TypeError('filename prefix is required');
util.nullCheck(prefix);
const result = this.getSyncAdapter().call('mkdtemp', [prefix, options]);
return (0, encoding_1.strToEncoding)(result, encoding);
};
this.readlinkSync = (path, options) => {
const opts = optHelpers.getDefaultOpts(options);
const filename = util.pathToFilename(path);
const buffer = buffer_1.Buffer.from(filename);
return util.bufferToEncoding(buffer, opts.encoding);
};
this.truncateSync = (id, len) => {
if (util.isFd(id))
return this.ftruncateSync(id, len);
const filename = util.pathToFilename(id);
this.getSyncAdapter().call('trunc', [filename, Number(len) || 0]);
};
this.ftruncateSync = (fd, len) => {
const filename = this.getFileName(fd);
this.truncateSync(filename, len);
};
this.unlinkSync = (path) => {
const filename = util.pathToFilename(path);
this.getSyncAdapter().call('unlink', [filename]);
};
this.readdirSync = (path, options) => {
const opts = optHelpers.getReaddirOptions(options);
const filename = util.pathToFilename(path);
const adapter = this.getSyncAdapter();
const list = adapter.call('readdir', [filename]);
if (opts.withFileTypes) {
const res = [];
for (const entry of list)
res.push(new FsaNodeDirent_1.FsaNodeDirent(entry.name, entry.kind));
return res;
}
else {
const res = [];
for (const entry of list) {
const buffer = buffer_1.Buffer.from(entry.name);
res.push(util.bufferToEncoding(buffer, opts.encoding));
}
return res;
}
};
this.realpathSync = (path, options) => {
let filename = util.pathToFilename(path);
const { encoding } = optHelpers.getRealpathOptions(options);
if (filename[0] !== "/" /* FsaToNodeConstants.Separator */)
filename = "/" /* FsaToNodeConstants.Separator */ + filename;
return (0, encoding_1.strToEncoding)(filename, encoding);
};
this.readSync = (fd, buffer, offset, length, position) => {
util.validateFd(fd);
const filename = this.getFileName(fd);
const adapter = this.getSyncAdapter();
const uint8 = adapter.call('read', [filename, position, length]);
const dest = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
dest.set(uint8, offset);
return uint8.length;
};
this.writeSync = (fd, a, b, c, d) => {
const [, buf, offset, length, position] = util.getWriteSyncArgs(fd, a, b, c, d);
const filename = this.getFileName(fd);
const data = new Uint8Array(buf.buffer, buf.byteOffset + offset, length);
return this.getSyncAdapter().call('write', [filename, data, position || null]);
};
this.openSync = (path, flags, mode = 438 /* MODE.DEFAULT */) => {
const modeNum = util.modeToNumber(mode);
const filename = util.pathToFilename(path);
const flagsNum = util.flagsToNumber(flags);
const adapter = this.getSyncAdapter();
const handle = adapter.call('open', [filename, flagsNum, modeNum]);
const openFile = this.__open2(handle, filename, flagsNum, modeNum);
return openFile.fd;
};
this.writevSync = (fd, buffers, position) => {
if (buffers.length === 0)
return;
this.writeSync(fd, buffers[0], 0, buffers[0].byteLength, position);
for (let i = 1; i < buffers.length; i++) {
this.writeSync(fd, buffers[i], 0, buffers[i].byteLength, null);
}
};
this.fdatasyncSync = noop;
this.fsyncSync = noop;
this.chmodSync = noop;
this.chownSync = noop;
this.fchmodSync = noop;
this.fchownSync = noop;
this.futimesSync = noop;
this.lchmodSync = noop;
this.lchownSync = noop;
this.utimesSync = noop;
this.lutimesSync = noop;
this.cpSync = notImplemented;
this.opendirSync = notImplemented;
this.statfsSync = notImplemented;
this.readvSync = notImplemented;
this.symlinkSync = notSupported;
this.linkSync = notSupported;
// ---------------------------------------------------------- FsCommonObjects
this.F_OK = constants_2.constants.F_OK;
this.R_OK = constants_2.constants.R_OK;
this.W_OK = constants_2.constants.W_OK;
this.X_OK = constants_2.constants.X_OK;
this.constants = constants_2.constants;
this.Dirent = FsaNodeDirent_1.FsaNodeDirent;
this.Stats = (FsaNodeStats_1.FsaNodeStats);
this.WriteStream = FsaNodeWriteStream_1.FsaNodeWriteStream;
this.ReadStream = FsaNodeReadStream_1.FsaNodeReadStream;
this.StatFs = 0;
this.Dir = 0;
this.StatsWatcher = 0;
this.FSWatcher = 0;
}
async getHandleStats(bigint, handle) {
let size = 0;
if (handle.kind === 'file') {
const file = handle;
const fileData = await file.getFile();
size = fileData.size;
}
const stats = new FsaNodeStats_1.FsaNodeStats(bigint, bigint ? BigInt(size) : size, handle.kind);
return stats;
}
rmAll(callback) {
(async () => {
var _a, e_3, _b, _c;
const root = await this.root;
try {
for (var _d = true, _e = tslib_1.__asyncValues(root.keys()), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
_c = _f.value;
_d = false;
const name = _c;
await root.removeEntry(name, { recursive: true });
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
}
finally { if (e_3) throw e_3.error; }
}
})().then(() => callback(null), error => callback(error));
}
}
exports.FsaNodeFs = FsaNodeFs;
//# sourceMappingURL=FsaNodeFs.js.map
File diff suppressed because one or more lines are too long
+24
View File
@@ -0,0 +1,24 @@
import type * as fsa from '../fsa/types';
import type * as misc from '../node/types/misc';
/**
* Represents an open file. Stores additional metadata about the open file, such
* as the seek position.
*/
export declare class FsaNodeFsOpenFile {
readonly fd: number;
readonly createMode: misc.TMode;
readonly flags: number;
readonly file: fsa.IFileSystemFileHandle;
readonly filename: string;
protected seek: number;
/**
* This influences the behavior of the next write operation. On the first
* write we want to overwrite the file or keep the existing data, depending
* with which flags the file was opened. On subsequent writes we want to
* append to the file.
*/
protected keepExistingData: boolean;
constructor(fd: number, createMode: misc.TMode, flags: number, file: fsa.IFileSystemFileHandle, filename: string);
close(): Promise<void>;
write(data: ArrayBufferView, seek: number | null): Promise<void>;
}
+34
View File
@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeFsOpenFile = void 0;
/**
* Represents an open file. Stores additional metadata about the open file, such
* as the seek position.
*/
class FsaNodeFsOpenFile {
constructor(fd, createMode, flags, file, filename) {
this.fd = fd;
this.createMode = createMode;
this.flags = flags;
this.file = file;
this.filename = filename;
this.seek = 0;
this.keepExistingData = !!(flags & 1024 /* FLAG.O_APPEND */);
}
async close() { }
async write(data, seek) {
if (typeof seek !== 'number')
seek = this.seek;
const writer = await this.file.createWritable({ keepExistingData: this.keepExistingData });
await writer.write({
type: 'write',
data,
position: seek,
});
await writer.close();
this.keepExistingData = true;
this.seek += data.byteLength;
}
}
exports.FsaNodeFsOpenFile = FsaNodeFsOpenFile;
//# sourceMappingURL=FsaNodeFsOpenFile.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeFsOpenFile.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeFsOpenFile.ts"],"names":[],"mappings":";;;AAIA;;;GAGG;AACH,MAAa,iBAAiB;IAW5B,YACkB,EAAU,EACV,UAAsB,EACtB,KAAa,EACb,IAA+B,EAC/B,QAAgB;QAJhB,OAAE,GAAF,EAAE,CAAQ;QACV,eAAU,GAAV,UAAU,CAAY;QACtB,UAAK,GAAL,KAAK,CAAQ;QACb,SAAI,GAAJ,IAAI,CAA2B;QAC/B,aAAQ,GAAR,QAAQ,CAAQ;QAfxB,SAAI,GAAW,CAAC,CAAC;QAiBzB,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,KAAK,2BAAgB,CAAC,CAAC;IACpD,CAAC;IAEM,KAAK,CAAC,KAAK,KAAmB,CAAC;IAE/B,KAAK,CAAC,KAAK,CAAC,IAAqB,EAAE,IAAmB;QAC3D,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAC3F,MAAM,MAAM,CAAC,KAAK,CAAC;YACjB,IAAI,EAAE,OAAO;YACb,IAAI;YACJ,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC;IAC/B,CAAC;CACF;AAnCD,8CAmCC"}
+23
View File
@@ -0,0 +1,23 @@
import { Readable } from 'stream';
import { Defer } from '../thingies/Defer';
import type { FsaNodeFsOpenFile } from './FsaNodeFsOpenFile';
import type { IReadStream } from '../node/types/misc';
import type { IReadStreamOptions } from '../node/types/options';
import type { FsaNodeFs } from './FsaNodeFs';
export declare class FsaNodeReadStream extends Readable implements IReadStream {
protected readonly fs: FsaNodeFs;
protected readonly handle: Promise<FsaNodeFsOpenFile>;
readonly path: string;
protected readonly options: IReadStreamOptions;
protected __pending__: boolean;
protected __closed__: boolean;
protected __bytes__: number;
protected readonly __mutex__: <T = unknown>(code: import("../thingies/types").Code<T>) => Promise<T>;
protected readonly __file__: Defer<FsaNodeFsOpenFile>;
constructor(fs: FsaNodeFs, handle: Promise<FsaNodeFsOpenFile>, path: string, options: IReadStreamOptions);
private __read__;
private __close__;
get bytesRead(): number;
get pending(): boolean;
_read(): void;
}
+90
View File
@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeReadStream = void 0;
const stream_1 = require("stream");
const Defer_1 = require("../thingies/Defer");
const concurrency_1 = require("../thingies/concurrency");
class FsaNodeReadStream extends stream_1.Readable {
constructor(fs, handle, path, options) {
super();
this.fs = fs;
this.handle = handle;
this.path = path;
this.options = options;
this.__pending__ = true;
this.__closed__ = false;
this.__bytes__ = 0;
this.__mutex__ = (0, concurrency_1.concurrency)(1);
this.__file__ = new Defer_1.Defer();
handle
.then(file => {
if (this.__closed__)
return;
this.__file__.resolve(file);
if (this.options.fd !== undefined)
this.emit('open', file.fd);
this.emit('ready');
})
.catch(error => {
this.__file__.reject(error);
})
.finally(() => {
this.__pending__ = false;
});
}
async __read__() {
return await this.__mutex__(async () => {
if (this.__closed__)
return;
const { file } = await this.__file__.promise;
const blob = await file.getFile();
const buffer = await blob.arrayBuffer();
const start = this.options.start || 0;
let end = typeof this.options.end === 'number' ? this.options.end + 1 : buffer.byteLength;
if (end > buffer.byteLength)
end = buffer.byteLength;
const uint8 = new Uint8Array(buffer, start, end - start);
return uint8;
});
}
__close__() {
if (this.__closed__)
return;
this.__closed__ = true;
if (this.options.autoClose) {
this.__file__.promise
.then(file => {
this.fs.close(file.fd, () => {
this.emit('close');
});
return file.close();
})
.catch(error => { });
}
}
// -------------------------------------------------------------- IReadStream
get bytesRead() {
return this.__bytes__;
}
get pending() {
return this.__pending__;
}
// ----------------------------------------------------------------- Readable
_read() {
this.__read__().then((uint8) => {
if (this.__closed__)
return;
if (!uint8)
return this.push(null);
this.__bytes__ += uint8.length;
this.__close__();
this.push(uint8);
this.push(null);
}, error => {
this.__close__();
this.destroy(error);
});
}
}
exports.FsaNodeReadStream = FsaNodeReadStream;
//# sourceMappingURL=FsaNodeReadStream.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeReadStream.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeReadStream.ts"],"names":[],"mappings":"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"}
+30
View File
@@ -0,0 +1,30 @@
import type * as misc from '../node/types/misc';
export declare class FsaNodeStats<T = misc.TStatNumber> implements misc.IStats<T> {
protected readonly kind: 'file' | 'directory';
readonly uid: T;
readonly gid: T;
readonly rdev: T;
readonly blksize: T;
readonly ino: T;
readonly size: T;
readonly blocks: T;
readonly atime: Date;
readonly mtime: Date;
readonly ctime: Date;
readonly birthtime: Date;
readonly atimeMs: T;
readonly mtimeMs: T;
readonly ctimeMs: T;
readonly birthtimeMs: T;
readonly dev: T;
readonly mode: T;
readonly nlink: T;
constructor(isBigInt: boolean, size: T, kind: 'file' | 'directory');
isDirectory(): boolean;
isFile(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
}
+53
View File
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeStats = void 0;
const time = 0;
const timex = typeof BigInt === 'function' ? BigInt(time) : time;
const date = new Date(time);
class FsaNodeStats {
constructor(isBigInt, size, kind) {
this.kind = kind;
const dummy = (isBigInt ? timex : time);
this.uid = dummy;
this.gid = dummy;
this.rdev = dummy;
this.blksize = dummy;
this.ino = dummy;
this.size = size;
this.blocks = dummy;
this.atime = date;
this.mtime = date;
this.ctime = date;
this.birthtime = date;
this.atimeMs = dummy;
this.mtimeMs = dummy;
this.ctimeMs = dummy;
this.birthtimeMs = dummy;
this.dev = dummy;
this.mode = dummy;
this.nlink = dummy;
}
isDirectory() {
return this.kind === 'directory';
}
isFile() {
return this.kind === 'file';
}
isBlockDevice() {
return false;
}
isCharacterDevice() {
return false;
}
isSymbolicLink() {
return false;
}
isFIFO() {
return false;
}
isSocket() {
return false;
}
}
exports.FsaNodeStats = FsaNodeStats;
//# sourceMappingURL=FsaNodeStats.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeStats.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeStats.ts"],"names":[],"mappings":";;;AAEA,MAAM,IAAI,GAAW,CAAC,CAAC;AACvB,MAAM,KAAK,GAAW,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAsB,CAAC;AAC5F,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;AAE5B,MAAa,YAAY;IAoBvB,YACE,QAAiB,EACjB,IAAO,EACY,IAA0B;QAA1B,SAAI,GAAJ,IAAI,CAAsB;QAE7C,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAa,CAAC;QACpD,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;QACjB,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAEM,WAAW;QAChB,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC;IACnC,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;IAC9B,CAAC;IAEM,aAAa;QAClB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,iBAAiB;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,cAAc;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,MAAM;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,QAAQ;QACb,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAzED,oCAyEC"}
+47
View File
@@ -0,0 +1,47 @@
import { Writable } from 'stream';
import { FsaNodeFsOpenFile } from './FsaNodeFsOpenFile';
import type { IFileSystemWritableFileStream } from '../fsa/types';
import type { IWriteStream } from '../node/types/misc';
import type { IWriteStreamOptions } from '../node/types/options';
/**
* This WriteStream implementation does not build on top of the `fs` module,
* but instead uses the lower-level `FileSystemFileHandle` interface. The reason
* is the different semantics in `fs` and FSA (File System Access API) write streams.
*
* When data is written to an FSA file, a new FSA stream is created, it copies
* the file to a temporary swap file. After each written chunk, that swap file
* is closed and the original file is replaced with the swap file. This means,
* if WriteStream was built on top of `fs`, each chunk write would result in
* a file copy, write, close, rename operations, which is not what we want.
*
* Instead this implementation hooks into the lower-level and closes the swap
* file only once the stream is closed. The downside is that the written data
* is not immediately visible to other processes (because it is written to the
* swap file), but that is the trade-off we have to make.
*
* @todo Could make this flush the data to the original file periodically, so that
* the data is visible to other processes.
* @todo This stream could work through `FileSystemSyncAccessHandle.write` in a
* Worker thread instead.
*/
export declare class FsaNodeWriteStream extends Writable implements IWriteStream {
readonly path: string;
protected readonly options: IWriteStreamOptions;
protected __pending__: boolean;
protected __closed__: boolean;
protected __bytes__: number;
protected readonly __stream__: Promise<IFileSystemWritableFileStream>;
protected readonly __mutex__: <T = unknown>(code: import("../thingies/types").Code<T>) => Promise<T>;
constructor(handle: Promise<FsaNodeFsOpenFile>, path: string, options: IWriteStreamOptions);
private ___write___;
private __close__;
get bytesWritten(): number;
get pending(): boolean;
close(cb: any): void;
_write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
_writev(chunks: Array<{
chunk: any;
encoding: string;
}>, callback: (error?: Error | null) => void): void;
_final(callback: (error?: Error | null) => void): void;
}
+151
View File
@@ -0,0 +1,151 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeWriteStream = void 0;
const stream_1 = require("stream");
const Defer_1 = require("../thingies/Defer");
const concurrency_1 = require("../thingies/concurrency");
const util_1 = require("../node/util");
const queueMicrotask_1 = require("../queueMicrotask");
/**
* This WriteStream implementation does not build on top of the `fs` module,
* but instead uses the lower-level `FileSystemFileHandle` interface. The reason
* is the different semantics in `fs` and FSA (File System Access API) write streams.
*
* When data is written to an FSA file, a new FSA stream is created, it copies
* the file to a temporary swap file. After each written chunk, that swap file
* is closed and the original file is replaced with the swap file. This means,
* if WriteStream was built on top of `fs`, each chunk write would result in
* a file copy, write, close, rename operations, which is not what we want.
*
* Instead this implementation hooks into the lower-level and closes the swap
* file only once the stream is closed. The downside is that the written data
* is not immediately visible to other processes (because it is written to the
* swap file), but that is the trade-off we have to make.
*
* @todo Could make this flush the data to the original file periodically, so that
* the data is visible to other processes.
* @todo This stream could work through `FileSystemSyncAccessHandle.write` in a
* Worker thread instead.
*/
class FsaNodeWriteStream extends stream_1.Writable {
constructor(handle, path, options) {
super();
this.path = path;
this.options = options;
this.__pending__ = true;
this.__closed__ = false;
this.__bytes__ = 0;
this.__mutex__ = (0, concurrency_1.concurrency)(1);
if (options.start !== undefined) {
if (typeof options.start !== 'number') {
throw new TypeError('"start" option must be a Number');
}
if (options.start < 0) {
throw new TypeError('"start" must be >= zero');
}
}
const stream = new Defer_1.Defer();
this.__stream__ = stream.promise;
(async () => {
var _a, _b;
const fsaHandle = await handle;
const fileWasOpened = !options.fd;
if (fileWasOpened)
this.emit('open', fsaHandle.fd);
const flags = (0, util_1.flagsToNumber)((_a = options.flags) !== null && _a !== void 0 ? _a : 'w');
const keepExistingData = flags & 1024 /* FLAG.O_APPEND */ ? true : false;
const writable = await fsaHandle.file.createWritable({ keepExistingData });
if (keepExistingData) {
const start = Number((_b = options.start) !== null && _b !== void 0 ? _b : 0);
if (start)
await writable.seek(start);
}
this.__pending__ = false;
stream.resolve(writable);
})().catch(error => {
stream.reject(error);
});
}
async ___write___(buffers) {
await this.__mutex__(async () => {
if (this.__closed__)
return;
// if (this.__closed__) throw new Error('WriteStream is closed');
const writable = await this.__stream__;
for (const buffer of buffers) {
await writable.write(buffer);
this.__bytes__ += buffer.byteLength;
}
});
}
async __close__() {
const emitClose = this.options.emitClose;
await this.__mutex__(async () => {
if (this.__closed__ && emitClose) {
(0, queueMicrotask_1.default)(() => this.emit('close'));
return;
}
try {
const writable = await this.__stream__;
this.__closed__ = true;
await writable.close();
if (emitClose)
this.emit('close');
}
catch (error) {
this.emit('error', error);
if (emitClose)
this.emit('close', error);
}
});
}
// ------------------------------------------------------------- IWriteStream
get bytesWritten() {
return this.__bytes__;
}
get pending() {
return this.__pending__;
}
close(cb) {
if (cb)
this.once('close', cb);
this.__close__().catch(() => { });
}
// ----------------------------------------------------------------- Writable
_write(chunk, encoding, callback) {
this.___write___([chunk])
.then(() => {
if (callback)
callback(null);
})
.catch(error => {
if (callback)
callback(error);
});
}
_writev(chunks, callback) {
const buffers = chunks.map(({ chunk }) => chunk);
this.___write___(buffers)
.then(() => {
if (callback)
callback(null);
})
.catch(error => {
if (callback)
callback(error);
});
}
_final(callback) {
this.__close__()
.then(() => {
if (callback)
callback(null);
})
.catch(error => {
if (callback)
callback(error);
});
}
}
exports.FsaNodeWriteStream = FsaNodeWriteStream;
//# sourceMappingURL=FsaNodeWriteStream.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeWriteStream.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeWriteStream.ts"],"names":[],"mappings":"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"}
+3
View File
@@ -0,0 +1,3 @@
export declare const enum FsaToNodeConstants {
Separator = "/"
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=constants.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/fsa-to-node/constants.ts"],"names":[],"mappings":""}
+2
View File
@@ -0,0 +1,2 @@
export { FsaNodeFs } from './FsaNodeFs';
export { FsaNodeSyncAdapterWorker } from './worker/FsaNodeSyncAdapterWorker';
+8
View File
@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeSyncAdapterWorker = exports.FsaNodeFs = void 0;
var FsaNodeFs_1 = require("./FsaNodeFs");
Object.defineProperty(exports, "FsaNodeFs", { enumerable: true, get: function () { return FsaNodeFs_1.FsaNodeFs; } });
var FsaNodeSyncAdapterWorker_1 = require("./worker/FsaNodeSyncAdapterWorker");
Object.defineProperty(exports, "FsaNodeSyncAdapterWorker", { enumerable: true, get: function () { return FsaNodeSyncAdapterWorker_1.FsaNodeSyncAdapterWorker; } });
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fsa-to-node/index.ts"],"names":[],"mappings":";;;AAAA,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAClB,8EAA6E;AAApE,oIAAA,wBAAwB,OAAA"}
+2
View File
@@ -0,0 +1,2 @@
import { encoder, decoder } from '@jsonjoy.com/json-pack/lib/cbor/shared';
export { encoder, decoder };
+7
View File
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.decoder = exports.encoder = void 0;
const shared_1 = require("@jsonjoy.com/json-pack/lib/cbor/shared");
Object.defineProperty(exports, "encoder", { enumerable: true, get: function () { return shared_1.encoder; } });
Object.defineProperty(exports, "decoder", { enumerable: true, get: function () { return shared_1.decoder; } });
//# sourceMappingURL=json.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/fsa-to-node/json.ts"],"names":[],"mappings":";;;AAAA,mEAA0E;AACjE,wFADA,gBAAO,OACA;AAAE,wFADA,gBAAO,OACA"}
+37
View File
@@ -0,0 +1,37 @@
import type { IFileSystemFileHandle } from '../fsa/types';
import type * as opts from '../node/types/options';
import type * as misc from '../node/types/misc';
export type FsLocation = [folder: string[], file: string];
/**
* Adapter which implements synchronous calls to the FSA API.
*/
export interface FsaNodeSyncAdapterApi {
stat(location: FsLocation): FsaNodeSyncAdapterStats;
access(req: [filename: string, mode: number]): void;
readFile(req: [filename: string, opts?: opts.IReadFileOptions]): Uint8Array;
writeFile(req: [filename: string, data: Uint8Array, opts?: opts.IWriteFileOptions]): void;
appendFile(req: [filename: string, data: Uint8Array, opts?: opts.IAppendFileOptions]): void;
copy(req: [src: string, dst: string, flags?: number]): void;
move(req: [src: string, dst: string]): void;
rmdir(req: [filename: string, opts?: opts.IRmdirOptions]): void;
rm(req: [filename: string, opts?: opts.IRmOptions]): void;
mkdir(req: [filename: string, opts?: misc.TMode | opts.IMkdirOptions]): string | undefined;
mkdtemp(req: [filename: string, opts?: misc.TMode | opts.IOptions]): string;
trunc(req: [filename: string, len: number]): void;
unlink(req: [filename: string]): void;
readdir(req: [filename: string]): FsaNodeSyncAdapterEntry[];
read(req: [filename: string, position: number, length: number]): Uint8Array;
write(req: [filename: string, data: Uint8Array, position: number | null]): number;
open(req: [filename: string, flags: number, mode: number]): IFileSystemFileHandle;
}
export interface FsaNodeSyncAdapter {
call<K extends keyof FsaNodeSyncAdapterApi>(method: K, payload: Parameters<FsaNodeSyncAdapterApi[K]>[0]): ReturnType<FsaNodeSyncAdapterApi[K]>;
}
export interface FsaNodeSyncAdapterStats {
kind: 'file' | 'directory';
size?: number;
}
export interface FsaNodeSyncAdapterEntry {
kind: 'file' | 'directory';
name: string;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/fsa-to-node/types.ts"],"names":[],"mappings":""}
+4
View File
@@ -0,0 +1,4 @@
import { IFileSystemDirectoryHandle } from '../fsa/types';
import type { FsLocation } from './types';
export declare const pathToLocation: (path: string) => FsLocation;
export declare const testDirectoryIsWritable: (dir: IFileSystemDirectoryHandle) => Promise<boolean>;
+34
View File
@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.testDirectoryIsWritable = exports.pathToLocation = void 0;
const pathToLocation = (path) => {
if (path[0] === "/" /* FsaToNodeConstants.Separator */)
path = path.slice(1);
if (path[path.length - 1] === "/" /* FsaToNodeConstants.Separator */)
path = path.slice(0, -1);
const lastSlashIndex = path.lastIndexOf("/" /* FsaToNodeConstants.Separator */);
if (lastSlashIndex === -1)
return [[], path];
const file = path.slice(lastSlashIndex + 1);
const folder = path.slice(0, lastSlashIndex).split("/" /* FsaToNodeConstants.Separator */);
return [folder, file];
};
exports.pathToLocation = pathToLocation;
const testDirectoryIsWritable = async (dir) => {
const testFileName = '__memfs_writable_test_file_' + Math.random().toString(36).slice(2) + Date.now();
try {
await dir.getFileHandle(testFileName, { create: true });
return true;
}
catch (_a) {
return false;
}
finally {
try {
await dir.removeEntry(testFileName);
}
catch (e) { }
}
};
exports.testDirectoryIsWritable = testDirectoryIsWritable;
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/fsa-to-node/util.ts"],"names":[],"mappings":";;;AAIO,MAAM,cAAc,GAAG,CAAC,IAAY,EAAc,EAAE;IACzD,IAAI,IAAI,CAAC,CAAC,CAAC,2CAAiC;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnE,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,2CAAiC;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,wCAA8B,CAAC;IACtE,IAAI,cAAc,KAAK,CAAC,CAAC;QAAE,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,KAAK,wCAA8B,CAAC;IACjF,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACxB,CAAC,CAAC;AARW,QAAA,cAAc,kBAQzB;AAEK,MAAM,uBAAuB,GAAG,KAAK,EAAE,GAA+B,EAAoB,EAAE;IACjG,MAAM,YAAY,GAAG,6BAA6B,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtG,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,aAAa,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC,CAAA,CAAC;IAChB,CAAC;AACH,CAAC,CAAC;AAZW,QAAA,uBAAuB,2BAYlC"}
@@ -0,0 +1,10 @@
import { SyncMessenger } from './SyncMessenger';
import type * as fsa from '../../fsa/types';
import type { FsaNodeSyncAdapter, FsaNodeSyncAdapterApi } from '../types';
export declare class FsaNodeSyncAdapterWorker implements FsaNodeSyncAdapter {
protected readonly messenger: SyncMessenger;
protected readonly root: fsa.IFileSystemDirectoryHandle;
static start(url: string, dir: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>): Promise<FsaNodeSyncAdapterWorker>;
constructor(messenger: SyncMessenger, root: fsa.IFileSystemDirectoryHandle);
call<K extends keyof FsaNodeSyncAdapterApi>(method: K, payload: Parameters<FsaNodeSyncAdapterApi[K]>[0]): ReturnType<FsaNodeSyncAdapterApi[K]>;
}
+62
View File
@@ -0,0 +1,62 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeSyncAdapterWorker = void 0;
const Defer_1 = require("../../thingies/Defer");
const SyncMessenger_1 = require("./SyncMessenger");
const json_1 = require("../json");
let rootId = 0;
class FsaNodeSyncAdapterWorker {
static async start(url, dir) {
const worker = new Worker(url);
const future = new Defer_1.Defer();
let id = rootId++;
let messenger = undefined;
const _dir = await dir;
worker.onmessage = e => {
const data = e.data;
if (!Array.isArray(data))
return;
const msg = data;
const code = msg[0];
switch (code) {
case 0 /* FsaNodeWorkerMessageCode.Init */: {
const [, sab] = msg;
messenger = new SyncMessenger_1.SyncMessenger(sab);
const setRootMessage = [1 /* FsaNodeWorkerMessageCode.SetRoot */, id, _dir];
worker.postMessage(setRootMessage);
break;
}
case 2 /* FsaNodeWorkerMessageCode.RootSet */: {
const [, rootId] = msg;
if (id !== rootId)
return;
const adapter = new FsaNodeSyncAdapterWorker(messenger, _dir);
future.resolve(adapter);
break;
}
}
};
return await future.promise;
}
constructor(messenger, root) {
this.messenger = messenger;
this.root = root;
}
call(method, payload) {
const request = [3 /* FsaNodeWorkerMessageCode.Request */, method, payload];
const encoded = json_1.encoder.encode(request);
const encodedResponse = this.messenger.callSync(encoded);
const [code, data] = json_1.decoder.decode(encodedResponse);
switch (code) {
case 4 /* FsaNodeWorkerMessageCode.Response */:
return data;
case 5 /* FsaNodeWorkerMessageCode.ResponseError */:
throw data;
default: {
throw new Error('Invalid response message code');
}
}
}
}
exports.FsaNodeSyncAdapterWorker = FsaNodeSyncAdapterWorker;
//# sourceMappingURL=FsaNodeSyncAdapterWorker.js.map
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeSyncAdapterWorker.js","sourceRoot":"","sources":["../../../src/fsa-to-node/worker/FsaNodeSyncAdapterWorker.ts"],"names":[],"mappings":";;;AAAA,gDAA6C;AAE7C,mDAAgD;AAChD,kCAA2C;AAa3C,IAAI,MAAM,GAAG,CAAC,CAAC;AAEf,MAAa,wBAAwB;IAC5B,MAAM,CAAC,KAAK,CAAC,KAAK,CACvB,GAAW,EACX,GAA6E;QAE7E,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,aAAK,EAA4B,CAAC;QACrD,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;QAClB,IAAI,SAAS,GAA8B,SAAS,CAAC;QACrD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC;QACvB,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE;YACrB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;YACpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,OAAO;YACjC,MAAM,GAAG,GAAG,IAAwB,CAAC;YACrC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAA6B,CAAC;YAChD,QAAQ,IAAI,EAAE,CAAC;gBACb,0CAAkC,CAAC,CAAC,CAAC;oBACnC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,GAA2B,CAAC;oBAC5C,SAAS,GAAG,IAAI,6BAAa,CAAC,GAAG,CAAC,CAAC;oBACnC,MAAM,cAAc,GAA4B,2CAAmC,EAAE,EAAE,IAAI,CAAC,CAAC;oBAC7F,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;oBACnC,MAAM;gBACR,CAAC;gBACD,6CAAqC,CAAC,CAAC,CAAC;oBACtC,MAAM,CAAC,EAAE,MAAM,CAAC,GAAG,GAA8B,CAAC;oBAClD,IAAI,EAAE,KAAK,MAAM;wBAAE,OAAO;oBAC1B,MAAM,OAAO,GAAG,IAAI,wBAAwB,CAAC,SAAU,EAAE,IAAI,CAAC,CAAC;oBAC/D,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBACxB,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC;IAC9B,CAAC;IAED,YACqB,SAAwB,EACxB,IAAoC;QADpC,cAAS,GAAT,SAAS,CAAe;QACxB,SAAI,GAAJ,IAAI,CAAgC;IACtD,CAAC;IAEG,IAAI,CACT,MAAS,EACT,OAAgD;QAEhD,MAAM,OAAO,GAA4B,2CAAmC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7F,MAAM,OAAO,GAAG,cAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEzD,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,cAAO,CAAC,MAAM,CAAC,eAAe,CAAY,CAAC;QAChE,QAAQ,IAAI,EAAE,CAAC;YACb;gBACE,OAAO,IAAW,CAAC;YACrB;gBACE,MAAM,IAAI,CAAC;YACb,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA3DD,4DA2DC"}
+20
View File
@@ -0,0 +1,20 @@
import { AsyncCallback, SyncMessenger } from './SyncMessenger';
import { FsaNodeFs } from '../FsaNodeFs';
import type * as fsa from '../../fsa/types';
import type { FsaNodeWorkerMsg } from './types';
import type { FsaNodeSyncAdapterApi } from '../types';
export declare class FsaNodeSyncWorker {
protected readonly sab: SharedArrayBuffer;
protected readonly messenger: SyncMessenger;
protected root: fsa.IFileSystemDirectoryHandle;
protected fs: FsaNodeFs;
start(): void;
protected onPostMessage: (msg: FsaNodeWorkerMsg) => void;
protected readonly onRequest: AsyncCallback;
protected getDir(path: string[], create: boolean, funcName?: string): Promise<fsa.IFileSystemDirectoryHandle>;
protected getFile(path: string[], name: string, funcName?: string, create?: boolean): Promise<fsa.IFileSystemFileHandle>;
protected getFileOrDir(path: string[], name: string, funcName?: string, create?: boolean): Promise<fsa.IFileSystemFileHandle | fsa.IFileSystemDirectoryHandle>;
protected handlers: {
[K in keyof FsaNodeSyncAdapterApi]: (request: Parameters<FsaNodeSyncAdapterApi[K]>[0]) => Promise<ReturnType<FsaNodeSyncAdapterApi[K]>>;
};
}
+176
View File
@@ -0,0 +1,176 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeSyncWorker = void 0;
const SyncMessenger_1 = require("./SyncMessenger");
const FsaNodeFs_1 = require("../FsaNodeFs");
const json_1 = require("../json");
class FsaNodeSyncWorker {
constructor() {
this.sab = new SharedArrayBuffer(1024 * 1024);
this.messenger = new SyncMessenger_1.SyncMessenger(this.sab);
this.onPostMessage = (msg) => {
switch (msg[0]) {
case 1 /* FsaNodeWorkerMessageCode.SetRoot */: {
const [, id, dir] = msg;
this.root = dir;
this.fs = new FsaNodeFs_1.FsaNodeFs(this.root);
const response = [2 /* FsaNodeWorkerMessageCode.RootSet */, id];
postMessage(response);
this.messenger.serveAsync(this.onRequest);
break;
}
}
};
this.onRequest = async (request) => {
try {
const message = json_1.decoder.decode(request);
if (!Array.isArray(message))
throw new Error('Invalid message format');
const code = message[0];
if (code !== 3 /* FsaNodeWorkerMessageCode.Request */)
throw new Error('Invalid message code');
const [, method, payload] = message;
const handler = this.handlers[method];
if (!handler)
throw new Error(`Unknown method ${method}`);
const response = await handler(payload);
return json_1.encoder.encode([4 /* FsaNodeWorkerMessageCode.Response */, response]);
}
catch (err) {
const message = err && typeof err === 'object' && err.message ? err.message : 'Unknown error';
const error = { message };
if (err && typeof err === 'object' && (err.code || err.name))
error.code = err.code || err.name;
return json_1.encoder.encode([5 /* FsaNodeWorkerMessageCode.ResponseError */, error]);
}
};
this.handlers = {
stat: async (location) => {
const handle = await this.getFileOrDir(location[0], location[1], 'statSync');
return {
kind: handle.kind,
};
},
access: async ([filename, mode]) => {
await this.fs.promises.access(filename, mode);
},
readFile: async ([filename, opts]) => {
const buf = (await this.fs.promises.readFile(filename, Object.assign(Object.assign({}, opts), { encoding: 'buffer' })));
const uint8 = new Uint8Array(buf, buf.byteOffset, buf.byteLength);
return uint8;
},
writeFile: async ([filename, data, opts]) => {
await this.fs.promises.writeFile(filename, data, Object.assign(Object.assign({}, opts), { encoding: 'buffer' }));
},
appendFile: async ([filename, data, opts]) => {
await this.fs.promises.appendFile(filename, data, Object.assign(Object.assign({}, opts), { encoding: 'buffer' }));
},
copy: async ([src, dst, flags]) => {
await this.fs.promises.copyFile(src, dst, flags);
},
move: async ([src, dst]) => {
await this.fs.promises.rename(src, dst);
},
rmdir: async ([filename, options]) => {
await this.fs.promises.rmdir(filename, options);
},
rm: async ([filename, options]) => {
await this.fs.promises.rm(filename, options);
},
mkdir: async ([filename, options]) => {
return await this.fs.promises.mkdir(filename, options);
},
mkdtemp: async ([filename]) => {
return (await this.fs.promises.mkdtemp(filename, { encoding: 'utf8' }));
},
trunc: async ([filename, len]) => {
await this.fs.promises.truncate(filename, len);
},
unlink: async ([filename]) => {
await this.fs.promises.unlink(filename);
},
readdir: async ([filename]) => {
const list = (await this.fs.promises.readdir(filename, { withFileTypes: true, encoding: 'utf8' }));
const res = list.map(entry => ({
kind: entry.isDirectory() ? 'directory' : 'file',
name: entry.name,
}));
return res;
},
read: async ([filename, position, length]) => {
let uint8 = new Uint8Array(length);
const handle = await this.fs.promises.open(filename, 'r');
const bytesRead = await new Promise((resolve, reject) => {
this.fs.read(handle.fd, uint8, 0, length, position, (err, bytesRead) => {
if (err)
return reject(err);
resolve(bytesRead || length);
});
});
if (bytesRead < length)
uint8 = uint8.slice(0, bytesRead);
return uint8;
},
write: async ([filename, data, position]) => {
const handle = await this.fs.promises.open(filename, 'a');
const { bytesWritten } = await handle.write(data, 0, data.length, position || undefined);
return bytesWritten;
},
open: async ([filename, flags, mode]) => {
const handle = await this.fs.promises.open(filename, flags, mode);
const file = await this.fs.__getFileById(handle.fd);
await handle.close();
return file;
},
};
}
start() {
onmessage = e => {
if (!Array.isArray(e.data))
return;
this.onPostMessage(e.data);
};
const initMsg = [0 /* FsaNodeWorkerMessageCode.Init */, this.sab];
postMessage(initMsg);
}
async getDir(path, create, funcName) {
let curr = this.root;
const options = { create };
try {
for (const name of path) {
curr = await curr.getDirectoryHandle(name, options);
}
}
catch (error) {
// if (error && typeof error === 'object' && error.name === 'TypeMismatchError')
// throw createError('ENOTDIR', funcName, path.join(FsaToNodeConstants.Separator));
throw error;
}
return curr;
}
async getFile(path, name, funcName, create) {
const dir = await this.getDir(path, false, funcName);
const file = await dir.getFileHandle(name, { create });
return file;
}
async getFileOrDir(path, name, funcName, create) {
const dir = await this.getDir(path, false, funcName);
try {
const file = await dir.getFileHandle(name);
return file;
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
return await dir.getDirectoryHandle(name);
// case 'NotFoundError':
// throw createError('ENOENT', funcName, path.join(FsaToNodeConstants.Separator));
}
}
throw error;
}
}
}
exports.FsaNodeSyncWorker = FsaNodeSyncWorker;
//# sourceMappingURL=FsaNodeSyncWorker.js.map
File diff suppressed because one or more lines are too long
+24
View File
@@ -0,0 +1,24 @@
export type AsyncCallback = (request: Uint8Array) => Promise<Uint8Array>;
/**
* `SyncMessenger` allows to execute asynchronous code synchronously. The
* asynchronous code is executed in a Worker thread, while the main thread is
* blocked until the asynchronous code is finished.
*
* First four 4-byte words is the header, where the first word is used for Atomics
* notifications. The second word is used for spin-locking the main thread until
* the asynchronous code is finished. The third word is used to specify payload
* length. The fourth word is currently unused.
*
* The maximum payload size is the size of the SharedArrayBuffer minus the
* header size.
*/
export declare class SyncMessenger {
protected readonly sab: SharedArrayBuffer;
protected readonly int32: Int32Array;
protected readonly uint8: Uint8Array;
protected readonly headerSize: any;
protected readonly dataSize: any;
constructor(sab: SharedArrayBuffer);
callSync(data: Uint8Array): Uint8Array;
serveAsync(callback: AsyncCallback): void;
}
+72
View File
@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SyncMessenger = void 0;
/**
* @param condition Condition to wait for, when true, the function returns.
* @param ms Maximum time to wait in milliseconds.
*/
const sleepUntil = (condition, ms = 100) => {
const start = Date.now();
while (!condition()) {
const now = Date.now();
if (now - start > ms)
throw new Error('Timeout');
}
};
/**
* `SyncMessenger` allows to execute asynchronous code synchronously. The
* asynchronous code is executed in a Worker thread, while the main thread is
* blocked until the asynchronous code is finished.
*
* First four 4-byte words is the header, where the first word is used for Atomics
* notifications. The second word is used for spin-locking the main thread until
* the asynchronous code is finished. The third word is used to specify payload
* length. The fourth word is currently unused.
*
* The maximum payload size is the size of the SharedArrayBuffer minus the
* header size.
*/
class SyncMessenger {
constructor(sab) {
this.sab = sab;
this.int32 = new Int32Array(sab);
this.uint8 = new Uint8Array(sab);
this.headerSize = 4 * 4;
this.dataSize = sab.byteLength - this.headerSize;
}
callSync(data) {
const requestLength = data.length;
const headerSize = this.headerSize;
const int32 = this.int32;
int32[1] = 0;
int32[2] = requestLength;
this.uint8.set(data, headerSize);
Atomics.notify(int32, 0);
sleepUntil(() => int32[1] === 1);
const responseLength = int32[2];
const response = this.uint8.slice(headerSize, headerSize + responseLength);
return response;
}
serveAsync(callback) {
const headerSize = this.headerSize;
(async () => {
try {
const int32 = this.int32;
const res = Atomics.wait(int32, 0, 0);
if (res !== 'ok')
throw new Error(`Unexpected Atomics.wait result: ${res}`);
const requestLength = this.int32[2];
const request = this.uint8.slice(headerSize, headerSize + requestLength);
const response = await callback(request);
const responseLength = response.length;
int32[2] = responseLength;
this.uint8.set(response, headerSize);
int32[1] = 1;
}
catch (_a) { }
this.serveAsync(callback);
})().catch(() => { });
}
}
exports.SyncMessenger = SyncMessenger;
//# sourceMappingURL=SyncMessenger.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"SyncMessenger.js","sourceRoot":"","sources":["../../../src/fsa-to-node/worker/SyncMessenger.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACH,MAAM,UAAU,GAAG,CAAC,SAAwB,EAAE,KAAa,GAAG,EAAE,EAAE;IAChE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,KAAK,GAAG,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAa,aAAa;IAMxB,YAAsC,GAAsB;QAAtB,QAAG,GAAH,GAAG,CAAmB;QAC1D,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACnD,CAAC;IAEM,QAAQ,CAAC,IAAgB;QAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACb,KAAK,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACzB,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACjC,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,GAAG,cAAc,CAAC,CAAC;QAC3E,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEM,UAAU,CAAC,QAAuB;QACvC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;gBACzB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBACtC,IAAI,GAAG,KAAK,IAAI;oBAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAC;gBAC5E,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,CAAC,CAAC;gBACzE,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;gBACzC,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC;gBACvC,KAAK,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;gBACrC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACf,CAAC;YAAC,WAAM,CAAC,CAAA,CAAC;YACV,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACvB,CAAC;CACF;AA7CD,sCA6CC"}
+8
View File
@@ -0,0 +1,8 @@
export declare const enum FsaNodeWorkerMessageCode {
Init = 0,
SetRoot = 1,
RootSet = 2,
Request = 3,
Response = 4,
ResponseError = 5
}

Some files were not shown because too many files have changed in this diff Show More