New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

structurae

Package Overview
Dependencies
Maintainers
1
Versions
75
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

structurae - npm Package Compare versions

Comparing version 3.2.0 to 3.3.0

lib/variable-view.js

3

CHANGELOG.md

@@ -7,2 +7,5 @@ # Changelog

## [3.3.0] - 2020-07-14
- Add VectorView
## [3.2.0] - 2020-07-09

@@ -9,0 +12,0 @@ - Support required fields and default values in MapView.

@@ -281,3 +281,3 @@ // Type definitions for structurae

static littleEndian: true;
static objectLength: number;
static viewLength: number;
static Views: Map<string, typeof TypeView>;

@@ -322,2 +322,3 @@ static ArrayClass: typeof ArrayView;

static getLength(size: number): number;
static getOffset(size: number): number;
static getSize(length: number): number;

@@ -369,3 +370,3 @@ }

static types: ObjectViewTypeDefs;
static objectLength: number;
static viewLength: number;
private static defaultBuffer: ArrayBuffer;

@@ -396,4 +397,2 @@

static masks: Int8Array;
static encoder: TextEncoder;
static decoder: TextDecoder;
static ArrayClass: typeof ArrayView;

@@ -415,8 +414,23 @@

trim(): StringView;
static decode(bytes: Uint8Array): string;
static encode(
string: string,
view: number[] | Uint8Array | DataView,
start?: number,
length?: number,
): number;
static from(...args: any[]): View;
static toJSON(view: View, start?: number, length?: number): string;
static getByteSize(string: string): number;
static getLength(string: string): number;
}
export declare class MapView extends DataView {
export declare class VariableView extends DataView {
static maxLength: number;
static maxView: DataView;
static bufferView: DataView;
}
type AnyView = View | VariableView;
export declare class MapView extends VariableView {
static schema: object;

@@ -431,7 +445,5 @@ static layout: ViewLayout;

static Views: ViewTypes;
static maxLength: number;
static maxView: DataView;
get(field: string): any;
getView(field: string): View;
getView(field: string): AnyView;
private getLayout(field: string): [ViewType, number, number];

@@ -441,4 +453,5 @@ set(field: string, value: any): this;

toJSON(): object;
static from(value: object, view?: View, start?: number): View;
static toJSON(view: View, start?: number): object;
static encode(value: object, view: AnyView, start?: number): number;
static from(value: object, view?: AnyView, start?: number): View;
static toJSON(view: AnyView, start?: number): object;
static getLength(value: any): number;

@@ -460,2 +473,25 @@ static initialize(): void;

export declare class VectorView extends VariableView {
static View: ViewType | typeof VariableView;
static Views: WeakMap<ViewType | typeof VariableView, typeof VectorView>;
get(index: number): any;
getView(index: number): AnyView;
private getLayout(index: number): [number, number];
set(index: number, value: any): this;
setView(index: number, value: AnyView): this;
toJSON(): any[];
[Symbol.iterator](): IterableIterator<AnyView>;
static encode(value: ArrayLike<any>, view: AnyView, start?: number): number;
static from(value: ArrayLike<any>, view?: AnyView, start?: number): AnyView;
static toJSON(view: AnyView, start?: number, length?: number): any[];
static getLength(value: any[]): number;
static getSize(view: AnyView): number;
}
export declare function VectorViewMixin(
ViewClass: ViewType | typeof VariableView,
VectorViewClass?: typeof VectorView,
): typeof VectorView;
interface BinaryProtocolSchema {

@@ -462,0 +498,0 @@ [propName: number]: typeof ObjectView;

@@ -25,2 +25,4 @@ const BitField = require('./lib/bit-field');

const BooleanView = require('./lib/boolean-view');
const VariableView = require('./lib/variable-view');
const { VectorView, VectorViewMixin } = require('./lib/vector-view');

@@ -70,2 +72,5 @@ /**

BooleanView,
VariableView,
VectorView,
VectorViewMixin,
};

2

lib/array-view-mixin.js

@@ -24,3 +24,3 @@ const ArrayView = require('./array-view');

View.View = ViewClass;
View.itemLength = ViewClass.objectLength || itemLength;
View.itemLength = ViewClass.viewLength || itemLength;
if (typeof itemLength !== 'number') ArrayViews.set(ViewClass, View);

@@ -27,0 +27,0 @@ return View;

@@ -16,3 +16,3 @@ /**

const { View } = this.constructor;
const offset = this.constructor.getLength(index);
const offset = this.constructor.getOffset(index);
return View.toJSON(this, offset);

@@ -28,4 +28,4 @@ }

getView(index) {
const { itemLength, View } = this.constructor;
const offset = this.constructor.getLength(index);
const { View, itemLength } = this.constructor;
const offset = this.constructor.getOffset(index);
return new View(this.buffer, this.byteOffset + offset, itemLength);

@@ -42,4 +42,4 @@ }

set(index, value) {
const { itemLength, View } = this.constructor;
const offset = this.constructor.getLength(index);
const { View, itemLength } = this.constructor;
const offset = this.constructor.getOffset(index);
View.from(value, this, this.byteOffset + offset, itemLength);

@@ -58,3 +58,3 @@ return this;

const { itemLength } = this.constructor;
const offset = this.constructor.getLength(index);
const offset = this.constructor.getOffset(index);
new Uint8Array(this.buffer, this.byteOffset + offset, itemLength).set(

@@ -105,3 +105,3 @@ new Uint8Array(value.buffer, value.byteOffset, value.byteLength),

*/
static from(value, array, start = 0, length = this.getLength(value.length)) {
static from(value, array, start = 0, length = this.getOffset(value.length)) {
const view = array || this.of(value.length);

@@ -113,3 +113,3 @@ new Uint8Array(view.buffer, view.byteOffset + start, length).fill(0);

for (let i = 0; i < max; i++) {
const offset = this.getLength(i);
const offset = this.getOffset(i);
View.from(value[i], view, start + offset, itemLength);

@@ -121,28 +121,19 @@ }

/**
* Returns an array representation of a given array view.
* Returns the byte length of an array view to hold a given amount of objects.
*
* @param {View} view
* @param {number} [start=0]
* @param {number} [length]
* @returns {Object}
* @param {number} size
* @returns {number}
*/
static toJSON(view, start, length) {
const { View, itemLength } = this;
const size = this.getSize(length);
const array = new Array(size);
for (let i = 0; i < size; i++) {
const offset = this.getLength(i);
array[i] = View.toJSON(view, start + offset, itemLength);
}
return array;
static getLength(size) {
return this.getOffset(size);
}
/**
* Returns the byte length of an array view to hold a given amount of objects.
* Returns the starting byte offset of an item in the array.
*
* @param {number} size
* @param {number} index
* @returns {number}
*/
static getLength(size) {
return (size * this.itemLength) | 0;
static getOffset(index) {
return (index * this.itemLength) | 0;
}

@@ -161,2 +152,21 @@

/**
* Returns an array representation of a given array view.
*
* @param {View} view
* @param {number} [start=0]
* @param {number} [length]
* @returns {Object}
*/
static toJSON(view, start, length) {
const { View, itemLength } = this;
const size = this.getSize(length);
const array = new Array(size);
for (let i = 0; i < size; i++) {
const offset = this.getOffset(i);
array[i] = View.toJSON(view, start + offset, itemLength);
}
return array;
}
/**
* Creates an empty array view of specified size.

@@ -168,3 +178,3 @@ *

static of(size = 1) {
const buffer = new ArrayBuffer(this.getLength(size));
const buffer = new ArrayBuffer(this.getOffset(size));
return new this(buffer);

@@ -171,0 +181,0 @@ }

@@ -85,3 +85,3 @@ const { ObjectView, ObjectViewMixin } = require('./object-view');

if (!View) throw TypeError('No tag information is found.');
return new View(buffer, offset, View.objectLength);
return new View(buffer, offset, View.viewLength);
}

@@ -100,4 +100,4 @@

if (!View) throw TypeError('No tag information is found.');
const buffer = arrayBuffer || new ArrayBuffer(View.objectLength);
const view = new View(buffer, offset, View.objectLength);
const buffer = arrayBuffer || new ArrayBuffer(View.viewLength);
const view = new View(buffer, offset, View.viewLength);
View.from(object, view);

@@ -104,0 +104,0 @@ return view;

@@ -0,10 +1,10 @@

const VariableView = require('./variable-view');
const { ObjectView, ObjectViewMixin } = require('./object-view');
const StringView = require('./string-view');
const ArrayViewMixin = require('./array-view-mixin');
const { writeUTF8 } = require('./utilities');
const { VectorViewMixin } = require('./vector-view');
/**
* @extends DataView
* @extends {VariableView}
*/
class MapView extends DataView {
class MapView extends VariableView {
/**

@@ -99,12 +99,7 @@ * Returns the JavaScript value at a given field.

* @param {Object} value the object to take data from
* @param {View} [view] the view to assign fields to
* @param {View} view the view to assign fields to
* @param {number} [start=0]
* @returns {View}
* @returns {number}
*/
static from(value, view, start = 0) {
const mapView = view || this.bufferView;
const mapArray = new Uint8Array(mapView.buffer, mapView.byteOffset);
if (this.defaultBuffer) {
mapArray.set(this.defaultBuffer, start);
}
static encode(value, view, start = 0) {
const { layout, requiredFields, optionalFields, lengthOffset } = this;

@@ -116,3 +111,3 @@ for (let i = 0; i < requiredFields.length; i++) {

const { View, length: maxLength, start: fieldStart } = layout[field];
View.from(fieldValue, mapView, start + fieldStart, maxLength);
View.from(fieldValue, view, start + fieldStart, maxLength);
}

@@ -128,18 +123,32 @@ }

const caret = start + end;
if (View === StringView) {
fieldLength = writeUTF8(fieldValue, mapArray, caret);
} else if (View.prototype instanceof MapView) {
View.from(fieldValue, mapView, caret);
const fieldEnd = caret + View.lengthOffset;
fieldLength = mapView.getUint32(fieldEnd, true);
if (View.viewLength || View.itemLength) {
fieldLength = View.getLength(fieldValue.length || 1);
View.from(fieldValue, view, caret, fieldLength);
} else {
fieldLength = View.getLength(fieldValue.length || 1);
View.from(fieldValue, mapView, caret, fieldLength);
fieldLength = View.encode(fieldValue, view, caret);
}
fieldLength = Math.min(fieldLength, maxLength);
}
mapView.setUint32(start + fieldStart, end, true);
view.setUint32(start + fieldStart, end, true);
end += fieldLength;
}
mapView.setUint32(start + lengthOffset, end, true);
view.setUint32(start + lengthOffset, end, true);
return end;
}
/**
* Creates a map view from a given object.
*
* @param {Object} value the object to take data from
* @param {View} [view] the view to assign fields to
* @param {number} [start=0]
* @returns {View}
*/
static from(value, view, start = 0) {
const mapView = view || this.bufferView;
const mapArray = new Uint8Array(mapView.buffer, mapView.byteOffset);
if (this.defaultBuffer) {
mapArray.set(this.defaultBuffer, start);
}
const end = this.encode(value, mapView, start);
return view || new this(mapView.buffer.slice(0, end));

@@ -163,8 +172,8 @@ }

const { View, length: maxLength } = layout[field];
if (View.prototype instanceof MapView) {
if (View.viewLength) {
fieldLength = View.viewLength;
} else if (View.itemLength) {
fieldLength = View.getLength(fieldValue.length);
} else {
fieldLength = View.getLength(fieldValue);
} else if (View.getByteSize) {
fieldLength = View.getByteSize(fieldValue);
} else {
fieldLength = View.getLength(fieldValue.length || 1);
}

@@ -213,2 +222,3 @@ length += Math.min(fieldLength, maxLength);

if (objects[i].btype === 'map') {
// eslint-disable-next-line no-use-before-define
MapViewMixin(objects[i], this, ObjectViewClass);

@@ -227,3 +237,3 @@ } else {

const field = schema.properties[property];
const fieldLayout = this.getFieldLayout(field, offset, true);
const fieldLayout = this.getFieldLayout(field, offset, true, property);
layout[property] = fieldLayout;

@@ -236,3 +246,3 @@ offset += fieldLayout.length;

const field = schema.properties[property];
layout[property] = this.getFieldLayout(field, offset + (i << 2), false);
layout[property] = this.getFieldLayout(field, offset + (i << 2), false, property);
}

@@ -243,3 +253,5 @@ this.lengthOffset = offset + (optional.length << 2);

this.optionalFields = optional;
if (offset) this.setDefaultBuffer();
if (offset) {
this.defaultBuffer = ObjectViewClass.getDefaultBuffer.call(this, offset, required, layout);
}
}

@@ -252,5 +264,6 @@

* @param {boolean} required
* @param {string} name
* @returns {Object}
*/
static getFieldLayout(field, start, required) {
static getFieldLayout(field, start, required, name) {
let currentField = field;

@@ -265,15 +278,20 @@ let View;

} else {
const sizes = [];
const arrays = [];
while (currentField && currentField.type === 'array') {
sizes.push(currentField.maxItems);
arrays.push(currentField);
currentField = currentField.items;
}
View = ArrayViewMixin(
this.ObjectViewClass.getViewFromSchema(currentField),
currentField.maxLength,
);
let itemLength = View.getLength(sizes.pop());
for (let j = sizes.length - 1; j >= 0; j--) {
View = ArrayViewMixin(View, itemLength);
itemLength = View.getLength(sizes[j]);
let currentArray = arrays.pop();
const isArray = currentArray.btype !== 'vector';
View = this.ObjectViewClass.getViewFromSchema(currentField);
View = isArray ? ArrayViewMixin(View, currentField.maxLength) : VectorViewMixin(View);
let itemLength = isArray ? View.getLength(currentArray.maxItems) : 0;
for (let j = arrays.length - 1; j >= 0; j--) {
currentArray = arrays[j];
if (currentArray.btype === 'vector') {
View = VectorViewMixin(View);
} else {
View = ArrayViewMixin(View, itemLength);
itemLength = View.getLength(currentArray.maxItems);
}
}

@@ -284,3 +302,3 @@ length = itemLength;

if (required && length === Infinity)
throw new TypeError('The length of a required field is undefined.');
throw new TypeError(`The length of a required field "${name}" is undefined.`);
const layout = { View, start, length, required };

@@ -290,31 +308,2 @@ if (Reflect.has(field, 'default')) layout.default = field.default;

}
/**
* @private
* @returns {void}
*/
static setDefaultBuffer() {
const { requiredFields, layout, optionalOffset } = this;
const buffer = new ArrayBuffer(optionalOffset);
const array = new Uint8Array(buffer);
const view = new this(buffer);
for (let i = 0; i < requiredFields.length; i++) {
const name = requiredFields[i];
const field = layout[name];
if (Reflect.has(field, 'default')) {
view.set(name, field.default);
} else if (field.View.defaultBuffer) {
array.set(new Uint8Array(field.View.defaultBuffer), field.start);
}
}
this.defaultBuffer = array;
}
/**
* @type {DataView}
*/
static get bufferView() {
if (!this.maxView) this.maxView = new DataView(new ArrayBuffer(this.maxLength));
return this.maxView;
}
}

@@ -368,13 +357,2 @@

/**
* @type {number} Maximum possible size of a map.
*/
MapView.maxLength = 8192;
/**
* @protected
* @type {DataView}
*/
MapView.maxView = undefined;
/**
* Creates a MapView class with a given schema.

@@ -381,0 +359,0 @@ *

@@ -99,4 +99,4 @@ const StringView = require('./string-view');

*/
static from(object, view, start = 0, length = this.objectLength) {
const objectView = view || new this(this.defaultBuffer.slice());
static from(object, view, start = 0, length = this.viewLength) {
const objectView = view || new this(this.defaultBuffer.buffer.slice());
if (view) new Uint8Array(view.buffer, view.byteOffset + start, length).fill(0);

@@ -134,7 +134,14 @@ const { fields, layout } = this;

* @private
* @returns {void}
* @param {number} viewLength
* @param {Array<string>} fields
* @param {Object<string, ViewLayoutField>} layout
* @returns {Uint8Array}
*/
static setDefaultBuffer() {
const { objectLength, fields, layout } = this;
const buffer = new ArrayBuffer(objectLength);
static getDefaultBuffer(
viewLength = this.viewLength,
fields = this.fields,
layout = this.layout,
) {
const buffer = new ArrayBuffer(viewLength);
const array = new Uint8Array(buffer);
const view = new this(buffer);

@@ -147,6 +154,6 @@ for (let i = 0; i < fields.length; i++) {

} else if (field.View.defaultBuffer) {
new Uint8Array(buffer).set(new Uint8Array(field.View.defaultBuffer), field.start);
array.set(new Uint8Array(field.View.defaultBuffer), field.start);
}
}
this.defaultBuffer = buffer;
return array;
}

@@ -160,3 +167,3 @@

static getLength() {
return this.objectLength;
return this.viewLength;
}

@@ -178,5 +185,5 @@

const View = i === 0 ? this : class extends ParentViewClass {};
[View.layout, View.objectLength, View.fields] = this.getLayoutFromSchema(objectSchema);
[View.layout, View.viewLength, View.fields] = this.getLayoutFromSchema(objectSchema);
ObjectView.Views[id] = View;
View.setDefaultBuffer();
View.defaultBuffer = View.getDefaultBuffer();
}

@@ -341,4 +348,3 @@ }

/**
* @private
* @type {Object<string, ViewLayoutField>}
* @private {Object<string, ViewLayoutField>}
*/

@@ -351,4 +357,3 @@ ObjectView.layout = undefined;

/**
* @private
* @type {Array<string>}
* @private {Array<string>}
*/

@@ -358,10 +363,8 @@ ObjectView.fields = undefined;

/**
* @private
* @type {number}
* @private {number}
*/
ObjectView.objectLength = 0;
ObjectView.viewLength = 0;
/**
* @private
* @type {ArrayBuffer}
* @private {Uint8Array}
*/

@@ -368,0 +371,0 @@ ObjectView.defaultBuffer = undefined;

const ArrayView = require('./array-view');
const { UTF8ToString, stringToUTF8 } = require('./utilities');

@@ -290,3 +289,3 @@ /**

toString() {
return UTF8ToString(this);
return this.constructor.decode(this);
}

@@ -298,3 +297,3 @@

toJSON() {
return this.toString();
return this.constructor.decode(this);
}

@@ -319,2 +318,95 @@

/**
* Converts a UTF8 byte array into a JS string.
* Shamelessly stolen from Google Closure:
* https://github.com/google/closure-library/blob/master/closure/goog/crypt/crypt.js
*
* @param {Uint8Array} bytes
* @returns {string}
*/
static decode(bytes) {
const out = [];
let pos = 0;
let c = 0;
while (pos < bytes.length) {
const c1 = bytes[pos++];
// bail on zero byte
if (c1 === 0) break;
if (c1 < 128) {
out[c++] = String.fromCharCode(c1);
} else if (c1 > 191 && c1 < 224) {
out[c++] = String.fromCharCode(((c1 & 31) << 6) | (bytes[pos++] & 63));
} else if (c1 > 239 && c1 < 365) {
// Surrogate Pair
const u =
(((c1 & 7) << 18) |
((bytes[pos++] & 63) << 12) |
((bytes[pos++] & 63) << 6) |
(bytes[pos++] & 63)) -
0x10000;
out[c++] = String.fromCharCode(0xd800 + (u >> 10));
out[c++] = String.fromCharCode(0xdc00 + (u & 1023));
} else {
out[c++] = String.fromCharCode(
((c1 & 15) << 12) | ((bytes[pos++] & 63) << 6) | (bytes[pos++] & 63),
);
}
}
return out.join('');
}
/**
* Converts a JS string into a UTF8 byte array.
* Shamelessly stolen from Google Closure:
* https://github.com/google/closure-library/blob/master/closure/goog/crypt/crypt.js
*
* TODO: use TextEncoder#encode/encodeInto when the following issues are resolved:
* - https://bugs.chromium.org/p/v8/issues/detail?id=4383
* - https://bugs.webkit.org/show_bug.cgi?id=193274
*
* @param {string} string
* @param {Array|Uint8Array} view
* @param {number} [start=0]
* @param {number} [length]
* @returns {number}
*/
static encode(string, view, start = 0, length) {
const bytes =
view instanceof DataView
? new Uint8Array(view.buffer, view.byteOffset + start, length || view.byteLength - start)
: view;
let p = 0;
for (let i = 0; i < string.length; i++) {
let c = string.charCodeAt(i);
if (c < 128) {
bytes[p++] = c;
} else if (c < 2048) {
bytes[p++] = (c >> 6) | 192;
bytes[p++] = (c & 63) | 128;
} else if (
(c & 0xfc00) === 0xd800 &&
i + 1 < string.length &&
(string.charCodeAt(i + 1) & 0xfc00) === 0xdc00
) {
// Surrogate Pair
c = 0x10000 + ((c & 0x03ff) << 10) + (string.charCodeAt(++i) & 0x03ff);
bytes[p++] = (c >> 18) | 240;
bytes[p++] = ((c >> 12) & 63) | 128;
bytes[p++] = ((c >> 6) & 63) | 128;
bytes[p++] = (c & 63) | 128;
} else {
bytes[p++] = (c >> 12) | 224;
bytes[p++] = ((c >> 6) & 63) | 128;
bytes[p++] = (c & 63) | 128;
}
}
if (!length) return p;
// zero out remaining bytes
while (p < length) {
bytes[p++] = 0;
}
return p;
}
/**
* Creates a StringView from a string or an array like object.

@@ -330,5 +422,8 @@

// no view is supplied
if (!view) return new this(stringToUTF8(value));
const array = new Uint8Array(view.buffer, view.byteOffset + start, length || view.byteLength);
stringToUTF8(value, array);
if (!view) {
const array = [];
this.encode(value, array);
return new this(array);
}
this.encode(value, view, start, length);
return view;

@@ -343,9 +438,19 @@ }

* @param {length} [length]
* @returns {Array<number>}
* @returns {string}
*/
static toJSON(view, start = 0, length) {
return new this(view.buffer, view.byteOffset + start, length).toString();
return this.decode(new this(view.buffer, view.byteOffset + start, length));
}
/* istanbul ignore next */
/**
* @deprecated Use String.getLength instead.
* @param {string} string
* @returns {number}
*/
static getByteSize(string) {
return this.getLength(string);
}
/**
* Returns the size in bytes of a given string without encoding it.

@@ -359,3 +464,3 @@ *

*/
static getByteSize(string) {
static getLength(string) {
let size = 0;

@@ -387,2 +492,3 @@ for (let i = 0; i < string.length; i++) {

/**
* @deprecated
* @type TextEncoder

@@ -393,2 +499,3 @@ */

/**
* @deprecated
* @type TextDecoder

@@ -395,0 +502,0 @@ */

@@ -43,3 +43,3 @@ const { typeGetters, typeSetters, typeOffsets } = require('./utilities');

static getLength() {
return this.objectLength;
return this.viewLength;
}

@@ -67,3 +67,3 @@

static of() {
return new this(new ArrayBuffer(this.objectLength));
return new this(new ArrayBuffer(this.viewLength));
}

@@ -100,3 +100,3 @@

*/
TypeView.objectLength = 1;
TypeView.viewLength = 1;

@@ -128,3 +128,3 @@ /**

View.littleEndian = !!littleEndian;
View.objectLength = 1 << View.offset;
View.viewLength = 1 << View.offset;
TypeViews.set(classId, View);

@@ -131,0 +131,0 @@ return View;

@@ -10,14 +10,2 @@ const ArrayView = require('./array-view');

/**
* Returns a number at a given index.
*
* @param {number} index
* @returns {number}
*/
get(index) {
const { View } = this.constructor;
const offset = this.constructor.getLength(index);
return View.toJSON(this, offset);
}
/**
* Allows iterating over objects views stored in the array.

@@ -35,9 +23,9 @@ *

/**
* Returns the byte length of an array view to hold a given amount of numbers.
* Returns the starting byte offset of an item in the array.
*
* @param {number} size
* @param {number} index
* @returns {number}
*/
static getLength(size) {
return size << this.View.offset;
static getOffset(index) {
return index << this.View.offset;
}

@@ -44,0 +32,0 @@

@@ -125,96 +125,2 @@ const BigInt = globalThis.BigInt || Number;

/**
* Converts a JS string into a UTF8 byte array.
* Shamelessly stolen from Google Closure:
* https://github.com/google/closure-library/blob/master/closure/goog/crypt/crypt.js
*
* TODO: use TextEncoder#encode/encodeInto when the following issues are resolved:
* - https://bugs.chromium.org/p/v8/issues/detail?id=4383
* - https://bugs.webkit.org/show_bug.cgi?id=193274
*
* @param {string} string
* @param {Array|Uint8Array} bytes
* @param {number} start
* @returns {number}
*/
function writeUTF8(string, bytes, start = 0) {
let p = start;
for (let i = 0; i < string.length; i++) {
let c = string.charCodeAt(i);
if (c < 128) {
bytes[p++] = c;
} else if (c < 2048) {
bytes[p++] = (c >> 6) | 192;
bytes[p++] = (c & 63) | 128;
} else if (
(c & 0xfc00) === 0xd800 &&
i + 1 < string.length &&
(string.charCodeAt(i + 1) & 0xfc00) === 0xdc00
) {
// Surrogate Pair
c = 0x10000 + ((c & 0x03ff) << 10) + (string.charCodeAt(++i) & 0x03ff);
bytes[p++] = (c >> 18) | 240;
bytes[p++] = ((c >> 12) & 63) | 128;
bytes[p++] = ((c >> 6) & 63) | 128;
bytes[p++] = (c & 63) | 128;
} else {
bytes[p++] = (c >> 12) | 224;
bytes[p++] = ((c >> 6) & 63) | 128;
bytes[p++] = (c & 63) | 128;
}
}
return p;
}
/**
* @param {string} string
* @param {Array|Uint8Array} bytes
* @returns {Array|Uint8Array}
*/
function stringToUTF8(string, bytes = []) {
let length = writeUTF8(string, bytes);
// zero out remaining bytes
while (length < bytes.length) {
bytes[length++] = 0;
}
return bytes;
}
/**
* Converts a UTF8 byte array into a JS string.
*
* @param {Uint8Array} bytes
* @returns {string}
*/
function UTF8ToString(bytes) {
const out = [];
let pos = 0;
let c = 0;
while (pos < bytes.length) {
const c1 = bytes[pos++];
// bail on zero byte
if (c1 === 0) break;
if (c1 < 128) {
out[c++] = String.fromCharCode(c1);
} else if (c1 > 191 && c1 < 224) {
out[c++] = String.fromCharCode(((c1 & 31) << 6) | (bytes[pos++] & 63));
} else if (c1 > 239 && c1 < 365) {
// Surrogate Pair
const u =
(((c1 & 7) << 18) |
((bytes[pos++] & 63) << 12) |
((bytes[pos++] & 63) << 6) |
(bytes[pos++] & 63)) -
0x10000;
out[c++] = String.fromCharCode(0xd800 + (u >> 10));
out[c++] = String.fromCharCode(0xdc00 + (u & 1023));
} else {
out[c++] = String.fromCharCode(
((c1 & 15) << 12) | ((bytes[pos++] & 63) << 6) | (bytes[pos++] & 63),
);
}
}
return out.join('');
}
module.exports = {

@@ -228,5 +134,2 @@ log2,

typeOffsets,
stringToUTF8,
writeUTF8,
UTF8ToString,
};
{
"name": "structurae",
"version": "3.2.0",
"version": "3.3.0",
"description": "Data structures for performance-sensitive modern JavaScript applications.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -12,2 +12,3 @@ # Structurae

- [MapView](https://github.com/zandaqo/structurae#MapView) - ObjectView with optional fields and fields of varying sizes.
- [VectorView](https://github.com/zandaqo/structurae#VectorView) - ArrayView that supports optional and variable length elements, including MapViews.
- [StringView](https://github.com/zandaqo/structurae#StringView) - extends Uint8Array to handle C-like representation of UTF-8 encoded strings.

@@ -319,2 +320,9 @@ - [BinaryProtocol](https://github.com/zandaqo/structurae#BinaryProtocol) - a helper class that simplifies defining and operating on multiple tagged ObjectViews.

},
names: {
type: 'array',
// uses VectorView for an array of variable length elements
// if btype is set to vector
btype: 'vector',
items: { type: 'string' },
},
},

@@ -337,3 +345,3 @@ // required fields are always present and can have default values

// create a person with no pets
const person0 = PersonWithPets.from({ id: 1, name: 'Artur'});
const person0 = Person.from({ id: 1, name: 'Artur'});
person0.byteLength;

@@ -346,7 +354,43 @@ //=> 18

//=> undefined
const person2 = Person.from({ names: ['Arthur', 'Dent', '', 'Arthur Dent']})
person2.toJSON();
//=> { id: 10, names: ['Arthur', 'Dent', undefined, 'Arthur Dent']}
```
For performance reasons, MapView uses a single buffer for serialization, thus, limiting the maximum size of a view.
By default the size is 8192 bytes, if you expect bigger views, please set the desired size in `MapView.maxLength`.
The buffer is inherited from `VariableView` class and the default is 8192 bytes, if you expect bigger views, please set the desired size in `VariableView.maxLength`.
#### VectorView
VectorView is an ArrayView that supports optional elements (i.e. `undefined`) and elements of variable length, such as MapView or StringView.
VectorView stores offsets inside the view itself resulting in an overhead of 4 * (_n_ + 2) bytes where _n_ is the number of elements in the view.
Like MapView, VectorView has limited editablity: the layout of an instance is calculated once upon creation,
hence, setting absent elements or resizing existing elements is not possible.
```javascript
const { MapViewMixin, VectorViewMixin, TypeViewMixin } = require('structurae');
const SparseArrayView = VectorViewMixin(TypeViewMixin('uint8'));
SparseArrayView.from([1, , 2, null]).toJSON();
//=> [1, undefined, 2, undefined]
const MapVector = VectorViewMixin(MapViewMixin({
$id: 'SomeMap',
btype: 'map',
properties: {
id: { type: 'integer' },
name: { type: 'string' },
},
}));
const mapVector = MapVector.from([{ id: 1 }, null, { name: 'abc'}]);
mapVector.size;
//=> 3
mapVector.get(0);
//=> { id: 1 };
mapVector.toJSON();
//=> [{ id: 1 }, undefined, { name: 'abc'}]
```
Like MapView, VectorView uses for serialization the default buffer inherited from `VariableView`, if you expect your
vectors to exceed the default 8192 bytes in length, please set the desired maximum length in `VariableView.maxLength`.
#### StringView

@@ -353,0 +397,0 @@ Encoding API (available both in modern browsers and Node.js) allows us to convert JavaScript strings to

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