fake-node 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/lib/_fs.d.ts +254 -0
- package/lib/_fs.js +750 -0
- package/lib/_fs.js.map +1 -0
- package/lib/buffer.d.ts +9 -0
- package/lib/buffer.js +12 -0
- package/lib/buffer.js.map +1 -0
- package/lib/fs.d.ts +110 -0
- package/lib/fs.js +223 -0
- package/lib/fs.js.map +1 -0
- package/lib/index.d.ts +80 -0
- package/lib/index.js +311 -0
- package/lib/index.js.map +1 -0
- package/lib/os.d.ts +191 -0
- package/lib/os.js +261 -0
- package/lib/os.js.map +1 -0
- package/lib/path.d.ts +55 -0
- package/lib/path.js +105 -0
- package/lib/path.js.map +1 -0
- package/lib/process.d.ts +103 -0
- package/lib/process.js +216 -0
- package/lib/process.js.map +1 -0
- package/lib/querystring.d.ts +7 -0
- package/lib/querystring.js +39 -0
- package/lib/querystring.js.map +1 -0
- package/lib/util.d.ts +145 -0
- package/lib/util.js +460 -0
- package/lib/util.js.map +1 -0
- package/lib/web_only_globals.json +1049 -0
- package/package.json +12 -13
- package/src/_fs.ts +852 -0
- package/src/buffer.ts +13 -0
- package/src/fs.ts +230 -0
- package/src/in_fake_node.d.ts +12 -0
- package/src/index.ts +321 -0
- package/src/os.ts +259 -0
- package/src/path.ts +141 -0
- package/src/process.ts +245 -0
- package/src/querystring.ts +36 -0
- package/src/util.ts +521 -0
- package/index.js +0 -171
- package/index.ts +0 -148
- package/tsconfig.json +0 -10
- /package/{web_only_globals.json → src/web_only_globals.json} +0 -0
package/src/buffer.ts
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
const Blob_ = Blob;
|
3
|
+
export {Blob_ as Blob};
|
4
|
+
|
5
|
+
export type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex";
|
6
|
+
|
7
|
+
export class Buffer extends Uint8Array {
|
8
|
+
|
9
|
+
toString(encoding: BufferEncoding = 'utf-8'): string {
|
10
|
+
return (new TextDecoder(encoding)).decode(this);
|
11
|
+
}
|
12
|
+
|
13
|
+
}
|
package/src/fs.ts
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
|
2
|
+
/// <reference path="./in_fake_node.d.ts" />
|
3
|
+
import {type TypedArray} from './util';
|
4
|
+
import {dirname, basename, resolve} from './path';
|
5
|
+
import {Buffer, type BufferEncoding} from './buffer';
|
6
|
+
import {constants, parsePathArg, Directory, FileSystem} from './_fs';
|
7
|
+
import type {PathArg, ModeArg, DataArg, TimeArg, Flag, Stats, BigIntStats, StatFs, BigIntStatFs} from './_fs';
|
8
|
+
|
9
|
+
export {constants} from './_fs';
|
10
|
+
|
11
|
+
export {Stats, BigIntStats, StatFs, BigIntStatFs} from './_fs';
|
12
|
+
|
13
|
+
export function accessSync(path: PathArg, mode: number = constants.F_OK) {
|
14
|
+
__fakeNode__.fs.get(path).access(mode);
|
15
|
+
}
|
16
|
+
|
17
|
+
export function appendFileSync(path: PathArg, data: DataArg, {encoding = 'utf8', mode = 0o666, flag = 'a'}: {encoding?: BufferEncoding, mode: number, flag: string}) {
|
18
|
+
__fakeNode__.fs.getRegular(path).append(data, encoding);
|
19
|
+
}
|
20
|
+
|
21
|
+
export function chmodSync(path: PathArg, mode: ModeArg): void {
|
22
|
+
__fakeNode__.fs.get(path).chmod(mode);
|
23
|
+
}
|
24
|
+
|
25
|
+
export function chownSync(path: PathArg, uid: number, gid: number): void {
|
26
|
+
__fakeNode__.fs.get(path).chown(uid, gid);
|
27
|
+
}
|
28
|
+
|
29
|
+
export function closeSync(fd: number): void {
|
30
|
+
__fakeNode__.fs.fileDescriptors[fd] = null;
|
31
|
+
}
|
32
|
+
|
33
|
+
export function copyFileSync(src: PathArg, dest: PathArg, mode: number = 0): void {
|
34
|
+
if ((mode & constants.COPYFILE_EXCL) === constants.COPYFILE_EXCL && __fakeNode__.fs.exists(dest)) {
|
35
|
+
throw new TypeError(`${dest} exists`);
|
36
|
+
}
|
37
|
+
if ((mode & constants.COPYFILE_FICLONE_FORCE) === constants.COPYFILE_FICLONE_FORCE) {
|
38
|
+
throw new TypeError('fake-node does not support copy-on-write');
|
39
|
+
}
|
40
|
+
__fakeNode__.fs.getRegular(dest).write(__fakeNode__.fs.getRegular(src).read());
|
41
|
+
}
|
42
|
+
|
43
|
+
export function existsSync(path: PathArg): boolean {
|
44
|
+
return __fakeNode__.fs.exists(path);
|
45
|
+
}
|
46
|
+
|
47
|
+
export function fchmodSync(fd: number, mode: ModeArg): void {
|
48
|
+
__fakeNode__.fs.getfd(fd).chmod(mode);
|
49
|
+
}
|
50
|
+
|
51
|
+
export function fchownsync(fd: number, uid: number, gid: number): void {
|
52
|
+
__fakeNode__.fs.getfd(fd).chown(uid, gid);
|
53
|
+
}
|
54
|
+
|
55
|
+
export function fdatasyncSync(fd: number): void {
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
|
59
|
+
export function fstatSync(fd: number): Stats {
|
60
|
+
return __fakeNode__.fs.getfd(fd).stat();
|
61
|
+
}
|
62
|
+
|
63
|
+
export function fsyncSync(fd: number): void {
|
64
|
+
return;
|
65
|
+
}
|
66
|
+
|
67
|
+
export function ftruncateSync(fd: number, len: number): void {
|
68
|
+
let file = __fakeNode__.fs.getfdRegular(fd);
|
69
|
+
file.data = file.data.slice(0, len);
|
70
|
+
}
|
71
|
+
|
72
|
+
export function futimesSync(fd: number, atime: TimeArg, ctime: TimeArg): void {
|
73
|
+
__fakeNode__.fs.getfd(fd).utimes(atime, ctime);
|
74
|
+
}
|
75
|
+
|
76
|
+
export function globSync(pattern: string | string[]): string[] {
|
77
|
+
throw new TypeError('globs are not supported in fake-node');
|
78
|
+
}
|
79
|
+
|
80
|
+
export function lchmodSync(path: PathArg, mode: number): void {
|
81
|
+
__fakeNode__.fs.lget(path).chmod(mode);
|
82
|
+
}
|
83
|
+
|
84
|
+
export function lchownSync(path: PathArg, uid: number, gid: number): void {
|
85
|
+
__fakeNode__.fs.lget(path).chown(uid, gid);
|
86
|
+
}
|
87
|
+
|
88
|
+
export function lutimesSync(path: PathArg, atime: TimeArg, mtime: TimeArg): void {
|
89
|
+
__fakeNode__.fs.lget(path).utimes(atime, mtime);
|
90
|
+
}
|
91
|
+
|
92
|
+
export function linkSync(existingPath: PathArg, newPath: PathArg): void {
|
93
|
+
__fakeNode__.fs.getDir(dirname(parsePathArg(existingPath))).link(basename(parsePathArg(newPath)), __fakeNode__.fs.get(existingPath));
|
94
|
+
}
|
95
|
+
|
96
|
+
export function lstatSync(path: PathArg, {bigint, throwIfNoEntry}: {bigint?: false, throwIfNoEntry: false}): Stats;
|
97
|
+
export function lstatSync(path: PathArg, {bigint, throwIfNoEntry}: {bigint?: false, throwIfNoEntry: true}): Stats | undefined;
|
98
|
+
export function lstatSync(path: PathArg, {bigint, throwIfNoEntry}: {bigint?: true, throwIfNoEntry: false}): BigIntStats;
|
99
|
+
export function lstatSync(path: PathArg, {bigint, throwIfNoEntry}: {bigint?: true, throwIfNoEntry: true}): BigIntStats | undefined;
|
100
|
+
export function lstatSync(path: PathArg, {bigint = false, throwIfNoEntry = false}: {bigint?: boolean, throwIfNoEntry?: boolean} = {}): Stats | BigIntStats | undefined {
|
101
|
+
if (!throwIfNoEntry && !__fakeNode__.fs.exists(path)) {
|
102
|
+
return undefined;
|
103
|
+
}
|
104
|
+
// @ts-ignore // why is it doing this
|
105
|
+
return __fakeNode__.fs.lget(path).stat(bigint);
|
106
|
+
}
|
107
|
+
|
108
|
+
export function mkdirSync(path: PathArg, options: {recursive?: boolean, mode?: ModeArg} | ModeArg = 0o777): void {
|
109
|
+
let recursive: boolean;
|
110
|
+
let mode: ModeArg;
|
111
|
+
if (typeof options === 'number' || typeof options === 'string') {
|
112
|
+
recursive = false;
|
113
|
+
mode = options;
|
114
|
+
} else {
|
115
|
+
recursive = options.recursive ?? false;
|
116
|
+
mode = options.mode ?? 0o777;
|
117
|
+
}
|
118
|
+
__fakeNode__.fs.mkdir(path, recursive, mode);
|
119
|
+
}
|
120
|
+
|
121
|
+
export function mkdtempSync(prefix: PathArg, options: {encoding?: string} | string = 'utf8'): void {
|
122
|
+
throw new TypeError('fs.mkdtemp is not supported in fake-node');
|
123
|
+
}
|
124
|
+
|
125
|
+
export function opendirSync(path: PathArg, {encoding = 'utf8', bufferSize = 32, recursive = false}: {encoding?: string, bufferSize?: number, recursive?: boolean} = {}): void {
|
126
|
+
throw new TypeError('fs.opendir is not supported in fake-node');
|
127
|
+
}
|
128
|
+
|
129
|
+
export function openSync(path: PathArg, flags: Flag, mode: ModeArg = 'r'): number {
|
130
|
+
return __fakeNode__.fs.open(path, flags, mode);
|
131
|
+
}
|
132
|
+
|
133
|
+
export function readdirSync(path: PathArg, options: {encoding?: string, withFileTypes?: boolean, recursive?: boolean} | string = 'utf8') {
|
134
|
+
throw new TypeError('fs.readdir is not supported in fake-node');
|
135
|
+
}
|
136
|
+
|
137
|
+
export function readFileSync(path: PathArg, options: {encoding?: null | 'buffer', flag?: string} | 'buffer'): Buffer;
|
138
|
+
export function readFileSync(path: PathArg, options: {encoding: BufferEncoding, flag?: string} | BufferEncoding): string;
|
139
|
+
export function readFileSync(path: PathArg, options: {encoding?: BufferEncoding | null | 'buffer', flag?: string} | BufferEncoding | 'buffer' = {encoding: null, flag: 'r'}): string | Buffer {
|
140
|
+
// @ts-ignore // why is it doing this
|
141
|
+
return __fakeNode__.fs.getRegular(path).read(typeof options === 'string' ? options : options.encoding ?? 'buffer');
|
142
|
+
}
|
143
|
+
|
144
|
+
export function readlinkSync(path: PathArg, options: {encoding?: string} | string = 'utf8'): string | Buffer {
|
145
|
+
throw new TypeError('fs.readlink is not supported in fake-node');
|
146
|
+
}
|
147
|
+
|
148
|
+
export function readSync(fd: number, buffer: Buffer | TypedArray | DataView, offset: number, length: number, position: number | bigint | null = null): number {
|
149
|
+
position = Number(position ?? 0);
|
150
|
+
const data = __fakeNode__.fs.getfdRegular(fd).read('uint8array', offset, length);
|
151
|
+
if (buffer instanceof DataView) {
|
152
|
+
for (let i = position; i < data.length; i++) {
|
153
|
+
buffer.setUint8(i, data[i]);
|
154
|
+
}
|
155
|
+
} else {
|
156
|
+
// @ts-ignore // why is it doing this
|
157
|
+
buffer.set(data, position);
|
158
|
+
}
|
159
|
+
return length;
|
160
|
+
}
|
161
|
+
|
162
|
+
export function readvSync(fd: number, buffers: ArrayBufferView[], position: number | null = null): number {
|
163
|
+
throw new TypeError('fs.readv is not supported in fake-node');
|
164
|
+
}
|
165
|
+
|
166
|
+
export function realpathSync(path: PathArg, {encoding}: {encoding: string} = {encoding: 'utf8'}): string {
|
167
|
+
return resolve(parsePathArg(path));
|
168
|
+
}
|
169
|
+
realpathSync.native = realpathSync;
|
170
|
+
|
171
|
+
export function renameSync(oldPath: PathArg, newPath: PathArg): void {
|
172
|
+
const parsedOldPath = parsePathArg(oldPath);
|
173
|
+
const parsedNewPath = parsePathArg(newPath);
|
174
|
+
const file = __fakeNode__.fs.getDir(dirname(parsedOldPath)).unlink(basename(parsedOldPath));
|
175
|
+
__fakeNode__.fs.getDir(dirname(parsedNewPath)).link(basename(parsedNewPath), file);
|
176
|
+
}
|
177
|
+
|
178
|
+
export function rmdirSync(path: PathArg): void {
|
179
|
+
const file = __fakeNode__.fs.get(path);
|
180
|
+
if (!(file instanceof Directory)) {
|
181
|
+
throw new TypeError(`cannot remove directory ${path}: is not a directory`);
|
182
|
+
} else if (!(file.size === 0)) {
|
183
|
+
throw new TypeError(`cannot remove directory ${path}: is not empty`);
|
184
|
+
}
|
185
|
+
__fakeNode__.fs.unlink(path);
|
186
|
+
}
|
187
|
+
|
188
|
+
export function rmSync(path: PathArg): void {
|
189
|
+
__fakeNode__.fs.unlink(path);
|
190
|
+
}
|
191
|
+
|
192
|
+
export function statSync(path: PathArg, {bigint, throwIfNoEntry}: {bigint?: false, throwIfNoEntry: false}): Stats;
|
193
|
+
export function statSync(path: PathArg, {bigint, throwIfNoEntry}: {bigint?: false, throwIfNoEntry: true}): Stats | undefined;
|
194
|
+
export function statSync(path: PathArg, {bigint, throwIfNoEntry}: {bigint?: true, throwIfNoEntry: false}): BigIntStats;
|
195
|
+
export function statSync(path: PathArg, {bigint, throwIfNoEntry}: {bigint?: true, throwIfNoEntry: true}): BigIntStats | undefined;
|
196
|
+
export function statSync(path: PathArg, {bigint = false, throwIfNoEntry = false}: {bigint?: boolean, throwIfNoEntry?: boolean} = {}): Stats | BigIntStats | undefined {
|
197
|
+
if (!throwIfNoEntry && !__fakeNode__.fs.exists(path)) {
|
198
|
+
return undefined;
|
199
|
+
}
|
200
|
+
// @ts-ignore // why is it doing this
|
201
|
+
return __fakeNode__.fs.get(path).stat(bigint);
|
202
|
+
}
|
203
|
+
|
204
|
+
export function statfsSync(path: PathArg, {bigint}: {bigint?: false}): StatFs;
|
205
|
+
export function statfsSync(path: PathArg, {bigint}: {bigint?: true}): BigIntStatFs;
|
206
|
+
export function statfsSync(path: PathArg, {bigint = false}: {bigint?: boolean} = {}): StatFs | BigIntStatFs {
|
207
|
+
let file = __fakeNode__.fs.get(path);
|
208
|
+
if (!(file instanceof FileSystem)) {
|
209
|
+
throw new TypeError(`cannot get fs stat for ${path}: is not a file system`);
|
210
|
+
}
|
211
|
+
// @ts-ignore // why is it doing this
|
212
|
+
return file.statfs(bigint);
|
213
|
+
}
|
214
|
+
|
215
|
+
export function symlinkSync(target: PathArg, path: PathArg): void {
|
216
|
+
__fakeNode__.fs.symlink(target, path);
|
217
|
+
}
|
218
|
+
|
219
|
+
export function truncateSync(path: PathArg, len: number = 0): void {
|
220
|
+
let file = __fakeNode__.fs.getRegular(path);
|
221
|
+
file.data = file.data.slice(0, len);
|
222
|
+
}
|
223
|
+
|
224
|
+
export function unlinkSync(path: PathArg): void {
|
225
|
+
__fakeNode__.fs.unlink(path);
|
226
|
+
}
|
227
|
+
|
228
|
+
export function utimesSync(path: PathArg, atime: TimeArg, mtime: TimeArg) {
|
229
|
+
__fakeNode__.fs.get(path).utimes(atime, mtime);
|
230
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
import {FakeNode, Process} from './index';
|
3
|
+
|
4
|
+
declare global {
|
5
|
+
var __fakeNode__: FakeNode;
|
6
|
+
var __fakeNode_process__: Process;
|
7
|
+
var module: {
|
8
|
+
exports: {[key: string]: any},
|
9
|
+
};
|
10
|
+
var exports: {[key: string]: any};
|
11
|
+
var require: typeof FakeNode.prototype.require;
|
12
|
+
}
|
package/src/index.ts
ADDED
@@ -0,0 +1,321 @@
|
|
1
|
+
|
2
|
+
import * as baseProcessObject from './process';
|
3
|
+
import {FileSystem} from './_fs';
|
4
|
+
import * as module_os from './os';
|
5
|
+
import * as module_util from './util';
|
6
|
+
import * as module_querystring from './querystring';
|
7
|
+
import * as module_punycode from 'punycode/';
|
8
|
+
import * as module_path from './path';
|
9
|
+
import * as module_buffer from './buffer';
|
10
|
+
import * as module_fs from './fs';
|
11
|
+
import WEB_ONLY_GLOBALS from './web_only_globals.json';
|
12
|
+
|
13
|
+
|
14
|
+
export * as fs from './_fs';
|
15
|
+
|
16
|
+
|
17
|
+
const IS_BROWSER = (('window' in globalThis && window === globalThis && 'document' in window && 'navigator' in window && 'window' in window && window.window === window) || ('self' in globalThis && self === globalThis && typeof self.postMessage === 'function' && 'self' in self && self.self === self));
|
18
|
+
|
19
|
+
|
20
|
+
type BaseProcessObject = typeof import ('./process');
|
21
|
+
interface ProcessObject extends BaseProcessObject {
|
22
|
+
argv: string[];
|
23
|
+
argv0: string;
|
24
|
+
env: {[key: string]: string};
|
25
|
+
execArgv: string[];
|
26
|
+
execPath: string;
|
27
|
+
mainModule: string;
|
28
|
+
platform: string;
|
29
|
+
version: string;
|
30
|
+
versions: {[key: string]: string};
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
const BUILTIN_MODULES: [string, any][] = [
|
35
|
+
['os', module_os],
|
36
|
+
['util', module_util],
|
37
|
+
['querystring', module_querystring],
|
38
|
+
['punycode', module_punycode],
|
39
|
+
['path', module_path],
|
40
|
+
['buffer', module_buffer],
|
41
|
+
['fs', module_fs],
|
42
|
+
];
|
43
|
+
|
44
|
+
const DEFAULT_ENV = {
|
45
|
+
PATH: '/usr/local/bin:/usr/bin:/bin',
|
46
|
+
SHLVL: '1',
|
47
|
+
SHELL: '/bin/bash',
|
48
|
+
TERM: 'none',
|
49
|
+
PS1: '',
|
50
|
+
PS2: '> ',
|
51
|
+
HISTFILE: '~/.bash_history',
|
52
|
+
EDITOR: 'vim',
|
53
|
+
VISUAL: 'vim',
|
54
|
+
LANG: 'en_US.utf8',
|
55
|
+
HOSTNAME: 'fake-node',
|
56
|
+
TMPDIR: '/tmp',
|
57
|
+
};
|
58
|
+
|
59
|
+
|
60
|
+
export class Process {
|
61
|
+
|
62
|
+
fakeNode: FakeNode;
|
63
|
+
|
64
|
+
pid: number;
|
65
|
+
priority: number = 0;
|
66
|
+
|
67
|
+
uid: number = 0;
|
68
|
+
gid: number = 0;
|
69
|
+
groups: number[] = [];
|
70
|
+
cwd: string;
|
71
|
+
umask: number = 0o6440;
|
72
|
+
|
73
|
+
argv: string[] = [];
|
74
|
+
argv0: string = '';
|
75
|
+
execArgv: string[] = [];
|
76
|
+
execPath: string = '/usr/bin/local/node';
|
77
|
+
|
78
|
+
path: string;
|
79
|
+
module: false | string;
|
80
|
+
code?: string;
|
81
|
+
|
82
|
+
constructor(fakeNode: FakeNode, {path = '<anonymous>', code, module = false}: {path?: string, code?: string, module?: false | string}) {
|
83
|
+
this.fakeNode = fakeNode;
|
84
|
+
this.pid = fakeNode.nextPid;
|
85
|
+
fakeNode.nextPid++;
|
86
|
+
fakeNode.processes.set(this.pid, this);
|
87
|
+
this.path = path;
|
88
|
+
this.cwd = path.split('/').slice(0, -1).join('/');
|
89
|
+
this.module = module;
|
90
|
+
this.code = code;
|
91
|
+
}
|
92
|
+
|
93
|
+
get env(): {[key: string]: string} {
|
94
|
+
return this.fakeNode.getenv(this.pid);
|
95
|
+
}
|
96
|
+
|
97
|
+
run(): void {
|
98
|
+
let code = this.code;
|
99
|
+
if (code === undefined) {
|
100
|
+
code = this.fakeNode.fs.readFrom(this.path);
|
101
|
+
}
|
102
|
+
let injectCode: string;
|
103
|
+
if (this.module) {
|
104
|
+
injectCode = `with(${this.fakeNode.globalName}.getGlobals(${this.pid})){__fakeNode__.modules.set('${this.module},(function(){${code};return module.exports;})());}`;
|
105
|
+
} else {
|
106
|
+
injectCode = `with(${this.fakeNode.globalName}.getGlobals(${this.pid})){(function(){${code}})();}`;
|
107
|
+
}
|
108
|
+
let elt = document.createElement('script');
|
109
|
+
elt.textContent = injectCode;
|
110
|
+
document.body.appendChild(elt);
|
111
|
+
}
|
112
|
+
|
113
|
+
}
|
114
|
+
|
115
|
+
|
116
|
+
if (!('__fakeNode_next_instance_id__' in globalThis)) {
|
117
|
+
// @ts-ignore
|
118
|
+
globalThis.__fakeNode_next_instance_id__ = 0;
|
119
|
+
}
|
120
|
+
|
121
|
+
|
122
|
+
export class FakeNode {
|
123
|
+
|
124
|
+
version: string = '0.3.0';
|
125
|
+
versions: {[key: string]: string} = {
|
126
|
+
'fake-node': '0.3.0',
|
127
|
+
'punycode': '2.3.1',
|
128
|
+
};
|
129
|
+
|
130
|
+
id: number;
|
131
|
+
globalName: string;
|
132
|
+
|
133
|
+
fs: FileSystem;
|
134
|
+
|
135
|
+
processes: Map<number, Process> = new Map();
|
136
|
+
nextPid: number = 3;
|
137
|
+
|
138
|
+
globalenv: {[key: string]: string} = DEFAULT_ENV;
|
139
|
+
|
140
|
+
modules: Map<string, unknown> = new Map();
|
141
|
+
|
142
|
+
// @ts-ignore
|
143
|
+
window: Window;
|
144
|
+
|
145
|
+
errorCallbacks: (Function | undefined)[] = [];
|
146
|
+
|
147
|
+
constructor() {
|
148
|
+
// @ts-ignore
|
149
|
+
this.id = globalThis.__fakeNode_next_instance_id;
|
150
|
+
// @ts-ignore
|
151
|
+
globalThis.__fakeNode_next_instance_id++;
|
152
|
+
this.globalName = '__fakeNode_' + this.id + '__';
|
153
|
+
// @ts-ignore
|
154
|
+
globalThis[this.globalName] = this;
|
155
|
+
if (IS_BROWSER) {
|
156
|
+
this.window = window;
|
157
|
+
} else {
|
158
|
+
Object.defineProperty(this, 'window', {get() {throw new ReferenceError('fake-node is not running in a browser')}});
|
159
|
+
}
|
160
|
+
this.fs = new FileSystem();
|
161
|
+
window.addEventListener('error', ({error}) => this.onError(error));
|
162
|
+
window.addEventListener('unhandledrejection', ({reason}) => reason instanceof Error ? this.onError(reason) : this.onError(new Error(String(reason))));
|
163
|
+
for (const [name, module] of BUILTIN_MODULES) {
|
164
|
+
this.addModuleFromValue(name, module);
|
165
|
+
this.addModuleFromValue('node:' + name, module);
|
166
|
+
this.addModuleFromValue('fake-node:' + name, module);
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
require(module: string, pid: number): unknown {
|
171
|
+
if (module.startsWith('/') || module.startsWith('./') || module.startsWith('../')) {
|
172
|
+
const process = this.processes.get(pid);
|
173
|
+
if (process === undefined) {
|
174
|
+
throw new TypeError(`nonexistent PID in FakeNode.getProcessObject call: ${pid}. If you do not know why this occured, it is probably a bug in fake-node.`);
|
175
|
+
}
|
176
|
+
module = module_path.resolve(process.cwd, module);
|
177
|
+
}
|
178
|
+
if (this.modules.has(module)) {
|
179
|
+
return this.modules.get(module);
|
180
|
+
} else if (module === 'process' || module === 'node:process' || module === 'fake-node:process') {
|
181
|
+
return this.getProcessObject(pid);
|
182
|
+
} else {
|
183
|
+
throw new Error(`cannot find module '${module}'`);
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
addModuleFromValue(name: string, module: unknown): void {
|
188
|
+
this.modules.set(name, module);
|
189
|
+
}
|
190
|
+
|
191
|
+
eval(code: string): void {
|
192
|
+
(new Process(this, {code, path: '/'})).run();
|
193
|
+
}
|
194
|
+
|
195
|
+
evalModule(name: string, code: string): void {
|
196
|
+
(new Process(this, {code, path: '/', module: name})).run();
|
197
|
+
}
|
198
|
+
|
199
|
+
addModule(path: string, data: string): void {
|
200
|
+
this.fs.writeTo(path, data);
|
201
|
+
(new Process(this, {path, module: path}))
|
202
|
+
}
|
203
|
+
|
204
|
+
getProcessObject(pid: number): ProcessObject {
|
205
|
+
let out = Object.create(baseProcessObject);
|
206
|
+
const process = this.processes.get(pid);
|
207
|
+
if (process === undefined) {
|
208
|
+
throw new TypeError(`nonexistent PID in FakeNode.getProcessObject call: ${pid}. If you do not know why this occured, it is probably a bug in fake-node.`);
|
209
|
+
}
|
210
|
+
out.argv = process.argv;
|
211
|
+
out.argv0 = process.argv0;
|
212
|
+
out.env = process.env;
|
213
|
+
out.execArgv = process.execArgv;
|
214
|
+
out.execPath = process.execPath;
|
215
|
+
out.mainModule = '';
|
216
|
+
out.platform = this.getPlatform();
|
217
|
+
out.version = this.version;
|
218
|
+
out.versions = this.versions;
|
219
|
+
return out;
|
220
|
+
}
|
221
|
+
|
222
|
+
getGlobals(pid: number): object {
|
223
|
+
const process = this.processes.get(pid);
|
224
|
+
if (process === undefined) {
|
225
|
+
throw new TypeError(`nonexistent PID in FakeNode.getGlobals call: ${pid}. If you do not know why this occured, it is probably a bug in fake-node.`);
|
226
|
+
}
|
227
|
+
let scope = Object.assign({
|
228
|
+
__fakeNode__: this,
|
229
|
+
__fakeNode_process__: process,
|
230
|
+
require: ((module: string) => this.require(module, pid)).bind(this)
|
231
|
+
}, Object.defineProperties({}, Object.fromEntries(WEB_ONLY_GLOBALS.map((name: string) => [name, {get(): void {throw new ReferenceError(`${name} is not defined`);}}]))));
|
232
|
+
scope.global = scope;
|
233
|
+
scope.globalThis = scope;
|
234
|
+
if (process.path !== '') {
|
235
|
+
const pathParts = process.path.split('/');
|
236
|
+
scope.__dirname = pathParts.slice(0, -1).join('/');
|
237
|
+
scope.__filename = pathParts[pathParts.length - 1];
|
238
|
+
}
|
239
|
+
if (process.module !== false) {
|
240
|
+
scope.module = {
|
241
|
+
exports: {},
|
242
|
+
};
|
243
|
+
// @ts-ignore
|
244
|
+
scope.exports = scope.module.exports;
|
245
|
+
}
|
246
|
+
return scope;
|
247
|
+
}
|
248
|
+
|
249
|
+
getenv(pid: number): {[key: string]: string} {
|
250
|
+
let env = Object.create(this.globalenv);
|
251
|
+
const process = this.processes.get(pid);
|
252
|
+
if (process === undefined) {
|
253
|
+
throw new TypeError(`invalid PID: ${pid}`);
|
254
|
+
}
|
255
|
+
env.USER = this.getUserFromUID(process.uid);
|
256
|
+
return env;
|
257
|
+
}
|
258
|
+
|
259
|
+
getUserFromUID(uid: number | string): string {
|
260
|
+
if (typeof uid === 'string') {
|
261
|
+
return uid;
|
262
|
+
} else {
|
263
|
+
return 'root';
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
getUserFromGID(gid: number | string): string {
|
268
|
+
if (typeof gid === 'string') {
|
269
|
+
return gid;
|
270
|
+
} else {
|
271
|
+
return 'root';
|
272
|
+
}
|
273
|
+
}
|
274
|
+
|
275
|
+
getUIDFromUser(user: string | number): number {
|
276
|
+
if (typeof user === 'number') {
|
277
|
+
return user;
|
278
|
+
} else {
|
279
|
+
return 0;
|
280
|
+
}
|
281
|
+
}
|
282
|
+
|
283
|
+
getGIDFromGroup(group: string | number): number {
|
284
|
+
if (typeof group === 'number') {
|
285
|
+
return group;
|
286
|
+
} else {
|
287
|
+
return 0;
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
291
|
+
onError(error: Error): void {
|
292
|
+
for (const callback of this.errorCallbacks) {
|
293
|
+
if (callback !== undefined) {
|
294
|
+
callback(error);
|
295
|
+
}
|
296
|
+
}
|
297
|
+
}
|
298
|
+
|
299
|
+
addErrorCallback(callback: Function): number {
|
300
|
+
this.errorCallbacks.push(callback);
|
301
|
+
return this.errorCallbacks.length - 1;
|
302
|
+
}
|
303
|
+
|
304
|
+
removeErrorCallback(callbackID: number): void {
|
305
|
+
this.errorCallbacks[callbackID] = undefined;
|
306
|
+
}
|
307
|
+
|
308
|
+
getPlatform(): string {
|
309
|
+
const data = navigator.userAgent.slice('Mozilla/5.0 ('.length, navigator.userAgent.indexOf(')'));
|
310
|
+
if (data.includes('Windows')) {
|
311
|
+
return 'win32';
|
312
|
+
} else if (data.includes('Linux')) {
|
313
|
+
return 'linux';
|
314
|
+
} else if (data.includes('Mac')) {
|
315
|
+
return 'darwin';
|
316
|
+
} else {
|
317
|
+
return 'unknown';
|
318
|
+
}
|
319
|
+
}
|
320
|
+
|
321
|
+
}
|