UNPKG

ni-data-types

Version:

Non-standard data types used by the webcharts team.

552 lines (439 loc) 16.2 kB
(function () { var TypeNames = Object.freeze({ VOID: 'Void', BOOLEAN: 'Boolean', UINT8: 'UInt8', UINT16: 'UInt16', UINT32: 'UInt32', UINT64: 'UInt64', INT8: 'Int8', INT16: 'Int16', INT32: 'Int32', INT64: 'Int64', SINGLE: 'Single', DOUBLE: 'Double', COMPLEXSINGLE: 'ComplexSingle', COMPLEXDOUBLE: 'ComplexDouble', STRING: 'String', PATH: 'Path', TIMESTAMP: 'Timestamp', ENUM: 'Enum', CLUSTER: 'Cluster', ARRAY: 'Array', ANALOGWAVEFORM: 'AnalogWaveform', DIGITALWAVEFORM: 'DigitalWaveform' }); // Numeric helper functions var isFloat = function (typeName) { return typeName === TypeNames.SINGLE || typeName === TypeNames.DOUBLE; }; var isSignedInteger = function (typeName) { switch (typeName) { case TypeNames.INT8: case TypeNames.INT16: case TypeNames.INT32: case TypeNames.INT64: return true; default: return false; } }; var isUnsignedInteger = function (typeName) { switch (typeName) { case TypeNames.UINT8: case TypeNames.UINT16: case TypeNames.UINT32: case TypeNames.UINT64: return true; default: return false; } }; var is64BitInteger = function (typeName) { return typeName === TypeNames.INT64 || typeName === TypeNames.UINT64; }; var isInteger = function (typeName) { return isSignedInteger(typeName) || isUnsignedInteger(typeName); }; var isComplex = function (typeName) { return typeName === TypeNames.COMPLEXSINGLE || typeName === TypeNames.COMPLEXDOUBLE; }; var isNumeric = function (typeName) { return isInteger(typeName) || isComplex(typeName) || isFloat(typeName); }; var isTimeStamp = function (typeName) { return typeName === TypeNames.TIMESTAMP; } var isAggregateType = function (typeName) { if (isNumeric(typeName)) { return false; } switch (typeName) { case TypeNames.VOID: case TypeNames.BOOLEAN: case TypeNames.STRING: case TypeNames.PATH: case TypeNames.TIMESTAMP: case TypeNames.DIGITALWAVEFORM: return false; } return true; }; // Validation methods var throwIfInvalidProperties = function (descriptor, propertyCount, errorMessage) { var descriptorKeys = Object.keys(descriptor); if(descriptorKeys.length !== propertyCount) { throw new Error(errorMessage); } }; var validProperties = function (descriptor, propertyCount) { var descriptorKeys = Object.keys(descriptor); return descriptorKeys.length !== propertyCount; }; var validatePrimitives = function (descriptor) { if (validProperties(descriptor, 1)) { throw new Error(descriptor.name + ' must only have the property "name".'); } }; var isValidArraySubtype = function (descriptor) { return descriptor.name !== TypeNames.ARRAY; }; var validateEnum = function (descriptor) { var subtype = descriptor.subtype; if(subtype === null || typeof subtype !== 'object') { throw new Error('Enum subtype must be a valid descriptor.'); } if(isUnsignedInteger(subtype.name) === false || is64BitInteger(subtype.name) === true) { throw new Error('Enum unsupported subtype: ' + subtype.name); } }; var validateArray = function (descriptor) { var subtype = descriptor.subtype; if (isValidArraySubtype(subtype) === false) { throw new Error('Invalid Array subtype: ' + subtype.name); } validateType(subtype); var rank = descriptor.rank; if (typeof rank !== 'number' || isNaN(rank) || rank <= 0) { throw new Error('Array type property "rank" must be an integer greater than 0.'); } var arrayFixedSize = descriptor.size; if (arrayFixedSize !== undefined) { if (Array.isArray(arrayFixedSize) === false) { throw new Error('Array type property "size" must be an array of integers.'); } var allElementsAreNumbersGreaterThanZero = arrayFixedSize.reduce(function (prev, curr){ return prev && typeof curr == 'number' && curr >= 0; }, true); if (allElementsAreNumbersGreaterThanZero === false) { throw new Error('Array type property "size" must contain only natural numbers.'); } } }; var validateCluster = function (descriptor) { var fields = descriptor.fields; var fieldTypes = descriptor.subtype; if (Array.isArray(fields) === false) { throw new Error('Cluster type must have a "fields" property of type array.'); } var allFieldsAreStrings = fields.reduce(function(prev, curr) { return prev && typeof curr === 'string'; }, true); if(allFieldsAreStrings === false) { throw new Error('Cluster type property "fields", must be an array of strings.'); } if (fieldTypes !== undefined) { if (Array.isArray(fieldTypes) === false) { throw new Error('Cluster type property "subtype" must be an array of types.'); } if (fields.length !== fieldTypes.length) { throw new Error('Cluster properties "fields" and "subtype", must be arrays with the same length.'); } var i = 0; try { for (; i < fieldTypes.length; i++) { var fieldType = fieldTypes[i]; validateType(fieldType); } } catch (e) { throw new Error('Cluster property "subtype" contains an invalid type descriptor.\n' + e.message); } } }; var validateAnalogWaveform = function (descriptor) { var subtype = descriptor.subtype; if (subtype === undefined) { throw new Error(TypeNames.ANALOGWAVEFORM + ' must have a property called "subtype".'); } if (isNumeric(subtype.name) === false) { throw new Error(TypeNames.ANALOGWAVEFORM + ' subtype only accepts numerics. ' + subtype.name + ' was found instead.'); } }; var validateType = function (descriptor) { if (descriptor !== null && typeof descriptor === 'object') { var type = descriptor.name; if (!isAggregateType(type)) { validatePrimitives(descriptor); } else { switch (type) { case TypeNames.ENUM: validateEnum(descriptor); break; case TypeNames.ARRAY: validateArray(descriptor); break; case TypeNames.CLUSTER: validateCluster(descriptor); break; case TypeNames.ANALOGWAVEFORM: validateAnalogWaveform(descriptor); break; default: throw new Error('Unknown type: ' + type); } } } else { throw new Error('Descriptor should be a JSON encoded string or a valid format Object. Value found: ' + descriptor); } }; // Short-type notation handling var wrapShortTypes = function (descriptor) { if (typeof descriptor === 'string') { return {name: descriptor}; } for(var key in descriptor) { if (descriptor.hasOwnProperty(key)) { var value = descriptor[key]; if (key === 'subtype') { if (Array.isArray(value)) { descriptor[key] = value.map(wrapShortTypes); } else { descriptor[key] = wrapShortTypes(value); } } } } return descriptor; }; var unwrapShortType = function (value) { if (value !== null && typeof value === 'object' && !isAggregateType(value.name)) { return value.name; } return value; }; var encodeShortType = function (key, value) { if (key === 'subtype' || key === '') { // Outermost key is always '' (empty string) if (Array.isArray(value)) { return value.map(unwrapShortType); } return unwrapShortType(value); } return value; }; // Equals helper methods var fieldsEqual = function (fields1, fields2) { if (Array.isArray(fields1) && Array.isArray(fields2)) { if (fields1.length !== fields2.length) { return false; } return fields1.reduce(function (pv, cv, i) { return pv && cv === fields2[i]; }, true); } return fields1 === fields2; }; var subtypesEqual = function (subtype1, subtype2) { if (subtype1 === undefined && subtype1 === subtype2) { return true; } if (subtype1 instanceof NIType && subtype2 instanceof NIType) { return subtype1.equals(subtype2); } if (Array.isArray(subtype1) && Array.isArray(subtype2)) { var areEqual = subtype1.reduce(function (pv, cv, i) { return pv && cv.equals(subtype2[i]); }, true); return areEqual; } return false; }; var ranksEqual = function (rank1, rank2) { if (rank1 === undefined && rank1 === rank2) { return true; } return rank1 === rank2; }; var sizesEqual = function (sizes1, sizes2) { if (sizes1 === undefined && sizes1 === sizes2) { return true; } if (sizes1.length !== sizes2.length) { return false; } var areAllSizesEqual = sizes1.reduce(function (pv, cv, i) { return pv && cv === sizes2[i]; }, true); return areAllSizesEqual; }; var parseDescriptor = function (descriptorValue) { var descriptor; if (typeof descriptorValue === 'string') { if (!isAggregateType(descriptorValue)) { descriptor = descriptorValue; } else { descriptor = JSON.parse(descriptorValue); } } if (descriptorValue !== null && typeof descriptorValue === 'object') { descriptor = descriptorValue; } descriptor = wrapShortTypes(descriptor); return descriptor; }; // Constructor var NIType = function (descriptorValue) { var descriptor = parseDescriptor(descriptorValue); validateType(descriptor); this._descriptor = descriptor; }; var generateTypeCheker = function (typeName) { var typeChecker = function () { return this._descriptor.name === typeName; }; try { Object.defineProperty(typeChecker, 'name', { value : 'is' + typeName }); } catch (e) { // Browser might not support this. } return typeChecker; }; var addQueries = function (typeDescriptorObject) { var proto = typeDescriptorObject.prototype; for(var key in TypeNames) { if (TypeNames.hasOwnProperty(key)) { var typeName = TypeNames[key]; var isQuery = 'is' + typeName; proto[isQuery] = generateTypeCheker(typeName); } } }; // Public instance methods var proto = NIType.prototype; addQueries(NIType); proto.toJSON = function () { return JSON.stringify(this._descriptor); }; proto.toShortJSON = function () { return JSON.stringify(this._descriptor, encodeShortType); }; proto.isNumeric = function () { return isNumeric(this._descriptor.name); }; proto.isFloat = function () { return isFloat(this._descriptor.name); }; proto.isSignedInteger = function () { return isSignedInteger(this._descriptor.name); }; proto.isUnsignedInteger = function () { return isUnsignedInteger(this._descriptor.name); }; proto.is64BitInteger = function () { return is64BitInteger(this._descriptor.name); }; proto.isInteger = function () { return isInteger(this._descriptor.name); }; proto.isComplex = function () { return isComplex(this._descriptor.name); }; proto.isTimeStamp = function () { return isTimeStamp(this._descriptor.name); } proto.isAggregateType = function() { return isAggregateType(this._descriptor.name); } proto.makeArray = function (rank, size) { if (this.isArray()) { throw new Error('Not possible to create an array from an array.'); } else { if (rank === undefined) { rank = 1; } var subtype = JSON.parse(this.toShortJSON()); return new NIType({name: TypeNames.ARRAY, rank: rank, subtype: subtype, size: size}); } }; proto.getName = function () { return this._descriptor.name; }; proto.getSubtype = function () { if (this._nisubtype !== undefined) { return this._nisubtype; } var subtype = this._descriptor.subtype; if (Array.isArray(subtype)) { this._nisubtype = subtype.map(function (v) { return new NIType(v); }); } else if (typeof subtype === 'object' && subtype !== null) { this._nisubtype = new NIType(subtype); } return this._nisubtype; }; proto.getRank = function () { return this._descriptor.rank; }; proto.getSize = function () { return this._descriptor.size; }; proto.getFields = function () { return this._descriptor.fields; }; proto.equals = function (typeDescriptor) { if (typeDescriptor instanceof NIType) { if (typeDescriptor.getName() !== this.getName()) { return false; } if (!fieldsEqual(typeDescriptor.getFields(), this.getFields())) { return false; } if (!subtypesEqual(typeDescriptor.getSubtype(), this.getSubtype())) { return false; } if (!ranksEqual(typeDescriptor.getRank(), this.getRank())) { return false; } if (!sizesEqual(typeDescriptor.getSize(), this.getSize())) { return false; } return true; } return false; }; // Exports window.NITypes = Object.freeze({ VOID: new NIType('"Void"'), BOOLEAN: new NIType('"Boolean"'), UINT8: new NIType('"UInt8"'), UINT16: new NIType('"UInt16"'), UINT32: new NIType('"UInt32"'), UINT64: new NIType('"UInt64"'), INT8: new NIType('"Int8"'), INT16: new NIType('"Int16"'), INT32: new NIType('"Int32"'), INT64: new NIType('"Int64"'), SINGLE: new NIType('"Single"'), DOUBLE: new NIType('"Double"'), COMPLEXSINGLE: new NIType('"ComplexSingle"'), COMPLEXDOUBLE: new NIType('"ComplexDouble"'), STRING: new NIType('"String"'), PATH: new NIType('"Path"'), TIMESTAMP: new NIType('"Timestamp"'), DIGITALWAVEFORM: new NIType('"DigitalWaveform"') }); window.NIType = NIType; window.NITypeNames = TypeNames; }());