diff --git a/src/fields.js b/src/fields.js deleted file mode 100644 index 3639c6a..0000000 --- a/src/fields.js +++ /dev/null @@ -1,82 +0,0 @@ -const schema = require("./schema"); -const debug = require("debug")("passkit:fields"); - -/** - * Class to represent lower-level keys pass fields - * @see https://apple.co/2wkUBdh - */ - -let uniqueKeys = []; - -class FieldsContainer { - constructor() { - this.fields = []; - } - - /** - * A wrapper of Array.prototype.push to validate the pushed content with the schema. - * Accepts also one array of objects. - * - * @method push - * @params {Object[]} fields - the fields to be checked and pushed - * @params {schema.field} fields[].* - each key must be compliant with schema.field structure - * @returns {Number} - the amount of pushed elements (for checks) - */ - - push(...fieldsData) { - if (fieldsData[0] instanceof Array && fieldsData[0].length) { - fieldsData = fieldsData[0]; - } - - let validFields = fieldsData.reduce((acc, current) => { - if (!(typeof current === "object") || !schema.isValid(current, "field")) { - return acc; - } - - if (acc.some(e => e.key === current.key) || uniqueKeys.includes(current.key)) { - debug(`UNIQUE field key CONSTRAINT VIOLATED. Fields keys must be unique in pass scope. Field key: "${current.key}"`); - return acc; - } - - acc.push(current); - return acc; - }, []); - - uniqueKeys.push(...validFields.map(v => v.key)); - this.fields.push(...validFields); - - return validFields.length; - } - - /** - * A wrapper of Array.prototype.pop and Array.prototype.slice to pop - * last element or n elements starting from the end. - * - * @method pop - * @params {Number} [quantity=-1] - the amount of elements to be removed - * @returns {Number} - the amount of removed elements - */ - - pop(amount = -1) { - if (!this.fields.length) { - return undefined; - } - - if (amount > -1) { - let removedElements = this.fields.slice(amount); - this.fields = this.fields.slice(0, this.fields.length - amount); - this._uniqueKeys = this._uniqueKeys.slice(0, this._uniqueKeys - amount); - - return removedElements; - } - - this._uniqueKeys.pop(); - return this.fields.pop(); - } - - static emptyUnique() { - uniqueKeys = []; - } -} - -module.exports = FieldsContainer; diff --git a/src/fieldsArray.js b/src/fieldsArray.js new file mode 100644 index 0000000..dfa2031 --- /dev/null +++ b/src/fieldsArray.js @@ -0,0 +1,72 @@ +const schema = require("./schema"); +const debug = require("debug")("passkit:fields"); + +/** + * Class to represent lower-level keys pass fields + * @see https://apple.co/2wkUBdh + */ + +const uniqueKeys = new Set(); + +class FieldsArray extends Array { + constructor(...items) { + super(...items); + } + + /** + * Like `Array.prototype.push` but will alter + * also uniqueKeys set. + */ + + push(...fieldsData) { + let validFields = fieldsData.reduce((acc, current) => { + if (!(typeof current === "object") || !schema.isValid(current, "field")) { + return acc; + } + + if (acc.some(e => e.key === current.key) || uniqueKeys.has(current.key)) { + debug(`UNIQUE field key CONSTRAINT VIOLATED. Fields keys must be unique in pass scope. Field key: "${current.key}"`); + } else { + uniqueKeys.add(current.key); + acc.push(current); + } + + return acc; + }, []); + + return Array.prototype.push.call(this, ...validFields); + } + + /** + * Like `Array.prototype.pop`, but will alter + * also uniqueKeys set + */ + + pop() { + const element = Array.prototype.pop.call(this); + uniqueKeys.delete(element.key); + return element; + } + + /** + * Like `Array.prototype.splice` but will alter + * also uniqueKeys set + */ + + splice(start, deleteCount, ...items) { + let removeList = this.slice(start, deleteCount+start); + removeList.forEach(item => uniqueKeys.delete(item.key)); + + return Array.prototype.splice.call(this, start, deleteCount, items); + } + + get length() { + return this.length; + } + + static emptyUnique() { + uniqueKeys.clear(); + } +} + +module.exports = FieldsArray; diff --git a/src/pass.js b/src/pass.js index 7de2422..df6d684 100644 --- a/src/pass.js +++ b/src/pass.js @@ -14,7 +14,7 @@ const loadDebug = debug("passkit:load"); const schema = require("./schema"); const formatMessage = require("./messages"); -const FieldsContainer = require("./fields"); +const FieldsArray = require("./fieldsArray"); const readdir = promisify(fs.readdir); const readFile = promisify(fs.readFile); @@ -37,7 +37,7 @@ class Pass { this._fields = ["primaryFields", "secondaryFields", "auxiliaryFields", "backFields", "headerFields"]; - this._fields.forEach(a => this[a] = new FieldsContainer()); + this._fields.forEach(a => this[a] = new FieldsArray()); this._transitType = ""; // Assigning model and _props to this @@ -212,7 +212,7 @@ class Pass { archive.pipe(passStream); - FieldsContainer.emptyUnique(); + FieldsArray.emptyUnique(); return archive.finalize().then(() => passStream); }); @@ -633,11 +633,11 @@ class Pass { } this._fields.forEach(area => { - if (this[area].fields.length) { + if (this[area].length) { if (this.shouldOverwrite) { - passFile[this.type][area] = this[area].fields; + passFile[this.type][area] = [...this[area]]; } else { - passFile[this.type][area].push(...this[area].fields); + passFile[this.type][area].push(...this[area]); } } });