Comparing version 2.0.2 to 3.0.0
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 |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
110093
66
2233
42
1
Updatediobuffer@^5.3.2