@statewalker/webrun-files 0.1.0 → 0.2.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/dist/index-umd.js +37 -35
- package/dist/index-umd.min.js +2 -2
- package/dist/index.js +36 -36
- package/dist/index.min.js +2 -2
- package/package.json +1 -1
- package/src/index.js +1 -1
- package/src/openBrowserFilesApi.js +35 -35
package/dist/index-umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @statewalker/webrun-files v0.
|
|
1
|
+
// @statewalker/webrun-files v0.2.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
|
|
2
2
|
(function (global, factory) {
|
|
3
3
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
4
4
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
@@ -823,46 +823,46 @@ async function openBrowserFilesApi({
|
|
|
823
823
|
throw new Error("Can not access to the folder. Please try again.");
|
|
824
824
|
}
|
|
825
825
|
return new BrowserFilesApi({ rootHandler });
|
|
826
|
+
}
|
|
826
827
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
}
|
|
828
|
+
async function isHandlerAccessible(fileHandle) {
|
|
829
|
+
// We need to perform a real read operation with the handler
|
|
830
|
+
// to check if the file/directory still exists.
|
|
831
|
+
let exists = false;
|
|
832
|
+
try {
|
|
833
|
+
if (fileHandle.kind === "file") {
|
|
834
|
+
await fileHandle.getFile();
|
|
835
|
+
} else {
|
|
836
|
+
for await (let item of fileHandle.values()) {
|
|
837
|
+
break;
|
|
838
838
|
}
|
|
839
|
-
exists = true;
|
|
840
|
-
} catch (error) {
|
|
841
|
-
console.log(error, fileHandle);
|
|
842
|
-
exists = false;
|
|
843
839
|
}
|
|
844
|
-
|
|
840
|
+
exists = true;
|
|
841
|
+
} catch (error) {
|
|
842
|
+
console.log(error, fileHandle);
|
|
843
|
+
exists = false;
|
|
845
844
|
}
|
|
845
|
+
return exists;
|
|
846
|
+
}
|
|
846
847
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
}
|
|
863
|
-
// The user didn't grant permission, so return false.
|
|
864
|
-
return granted;
|
|
848
|
+
async function verifyPermission(fileHandle, readWrite) {
|
|
849
|
+
const options = {};
|
|
850
|
+
if (readWrite) {
|
|
851
|
+
options.mode = "readwrite";
|
|
852
|
+
}
|
|
853
|
+
let granted = false;
|
|
854
|
+
// Check if permission was already granted. If so, return true.
|
|
855
|
+
if ((await fileHandle.queryPermission(options)) === "granted") {
|
|
856
|
+
granted = true;
|
|
857
|
+
}
|
|
858
|
+
// Request permission. If the user grants permission, return true.
|
|
859
|
+
if (
|
|
860
|
+
!granted && (await fileHandle.requestPermission(options)) === "granted"
|
|
861
|
+
) {
|
|
862
|
+
granted = true;
|
|
865
863
|
}
|
|
864
|
+
// The user didn't grant permission, so return false.
|
|
865
|
+
return granted;
|
|
866
866
|
}
|
|
867
867
|
|
|
868
868
|
exports.BrowserFilesApi = BrowserFilesApi;
|
|
@@ -872,10 +872,12 @@ exports.NodeFilesApi = NodeFilesApi;
|
|
|
872
872
|
exports.addFilesApiLogger = addFilesApiLogger;
|
|
873
873
|
exports.extensionToMimeType = extensionToMimeType;
|
|
874
874
|
exports.getMimeType = getMimeType;
|
|
875
|
+
exports.isHandlerAccessible = isHandlerAccessible;
|
|
875
876
|
exports.mimeTypeToExtensions = mimeTypeToExtensions;
|
|
876
877
|
exports.mimeTypes = mimeTypes;
|
|
877
878
|
exports.mimeTypesDescriptions = mimeTypesDescriptions;
|
|
878
879
|
exports.normalizePath = normalizePath;
|
|
879
880
|
exports.openBrowserFilesApi = openBrowserFilesApi;
|
|
881
|
+
exports.verifyPermission = verifyPermission;
|
|
880
882
|
|
|
881
883
|
}));
|
package/dist/index-umd.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// @statewalker/webrun-files v0.
|
|
2
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).statewalker=e.statewalker||{},e.statewalker["webrun-files"]=e.statewalker["webrun-files"]||{}))}(this,(function(e){"use strict";function t(e){const t=e.split("/").filter((e=>!!e&&"."!==e));return 0===t.length&&t.push(""),t.unshift(""),t.join("/")}function i(){throw new Error("Not implemented.")}class n{constructor(e){this.options=e||{}}async*list(e,t={}){yield i()}async stats(e){return i()}async remove(e){return i()}async write(e,t){return i()}async*read(e,t){yield i()}async copy(e,t,i={}){const n=async(e,t,i)=>{t=`${t}${i.path.substring(e.length)}`;const n=this.read(i);return await this.write(t,n)},s=void 0===i.recursive||!!i.recursive,o=await this.stats(e);if("directory"===o.kind)for await(const o of this.list(e,{...i,recursive:s}))"directory"!==o.kind&&await n(e,t,o);else await n(e,t,o);return!0}async move(e,t,i={}){return!!await this.copy(e,t,i)&&(await this.remove(e),!0)}normalizePath(e){return t("object"==typeof e?e.path:e+"")}}const s=[{extensions:["aac"],mime:"audio/aac",description:"AAC audio"},{extensions:["abw"],mime:"application/x-abiword",description:"AbiWord document"},{extensions:["arc"],mime:"application/x-freearc",description:"Archive document (multiple files embedded)"},{extensions:["avi"],mime:"video/x-msvideo",description:"AVI: Audio Video Interleave"},{extensions:["azw"],mime:"application/vnd.amazon.ebook",description:"Amazon Kindle eBook format"},{extensions:["bin"],mime:"application/octet-stream",description:"Any kind of binary data"},{extensions:["bmp"],mime:"image/bmp",description:"Windows OS/2 Bitmap Graphics"},{extensions:["bz"],mime:"application/x-bzip",description:"BZip archive"},{extensions:["bz2"],mime:"application/x-bzip2",description:"BZip2 archive"},{extensions:["csh"],mime:"application/x-csh",description:"C-Shell script"},{extensions:["css"],mime:"text/css",description:"Cascading Style Sheets (CSS)"},{extensions:["csv"],mime:"text/csv",description:"Comma-separated values (CSV)"},{extensions:["doc"],mime:"application/msword",description:"Microsoft Word"},{extensions:["docx"],mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",description:"Microsoft Word (OpenXML)"},{extensions:["eot"],mime:"application/vnd.ms-fontobject",description:"MS Embedded OpenType fonts"},{extensions:["epub"],mime:"application/epub+zip",description:"Electronic publication (EPUB)"},{extensions:["gz"],mime:"application/gzip",description:"GZip Compressed Archive"},{extensions:["gif"],mime:"image/gif",description:"Graphics Interchange Format (GIF)"},{extensions:["htm","html"],mime:"text/html",description:"HyperText Markup Language (HTML)"},{extensions:["ico"],mime:"image/vnd.microsoft.icon",description:"Icon format"},{extensions:["ics"],mime:"text/calendar",description:"iCalendar format"},{extensions:["jar"],mime:"application/java-archive",description:"Java Archive (JAR)"},{extensions:["jpg","jpeg"],mime:"image/jpeg",description:"JPEG images"},{extensions:["js"],mime:"text/javascript",description:"JavaScript per the following specifications: https://html.spec.whatwg.org/multipage/#scriptingLanguages, https://html.spec.whatwg.org/multipage/#dependencies:willful-violation, https://datatracker.ietf.org/doc/draft-ietf-dispatch-javascript-mjs/"},{extensions:["json"],mime:"application/json",description:"JSON format"},{extensions:["jsonld"],mime:"application/ld+json",description:"JSON-LD format"},{extensions:["mid","midi"],mime:"application/ld+json",description:"Musical Instrument Digital Interface (MIDI)\taudio/midi audio/x-midi"},{extensions:["mjs"],mime:"text/javascript",description:"JavaScript module"},{extensions:["mp3"],mime:"audio/mpeg",description:"MP3 audio"},{extensions:["md"],mime:"text/markdown",description:"Markdown"},{extensions:["mpeg"],mime:"video/mpeg",description:"MPEG Video"},{extensions:["mpkg"],mime:"application/vnd.apple.installer+xml",description:"Apple Installer Package"},{extensions:["odp"],mime:"application/vnd.oasis.opendocument.presentation",description:"OpenDocument presentation document"},{extensions:["ods"],mime:"application/vnd.oasis.opendocument.spreadsheet",description:"OpenDocument spreadsheet document"},{extensions:["odt"],mime:"application/vnd.oasis.opendocument.text",description:"OpenDocument text document"},{extensions:["oga"],mime:"audio/ogg",description:"OGG audio"},{extensions:["ogv"],mime:"video/ogg",description:"OGG video"},{extensions:["ogx"],mime:"application/ogg",description:"OGG"},{extensions:["opus"],mime:"audio/opus",description:"Opus audio"},{extensions:["otf"],mime:"font/otf",description:"OpenType font"},{extensions:["png"],mime:"image/png",description:"Portable Network Graphics"},{extensions:["pdf"],mime:"application/pdf",description:"Adobe Portable Document Format (PDF)"},{extensions:["php"],mime:"application/x-httpd-php",description:"Hypertext Preprocessor (Personal Home Page)"},{extensions:["ppt"],mime:"application/vnd.ms-powerpoint",description:"Microsoft PowerPoint"},{extensions:["pptx"],mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation",description:"Microsoft PowerPoint (OpenXML)"},{extensions:["rar"],mime:"application/vnd.rar",description:"RAR archive"},{extensions:["rtf"],mime:"application/rtf",description:"Rich Text Format (RTF)"},{extensions:["sh"],mime:"application/x-sh",description:"Bourne shell script"},{extensions:["svg"],mime:"image/svg+xml",description:"Scalable Vector Graphics (SVG)"},{extensions:["swf"],mime:"application/x-shockwave-flash",description:"Small web format (SWF) or Adobe Flash document"},{extensions:["tar"],mime:"application/x-tar",description:"Tape Archive (TAR)"},{extensions:["tif","tiff"],mime:"image/tiff",description:"Tagged Image File Format (TIFF)"},{extensions:["ttf"],mime:"font/ttf",description:"TrueType Font"},{extensions:["txt"],mime:"text/plain",description:"Text, (generally ASCII or ISO 8859-n)"},{extensions:["vsd"],mime:"application/vnd.visio",description:"Microsoft Visio"},{extensions:["wav"],mime:"audio/wav",description:"Waveform Audio Format"},{extensions:["weba"],mime:"audio/webm",description:"WEBM audio"},{extensions:["webm"],mime:"video/webm",description:"WEBM video"},{extensions:["webp"],mime:"image/webp",description:"WEBP image"},{extensions:["woff"],mime:"font/woff",description:"Web Open Font Format (WOFF)"},{extensions:["woff2"],mime:"font/woff2",description:"Web Open Font Format (WOFF)"},{extensions:["xhtml"],mime:"application/xhtml+xml",description:"XHTML"},{extensions:["xls"],mime:"application/vnd.ms-excel",description:"Microsoft Excel"},{extensions:["xlsx"],mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",description:"Microsoft Excel (OpenXML)"},{extensions:["xml"],mime:"application/xml",description:"XML; application/xml - if not readable from casual users (RFC 3023, section 3); text/xml - if readable from casual users (RFC 3023, section 3)"},{extensions:["xul"],mime:"application/vnd.mozilla.xul+xml",description:"XUL"},{extensions:["zip"],mime:"application/zip",description:"ZIP archive"},{extensions:["3gp"],mime:"video/3gpp",description:"3GPP audio/video container"},{extensions:["3g2"],mime:"video/3gpp2",description:"3GPP2 audio/video container; audio/3gpp if it doesn't contain video; audio/3gpp2 if it doesn't contain video"},{extensions:["7z"],mime:"application/x-7z-compressed",description:"7-zip archive"},{extensions:["jsx"],mime:"text/jsx",description:"JavaScript Syntax Extension / JavaScript XML format"},{extensions:["ts"],mime:"text/ts",description:"TypeScript format"},{extensions:["tsx"],mime:"text/tsx",description:"TypeScript Syntax Extension / TypeScript XML format"}],o=s.reduce(((e,t)=>(e[t.mime]=t.description,e)),{}),a=s.reduce(((e,t)=>{for(const i of t.extensions)e[i]=t.mime;return e}),{}),r=s.reduce(((e,t)=>(e[t.mime]=t.extensions,e)),{});function c(e){const t=e=e||"",i=(e=(e=e.split("?").shift()).split("/").pop()).split(".").pop();let n=a[i];return n||(n=t.match(/api\.observablehq\.com/)||t.match(/\.ojs$/)?"application/javascript-observable":"application/binary"),n}function p(e){const t=e.split("/");return t.pop(),t.join("/")}function d(...e){let t=e.map((e=>e.split("/"))).reduce(((e,t)=>(e.push(...t),e)),[]);const i=t.shift();return t=t.filter((e=>!!e&&"."!==e)),t.unshift(i),t.join("/")}async function m(e,t){try{const i=await e.stat(t);if(i&&i.isDirectory())return!0}catch(e){}const i=p(t);return t!==i&&(await m(e,i),await e.mkdir(t,{recursive:!0}),!0)}async function l(e,t){try{if((await e.stat(t)).isDirectory()){for await(let i of f(e,t,!1))await l(e,i.path);await e.rmdir(t)}else await e.unlink(t)}catch(e){if("ENOENT"!==e.code)throw e}}async function*f(e,t,i){try{if((await e.stat(t)).isDirectory()){const n=await e.readdir(t);for(const s of n.sort()){const n=d(t,s);let o=await e.stat(n);yield{path:n,stat:o},i&&o.isDirectory()&&(yield*f(e,n,!0))}}}catch(e){if("ENOENT"!==e.code)throw e}}class h extends n{constructor(e){if(super(e),!this.rootHandler)throw new Error("Root directory handler is not defined")}get rootHandler(){return this.options.rootHandler}async*list(e,{recursive:t=!1}={}){const i=this._getPathSegments(e),n=await this._getHandler(i,!1),s=this;"directory"===n.kind&&(yield*async function*e(t,i,n){for await(const o of i.values())yield await s._getFileInfo([...t,o.name],o),n&&"directory"==o.kind&&(yield*e([...t,o.name],o,n))}(i,n,t))}async stats(e){const t=this._getPathSegments(e),i=await this._getHandler(t,!1);return i?await this._getFileInfo(t,i):null}async remove(e){let t=this._getPathSegments(e);const i=t.pop(),n=await this._getHandler(t,!1),s=[];if(i)s.push(i);else for await(const e of n.values())s.push(e.name);for(const e of s)await n.removeEntry(e,{recursive:!0});return!0}async write(e,t){const i=this._getPathSegments(e),n=await this._getFileHandler(i),s=await n.createWritable();try{"function"==typeof t&&(t=t());for await(let e of t)await s.write(e.buffer?e.buffer:e)}finally{await s.close()}}async*read(e){const t=this._getPathSegments(e),i=await this._getFileHandler(t,!1);if(!i)return;const n=(await i.getFile()).stream().getReader();try{let e;for(;(e=await n.read())&&!e.done;)yield e.value}finally{n.cancel&&n.cancel()}}async _getHandler(e,t=!1){let i;try{i=await this._getFileHandler(e,t)}catch(n){try{i=await this._getDirectoryHandler(e,t)}catch(e){}}return i}async _getDirectoryHandler(e,t=!0){e=[...e];let i=this.rootHandler;for(let n of e)i=await i.getDirectoryHandle(n,{create:t});return i}async _getFileHandler(e,t=!0){const i=(e=[...e]).pop();let n=this.rootHandler;for(let t of e)n=await n.getDirectoryHandle(t,{create:!0});return await n.getFileHandle(i,{create:t})}async _getFileInfo(e,t){const i=(e=[...e])[e.length-1];e.unshift("");const n=e.join("/"),s={kind:"",path:n,name:i};if("directory"===t.kind)s.kind="directory";else{s.kind="file";const e=await t.getFile();s.size=e.size,s.type=c(n),s.lastModified=e.lastModified}return s}_getPathSegments(e){return("object"==typeof e?e.path:e+"").split("/").filter((e=>!!e))}}e.BrowserFilesApi=h,e.FilesApi=n,e.MemFilesApi=class extends n{constructor(e){super(e),this.index={"/":{kind:"directory",path:"/",name:""}}}async*list(e,{recursive:t=!1}={}){await this._init();const i=this.normalizePath(e),n=this._getPaths();for(const e of n){if(0!==e.indexOf(i)||e===i)continue;const n=e.substring(i.length+1).split("/");(t||1===n.length)&&(yield this._getFileInfo(e))}}async stats(e){await this._init();const t=this.normalizePath(e);return this._getFileInfo(t)}async remove(e){await this._init();const t=await this.stats(e);if(!t)return!1;for await(const{path:e}of this.list(t,{recursive:!0}))"/"!==e&&delete this.index[e];delete this.index[t.path]}async write(e,t){await this._init(),await this._doWrite(e,t)}async*read(e){await this._init();const t=this.normalizePath(e),i=this.index[t];if(!i||"file"!==i.kind)return;const n=i.content;yield*n}async _init(){return this._initPromise=this._initPromise||Promise.resolve().then((()=>this._addEntries(this.options.files)))}async _doWrite(e,t){const i=this.normalizePath(e).split("/").filter((e=>!!e)),n=[""];let s;for(let e=0;e<i.length;e++){const t=i[e];n.push(t);const o=n.join("/");s=this.index[o]=this.index[o]||{path:o,name:t,kind:"directory"}}s.kind="file",s.content=[],s.type=c(s.path),s.size=0,s.lastModified=Date.now(),"function"==typeof t&&(t=t());for await(let e of t)e=new Uint8Array(e),s.content.push(e),s.size+=e.length}async _addEntries(e={}){for(let[t,i]of Object.entries(e))"string"==typeof i?i=[(new TextEncoder).encode(i)]:i instanceof Uint8Array&&(i=[i]),await this._doWrite(t,i)}_getPaths(){return this._getIndexPaths(this.index)}_getIndexPaths(e){return Object.keys(e).sort((function(e,t){return e>t?1:e<t?-1:0}))}_getFileInfo(e){const t=this.index[e];if(!t)return null;const i={...t};return delete i.content,i}},e.NodeFilesApi=class extends n{constructor(e){if(super(e),!this.fs)throw new Error("File System is not defined.");if(!this.rootDir)throw new Error("Root directory is not defined.")}get rootDirSegments(){return this._rootDirSegments||(this._rootDirSegments=this._toPathSegments(this.options.rootDir||"./")),this._rootDirSegments}get rootDir(){return this._rootDir||(this._rootDir=this.rootDirSegments.join("/")),this._rootDir}get fs(){return this.options.fs}async _init(){return this._initialized=this._initialized||(async()=>{const e=this.rootDir;return await m(this.fs,e)})()}async*list(e,{recursive:t=!1}={}){await this._init();const i=this._expandPath(e),n=await this._stats(i);if(n&&"directory"===n.kind)for await(let e of f(this.fs,i,t))yield this._getFileInfo(e.path,e.stat)}async stats(e){await this._init();const t=this._expandPath(e);return this._stats(t)}async remove(e){await this._init();const t=this._expandPath(e);return await l(this.fs,t)}async write(e,t){await this._init();const i=this._expandPath(e),n=p(i);let s;await this.fs.mkdir(n,{recursive:!0});try{s=await this.fs.open(i,"w"),"function"==typeof t&&(t=t()),await s.writeFile(t)}finally{s&&await s.close()}}async*read(e,{start:t=0,bufferSize:i=8192}={}){await this._init();const n=this._expandPath(e);let s;try{s=await this.fs.open(n,"r");const e=0;for(let n=t,o=0;;n+=o){const t=new Uint8ClampedArray(i),a=await s.read(t,e,i,n);if(o=a.bytesRead,0===o)break;yield o<i?a.buffer.slice(0,o):a.buffer}}finally{s&&await s.close()}}async _stats(e){try{const t=await this.fs.stat(e);return this._getFileInfo(e,t)}catch(e){if("ENOENT"!==e.code)throw e;return null}}_getFileInfo(e,t){const i=this._toPathSegments(e).slice(this.rootDirSegments.length);i.unshift("");const n=i[i.length-1];let s={path:e=i.join("/"),name:n,kind:""};return t.isFile()?(s.size=t.size||0,s.type=c(e),s.kind="file",s.lastModified=new Date(t.mtime).getTime()):s.kind="directory",s}_toPathSegments(e){return(e=this.normalizePath(e)).split("/")}_expandPath(e){const t="object"==typeof e?e.path:e+"",i=this._toPathSegments(t).filter((e=>!!e));return i.unshift(...this.rootDirSegments),i.join("/")}},e.addFilesApiLogger=function({filesApi:e,log:t=console.log,wrapper:i={}}){return["list","stats","remove","write","read","copy","move"].reduce(((i,n)=>{const s=e[n].bind(e);return i[n]=(...i)=>{let o={method:n,stage:"enter",args:i};try{return t(o),o.result=s.call(e,...i)}catch(e){o.error=e}finally{o.stage="exit",t(o)}},i}),i)},e.extensionToMimeType=a,e.getMimeType=c,e.mimeTypeToExtensions=r,e.mimeTypes=s,e.mimeTypesDescriptions=o,e.normalizePath=t,e.openBrowserFilesApi=async function({handlerKey:e="root-dir",readwrite:t=!0,index:i={},get:n=(async e=>i[e]),set:s=(async(e,t)=>i[e]=t),del:o=(async e=>delete i[e])}={}){let a=await n(e);if(a||(a=await window.showDirectoryPicker(),await s(e,a)),!await async function(e,t){const i={};t&&(i.mode="readwrite");let n=!1;"granted"===await e.queryPermission(i)&&(n=!0);n||"granted"!==await e.requestPermission(i)||(n=!0);return n}(a,t))throw new Error("Access was not granted");if(!await async function(e){let t=!1;try{if("file"===e.kind)await e.getFile();else for await(let t of e.values())break;t=!0}catch(i){console.log(i,e),t=!1}return t}(a))throw await o(e),new Error("Can not access to the folder. Please try again.");return new h({rootHandler:a})}}));
|
|
1
|
+
// @statewalker/webrun-files v0.2.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
|
|
2
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).statewalker=e.statewalker||{},e.statewalker["webrun-files"]=e.statewalker["webrun-files"]||{}))}(this,(function(e){"use strict";function t(e){const t=e.split("/").filter((e=>!!e&&"."!==e));return 0===t.length&&t.push(""),t.unshift(""),t.join("/")}function i(){throw new Error("Not implemented.")}class n{constructor(e){this.options=e||{}}async*list(e,t={}){yield i()}async stats(e){return i()}async remove(e){return i()}async write(e,t){return i()}async*read(e,t){yield i()}async copy(e,t,i={}){const n=async(e,t,i)=>{t=`${t}${i.path.substring(e.length)}`;const n=this.read(i);return await this.write(t,n)},s=void 0===i.recursive||!!i.recursive,o=await this.stats(e);if("directory"===o.kind)for await(const o of this.list(e,{...i,recursive:s}))"directory"!==o.kind&&await n(e,t,o);else await n(e,t,o);return!0}async move(e,t,i={}){return!!await this.copy(e,t,i)&&(await this.remove(e),!0)}normalizePath(e){return t("object"==typeof e?e.path:e+"")}}const s=[{extensions:["aac"],mime:"audio/aac",description:"AAC audio"},{extensions:["abw"],mime:"application/x-abiword",description:"AbiWord document"},{extensions:["arc"],mime:"application/x-freearc",description:"Archive document (multiple files embedded)"},{extensions:["avi"],mime:"video/x-msvideo",description:"AVI: Audio Video Interleave"},{extensions:["azw"],mime:"application/vnd.amazon.ebook",description:"Amazon Kindle eBook format"},{extensions:["bin"],mime:"application/octet-stream",description:"Any kind of binary data"},{extensions:["bmp"],mime:"image/bmp",description:"Windows OS/2 Bitmap Graphics"},{extensions:["bz"],mime:"application/x-bzip",description:"BZip archive"},{extensions:["bz2"],mime:"application/x-bzip2",description:"BZip2 archive"},{extensions:["csh"],mime:"application/x-csh",description:"C-Shell script"},{extensions:["css"],mime:"text/css",description:"Cascading Style Sheets (CSS)"},{extensions:["csv"],mime:"text/csv",description:"Comma-separated values (CSV)"},{extensions:["doc"],mime:"application/msword",description:"Microsoft Word"},{extensions:["docx"],mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",description:"Microsoft Word (OpenXML)"},{extensions:["eot"],mime:"application/vnd.ms-fontobject",description:"MS Embedded OpenType fonts"},{extensions:["epub"],mime:"application/epub+zip",description:"Electronic publication (EPUB)"},{extensions:["gz"],mime:"application/gzip",description:"GZip Compressed Archive"},{extensions:["gif"],mime:"image/gif",description:"Graphics Interchange Format (GIF)"},{extensions:["htm","html"],mime:"text/html",description:"HyperText Markup Language (HTML)"},{extensions:["ico"],mime:"image/vnd.microsoft.icon",description:"Icon format"},{extensions:["ics"],mime:"text/calendar",description:"iCalendar format"},{extensions:["jar"],mime:"application/java-archive",description:"Java Archive (JAR)"},{extensions:["jpg","jpeg"],mime:"image/jpeg",description:"JPEG images"},{extensions:["js"],mime:"text/javascript",description:"JavaScript per the following specifications: https://html.spec.whatwg.org/multipage/#scriptingLanguages, https://html.spec.whatwg.org/multipage/#dependencies:willful-violation, https://datatracker.ietf.org/doc/draft-ietf-dispatch-javascript-mjs/"},{extensions:["json"],mime:"application/json",description:"JSON format"},{extensions:["jsonld"],mime:"application/ld+json",description:"JSON-LD format"},{extensions:["mid","midi"],mime:"application/ld+json",description:"Musical Instrument Digital Interface (MIDI)\taudio/midi audio/x-midi"},{extensions:["mjs"],mime:"text/javascript",description:"JavaScript module"},{extensions:["mp3"],mime:"audio/mpeg",description:"MP3 audio"},{extensions:["md"],mime:"text/markdown",description:"Markdown"},{extensions:["mpeg"],mime:"video/mpeg",description:"MPEG Video"},{extensions:["mpkg"],mime:"application/vnd.apple.installer+xml",description:"Apple Installer Package"},{extensions:["odp"],mime:"application/vnd.oasis.opendocument.presentation",description:"OpenDocument presentation document"},{extensions:["ods"],mime:"application/vnd.oasis.opendocument.spreadsheet",description:"OpenDocument spreadsheet document"},{extensions:["odt"],mime:"application/vnd.oasis.opendocument.text",description:"OpenDocument text document"},{extensions:["oga"],mime:"audio/ogg",description:"OGG audio"},{extensions:["ogv"],mime:"video/ogg",description:"OGG video"},{extensions:["ogx"],mime:"application/ogg",description:"OGG"},{extensions:["opus"],mime:"audio/opus",description:"Opus audio"},{extensions:["otf"],mime:"font/otf",description:"OpenType font"},{extensions:["png"],mime:"image/png",description:"Portable Network Graphics"},{extensions:["pdf"],mime:"application/pdf",description:"Adobe Portable Document Format (PDF)"},{extensions:["php"],mime:"application/x-httpd-php",description:"Hypertext Preprocessor (Personal Home Page)"},{extensions:["ppt"],mime:"application/vnd.ms-powerpoint",description:"Microsoft PowerPoint"},{extensions:["pptx"],mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation",description:"Microsoft PowerPoint (OpenXML)"},{extensions:["rar"],mime:"application/vnd.rar",description:"RAR archive"},{extensions:["rtf"],mime:"application/rtf",description:"Rich Text Format (RTF)"},{extensions:["sh"],mime:"application/x-sh",description:"Bourne shell script"},{extensions:["svg"],mime:"image/svg+xml",description:"Scalable Vector Graphics (SVG)"},{extensions:["swf"],mime:"application/x-shockwave-flash",description:"Small web format (SWF) or Adobe Flash document"},{extensions:["tar"],mime:"application/x-tar",description:"Tape Archive (TAR)"},{extensions:["tif","tiff"],mime:"image/tiff",description:"Tagged Image File Format (TIFF)"},{extensions:["ttf"],mime:"font/ttf",description:"TrueType Font"},{extensions:["txt"],mime:"text/plain",description:"Text, (generally ASCII or ISO 8859-n)"},{extensions:["vsd"],mime:"application/vnd.visio",description:"Microsoft Visio"},{extensions:["wav"],mime:"audio/wav",description:"Waveform Audio Format"},{extensions:["weba"],mime:"audio/webm",description:"WEBM audio"},{extensions:["webm"],mime:"video/webm",description:"WEBM video"},{extensions:["webp"],mime:"image/webp",description:"WEBP image"},{extensions:["woff"],mime:"font/woff",description:"Web Open Font Format (WOFF)"},{extensions:["woff2"],mime:"font/woff2",description:"Web Open Font Format (WOFF)"},{extensions:["xhtml"],mime:"application/xhtml+xml",description:"XHTML"},{extensions:["xls"],mime:"application/vnd.ms-excel",description:"Microsoft Excel"},{extensions:["xlsx"],mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",description:"Microsoft Excel (OpenXML)"},{extensions:["xml"],mime:"application/xml",description:"XML; application/xml - if not readable from casual users (RFC 3023, section 3); text/xml - if readable from casual users (RFC 3023, section 3)"},{extensions:["xul"],mime:"application/vnd.mozilla.xul+xml",description:"XUL"},{extensions:["zip"],mime:"application/zip",description:"ZIP archive"},{extensions:["3gp"],mime:"video/3gpp",description:"3GPP audio/video container"},{extensions:["3g2"],mime:"video/3gpp2",description:"3GPP2 audio/video container; audio/3gpp if it doesn't contain video; audio/3gpp2 if it doesn't contain video"},{extensions:["7z"],mime:"application/x-7z-compressed",description:"7-zip archive"},{extensions:["jsx"],mime:"text/jsx",description:"JavaScript Syntax Extension / JavaScript XML format"},{extensions:["ts"],mime:"text/ts",description:"TypeScript format"},{extensions:["tsx"],mime:"text/tsx",description:"TypeScript Syntax Extension / TypeScript XML format"}],o=s.reduce(((e,t)=>(e[t.mime]=t.description,e)),{}),a=s.reduce(((e,t)=>{for(const i of t.extensions)e[i]=t.mime;return e}),{}),r=s.reduce(((e,t)=>(e[t.mime]=t.extensions,e)),{});function c(e){const t=e=e||"",i=(e=(e=e.split("?").shift()).split("/").pop()).split(".").pop();let n=a[i];return n||(n=t.match(/api\.observablehq\.com/)||t.match(/\.ojs$/)?"application/javascript-observable":"application/binary"),n}function p(e){const t=e.split("/");return t.pop(),t.join("/")}function d(...e){let t=e.map((e=>e.split("/"))).reduce(((e,t)=>(e.push(...t),e)),[]);const i=t.shift();return t=t.filter((e=>!!e&&"."!==e)),t.unshift(i),t.join("/")}async function m(e,t){try{const i=await e.stat(t);if(i&&i.isDirectory())return!0}catch(e){}const i=p(t);return t!==i&&(await m(e,i),await e.mkdir(t,{recursive:!0}),!0)}async function l(e,t){try{if((await e.stat(t)).isDirectory()){for await(let i of f(e,t,!1))await l(e,i.path);await e.rmdir(t)}else await e.unlink(t)}catch(e){if("ENOENT"!==e.code)throw e}}async function*f(e,t,i){try{if((await e.stat(t)).isDirectory()){const n=await e.readdir(t);for(const s of n.sort()){const n=d(t,s);let o=await e.stat(n);yield{path:n,stat:o},i&&o.isDirectory()&&(yield*f(e,n,!0))}}}catch(e){if("ENOENT"!==e.code)throw e}}class h extends n{constructor(e){if(super(e),!this.rootHandler)throw new Error("Root directory handler is not defined")}get rootHandler(){return this.options.rootHandler}async*list(e,{recursive:t=!1}={}){const i=this._getPathSegments(e),n=await this._getHandler(i,!1),s=this;"directory"===n.kind&&(yield*async function*e(t,i,n){for await(const o of i.values())yield await s._getFileInfo([...t,o.name],o),n&&"directory"==o.kind&&(yield*e([...t,o.name],o,n))}(i,n,t))}async stats(e){const t=this._getPathSegments(e),i=await this._getHandler(t,!1);return i?await this._getFileInfo(t,i):null}async remove(e){let t=this._getPathSegments(e);const i=t.pop(),n=await this._getHandler(t,!1),s=[];if(i)s.push(i);else for await(const e of n.values())s.push(e.name);for(const e of s)await n.removeEntry(e,{recursive:!0});return!0}async write(e,t){const i=this._getPathSegments(e),n=await this._getFileHandler(i),s=await n.createWritable();try{"function"==typeof t&&(t=t());for await(let e of t)await s.write(e.buffer?e.buffer:e)}finally{await s.close()}}async*read(e){const t=this._getPathSegments(e),i=await this._getFileHandler(t,!1);if(!i)return;const n=(await i.getFile()).stream().getReader();try{let e;for(;(e=await n.read())&&!e.done;)yield e.value}finally{n.cancel&&n.cancel()}}async _getHandler(e,t=!1){let i;try{i=await this._getFileHandler(e,t)}catch(n){try{i=await this._getDirectoryHandler(e,t)}catch(e){}}return i}async _getDirectoryHandler(e,t=!0){e=[...e];let i=this.rootHandler;for(let n of e)i=await i.getDirectoryHandle(n,{create:t});return i}async _getFileHandler(e,t=!0){const i=(e=[...e]).pop();let n=this.rootHandler;for(let t of e)n=await n.getDirectoryHandle(t,{create:!0});return await n.getFileHandle(i,{create:t})}async _getFileInfo(e,t){const i=(e=[...e])[e.length-1];e.unshift("");const n=e.join("/"),s={kind:"",path:n,name:i};if("directory"===t.kind)s.kind="directory";else{s.kind="file";const e=await t.getFile();s.size=e.size,s.type=c(n),s.lastModified=e.lastModified}return s}_getPathSegments(e){return("object"==typeof e?e.path:e+"").split("/").filter((e=>!!e))}}async function u(e){let t=!1;try{if("file"===e.kind)await e.getFile();else for await(let t of e.values())break;t=!0}catch(i){console.log(i,e),t=!1}return t}async function x(e,t){const i={};t&&(i.mode="readwrite");let n=!1;return"granted"===await e.queryPermission(i)&&(n=!0),n||"granted"!==await e.requestPermission(i)||(n=!0),n}e.BrowserFilesApi=h,e.FilesApi=n,e.MemFilesApi=class extends n{constructor(e){super(e),this.index={"/":{kind:"directory",path:"/",name:""}}}async*list(e,{recursive:t=!1}={}){await this._init();const i=this.normalizePath(e),n=this._getPaths();for(const e of n){if(0!==e.indexOf(i)||e===i)continue;const n=e.substring(i.length+1).split("/");(t||1===n.length)&&(yield this._getFileInfo(e))}}async stats(e){await this._init();const t=this.normalizePath(e);return this._getFileInfo(t)}async remove(e){await this._init();const t=await this.stats(e);if(!t)return!1;for await(const{path:e}of this.list(t,{recursive:!0}))"/"!==e&&delete this.index[e];delete this.index[t.path]}async write(e,t){await this._init(),await this._doWrite(e,t)}async*read(e){await this._init();const t=this.normalizePath(e),i=this.index[t];if(!i||"file"!==i.kind)return;const n=i.content;yield*n}async _init(){return this._initPromise=this._initPromise||Promise.resolve().then((()=>this._addEntries(this.options.files)))}async _doWrite(e,t){const i=this.normalizePath(e).split("/").filter((e=>!!e)),n=[""];let s;for(let e=0;e<i.length;e++){const t=i[e];n.push(t);const o=n.join("/");s=this.index[o]=this.index[o]||{path:o,name:t,kind:"directory"}}s.kind="file",s.content=[],s.type=c(s.path),s.size=0,s.lastModified=Date.now(),"function"==typeof t&&(t=t());for await(let e of t)e=new Uint8Array(e),s.content.push(e),s.size+=e.length}async _addEntries(e={}){for(let[t,i]of Object.entries(e))"string"==typeof i?i=[(new TextEncoder).encode(i)]:i instanceof Uint8Array&&(i=[i]),await this._doWrite(t,i)}_getPaths(){return this._getIndexPaths(this.index)}_getIndexPaths(e){return Object.keys(e).sort((function(e,t){return e>t?1:e<t?-1:0}))}_getFileInfo(e){const t=this.index[e];if(!t)return null;const i={...t};return delete i.content,i}},e.NodeFilesApi=class extends n{constructor(e){if(super(e),!this.fs)throw new Error("File System is not defined.");if(!this.rootDir)throw new Error("Root directory is not defined.")}get rootDirSegments(){return this._rootDirSegments||(this._rootDirSegments=this._toPathSegments(this.options.rootDir||"./")),this._rootDirSegments}get rootDir(){return this._rootDir||(this._rootDir=this.rootDirSegments.join("/")),this._rootDir}get fs(){return this.options.fs}async _init(){return this._initialized=this._initialized||(async()=>{const e=this.rootDir;return await m(this.fs,e)})()}async*list(e,{recursive:t=!1}={}){await this._init();const i=this._expandPath(e),n=await this._stats(i);if(n&&"directory"===n.kind)for await(let e of f(this.fs,i,t))yield this._getFileInfo(e.path,e.stat)}async stats(e){await this._init();const t=this._expandPath(e);return this._stats(t)}async remove(e){await this._init();const t=this._expandPath(e);return await l(this.fs,t)}async write(e,t){await this._init();const i=this._expandPath(e),n=p(i);let s;await this.fs.mkdir(n,{recursive:!0});try{s=await this.fs.open(i,"w"),"function"==typeof t&&(t=t()),await s.writeFile(t)}finally{s&&await s.close()}}async*read(e,{start:t=0,bufferSize:i=8192}={}){await this._init();const n=this._expandPath(e);let s;try{s=await this.fs.open(n,"r");const e=0;for(let n=t,o=0;;n+=o){const t=new Uint8ClampedArray(i),a=await s.read(t,e,i,n);if(o=a.bytesRead,0===o)break;yield o<i?a.buffer.slice(0,o):a.buffer}}finally{s&&await s.close()}}async _stats(e){try{const t=await this.fs.stat(e);return this._getFileInfo(e,t)}catch(e){if("ENOENT"!==e.code)throw e;return null}}_getFileInfo(e,t){const i=this._toPathSegments(e).slice(this.rootDirSegments.length);i.unshift("");const n=i[i.length-1];let s={path:e=i.join("/"),name:n,kind:""};return t.isFile()?(s.size=t.size||0,s.type=c(e),s.kind="file",s.lastModified=new Date(t.mtime).getTime()):s.kind="directory",s}_toPathSegments(e){return(e=this.normalizePath(e)).split("/")}_expandPath(e){const t="object"==typeof e?e.path:e+"",i=this._toPathSegments(t).filter((e=>!!e));return i.unshift(...this.rootDirSegments),i.join("/")}},e.addFilesApiLogger=function({filesApi:e,log:t=console.log,wrapper:i={}}){return["list","stats","remove","write","read","copy","move"].reduce(((i,n)=>{const s=e[n].bind(e);return i[n]=(...i)=>{let o={method:n,stage:"enter",args:i};try{return t(o),o.result=s.call(e,...i)}catch(e){o.error=e}finally{o.stage="exit",t(o)}},i}),i)},e.extensionToMimeType=a,e.getMimeType=c,e.isHandlerAccessible=u,e.mimeTypeToExtensions=r,e.mimeTypes=s,e.mimeTypesDescriptions=o,e.normalizePath=t,e.openBrowserFilesApi=async function({handlerKey:e="root-dir",readwrite:t=!0,index:i={},get:n=(async e=>i[e]),set:s=(async(e,t)=>i[e]=t),del:o=(async e=>delete i[e])}={}){let a=await n(e);if(a||(a=await window.showDirectoryPicker(),await s(e,a)),!await x(a,t))throw new Error("Access was not granted");if(!await u(a))throw await o(e),new Error("Can not access to the folder. Please try again.");return new h({rootHandler:a})},e.verifyPermission=x}));
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @statewalker/webrun-files v0.
|
|
1
|
+
// @statewalker/webrun-files v0.2.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
|
|
2
2
|
function normalizePath(filePath) {
|
|
3
3
|
const segments = filePath.split("/").filter((s) => !!s && s !== ".");
|
|
4
4
|
if (segments.length === 0) {
|
|
@@ -817,46 +817,46 @@ async function openBrowserFilesApi({
|
|
|
817
817
|
throw new Error("Can not access to the folder. Please try again.");
|
|
818
818
|
}
|
|
819
819
|
return new BrowserFilesApi({ rootHandler });
|
|
820
|
+
}
|
|
820
821
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
822
|
+
async function isHandlerAccessible(fileHandle) {
|
|
823
|
+
// We need to perform a real read operation with the handler
|
|
824
|
+
// to check if the file/directory still exists.
|
|
825
|
+
let exists = false;
|
|
826
|
+
try {
|
|
827
|
+
if (fileHandle.kind === "file") {
|
|
828
|
+
await fileHandle.getFile();
|
|
829
|
+
} else {
|
|
830
|
+
for await (let item of fileHandle.values()) {
|
|
831
|
+
break;
|
|
832
832
|
}
|
|
833
|
-
exists = true;
|
|
834
|
-
} catch (error) {
|
|
835
|
-
console.log(error, fileHandle);
|
|
836
|
-
exists = false;
|
|
837
833
|
}
|
|
838
|
-
|
|
834
|
+
exists = true;
|
|
835
|
+
} catch (error) {
|
|
836
|
+
console.log(error, fileHandle);
|
|
837
|
+
exists = false;
|
|
839
838
|
}
|
|
839
|
+
return exists;
|
|
840
|
+
}
|
|
840
841
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
}
|
|
857
|
-
// The user didn't grant permission, so return false.
|
|
858
|
-
return granted;
|
|
842
|
+
async function verifyPermission(fileHandle, readWrite) {
|
|
843
|
+
const options = {};
|
|
844
|
+
if (readWrite) {
|
|
845
|
+
options.mode = "readwrite";
|
|
846
|
+
}
|
|
847
|
+
let granted = false;
|
|
848
|
+
// Check if permission was already granted. If so, return true.
|
|
849
|
+
if ((await fileHandle.queryPermission(options)) === "granted") {
|
|
850
|
+
granted = true;
|
|
851
|
+
}
|
|
852
|
+
// Request permission. If the user grants permission, return true.
|
|
853
|
+
if (
|
|
854
|
+
!granted && (await fileHandle.requestPermission(options)) === "granted"
|
|
855
|
+
) {
|
|
856
|
+
granted = true;
|
|
859
857
|
}
|
|
858
|
+
// The user didn't grant permission, so return false.
|
|
859
|
+
return granted;
|
|
860
860
|
}
|
|
861
861
|
|
|
862
|
-
export { BrowserFilesApi, FilesApi, MemFilesApi, NodeFilesApi, addFilesApiLogger, extensionToMimeType, getMimeType, mimeTypeToExtensions, mimeTypes, mimeTypesDescriptions, normalizePath, openBrowserFilesApi };
|
|
862
|
+
export { BrowserFilesApi, FilesApi, MemFilesApi, NodeFilesApi, addFilesApiLogger, extensionToMimeType, getMimeType, isHandlerAccessible, mimeTypeToExtensions, mimeTypes, mimeTypesDescriptions, normalizePath, openBrowserFilesApi, verifyPermission };
|
package/dist/index.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// @statewalker/webrun-files v0.
|
|
2
|
-
function t(t){const e=t.split("/").filter((t=>!!t&&"."!==t));return 0===e.length&&e.push(""),e.unshift(""),e.join("/")}function e(){throw new Error("Not implemented.")}class i{constructor(t){this.options=t||{}}async*list(t,i={}){yield e()}async stats(t){return e()}async remove(t){return e()}async write(t,i){return e()}async*read(t,i){yield e()}async copy(t,e,i={}){const n=async(t,e,i)=>{e=`${e}${i.path.substring(t.length)}`;const n=this.read(i);return await this.write(e,n)},s=void 0===i.recursive||!!i.recursive,o=await this.stats(t);if("directory"===o.kind)for await(const o of this.list(t,{...i,recursive:s}))"directory"!==o.kind&&await n(t,e,o);else await n(t,e,o);return!0}async move(t,e,i={}){return!!await this.copy(t,e,i)&&(await this.remove(t),!0)}normalizePath(e){return t("object"==typeof e?e.path:e+"")}}const n=[{extensions:["aac"],mime:"audio/aac",description:"AAC audio"},{extensions:["abw"],mime:"application/x-abiword",description:"AbiWord document"},{extensions:["arc"],mime:"application/x-freearc",description:"Archive document (multiple files embedded)"},{extensions:["avi"],mime:"video/x-msvideo",description:"AVI: Audio Video Interleave"},{extensions:["azw"],mime:"application/vnd.amazon.ebook",description:"Amazon Kindle eBook format"},{extensions:["bin"],mime:"application/octet-stream",description:"Any kind of binary data"},{extensions:["bmp"],mime:"image/bmp",description:"Windows OS/2 Bitmap Graphics"},{extensions:["bz"],mime:"application/x-bzip",description:"BZip archive"},{extensions:["bz2"],mime:"application/x-bzip2",description:"BZip2 archive"},{extensions:["csh"],mime:"application/x-csh",description:"C-Shell script"},{extensions:["css"],mime:"text/css",description:"Cascading Style Sheets (CSS)"},{extensions:["csv"],mime:"text/csv",description:"Comma-separated values (CSV)"},{extensions:["doc"],mime:"application/msword",description:"Microsoft Word"},{extensions:["docx"],mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",description:"Microsoft Word (OpenXML)"},{extensions:["eot"],mime:"application/vnd.ms-fontobject",description:"MS Embedded OpenType fonts"},{extensions:["epub"],mime:"application/epub+zip",description:"Electronic publication (EPUB)"},{extensions:["gz"],mime:"application/gzip",description:"GZip Compressed Archive"},{extensions:["gif"],mime:"image/gif",description:"Graphics Interchange Format (GIF)"},{extensions:["htm","html"],mime:"text/html",description:"HyperText Markup Language (HTML)"},{extensions:["ico"],mime:"image/vnd.microsoft.icon",description:"Icon format"},{extensions:["ics"],mime:"text/calendar",description:"iCalendar format"},{extensions:["jar"],mime:"application/java-archive",description:"Java Archive (JAR)"},{extensions:["jpg","jpeg"],mime:"image/jpeg",description:"JPEG images"},{extensions:["js"],mime:"text/javascript",description:"JavaScript per the following specifications: https://html.spec.whatwg.org/multipage/#scriptingLanguages, https://html.spec.whatwg.org/multipage/#dependencies:willful-violation, https://datatracker.ietf.org/doc/draft-ietf-dispatch-javascript-mjs/"},{extensions:["json"],mime:"application/json",description:"JSON format"},{extensions:["jsonld"],mime:"application/ld+json",description:"JSON-LD format"},{extensions:["mid","midi"],mime:"application/ld+json",description:"Musical Instrument Digital Interface (MIDI)\taudio/midi audio/x-midi"},{extensions:["mjs"],mime:"text/javascript",description:"JavaScript module"},{extensions:["mp3"],mime:"audio/mpeg",description:"MP3 audio"},{extensions:["md"],mime:"text/markdown",description:"Markdown"},{extensions:["mpeg"],mime:"video/mpeg",description:"MPEG Video"},{extensions:["mpkg"],mime:"application/vnd.apple.installer+xml",description:"Apple Installer Package"},{extensions:["odp"],mime:"application/vnd.oasis.opendocument.presentation",description:"OpenDocument presentation document"},{extensions:["ods"],mime:"application/vnd.oasis.opendocument.spreadsheet",description:"OpenDocument spreadsheet document"},{extensions:["odt"],mime:"application/vnd.oasis.opendocument.text",description:"OpenDocument text document"},{extensions:["oga"],mime:"audio/ogg",description:"OGG audio"},{extensions:["ogv"],mime:"video/ogg",description:"OGG video"},{extensions:["ogx"],mime:"application/ogg",description:"OGG"},{extensions:["opus"],mime:"audio/opus",description:"Opus audio"},{extensions:["otf"],mime:"font/otf",description:"OpenType font"},{extensions:["png"],mime:"image/png",description:"Portable Network Graphics"},{extensions:["pdf"],mime:"application/pdf",description:"Adobe Portable Document Format (PDF)"},{extensions:["php"],mime:"application/x-httpd-php",description:"Hypertext Preprocessor (Personal Home Page)"},{extensions:["ppt"],mime:"application/vnd.ms-powerpoint",description:"Microsoft PowerPoint"},{extensions:["pptx"],mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation",description:"Microsoft PowerPoint (OpenXML)"},{extensions:["rar"],mime:"application/vnd.rar",description:"RAR archive"},{extensions:["rtf"],mime:"application/rtf",description:"Rich Text Format (RTF)"},{extensions:["sh"],mime:"application/x-sh",description:"Bourne shell script"},{extensions:["svg"],mime:"image/svg+xml",description:"Scalable Vector Graphics (SVG)"},{extensions:["swf"],mime:"application/x-shockwave-flash",description:"Small web format (SWF) or Adobe Flash document"},{extensions:["tar"],mime:"application/x-tar",description:"Tape Archive (TAR)"},{extensions:["tif","tiff"],mime:"image/tiff",description:"Tagged Image File Format (TIFF)"},{extensions:["ttf"],mime:"font/ttf",description:"TrueType Font"},{extensions:["txt"],mime:"text/plain",description:"Text, (generally ASCII or ISO 8859-n)"},{extensions:["vsd"],mime:"application/vnd.visio",description:"Microsoft Visio"},{extensions:["wav"],mime:"audio/wav",description:"Waveform Audio Format"},{extensions:["weba"],mime:"audio/webm",description:"WEBM audio"},{extensions:["webm"],mime:"video/webm",description:"WEBM video"},{extensions:["webp"],mime:"image/webp",description:"WEBP image"},{extensions:["woff"],mime:"font/woff",description:"Web Open Font Format (WOFF)"},{extensions:["woff2"],mime:"font/woff2",description:"Web Open Font Format (WOFF)"},{extensions:["xhtml"],mime:"application/xhtml+xml",description:"XHTML"},{extensions:["xls"],mime:"application/vnd.ms-excel",description:"Microsoft Excel"},{extensions:["xlsx"],mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",description:"Microsoft Excel (OpenXML)"},{extensions:["xml"],mime:"application/xml",description:"XML; application/xml - if not readable from casual users (RFC 3023, section 3); text/xml - if readable from casual users (RFC 3023, section 3)"},{extensions:["xul"],mime:"application/vnd.mozilla.xul+xml",description:"XUL"},{extensions:["zip"],mime:"application/zip",description:"ZIP archive"},{extensions:["3gp"],mime:"video/3gpp",description:"3GPP audio/video container"},{extensions:["3g2"],mime:"video/3gpp2",description:"3GPP2 audio/video container; audio/3gpp if it doesn't contain video; audio/3gpp2 if it doesn't contain video"},{extensions:["7z"],mime:"application/x-7z-compressed",description:"7-zip archive"},{extensions:["jsx"],mime:"text/jsx",description:"JavaScript Syntax Extension / JavaScript XML format"},{extensions:["ts"],mime:"text/ts",description:"TypeScript format"},{extensions:["tsx"],mime:"text/tsx",description:"TypeScript Syntax Extension / TypeScript XML format"}],s=n.reduce(((t,e)=>(t[e.mime]=e.description,t)),{}),o=n.reduce(((t,e)=>{for(const i of e.extensions)t[i]=e.mime;return t}),{}),a=n.reduce(((t,e)=>(t[e.mime]=e.extensions,t)),{});function r(t){const e=t=t||"",i=(t=(t=t.split("?").shift()).split("/").pop()).split(".").pop();let n=o[i];return n||(n=e.match(/api\.observablehq\.com/)||e.match(/\.ojs$/)?"application/javascript-observable":"application/binary"),n}class c extends i{constructor(t){super(t),this.index={"/":{kind:"directory",path:"/",name:""}}}async*list(t,{recursive:e=!1}={}){await this._init();const i=this.normalizePath(t),n=this._getPaths();for(const t of n){if(0!==t.indexOf(i)||t===i)continue;const n=t.substring(i.length+1).split("/");(e||1===n.length)&&(yield this._getFileInfo(t))}}async stats(t){await this._init();const e=this.normalizePath(t);return this._getFileInfo(e)}async remove(t){await this._init();const e=await this.stats(t);if(!e)return!1;for await(const{path:t}of this.list(e,{recursive:!0}))"/"!==t&&delete this.index[t];delete this.index[e.path]}async write(t,e){await this._init(),await this._doWrite(t,e)}async*read(t){await this._init();const e=this.normalizePath(t),i=this.index[e];if(!i||"file"!==i.kind)return;const n=i.content;yield*n}async _init(){return this._initPromise=this._initPromise||Promise.resolve().then((()=>this._addEntries(this.options.files)))}async _doWrite(t,e){const i=this.normalizePath(t).split("/").filter((t=>!!t)),n=[""];let s;for(let t=0;t<i.length;t++){const e=i[t];n.push(e);const o=n.join("/");s=this.index[o]=this.index[o]||{path:o,name:e,kind:"directory"}}s.kind="file",s.content=[],s.type=r(s.path),s.size=0,s.lastModified=Date.now(),"function"==typeof e&&(e=e());for await(let t of e)t=new Uint8Array(t),s.content.push(t),s.size+=t.length}async _addEntries(t={}){for(let[e,i]of Object.entries(t))"string"==typeof i?i=[(new TextEncoder).encode(i)]:i instanceof Uint8Array&&(i=[i]),await this._doWrite(e,i)}_getPaths(){return this._getIndexPaths(this.index)}_getIndexPaths(t){return Object.keys(t).sort((function(t,e){return t>e?1:t<e?-1:0}))}_getFileInfo(t){const e=this.index[t];if(!e)return null;const i={...e};return delete i.content,i}}class p extends i{constructor(t){if(super(t),!this.fs)throw new Error("File System is not defined.");if(!this.rootDir)throw new Error("Root directory is not defined.")}get rootDirSegments(){return this._rootDirSegments||(this._rootDirSegments=this._toPathSegments(this.options.rootDir||"./")),this._rootDirSegments}get rootDir(){return this._rootDir||(this._rootDir=this.rootDirSegments.join("/")),this._rootDir}get fs(){return this.options.fs}async _init(){return this._initialized=this._initialized||(async()=>{const t=this.rootDir;return await l(this.fs,t)})()}async*list(t,{recursive:e=!1}={}){await this._init();const i=this._expandPath(t),n=await this._stats(i);if(n&&"directory"===n.kind)for await(let t of f(this.fs,i,e))yield this._getFileInfo(t.path,t.stat)}async stats(t){await this._init();const e=this._expandPath(t);return this._stats(e)}async remove(t){await this._init();const e=this._expandPath(t);return await h(this.fs,e)}async write(t,e){await this._init();const i=this._expandPath(t),n=d(i);let s;await this.fs.mkdir(n,{recursive:!0});try{s=await this.fs.open(i,"w"),"function"==typeof e&&(e=e()),await s.writeFile(e)}finally{s&&await s.close()}}async*read(t,{start:e=0,bufferSize:i=8192}={}){await this._init();const n=this._expandPath(t);let s;try{s=await this.fs.open(n,"r");const t=0;for(let n=e,o=0;;n+=o){const e=new Uint8ClampedArray(i),a=await s.read(e,t,i,n);if(o=a.bytesRead,0===o)break;yield o<i?a.buffer.slice(0,o):a.buffer}}finally{s&&await s.close()}}async _stats(t){try{const e=await this.fs.stat(t);return this._getFileInfo(t,e)}catch(t){if("ENOENT"!==t.code)throw t;return null}}_getFileInfo(t,e){const i=this._toPathSegments(t).slice(this.rootDirSegments.length);i.unshift("");const n=i[i.length-1];let s={path:t=i.join("/"),name:n,kind:""};return e.isFile()?(s.size=e.size||0,s.type=r(t),s.kind="file",s.lastModified=new Date(e.mtime).getTime()):s.kind="directory",s}_toPathSegments(t){return(t=this.normalizePath(t)).split("/")}_expandPath(t){const e="object"==typeof t?t.path:t+"",i=this._toPathSegments(e).filter((t=>!!t));return i.unshift(...this.rootDirSegments),i.join("/")}}function d(t){const e=t.split("/");return e.pop(),e.join("/")}function m(...t){let e=t.map((t=>t.split("/"))).reduce(((t,e)=>(t.push(...e),t)),[]);const i=e.shift();return e=e.filter((t=>!!t&&"."!==t)),e.unshift(i),e.join("/")}async function l(t,e){try{const i=await t.stat(e);if(i&&i.isDirectory())return!0}catch(t){}const i=d(e);return e!==i&&(await l(t,i),await t.mkdir(e,{recursive:!0}),!0)}async function h(t,e){try{if((await t.stat(e)).isDirectory()){for await(let i of f(t,e,!1))await h(t,i.path);await t.rmdir(e)}else await t.unlink(e)}catch(t){if("ENOENT"!==t.code)throw t}}async function*f(t,e,i){try{if((await t.stat(e)).isDirectory()){const n=await t.readdir(e);for(const s of n.sort()){const n=m(e,s);let o=await t.stat(n);yield{path:n,stat:o},i&&o.isDirectory()&&(yield*f(t,n,!0))}}}catch(t){if("ENOENT"!==t.code)throw t}}class u extends i{constructor(t){if(super(t),!this.rootHandler)throw new Error("Root directory handler is not defined")}get rootHandler(){return this.options.rootHandler}async*list(t,{recursive:e=!1}={}){const i=this._getPathSegments(t),n=await this._getHandler(i,!1),s=this;"directory"===n.kind&&(yield*async function*t(e,i,n){for await(const o of i.values())yield await s._getFileInfo([...e,o.name],o),n&&"directory"==o.kind&&(yield*t([...e,o.name],o,n))}(i,n,e))}async stats(t){const e=this._getPathSegments(t),i=await this._getHandler(e,!1);return i?await this._getFileInfo(e,i):null}async remove(t){let e=this._getPathSegments(t);const i=e.pop(),n=await this._getHandler(e,!1),s=[];if(i)s.push(i);else for await(const t of n.values())s.push(t.name);for(const t of s)await n.removeEntry(t,{recursive:!0});return!0}async write(t,e){const i=this._getPathSegments(t),n=await this._getFileHandler(i),s=await n.createWritable();try{"function"==typeof e&&(e=e());for await(let t of e)await s.write(t.buffer?t.buffer:t)}finally{await s.close()}}async*read(t){const e=this._getPathSegments(t),i=await this._getFileHandler(e,!1);if(!i)return;const n=(await i.getFile()).stream().getReader();try{let t;for(;(t=await n.read())&&!t.done;)yield t.value}finally{n.cancel&&n.cancel()}}async _getHandler(t,e=!1){let i;try{i=await this._getFileHandler(t,e)}catch(n){try{i=await this._getDirectoryHandler(t,e)}catch(t){}}return i}async _getDirectoryHandler(t,e=!0){t=[...t];let i=this.rootHandler;for(let n of t)i=await i.getDirectoryHandle(n,{create:e});return i}async _getFileHandler(t,e=!0){const i=(t=[...t]).pop();let n=this.rootHandler;for(let e of t)n=await n.getDirectoryHandle(e,{create:!0});return await n.getFileHandle(i,{create:e})}async _getFileInfo(t,e){const i=(t=[...t])[t.length-1];t.unshift("");const n=t.join("/"),s={kind:"",path:n,name:i};if("directory"===e.kind)s.kind="directory";else{s.kind="file";const t=await e.getFile();s.size=t.size,s.type=r(n),s.lastModified=t.lastModified}return s}_getPathSegments(t){return("object"==typeof t?t.path:t+"").split("/").filter((t=>!!t))}}function x({filesApi:t,log:e=console.log,wrapper:i={}}){return["list","stats","remove","write","read","copy","move"].reduce(((i,n)=>{const s=t[n].bind(t);return i[n]=(...i)=>{let o={method:n,stage:"enter",args:i};try{return e(o),o.result=s.call(t,...i)}catch(t){o.error=t}finally{o.stage="exit",e(o)}},i}),i)}async function w({handlerKey:t="root-dir",readwrite:e=!0,index:i={},get:n=(async t=>i[t]),set:s=(async(t,e)=>i[t]=e),del:o=(async t=>delete i[t])}={}){let a=await n(t);if(a||(a=await window.showDirectoryPicker(),await s(t,a)),!await async function(t,e){const i={};e&&(i.mode="readwrite");let n=!1;"granted"===await t.queryPermission(i)&&(n=!0);n||"granted"!==await t.requestPermission(i)||(n=!0);return n}(a,e))throw new Error("Access was not granted");if(!await async function(t){let e=!1;try{if("file"===t.kind)await t.getFile();else for await(let e of t.values())break;e=!0}catch(i){console.log(i,t),e=!1}return e}(a))throw await o(t),new Error("Can not access to the folder. Please try again.");return new u({rootHandler:a})}export{u as BrowserFilesApi,i as FilesApi,c as MemFilesApi,p as NodeFilesApi,x as addFilesApiLogger,o as extensionToMimeType,r as getMimeType,a as mimeTypeToExtensions,n as mimeTypes,s as mimeTypesDescriptions,t as normalizePath,w as openBrowserFilesApi};
|
|
1
|
+
// @statewalker/webrun-files v0.2.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
|
|
2
|
+
function t(t){const e=t.split("/").filter((t=>!!t&&"."!==t));return 0===e.length&&e.push(""),e.unshift(""),e.join("/")}function e(){throw new Error("Not implemented.")}class i{constructor(t){this.options=t||{}}async*list(t,i={}){yield e()}async stats(t){return e()}async remove(t){return e()}async write(t,i){return e()}async*read(t,i){yield e()}async copy(t,e,i={}){const n=async(t,e,i)=>{e=`${e}${i.path.substring(t.length)}`;const n=this.read(i);return await this.write(e,n)},s=void 0===i.recursive||!!i.recursive,o=await this.stats(t);if("directory"===o.kind)for await(const o of this.list(t,{...i,recursive:s}))"directory"!==o.kind&&await n(t,e,o);else await n(t,e,o);return!0}async move(t,e,i={}){return!!await this.copy(t,e,i)&&(await this.remove(t),!0)}normalizePath(e){return t("object"==typeof e?e.path:e+"")}}const n=[{extensions:["aac"],mime:"audio/aac",description:"AAC audio"},{extensions:["abw"],mime:"application/x-abiword",description:"AbiWord document"},{extensions:["arc"],mime:"application/x-freearc",description:"Archive document (multiple files embedded)"},{extensions:["avi"],mime:"video/x-msvideo",description:"AVI: Audio Video Interleave"},{extensions:["azw"],mime:"application/vnd.amazon.ebook",description:"Amazon Kindle eBook format"},{extensions:["bin"],mime:"application/octet-stream",description:"Any kind of binary data"},{extensions:["bmp"],mime:"image/bmp",description:"Windows OS/2 Bitmap Graphics"},{extensions:["bz"],mime:"application/x-bzip",description:"BZip archive"},{extensions:["bz2"],mime:"application/x-bzip2",description:"BZip2 archive"},{extensions:["csh"],mime:"application/x-csh",description:"C-Shell script"},{extensions:["css"],mime:"text/css",description:"Cascading Style Sheets (CSS)"},{extensions:["csv"],mime:"text/csv",description:"Comma-separated values (CSV)"},{extensions:["doc"],mime:"application/msword",description:"Microsoft Word"},{extensions:["docx"],mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",description:"Microsoft Word (OpenXML)"},{extensions:["eot"],mime:"application/vnd.ms-fontobject",description:"MS Embedded OpenType fonts"},{extensions:["epub"],mime:"application/epub+zip",description:"Electronic publication (EPUB)"},{extensions:["gz"],mime:"application/gzip",description:"GZip Compressed Archive"},{extensions:["gif"],mime:"image/gif",description:"Graphics Interchange Format (GIF)"},{extensions:["htm","html"],mime:"text/html",description:"HyperText Markup Language (HTML)"},{extensions:["ico"],mime:"image/vnd.microsoft.icon",description:"Icon format"},{extensions:["ics"],mime:"text/calendar",description:"iCalendar format"},{extensions:["jar"],mime:"application/java-archive",description:"Java Archive (JAR)"},{extensions:["jpg","jpeg"],mime:"image/jpeg",description:"JPEG images"},{extensions:["js"],mime:"text/javascript",description:"JavaScript per the following specifications: https://html.spec.whatwg.org/multipage/#scriptingLanguages, https://html.spec.whatwg.org/multipage/#dependencies:willful-violation, https://datatracker.ietf.org/doc/draft-ietf-dispatch-javascript-mjs/"},{extensions:["json"],mime:"application/json",description:"JSON format"},{extensions:["jsonld"],mime:"application/ld+json",description:"JSON-LD format"},{extensions:["mid","midi"],mime:"application/ld+json",description:"Musical Instrument Digital Interface (MIDI)\taudio/midi audio/x-midi"},{extensions:["mjs"],mime:"text/javascript",description:"JavaScript module"},{extensions:["mp3"],mime:"audio/mpeg",description:"MP3 audio"},{extensions:["md"],mime:"text/markdown",description:"Markdown"},{extensions:["mpeg"],mime:"video/mpeg",description:"MPEG Video"},{extensions:["mpkg"],mime:"application/vnd.apple.installer+xml",description:"Apple Installer Package"},{extensions:["odp"],mime:"application/vnd.oasis.opendocument.presentation",description:"OpenDocument presentation document"},{extensions:["ods"],mime:"application/vnd.oasis.opendocument.spreadsheet",description:"OpenDocument spreadsheet document"},{extensions:["odt"],mime:"application/vnd.oasis.opendocument.text",description:"OpenDocument text document"},{extensions:["oga"],mime:"audio/ogg",description:"OGG audio"},{extensions:["ogv"],mime:"video/ogg",description:"OGG video"},{extensions:["ogx"],mime:"application/ogg",description:"OGG"},{extensions:["opus"],mime:"audio/opus",description:"Opus audio"},{extensions:["otf"],mime:"font/otf",description:"OpenType font"},{extensions:["png"],mime:"image/png",description:"Portable Network Graphics"},{extensions:["pdf"],mime:"application/pdf",description:"Adobe Portable Document Format (PDF)"},{extensions:["php"],mime:"application/x-httpd-php",description:"Hypertext Preprocessor (Personal Home Page)"},{extensions:["ppt"],mime:"application/vnd.ms-powerpoint",description:"Microsoft PowerPoint"},{extensions:["pptx"],mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation",description:"Microsoft PowerPoint (OpenXML)"},{extensions:["rar"],mime:"application/vnd.rar",description:"RAR archive"},{extensions:["rtf"],mime:"application/rtf",description:"Rich Text Format (RTF)"},{extensions:["sh"],mime:"application/x-sh",description:"Bourne shell script"},{extensions:["svg"],mime:"image/svg+xml",description:"Scalable Vector Graphics (SVG)"},{extensions:["swf"],mime:"application/x-shockwave-flash",description:"Small web format (SWF) or Adobe Flash document"},{extensions:["tar"],mime:"application/x-tar",description:"Tape Archive (TAR)"},{extensions:["tif","tiff"],mime:"image/tiff",description:"Tagged Image File Format (TIFF)"},{extensions:["ttf"],mime:"font/ttf",description:"TrueType Font"},{extensions:["txt"],mime:"text/plain",description:"Text, (generally ASCII or ISO 8859-n)"},{extensions:["vsd"],mime:"application/vnd.visio",description:"Microsoft Visio"},{extensions:["wav"],mime:"audio/wav",description:"Waveform Audio Format"},{extensions:["weba"],mime:"audio/webm",description:"WEBM audio"},{extensions:["webm"],mime:"video/webm",description:"WEBM video"},{extensions:["webp"],mime:"image/webp",description:"WEBP image"},{extensions:["woff"],mime:"font/woff",description:"Web Open Font Format (WOFF)"},{extensions:["woff2"],mime:"font/woff2",description:"Web Open Font Format (WOFF)"},{extensions:["xhtml"],mime:"application/xhtml+xml",description:"XHTML"},{extensions:["xls"],mime:"application/vnd.ms-excel",description:"Microsoft Excel"},{extensions:["xlsx"],mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",description:"Microsoft Excel (OpenXML)"},{extensions:["xml"],mime:"application/xml",description:"XML; application/xml - if not readable from casual users (RFC 3023, section 3); text/xml - if readable from casual users (RFC 3023, section 3)"},{extensions:["xul"],mime:"application/vnd.mozilla.xul+xml",description:"XUL"},{extensions:["zip"],mime:"application/zip",description:"ZIP archive"},{extensions:["3gp"],mime:"video/3gpp",description:"3GPP audio/video container"},{extensions:["3g2"],mime:"video/3gpp2",description:"3GPP2 audio/video container; audio/3gpp if it doesn't contain video; audio/3gpp2 if it doesn't contain video"},{extensions:["7z"],mime:"application/x-7z-compressed",description:"7-zip archive"},{extensions:["jsx"],mime:"text/jsx",description:"JavaScript Syntax Extension / JavaScript XML format"},{extensions:["ts"],mime:"text/ts",description:"TypeScript format"},{extensions:["tsx"],mime:"text/tsx",description:"TypeScript Syntax Extension / TypeScript XML format"}],s=n.reduce(((t,e)=>(t[e.mime]=e.description,t)),{}),o=n.reduce(((t,e)=>{for(const i of e.extensions)t[i]=e.mime;return t}),{}),a=n.reduce(((t,e)=>(t[e.mime]=e.extensions,t)),{});function r(t){const e=t=t||"",i=(t=(t=t.split("?").shift()).split("/").pop()).split(".").pop();let n=o[i];return n||(n=e.match(/api\.observablehq\.com/)||e.match(/\.ojs$/)?"application/javascript-observable":"application/binary"),n}class c extends i{constructor(t){super(t),this.index={"/":{kind:"directory",path:"/",name:""}}}async*list(t,{recursive:e=!1}={}){await this._init();const i=this.normalizePath(t),n=this._getPaths();for(const t of n){if(0!==t.indexOf(i)||t===i)continue;const n=t.substring(i.length+1).split("/");(e||1===n.length)&&(yield this._getFileInfo(t))}}async stats(t){await this._init();const e=this.normalizePath(t);return this._getFileInfo(e)}async remove(t){await this._init();const e=await this.stats(t);if(!e)return!1;for await(const{path:t}of this.list(e,{recursive:!0}))"/"!==t&&delete this.index[t];delete this.index[e.path]}async write(t,e){await this._init(),await this._doWrite(t,e)}async*read(t){await this._init();const e=this.normalizePath(t),i=this.index[e];if(!i||"file"!==i.kind)return;const n=i.content;yield*n}async _init(){return this._initPromise=this._initPromise||Promise.resolve().then((()=>this._addEntries(this.options.files)))}async _doWrite(t,e){const i=this.normalizePath(t).split("/").filter((t=>!!t)),n=[""];let s;for(let t=0;t<i.length;t++){const e=i[t];n.push(e);const o=n.join("/");s=this.index[o]=this.index[o]||{path:o,name:e,kind:"directory"}}s.kind="file",s.content=[],s.type=r(s.path),s.size=0,s.lastModified=Date.now(),"function"==typeof e&&(e=e());for await(let t of e)t=new Uint8Array(t),s.content.push(t),s.size+=t.length}async _addEntries(t={}){for(let[e,i]of Object.entries(t))"string"==typeof i?i=[(new TextEncoder).encode(i)]:i instanceof Uint8Array&&(i=[i]),await this._doWrite(e,i)}_getPaths(){return this._getIndexPaths(this.index)}_getIndexPaths(t){return Object.keys(t).sort((function(t,e){return t>e?1:t<e?-1:0}))}_getFileInfo(t){const e=this.index[t];if(!e)return null;const i={...e};return delete i.content,i}}class p extends i{constructor(t){if(super(t),!this.fs)throw new Error("File System is not defined.");if(!this.rootDir)throw new Error("Root directory is not defined.")}get rootDirSegments(){return this._rootDirSegments||(this._rootDirSegments=this._toPathSegments(this.options.rootDir||"./")),this._rootDirSegments}get rootDir(){return this._rootDir||(this._rootDir=this.rootDirSegments.join("/")),this._rootDir}get fs(){return this.options.fs}async _init(){return this._initialized=this._initialized||(async()=>{const t=this.rootDir;return await l(this.fs,t)})()}async*list(t,{recursive:e=!1}={}){await this._init();const i=this._expandPath(t),n=await this._stats(i);if(n&&"directory"===n.kind)for await(let t of f(this.fs,i,e))yield this._getFileInfo(t.path,t.stat)}async stats(t){await this._init();const e=this._expandPath(t);return this._stats(e)}async remove(t){await this._init();const e=this._expandPath(t);return await h(this.fs,e)}async write(t,e){await this._init();const i=this._expandPath(t),n=d(i);let s;await this.fs.mkdir(n,{recursive:!0});try{s=await this.fs.open(i,"w"),"function"==typeof e&&(e=e()),await s.writeFile(e)}finally{s&&await s.close()}}async*read(t,{start:e=0,bufferSize:i=8192}={}){await this._init();const n=this._expandPath(t);let s;try{s=await this.fs.open(n,"r");const t=0;for(let n=e,o=0;;n+=o){const e=new Uint8ClampedArray(i),a=await s.read(e,t,i,n);if(o=a.bytesRead,0===o)break;yield o<i?a.buffer.slice(0,o):a.buffer}}finally{s&&await s.close()}}async _stats(t){try{const e=await this.fs.stat(t);return this._getFileInfo(t,e)}catch(t){if("ENOENT"!==t.code)throw t;return null}}_getFileInfo(t,e){const i=this._toPathSegments(t).slice(this.rootDirSegments.length);i.unshift("");const n=i[i.length-1];let s={path:t=i.join("/"),name:n,kind:""};return e.isFile()?(s.size=e.size||0,s.type=r(t),s.kind="file",s.lastModified=new Date(e.mtime).getTime()):s.kind="directory",s}_toPathSegments(t){return(t=this.normalizePath(t)).split("/")}_expandPath(t){const e="object"==typeof t?t.path:t+"",i=this._toPathSegments(e).filter((t=>!!t));return i.unshift(...this.rootDirSegments),i.join("/")}}function d(t){const e=t.split("/");return e.pop(),e.join("/")}function m(...t){let e=t.map((t=>t.split("/"))).reduce(((t,e)=>(t.push(...e),t)),[]);const i=e.shift();return e=e.filter((t=>!!t&&"."!==t)),e.unshift(i),e.join("/")}async function l(t,e){try{const i=await t.stat(e);if(i&&i.isDirectory())return!0}catch(t){}const i=d(e);return e!==i&&(await l(t,i),await t.mkdir(e,{recursive:!0}),!0)}async function h(t,e){try{if((await t.stat(e)).isDirectory()){for await(let i of f(t,e,!1))await h(t,i.path);await t.rmdir(e)}else await t.unlink(e)}catch(t){if("ENOENT"!==t.code)throw t}}async function*f(t,e,i){try{if((await t.stat(e)).isDirectory()){const n=await t.readdir(e);for(const s of n.sort()){const n=m(e,s);let o=await t.stat(n);yield{path:n,stat:o},i&&o.isDirectory()&&(yield*f(t,n,!0))}}}catch(t){if("ENOENT"!==t.code)throw t}}class u extends i{constructor(t){if(super(t),!this.rootHandler)throw new Error("Root directory handler is not defined")}get rootHandler(){return this.options.rootHandler}async*list(t,{recursive:e=!1}={}){const i=this._getPathSegments(t),n=await this._getHandler(i,!1),s=this;"directory"===n.kind&&(yield*async function*t(e,i,n){for await(const o of i.values())yield await s._getFileInfo([...e,o.name],o),n&&"directory"==o.kind&&(yield*t([...e,o.name],o,n))}(i,n,e))}async stats(t){const e=this._getPathSegments(t),i=await this._getHandler(e,!1);return i?await this._getFileInfo(e,i):null}async remove(t){let e=this._getPathSegments(t);const i=e.pop(),n=await this._getHandler(e,!1),s=[];if(i)s.push(i);else for await(const t of n.values())s.push(t.name);for(const t of s)await n.removeEntry(t,{recursive:!0});return!0}async write(t,e){const i=this._getPathSegments(t),n=await this._getFileHandler(i),s=await n.createWritable();try{"function"==typeof e&&(e=e());for await(let t of e)await s.write(t.buffer?t.buffer:t)}finally{await s.close()}}async*read(t){const e=this._getPathSegments(t),i=await this._getFileHandler(e,!1);if(!i)return;const n=(await i.getFile()).stream().getReader();try{let t;for(;(t=await n.read())&&!t.done;)yield t.value}finally{n.cancel&&n.cancel()}}async _getHandler(t,e=!1){let i;try{i=await this._getFileHandler(t,e)}catch(n){try{i=await this._getDirectoryHandler(t,e)}catch(t){}}return i}async _getDirectoryHandler(t,e=!0){t=[...t];let i=this.rootHandler;for(let n of t)i=await i.getDirectoryHandle(n,{create:e});return i}async _getFileHandler(t,e=!0){const i=(t=[...t]).pop();let n=this.rootHandler;for(let e of t)n=await n.getDirectoryHandle(e,{create:!0});return await n.getFileHandle(i,{create:e})}async _getFileInfo(t,e){const i=(t=[...t])[t.length-1];t.unshift("");const n=t.join("/"),s={kind:"",path:n,name:i};if("directory"===e.kind)s.kind="directory";else{s.kind="file";const t=await e.getFile();s.size=t.size,s.type=r(n),s.lastModified=t.lastModified}return s}_getPathSegments(t){return("object"==typeof t?t.path:t+"").split("/").filter((t=>!!t))}}function x({filesApi:t,log:e=console.log,wrapper:i={}}){return["list","stats","remove","write","read","copy","move"].reduce(((i,n)=>{const s=t[n].bind(t);return i[n]=(...i)=>{let o={method:n,stage:"enter",args:i};try{return e(o),o.result=s.call(t,...i)}catch(t){o.error=t}finally{o.stage="exit",e(o)}},i}),i)}async function w({handlerKey:t="root-dir",readwrite:e=!0,index:i={},get:n=(async t=>i[t]),set:s=(async(t,e)=>i[t]=e),del:o=(async t=>delete i[t])}={}){let a=await n(t);if(a||(a=await window.showDirectoryPicker(),await s(t,a)),!await y(a,e))throw new Error("Access was not granted");if(!await g(a))throw await o(t),new Error("Can not access to the folder. Please try again.");return new u({rootHandler:a})}async function g(t){let e=!1;try{if("file"===t.kind)await t.getFile();else for await(let e of t.values())break;e=!0}catch(i){console.log(i,t),e=!1}return e}async function y(t,e){const i={};e&&(i.mode="readwrite");let n=!1;return"granted"===await t.queryPermission(i)&&(n=!0),n||"granted"!==await t.requestPermission(i)||(n=!0),n}export{u as BrowserFilesApi,i as FilesApi,c as MemFilesApi,p as NodeFilesApi,x as addFilesApiLogger,o as extensionToMimeType,r as getMimeType,g as isHandlerAccessible,a as mimeTypeToExtensions,n as mimeTypes,s as mimeTypesDescriptions,t as normalizePath,w as openBrowserFilesApi,y as verifyPermission};
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -7,4 +7,4 @@ export { default as addFilesApiLogger } from "./addFilesApiLogger.js";
|
|
|
7
7
|
|
|
8
8
|
export { default as getMimeType } from "./getMimeType.js";
|
|
9
9
|
export * from "./mimeTypes.js";
|
|
10
|
-
export
|
|
10
|
+
export * from "./openBrowserFilesApi.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import BrowserFilesApi from "./BrowserFilesApi.js";
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export async function openBrowserFilesApi({
|
|
4
4
|
handlerKey = "root-dir",
|
|
5
5
|
readwrite = true,
|
|
6
6
|
// Methods below could be replaced by persistent implementation
|
|
@@ -24,44 +24,44 @@ export default async function openBrowserFilesApi({
|
|
|
24
24
|
throw new Error("Can not access to the folder. Please try again.");
|
|
25
25
|
}
|
|
26
26
|
return new BrowserFilesApi({ rootHandler });
|
|
27
|
+
}
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
29
|
+
export async function isHandlerAccessible(fileHandle) {
|
|
30
|
+
// We need to perform a real read operation with the handler
|
|
31
|
+
// to check if the file/directory still exists.
|
|
32
|
+
let exists = false;
|
|
33
|
+
try {
|
|
34
|
+
if (fileHandle.kind === "file") {
|
|
35
|
+
await fileHandle.getFile();
|
|
36
|
+
} else {
|
|
37
|
+
for await (let item of fileHandle.values()) {
|
|
38
|
+
break;
|
|
39
39
|
}
|
|
40
|
-
exists = true;
|
|
41
|
-
} catch (error) {
|
|
42
|
-
console.log(error, fileHandle);
|
|
43
|
-
exists = false;
|
|
44
40
|
}
|
|
45
|
-
|
|
41
|
+
exists = true;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.log(error, fileHandle);
|
|
44
|
+
exists = false;
|
|
46
45
|
}
|
|
46
|
+
return exists;
|
|
47
|
+
}
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
// The user didn't grant permission, so return false.
|
|
65
|
-
return granted;
|
|
49
|
+
export async function verifyPermission(fileHandle, readWrite) {
|
|
50
|
+
const options = {};
|
|
51
|
+
if (readWrite) {
|
|
52
|
+
options.mode = "readwrite";
|
|
53
|
+
}
|
|
54
|
+
let granted = false;
|
|
55
|
+
// Check if permission was already granted. If so, return true.
|
|
56
|
+
if ((await fileHandle.queryPermission(options)) === "granted") {
|
|
57
|
+
granted = true;
|
|
58
|
+
}
|
|
59
|
+
// Request permission. If the user grants permission, return true.
|
|
60
|
+
if (
|
|
61
|
+
!granted && (await fileHandle.requestPermission(options)) === "granted"
|
|
62
|
+
) {
|
|
63
|
+
granted = true;
|
|
66
64
|
}
|
|
65
|
+
// The user didn't grant permission, so return false.
|
|
66
|
+
return granted;
|
|
67
67
|
}
|