@environment-safe/file 0.0.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/.babelrc.cjs +18 -0
- package/.eslintrc.cjs +42 -0
- package/.husky/pre-commit +11 -0
- package/.import-config.json +5 -0
- package/.jsdoc.json +15 -0
- package/LICENSE +20 -0
- package/README.md +95 -0
- package/containers/development.dockerfile +11 -0
- package/containers/production.dockerfile +11 -0
- package/containers/test.dockerfile +11 -0
- package/dist/buffer.cjs +77 -0
- package/dist/index.cjs +599 -0
- package/index.html +74 -0
- package/package.json +107 -0
- package/src/buffer.mjs +73 -0
- package/src/index.mjs +599 -0
- package/test/index.html +443 -0
- package/test/lauch-insecure-chrome +20 -0
- package/test/test.cjs +10 -0
- package/test/test.mjs +59 -0
package/src/index.mjs
ADDED
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
/*
|
|
2
|
+
import { isBrowser, isJsDom } from 'browser-or-node';
|
|
3
|
+
import * as mod from 'module';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
let internalRequire = null;
|
|
6
|
+
if(typeof require !== 'undefined') internalRequire = require;
|
|
7
|
+
const ensureRequire = ()=> (!internalRequire) && (internalRequire = mod.createRequire(import.meta.url));
|
|
8
|
+
//*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A JSON object
|
|
12
|
+
* @typedef { object } JSON
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { isBrowser, isJsDom } from 'browser-or-node';
|
|
16
|
+
import { FileBuffer } from './buffer.mjs';
|
|
17
|
+
import * as fs from 'fs';
|
|
18
|
+
import * as path from 'path';
|
|
19
|
+
|
|
20
|
+
const inputQueue = [];
|
|
21
|
+
const attachInputGenerator = (eventType)=>{
|
|
22
|
+
const handler = (event)=>{
|
|
23
|
+
if(inputQueue.length){
|
|
24
|
+
const input = inputQueue.shift();
|
|
25
|
+
try{
|
|
26
|
+
input.handler(event, input.resolve, input.reject);
|
|
27
|
+
}catch(ex){
|
|
28
|
+
inputQueue.unshift(input);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
window.addEventListener('load', (event) => {
|
|
33
|
+
document.body.addEventListener(eventType, handler, false);
|
|
34
|
+
});
|
|
35
|
+
//document.body.addEventListener(eventType, handler, false);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
if(isBrowser || isJsDom){
|
|
39
|
+
attachInputGenerator('mousedown');
|
|
40
|
+
// mousemove is cleanest, but seems unreliable
|
|
41
|
+
// attachInputGenerator('mousemove');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const wantInput = async (id, handler, cache)=>{
|
|
45
|
+
const promise = new Promise((resolve, reject)=>{
|
|
46
|
+
inputQueue.push({ resolve, reject, handler });
|
|
47
|
+
});
|
|
48
|
+
const input = await promise;
|
|
49
|
+
return await input;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const getFilePickerOptions = (name, path)=>{
|
|
53
|
+
let suffix = name.split('.').pop();
|
|
54
|
+
if(suffix.length > 6) suffix = '';
|
|
55
|
+
const options = {
|
|
56
|
+
suggestedName: name
|
|
57
|
+
};
|
|
58
|
+
if(path) options.startIn = path;
|
|
59
|
+
if(suffix){
|
|
60
|
+
const accept = {};
|
|
61
|
+
accept[mimesBySuffix[suffix]] = '.'+suffix;
|
|
62
|
+
options.types = [{
|
|
63
|
+
description: suffix,
|
|
64
|
+
accept,
|
|
65
|
+
}];
|
|
66
|
+
options.excludeAcceptAllOption = true;
|
|
67
|
+
}
|
|
68
|
+
return options;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const makeLocation = (path, dir)=>{
|
|
72
|
+
if(dir && dir[0] === '.'){
|
|
73
|
+
if(dir[1] === '.'){
|
|
74
|
+
if(dir[2] === '/' && dir[3]){
|
|
75
|
+
return pathJoin(File.directory.current, '..', dir.substring(3), path);
|
|
76
|
+
}else{
|
|
77
|
+
if(dir[2]){
|
|
78
|
+
return pathJoin(File.directory.current, '..', dir.substring(3), path);
|
|
79
|
+
}else{
|
|
80
|
+
return pathJoin(File.directory.current, '..', path);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}else{
|
|
84
|
+
if(dir[1] === '/'){
|
|
85
|
+
return pathJoin(File.directory.current, dir.substring(2), path);
|
|
86
|
+
}else{
|
|
87
|
+
if(dir[1]){
|
|
88
|
+
return pathJoin(File.directory.current, dir, path);
|
|
89
|
+
}else{
|
|
90
|
+
return pathJoin(File.directory.current, path);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return dir?handleCanonicalPath(dir, File.os, File.user)+ '/' + path:path;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const save = async (name, dir, buffer, meta={})=>{
|
|
99
|
+
const location = makeLocation(name, dir);
|
|
100
|
+
if(isBrowser || isJsDom){
|
|
101
|
+
const options = getFilePickerOptions(name, dir);
|
|
102
|
+
const newHandle = await wantInput(location, (event, resolve, reject)=>{
|
|
103
|
+
try{
|
|
104
|
+
window.showSaveFilePicker(options).then((thisHandle)=>{
|
|
105
|
+
resolve(thisHandle);
|
|
106
|
+
}).catch((ex)=>{
|
|
107
|
+
reject(ex);
|
|
108
|
+
});
|
|
109
|
+
}catch(ex){
|
|
110
|
+
reject(ex);
|
|
111
|
+
}
|
|
112
|
+
}, meta.cache);
|
|
113
|
+
const writableStream = await newHandle.createWritable();
|
|
114
|
+
// write our file
|
|
115
|
+
await writableStream.write(buffer);
|
|
116
|
+
// close the file and write the contents to disk.
|
|
117
|
+
await writableStream.close();
|
|
118
|
+
}else{
|
|
119
|
+
return await new Promise((resolve, reject)=>{
|
|
120
|
+
fs.writeFile(location, buffer, (err)=>{
|
|
121
|
+
if(err) return reject(err);
|
|
122
|
+
resolve();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const mimesBySuffix = {
|
|
129
|
+
json : 'application/json',
|
|
130
|
+
jpg : 'image/jpeg',
|
|
131
|
+
jpeg : 'image/jpeg',
|
|
132
|
+
gif : 'image/gif',
|
|
133
|
+
png : 'image/png',
|
|
134
|
+
svg : 'image/sxg+xml',
|
|
135
|
+
webp : 'image/webp',
|
|
136
|
+
csv : 'text/csv',
|
|
137
|
+
tsv : 'text/tsv',
|
|
138
|
+
ssv : 'text/ssv',
|
|
139
|
+
js : 'text/javascript',
|
|
140
|
+
mjs : 'text/javascript',
|
|
141
|
+
cjs : 'text/javascript',
|
|
142
|
+
css : 'text/css',
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export const pathJoin = (...parts)=>{ //returns buffer, eventually stream
|
|
146
|
+
if(isBrowser || isJsDom){
|
|
147
|
+
return parts.join('/');
|
|
148
|
+
}else{
|
|
149
|
+
return path.join.apply(path, parts);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
//todo: should I remove export (no one should use this)?
|
|
155
|
+
export const fileBody = async (path, dir, baseDir, allowRedirect, forceReturn)=>{
|
|
156
|
+
try{
|
|
157
|
+
//let location = dir?dir+ '/' + path:path; //todo: looser handling
|
|
158
|
+
let location = makeLocation(path, dir);
|
|
159
|
+
if(canonicalLocationToPath['darwin'][dir]){
|
|
160
|
+
if(baseDir){
|
|
161
|
+
throw new Error('custom directories unsupported');
|
|
162
|
+
}else{
|
|
163
|
+
location = 'file://'+handleCanonicalPath(dir, File.os, File.user)+'/'+path;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const response = await fetch(location);
|
|
167
|
+
const text = await response.text();
|
|
168
|
+
if(!(response.ok || (allowRedirect && response.redirected) || forceReturn)){
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
return text;
|
|
172
|
+
}catch(ex){
|
|
173
|
+
//console.log(location, ex);
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const handle = async (path, dir, writable, cache={})=>{ //returns buffer, eventually stream
|
|
179
|
+
let suffix = path.split('.').pop();
|
|
180
|
+
if(suffix.length > 6) suffix = '';
|
|
181
|
+
const location = makeLocation(path, dir);
|
|
182
|
+
if(isBrowser || isJsDom){
|
|
183
|
+
if(cache && cache[path]) return cache[path];
|
|
184
|
+
const options = getFilePickerOptions(path);
|
|
185
|
+
try{
|
|
186
|
+
const response = await fileBody(path, dir);
|
|
187
|
+
if(response === null) throw new Error('File not found');
|
|
188
|
+
}catch(ex){
|
|
189
|
+
const newHandle = await wantInput(location, (event, resolve, reject)=>{
|
|
190
|
+
try{
|
|
191
|
+
window.showSaveFilePicker(options).then((thisHandle)=>{
|
|
192
|
+
resolve(thisHandle);
|
|
193
|
+
}).catch((ex)=>{
|
|
194
|
+
reject(ex);
|
|
195
|
+
});
|
|
196
|
+
}catch(ex){
|
|
197
|
+
reject(ex);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
return newHandle;
|
|
201
|
+
}
|
|
202
|
+
const fileHandle = await wantInput(location, (event, resolve, reject)=>{
|
|
203
|
+
try{
|
|
204
|
+
window.showOpenFilePicker(options).then(([ handle ])=>{
|
|
205
|
+
resolve(handle);
|
|
206
|
+
}).catch((ex)=>{
|
|
207
|
+
reject(ex);
|
|
208
|
+
});
|
|
209
|
+
}catch(ex){
|
|
210
|
+
reject(ex);
|
|
211
|
+
}
|
|
212
|
+
}, cache);
|
|
213
|
+
// eslint-disable-next-line no-undef
|
|
214
|
+
if(cache) cache[location] = fileHandle;
|
|
215
|
+
// eslint-disable-next-line no-undef
|
|
216
|
+
return fileHandle;
|
|
217
|
+
}else{
|
|
218
|
+
// todo: impl
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export const load = async (path, dir, cache)=>{ //returns buffer, eventually stream
|
|
223
|
+
const location = makeLocation(path, dir);
|
|
224
|
+
if(isBrowser || isJsDom){
|
|
225
|
+
try{
|
|
226
|
+
const response = await fetch(location);
|
|
227
|
+
if(!response){
|
|
228
|
+
return new ArrayBuffer();
|
|
229
|
+
}
|
|
230
|
+
const buffer = await response.arrayBuffer();
|
|
231
|
+
buffer;
|
|
232
|
+
return buffer;
|
|
233
|
+
}catch(ex){
|
|
234
|
+
return new ArrayBuffer();
|
|
235
|
+
}
|
|
236
|
+
}else{
|
|
237
|
+
return await new Promise((resolve, reject)=>{
|
|
238
|
+
fs.readFile(location, (err, body)=>{
|
|
239
|
+
if(err) return reject(err);
|
|
240
|
+
resolve(body);
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
export const exists = async (path, dir, cache, incomingHandle)=>{ //returns buffer, eventually stream
|
|
247
|
+
if(isBrowser || isJsDom){
|
|
248
|
+
if(incomingHandle){
|
|
249
|
+
const fileHandle = incomingHandle;
|
|
250
|
+
const file = await fileHandle.getFile();
|
|
251
|
+
const buffer = await file.arrayBuffer();
|
|
252
|
+
return !!buffer;
|
|
253
|
+
}else{
|
|
254
|
+
const body = await fileBody(path, dir);
|
|
255
|
+
return body !== null;
|
|
256
|
+
}
|
|
257
|
+
}else{
|
|
258
|
+
return await new Promise((resolve, reject)=>{
|
|
259
|
+
const location = makeLocation(path, dir);
|
|
260
|
+
fs.stat(location, (err, res)=>{
|
|
261
|
+
if(err) resolve(false);
|
|
262
|
+
resolve(true);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export const remove = async (path, dir, cache)=>{
|
|
269
|
+
if(isBrowser || isJsDom){
|
|
270
|
+
const fileHandle = await handle(path, dir, true, cache);
|
|
271
|
+
if(fileHandle.remove) fileHandle.remove(); //non-standard, but supported
|
|
272
|
+
}else{
|
|
273
|
+
// todo: impl
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
export const info = async (path, dir, cache)=>{
|
|
278
|
+
if(isBrowser || isJsDom){
|
|
279
|
+
// todo: impl
|
|
280
|
+
}else{
|
|
281
|
+
// todo: impl
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export const list = async (path, options={})=>{
|
|
286
|
+
if(isBrowser || isJsDom){
|
|
287
|
+
// todo: impl
|
|
288
|
+
switch(File.agent.name){
|
|
289
|
+
case 'chrome': {
|
|
290
|
+
const page = await fileBody('', path, null, null, true);
|
|
291
|
+
let rows = (page && page.match( /<script>addRow\((.*)\);<\/script>/g ) ) || [];
|
|
292
|
+
rows = rows.map((row)=>{
|
|
293
|
+
return row.match( /<script>addRow\((.*)\);<\/script>/ )[1];
|
|
294
|
+
});
|
|
295
|
+
const jsonData = `[[${rows.join('], [')}]]`;
|
|
296
|
+
const data = JSON.parse(jsonData);
|
|
297
|
+
let results = data.map((meta)=>{
|
|
298
|
+
return {
|
|
299
|
+
name: meta[0],
|
|
300
|
+
isFile: ()=>{
|
|
301
|
+
return !!meta[2];
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
});
|
|
305
|
+
if(Object.keys(options).length){
|
|
306
|
+
if(options.files === false){
|
|
307
|
+
results = results.filter((file)=>{
|
|
308
|
+
return !file.isFile();
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
if(options.directories === false){
|
|
312
|
+
results = results.filter((file)=>{
|
|
313
|
+
return file.isFile();
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
if(!options.hidden){
|
|
317
|
+
results = results.filter((file)=>{
|
|
318
|
+
return file !== '.' && file !== '..';
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return results.map((file)=>{
|
|
323
|
+
return file.name;
|
|
324
|
+
});
|
|
325
|
+
//TODO: apache fallback
|
|
326
|
+
//break;
|
|
327
|
+
}
|
|
328
|
+
default: throw new Error(`Usupported Browser: ${File.os}`);
|
|
329
|
+
}
|
|
330
|
+
}else{
|
|
331
|
+
//todo: platform safe separator
|
|
332
|
+
const target = path.indexOf('/') === -1?makeLocation('', path):path;
|
|
333
|
+
return await new Promise((resolve, reject)=>{
|
|
334
|
+
fs.readdir(target, { withFileTypes: true }, (err, files)=>{
|
|
335
|
+
if(err) return reject(err);
|
|
336
|
+
let results = files;
|
|
337
|
+
if(Object.keys(options).length){
|
|
338
|
+
if(options.files === false){
|
|
339
|
+
results = results.filter((file)=>{
|
|
340
|
+
return !file.isFile();
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
if(options.directories === false){
|
|
344
|
+
results = results.filter((file)=>{
|
|
345
|
+
return file.isFile();
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
if(!options.hidden){
|
|
349
|
+
results = results.filter((file)=>{
|
|
350
|
+
return file !== '.' && file !== '..';
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
resolve(results.map((file)=>{
|
|
355
|
+
return file.name;
|
|
356
|
+
}));
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const internalCache = {};
|
|
363
|
+
|
|
364
|
+
export const listFiles = (path)=>{
|
|
365
|
+
return list(path).map((src)=>{
|
|
366
|
+
const url = src.indexOf('://') !== -1?src:`file://${src}`;
|
|
367
|
+
return new File(url);
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
export class File{
|
|
373
|
+
constructor(path, options={}){
|
|
374
|
+
//todo: clean this rats nest up
|
|
375
|
+
const location = ( (path && path[0] === '/')?`file:${path}`:path ) ||
|
|
376
|
+
( (!path) && options.directory && handleCanonicalPath(options.directory, File.os, File.user) ) ||
|
|
377
|
+
('/tmp/' + Math.floor( Math.random() * 10000 ));
|
|
378
|
+
if(options.cache === true) options.cache = internalCache;
|
|
379
|
+
this.options = options;
|
|
380
|
+
//one of: desktop, documents, downloads, music, pictures, videos
|
|
381
|
+
this.directory = options.directory || '.';
|
|
382
|
+
this.path = location;
|
|
383
|
+
this.buffer = new FileBuffer();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async save(){
|
|
387
|
+
await save(this.path, this.directory, this.buffer, this.options);
|
|
388
|
+
return this;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async load(){
|
|
392
|
+
const dir = this.path.indexOf('/') === -1?this.directory:'';
|
|
393
|
+
this.buffer = await load(this.path, dir, this.options);
|
|
394
|
+
this.buffer.cast = (type)=>{
|
|
395
|
+
return FileBuffer.to(type, this.buffer);
|
|
396
|
+
};
|
|
397
|
+
return this;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
body(value){
|
|
401
|
+
if(value === null || value === undefined) return this.buffer;
|
|
402
|
+
this.buffer = FileBuffer.from(value);
|
|
403
|
+
this.buffer.cast = (type)=>{
|
|
404
|
+
return FileBuffer.to(type, this.buffer);
|
|
405
|
+
};
|
|
406
|
+
if(value) return this;
|
|
407
|
+
return this.buffer;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
async info(){
|
|
411
|
+
return await info(this.path, this.directory);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async 'delete'(){
|
|
415
|
+
await remove(this.path, this.directory, this.options);
|
|
416
|
+
return this;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
static exists(path, directory){
|
|
420
|
+
return exists(path, directory);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
static list(path, options){
|
|
424
|
+
return list(path, options);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
let user = '';
|
|
428
|
+
Object.defineProperty(File, 'user', {
|
|
429
|
+
get() {
|
|
430
|
+
if(isBrowser || isJsDom){
|
|
431
|
+
return user || 'khrome'; //todo: something real;
|
|
432
|
+
}else{
|
|
433
|
+
return user || 'khrome'; //todo: something real;
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
set(newValue) {
|
|
437
|
+
user = newValue;
|
|
438
|
+
},
|
|
439
|
+
enumerable: true,
|
|
440
|
+
configurable: true,
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
Object.defineProperty(File, 'os', {
|
|
444
|
+
get() {
|
|
445
|
+
if(isBrowser || isJsDom){
|
|
446
|
+
return 'darwin'; //todo: something real;
|
|
447
|
+
}else{
|
|
448
|
+
return 'darwin';
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
set(newValue) {
|
|
452
|
+
//do nothing
|
|
453
|
+
},
|
|
454
|
+
enumerable: true,
|
|
455
|
+
configurable: true,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const canonicalLocationToPath = {
|
|
459
|
+
darwin : {
|
|
460
|
+
'desktop': '~/Desktop',
|
|
461
|
+
'documents': '~/Documents',
|
|
462
|
+
'downloads': '~/Downloads',
|
|
463
|
+
'music': '~/Music',
|
|
464
|
+
'pictures': '~/Pictures',
|
|
465
|
+
'home': '~/Pictures',
|
|
466
|
+
'videos': '~/Movies'
|
|
467
|
+
},
|
|
468
|
+
win : {},
|
|
469
|
+
linux : {},
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
const osToHome = {
|
|
473
|
+
darwin : '/Users/${user}',
|
|
474
|
+
win : 'C:/',
|
|
475
|
+
linux : '/Users/${user}',
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
/*const handlePath = (path, os, username)=>{
|
|
479
|
+
return path.replace('~', osToHome[os].replace('${user}', username));
|
|
480
|
+
};*/
|
|
481
|
+
|
|
482
|
+
const handleCanonicalPath = (name, os, username)=>{
|
|
483
|
+
const path = canonicalLocationToPath[os][name];
|
|
484
|
+
return path.replace('~', osToHome[os].replace('${user}', username));
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
File.directory = {};
|
|
488
|
+
Object.defineProperty(File.directory, 'current', {
|
|
489
|
+
get() {
|
|
490
|
+
if(isBrowser || isJsDom){
|
|
491
|
+
const base = document.getElementsByTagName('base')[0];
|
|
492
|
+
let basedir = null;
|
|
493
|
+
if(base && (basedir = base.getAttribute('href'))){
|
|
494
|
+
return basedir;
|
|
495
|
+
}else{
|
|
496
|
+
let path = window.location.pathname;
|
|
497
|
+
path = path.split('/');
|
|
498
|
+
path.pop(); // drop the top one
|
|
499
|
+
return path .join('/');
|
|
500
|
+
}
|
|
501
|
+
}else{
|
|
502
|
+
return process.cwd();
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
set(newValue) {
|
|
506
|
+
//do nothing
|
|
507
|
+
},
|
|
508
|
+
enumerable: true,
|
|
509
|
+
configurable: true,
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
Object.defineProperty(File, 'agent', {
|
|
513
|
+
get() {
|
|
514
|
+
if(isBrowser || isJsDom){
|
|
515
|
+
//var nVer = navigator.appVersion;
|
|
516
|
+
var nAgt = navigator.userAgent;
|
|
517
|
+
var browserName = navigator.appName;
|
|
518
|
+
var fullVersion = ''+parseFloat(navigator.appVersion);
|
|
519
|
+
var majorVersion = parseInt(navigator.appVersion,10);
|
|
520
|
+
var nameOffset,verOffset,ix;
|
|
521
|
+
|
|
522
|
+
// In Opera, the true version is after "Opera" or after "Version"
|
|
523
|
+
if ((verOffset=nAgt.indexOf('Opera'))!=-1) {
|
|
524
|
+
browserName = 'Opera';
|
|
525
|
+
fullVersion = nAgt.substring(verOffset+6);
|
|
526
|
+
if ((verOffset=nAgt.indexOf('Version'))!=-1)
|
|
527
|
+
fullVersion = nAgt.substring(verOffset+8);
|
|
528
|
+
}
|
|
529
|
+
// In MSIE, the true version is after 'MSIE' in userAgent
|
|
530
|
+
else if ((verOffset=nAgt.indexOf('MSIE'))!=-1) {
|
|
531
|
+
browserName = 'Microsoft Internet Explorer';
|
|
532
|
+
fullVersion = nAgt.substring(verOffset+5);
|
|
533
|
+
}
|
|
534
|
+
// In Chrome, the true version is after 'Chrome'
|
|
535
|
+
else if ((verOffset=nAgt.indexOf('Chrome'))!=-1) {
|
|
536
|
+
browserName = 'Chrome';
|
|
537
|
+
fullVersion = nAgt.substring(verOffset+7);
|
|
538
|
+
}
|
|
539
|
+
// In Safari, the true version is after 'Safari' or after 'Version'
|
|
540
|
+
else if ((verOffset=nAgt.indexOf('Safari'))!=-1) {
|
|
541
|
+
browserName = 'Safari';
|
|
542
|
+
fullVersion = nAgt.substring(verOffset+7);
|
|
543
|
+
if ((verOffset=nAgt.indexOf('Version'))!=-1)
|
|
544
|
+
fullVersion = nAgt.substring(verOffset+8);
|
|
545
|
+
}
|
|
546
|
+
// In Firefox, the true version is after 'Firefox'
|
|
547
|
+
else if ((verOffset=nAgt.indexOf('Firefox'))!=-1) {
|
|
548
|
+
browserName = 'Firefox';
|
|
549
|
+
fullVersion = nAgt.substring(verOffset+8);
|
|
550
|
+
}
|
|
551
|
+
// In most other browsers, 'name/version' is at the end of userAgent
|
|
552
|
+
else if ( (nameOffset=nAgt.lastIndexOf(' ')+1) < (verOffset=nAgt.lastIndexOf('/')) ) {
|
|
553
|
+
browserName = nAgt.substring(nameOffset,verOffset);
|
|
554
|
+
fullVersion = nAgt.substring(verOffset+1);
|
|
555
|
+
if (browserName.toLowerCase()==browserName.toUpperCase()) {
|
|
556
|
+
browserName = navigator.appName;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
// trim the fullVersion string at semicolon/space if present
|
|
560
|
+
if ((ix=fullVersion.indexOf(';'))!=-1)
|
|
561
|
+
fullVersion=fullVersion.substring(0,ix);
|
|
562
|
+
if ((ix=fullVersion.indexOf(' '))!=-1)
|
|
563
|
+
fullVersion=fullVersion.substring(0,ix);
|
|
564
|
+
|
|
565
|
+
majorVersion = parseInt(''+fullVersion,10);
|
|
566
|
+
if (isNaN(majorVersion)) {
|
|
567
|
+
fullVersion = ''+parseFloat(navigator.appVersion);
|
|
568
|
+
majorVersion = parseInt(navigator.appVersion,10);
|
|
569
|
+
}
|
|
570
|
+
return { name: browserName.toLowerCase(), version: fullVersion, major: majorVersion };
|
|
571
|
+
}else{
|
|
572
|
+
return {};
|
|
573
|
+
}
|
|
574
|
+
},
|
|
575
|
+
set(newValue) {
|
|
576
|
+
//do nothing
|
|
577
|
+
},
|
|
578
|
+
enumerable: true,
|
|
579
|
+
configurable: true,
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
const directoryGet = (type)=>{
|
|
583
|
+
if(isBrowser || isJsDom){
|
|
584
|
+
return handleCanonicalPath('home', File.os, File.user);
|
|
585
|
+
}else{
|
|
586
|
+
return process.cwd();
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
Object.keys(canonicalLocationToPath['darwin']).forEach((key)=>{
|
|
591
|
+
// register all available keys
|
|
592
|
+
Object.defineProperty(File.directory, key, {
|
|
593
|
+
enumerable: true, configurable: true,
|
|
594
|
+
get() {
|
|
595
|
+
return directoryGet(key);
|
|
596
|
+
},
|
|
597
|
+
set(newValue){ }
|
|
598
|
+
});
|
|
599
|
+
});
|