transportation
Version:
Import GTFS into a semantic model
195 lines (172 loc) • 4.51 kB
JavaScript
module.exports = List
function List () {
this._generateId = List.createSequentialIdGenerator()
this._canBeArray = false
}
List.prototype.add = function addItem (element, id) {
if (element instanceof Array && !this._canBeArray) {
const ids = []
for (let i = 0; i < element.length; i++) {
ids.push(this.add(element[i]))
}
return ids
}
if (id && !this.isPossibleId(id)) {
throw new Error('ID already in use: ' + id)
}
if (typeof element.id !== 'undefined' && element.id !== null && !this.isPossibleId(element.id)) {
throw new Error('ID already in use: ' + element.id)
}
id = id || element.id || this._generateId(element)
this[id] = element
element.id = id
element._list = this
}
/**
* Call a function to each element.
* @param {Function} f
*/
List.prototype.forEach = function forEach (f) {
const self = this
this.ids.forEach(function (id) {
f(self[id], id)
})
}
List.prototype.slice = function slice () {
const self = this
return Array.prototype.slice.apply(this.ids, arguments).map(function (id) {
return self[id]
})
}
List.prototype.map = function map (f) {
const self = this
return this.ids.map(function (id) {
return f(self[id], id)
})
}
/**
* Return an array of all elements. Note that there is no predictable order.
* @return {Array} Array of elements
*/
List.prototype.toArray = function toArray () {
const elementsArray = []
this.forEach(function (element) {
elementsArray.push(element)
})
return elementsArray
}
/**
* Function to check if a ID is allowed and not already in use.
* @param {Any} id
* @return {Boolean}
*/
List.prototype.isPossibleId = function isPossibleId (id) {
if (id[0] === '_') {
return false // must not start with '_'
}
return (typeof this.id === 'undefined')
}
/**
* Removes all items of this list.
* @return {Array} list of deleted IDs
*/
List.prototype.clear = function clear () {
const self = this
const ids = []
this.ids.forEach(function (id) {
if (delete self[id]) {
ids.push(id)
}
})
return ids
}
/**
* Search for an element which satisfies the given
* function.
* @param {Function} predicate
* @return {String} ID of the found element.
*/
List.prototype.find = function findElement (predicate) {
const ids = this.ids
for (let i = 0; i < ids.length; i++) {
if (predicate(this[ids[i]])) {
return ids[i]
}
}
return false
}
/**
* Search for all elements which satisfies the given
* function.
* @param {Function} predicate
* @return {Array} of elements of Type this._type
*/
List.prototype.findAll = function findAllElements (predicate) {
return this.toArray().filter(predicate)
}
Object.defineProperty(List.prototype, 'ids', {
get: function () {
return Object.keys(this).filter(function (key) {
return key[0] !== '_'
})
}
})
Object.defineProperty(List.prototype, 'length', {
get: function () {
return this.ids.length
}
})
Object.defineProperty(List.prototype, 'idGenerator', {
set: function (idGenerator) {
if (typeof idGenerator !== 'function') {
throw new Error('ID-Generator must be a function.')
}
this._generateId = idGenerator
},
get: function () {
return this._generateId
}
})
/**
* Create a generator function which returns IDs with the given length.
* @param {Integer} length
* @return {Function} generator function
*/
List.createRandomIdGenerator = function createRandomIdGenerator (length) {
return function () {
return generateRandomId(length)
}
}
/**
* Generate an alphanumeric ID with the given length.
* @param {Integer} length
* @return {String} ID
*/
function generateRandomId (length) {
let str = ''
length = length || 6
while (str.length < length) {
str += (((1 + Math.random()) * 0x10000) | 0).toString(16)
}
return str.substring(str.length - length, str.length)
}
List.generateRandomId = generateRandomId
/**
* Create a generator function which returns a sequential numeric ID.
* @return {Function} generator function
*/
List.createSequentialIdGenerator = function createSequentialIdGenerator () {
return function () {
return List.generateSequentialId.call(this)
}
}
/**
* Generate a sequential ID depending on the current `this._lastId`.
* @return {Integer} ID
*/
List.generateSequentialId = function generateSequentialId () {
const prevId = this._lastId || 0
const nextId = prevId + 1
this._lastId = nextId
return nextId
}