forked from codesandbox/codesandbox-client
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbrowserfs.ts
More file actions
178 lines (167 loc) · 5.15 KB
/
browserfs.ts
File metadata and controls
178 lines (167 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/**
* BrowserFS's main module. This is exposed in the browser via the BrowserFS global.
* Due to limitations in typedoc, we document these functions in ./typedoc.ts.
*/
import * as buffer from 'buffer';
import fs from './node_fs';
import * as path from 'path';
import {FileSystemConstructor, FileSystem, BFSOneArgCallback, BFSCallback} from './file_system';
import EmscriptenFS from '../generic/emscripten_fs';
import Backends from './backends';
import * as BFSUtils from './util';
import * as Errors from './api_error';
import setImmediate from '../generic/setImmediate';
if ((<any> process)['initializeTTYs']) {
(<any> process)['initializeTTYs']();
}
/**
* Installs BFSRequire as global `require`, a Node Buffer polyfill as the global `Buffer` variable,
* and a Node process polyfill as the global `process` variable.
*/
export function install(obj: any) {
obj.Buffer = Buffer;
obj.process = process;
const oldRequire = obj.require ? obj.require : null;
// Monkey-patch require for Node-style code.
obj.require = function(arg: string) {
const rv = BFSRequire(arg);
if (!rv) {
return oldRequire.apply(null, Array.prototype.slice.call(arguments, 0));
} else {
return rv;
}
};
}
/**
* @hidden
*/
export function registerFileSystem(name: string, fs: FileSystemConstructor) {
(<any> Backends)[name] = fs;
}
/**
* Polyfill for CommonJS `require()`. For example, can call `BFSRequire('fs')` to get a 'fs' module polyfill.
*/
export function BFSRequire(module: 'fs'): typeof fs;
export function BFSRequire(module: 'path'): typeof path;
export function BFSRequire(module: 'buffer'): typeof buffer;
export function BFSRequire(module: 'process'): typeof process;
export function BFSRequire(module: 'bfs_utils'): typeof BFSUtils;
export function BFSRequire(module: string): any;
export function BFSRequire(module: string): any {
switch (module) {
case 'fs':
return fs;
case 'path':
return path;
case 'buffer':
// The 'buffer' module has 'Buffer' as a property.
return buffer;
case 'process':
return process;
case 'bfs_utils':
return BFSUtils;
default:
return (<any> Backends)[module];
}
}
/**
* Initializes BrowserFS with the given root file system.
*/
export function initialize(rootfs: FileSystem) {
return fs.initialize(rootfs);
}
/**
* Creates a file system with the given configuration, and initializes BrowserFS with it.
* See the FileSystemConfiguration type for more info on the configuration object.
*/
export function configure(config: FileSystemConfiguration, cb: BFSOneArgCallback): void {
getFileSystem(config, (e, fs?) => {
if (fs) {
initialize(fs);
cb();
} else {
cb(e);
}
});
}
/**
* Specifies a file system backend type and its options.
*
* Individual options can recursively contain FileSystemConfiguration objects for
* option values that require file systems.
*
* For example, to mirror Dropbox to LocalStorage with AsyncMirror, use the following
* object:
*
* ```javascript
* var config = {
* fs: "AsyncMirror",
* options: {
* sync: {fs: "LocalStorage"},
* async: {fs: "Dropbox", options: {client: anAuthenticatedDropboxSDKClient }}
* }
* };
* ```
*
* The option object for each file system corresponds to that file system's option object passed to its `Create()` method.
*/
export interface FileSystemConfiguration {
fs: string;
options?: any;
}
/**
* Retrieve a file system with the given configuration.
* @param config A FileSystemConfiguration object. See FileSystemConfiguration for details.
* @param cb Called when the file system is constructed, or when an error occurs.
*/
export function getFileSystem(config: FileSystemConfiguration, cb: BFSCallback<FileSystem>): void {
const fsName = config['fs'];
if (!fsName) {
return cb(new Errors.ApiError(Errors.ErrorCode.EPERM, 'Missing "fs" property on configuration object.'));
}
const options = config['options'];
let waitCount = 0;
let called = false;
function finish() {
if (!called) {
called = true;
const fsc = <FileSystemConstructor | undefined> (<any> Backends)[fsName];
if (!fsc) {
cb(new Errors.ApiError(Errors.ErrorCode.EPERM, `File system ${fsName} is not available in BrowserFS.`));
} else {
fsc.Create(options, cb);
}
}
}
if (options !== null && typeof(options) === "object") {
let finishedIterating = false;
const props = Object.keys(options).filter((k) => k !== 'fs');
// Check recursively if other fields have 'fs' properties.
props.forEach((p) => {
const d = options[p];
if (d !== null && typeof(d) === "object" && d['fs']) {
waitCount++;
getFileSystem(d, function(e, fs?) {
waitCount--;
if (e) {
if (called) {
return;
}
called = true;
cb(e);
} else {
options[p] = fs;
if (waitCount === 0 && finishedIterating) {
finish();
}
}
});
}
});
finishedIterating = true;
}
if (waitCount === 0) {
finish();
}
}
export {EmscriptenFS, Backends as FileSystem, Errors, setImmediate};