observablehq-file-attachments
Version:
Library to handle ObservableHQ's file attachments more flexibly, and to support virtualizing them.
3 lines (2 loc) • 11.8 kB
JavaScript
const t=Symbol.for("METADATA"),e=Symbol.for("CACHED_METADATA"),n=Symbol.for("FILE"),r=Symbol.for("DIRECTORY"),a=Symbol.for("TAGS");var i={},s={};function o(t){return new Function("d","return {"+t.map((function(t,e){return JSON.stringify(t)+": d["+e+'] || ""'})).join(",")+"}")}function c(t){var e=Object.create(null),n=[];return t.forEach((function(t){for(var r in t)r in e||n.push(e[r]=r)})),n}function u(t,e){var n=t+"",r=n.length;return r<e?new Array(e-r+1).join(0)+n:n}function l(t){var e,n=t.getUTCHours(),r=t.getUTCMinutes(),a=t.getUTCSeconds(),i=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":((e=t.getUTCFullYear())<0?"-"+u(-e,6):e>9999?"+"+u(e,6):u(e,4))+"-"+u(t.getUTCMonth()+1,2)+"-"+u(t.getUTCDate(),2)+(i?"T"+u(n,2)+":"+u(r,2)+":"+u(a,2)+"."+u(i,3)+"Z":a?"T"+u(n,2)+":"+u(r,2)+":"+u(a,2)+"Z":r||n?"T"+u(n,2)+":"+u(r,2)+"Z":"")}function f(t){var e=new RegExp('["'+t+"\n\r]"),n=t.charCodeAt(0);function r(t,e){var r,a=[],o=t.length,c=0,u=0,l=o<=0,f=!1;function h(){if(l)return s;if(f)return f=!1,i;var e,r,a=c;if(34===t.charCodeAt(a)){for(;c++<o&&34!==t.charCodeAt(c)||34===t.charCodeAt(++c););return(e=c)>=o?l=!0:10===(r=t.charCodeAt(c++))?f=!0:13===r&&(f=!0,10===t.charCodeAt(c)&&++c),t.slice(a+1,e-1).replace(/""/g,'"')}for(;c<o;){if(10===(r=t.charCodeAt(e=c++)))f=!0;else if(13===r)f=!0,10===t.charCodeAt(c)&&++c;else if(r!==n)continue;return t.slice(a,e)}return l=!0,t.slice(a,o)}for(10===t.charCodeAt(o-1)&&--o,13===t.charCodeAt(o-1)&&--o;(r=h())!==s;){for(var d=[];r!==i&&r!==s;)d.push(r),r=h();e&&null==(d=e(d,u++))||a.push(d)}return a}function a(e,n){return e.map((function(e){return n.map((function(t){return f(e[t])})).join(t)}))}function u(e){return e.map(f).join(t)}function f(t){return null==t?"":t instanceof Date?l(t):e.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,e){var n,a,i=r(t,(function(t,r){if(n)return n(t,r-1);a=t,n=e?function(t,e){var n=o(t);return function(r,a){return e(n(r),a,t)}}(t,e):o(t)}));return i.columns=a||[],i},parseRows:r,format:function(e,n){return null==n&&(n=c(e)),[n.map(f).join(t)].concat(a(e,n)).join("\n")},formatBody:function(t,e){return null==e&&(e=c(t)),a(t,e).join("\n")},formatRows:function(t){return t.map(u).join("\n")},formatRow:u,formatValue:f}}var h=f(","),d=h.parse,y=h.parseRows,w=f("\t"),g=w.parse,p=w.parseRows;function m(t){for(var e in t){var n,r,a=t[e].trim();if(a)if("true"===a)a=!0;else if("false"===a)a=!1;else if("NaN"===a)a=NaN;else if(isNaN(n=+a)){if(!(r=a.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;b&&r[4]&&!r[7]&&(a=a.replace(/-/g,"/").replace(/T/," ")),a=new Date(a)}else a=n;else a=null;t[e]=a}return t}const b=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();for(var A=function(t){for(var e,n=t.length,r=n%3,a=[],i=16383,s=0,o=n-r;s<o;s+=i)a.push(x(t,s,s+i>o?o:s+i));1===r?(e=t[n-1],a.push(v[e>>2]+v[e<<4&63]+"==")):2===r&&(e=(t[n-2]<<8)+t[n-1],a.push(v[e>>10]+v[e>>4&63]+v[e<<2&63]+"="));return a.join("")},v=[],C=[],j="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",D=0,T=j.length;D<T;++D)v[D]=j[D],C[j.charCodeAt(D)]=D;function x(t,e,n){for(var r,a,i=[],s=e;s<n;s+=3)r=(t[s]<<16&16711680)+(t[s+1]<<8&65280)+(255&t[s+2]),i.push(v[(a=r)>>18&63]+v[a>>12&63]+v[a>>6&63]+v[63&a]);return i.join("")}C["-".charCodeAt(0)]=62,C["_".charCodeAt(0)]=63;class B{constructor(e,n,r={}){this.#noCache=!1,"string"==typeof r&&(r={name:e,contentType:r}),this[t]={...r,name:e},this.name=e,this.data=n;let{contentType:a}=r;this["content-type"]=a=a||("string"==typeof n?"text/plain":n.constructor===Array||n.constructor===Object?"application/json":"application/binary"),this[t].contentType=a}#dataResult;#noCache;async getData(t,e){let n=await(!this.#noCache&&this.#dataResult||this.data);if(n instanceof B)return n.getData(t,e);if("function"==typeof n&&(this.#dataResult=Promise.resolve(n(this,t,e)).then((t=>(this.#noCache=t instanceof ReadableStream,t))),n=await this.#dataResult,this.#noCache&&(this.#dataResult=void 0)),n instanceof ReadableStream&&"stream"!==t){let t=[];const e=await n.getReader();let r=!1,a=0;for(;!r;){const n=await e.read();n.value&&(t.push(n.value),a+=n.value.byteLength),r=r||n.done}const i=new ArrayBuffer(a),s=new Uint8Array(i);let o=0;for(const e of t)s.set(e,o),o+=e.byteLength;return i}return this.#noCache||(this.data=n),n}async json(t={utf8:!0}){const e=await this.getData("json",t);return e instanceof Blob||e instanceof ReadableStream||e instanceof ArrayBuffer?JSON.parse(await this.text(t)):e}async text(t={utf8:!0}){const{utf8:e=!0}=t,n=await this.getData("text",t);return"string"==typeof n?n:n instanceof ArrayBuffer?e?(new TextDecoder).decode(new Uint8Array(n)):String.fromCodePoint(...new Uint16Array(n)):n instanceof Blob?e?(new TextDecoder).decode(new Uint8Array(await n.arrayBuffer())):String.fromCodePoint(...new Uint16Array(await n.arrayBuffer())):JSON.stringify(n)}async url(t={utf8:!0}){const e=await this.getData("url",t),n=this?.["content-type"];if("string"==typeof e)return`data:${n};UTF-8,${e}`;const r=await this.arrayBuffer(),a=new Uint8Array(r);return`data:${n};base64,${A(a)}`}async arrayBuffer(t={utf8:!0}){const e=await this.getData("arrayBuffer",t);return e instanceof ArrayBuffer?e:e instanceof Blob?e.arrayBuffer():H(await this.text(t),t)}async blob(t={utf8:!0}){const e=await this.getData("blob",t);return e instanceof Blob?e:new Blob([new Uint8Array(await this.arrayBuffer(t))])}async csv(t={utf8:!0}){const e=await this.getData("csv",t);return Array.isArray(e)||e.constructor===Object?e:Z(await this.text(),",",t)}async tsv(t={utf8:!0}){const e=await this.getData("tsv",t);return Array.isArray(e)||e.constructor===Object?e:Z(await this.text(),"\t",t)}async stream(t={utf8:!0}){let e=await this.getData("stream",t);return e instanceof ReadableStream?e:new ReadableStream({pull:async t=>{const e=await this.arrayBuffer(),n=new Uint8Array(e);t.enqueue(n),t.close()}})}}const E=t=>{if(t instanceof Error)throw t;throw new Error(t)},R=t=>(t=>Array.isArray(t))(t)?t:null==t?null:E("Unexpected file level"),S=t=>(t=>t instanceof Object)(t)?t:null==t?null:E("Unexpected directory level"),U=t=>t instanceof Function,O=(t,e)=>{if("string"==typeof(t=t??-1)){switch(t){case"latest":return e-1;case"earliest":return 0;case"*":throw new Error(`Illegal version: ${t}`)}return/^[-+]?\d+$/.test(t)?O(Number.parseInt(t,10),e):t}return 0===(t=t??-1)?null:t<0?e+t<0?null:e+t:t-1},$=(t,e)=>{const n=O(e,t.length);return null===n?null:"string"==typeof n?t[a]?.[n]??null:t[n]??null},N=(t,...e)=>{0===e.length&&(e=[1]);const n=[];return e.forEach((e=>I(n,e,t))),n};function F(e,n,r,...a){if(!r){const r={name:e},i=new B(e,n),s={...r,...i[t]??{}};return J(N(i,...a),s)}if("string"==typeof r||"number"==typeof r){const i={name:e},s=new B(e,n),o={...i,...s[t]??{}};return J(N(s,r,...a),o)}{const i={name:e,...r??{}},s=new B(e,n,r),o={...i,...s[t]??{}};return J(N(s,...a),o)}}function P(t,e,n,...r){return{[t]:F(t,e,n,...r)}}const I=(t,e,n)=>{const r=O(e,t.length);if(null===r)throw new Error(`Cannot set version ${e}`);"string"==typeof r?(t[a]||(t[a]={}),t[a][e]=n):t[r]=n},M=(e,n)=>{switch(n){case"*":return e.length=0,e[a]={},void(e[t]=e[t]??{name:e[t].name})}if(null!==O(n,e.length))if("string"!=typeof n)delete e[n];else{const t=e?.[a];t&&delete t[n]}},H=(t,{utf8:e=!0}={utf8:!0})=>e?(new TextEncoder).encode(t).buffer:(t=>{const e=new ArrayBuffer(2*t.length),n=new Uint16Array(e);for(let e=0;e<t.length;e++)n[e]=t.codePointAt(e);return e})(t),J=(e,n)=>e&&Object.defineProperty(e,t,{value:n});function Z(t,e,{array:n=!1,typed:r=!1,utf8:a=!1}={}){const i=r?m:undefined;switch(e){case"\t":return n?p(t,i):g(t,i);case",":return n?y(t,i):d(t,i)}}class k{constructor(e,n){this.#name="(unresolved)",void 0===n?this.#target=e.then((e=>(e&&(this.#name=e.name??this.#name,this[t]={name:this.#name,...this[t]??{},...e[t]??{}}),e))):(this.#name=n,this.#target=e)}#target;#name;async url(){return(await this.#target)?.url()}async json(){return(await this.#target)?.json()}async blob(){return(await this.#target)?.blob()}async text(){return(await this.#target)?.text()}async arrayBuffer(){return(await this.#target)?.arrayBuffer()}async csv(){return(await this.#target)?.text()}async tsv(){return(await this.#target)?.text()}get name(){return this.#name??"(unresolved)"}get target(){return this.#target}get exists(){const t=this.#target.then((t=>{if(!t)throw new L(`Virtual file not found: ${this.name}`);return t}));return new k(t,this.#name)}}class L extends Error{constructor(t="Virtual file not found"){super(t)}}let V=0;const Y=(t,e,a,i)=>{const{file:s=(()=>null),directory:o=(()=>null),createFiles:c=(()=>null),createDirectory:u=(()=>null)}=i,l=async([a,...i],f)=>{if(!f)return null;if(""===a)return f?l(i,f):null;if(void 0===a)throw new Error("Accessing root as file.");if(0===i.length){const[r,o]=a.split("@");let u=R(f[r]);return u||(u=await(f[n]?.(t,e,r,o,i,f))??await c(t,e,r,o,f,u??[])??[],u&&(f[r]=u)),u?(f[r]=u,s(e,r,o,u)):null}{let n=S(f[a]);return n||(n=await(f[r]?.(t,e,a,i,f))??await u(t,e,a,i,f)??null,n&&(f[a]=n)),o(e,a,f),l(i,n)}};return l(e.split("/"),a)},_=(t,e,...n)=>r=>{try{return r()}catch(r){throw r.message=`${t.name}.${e}(${n.map((t=>JSON.stringify(t))).join(", ")}) ${r.message}`,r}};class q{constructor(t,e={}){const{readOnly:n,name:r}=e;this.readOnly=!!n,this.name=r||"FS_"+ ++V,this.tree=t||E("Missing tree."),this.subscription=async function*(t){let e=Promise.resolve(t);for(t.updateCount=0;;)e=new Promise(((e,n)=>{t.updated=e,t.errored=n})),yield t,await e,t.updateCount++}(this),this.subscription.next(),this.updateCount=0,this.errored=()=>{},this.updated=()=>{}}find(t){return _(this,"find",t)((()=>new k(Y(this,t,this.tree,{file:(t,e,n,r)=>{if(r.constructor===Object)throw new Error(`${t} is a directory.`);const a=$(r,n);if(!a)return null;if(Array.isArray(a)||a.constructor===Object)throw new Error(`${t} is a directory`);return a}}))))}async*waitFor(t){let e=this.find(t);if(e)yield e;else for await(const n of this.subscription){const r=n.find(t);if(r)return e=r,void(yield e)}}async*watch(t,e=!1){let n=this.find(t);(n||e)&&(yield n);for await(const r of this.subscription){const a=r.find(t);a!==n&&(n=a,(e||n)&&(yield n))}}async metadata(n){return _(this,"metadata",n)((()=>Y(this,n,this.tree,{file:async(n,r,a,i)=>{const s=$(i,a);if(!s)return null;const o=i[t]||{};if((c=s)&&U(c?.json)&&U(c?.text)&&U(c?.blob)&&U(c?.buffer)&&U(c?.stream)&&U(c?.url)&&c.constructor!==Object&&!s[e]){const n=await(await fetch(await s.url(),{method:"HEAD"})).headers,r={name:s.name,url:await s.url()};n.forEach(((t,e)=>{switch(e){case"content-length":r.length=Number.parseInt(t);break;case"last-modified":r.modificationDate=new Date(t);break;case"etag":r.etag=t;break;case"content-type":r.contentType=t}}));const a=s[t]||{};Object.defineProperty(s,e,{value:{...o,...a,...r}})}var c;const u=s["content-type"],l=u?{"content-type":u}:{name:r};return{name:r,...o,...l,...s[e]??{}}}})))}add(t,e){return _(this,"add",t,e)((()=>{if(this.readOnly)throw new Error("Read only filesystem.");const n=(t,n,r,a,i)=>0===a.length?i[r]=[e]:i[r]={},r=(t,n,r,a)=>(I(a,r,e),e);try{return Y(this,t,this.tree,{file:r,createDirectory:n})}catch(t){throw this.errored(t),t}finally{this.updated(this)}}))}copy(t,e){return this.add(e,this.find(t))}label(t,e){const n=t.split("/"),r=n[n.length-1].split("@")[0];n[n.length-1]=`${r}@${e}`;const a=n.join("/");return this.copy(t,a)}}const G={version:"0.1.13",git:{revision:"723a4c5aba11a56f0f33bbc9024419b61ec3b4d8"},date:new Date(1615835054340)};export{B as AFile,k as AFileAwait,q as AFileSystem,r as DIRECTORY,n as FILE,G as VERSION,L as VirtualFileNotFound,M as deleteVersion,Z as dsv,P as entry,F as file,$ as getVersion,J as meta,I as setVersion,N as versions};
//# sourceMappingURL=index.js.map