fake-node 0.3.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.
@@ -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 CHANGED
@@ -1,18 +1,44 @@
1
1
 
2
+ import * as baseProcessObject from './process';
3
+ import {FileSystem} from './_fs';
2
4
  import * as module_os from './os';
3
- import * as module_process from './process';
4
- import * as module_punycode from 'punycode/';
5
+ import * as module_util from './util';
5
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';
6
11
  import WEB_ONLY_GLOBALS from './web_only_globals.json';
7
12
 
8
13
 
9
- const DEFAULT_GLOBALS = Object.defineProperties({}, Object.fromEntries(WEB_ONLY_GLOBALS.map((name: string) => [name, {get(): void {throw new ReferenceError(`${name} is not defined`);}}])));
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
+
10
33
 
11
34
  const BUILTIN_MODULES: [string, any][] = [
12
35
  ['os', module_os],
13
- ['process', module_process],
36
+ ['util', module_util],
14
37
  ['querystring', module_querystring],
15
38
  ['punycode', module_punycode],
39
+ ['path', module_path],
40
+ ['buffer', module_buffer],
41
+ ['fs', module_fs],
16
42
  ];
17
43
 
18
44
  const DEFAULT_ENV = {
@@ -47,21 +73,21 @@ export class Process {
47
73
  argv: string[] = [];
48
74
  argv0: string = '';
49
75
  execArgv: string[] = [];
50
- execArgv0: string = '/usr/bin/local/node';
76
+ execPath: string = '/usr/bin/local/node';
51
77
 
52
78
  path: string;
53
79
  module: false | string;
54
- code: string;
80
+ code?: string;
55
81
 
56
- constructor(fakeNode: FakeNode, {path = '', code, module}: {path?: string, code: string, module?: false | string}) {
82
+ constructor(fakeNode: FakeNode, {path = '<anonymous>', code, module = false}: {path?: string, code?: string, module?: false | string}) {
57
83
  this.fakeNode = fakeNode;
58
84
  this.pid = fakeNode.nextPid;
59
85
  fakeNode.nextPid++;
60
86
  fakeNode.processes.set(this.pid, this);
61
- this.code = code;
62
87
  this.path = path;
63
88
  this.cwd = path.split('/').slice(0, -1).join('/');
64
- this.module = module ?? false;
89
+ this.module = module;
90
+ this.code = code;
65
91
  }
66
92
 
67
93
  get env(): {[key: string]: string} {
@@ -69,49 +95,69 @@ export class Process {
69
95
  }
70
96
 
71
97
  run(): void {
72
- let code: string;
98
+ let code = this.code;
99
+ if (code === undefined) {
100
+ code = this.fakeNode.fs.readFrom(this.path);
101
+ }
102
+ let injectCode: string;
73
103
  if (this.module) {
74
- code = `with(${this.fakeNode.globalName}.getGlobals(${this.pid})){__fakeNode__.modules.set('${this.module},(function(){${this.code};return module.exports;})());}`;
104
+ injectCode = `with(${this.fakeNode.globalName}.getGlobals(${this.pid})){__fakeNode__.modules.set('${this.module},(function(){${code};return module.exports;})());}`;
75
105
  } else {
76
- code = `with(${this.fakeNode.globalName}.getGlobals(${this.pid})){(function(){${this.code}})();}`;
106
+ injectCode = `with(${this.fakeNode.globalName}.getGlobals(${this.pid})){(function(){${code}})();}`;
77
107
  }
78
108
  let elt = document.createElement('script');
79
- elt.textContent = code;
109
+ elt.textContent = injectCode;
80
110
  document.body.appendChild(elt);
81
111
  }
82
112
 
83
113
  }
84
114
 
85
115
 
116
+ if (!('__fakeNode_next_instance_id__' in globalThis)) {
117
+ // @ts-ignore
118
+ globalThis.__fakeNode_next_instance_id__ = 0;
119
+ }
120
+
121
+
86
122
  export class FakeNode {
87
123
 
88
124
  version: string = '0.3.0';
125
+ versions: {[key: string]: string} = {
126
+ 'fake-node': '0.3.0',
127
+ 'punycode': '2.3.1',
128
+ };
89
129
 
90
- static nextId: number = 0;
91
130
  id: number;
92
131
  globalName: string;
93
132
 
94
- globalenv: {[key: string]: string} = DEFAULT_ENV;
95
-
96
- modules: Map<string, unknown> = new Map();
97
-
98
- globals: {[key: string]: unknown};
133
+ fs: FileSystem;
99
134
 
100
135
  processes: Map<number, Process> = new Map();
101
136
  nextPid: number = 3;
102
137
 
103
- window: Window = window;
138
+ globalenv: {[key: string]: string} = DEFAULT_ENV;
139
+
140
+ modules: Map<string, unknown> = new Map();
141
+
142
+ // @ts-ignore
143
+ window: Window;
104
144
 
105
145
  errorCallbacks: (Function | undefined)[] = [];
106
146
 
107
147
  constructor() {
108
- this.id = FakeNode.nextId;
109
- FakeNode.nextId++;
148
+ // @ts-ignore
149
+ this.id = globalThis.__fakeNode_next_instance_id;
150
+ // @ts-ignore
151
+ globalThis.__fakeNode_next_instance_id++;
110
152
  this.globalName = '__fakeNode_' + this.id + '__';
111
153
  // @ts-ignore
112
154
  globalThis[this.globalName] = this;
113
- this.globals = {__fakeNode__: this};
114
- Object.assign(this.globals, DEFAULT_GLOBALS);
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();
115
161
  window.addEventListener('error', ({error}) => this.onError(error));
116
162
  window.addEventListener('unhandledrejection', ({reason}) => reason instanceof Error ? this.onError(reason) : this.onError(new Error(String(reason))));
117
163
  for (const [name, module] of BUILTIN_MODULES) {
@@ -121,25 +167,70 @@ export class FakeNode {
121
167
  }
122
168
  }
123
169
 
124
- require(module: string): unknown {
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
+ }
125
178
  if (this.modules.has(module)) {
126
179
  return this.modules.get(module);
180
+ } else if (module === 'process' || module === 'node:process' || module === 'fake-node:process') {
181
+ return this.getProcessObject(pid);
127
182
  } else {
128
183
  throw new Error(`cannot find module '${module}'`);
129
184
  }
130
185
  }
131
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
+
132
222
  getGlobals(pid: number): object {
133
223
  const process = this.processes.get(pid);
134
224
  if (process === undefined) {
135
- 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. Please report it at https://github.com/speedydelete/fake-node/issues.`);
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.`);
136
226
  }
137
- let scope: {[key: string]: unknown} = {};
138
- Object.assign(scope, this.globals);
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`);}}]))));
139
232
  scope.global = scope;
140
233
  scope.globalThis = scope;
141
- scope.__fakeNode_process__ = process;
142
- scope.require = this.require.bind(this);
143
234
  if (process.path !== '') {
144
235
  const pathParts = process.path.split('/');
145
236
  scope.__dirname = pathParts.slice(0, -1).join('/');
@@ -165,18 +256,6 @@ export class FakeNode {
165
256
  return env;
166
257
  }
167
258
 
168
- run(code: string): void {
169
- (new Process(this, {code, path: '/'})).run();
170
- }
171
-
172
- addModule(name: string, code: string): void {
173
- (new Process(this, {code, path: '/', module: name})).run();
174
- }
175
-
176
- addModuleFromValue(name: string, module: unknown): void {
177
- this.modules.set(name, module);
178
- }
179
-
180
259
  getUserFromUID(uid: number | string): string {
181
260
  if (typeof uid === 'string') {
182
261
  return uid;
@@ -226,4 +305,17 @@ export class FakeNode {
226
305
  this.errorCallbacks[callbackID] = undefined;
227
306
  }
228
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
+
229
321
  }
package/src/os.ts CHANGED
@@ -1,4 +1,6 @@
1
1
 
2
+ /// <reference path="./in_fake_node.d.ts" />
3
+
2
4
  export const EOL = '\n';
3
5
 
4
6
  export function availableParallelism(): number {
@@ -196,16 +198,7 @@ export function networkInterfaces(): {[key: string]: {address: string, netmask:
196
198
  }
197
199
 
198
200
  export function platform(): string {
199
- const data = __fakeNode__.window.navigator.userAgent.slice('Mozilla/5.0 ('.length, navigator.userAgent.indexOf(')'));
200
- if (data.includes('Windows')) {
201
- return 'win32';
202
- } else if (data.includes('Linux')) {
203
- return 'linux';
204
- } else if (data.includes('Mac')) {
205
- return 'darwin';
206
- } else {
207
- return 'unknown';
208
- }
201
+ return __fakeNode__.getPlatform();
209
202
  }
210
203
 
211
204
  export function release(): string {
package/src/path.ts ADDED
@@ -0,0 +1,141 @@
1
+
2
+ /// <reference path="./in_fake_node.d.ts" />
3
+
4
+
5
+ export interface PathObject {
6
+ dir: string;
7
+ root: string;
8
+ base: string;
9
+ name: string;
10
+ ext: string;
11
+ };
12
+
13
+
14
+ abstract class PathModule {
15
+
16
+ abstract sep: string;
17
+ abstract delimiter: string;
18
+ abstract _normalizeSplit: string | RegExp;
19
+
20
+ basename(path: string, suffix?: string): string {
21
+ const split = path.split(this.sep);
22
+ let out = split[split.length - 1];
23
+ if (suffix !== undefined && out.endsWith(suffix)) {
24
+ out = out.slice(0, out.length - suffix.length);
25
+ }
26
+ return out;
27
+ }
28
+
29
+ dirname(path: string): string {
30
+ return path.split('/').slice(0, -1).join('/');
31
+ }
32
+
33
+ extname(path: string): string {
34
+ let pos = path.indexOf('.');
35
+ if (pos === -1) {
36
+ return '';
37
+ } else {
38
+ return path.slice(pos);
39
+ }
40
+ }
41
+
42
+ format(path: string): string {
43
+ throw new TypeError('path.format is not supported in fake-node');
44
+ }
45
+
46
+ matchesGlob(path: string, pattern: string): boolean {
47
+ throw new TypeError('path.matchesGlob is not supported in fake-node');
48
+ }
49
+
50
+ abstract isAbsolute(path: string): boolean;
51
+
52
+ join(...paths: string[]) {
53
+ return this.normalize(paths.join(this.sep));
54
+ }
55
+
56
+ normalize(path: string): string {
57
+ let out: string[] = [];
58
+ for (const segment of path.split(this._normalizeSplit)) {
59
+ if (segment === '' || segment === '.') {
60
+ continue;
61
+ } else if (segment === '..') {
62
+ out.pop();
63
+ } else {
64
+ out.push(segment);
65
+ }
66
+ }
67
+ return out.join(this.sep);
68
+ }
69
+
70
+ parse(path: string): PathObject {
71
+ throw new TypeError('path.parse is not supported in fake-node');
72
+ }
73
+
74
+ relative(from: string, to: string): string {
75
+ throw new TypeError('path.relative is not supported in fake-node');
76
+ }
77
+
78
+ resolve(...paths: string[]): string {
79
+ let out = '';
80
+ for (let i = paths.length - 1; i > 0; i--) {
81
+ out += paths[i];
82
+ if (this.isAbsolute(out)) {
83
+ return out;
84
+ }
85
+ }
86
+ return __fakeNode_process__.cwd + out;
87
+ }
88
+
89
+ abstract toNamespacedPath(path: string): string;
90
+
91
+ };
92
+
93
+
94
+ export const posix = new class extends PathModule {
95
+
96
+ sep = '/';
97
+ delimiter = ':';
98
+ _normalizeSplit = '/';
99
+
100
+ isAbsolute(path: string): boolean {
101
+ return path.startsWith(this.sep);
102
+ }
103
+
104
+ toNamespacedPath(path: string): string {
105
+ return path;
106
+ }
107
+
108
+ };
109
+
110
+
111
+ export const win32 = new class extends PathModule {
112
+
113
+ sep = '\\';
114
+ delimiter = ';';
115
+ _normalizeSplit = /\/|\\/;
116
+
117
+ isAbsolute(path: string): boolean {
118
+ return 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.includes(path[0]) && path[1] === ':' && path[2] === this.sep;
119
+ }
120
+
121
+ toNamespacedPath(path: string): string {
122
+ throw new TypeError('path.windows.toNamespacedPath is not supported in fake-node');
123
+ }
124
+
125
+ };
126
+
127
+
128
+ export const basename = posix.basename;
129
+ export const delimiter = posix.delimiter;
130
+ export const dirname = posix.dirname;
131
+ export const extname = posix.extname;
132
+ export const format = posix.format;
133
+ export const matchesGlob = posix.matchesGlob;
134
+ export const isAbsolute = posix.isAbsolute;
135
+ export const join = posix.join;
136
+ export const normalize = posix.normalize;
137
+ export const parse = posix.parse;
138
+ export const relative = posix.relative;
139
+ export const resolve = posix.resolve;
140
+ export const sep = posix.sep;
141
+ export const toNamespacedPath = posix.toNamespacedPath;
package/src/process.ts CHANGED
@@ -1,18 +1,14 @@
1
1
 
2
- import {platform as _platform} from './os';
2
+ /// <reference path="./in_fake_node.d.ts" />
3
3
 
4
4
  export function abort(): void {
5
5
  __fakeNode__.window.close();
6
6
  }
7
-
7
+
8
8
  export const allowedNodeEnvironmentFlags = new Set<never>();
9
9
 
10
10
  export const arch = 'fake';
11
11
 
12
- // export const argv = __fakeNode_process__.argv;
13
-
14
- // export const argv0 = __fakeNode_process__.argv0;
15
-
16
12
  export const channel = undefined;
17
13
 
18
14
  export function chdir(path: string): void {
@@ -51,12 +47,6 @@ export function emitWarning(warning: string | Error, type_or_options: string | {
51
47
  throw new TypeError('process.emitWarning is not supported in fake-node');
52
48
  }
53
49
 
54
- // export const env = __fakeNode_process__.env;
55
-
56
- // export const execArgv = __fakeNode_process__.execArgv;
57
-
58
- // export const execPath = __fakeNode_process__.execPath;
59
-
60
50
  export function exit(code: number = 0): void {
61
51
  window.console.log('Exit code', code);
62
52
  window.close();
@@ -152,8 +142,6 @@ export function loadEnvFile(path: string = './.env'): void {
152
142
  throw new TypeError('process.loadEnvFile is not supported in fake-node');
153
143
  }
154
144
 
155
- // export const mainModule = __fakeNode_process__.path === '' ? undefined : __fakeNode_process__.path;
156
-
157
145
  export function memoryUsage(): {rss: number, heapTotal: number, heapUsed: number, external: number, arrayBuffers: number} {
158
146
  throw new TypeError('process.memoryUsage is not supported in fake-node');
159
147
  }
@@ -182,8 +170,6 @@ export function ref(maybeRefable: any): void {
182
170
 
183
171
  export const pid = 1;
184
172
 
185
- // export const platform = _platform();
186
-
187
173
  export const ppid = 1;
188
174
 
189
175
  export const release = {
@@ -257,7 +243,3 @@ export function unref(maybeRefable: any): void {
257
243
  export function uptime(): number {
258
244
  return __fakeNode_process__.fakeNode.window.performance.now() / 1000;
259
245
  }
260
-
261
- // export const version = __fakeNode__.version;
262
-
263
- // export const versions = [version];