Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

netcdfjs

Package Overview
Dependencies
Maintainers
5
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

netcdfjs - npm Package Compare versions

Comparing version 2.0.2 to 3.0.0

lib-esm/data.d.ts

691

lib/index.js

@@ -1,675 +0,18 @@

'use strict';
var iobuffer = require('iobuffer');
/**
* Throws a non-valid NetCDF exception if the statement it's true
* @ignore
* @param {boolean} statement - Throws if true
* @param {string} reason - Reason to throw
*/
function notNetcdf(statement, reason) {
if (statement) {
throw new TypeError(`Not a valid NetCDF v3.x file: ${reason}`);
}
}
/**
* Moves 1, 2, or 3 bytes to next 4-byte boundary
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
*/
function padding(buffer) {
if (buffer.offset % 4 !== 0) {
buffer.skip(4 - (buffer.offset % 4));
}
}
/**
* Reads the name
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @return {string} - Name
*/
function readName(buffer) {
// Read name
let nameLength = buffer.readUint32();
let name = buffer.readChars(nameLength);
// validate name
// TODO
// Apply padding
padding(buffer);
return name;
}
const types = {
BYTE: 1,
CHAR: 2,
SHORT: 3,
INT: 4,
FLOAT: 5,
DOUBLE: 6,
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
/**
* Parse a number into their respective type
* @ignore
* @param {number} type - integer that represents the type
* @return {string} - parsed value of the type
*/
function num2str(type) {
switch (Number(type)) {
case types.BYTE:
return "byte";
case types.CHAR:
return "char";
case types.SHORT:
return "short";
case types.INT:
return "int";
case types.FLOAT:
return "float";
case types.DOUBLE:
return "double";
/* istanbul ignore next */
default:
return "undefined";
}
}
/**
* Parse a number type identifier to his size in bytes
* @ignore
* @param {number} type - integer that represents the type
* @return {number} -size of the type
*/
function num2bytes(type) {
switch (Number(type)) {
case types.BYTE:
return 1;
case types.CHAR:
return 1;
case types.SHORT:
return 2;
case types.INT:
return 4;
case types.FLOAT:
return 4;
case types.DOUBLE:
return 8;
/* istanbul ignore next */
default:
return -1;
}
}
/**
* Reverse search of num2str
* @ignore
* @param {string} type - string that represents the type
* @return {number} - parsed value of the type
*/
function str2num(type) {
switch (String(type)) {
case "byte":
return types.BYTE;
case "char":
return types.CHAR;
case "short":
return types.SHORT;
case "int":
return types.INT;
case "float":
return types.FLOAT;
case "double":
return types.DOUBLE;
/* istanbul ignore next */
default:
return -1;
}
}
/**
* Auxiliary function to read numeric data
* @ignore
* @param {number} size - Size of the element to read
* @param {function} bufferReader - Function to read next value
* @return {Array<number>|number}
*/
function readNumber(size, bufferReader) {
if (size !== 1) {
let numbers = new Array(size);
for (let i = 0; i < size; i++) {
numbers[i] = bufferReader();
}
return numbers;
} else {
return bufferReader();
}
}
/**
* Given a type and a size reads the next element
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {number} type - Type of the data to read
* @param {number} size - Size of the element to read
* @return {string|Array<number>|number}
*/
function readType(buffer, type, size) {
switch (type) {
case types.BYTE:
return buffer.readBytes(size);
case types.CHAR:
return trimNull(buffer.readChars(size));
case types.SHORT:
return readNumber(size, buffer.readInt16.bind(buffer));
case types.INT:
return readNumber(size, buffer.readInt32.bind(buffer));
case types.FLOAT:
return readNumber(size, buffer.readFloat32.bind(buffer));
case types.DOUBLE:
return readNumber(size, buffer.readFloat64.bind(buffer));
/* istanbul ignore next */
default:
notNetcdf(true, `non valid type ${type}`);
return undefined;
}
}
/**
* Removes null terminate value
* @ignore
* @param {string} value - String to trim
* @return {string} - Trimmed string
*/
function trimNull(value) {
if (value.charCodeAt(value.length - 1) === 0) {
return value.substring(0, value.length - 1);
}
return value;
}
// const STREAMING = 4294967295;
/**
* Read data for the given non-record variable
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {object} variable - Variable metadata
* @return {Array} - Data of the element
*/
function nonRecord(buffer, variable) {
// variable type
const type = str2num(variable.type);
// size of the data
let size = variable.size / num2bytes(type);
// iterates over the data
let data = new Array(size);
for (let i = 0; i < size; i++) {
data[i] = readType(buffer, type, 1);
}
return data;
}
/**
* Read data for the given record variable
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {object} variable - Variable metadata
* @param {object} recordDimension - Record dimension metadata
* @return {Array} - Data of the element
*/
function record(buffer, variable, recordDimension) {
// variable type
const type = str2num(variable.type);
const width = variable.size ? variable.size / num2bytes(type) : 1;
// size of the data
// TODO streaming data
let size = recordDimension.length;
// iterates over the data
let data = new Array(size);
const step = recordDimension.recordStep;
for (let i = 0; i < size; i++) {
let currentOffset = buffer.offset;
data[i] = readType(buffer, type, width);
buffer.seek(currentOffset + step);
}
return data;
}
// Grammar constants
const ZERO = 0;
const NC_DIMENSION = 10;
const NC_VARIABLE = 11;
const NC_ATTRIBUTE = 12;
/**
* Read the header of the file
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {number} version - Version of the file
* @return {object} - Object with the fields:
* * `recordDimension`: Number with the length of record dimension
* * `dimensions`: List of dimensions
* * `globalAttributes`: List of global attributes
* * `variables`: List of variables
*/
function header(buffer, version) {
// Length of record dimension
// sum of the varSize's of all the record variables.
let header = { recordDimension: { length: buffer.readUint32() } };
// Version
header.version = version;
// List of dimensions
let dimList = dimensionsList(buffer);
header.recordDimension.id = dimList.recordId; // id of the unlimited dimension
header.recordDimension.name = dimList.recordName; // name of the unlimited dimension
header.dimensions = dimList.dimensions;
// List of global attributes
header.globalAttributes = attributesList(buffer);
// List of variables
let variables = variablesList(buffer, dimList.recordId, version);
header.variables = variables.variables;
header.recordDimension.recordStep = variables.recordStep;
return header;
}
const NC_UNLIMITED = 0;
/**
* List of dimensions
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @return {object} - Ojbect containing the following properties:
* * `dimensions` that is an array of dimension object:
* * `name`: String with the name of the dimension
* * `size`: Number with the size of the dimension dimensions: dimensions
* * `recordId`: the id of the dimension that has unlimited size or undefined,
* * `recordName`: name of the dimension that has unlimited size
*/
function dimensionsList(buffer) {
let recordId, recordName;
const dimList = buffer.readUint32();
let dimensions;
if (dimList === ZERO) {
notNetcdf(
buffer.readUint32() !== ZERO,
"wrong empty tag for list of dimensions"
);
return [];
} else {
notNetcdf(dimList !== NC_DIMENSION, "wrong tag for list of dimensions");
// Length of dimensions
const dimensionSize = buffer.readUint32();
dimensions = new Array(dimensionSize);
for (let dim = 0; dim < dimensionSize; dim++) {
// Read name
let name = readName(buffer);
// Read dimension size
const size = buffer.readUint32();
if (size === NC_UNLIMITED) {
// in netcdf 3 one field can be of size unlimmited
recordId = dim;
recordName = name;
}
dimensions[dim] = {
name,
size,
};
}
}
return {
dimensions,
recordId,
recordName,
};
}
/**
* List of attributes
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @return {Array<object>} - List of attributes with:
* * `name`: String with the name of the attribute
* * `type`: String with the type of the attribute
* * `value`: A number or string with the value of the attribute
*/
function attributesList(buffer) {
const gAttList = buffer.readUint32();
let attributes;
if (gAttList === ZERO) {
notNetcdf(
buffer.readUint32() !== ZERO,
"wrong empty tag for list of attributes"
);
return [];
} else {
notNetcdf(gAttList !== NC_ATTRIBUTE, "wrong tag for list of attributes");
// Length of attributes
const attributeSize = buffer.readUint32();
attributes = new Array(attributeSize);
for (let gAtt = 0; gAtt < attributeSize; gAtt++) {
// Read name
let name = readName(buffer);
// Read type
let type = buffer.readUint32();
notNetcdf(type < 1 || type > 6, `non valid type ${type}`);
// Read attribute
let size = buffer.readUint32();
let value = readType(buffer, type, size);
// Apply padding
padding(buffer);
attributes[gAtt] = {
name,
type: num2str(type),
value,
};
}
}
return attributes;
}
/**
* List of variables
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {number} recordId - Id of the unlimited dimension (also called record dimension)
* This value may be undefined if there is no unlimited dimension
* @param {number} version - Version of the file
* @return {object} - Number of recordStep and list of variables with:
* * `name`: String with the name of the variable
* * `dimensions`: Array with the dimension IDs of the variable
* * `attributes`: Array with the attributes of the variable
* * `type`: String with the type of the variable
* * `size`: Number with the size of the variable
* * `offset`: Number with the offset where of the variable begins
* * `record`: True if is a record variable, false otherwise (unlimited size)
*/
function variablesList(buffer, recordId, version) {
const varList = buffer.readUint32();
let recordStep = 0;
let variables;
if (varList === ZERO) {
notNetcdf(
buffer.readUint32() !== ZERO,
"wrong empty tag for list of variables"
);
return [];
} else {
notNetcdf(varList !== NC_VARIABLE, "wrong tag for list of variables");
// Length of variables
const variableSize = buffer.readUint32();
variables = new Array(variableSize);
for (let v = 0; v < variableSize; v++) {
// Read name
let name = readName(buffer);
// Read dimensionality of the variable
const dimensionality = buffer.readUint32();
// Index into the list of dimensions
let dimensionsIds = new Array(dimensionality);
for (let dim = 0; dim < dimensionality; dim++) {
dimensionsIds[dim] = buffer.readUint32();
}
// Read variables size
let attributes = attributesList(buffer);
// Read type
let type = buffer.readUint32();
notNetcdf(type < 1 && type > 6, `non valid type ${type}`);
// Read variable size
// The 32-bit varSize field is not large enough to contain the size of variables that require
// more than 2^32 - 4 bytes, so 2^32 - 1 is used in the varSize field for such variables.
const varSize = buffer.readUint32();
// Read offset
let offset = buffer.readUint32();
if (version === 2) {
notNetcdf(offset > 0, "offsets larger than 4GB not supported");
offset = buffer.readUint32();
}
let record = false;
// Count amount of record variables
if (typeof recordId !== "undefined" && dimensionsIds[0] === recordId) {
recordStep += varSize;
record = true;
}
variables[v] = {
name,
dimensions: dimensionsIds,
attributes,
type: num2str(type),
size: varSize,
offset,
record,
};
}
}
return {
variables,
recordStep,
};
}
function toString() {
let result = [];
result.push("DIMENSIONS");
for (let dimension of this.dimensions) {
result.push(` ${dimension.name.padEnd(30)} = size: ${dimension.size}`);
}
result.push("");
result.push("GLOBAL ATTRIBUTES");
for (let attribute of this.globalAttributes) {
result.push(` ${attribute.name.padEnd(30)} = ${attribute.value}`);
}
let variables = JSON.parse(JSON.stringify(this.variables));
result.push("");
result.push("VARIABLES:");
for (let variable of variables) {
variable.value = this.getDataVariable(variable);
let stringify = JSON.stringify(variable.value);
if (stringify.length > 50) stringify = stringify.substring(0, 50);
if (!isNaN(variable.value.length)) {
stringify += ` (length: ${variable.value.length})`;
}
result.push(` ${variable.name.padEnd(30)} = ${stringify}`);
}
return result.join("\n");
}
/**
* Reads a NetCDF v3.x file
* https://www.unidata.ucar.edu/software/netcdf/docs/file_format_specifications.html
* @param {ArrayBuffer} data - ArrayBuffer or any Typed Array (including Node.js' Buffer from v4) with the data
* @constructor
*/
class NetCDFReader {
constructor(data) {
const buffer = new iobuffer.IOBuffer(data);
buffer.setBigEndian();
// Validate that it's a NetCDF file
notNetcdf(buffer.readChars(3) !== "CDF", "should start with CDF");
// Check the NetCDF format
const version = buffer.readByte();
notNetcdf(version > 2, "unknown version");
// Read the header
this.header = header(buffer, version);
this.buffer = buffer;
}
/**
* @return {string} - Version for the NetCDF format
*/
get version() {
if (this.header.version === 1) {
return "classic format";
} else {
return "64-bit offset format";
}
}
/**
* @return {object} - Metadata for the record dimension
* * `length`: Number of elements in the record dimension
* * `id`: Id number in the list of dimensions for the record dimension
* * `name`: String with the name of the record dimension
* * `recordStep`: Number with the record variables step size
*/
get recordDimension() {
return this.header.recordDimension;
}
/**
* @return {Array<object>} - List of dimensions with:
* * `name`: String with the name of the dimension
* * `size`: Number with the size of the dimension
*/
get dimensions() {
return this.header.dimensions;
}
/**
* @return {Array<object>} - List of global attributes with:
* * `name`: String with the name of the attribute
* * `type`: String with the type of the attribute
* * `value`: A number or string with the value of the attribute
*/
get globalAttributes() {
return this.header.globalAttributes;
}
/**
* Returns the value of an attribute
* @param {string} attributeName
* @return {string} Value of the attributeName or null
*/
getAttribute(attributeName) {
const attribute = this.globalAttributes.find(
(val) => val.name === attributeName
);
if (attribute) return attribute.value;
return null;
}
/**
* Returns the value of a variable as a string
* @param {string} variableName
* @return {string} Value of the variable as a string or null
*/
getDataVariableAsString(variableName) {
const variable = this.getDataVariable(variableName);
if (variable) return variable.join("");
return null;
}
/**
* @return {Array<object>} - List of variables with:
* * `name`: String with the name of the variable
* * `dimensions`: Array with the dimension IDs of the variable
* * `attributes`: Array with the attributes of the variable
* * `type`: String with the type of the variable
* * `size`: Number with the size of the variable
* * `offset`: Number with the offset where of the variable begins
* * `record`: True if is a record variable, false otherwise
*/
get variables() {
return this.header.variables;
}
toString() {
return toString.call(this);
}
/**
* Retrieves the data for a given variable
* @param {string|object} variableName - Name of the variable to search or variable object
* @return {Array} - List with the variable values
*/
getDataVariable(variableName) {
let variable;
if (typeof variableName === "string") {
// search the variable
variable = this.header.variables.find((val) => {
return val.name === variableName;
});
} else {
variable = variableName;
}
// throws if variable not found
notNetcdf(variable === undefined, `variable not found: ${variableName}`);
// go to the offset position
this.buffer.seek(variable.offset);
if (variable.record) {
// record variable case
return record(this.buffer, variable, this.header.recordDimension);
} else {
// non-record variable case
return nonRecord(this.buffer, variable);
}
}
/**
* Check if a dataVariable exists
* @param {string} variableName - Name of the variable to find
* @return {boolean}
*/
dataVariableExists(variableName) {
const variable = this.header.variables.find((val) => {
return val.name === variableName;
});
return variable !== undefined;
}
/**
* Check if an attribute exists
* @param {string} attributeName - Name of the attribute to find
* @return {boolean}
*/
attributeExists(attributeName) {
const attribute = this.globalAttributes.find(
(val) => val.name === attributeName
);
return attribute !== undefined;
}
}
exports.NetCDFReader = NetCDFReader;
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./parser"), exports);
//# sourceMappingURL=index.js.map
{
"name": "netcdfjs",
"version": "2.0.2",
"version": "3.0.0",
"description": "Read and explore NetCDF files",
"main": "lib/index.js",
"module": "src/index.js",
"main": "./lib/index.js",
"module": "./lib-esm/index.js",
"types": "./lib/index.d.ts",
"files": [
"src",
"lib",
"lib-esm"
],
"keywords": [

@@ -13,6 +19,2 @@ "netcdf",

],
"files": [
"src",
"lib"
],
"author": "Miguel Asencio <maasencioh@gmail.com> (https://github.com/maasencioh)",

@@ -26,24 +28,28 @@ "repository": "cheminfo/netcdfjs",

"scripts": {
"build": "cheminfo-build --entry src/index.js --root NetCDF",
"eslint": "eslint src",
"check-types": "tsc --noEmit",
"clean": "rimraf lib lib-esm",
"eslint": "eslint src --cache",
"eslint-fix": "npm run eslint -- --fix",
"prepack": "rollup -c",
"prepack": "npm run tsc",
"prettier": "prettier --check src",
"prettier-write": "prettier --write src",
"test": "npm run test-only && npm run eslint && npm run prettier",
"test-only": "jest --coverage"
"test": "npm run test-only && npm run eslint && npm run prettier && npm run check-types",
"test-only": "jest --coverage",
"tsc": "npm run clean && npm run tsc-cjs && npm run tsc-esm",
"tsc-cjs": "tsc --project tsconfig.cjs.json",
"tsc-esm": "tsc --project tsconfig.esm.json"
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.19.6",
"@types/jest": "^29.2.0",
"cheminfo-build": "^1.1.11",
"eslint": "^8.25.0",
"eslint-config-cheminfo": "^8.0.2",
"jest": "^29.2.1",
"prettier": "^2.7.1",
"rollup": "^3.2.3"
"@types/jest": "^29.5.3",
"cheminfo-types": "^1.7.2",
"eslint": "^8.46.0",
"eslint-config-cheminfo-typescript": "^12.0.4",
"jest": "^29.6.2",
"prettier": "^3.0.1",
"ts-jest": "^29.1.1",
"typescript": "^5.1.6"
},
"dependencies": {
"iobuffer": "^5.2.1"
"iobuffer": "^5.3.2"
}
}
# netcdfjs
[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![build status][ci-image]][ci-url]
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url]

@@ -35,7 +35,8 @@

[npm-image]: https://img.shields.io/npm/v/netcdfjs.svg?style=flat-square
[npm-image]: https://img.shields.io/npm/v/netcdfjs.svg
[npm-url]: https://www.npmjs.com/package/netcdfjs
[coveralls-image]: https://img.shields.io/coveralls/cheminfo/netcdfjs.svg?style=flat-square
[coveralls-url]: https://coveralls.io/github/cheminfo/netcdfjs
[download-image]: https://img.shields.io/npm/dm/netcdfjs.svg?style=flat-square
[download-url]: https://www.npmjs.com/package/netcdfjs
[ci-image]: https://github.com/cheminfo/netcdfjs/workflows/Node.js%20CI/badge.svg?branch=main
[ci-url]: https://github.com/cheminfo/netcdfjs/actions?query=workflow%3A%22Node.js+CI%22
[codecov-image]: https://img.shields.io/codecov/c/github/cheminfo/netcdfjs.svg
[codecov-url]: https://codecov.io/gh/cheminfo/netcdfjs
[download-image]: https://img.shields.io/npm/dm/netcdfjs.svg
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc