collect-your-stuff 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +802 -77
  2. package/dist/collections/arrayable/ArrayElement.d.ts +2 -0
  3. package/dist/collections/arrayable/ArrayElement.js +4 -2
  4. package/dist/collections/arrayable/ArrayElement.min.js +1 -1
  5. package/dist/collections/arrayable/Arrayable.d.ts +27 -13
  6. package/dist/collections/arrayable/Arrayable.js +47 -12
  7. package/dist/collections/arrayable/Arrayable.min.js +1 -1
  8. package/dist/collections/doubly-linked-list/DoubleLinker.d.ts +5 -1
  9. package/dist/collections/doubly-linked-list/DoubleLinker.js +5 -1
  10. package/dist/collections/doubly-linked-list/DoublyLinkedList.d.ts +25 -13
  11. package/dist/collections/doubly-linked-list/DoublyLinkedList.js +106 -53
  12. package/dist/collections/doubly-linked-list/DoublyLinkedList.min.js +1 -1
  13. package/dist/collections/linked-list/LinkedList.d.ts +27 -10
  14. package/dist/collections/linked-list/LinkedList.js +106 -43
  15. package/dist/collections/linked-list/LinkedList.min.js +1 -1
  16. package/dist/collections/linked-list/Linker.d.ts +5 -2
  17. package/dist/collections/linked-list/Linker.js +9 -5
  18. package/dist/collections/linked-list/Linker.min.js +1 -1
  19. package/dist/collections/linked-tree-list/LinkedTreeList.d.ts +16 -4
  20. package/dist/collections/linked-tree-list/LinkedTreeList.js +25 -22
  21. package/dist/collections/linked-tree-list/LinkedTreeList.min.js +1 -1
  22. package/dist/collections/linked-tree-list/TreeLinker.d.ts +7 -1
  23. package/dist/collections/linked-tree-list/TreeLinker.js +7 -1
  24. package/dist/collections/queue/Queue.d.ts +6 -3
  25. package/dist/collections/queue/Queue.js +23 -18
  26. package/dist/collections/queue/Queue.min.js +1 -1
  27. package/dist/collections/queue/Queueable.d.ts +10 -4
  28. package/dist/collections/queue/Queueable.js +11 -6
  29. package/dist/collections/queue/Queueable.min.js +1 -1
  30. package/dist/collections/stack/Stack.d.ts +4 -3
  31. package/dist/collections/stack/Stack.js +4 -4
  32. package/dist/collections/stack/Stack.min.js +1 -1
  33. package/dist/collections/stack/Stackable.d.ts +4 -1
  34. package/dist/collections/stack/Stackable.js +7 -5
  35. package/dist/collections/stack/Stackable.min.js +1 -1
  36. package/dist/main.d.ts +2 -2
  37. package/dist/recipes/ArrayIterator.d.ts +10 -0
  38. package/dist/recipes/ArrayIterator.js +10 -0
  39. package/dist/recipes/DoubleLinkerIterator.d.ts +9 -0
  40. package/dist/recipes/DoubleLinkerIterator.js +9 -0
  41. package/dist/recipes/LinkerIterator.d.ts +9 -0
  42. package/dist/recipes/LinkerIterator.js +9 -0
  43. package/dist/recipes/Runnable.d.ts +3 -2
  44. package/dist/recipes/Runnable.js +3 -2
  45. package/dist/recipes/TreeLinkerIterator.d.ts +9 -0
  46. package/dist/recipes/TreeLinkerIterator.js +9 -0
  47. package/package.json +2 -1
@@ -14,7 +14,7 @@ var _ArrayElement = require('../arrayable/ArrayElement')
14
14
  class Linker {
15
15
  /**
16
16
  * Create the new Linker instance, provide the data and optionally give the next Linker.
17
- * @param {Object} [nodeData={}]
17
+ * @param {Object} [nodeData={}] The settings for the new linker.
18
18
  * @param {*} [nodeData.data=null] The data to be stored in this linker
19
19
  * @param {Linker|null} [nodeData.next=null] The reference to the next linker if any
20
20
  */
@@ -22,8 +22,11 @@ class Linker {
22
22
  data = null,
23
23
  next = null
24
24
  } = {}) {
25
+ /** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
25
26
  this.classType = Linker
27
+ /** The data stored in this linker. */
26
28
  this.data = null
29
+ /** The linker after this one, or null when this is the last. */
27
30
  this.next = null
28
31
  this.data = data
29
32
  this.next = next
@@ -37,8 +40,8 @@ class Linker {
37
40
  */
38
41
  exports.Linker = Linker
39
42
  Linker.make = (linker, classType = Linker) => {
40
- if (typeof linker !== 'object') {
41
- // It is not an object, so instantiate the Linker with element as the data
43
+ if (linker === null || typeof linker !== 'object') {
44
+ // It is not an object (or it is null), so instantiate the Linker with element as the data
42
45
  return new classType({
43
46
  data: linker
44
47
  })
@@ -47,7 +50,8 @@ Linker.make = (linker, classType = Linker) => {
47
50
  // Already valid Linker, return as-is
48
51
  return linker
49
52
  }
50
- if (!linker.data) {
53
+ if (!('data' in linker)) {
54
+ // Not the settings for a linker (which would have data, even if it is falsy), so it is the data itself
51
55
  linker = {
52
56
  data: linker
53
57
  }
@@ -61,7 +65,7 @@ Linker.make = (linker, classType = Linker) => {
61
65
  * @param {IsLinker} [classType=Linker] Provide the type of IsLinker to use.
62
66
  * @returns {{head: Linker, tail: Linker}}
63
67
  */
64
- Linker.fromArray = (values, classType = Linker) => values.reduce((references, linker) => {
68
+ Linker.fromArray = (values = [], classType = Linker) => values.reduce((references, linker) => {
65
69
  const newLinker = classType.make(linker, classType)
66
70
  if (references.head === null) {
67
71
  // Initialize the head and tail with the new node
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Linker=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.reduce.js");var _ArrayElement=require("../arrayable/ArrayElement");class Linker{constructor({data:e=null,next:r=null}={}){this.classType=Linker,this.data=null,this.next=null,this.data=e,this.next=r}}exports.Linker=Linker,Linker.make=(e,r=Linker)=>"object"!=typeof e?new r({data:e}):e.classType?e:(e.data||(e={data:e}),_ArrayElement.ArrayElement.make(e,r)),Linker.fromArray=(e,r=Linker)=>e.reduce(((e,t)=>{const a=r.make(t,r);return null===e.head?{head:a,tail:a}:(e.tail.next=a,e.tail=a,e)}),{head:null,tail:null});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Linker=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.reduce.js");var _ArrayElement=require("../arrayable/ArrayElement");class Linker{constructor({data:e=null,next:r=null}={}){this.classType=Linker,this.data=null,this.next=null,this.data=e,this.next=r}}exports.Linker=Linker,Linker.make=(e,r=Linker)=>null===e||"object"!=typeof e?new r({data:e}):e.classType?e:("data"in e||(e={data:e}),_ArrayElement.ArrayElement.make(e,r)),Linker.fromArray=(e=[],r=Linker)=>e.reduce(((e,t)=>{const a=r.make(t,r);return null===e.head?{head:a,tail:a}:(e.tail.next=a,e.tail=a,e)}),{head:null,tail:null});
@@ -13,12 +13,21 @@ import { IsTreeNode } from '../../recipes/IsTreeNode';
13
13
  * @extends DoublyLinkedList
14
14
  */
15
15
  export declare class LinkedTreeList implements IsTree, Iterable<TreeLinker> {
16
+ /** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
16
17
  readonly classType: typeof LinkedTreeList;
18
+ /** A linker of the list (null when the list is empty); the head is found by walking back from it. */
17
19
  innerList: IsTreeNode | any;
20
+ /** Whether the inner list has been initialized (it can only be initialized once). */
18
21
  initialized: boolean;
22
+ /** The class used to wrap the data given to this list as tree linkers. */
19
23
  linkerClass: typeof TreeLinker;
24
+ /** The last linker, remembered so that adding to the end does not need to walk the whole list (null when not known yet). */
25
+ private tailCache;
26
+ /** The number of linkers, kept up to date by the list's own methods so that the length does not need to walk the whole list (null when not known yet). */
27
+ private countCache;
20
28
  /**
21
29
  * Create the new LinkedTreeList instance, configure the list class.
30
+ * @param {TreeLinker} [linkerClass=TreeLinker] The class used to wrap given data as tree linkers.
22
31
  */
23
32
  constructor(linkerClass?: typeof TreeLinker);
24
33
  /**
@@ -28,7 +37,7 @@ export declare class LinkedTreeList implements IsTree, Iterable<TreeLinker> {
28
37
  */
29
38
  initialize(initialList: TreeLinker): LinkedTreeList;
30
39
  /**
31
- * Retrieve a copy of the innerList used.
40
+ * Retrieve the innerList used (the list itself, not a copy).
32
41
  * @returns {TreeLinker}
33
42
  */
34
43
  get list(): TreeLinker;
@@ -38,12 +47,13 @@ export declare class LinkedTreeList implements IsTree, Iterable<TreeLinker> {
38
47
  */
39
48
  get first(): TreeLinker;
40
49
  /**
41
- * Retrieve the last TreeLinker in the list.
50
+ * Retrieve the last TreeLinker in the list. The end is remembered, so this does not walk the list.
42
51
  * @returns {TreeLinker}
43
52
  */
44
53
  get last(): TreeLinker;
45
54
  /**
46
- * Return the length of the list.
55
+ * Return the length of the list. It is kept up to date by the list's own methods, so this does not walk the list
56
+ * (call reset() after linkers were changed directly).
47
57
  * @returns {number}
48
58
  */
49
59
  get length(): number;
@@ -103,7 +113,8 @@ export declare class LinkedTreeList implements IsTree, Iterable<TreeLinker> {
103
113
  */
104
114
  remove(node: TreeLinker): TreeLinker;
105
115
  /**
106
- * Refresh all references and return head reference.
116
+ * Refresh all references (the head, the end and the length) by walking the list once, and return the head. The
117
+ * list's own methods keep these up to date, so this is only needed after linkers were changed directly.
107
118
  * @return {TreeLinker}
108
119
  */
109
120
  reset(): TreeLinker;
@@ -117,6 +128,7 @@ export declare class LinkedTreeList implements IsTree, Iterable<TreeLinker> {
117
128
  * Be able to run forEach on this LinkedTreeList to iterate over the TreeLinker Items.
118
129
  * @param {forEachCallback} callback The function to call for-each tree node
119
130
  * @param {LinkedTreeList} thisArg Optional, 'this' reference
131
+ * @return {LinkedTreeList} The list which was iterated.
120
132
  */
121
133
  forEach(callback: forEachCallback, thisArg?: LinkedTreeList): LinkedTreeList;
122
134
  /**
@@ -14,6 +14,13 @@ var _DoublyLinkedList = require('../doubly-linked-list/DoublyLinkedList')
14
14
  * @memberOf module:collect-your-stuff
15
15
  */
16
16
 
17
+ /**
18
+ * Use one of the accessors of DoublyLinkedList (which keeps track of the head, tail and length) for a LinkedTreeList.
19
+ * @param {string} name The accessor to use
20
+ * @param {LinkedTreeList} list The list to use it on
21
+ * @returns {*}
22
+ */
23
+ const borrowedGetter = (name, list) => Object.getOwnPropertyDescriptor(_DoublyLinkedList.DoublyLinkedList.prototype, name).get.call(list)
17
24
  /**
18
25
  * LinkedTreeList represents a collection stored with a root and spreading in branching (tree) formation.
19
26
  * @extends DoublyLinkedList
@@ -21,11 +28,19 @@ var _DoublyLinkedList = require('../doubly-linked-list/DoublyLinkedList')
21
28
  class LinkedTreeList {
22
29
  /**
23
30
  * Create the new LinkedTreeList instance, configure the list class.
31
+ * @param {TreeLinker} [linkerClass=TreeLinker] The class used to wrap given data as tree linkers.
24
32
  */
25
33
  constructor (linkerClass = _TreeLinker.TreeLinker) {
34
+ /** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
26
35
  this.classType = LinkedTreeList
36
+ /** A linker of the list (null when the list is empty); the head is found by walking back from it. */
27
37
  this.innerList = null
38
+ /** Whether the inner list has been initialized (it can only be initialized once). */
28
39
  this.initialized = false
40
+ /** The last linker, remembered so that adding to the end does not need to walk the whole list (null when not known yet). */
41
+ this.tailCache = null
42
+ /** The number of linkers, kept up to date by the list's own methods so that the length does not need to walk the whole list (null when not known yet). */
43
+ this.countCache = null
29
44
  this.linkerClass = linkerClass
30
45
  }
31
46
 
@@ -45,7 +60,7 @@ class LinkedTreeList {
45
60
  }
46
61
 
47
62
  /**
48
- * Retrieve a copy of the innerList used.
63
+ * Retrieve the innerList used (the list itself, not a copy).
49
64
  * @returns {TreeLinker}
50
65
  */
51
66
  get list () {
@@ -57,38 +72,24 @@ class LinkedTreeList {
57
72
  * @returns {TreeLinker}
58
73
  */
59
74
  get first () {
60
- return this.reset()
75
+ return borrowedGetter('first', this)
61
76
  }
62
77
 
63
78
  /**
64
- * Retrieve the last TreeLinker in the list.
79
+ * Retrieve the last TreeLinker in the list. The end is remembered, so this does not walk the list.
65
80
  * @returns {TreeLinker}
66
81
  */
67
82
  get last () {
68
- let tail = this.innerList
69
- if (tail === null) {
70
- return null
71
- }
72
- let next = tail.next
73
- while (next !== null) {
74
- tail = next
75
- next = tail.next
76
- }
77
- return tail
83
+ return borrowedGetter('last', this)
78
84
  }
79
85
 
80
86
  /**
81
- * Return the length of the list.
87
+ * Return the length of the list. It is kept up to date by the list's own methods, so this does not walk the list
88
+ * (call reset() after linkers were changed directly).
82
89
  * @returns {number}
83
90
  */
84
91
  get length () {
85
- let current = this.first
86
- let length = 0
87
- while (current !== null) {
88
- ++length
89
- current = current.next
90
- }
91
- return length
92
+ return borrowedGetter('length', this)
92
93
  }
93
94
 
94
95
  /**
@@ -197,7 +198,8 @@ class LinkedTreeList {
197
198
  }
198
199
 
199
200
  /**
200
- * Refresh all references and return head reference.
201
+ * Refresh all references (the head, the end and the length) by walking the list once, and return the head. The
202
+ * list's own methods keep these up to date, so this is only needed after linkers were changed directly.
201
203
  * @return {TreeLinker}
202
204
  */
203
205
  reset () {
@@ -217,6 +219,7 @@ class LinkedTreeList {
217
219
  * Be able to run forEach on this LinkedTreeList to iterate over the TreeLinker Items.
218
220
  * @param {forEachCallback} callback The function to call for-each tree node
219
221
  * @param {LinkedTreeList} thisArg Optional, 'this' reference
222
+ * @return {LinkedTreeList} The list which was iterated.
220
223
  */
221
224
  forEach (callback, thisArg = this) {
222
225
  let index = 0
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.LinkedTreeList=void 0;var _TreeLinker=require("./TreeLinker"),_TreeLinkerIterator=require("../../recipes/TreeLinkerIterator"),_DoublyLinkedList=require("../doubly-linked-list/DoublyLinkedList");class LinkedTreeList{constructor(e=_TreeLinker.TreeLinker){this.classType=LinkedTreeList,this.innerList=null,this.initialized=!1,this.linkerClass=e}initialize(e){return this.initialized?(console.warn("Attempt to initialize LinkedTreeList which is not empty."),this):(this.initialized=!0,this.innerList=e,this)}get list(){return this.innerList}get first(){return this.reset()}get last(){let e=this.innerList;if(null===e)return null;let t=e.next;for(;null!==t;)e=t,t=e.next;return e}get length(){let e=this.first,t=0;for(;null!==e;)++t,e=e.next;return t}get parent(){return null===this.first?null:this.first.parent}set parent(e){let t=this.first;for(;null!==t;)t.parent=e,t=t.next;e&&(e.children=this)}get rootParent(){let e=this.first;if(!e)return null;let t=this.first.parent;for(;null!==t;)e=t,t=e.parent;return e}setChildren(e,t=null){Array.from(this).indexOf(e)<0&&console.error("item is not a child of this"),t.parent=e}insertAfter(e,t){return _DoublyLinkedList.DoublyLinkedList.prototype.insertAfter.call(this,e,t)}insertBefore(e,t){return _DoublyLinkedList.DoublyLinkedList.prototype.insertBefore.call(this,e,t)}append(e,t=this.last){return _DoublyLinkedList.DoublyLinkedList.prototype.append.call(this,e,t)}prepend(e,t=this.first){return _DoublyLinkedList.DoublyLinkedList.prototype.prepend.call(this,e,t)}remove(e){return _DoublyLinkedList.DoublyLinkedList.prototype.remove.call(this,e)}reset(){return _DoublyLinkedList.DoublyLinkedList.prototype.reset.call(this)}item(e){return _DoublyLinkedList.DoublyLinkedList.prototype.item.call(this,e)}forEach(e,t=this){let i=0,r=t.first;for(;null!==r;)e(r,i,t),r=r.next,++i;return t}[Symbol.iterator](){let e=this.rootParent;return new _TreeLinkerIterator.TreeLinkerIterator(e)}}exports.LinkedTreeList=LinkedTreeList,LinkedTreeList.fromArray=(e=[],t=_TreeLinker.TreeLinker,i=LinkedTreeList)=>new i(t).initialize(t.fromArray(e).head);
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.LinkedTreeList=void 0;var _TreeLinker=require("./TreeLinker"),_TreeLinkerIterator=require("../../recipes/TreeLinkerIterator"),_DoublyLinkedList=require("../doubly-linked-list/DoublyLinkedList");const borrowedGetter=(e,t)=>Object.getOwnPropertyDescriptor(_DoublyLinkedList.DoublyLinkedList.prototype,e).get.call(t);class LinkedTreeList{constructor(e=_TreeLinker.TreeLinker){this.classType=LinkedTreeList,this.innerList=null,this.initialized=!1,this.tailCache=null,this.countCache=null,this.linkerClass=e}initialize(e){return this.initialized?(console.warn("Attempt to initialize LinkedTreeList which is not empty."),this):(this.initialized=!0,this.innerList=e,this)}get list(){return this.innerList}get first(){return borrowedGetter("first",this)}get last(){return borrowedGetter("last",this)}get length(){return borrowedGetter("length",this)}get parent(){return null===this.first?null:this.first.parent}set parent(e){let t=this.first;for(;null!==t;)t.parent=e,t=t.next;e&&(e.children=this)}get rootParent(){let e=this.first;if(!e)return null;let t=this.first.parent;for(;null!==t;)e=t,t=e.parent;return e}setChildren(e,t=null){Array.from(this).indexOf(e)<0&&console.error("item is not a child of this"),t.parent=e}insertAfter(e,t){return _DoublyLinkedList.DoublyLinkedList.prototype.insertAfter.call(this,e,t)}insertBefore(e,t){return _DoublyLinkedList.DoublyLinkedList.prototype.insertBefore.call(this,e,t)}append(e,t=this.last){return _DoublyLinkedList.DoublyLinkedList.prototype.append.call(this,e,t)}prepend(e,t=this.first){return _DoublyLinkedList.DoublyLinkedList.prototype.prepend.call(this,e,t)}remove(e){return _DoublyLinkedList.DoublyLinkedList.prototype.remove.call(this,e)}reset(){return _DoublyLinkedList.DoublyLinkedList.prototype.reset.call(this)}item(e){return _DoublyLinkedList.DoublyLinkedList.prototype.item.call(this,e)}forEach(e,t=this){let r=0,i=t.first;for(;null!==i;)e(i,r,t),i=i.next,++r;return t}[Symbol.iterator](){let e=this.rootParent;return new _TreeLinkerIterator.TreeLinkerIterator(e)}}exports.LinkedTreeList=LinkedTreeList,LinkedTreeList.fromArray=(e=[],t=_TreeLinker.TreeLinker,r=LinkedTreeList)=>new r(t).initialize(t.fromArray(e).head);
@@ -12,15 +12,21 @@ import { IsTree } from '../../recipes/IsTree';
12
12
  * @extends DoubleLinker
13
13
  */
14
14
  export declare class TreeLinker implements IsTreeNode {
15
+ /** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
15
16
  readonly classType: typeof TreeLinker;
17
+ /** The data stored in this tree node. */
16
18
  data: any;
19
+ /** The sibling after this node, or null when this is the last child. */
17
20
  next: IsTreeNode | null;
21
+ /** The sibling before this node, or null when this is the first child. */
18
22
  prev: IsTreeNode | null;
23
+ /** The node this node is a child of, or null for a root node. */
19
24
  parent: IsTreeNode;
25
+ /** The list of the children of this node, or null when it has none. */
20
26
  children: IsArrayable<IsTreeNode>;
21
27
  /**
22
28
  * Create the new TreeLinker instance, provide the data and optionally set references for next, prev, parent, or children.
23
- * @param {Object} [settings={}]
29
+ * @param {Object} [settings={}] The settings for the new tree node.
24
30
  * @param {*} [settings.data=null] The data to be stored in this tree node
25
31
  * @param {TreeLinker} [settings.next=null] The reference to the next linker if any
26
32
  * @param {TreeLinker} [settings.prev=null] The reference to the previous linker if any
@@ -15,7 +15,7 @@ var _LinkedTreeList = require('./LinkedTreeList')
15
15
  class TreeLinker {
16
16
  /**
17
17
  * Create the new TreeLinker instance, provide the data and optionally set references for next, prev, parent, or children.
18
- * @param {Object} [settings={}]
18
+ * @param {Object} [settings={}] The settings for the new tree node.
19
19
  * @param {*} [settings.data=null] The data to be stored in this tree node
20
20
  * @param {TreeLinker} [settings.next=null] The reference to the next linker if any
21
21
  * @param {TreeLinker} [settings.prev=null] The reference to the previous linker if any
@@ -31,11 +31,17 @@ class TreeLinker {
31
31
  parent = null,
32
32
  listClass = _LinkedTreeList.LinkedTreeList
33
33
  } = {}) {
34
+ /** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
34
35
  this.classType = TreeLinker
36
+ /** The data stored in this tree node. */
35
37
  this.data = null
38
+ /** The sibling after this node, or null when this is the last child. */
36
39
  this.next = null
40
+ /** The sibling before this node, or null when this is the first child. */
37
41
  this.prev = null
42
+ /** The node this node is a child of, or null for a root node. */
38
43
  this.parent = null
44
+ /** The list of the children of this node, or null when it has none. */
39
45
  this.children = null
40
46
  this.data = data
41
47
  this.next = next
@@ -12,18 +12,21 @@ import { completeResponse } from '../../recipes/Runnable';
12
12
  * Maintain a series of queued items.
13
13
  */
14
14
  export declare class Queue {
15
+ /** The list which stores the queueables, the first is next to be dequeued. */
15
16
  queuedList: IsArrayable<any>;
16
17
  private listClass;
17
18
  private queueableClass;
18
19
  /**
19
20
  * Instantiate the queue with the given queue list.
20
21
  * @param {Iterable|LinkedList} queuedList Give the list of queueables to start in this queue.
21
- * @param {IsArrayable} listClass
22
- * @param {Queueable} queueableClass
22
+ * @param {IsArrayable} [listClass=LinkedList] The type of list to create when no queued list is given.
23
+ * @param {Queueable} [queueableClass=Queueable] The class used to wrap queued items.
23
24
  */
24
25
  constructor(queuedList?: IsArrayable<any>, listClass?: any, queueableClass?: typeof Queueable);
25
26
  /**
26
- * Take a queued task from the front of the queue and run it if ready.
27
+ * Take a queued task from the front of the queue and run it if ready. A task which is not ready yet is kept in the
28
+ * queue (never dropped), a task which is still running is reported as blocking and left to finish on its own, and
29
+ * completed tasks are discarded.
27
30
  * @return {completeResponse|*}
28
31
  */
29
32
  dequeue(): completeResponse | any;
@@ -20,8 +20,8 @@ class Queue {
20
20
  /**
21
21
  * Instantiate the queue with the given queue list.
22
22
  * @param {Iterable|LinkedList} queuedList Give the list of queueables to start in this queue.
23
- * @param {IsArrayable} listClass
24
- * @param {Queueable} queueableClass
23
+ * @param {IsArrayable} [listClass=LinkedList] The type of list to create when no queued list is given.
24
+ * @param {Queueable} [queueableClass=Queueable] The class used to wrap queued items.
25
25
  */
26
26
  constructor (queuedList = null, listClass = _LinkedList.LinkedList, queueableClass = _Queueable.Queueable) {
27
27
  this.listClass = listClass
@@ -33,11 +33,17 @@ class Queue {
33
33
  }
34
34
 
35
35
  /**
36
- * Take a queued task from the front of the queue and run it if ready.
36
+ * Take a queued task from the front of the queue and run it if ready. A task which is not ready yet is kept in the
37
+ * queue (never dropped), a task which is still running is reported as blocking and left to finish on its own, and
38
+ * completed tasks are discarded.
37
39
  * @return {completeResponse|*}
38
40
  */
39
41
  dequeue () {
40
- const next = this.remove()
42
+ let next = this.remove()
43
+ // Tasks which already completed are discarded when they reach the front of the queue
44
+ while (next && next.complete) {
45
+ next = this.remove()
46
+ }
41
47
  if (!next) {
42
48
  return {
43
49
  success: 'No more queueable tasks in the queue',
@@ -45,31 +51,30 @@ class Queue {
45
51
  context: this.queuedList
46
52
  }
47
53
  }
48
- if (next.complete) {
49
- // Previously ran queued, run next
50
- return this.dequeue()
51
- }
52
54
  if (next.running) {
55
+ // The unfinished task reports back through its own complete callback, so it is not kept in the queue
53
56
  return {
54
57
  success: false,
55
58
  error: 'The queue has been blocked by an unfinished task.',
56
59
  context: next
57
60
  }
58
61
  }
62
+ if (!next.isReady) {
63
+ // Keep the task (at the back, so the next dequeue can try the other tasks) rather than losing it
64
+ this.enqueue(next)
65
+ // We could go check the next in queue here but if we end up in a state where nothing is ready it would infinite loop
66
+ // Also, we want the loop handled externally
67
+ return {
68
+ success: false,
69
+ error: 'Unable to find ready task.',
70
+ context: next
71
+ }
72
+ }
59
73
  if (!this.empty()) {
60
74
  // Place back in queue to be checked once again next time, only if the queue will not be empty
61
75
  this.enqueue(next)
62
76
  }
63
- if (next.isReady) {
64
- return next.run.call(next)
65
- }
66
- // We could go check the next in queue here but if we end up in a state where nothing is ready it would infinite loop
67
- // Also, we want the loop handled externally
68
- return {
69
- success: false,
70
- error: 'Unable to find ready task.',
71
- context: next
72
- }
77
+ return next.run.call(next)
73
78
  }
74
79
 
75
80
  /**
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Queue=void 0;var _Queueable=require("./Queueable"),_LinkedList=require("../linked-list/LinkedList");class Queue{constructor(e=null,u=_LinkedList.LinkedList,t=_Queueable.Queueable){this.listClass=u,this.queueableClass=t,null===e&&(e=new u(t)),this.queuedList=e}dequeue(){const e=this.remove();return e?e.complete?this.dequeue():e.running?{success:!1,error:"The queue has been blocked by an unfinished task.",context:e}:(this.empty()||this.enqueue(e),e.isReady?e.run.call(e):{success:!1,error:"Unable to find ready task.",context:e}):{success:"No more queueable tasks in the queue",error:!1,context:this.queuedList}}empty(){return this.size()<=0}enqueue(e){this.queuedList.append(e)}peek(){return this.queuedList.first}remove(){return this.empty()?null:this.queuedList.remove(this.queuedList.first)}size(){return this.queuedList.length}}exports.Queue=Queue,Queue.fromArray=(e=[],u=_Queueable.Queueable,t=_LinkedList.LinkedList)=>{const s=new t(u);return s.initialize(u.fromArray(e,u).head),new Queue(s,t,u)};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Queue=void 0;var _Queueable=require("./Queueable"),_LinkedList=require("../linked-list/LinkedList");class Queue{constructor(e=null,u=_LinkedList.LinkedList,t=_Queueable.Queueable){this.listClass=u,this.queueableClass=t,null===e&&(e=new u(t)),this.queuedList=e}dequeue(){let e=this.remove();for(;e&&e.complete;)e=this.remove();return e?e.running?{success:!1,error:"The queue has been blocked by an unfinished task.",context:e}:e.isReady?(this.empty()||this.enqueue(e),e.run.call(e)):(this.enqueue(e),{success:!1,error:"Unable to find ready task.",context:e}):{success:"No more queueable tasks in the queue",error:!1,context:this.queuedList}}empty(){return this.size()<=0}enqueue(e){this.queuedList.append(e)}peek(){return this.queuedList.first}remove(){return this.empty()?null:this.queuedList.remove(this.queuedList.first)}size(){return this.queuedList.length}}exports.Queue=Queue,Queue.fromArray=(e=[],u=_Queueable.Queueable,t=_LinkedList.LinkedList)=>{const s=new t(u);return s.initialize(u.fromArray(e,u).head),new Queue(s,t,u)};
@@ -11,15 +11,21 @@ import { IsLinker } from '../../recipes/IsLinker';
11
11
  * @extends Linker
12
12
  */
13
13
  export declare class Queueable implements IsLinker, IsRunnable {
14
+ /** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
14
15
  readonly classType: typeof Queueable;
16
+ /** The task (or data) this queueable holds. */
15
17
  data: any;
18
+ /** The queueable after this one, or null when this is the last. */
16
19
  next: Queueable | null;
20
+ /** Whether this queueable has been run to completion. */
17
21
  complete: boolean;
22
+ /** Whether this queueable may run, or a function which answers that when asked. */
18
23
  ready: Function | boolean;
24
+ /** Whether this queueable is running right now. */
19
25
  running: boolean;
20
26
  /**
21
27
  * Create a queueable item that can be used in a queue.
22
- * @param {Object} [queueableData={}]
28
+ * @param {Object} [queueableData={}] The settings for the new queueable.
23
29
  * @param {*} [queueableData.task=null] The data to be stored in this queueable
24
30
  * @param {Queueable|null} [queueableData.next=null] The reference to the next queueable if any
25
31
  * @param {boolean|Function} [queueableData.ready=false] Indicate if the queueable is ready to run
@@ -27,7 +33,7 @@ export declare class Queueable implements IsLinker, IsRunnable {
27
33
  constructor({ task, next, ready }?: {
28
34
  task?: any;
29
35
  next?: Queueable | null;
30
- ready?: boolean;
36
+ ready?: boolean | Function;
31
37
  });
32
38
  /**
33
39
  * Check ready state.
@@ -41,7 +47,7 @@ export declare class Queueable implements IsLinker, IsRunnable {
41
47
  get task(): any;
42
48
  /**
43
49
  * Set this queueable as completed.
44
- * @param {Object} completeResponse
50
+ * @param {Object} [completeResponse={}] The result to report for the task.
45
51
  * @param {*} [completeResponse.success=true] Indicate when the task failed (use false) or give a success message
46
52
  * @param {*} [completeResponse.error=false] Indicate a task was error-free (use false) or give an error message
47
53
  * @param {*} [completeResponse.context=null] Provide additional data in the response
@@ -70,7 +76,7 @@ export declare class Queueable implements IsLinker, IsRunnable {
70
76
  * @param {IsLinker} [classType=Queueable] Provide the type of IsLinker to use.
71
77
  * @returns {{head: Queueable, tail: Queueable}}
72
78
  */
73
- static fromArray: (values: Array<any>, classType?: any) => {
79
+ static fromArray: (values?: Array<any>, classType?: any) => {
74
80
  head: IsLinker;
75
81
  tail: IsLinker;
76
82
  };
@@ -12,7 +12,7 @@ var _Linker = require('../linked-list/Linker')
12
12
  class Queueable {
13
13
  /**
14
14
  * Create a queueable item that can be used in a queue.
15
- * @param {Object} [queueableData={}]
15
+ * @param {Object} [queueableData={}] The settings for the new queueable.
16
16
  * @param {*} [queueableData.task=null] The data to be stored in this queueable
17
17
  * @param {Queueable|null} [queueableData.next=null] The reference to the next queueable if any
18
18
  * @param {boolean|Function} [queueableData.ready=false] Indicate if the queueable is ready to run
@@ -22,10 +22,15 @@ class Queueable {
22
22
  next = null,
23
23
  ready = false
24
24
  } = {}) {
25
+ /** The task (or data) this queueable holds. */
25
26
  this.data = null
27
+ /** The queueable after this one, or null when this is the last. */
26
28
  this.next = null
29
+ /** Whether this queueable has been run to completion. */
27
30
  this.complete = false
31
+ /** Whether this queueable may run, or a function which answers that when asked. */
28
32
  this.ready = false
33
+ /** Whether this queueable is running right now. */
29
34
  this.running = false
30
35
  this.classType = Queueable
31
36
  this.data = task
@@ -58,7 +63,7 @@ class Queueable {
58
63
 
59
64
  /**
60
65
  * Set this queueable as completed.
61
- * @param {Object} completeResponse
66
+ * @param {Object} [completeResponse={}] The result to report for the task.
62
67
  * @param {*} [completeResponse.success=true] Indicate when the task failed (use false) or give a success message
63
68
  * @param {*} [completeResponse.error=false] Indicate a task was error-free (use false) or give an error message
64
69
  * @param {*} [completeResponse.context=null] Provide additional data in the response
@@ -112,8 +117,8 @@ class Queueable {
112
117
  */
113
118
  exports.Queueable = Queueable
114
119
  Queueable.make = (queueable, classType = Queueable) => {
115
- if (typeof queueable !== 'object') {
116
- // It is not an object, so instantiate the Queueable with an element as the data
120
+ if (queueable === null || typeof queueable !== 'object') {
121
+ // It is not an object (or it is null), so instantiate the Queueable with an element as the data
117
122
  return new classType({
118
123
  task: queueable,
119
124
  ready: true
@@ -123,7 +128,7 @@ Queueable.make = (queueable, classType = Queueable) => {
123
128
  // Already valid Queueable, return as-is
124
129
  return queueable
125
130
  }
126
- if (!queueable.task) {
131
+ if (!('task' in queueable)) {
127
132
  queueable = {
128
133
  task: queueable,
129
134
  ready: true
@@ -138,4 +143,4 @@ Queueable.make = (queueable, classType = Queueable) => {
138
143
  * @param {IsLinker} [classType=Queueable] Provide the type of IsLinker to use.
139
144
  * @returns {{head: Queueable, tail: Queueable}}
140
145
  */
141
- Queueable.fromArray = (values, classType = Queueable) => _Linker.Linker.fromArray(values, classType)
146
+ Queueable.fromArray = (values = [], classType = Queueable) => _Linker.Linker.fromArray(values, classType)
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Queueable=void 0;var _Linker=require("../linked-list/Linker");class Queueable{constructor({task:e=null,next:t=null,ready:s=!1}={}){this.data=null,this.next=null,this.complete=!1,this.ready=!1,this.running=!1,this.classType=Queueable,this.data=e,this.next=t,this.complete=!1,this.ready=s,this.running=!1}get isReady(){return"function"==typeof this.ready?this.ready():this.ready}get task(){return"function"==typeof this.data?this.data:e=>"function"==typeof e?e({context:this.data}).context:this.data}markCompleted({success:e=!0,error:t=!1,context:s=null}={}){return this.complete=!0,this.running=!1,{success:e,error:t,context:s}}run(){return this.isReady?this.running?{success:!1,error:"Queued task is already running, possible missing 'complete' callback",context:this.data}:(this.running=!0,this.task(this.markCompleted.bind(this))):{success:!1,error:"Task is not ready",context:this.data}}}exports.Queueable=Queueable,Queueable.make=(e,t=Queueable)=>"object"!=typeof e?new t({task:e,ready:!0}):e.classType?e:(e.task||(e={task:e,ready:!0}),new t(e)),Queueable.fromArray=(e,t=Queueable)=>_Linker.Linker.fromArray(e,t);
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Queueable=void 0;var _Linker=require("../linked-list/Linker");class Queueable{constructor({task:e=null,next:t=null,ready:s=!1}={}){this.data=null,this.next=null,this.complete=!1,this.ready=!1,this.running=!1,this.classType=Queueable,this.data=e,this.next=t,this.complete=!1,this.ready=s,this.running=!1}get isReady(){return"function"==typeof this.ready?this.ready():this.ready}get task(){return"function"==typeof this.data?this.data:e=>"function"==typeof e?e({context:this.data}).context:this.data}markCompleted({success:e=!0,error:t=!1,context:s=null}={}){return this.complete=!0,this.running=!1,{success:e,error:t,context:s}}run(){return this.isReady?this.running?{success:!1,error:"Queued task is already running, possible missing 'complete' callback",context:this.data}:(this.running=!0,this.task(this.markCompleted.bind(this))):{success:!1,error:"Task is not ready",context:this.data}}}exports.Queueable=Queueable,Queueable.make=(e,t=Queueable)=>null===e||"object"!=typeof e?new t({task:e,ready:!0}):e.classType?e:("task"in e||(e={task:e,ready:!0}),new t(e)),Queueable.fromArray=(e=[],t=Queueable)=>_Linker.Linker.fromArray(e,t);
@@ -12,14 +12,15 @@ import { completeResponse } from '../../recipes/Runnable';
12
12
  * Store a collection of items which can only be inserted and removed from the top.
13
13
  */
14
14
  export declare class Stack {
15
+ /** The list which stores the stackables, the first is the top of the stack. */
15
16
  stackedList: IsArrayable<any>;
16
17
  private listClass;
17
18
  private stackableClass;
18
19
  /**
19
20
  * Instantiate the state with the starter stacked list.
20
- * @param {Iterable|LinkedList} stackedList
21
- * @param {IsArrayable} listClass
22
- * @param {Stackable} stackableClass
21
+ * @param {Iterable|LinkedList} [stackedList=null] The list of stackables to start in this stack.
22
+ * @param {IsArrayable} [listClass=LinkedList] The type of list to create when no stacked list is given.
23
+ * @param {Stackable} [stackableClass=Stackable] The class used to wrap stacked items.
23
24
  */
24
25
  constructor(stackedList?: IsArrayable<any>, listClass?: any, stackableClass?: typeof Stackable);
25
26
  /**
@@ -19,9 +19,9 @@ var _LinkedList = require('../linked-list/LinkedList')
19
19
  class Stack {
20
20
  /**
21
21
  * Instantiate the state with the starter stacked list.
22
- * @param {Iterable|LinkedList} stackedList
23
- * @param {IsArrayable} listClass
24
- * @param {Stackable} stackableClass
22
+ * @param {Iterable|LinkedList} [stackedList=null] The list of stackables to start in this stack.
23
+ * @param {IsArrayable} [listClass=LinkedList] The type of list to create when no stacked list is given.
24
+ * @param {Stackable} [stackableClass=Stackable] The class used to wrap stacked items.
25
25
  */
26
26
  constructor (stackedList = null, listClass = _LinkedList.LinkedList, stackableClass = _Stackable.Stackable) {
27
27
  this.listClass = listClass
@@ -102,5 +102,5 @@ exports.Stack = Stack
102
102
  Stack.fromArray = (values = [], stackableClass = _Stackable.Stackable, listClass = _LinkedList.LinkedList) => {
103
103
  const list = new listClass(stackableClass)
104
104
  list.initialize(stackableClass.fromArray(values, stackableClass).head)
105
- return new Stack(list)
105
+ return new Stack(list, listClass, stackableClass)
106
106
  }
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Stack=void 0;var _Stackable=require("./Stackable"),_LinkedList=require("../linked-list/LinkedList");class Stack{constructor(t=null,e=_LinkedList.LinkedList,s=_Stackable.Stackable){this.listClass=e,this.stackableClass=s,null===t&&(t=new e(s)),this.stackedList=t}empty(){return this.size()<=0}top(){return this.stackedList.first}pop(){const t=this.remove();return t?t.run():{success:"No more stackable tasks in the stack",error:!1,context:this.stackedList}}push(t){this.stackedList.prepend(t)}remove(){return this.empty()?null:this.stackedList.remove(this.stackedList.first)}size(){return this.stackedList.length}}exports.Stack=Stack,Stack.fromArray=(t=[],e=_Stackable.Stackable,s=_LinkedList.LinkedList)=>{const i=new s(e);return i.initialize(e.fromArray(t,e).head),new Stack(i)};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Stack=void 0;var _Stackable=require("./Stackable"),_LinkedList=require("../linked-list/LinkedList");class Stack{constructor(t=null,e=_LinkedList.LinkedList,s=_Stackable.Stackable){this.listClass=e,this.stackableClass=s,null===t&&(t=new e(s)),this.stackedList=t}empty(){return this.size()<=0}top(){return this.stackedList.first}pop(){const t=this.remove();return t?t.run():{success:"No more stackable tasks in the stack",error:!1,context:this.stackedList}}push(t){this.stackedList.prepend(t)}remove(){return this.empty()?null:this.stackedList.remove(this.stackedList.first)}size(){return this.stackedList.length}}exports.Stack=Stack,Stack.fromArray=(t=[],e=_Stackable.Stackable,s=_LinkedList.LinkedList)=>{const i=new s(e);return i.initialize(e.fromArray(t,e).head),new Stack(i,s,e)};
@@ -11,12 +11,15 @@ import { IsLinker } from '../../recipes/IsLinker';
11
11
  * @extends Linker
12
12
  */
13
13
  export declare class Stackable implements IsLinker, IsRunnable {
14
+ /** The class used to create this instance, so that it can be recognized as valid without an instanceof check. */
14
15
  readonly classType: typeof Stackable;
16
+ /** The task (or data) this stackable holds. */
15
17
  data: any;
18
+ /** The stackable below this one, or null when this is the bottom. */
16
19
  next: Stackable | null;
17
20
  /**
18
21
  * Create a stackable item that can be used in a stack.
19
- * @param {Object} [stackData={}]
22
+ * @param {Object} [stackData={}] The settings for the new stackable.
20
23
  * @param {*} [stackData.task=null] The data to be stored in this stackable
21
24
  * @param {Stackable|null} [stackData.next=null] The reference to the next stackable if any
22
25
  * @param {boolean|Function} [stackData.ready=false] Indicate if the stackable is ready to run
@@ -12,7 +12,7 @@ var _Linker = require('../linked-list/Linker')
12
12
  class Stackable {
13
13
  /**
14
14
  * Create a stackable item that can be used in a stack.
15
- * @param {Object} [stackData={}]
15
+ * @param {Object} [stackData={}] The settings for the new stackable.
16
16
  * @param {*} [stackData.task=null] The data to be stored in this stackable
17
17
  * @param {Stackable|null} [stackData.next=null] The reference to the next stackable if any
18
18
  * @param {boolean|Function} [stackData.ready=false] Indicate if the stackable is ready to run
@@ -22,7 +22,9 @@ class Stackable {
22
22
  next = null,
23
23
  ready = false
24
24
  } = {}) {
25
+ /** The task (or data) this stackable holds. */
25
26
  this.data = null
27
+ /** The stackable below this one, or null when this is the bottom. */
26
28
  this.next = null
27
29
  this.classType = Stackable
28
30
  this.data = task
@@ -56,8 +58,8 @@ class Stackable {
56
58
  */
57
59
  exports.Stackable = Stackable
58
60
  Stackable.make = (stackable, classType = Stackable) => {
59
- if (typeof stackable !== 'object') {
60
- // It is not an object, so instantiate the Stackable with stackable as the data
61
+ if (stackable === null || typeof stackable !== 'object') {
62
+ // It is not an object (or it is null), so instantiate the Stackable with stackable as the data
61
63
  return new classType({
62
64
  task: stackable
63
65
  })
@@ -66,13 +68,13 @@ Stackable.make = (stackable, classType = Stackable) => {
66
68
  // Already valid Stackable, return as-is
67
69
  return stackable
68
70
  }
69
- if (!stackable.task) {
71
+ if (!('task' in stackable)) {
70
72
  stackable = {
71
73
  task: stackable
72
74
  }
73
75
  }
74
76
  // Create the new node as the configured stackableClass
75
- return new Stackable(stackable)
77
+ return new classType(stackable)
76
78
  }
77
79
  /**
78
80
  * Convert an array into Stackable instances, return the head and tail Stackables.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Stackable=void 0;var _Linker=require("../linked-list/Linker");class Stackable{constructor({task:t=null,next:a=null,ready:e=!1}={}){this.data=null,this.next=null,this.classType=Stackable,this.data=t,this.next=a}get task(){return"function"==typeof this.data?this.data:()=>this.data}run(){return this.task()}}exports.Stackable=Stackable,Stackable.make=(t,a=Stackable)=>"object"!=typeof t?new a({task:t}):t.classType?t:(t.task||(t={task:t}),new Stackable(t)),Stackable.fromArray=(t=[],a=Stackable)=>_Linker.Linker.fromArray(t,a);
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Stackable=void 0;var _Linker=require("../linked-list/Linker");class Stackable{constructor({task:t=null,next:a=null,ready:e=!1}={}){this.data=null,this.next=null,this.classType=Stackable,this.data=t,this.next=a}get task(){return"function"==typeof this.data?this.data:()=>this.data}run(){return this.task()}}exports.Stackable=Stackable,Stackable.make=(t,a=Stackable)=>null===t||"object"!=typeof t?new a({task:t}):t.classType?t:("task"in t||(t={task:t}),new a(t)),Stackable.fromArray=(t=[],a=Stackable)=>_Linker.Linker.fromArray(t,a);