netcdf4-wasm
Version:
NetCDF4 library compiled to WebAssembly with TypeScript bindings
280 lines • 13.8 kB
JavaScript
;
// WASM module loading and wrapping functionality
Object.defineProperty(exports, "__esModule", { value: true });
exports.WasmModuleLoader = void 0;
class WasmModuleLoader {
static async loadModule(options = {}) {
try {
const moduleFactory = WasmModuleLoader.resolveModuleFactory(WasmModuleLoader.loadRawLoader(options));
const rawModule = await moduleFactory({
locateFile: (path) => {
if (options.wasmPath) {
const wasmPath = options.wasmPath.replace(".js", ".wasm");
return wasmPath;
}
// For Node.js environment, provide absolute path to WASM file
if (typeof window === "undefined") {
const path_module = require("path");
return path_module.join(__dirname, "..", "dist", "netcdf4-module.wasm");
}
return path;
},
});
// A real Emscripten runtime exposes cwrap. If it does not, we loaded
// the wrong file (see resolveModuleFactory) or a build without the
// required runtime methods exported.
if (typeof rawModule?.cwrap !== "function") {
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".');
}
// Wrap the module with high-level functions
return WasmModuleLoader.wrapModule(rawModule);
}
catch (error) {
throw new Error(`Failed to load NetCDF4 WASM module: ${error}`);
}
}
/** Load the raw Emscripten loader export: browser global or Node require. */
static loadRawLoader(options) {
if (typeof window !== "undefined") {
// Browser: the Emscripten loader must already be on the global scope.
if (typeof NetCDF4Module === "undefined") {
throw new Error("NetCDF4Module global not found. Load dist/netcdf4-module.js " +
"(the Emscripten loader) before using the library in the browser.");
}
return NetCDF4Module;
}
// Node.js: require the generated Emscripten loader.
const path = require("path");
const wasmPath = options.wasmPath ||
path.join(__dirname, "..", "dist", "netcdf4-module.js");
try {
return require(wasmPath);
}
catch (error) {
throw new Error(`Could not load the Emscripten loader from "${wasmPath}". Build it with ` +
`\`npm run build:wasm\`, or pass options.wasmPath. (${error})`);
}
}
/**
* Resolve the Emscripten module factory from a raw module export.
*
* Emscripten's MODULARIZE build exports the factory as `module.exports`
* (CommonJS) or, under ESM interop, as a `default` export. Accept either.
* Throws a clear, actionable error when the value is not a factory function
* - most commonly because the library entry point (which exports the
* `NetCDF4` class) was required instead of the generated loader. See issue #3.
*/
static resolveModuleFactory(raw) {
const candidate = typeof raw === "function"
? raw
: raw?.default;
if (typeof candidate !== "function") {
const found = raw && typeof raw === "object"
? `object with keys [${Object.keys(raw).join(", ")}]`
: `${raw === null ? "null" : typeof raw}`;
throw new Error(`Expected the Emscripten module factory (a function) but got ${found}. ` +
"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 candidate;
}
static wrapModule(module) {
// Create wrappers for NetCDF functions
const nc_open_wrapper = module.cwrap("nc_open_wrapper", "number", [
"string",
"number",
"number",
]);
const nc_close_wrapper = module.cwrap("nc_close_wrapper", "number", [
"number",
]);
const nc_create_wrapper = module.cwrap("nc_create_wrapper", "number", [
"string",
"number",
"number",
]);
const nc_def_dim_wrapper = module.cwrap("nc_def_dim_wrapper", "number", [
"number",
"string",
"number",
"number",
]);
const nc_def_var_wrapper = module.cwrap("nc_def_var_wrapper", "number", [
"number",
"string",
"number",
"number",
"number",
"number",
]);
const nc_put_var_double_wrapper = module.cwrap("nc_put_var_double_wrapper", "number", ["number", "number", "number"]);
const nc_get_var_double_wrapper = module.cwrap("nc_get_var_double_wrapper", "number", ["number", "number", "number"]);
const nc_enddef_wrapper = module.cwrap("nc_enddef_wrapper", "number", [
"number",
]);
const nc_inq_ndims_wrapper = module.cwrap("nc_inq_ndims_wrapper", "number", ["number", "number"]);
const nc_inq_unlimdim_wrapper = module.cwrap("nc_inq_unlimdim_wrapper", "number", ["number", "number"]);
const nc_inq_dim_wrapper = module.cwrap("nc_inq_dim_wrapper", "number", ["number", "number", "number", "number"]);
const nc_inq_nvars_wrapper = module.cwrap("nc_inq_nvars_wrapper", "number", ["number", "number"]);
const nc_inq_var_wrapper = module.cwrap("nc_inq_var_wrapper", "number", ["number", "number", "number", "number", "number", "number", "number"]);
const nc_inq_natts_wrapper = module.cwrap("nc_inq_natts_wrapper", "number", ["number", "number"]);
const nc_inq_attname_wrapper = module.cwrap("nc_inq_attname_wrapper", "number", ["number", "number", "number", "number"]);
const nc_inq_att_wrapper = module.cwrap("nc_inq_att_wrapper", "number", ["number", "number", "string", "number", "number"]);
const nc_get_att_text_wrapper = module.cwrap("nc_get_att_text_wrapper", "number", ["number", "number", "string", "number"]);
const nc_get_att_double_wrapper = module.cwrap("nc_get_att_double_wrapper", "number", ["number", "number", "string", "number"]);
return {
...module,
nc_open: (path, mode) => {
const ncidPtr = module._malloc(4);
const result = nc_open_wrapper(path, mode, ncidPtr);
const ncid = module.getValue(ncidPtr, "i32");
module._free(ncidPtr);
return { result, ncid };
},
nc_close: (ncid) => {
return nc_close_wrapper(ncid);
},
nc_create: (path, mode) => {
const ncidPtr = module._malloc(4);
const result = nc_create_wrapper(path, mode, ncidPtr);
const ncid = module.getValue(ncidPtr, "i32");
module._free(ncidPtr);
return { result, ncid };
},
nc_def_dim: (ncid, name, len) => {
const dimidPtr = module._malloc(4);
const result = nc_def_dim_wrapper(ncid, name, len, dimidPtr);
const dimid = module.getValue(dimidPtr, "i32");
module._free(dimidPtr);
return { result, dimid };
},
nc_def_var: (ncid, name, xtype, ndims, dimids) => {
const varidPtr = module._malloc(4);
const dimidsPtr = module._malloc(dimids.length * 4);
for (let i = 0; i < dimids.length; i++) {
module.setValue(dimidsPtr + i * 4, dimids[i], "i32");
}
const result = nc_def_var_wrapper(ncid, name, xtype, ndims, dimidsPtr, varidPtr);
const varid = module.getValue(varidPtr, "i32");
module._free(varidPtr);
module._free(dimidsPtr);
return { result, varid };
},
nc_put_var_double: (ncid, varid, data) => {
const dataPtr = module._malloc(data.length * 8);
module.HEAPF64.set(data, dataPtr / 8);
const result = nc_put_var_double_wrapper(ncid, varid, dataPtr);
module._free(dataPtr);
return result;
},
nc_get_var_double: (ncid, varid, size) => {
const dataPtr = module._malloc(size * 8);
const result = nc_get_var_double_wrapper(ncid, varid, dataPtr);
const data = new Float64Array(module.HEAPF64.buffer, dataPtr, size);
const resultData = new Float64Array(data);
module._free(dataPtr);
return { result, data: resultData };
},
nc_enddef: (ncid) => {
return nc_enddef_wrapper(ncid);
},
nc_inq_ndims: (ncid) => {
const p = module._malloc(4);
const result = nc_inq_ndims_wrapper(ncid, p);
const ndims = module.getValue(p, "i32");
module._free(p);
return { result, ndims };
},
nc_inq_unlimdim: (ncid) => {
const p = module._malloc(4);
const result = nc_inq_unlimdim_wrapper(ncid, p);
const unlimdimid = module.getValue(p, "i32");
module._free(p);
return { result, unlimdimid };
},
nc_inq_dim: (ncid, dimid) => {
const namePtr = module._malloc(256);
const lenPtr = module._malloc(4);
const result = nc_inq_dim_wrapper(ncid, dimid, namePtr, lenPtr);
const name = module.UTF8ToString(namePtr);
const len = module.getValue(lenPtr, "i32");
module._free(namePtr);
module._free(lenPtr);
return { result, name, len };
},
nc_inq_nvars: (ncid) => {
const p = module._malloc(4);
const result = nc_inq_nvars_wrapper(ncid, p);
const nvars = module.getValue(p, "i32");
module._free(p);
return { result, nvars };
},
nc_inq_var: (ncid, varid) => {
const namePtr = module._malloc(256);
const xtypePtr = module._malloc(4);
const ndimsPtr = module._malloc(4);
const dimidsPtr = module._malloc(1024 * 4);
const nattsPtr = module._malloc(4);
const result = nc_inq_var_wrapper(ncid, varid, namePtr, xtypePtr, ndimsPtr, dimidsPtr, nattsPtr);
const name = module.UTF8ToString(namePtr);
const xtype = module.getValue(xtypePtr, "i32");
const ndims = module.getValue(ndimsPtr, "i32");
const dimids = [];
for (let i = 0; i < ndims; i++) {
dimids.push(module.getValue(dimidsPtr + i * 4, "i32"));
}
const natts = module.getValue(nattsPtr, "i32");
module._free(namePtr);
module._free(xtypePtr);
module._free(ndimsPtr);
module._free(dimidsPtr);
module._free(nattsPtr);
return { result, name, xtype, ndims, dimids, natts };
},
nc_inq_natts: (ncid) => {
const p = module._malloc(4);
const result = nc_inq_natts_wrapper(ncid, p);
const natts = module.getValue(p, "i32");
module._free(p);
return { result, natts };
},
nc_inq_attname: (ncid, varid, attnum) => {
const namePtr = module._malloc(256);
const result = nc_inq_attname_wrapper(ncid, varid, attnum, namePtr);
const name = module.UTF8ToString(namePtr);
module._free(namePtr);
return { result, name };
},
nc_inq_att: (ncid, varid, name) => {
const xtypePtr = module._malloc(4);
const lenPtr = module._malloc(4);
const result = nc_inq_att_wrapper(ncid, varid, name, xtypePtr, lenPtr);
const xtype = module.getValue(xtypePtr, "i32");
const len = module.getValue(lenPtr, "i32");
module._free(xtypePtr);
module._free(lenPtr);
return { result, xtype, len };
},
nc_get_att_text: (ncid, varid, name, len) => {
const valuePtr = module._malloc(len + 1);
const result = nc_get_att_text_wrapper(ncid, varid, name, valuePtr);
module.setValue(valuePtr + len, 0, "i8");
const text = module.UTF8ToString(valuePtr);
module._free(valuePtr);
return { result, text };
},
nc_get_att_double: (ncid, varid, name, len) => {
const count = Math.max(len, 1);
const valuePtr = module._malloc(count * 8);
const result = nc_get_att_double_wrapper(ncid, varid, name, valuePtr);
const values = new Float64Array(new Float64Array(module.HEAPF64.buffer, valuePtr, len));
module._free(valuePtr);
return { result, values };
},
};
}
}
exports.WasmModuleLoader = WasmModuleLoader;
//# sourceMappingURL=wasm-module.js.map