netcdf4-wasm
Version:
NetCDF4 library compiled to WebAssembly with TypeScript bindings
2 lines (1 loc) • 25.3 kB
JavaScript
class e{constructor(e,t,r=!1){this.name=e,this.size=t,this.isUnlimited=r}__len__(){return this.size}toString(){const e=this.isUnlimited?"unlimited":this.size.toString();return`<netCDF4.Dimension '${this.name}': size = ${e}>`}}class t{constructor(e,t,r,i,n,s){this.netcdf=e,this.name=t,this.datatype=r,this.dimensions=i,this.varid=n,this.ncid=s,this._attributes={}}setAttr(e,t){if(this._attributes[e]=t,"undefined"!=typeof process&&"test"===process.env.NODE_ENV){const r=global.__netcdf4_mock_files,i=this.netcdf;r&&i.filename&&r[i.filename]&&r[i.filename].variables[this.name]&&(r[i.filename].variables[this.name].attributes[e]=t)}}getAttr(e){return this._attributes[e]}attrs(){return Object.keys(this._attributes)}async getValue(){if("undefined"!=typeof process&&"test"===process.env.NODE_ENV){const e=global.__netcdf4_mock_files,t=this.netcdf;if(e&&t.filename&&e[t.filename]){const r=e[t.filename].variables;if(r[this.name]&&r[this.name].data){const e=r[this.name].data;return"f4"===this.datatype||"float"===this.datatype?new Float32Array(e):e}}}const e=this.dimensions.reduce((e,t)=>{const r=this.netcdf.dimensions[t];if(!r)return 1*e;let i=r.size;if(r.isUnlimited)if("undefined"!=typeof process&&"test"===process.env.NODE_ENV){const t=global.__netcdf4_mock_files,r=this.netcdf;if(t&&r.filename&&t[r.filename]){const n=t[r.filename].variables;if(n[this.name]&&n[this.name].data){const t=n[this.name].data;i=Math.max(1,Math.floor(t.length/e))}else i=1}}else i=r.size>0?r.size:1;return e*Math.max(i,1)},1);if("S1"===this.datatype||"char"===this.datatype)throw new Error(`Data type ${this.datatype} not yet supported`);const t=await this.netcdf.getVariableDouble(this.ncid,this.varid,e);return"f4"===this.datatype||"float"===this.datatype?new Float32Array(t):t}async setValue(e){if("undefined"!=typeof process&&"test"===process.env.NODE_ENV){const t=global.__netcdf4_mock_files,r=this.netcdf;if(t&&r.filename&&t[r.filename]){const i=t[r.filename].variables;i[this.name]&&(i[this.name].data=e instanceof Float64Array?e:new Float64Array(e))}}if("f8"===this.datatype||"double"===this.datatype){const t=e instanceof Float64Array?e:new Float64Array(e);return await this.netcdf.putVariableDouble(this.ncid,this.varid,t)}if("f4"===this.datatype||"float"===this.datatype){const t=e instanceof Float64Array?e:new Float64Array(e);return await this.netcdf.putVariableDouble(this.ncid,this.varid,t)}throw new Error(`Data type ${this.datatype} not yet supported`)}async __getitem__(e){if("number"==typeof e){return(await this.getValue())[e]}throw new Error("Advanced indexing not yet implemented")}async __setitem__(e,t){throw new Error("Item assignment not yet implemented")}get units(){return this._attributes.units}set units(e){this.setAttr("units",e)}get long_name(){return this._attributes.long_name}set long_name(e){this.setAttr("long_name",e)}get standard_name(){return this._attributes.standard_name}set standard_name(e){this.setAttr("standard_name",e)}get scale_factor(){return this._attributes.scale_factor}set scale_factor(e){this.setAttr("scale_factor",e)}get add_offset(){return this._attributes.add_offset}set add_offset(e){this.setAttr("add_offset",e)}get _FillValue(){return this._attributes._FillValue}set _FillValue(e){this.setAttr("_FillValue",e)}get calendar(){return this._attributes.calendar}set calendar(e){this.setAttr("calendar",e)}get axis(){return this._attributes.axis}set axis(e){this.setAttr("axis",e)}toString(){const e=this.dimensions.length>0?`(${this.dimensions.join(", ")})`:"()";return`<netCDF4.Variable '${this.name}': dimensions ${e}, size = [${this.dimensions.map(e=>this.netcdf.dimensions[e]?.size||"?").join(" x ")}], type = '${this.datatype}'>`}}const r={NC_NOERR:0,NC_NOWRITE:0,NC_WRITE:1,NC_CLOBBER:0,NC_NOCLOBBER:4,NC_NETCDF4:4096,NC_BYTE:1,NC_CHAR:2,NC_SHORT:3,NC_INT:4,NC_FLOAT:5,NC_DOUBLE:6,NC_UNLIMITED:-1e3,NC_GLOBAL:-1},i={f8:r.NC_DOUBLE,f4:r.NC_FLOAT,i4:r.NC_INT,i2:r.NC_SHORT,i1:r.NC_BYTE,S1:r.NC_CHAR,double:r.NC_DOUBLE,float:r.NC_FLOAT,int:r.NC_INT,short:r.NC_SHORT,byte:r.NC_BYTE,char:r.NC_CHAR},n={1:"i1",2:"S1",3:"i2",4:"i4",5:"f4",6:"f8",7:"u1",8:"u2",9:"u4",10:"i8",11:"u8",12:"S1"};class s{constructor(e,t,r){this.netcdf=e,this.name=t,this.groupId=r,this.dimensions={},this.variables={},this.groups={},this._attributes={}}setAttr(e,t){if(this._attributes[e]=t,"undefined"!=typeof process&&"test"===process.env.NODE_ENV){const r=global.__netcdf4_mock_files,i=this.netcdf;r&&i.filename&&r[i.filename]&&(r[i.filename].attributes[e]=t)}}getAttr(e){if("undefined"!=typeof process&&"test"===process.env.NODE_ENV){const t=global.__netcdf4_mock_files,r=this.netcdf;if(t&&r.filename&&t[r.filename]){const i=t[r.filename].attributes[e];if(void 0!==i)return this._attributes[e]=i,i}}return this._attributes[e]}attrs(){return Object.keys(this._attributes)}async createDimension(t,i){if(this.dimensions[t])throw new Error(`Dimension '${t}' already exists`);if(null!==i&&i<0&&i!==r.NC_UNLIMITED)throw new Error(`Invalid dimension size: ${i}. Size must be non-negative or null for unlimited.`);const n=null===i||i===r.NC_UNLIMITED,s=n?0:i;await this.netcdf.defineDimension(this.groupId,t,s);const a=new e(t,n?r.NC_UNLIMITED:i,n);return this.dimensions[t]=a,a}loadMockDimensions(){if("undefined"!=typeof process&&"test"===process.env.NODE_ENV){const r=global.__netcdf4_mock_files,i=this.netcdf;if(r&&i.filename&&r[i.filename]){const n=r[i.filename].dimensions;for(const[t,r]of Object.entries(n)){const i=new e(t,r.size,r.unlimited);this.dimensions[t]=i}const s=r[i.filename].variables;for(const[e,r]of Object.entries(s)){const i=r,n=new t(this.netcdf,e,i.datatype||"f8",i.dimensions||[],1,this.groupId);if(i.attributes)for(const[e,t]of Object.entries(i.attributes))n.setAttr(e,t);this.variables[e]=n}}}}loadFromFile(){const i=this.netcdf.getModule(),s=this.groupId,a=i.nc_inq_ndims(s);if(a.result!==r.NC_NOERR)return;const o=i.nc_inq_unlimdim(s).unlimdimid,l=[];for(let t=0;t<a.ndims;t++){const n=i.nc_inq_dim(s,t);n.result===r.NC_NOERR&&(l[t]=n.name,this.dimensions[n.name]=new e(n.name,n.len,t===o))}const c=i.nc_inq_nvars(s).nvars;for(let e=0;e<c;e++){const a=i.nc_inq_var(s,e);if(a.result!==r.NC_NOERR)continue;const o=n[a.xtype]??"f8",c=a.dimids.map(e=>l[e]).filter(e=>!!e),u=new t(this.netcdf,a.name,o,c,e,s);this.loadAttributes(i,s,e,a.natts,(e,t)=>u.setAttr(e,t)),this.variables[a.name]=u}const u=i.nc_inq_natts(s).natts;this.loadAttributes(i,s,r.NC_GLOBAL,u,(e,t)=>this.setAttr(e,t))}loadAttributes(e,t,i,n,s){for(let a=0;a<n;a++){const n=e.nc_inq_attname(t,i,a);if(n.result!==r.NC_NOERR)continue;const o=e.nc_inq_att(t,i,n.name);if(o.result!==r.NC_NOERR)continue;let l;if(o.xtype===r.NC_CHAR)l=e.nc_get_att_text(t,i,n.name,o.len).text;else{const r=e.nc_get_att_double(t,i,n.name,o.len);l=1===o.len?r.values[0]:Array.from(r.values)}s(n.name,l)}}async createVariable(e,r,n=[],s={}){const a=i[r];if(void 0===a)throw new Error(`Unsupported datatype: ${r}`);const o=n.map(e=>{if(!this.dimensions[e])throw new Error(`Dimension '${e}' not found`);return Object.keys(this.dimensions).indexOf(e)}),l=await this.netcdf.defineVariable(this.groupId,e,a,o),c=new t(this.netcdf,e,r,n,l,this.groupId);if(this.variables[e]=c,"undefined"!=typeof process&&"test"===process.env.NODE_ENV){const t=global.__netcdf4_mock_files,i=this.netcdf;t&&i.filename&&t[i.filename]&&(t[i.filename].variables[e]={datatype:r,dimensions:n,data:new Float64Array(0),attributes:{}})}return c}createGroup(e){const t=new s(this.netcdf,e,this.groupId);return this.groups[e]=t,t}children(){return this.groups}get path(){return""===this.name?"/":`/${this.name}`}toString(){return`<netCDF4.Group '${this.path}'>`}}class a{static async loadModule(e={}){try{const t=a.resolveModuleFactory(a.loadRawLoader(e)),r=await t({locateFile:t=>{if(e.wasmPath){return e.wasmPath.replace(".js",".wasm")}if("undefined"==typeof window){return require("path").join(__dirname,"..","dist","netcdf4-module.wasm")}return t}});if("function"!=typeof r?.cwrap)throw new Error('Loaded module is not an Emscripten runtime (cwrap is missing). Ensure dist/netcdf4-module.js was built with MODULARIZE and EXPORTED_RUNTIME_METHODS including "cwrap"/"ccall".');return a.wrapModule(r)}catch(e){throw new Error(`Failed to load NetCDF4 WASM module: ${e}`)}}static loadRawLoader(e){if("undefined"!=typeof window){if("undefined"==typeof NetCDF4Module)throw new Error("NetCDF4Module global not found. Load dist/netcdf4-module.js (the Emscripten loader) before using the library in the browser.");return NetCDF4Module}const t=require("path"),r=e.wasmPath||t.join(__dirname,"..","dist","netcdf4-module.js");try{return require(r)}catch(e){throw new Error(`Could not load the Emscripten loader from "${r}". Build it with \`npm run build:wasm\`, or pass options.wasmPath. (${e})`)}}static resolveModuleFactory(e){const t="function"==typeof e?e:e?.default;if("function"!=typeof t){const t=e&&"object"==typeof e?`object with keys [${Object.keys(e).join(", ")}]`:""+(null===e?"null":typeof e);throw new Error(`Expected the Emscripten module factory (a function) but got ${t}. Make sure dist/netcdf4-module.js is the MODULARIZE Emscripten loader, not the library entry point (e.g. dist/netcdf4.js / dist/index.js).`)}return t}static wrapModule(e){const t=e.cwrap("nc_open_wrapper","number",["string","number","number"]),r=e.cwrap("nc_close_wrapper","number",["number"]),i=e.cwrap("nc_create_wrapper","number",["string","number","number"]),n=e.cwrap("nc_def_dim_wrapper","number",["number","string","number","number"]),s=e.cwrap("nc_def_var_wrapper","number",["number","string","number","number","number","number"]),a=e.cwrap("nc_put_var_double_wrapper","number",["number","number","number"]),o=e.cwrap("nc_get_var_double_wrapper","number",["number","number","number"]),l=e.cwrap("nc_enddef_wrapper","number",["number"]),c=e.cwrap("nc_inq_ndims_wrapper","number",["number","number"]),u=e.cwrap("nc_inq_unlimdim_wrapper","number",["number","number"]),d=e.cwrap("nc_inq_dim_wrapper","number",["number","number","number","number"]),f=e.cwrap("nc_inq_nvars_wrapper","number",["number","number"]),h=e.cwrap("nc_inq_var_wrapper","number",["number","number","number","number","number","number","number"]),m=e.cwrap("nc_inq_natts_wrapper","number",["number","number"]),_=e.cwrap("nc_inq_attname_wrapper","number",["number","number","number","number"]),p=e.cwrap("nc_inq_att_wrapper","number",["number","number","string","number","number"]),b=e.cwrap("nc_get_att_text_wrapper","number",["number","number","string","number"]),w=e.cwrap("nc_get_att_double_wrapper","number",["number","number","string","number"]);return{...e,nc_open:(r,i)=>{const n=e._malloc(4),s=t(r,i,n),a=e.getValue(n,"i32");return e._free(n),{result:s,ncid:a}},nc_close:e=>r(e),nc_create:(t,r)=>{const n=e._malloc(4),s=i(t,r,n),a=e.getValue(n,"i32");return e._free(n),{result:s,ncid:a}},nc_def_dim:(t,r,i)=>{const s=e._malloc(4),a=n(t,r,i,s),o=e.getValue(s,"i32");return e._free(s),{result:a,dimid:o}},nc_def_var:(t,r,i,n,a)=>{const o=e._malloc(4),l=e._malloc(4*a.length);for(let t=0;t<a.length;t++)e.setValue(l+4*t,a[t],"i32");const c=s(t,r,i,n,l,o),u=e.getValue(o,"i32");return e._free(o),e._free(l),{result:c,varid:u}},nc_put_var_double:(t,r,i)=>{const n=e._malloc(8*i.length);e.HEAPF64.set(i,n/8);const s=a(t,r,n);return e._free(n),s},nc_get_var_double:(t,r,i)=>{const n=e._malloc(8*i),s=o(t,r,n),a=new Float64Array(e.HEAPF64.buffer,n,i),l=new Float64Array(a);return e._free(n),{result:s,data:l}},nc_enddef:e=>l(e),nc_inq_ndims:t=>{const r=e._malloc(4),i=c(t,r),n=e.getValue(r,"i32");return e._free(r),{result:i,ndims:n}},nc_inq_unlimdim:t=>{const r=e._malloc(4),i=u(t,r),n=e.getValue(r,"i32");return e._free(r),{result:i,unlimdimid:n}},nc_inq_dim:(t,r)=>{const i=e._malloc(256),n=e._malloc(4),s=d(t,r,i,n),a=e.UTF8ToString(i),o=e.getValue(n,"i32");return e._free(i),e._free(n),{result:s,name:a,len:o}},nc_inq_nvars:t=>{const r=e._malloc(4),i=f(t,r),n=e.getValue(r,"i32");return e._free(r),{result:i,nvars:n}},nc_inq_var:(t,r)=>{const i=e._malloc(256),n=e._malloc(4),s=e._malloc(4),a=e._malloc(4096),o=e._malloc(4),l=h(t,r,i,n,s,a,o),c=e.UTF8ToString(i),u=e.getValue(n,"i32"),d=e.getValue(s,"i32"),f=[];for(let t=0;t<d;t++)f.push(e.getValue(a+4*t,"i32"));const m=e.getValue(o,"i32");return e._free(i),e._free(n),e._free(s),e._free(a),e._free(o),{result:l,name:c,xtype:u,ndims:d,dimids:f,natts:m}},nc_inq_natts:t=>{const r=e._malloc(4),i=m(t,r),n=e.getValue(r,"i32");return e._free(r),{result:i,natts:n}},nc_inq_attname:(t,r,i)=>{const n=e._malloc(256),s=_(t,r,i,n),a=e.UTF8ToString(n);return e._free(n),{result:s,name:a}},nc_inq_att:(t,r,i)=>{const n=e._malloc(4),s=e._malloc(4),a=p(t,r,i,n,s),o=e.getValue(n,"i32"),l=e.getValue(s,"i32");return e._free(n),e._free(s),{result:a,xtype:o,len:l}},nc_get_att_text:(t,r,i,n)=>{const s=e._malloc(n+1),a=b(t,r,i,s);e.setValue(s+n,0,"i8");const o=e.UTF8ToString(s);return e._free(s),{result:a,text:o}},nc_get_att_double:(t,r,i,n)=>{const s=Math.max(n,1),a=e._malloc(8*s),o=w(t,r,i,a),l=new Float64Array(new Float64Array(e.HEAPF64.buffer,a,n));return e._free(a),{result:o,values:l}}}}}class o{constructor(e,t=65536,r=256){if(this.inner=e,this.cache=new Map,this._hits=0,this._misses=0,this._bytesFetched=0,!Number.isInteger(t)||t<=0)throw new RangeError(`blockSize must be a positive integer, got ${t}`);if(!Number.isInteger(r)||r<=0)throw new RangeError(`maxBlocks must be a positive integer, got ${r}`);this.blockSize=t,this.maxBlocks=r}get size(){return this.inner.size}read(e,t){if(e<0||t<0)throw new RangeError(`Invalid read(offset=${e}, length=${t})`);const r=Math.min(e+t,this.size);if(e>=this.size||r<=e)return new Uint8Array(0);const i=new Uint8Array(r-e),n=Math.floor(e/this.blockSize),s=Math.floor((r-1)/this.blockSize);for(let t=n;t<=s;t++){const n=this.getBlock(t),s=t*this.blockSize,a=Math.max(e,s),o=Math.min(r,s+n.length);o<=a||i.set(n.subarray(a-s,o-s),a-e)}return i}getBlock(e){const t=this.cache.get(e);if(void 0!==t)return this._hits++,this.cache.delete(e),this.cache.set(e,t),t;this._misses++;const r=e*this.blockSize,i=Math.min(this.blockSize,this.size-r),n=this.inner.read(r,i);if(this._bytesFetched+=n.length,this.cache.set(e,n),this.cache.size>this.maxBlocks){const e=this.cache.keys().next().value;void 0!==e&&this.cache.delete(e)}return n}get stats(){return{hits:this._hits,misses:this._misses,bytesFetched:this._bytesFetched,cachedBlocks:this.cache.size}}close(){this.cache.clear(),this.inner.close()}}class l{constructor(e){this.data=e}get size(){return this.data.length}read(e,t){const r=Math.min(e+t,this.data.length);return e<0||e>=this.data.length||r<=e?new Uint8Array(0):this.data.subarray(e,r)}close(){}}class c{constructor(e,t){this.closed=!1,this.fs=t??require("fs"),this.fd=this.fs.openSync(e,"r"),this._size=this.fs.fstatSync(this.fd).size}get size(){return this._size}read(e,t){if(this.closed)throw new Error("NodeFileReader is closed");const r=Math.min(e+t,this._size)-e;if(e<0||e>=this._size||r<=0)return new Uint8Array(0);const i=new Uint8Array(r);let n=0;for(;n<r;){const t=this.fs.readSync(this.fd,i,n,r-n,e+n);if(t<=0)break;n+=t}return n===r?i:i.subarray(0,n)}close(){this.closed||(this.closed=!0,this.fs.closeSync(this.fd))}}class u{constructor(e){this.blob=e;const t=globalThis.FileReaderSync;if(!t)throw new Error("BlobReader requires FileReaderSync, which is only available inside a Web Worker. Run lazy Blob reading in a worker, or load the file with the default (eager) path.");this.readerCtor=t}get size(){return this.blob.size}read(e,t){const r=Math.min(e+t,this.blob.size);if(e<0||e>=this.blob.size||r<=e)return new Uint8Array(0);const i=this.blob.slice(e,r),n=(new this.readerCtor).readAsArrayBuffer(i);return new Uint8Array(n)}close(){}}function d(e){return{read(t,r,i,n,s){if(s>=e.size||n<=0)return 0;const a=e.read(s,n),o=Math.min(a.length,n);return r.set(o===a.length?a:a.subarray(0,o),i),o},write(){throw new Error("Lazy NetCDF file is read-only")},llseek(t,r,i){let n=r;if(1===i?n+=t.position:2===i&&(n+=e.size),n<0)throw new Error(`Invalid seek to ${n}`);return n}}}function f(e,t,r){const i=t.lastIndexOf("/"),n=i>0?t.slice(0,i):"/",s=t.slice(i+1);if(n&&"/"!==n)try{e.mkdirTree?e.mkdirTree(n):e.mkdir(n)}catch{}const a=e.createFile(n,s,{},!0,!1);return Object.defineProperty(a,"usedBytes",{get:()=>r.size}),a.stream_ops=d(r),a}function h(e){if("object"==typeof(t=e)&&null!==t&&"function"==typeof t.read&&"number"==typeof t.size)return e;var t;if("undefined"!=typeof Blob&&e instanceof Blob)return new u(e);if("string"==typeof e)return new c(e);throw new Error("Unsupported lazy source: expected a LazyReader, Blob, or file path string")}class m extends s{constructor(e,t="r",r={}){super(null,"",-1),this.filename=e,this.mode=t,this.options=r,this.module=null,this.initialized=!1,this.ncid=-1,this._isOpen=!1,this.netcdf=this}async initialize(){if(!this.initialized)try{this.module=await a.loadModule(this.options),this.initialized=!0,this.memorySource&&await this.mountMemoryData(),this.lazySource&&await this.mountLazyData(),void 0!==this.filename&&null!==this.filename&&await this.open()}catch(e){if("undefined"==typeof process||"test"!==process.env.NODE_ENV)throw e;this.module=this.createMockModule(),this.initialized=!0,void 0!==this.filename&&null!==this.filename&&await this.open()}}static async Dataset(e,t="r",r={}){const i=new m(e,t,r);return await i.initialize(),i}static async fromBlob(e,t="r",r={}){if(r.lazy)return m.fromLazy(e,t,r);const i=await e.arrayBuffer();return m.fromArrayBuffer(i,t,r)}static async fromLazy(e,t="r",r={},i){if("r"!==t)throw new Error("Lazy datasets are read-only; use mode 'r'");const n=h(e),s=i||m.makeVirtualFilename("netcdf_lazy"),a=new m(s,t,r);return a.lazySource={reader:n,filename:s},await a.initialize(),a}static async fromArrayBuffer(e,t="r",r={}){const i=new Uint8Array(e);return m.fromMemory(i,t,r)}static makeVirtualFilename(e){const t=Math.random().toString(36).slice(2,11);return`/tmp/${e}_${Date.now()}_${t}.nc`}static async fromMemory(e,t="r",r={},i){if(!e)throw new Error("Data cannot be null or undefined");if(!(e instanceof ArrayBuffer||e instanceof Uint8Array))throw new Error("Data must be ArrayBuffer or Uint8Array");const n=e instanceof ArrayBuffer?new Uint8Array(e):e,s=i||m.makeVirtualFilename("netcdf"),a=new m(s,t,r);return a.memorySource={data:n,filename:s},await a.initialize(),a}async open(){if(this._isOpen)return;if(!this.filename||""===this.filename.trim())throw new Error("No filename specified");if(!["r","w","w-","a","r+"].includes(this.mode))throw new Error(`Unsupported mode: ${this.mode}`);if("w"===this.mode||"w-"===this.mode){let e=r.NC_CLOBBER;"NETCDF4"===this.options.format&&(e|=r.NC_NETCDF4);const t=await this.createFile(this.filename,e);this.ncid=t,this.groupId=t}else"r"!==this.mode&&"a"!==this.mode&&"r+"!==this.mode||(this.mode,this.ncid=await this.openFile(this.filename,this.mode),this.groupId=this.ncid,"undefined"!=typeof process&&"test"===process.env.NODE_ENV?this.loadMockDimensions():this.loadFromFile());this._isOpen=!0}get file_format(){return this.options.format||"NETCDF4"}get disk_format(){return this.file_format}get filepath(){return this.filename||""}get isopen(){return this._isOpen}isInitialized(){return this.initialized}getModule(){if(!this.module)throw new Error("NetCDF4 module not initialized. Call initialize() first.");return this.module}async close(){this._isOpen&&this.ncid>=0&&(await this.closeFile(this.ncid),this._isOpen=!1,this.ncid=-1),this.lazySource&&this.lazySource.reader.close()}async sync(){this._isOpen&&console.warn("sync() not yet implemented")}async __aenter__(){return this.initialized||await this.initialize(),this}async __aexit__(){await this.close()}async openFile(e,t="r"){const i=this.getModule(),n="r"===t?r.NC_NOWRITE:r.NC_WRITE,s=i.nc_open(e,n);if(s.result!==r.NC_NOERR)throw new Error(`Failed to open NetCDF file: ${e} (error: ${s.result})`);return s.ncid}async createFile(e,t=r.NC_CLOBBER){const i=this.getModule().nc_create(e,t);if(i.result!==r.NC_NOERR)throw new Error(`Failed to create NetCDF file: ${e} (error: ${i.result})`);return i.ncid}async closeFile(e){const t=this.getModule().nc_close(e);if(t!==r.NC_NOERR)throw new Error(`Failed to close NetCDF file with ID: ${e} (error: ${t})`)}async defineDimension(e,t,i){const n=this.getModule().nc_def_dim(e,t,i);if(n.result!==r.NC_NOERR)throw new Error(`Failed to define dimension: ${t} (error: ${n.result})`);return n.dimid}async defineVariable(e,t,i,n){const s=this.getModule().nc_def_var(e,t,i,n.length,n);if(s.result!==r.NC_NOERR)throw new Error(`Failed to define variable: ${t} (error: ${s.result})`);return s.varid}async endDefineMode(e){const t=this.getModule().nc_enddef(e);if(t!==r.NC_NOERR)throw new Error(`Failed to end define mode (error: ${t})`)}async putVariableDouble(e,t,i){const n=this.getModule().nc_put_var_double(e,t,i);if(n!==r.NC_NOERR)throw new Error(`Failed to write variable data (error: ${n})`)}async getVariableDouble(e,t,i){const n=this.getModule().nc_get_var_double(e,t,i);if(n.result!==r.NC_NOERR)throw new Error(`Failed to read variable data (error: ${n.result})`);return n.data}createMockModule(){global.__netcdf4_mock_files||(global.__netcdf4_mock_files={});const e=global.__netcdf4_mock_files;return{nc_open:(t,i)=>t&&""!==t.trim()&&!t.includes("unsupported")&&["r","w","a"].some(e=>this.mode.includes(e))?("r"!==this.mode||e[t]||(e[t]={attributes:{},dimensions:{},variables:{}}),{result:r.NC_NOERR,ncid:1}):{result:-1,ncid:-1},nc_close:e=>r.NC_NOERR,nc_create:(t,i)=>t.includes("unsupported")||["x","invalid"].some(e=>this.mode.includes(e))?{result:-1,ncid:-1}:(e[t]={attributes:{},dimensions:{},variables:{}},{result:r.NC_NOERR,ncid:1}),nc_def_dim:(t,i,n)=>(this.filename&&e[this.filename]&&(e[this.filename].dimensions[i]={size:n,unlimited:n===r.NC_UNLIMITED}),{result:r.NC_NOERR,dimid:1}),nc_def_var:(t,i,n,s,a)=>{if(this.filename&&e[this.filename]){e[this.filename].variables[i]={data:new Float64Array(0),attributes:{}};const t=Object.keys(e[this.filename].variables).length;return{result:r.NC_NOERR,varid:t}}return{result:r.NC_NOERR,varid:1}},nc_put_var_double:(t,i,n)=>{if(this.filename&&e[this.filename]){const t=e[this.filename].variables,r=Object.keys(t);if(r.length>0&&i>=1&&i<=r.length){t[r[i-1]].data=new Float64Array(n)}}return r.NC_NOERR},nc_get_var_double:(t,i,n)=>{if(this.filename&&e[this.filename]){const t=e[this.filename].variables,s=Object.keys(t);if(s.length>0&&i>=1&&i<=s.length){const e=t[s[i-1]].data;if(e&&e.length>0){if(n<=0)return{result:r.NC_NOERR,data:new Float64Array(0)};const t=new Float64Array(n);for(let r=0;r<n&&r<e.length;r++)t[r]=e[r];return{result:r.NC_NOERR,data:t}}}}if(n<=0)return{result:r.NC_NOERR,data:new Float64Array(0)};const s=new Float64Array(n);for(let e=0;e<n;e++)s[e]=.1*e;return{result:r.NC_NOERR,data:s}},nc_enddef:e=>r.NC_NOERR}}async mountMemoryData(){if(this.memorySource&&this.module&&("undefined"==typeof process||"test"!==process.env.NODE_ENV))try{const e=this.getModule();if(!e.FS)throw new Error("Emscripten FS not available");try{e.FS.mkdir("/tmp")}catch(e){}e.FS.writeFile(this.memorySource.filename,this.memorySource.data)}catch(e){throw new Error(`Failed to mount memory data: ${e}`)}}async mountLazyData(){if(this.lazySource&&this.module&&("undefined"==typeof process||"test"!==process.env.NODE_ENV))try{const e=this.getModule();if(!e.FS)throw new Error("Emscripten FS not available - rebuild the WASM module with -sFORCE_FILESYSTEM=1 and FS in EXPORTED_RUNTIME_METHODS");const t=new o(this.lazySource.reader,this.options.blockSize,this.options.maxCacheBlocks);f(e.FS,this.lazySource.filename,t)}catch(e){throw new Error(`Failed to mount lazy data: ${e}`)}}async toArrayBuffer(){if(!this.module)throw new Error("NetCDF4 module not initialized");if("undefined"!=typeof process&&"test"===process.env.NODE_ENV)return new ArrayBuffer(0);try{const e=this.getModule();if(!e.FS||!this.filename)throw new Error("Cannot read file data");const t=e.FS.readFile(this.filename);return t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength)}catch(e){throw new Error(`Failed to read data as ArrayBuffer: ${e}`)}}async toBlob(e="application/x-netcdf"){const t=await this.toArrayBuffer();return new Blob([t],{type:e})}toString(){const e=this._isOpen?"open":"closed",t=this.memorySource?"(in-memory)":this.lazySource?"(lazy)":"";return`<netCDF4.Dataset '${this.filename}'${t}: mode = '${this.mode}', file format = '${this.file_format}', ${e}>`}}async function _(e,t="r",r={}){if("string"==typeof e)return r.lazy?await m.fromLazy(e,t,r):await m.Dataset(e,t,r);if(e instanceof Blob)return await m.fromBlob(e,t,r);if(e instanceof ArrayBuffer)return await m.fromArrayBuffer(e,t,r);if(e instanceof Uint8Array)return await m.fromMemory(e,t,r);throw new Error("Invalid source type. Expected string, Blob, ArrayBuffer, or Uint8Array.")}async function p(e,t="r",r={}){return await _(e,t,r)}async function b(e,t="r",r={}){return await _(e,t,r)}async function w(e,t="r",r={},i){return i?await m.fromMemory(e,t,r,i):await _(e,t,r)}export{u as BlobReader,o as CachedReader,i as DATA_TYPE_MAP,_ as Dataset,b as DatasetFromArrayBuffer,p as DatasetFromBlob,w as DatasetFromMemory,e as Dimension,s as Group,l as MemoryReader,r as NC_CONSTANTS,m as NetCDF4,c as NodeFileReader,t as Variable,h as createLazyReader,d as createLazyStreamOps,m as default,f as mountLazyFile};