core-3nweb-client-lib 0.45.3 → 0.46.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/build/injected-globals/inject-on-node.d.ts +2 -0
- package/build/injected-globals/inject-on-node.js +70 -0
- package/build/injected-globals/platform-devfs.d.ts +31 -0
- package/build/injected-globals/platform-devfs.js +19 -0
- package/build/lib-common/async-fs-node.d.ts +7 -48
- package/build/lib-common/async-fs-node.js +11 -137
- package/build/tests/jasmine.js +6 -1
- package/build/tests/units/obj-folders.js +9 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,18 +6,36 @@
|
|
|
6
6
|
## Development and testing
|
|
7
7
|
|
|
8
8
|
After repository clone, bring down all NodeJS modules, by running in project's folder:
|
|
9
|
-
```
|
|
9
|
+
```bash
|
|
10
10
|
npm ci
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Tests have some unit and integrated components. Integration test uses 3NWeb spec server. Integrated tests use server and dns mocking from `spec-3nweb-server`.
|
|
14
14
|
|
|
15
15
|
Build is done with
|
|
16
|
-
```
|
|
16
|
+
```bash
|
|
17
17
|
npm run build
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Test is done with (after build)
|
|
21
|
-
```
|
|
21
|
+
```bash
|
|
22
22
|
npm run test
|
|
23
23
|
```
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## Reuse on non-Node and injecting implementation
|
|
27
|
+
|
|
28
|
+
To reuse this library in non-Node environments, like Android's jsengine and browser, we need to provide different implementations for access to network, files.
|
|
29
|
+
|
|
30
|
+
Some of these functions are explicitly passed in setup phases, like naming functionality that may either use DNS of DoH. Switch between these may even be done based on same platform, but depending on user prefernces.
|
|
31
|
+
|
|
32
|
+
Other functions, like access to device's file system, depend only on environment. For these we use a bit cheaper injection approach. We articulate types that should be implemented. And modules expect to get implementation from `globalThis`. Hence, environments that use core should inject respective implementations at some early stage.
|
|
33
|
+
|
|
34
|
+
Note that import of implementations of injected for node should be done directly, placing it before other imports that need injected global value(s). Do something like:
|
|
35
|
+
```typescript
|
|
36
|
+
import { makePlatformDeviceFS } from 'core-3nweb-client-lib/build/injected-globals/inject-on-node';
|
|
37
|
+
globalThis.platform = {
|
|
38
|
+
device_fs: makePlatformDeviceFS()
|
|
39
|
+
};
|
|
40
|
+
import ... // other modules
|
|
41
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (C) 2026 3NSoft Inc.
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify it under
|
|
6
|
+
the terms of the GNU General Public License as published by the Free Software
|
|
7
|
+
Foundation, either version 3 of the License, or (at your option) any later
|
|
8
|
+
version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful, but
|
|
11
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
13
|
+
See the GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License along with
|
|
16
|
+
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.makePlatformDeviceFS = makePlatformDeviceFS;
|
|
20
|
+
const fs_1 = require("fs");
|
|
21
|
+
const file_1 = require("../lib-common/exceptions/file");
|
|
22
|
+
function makeFileExceptionFromNodesAndThrow(nodeExc) {
|
|
23
|
+
throw (0, file_1.makeFileExceptionFromCode)(nodeExc.code, nodeExc.path, undefined, 1);
|
|
24
|
+
}
|
|
25
|
+
function wrapNodeFn(nodePromisingFn) {
|
|
26
|
+
return function wrapOfNodePromisingFn(...args) {
|
|
27
|
+
return nodePromisingFn.call(undefined, ...args).catch(makeFileExceptionFromNodesAndThrow);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function makePlatformDeviceFS() {
|
|
31
|
+
return {
|
|
32
|
+
readFile: wrapNodeFn(fs_1.promises.readFile),
|
|
33
|
+
writeFile: wrapNodeFn(fs_1.promises.writeFile),
|
|
34
|
+
appendFile: wrapNodeFn(fs_1.promises.appendFile),
|
|
35
|
+
mkdir: wrapNodeFn(fs_1.promises.mkdir),
|
|
36
|
+
open: wrapNodeFn(fs_1.promises.open),
|
|
37
|
+
symlink: wrapNodeFn(fs_1.promises.symlink),
|
|
38
|
+
readlink: wrapNodeFn(fs_1.promises.readlink),
|
|
39
|
+
lstat: wrapNodeFn(fs_1.promises.lstat),
|
|
40
|
+
stat: wrapNodeFn(fs_1.promises.stat),
|
|
41
|
+
readdir: wrapNodeFn(fs_1.promises.readdir),
|
|
42
|
+
rmdir: wrapNodeFn(fs_1.promises.rmdir),
|
|
43
|
+
unlink: wrapNodeFn(fs_1.promises.unlink),
|
|
44
|
+
rename: wrapNodeFn(fs_1.promises.rename),
|
|
45
|
+
truncate: wrapNodeFn(fs_1.promises.truncate),
|
|
46
|
+
copyFile: (src, dst, overwrite = false, dstMode = '660') => {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const srcStream = (0, fs_1.createReadStream)(src);
|
|
49
|
+
const dstStream = (0, fs_1.createWriteStream)(dst, {
|
|
50
|
+
mode: parseInt(dstMode, 8),
|
|
51
|
+
flags: (overwrite ? 'w' : 'wx')
|
|
52
|
+
});
|
|
53
|
+
srcStream.pipe(dstStream);
|
|
54
|
+
dstStream.on('finish', () => {
|
|
55
|
+
resolve();
|
|
56
|
+
});
|
|
57
|
+
const isRejected = false;
|
|
58
|
+
const onErr = (err) => {
|
|
59
|
+
if (!isRejected) {
|
|
60
|
+
reject(err);
|
|
61
|
+
srcStream.unpipe();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
srcStream.on('error', onErr);
|
|
65
|
+
dstStream.on('error', onErr);
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
Object.freeze(exports);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { promises as fsFns } from 'fs';
|
|
2
|
+
export type { Stats } from 'fs';
|
|
3
|
+
export type { FileException } from '../lib-common/exceptions/file';
|
|
4
|
+
export type FileHandle = fsFns.FileHandle;
|
|
5
|
+
/**
|
|
6
|
+
* This should be injected at globalThis.platform.device_fs
|
|
7
|
+
*/
|
|
8
|
+
export interface PlatformDeviceFS {
|
|
9
|
+
readFile: typeof fsFns['readFile'];
|
|
10
|
+
writeFile: typeof fsFns['writeFile'];
|
|
11
|
+
appendFile: typeof fsFns['appendFile'];
|
|
12
|
+
mkdir: typeof fsFns['mkdir'];
|
|
13
|
+
open: typeof fsFns['open'];
|
|
14
|
+
symlink: typeof fsFns['symlink'];
|
|
15
|
+
readlink: typeof fsFns['readlink'];
|
|
16
|
+
lstat: typeof fsFns['lstat'];
|
|
17
|
+
stat: typeof fsFns['stat'];
|
|
18
|
+
readdir: typeof fsFns['readdir'];
|
|
19
|
+
rmdir: typeof fsFns['rmdir'];
|
|
20
|
+
unlink: typeof fsFns['unlink'];
|
|
21
|
+
rename: typeof fsFns['rename'];
|
|
22
|
+
truncate: typeof fsFns['truncate'];
|
|
23
|
+
/**
|
|
24
|
+
* This pipes source file into destination file.
|
|
25
|
+
* @param src
|
|
26
|
+
* @param dst
|
|
27
|
+
* @param overwrite
|
|
28
|
+
* @return a promise, resolvable when piping completes.
|
|
29
|
+
*/
|
|
30
|
+
copyFile(src: string, dst: string, overwrite?: boolean, dstMode?: string): Promise<void>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (C) 2026 3NSoft Inc.
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify it under
|
|
6
|
+
the terms of the GNU General Public License as published by the Free Software
|
|
7
|
+
Foundation, either version 3 of the License, or (at your option) any later
|
|
8
|
+
version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful, but
|
|
11
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
13
|
+
See the GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License along with
|
|
16
|
+
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
Object.freeze(exports);
|
|
@@ -1,22 +1,11 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
1
|
import { Readable, Writable } from 'stream';
|
|
3
|
-
|
|
4
|
-
export type { FileException } from '
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export declare const mkdir: typeof fs.promises.
|
|
10
|
-
export declare const open: typeof fs.promises.open;
|
|
11
|
-
export declare const symlink: typeof fs.promises.symlink;
|
|
12
|
-
export declare const readlink: typeof fs.promises.readlink;
|
|
13
|
-
export declare const lstat: typeof fs.promises.lstat;
|
|
14
|
-
export declare const stat: typeof fs.promises.stat;
|
|
15
|
-
export declare const readdir: typeof fs.promises.readdir;
|
|
16
|
-
export declare const rmdir: typeof fs.promises.rmdir;
|
|
17
|
-
export declare const unlink: typeof fs.promises.unlink;
|
|
18
|
-
export declare const rename: typeof fs.promises.rename;
|
|
19
|
-
export declare const truncate: typeof fs.promises.truncate;
|
|
2
|
+
import type { FileHandle } from '../injected-globals/platform-devfs';
|
|
3
|
+
export type { FileHandle, FileException, Stats } from '../injected-globals/platform-devfs';
|
|
4
|
+
/**
|
|
5
|
+
* fs functions follow node's type, and are injected via global object to allow injection in
|
|
6
|
+
* non-node environments, like Android or browser.
|
|
7
|
+
*/
|
|
8
|
+
export declare const appendFile: typeof import("fs/promises").appendFile, lstat: typeof import("fs/promises").lstat, mkdir: typeof import("fs/promises").mkdir, open: typeof import("fs/promises").open, readFile: typeof import("fs/promises").readFile, readdir: typeof import("fs/promises").readdir, readlink: typeof import("fs/promises").readlink, rename: typeof import("fs/promises").rename, rmdir: typeof import("fs/promises").rmdir, stat: typeof import("fs/promises").stat, symlink: typeof import("fs/promises").symlink, truncate: typeof import("fs/promises").truncate, unlink: typeof import("fs/promises").unlink, writeFile: typeof import("fs/promises").writeFile, copyFile: (src: string, dst: string, overwrite?: boolean, dstMode?: string) => Promise<void>;
|
|
20
9
|
/**
|
|
21
10
|
* @param fh is an open file handle
|
|
22
11
|
* @param pos is a position in the file, from which reading should start
|
|
@@ -53,16 +42,6 @@ export declare function createEmptyFile(filePath: string, fileSize: number, keep
|
|
|
53
42
|
* or false, if it does not.
|
|
54
43
|
*/
|
|
55
44
|
export declare function existsFolder(path: string): Promise<boolean>;
|
|
56
|
-
/**
|
|
57
|
-
* @param path
|
|
58
|
-
* @return true, if given path represents directory, or false, if it does not.
|
|
59
|
-
*/
|
|
60
|
-
export declare function existsFolderSync(path: string): boolean;
|
|
61
|
-
/**
|
|
62
|
-
* @param path
|
|
63
|
-
* @return true, if given path represents file, or false, if it does not.
|
|
64
|
-
*/
|
|
65
|
-
export declare function existsFileSync(path: string): boolean;
|
|
66
45
|
/**
|
|
67
46
|
* @param filePath
|
|
68
47
|
* @return a promise, resolvable to file's size.
|
|
@@ -126,26 +105,6 @@ export declare function rmDirWithContent(folder: string): Promise<void>;
|
|
|
126
105
|
* sink completes.
|
|
127
106
|
*/
|
|
128
107
|
export declare function streamFromFile(filePath: string, pos: number, len: number, sink: Writable, bufSize: number): Promise<void>;
|
|
129
|
-
/**
|
|
130
|
-
* This pipes source file into destination file.
|
|
131
|
-
* @param src
|
|
132
|
-
* @param dst
|
|
133
|
-
* @param overwrite
|
|
134
|
-
* @return a promise, resolvable when piping completes.
|
|
135
|
-
*/
|
|
136
|
-
export declare function copyFile(src: string, dst: string, overwrite?: boolean, dstMode?: string): Promise<void>;
|
|
137
|
-
/**
|
|
138
|
-
* This copies tree of files from source to destination folders.
|
|
139
|
-
* Target folders may exist in a destination tree.
|
|
140
|
-
* Objects that are neither files, nor folders, are ignored.
|
|
141
|
-
* @param src
|
|
142
|
-
* @param dst
|
|
143
|
-
* @param fileOverwrite when set to true, allows to overwrite files in a
|
|
144
|
-
* destination tree. Otherwise, exception is thrown on already existing files.
|
|
145
|
-
* @return a promise resolvable when the whole tree is copied from source to
|
|
146
|
-
* destination.
|
|
147
|
-
*/
|
|
148
|
-
export declare function copyTree(src: string, dst: string, fileOverwrite?: boolean): Promise<void>;
|
|
149
108
|
/**
|
|
150
109
|
* This function checks that given folder exists. If folder is not present,
|
|
151
110
|
* it is created, recreating whole folder tree, if needed.
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
You should have received a copy of the GNU General Public License along with
|
|
16
16
|
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
+
var _a;
|
|
19
|
+
var _b;
|
|
18
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.
|
|
21
|
+
exports.copyFile = exports.writeFile = exports.unlink = exports.truncate = exports.symlink = exports.stat = exports.rmdir = exports.rename = exports.readlink = exports.readdir = exports.readFile = exports.open = exports.mkdir = exports.lstat = exports.appendFile = void 0;
|
|
20
22
|
exports.readToBuf = readToBuf;
|
|
21
23
|
exports.writeFromBuf = writeFromBuf;
|
|
22
24
|
exports.createEmptyFile = createEmptyFile;
|
|
23
25
|
exports.existsFolder = existsFolder;
|
|
24
|
-
exports.existsFolderSync = existsFolderSync;
|
|
25
|
-
exports.existsFileSync = existsFileSync;
|
|
26
26
|
exports.getFileSize = getFileSize;
|
|
27
27
|
exports.getFolderContentSize = getFolderContentSize;
|
|
28
28
|
exports.write = write;
|
|
@@ -31,40 +31,21 @@ exports.streamToExistingFile = streamToExistingFile;
|
|
|
31
31
|
exports.read = read;
|
|
32
32
|
exports.rmDirWithContent = rmDirWithContent;
|
|
33
33
|
exports.streamFromFile = streamFromFile;
|
|
34
|
-
exports.copyFile = copyFile;
|
|
35
|
-
exports.copyTree = copyTree;
|
|
36
34
|
exports.ensureFolderExists = ensureFolderExists;
|
|
37
|
-
const fs = require("fs");
|
|
38
|
-
const fs_1 = require("fs");
|
|
39
35
|
const file_1 = require("./exceptions/file");
|
|
40
36
|
const synced_1 = require("./processes/synced");
|
|
41
37
|
const deferred_1 = require("./processes/deferred");
|
|
42
38
|
const bytes_fifo_buffer_1 = require("./byte-streaming/bytes-fifo-buffer");
|
|
43
39
|
const buffer_utils_1 = require("./buffer-utils");
|
|
44
|
-
const path_1 = require("path");
|
|
45
|
-
function makeFileExceptionFromNodesAndThrow(nodeExc) {
|
|
46
|
-
throw (0, file_1.makeFileExceptionFromCode)(nodeExc.code, nodeExc.path, undefined, 1);
|
|
47
|
-
}
|
|
48
|
-
function wrapNodeFn(nodePromisingFn) {
|
|
49
|
-
return function wrapOfNodePromisingFn(...args) {
|
|
50
|
-
return nodePromisingFn.call(undefined, ...args).catch(makeFileExceptionFromNodesAndThrow);
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
40
|
function noop() { }
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
exports.lstat =
|
|
62
|
-
exports.stat = wrapNodeFn(fs.promises.stat);
|
|
63
|
-
exports.readdir = wrapNodeFn(fs.promises.readdir);
|
|
64
|
-
exports.rmdir = wrapNodeFn(fs.promises.rmdir);
|
|
65
|
-
exports.unlink = wrapNodeFn(fs.promises.unlink);
|
|
66
|
-
exports.rename = wrapNodeFn(fs.promises.rename);
|
|
67
|
-
exports.truncate = wrapNodeFn(fs.promises.truncate);
|
|
41
|
+
if (!((_b = globalThis.platform) === null || _b === void 0 ? void 0 : _b.device_fs)) {
|
|
42
|
+
throw new Error(`Expected globally injected object globalThis.platform?.device_fs is missing`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* fs functions follow node's type, and are injected via global object to allow injection in
|
|
46
|
+
* non-node environments, like Android or browser.
|
|
47
|
+
*/
|
|
48
|
+
_a = globalThis.platform.device_fs, exports.appendFile = _a.appendFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readFile = _a.readFile, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.truncate = _a.truncate, exports.unlink = _a.unlink, exports.writeFile = _a.writeFile, exports.copyFile = _a.copyFile;
|
|
68
49
|
/**
|
|
69
50
|
* @param fh is an open file handle
|
|
70
51
|
* @param pos is a position in the file, from which reading should start
|
|
@@ -164,46 +145,6 @@ async function existsFolder(path) {
|
|
|
164
145
|
throw e;
|
|
165
146
|
}
|
|
166
147
|
}
|
|
167
|
-
/**
|
|
168
|
-
* @param path
|
|
169
|
-
* @return true, if given path represents directory, or false, if it does not.
|
|
170
|
-
*/
|
|
171
|
-
function existsFolderSync(path) {
|
|
172
|
-
try {
|
|
173
|
-
if ((0, fs_1.statSync)(path).isDirectory()) {
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
throw (0, file_1.makeFileException)('notDirectory', path);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
catch (e) {
|
|
181
|
-
if (e.code === file_1.Code.notFound) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
throw e;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* @param path
|
|
189
|
-
* @return true, if given path represents file, or false, if it does not.
|
|
190
|
-
*/
|
|
191
|
-
function existsFileSync(path) {
|
|
192
|
-
try {
|
|
193
|
-
if ((0, fs_1.statSync)(path).isFile()) {
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
throw (0, file_1.makeFileException)('notFile', path);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
catch (e) {
|
|
201
|
-
if (e.code === file_1.Code.notFound) {
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
throw e;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
148
|
/**
|
|
208
149
|
* @param filePath
|
|
209
150
|
* @return a promise, resolvable to file's size.
|
|
@@ -485,73 +426,6 @@ async function streamFromFile(filePath, pos, len, sink, bufSize) {
|
|
|
485
426
|
byteCount += buf.length;
|
|
486
427
|
}
|
|
487
428
|
}
|
|
488
|
-
/**
|
|
489
|
-
* This pipes source file into destination file.
|
|
490
|
-
* @param src
|
|
491
|
-
* @param dst
|
|
492
|
-
* @param overwrite
|
|
493
|
-
* @return a promise, resolvable when piping completes.
|
|
494
|
-
*/
|
|
495
|
-
function copyFile(src, dst, overwrite = false, dstMode = '660') {
|
|
496
|
-
return new Promise((resolve, reject) => {
|
|
497
|
-
const srcStream = (0, fs_1.createReadStream)(src);
|
|
498
|
-
const dstStream = (0, fs_1.createWriteStream)(dst, {
|
|
499
|
-
mode: parseInt(dstMode, 8),
|
|
500
|
-
flags: (overwrite ? 'w' : 'wx')
|
|
501
|
-
});
|
|
502
|
-
srcStream.pipe(dstStream);
|
|
503
|
-
dstStream.on('finish', () => {
|
|
504
|
-
resolve();
|
|
505
|
-
});
|
|
506
|
-
const isRejected = false;
|
|
507
|
-
const onErr = (err) => {
|
|
508
|
-
if (!isRejected) {
|
|
509
|
-
reject(err);
|
|
510
|
-
srcStream.unpipe();
|
|
511
|
-
}
|
|
512
|
-
};
|
|
513
|
-
srcStream.on('error', onErr);
|
|
514
|
-
dstStream.on('error', onErr);
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
/**
|
|
518
|
-
* This copies tree of files from source to destination folders.
|
|
519
|
-
* Target folders may exist in a destination tree.
|
|
520
|
-
* Objects that are neither files, nor folders, are ignored.
|
|
521
|
-
* @param src
|
|
522
|
-
* @param dst
|
|
523
|
-
* @param fileOverwrite when set to true, allows to overwrite files in a
|
|
524
|
-
* destination tree. Otherwise, exception is thrown on already existing files.
|
|
525
|
-
* @return a promise resolvable when the whole tree is copied from source to
|
|
526
|
-
* destination.
|
|
527
|
-
*/
|
|
528
|
-
async function copyTree(src, dst, fileOverwrite = false) {
|
|
529
|
-
// destination folder, non-exclusively
|
|
530
|
-
await (0, exports.mkdir)(dst, { recursive: true })
|
|
531
|
-
.catch(async (exc) => {
|
|
532
|
-
if (!exc.alreadyExists) {
|
|
533
|
-
throw exc;
|
|
534
|
-
}
|
|
535
|
-
});
|
|
536
|
-
// copy files and folders from src folder
|
|
537
|
-
const srcFNames = await (0, exports.readdir)(src);
|
|
538
|
-
const cpTasks = [];
|
|
539
|
-
for (const fName of srcFNames) {
|
|
540
|
-
const srcPath = (0, path_1.join)(src, fName);
|
|
541
|
-
const dstPath = (0, path_1.join)(dst, fName);
|
|
542
|
-
const task = (0, exports.stat)(srcPath)
|
|
543
|
-
.then((stats) => {
|
|
544
|
-
if (stats.isFile()) {
|
|
545
|
-
return copyFile(srcPath, dstPath, fileOverwrite);
|
|
546
|
-
}
|
|
547
|
-
else if (stats.isDirectory()) {
|
|
548
|
-
return copyTree(srcPath, dstPath, fileOverwrite);
|
|
549
|
-
}
|
|
550
|
-
});
|
|
551
|
-
cpTasks.push(task);
|
|
552
|
-
}
|
|
553
|
-
await Promise.all(cpTasks);
|
|
554
|
-
}
|
|
555
429
|
/**
|
|
556
430
|
* This function checks that given folder exists. If folder is not present,
|
|
557
431
|
* it is created, recreating whole folder tree, if needed.
|
package/build/tests/jasmine.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2016, 2020 - 2022, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2016, 2020 - 2022, 2025 - 2026 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
const jasmine = require("jasmine");
|
|
20
|
+
const inject_on_node_1 = require("../injected-globals/inject-on-node");
|
|
21
|
+
// injecting global's expected to be on node
|
|
22
|
+
globalThis.platform = {
|
|
23
|
+
device_fs: (0, inject_on_node_1.makePlatformDeviceFS)()
|
|
24
|
+
};
|
|
20
25
|
const jas = new jasmine({});
|
|
21
26
|
const specsFromCLI = [];
|
|
22
27
|
for (let i = 2; i < process.argv.length; i += 1) {
|
|
@@ -60,7 +60,7 @@ describe('ObjFolders without timed generations', () => {
|
|
|
60
60
|
await (0, async_fs_node_1.rmDirWithContent)(TEST_DATA);
|
|
61
61
|
});
|
|
62
62
|
(0, jasmine_utils_1.itCond)(`static folder content`, async () => {
|
|
63
|
-
expect((0, async_fs_node_1.
|
|
63
|
+
expect(await (0, async_fs_node_1.existsFolder)((0, path_1.join)(TEST_DATA, ACCESS_DIR))).toBeTrue();
|
|
64
64
|
const cfg = await readJSONFile((0, path_1.join)(TEST_DATA, CONFIG_FILE));
|
|
65
65
|
expect(cfg.charsInSplit).withContext('default config value').toBe(charsInSplit);
|
|
66
66
|
expect(cfg.numOfSplits).withContext('default config value').toBe(numOfSplits);
|
|
@@ -68,13 +68,13 @@ describe('ObjFolders without timed generations', () => {
|
|
|
68
68
|
(0, jasmine_utils_1.itCond)(`null id for root object`, async () => {
|
|
69
69
|
const rootObjPath = (0, path_1.join)(objsDir, ROOT_OBJ_DIR);
|
|
70
70
|
// behaviour with missing obj folder and no creation
|
|
71
|
-
expect((0, async_fs_node_1.
|
|
71
|
+
expect(await (0, async_fs_node_1.existsFolder)(rootObjPath)).not.toBeTrue();
|
|
72
72
|
let folderPath = await folders.getFolderAccessFor(null);
|
|
73
73
|
expect(folderPath).withContext(`obj folder not present, and is not created`).toBeUndefined();
|
|
74
|
-
expect((0, async_fs_node_1.
|
|
74
|
+
expect(await (0, async_fs_node_1.existsFolder)(rootObjPath)).not.toBeTrue();
|
|
75
75
|
folderPath = await folders.getFolderAccessFor(null, true);
|
|
76
76
|
expect(folderPath).toBe(rootObjPath);
|
|
77
|
-
expect((0, async_fs_node_1.
|
|
77
|
+
expect(await (0, async_fs_node_1.existsFolder)(folderPath)).toBeTrue();
|
|
78
78
|
await writeFilesTo(folderPath, 4);
|
|
79
79
|
// behaviour with exiting obj folder
|
|
80
80
|
let existingPath = await folders.getFolderAccessFor(null);
|
|
@@ -95,11 +95,11 @@ describe('ObjFolders without timed generations', () => {
|
|
|
95
95
|
const sameThirdIdPart = idA.slice(charsInSplit * 2, charsInSplit * 3);
|
|
96
96
|
const fstDepthCount = await numOfItemsIn(objsDir);
|
|
97
97
|
// behaviour with missing obj folder and no creation
|
|
98
|
-
expect((0, async_fs_node_1.
|
|
98
|
+
expect(await (0, async_fs_node_1.existsFolder)((0, path_1.join)(objsDir, sameFstIdPart))).not.toBeTrue();
|
|
99
99
|
let folderA = await folders.getFolderAccessFor(idA);
|
|
100
100
|
expect(folderA).withContext(`obj folder not present, and is not created`).toBeUndefined();
|
|
101
101
|
folderA = await folders.getFolderAccessFor(idA, true);
|
|
102
|
-
expect((0, async_fs_node_1.
|
|
102
|
+
expect(await (0, async_fs_node_1.existsFolder)(folderA)).toBeTrue();
|
|
103
103
|
expect((0, path_1.basename)(folderA)).toBe(idA.slice(numOfSplits * charsInSplit));
|
|
104
104
|
const threeLevelsDown = (0, path_1.join)(objsDir, sameFstIdPart, sameSndIdPart, sameThirdIdPart);
|
|
105
105
|
expect(await numOfItemsIn(threeLevelsDown)).toBe(1);
|
|
@@ -110,18 +110,18 @@ describe('ObjFolders without timed generations', () => {
|
|
|
110
110
|
existingPath = await folders.getFolderAccessFor(idA);
|
|
111
111
|
expect(existingPath).toBe(folderA);
|
|
112
112
|
expect(await numOfItemsIn(objsDir)).toBe(fstDepthCount + 1);
|
|
113
|
-
expect((0, async_fs_node_1.
|
|
113
|
+
expect(await (0, async_fs_node_1.existsFolder)((0, path_1.join)(objsDir, sameFstIdPart))).toBeTrue();
|
|
114
114
|
const twoLevelsDown = (0, path_1.join)(objsDir, sameFstIdPart, sameSndIdPart);
|
|
115
115
|
const thirdDepthCount = await numOfItemsIn(twoLevelsDown);
|
|
116
116
|
const folderB = await folders.getFolderAccessFor(idB, true);
|
|
117
|
-
expect((0, async_fs_node_1.
|
|
117
|
+
expect(await (0, async_fs_node_1.existsFolder)(folderB)).toBeTrue();
|
|
118
118
|
expect((0, path_1.basename)(folderB)).toBe(idB.slice(numOfSplits * charsInSplit));
|
|
119
119
|
expect(await numOfItemsIn(objsDir)).toBe(fstDepthCount + 1);
|
|
120
120
|
expect(await numOfItemsIn(twoLevelsDown)).toBe(thirdDepthCount);
|
|
121
121
|
expect(await numOfItemsIn(threeLevelsDown)).toBe(2);
|
|
122
122
|
await writeFilesTo(folderB, 4);
|
|
123
123
|
const folderC = await folders.getFolderAccessFor(idC, true);
|
|
124
|
-
expect((0, async_fs_node_1.
|
|
124
|
+
expect(await (0, async_fs_node_1.existsFolder)(folderC)).toBeTrue();
|
|
125
125
|
expect((0, path_1.basename)(folderC)).toBe(idC.slice(numOfSplits * charsInSplit));
|
|
126
126
|
expect(await numOfItemsIn(objsDir)).toBe(fstDepthCount + 1);
|
|
127
127
|
expect(await numOfItemsIn(twoLevelsDown)).toBe(thirdDepthCount + 1);
|