@nejs/basic-extensions 2.6.0 → 2.8.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 (271) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/README.md +6129 -1574
  3. package/dist/@nejs/basic-extensions.bundle.2.7.0.js +19 -0
  4. package/dist/@nejs/basic-extensions.bundle.2.7.0.js.map +7 -0
  5. package/dist/cjs/array.extensions.d.ts +39 -0
  6. package/dist/cjs/array.extensions.js +303 -0
  7. package/dist/cjs/array.extensions.js.map +1 -0
  8. package/dist/cjs/big.int.extension.d.ts +31 -0
  9. package/dist/cjs/big.int.extension.js +164 -0
  10. package/dist/cjs/big.int.extension.js.map +1 -0
  11. package/dist/cjs/{newClasses → classes}/asyncIterable.js +32 -44
  12. package/dist/cjs/classes/asyncIterable.js.map +1 -0
  13. package/dist/cjs/{newClasses → classes}/deferred.js +66 -138
  14. package/dist/cjs/classes/deferred.js.map +1 -0
  15. package/dist/cjs/{newClasses → classes}/descriptor.js +56 -90
  16. package/dist/cjs/classes/descriptor.js.map +1 -0
  17. package/dist/cjs/classes/index.d.ts +13 -0
  18. package/dist/cjs/classes/index.js +57 -0
  19. package/dist/cjs/classes/index.js.map +1 -0
  20. package/dist/cjs/classes/introspector.d.ts +20 -0
  21. package/dist/cjs/classes/introspector.js +130 -0
  22. package/dist/cjs/classes/introspector.js.map +1 -0
  23. package/dist/cjs/{newClasses → classes}/iterable.js +42 -63
  24. package/dist/cjs/classes/iterable.js.map +1 -0
  25. package/dist/cjs/classes/param.parser.d.ts +227 -0
  26. package/dist/cjs/classes/param.parser.js +242 -0
  27. package/dist/cjs/classes/param.parser.js.map +1 -0
  28. package/dist/cjs/classes/pluggable.proxy.d.ts +152 -0
  29. package/dist/cjs/classes/pluggable.proxy.js +444 -0
  30. package/dist/cjs/classes/pluggable.proxy.js.map +1 -0
  31. package/dist/cjs/{newClasses → classes}/refmap.js +18 -30
  32. package/dist/cjs/classes/refmap.js.map +1 -0
  33. package/dist/cjs/{newClasses → classes}/refset.js +28 -47
  34. package/dist/cjs/classes/refset.js.map +1 -0
  35. package/dist/cjs/classes/symkeys.d.ts +292 -0
  36. package/dist/cjs/classes/symkeys.js +424 -0
  37. package/dist/cjs/classes/symkeys.js.map +1 -0
  38. package/dist/cjs/classes/type.d.ts +56 -0
  39. package/dist/cjs/classes/type.js +405 -0
  40. package/dist/cjs/classes/type.js.map +1 -0
  41. package/dist/cjs/function.extensions.js +757 -0
  42. package/dist/cjs/function.extensions.js.map +1 -0
  43. package/dist/cjs/global.this.js +261 -0
  44. package/dist/cjs/global.this.js.map +1 -0
  45. package/dist/cjs/index.d.ts +4 -3
  46. package/dist/cjs/index.js +62 -32
  47. package/dist/cjs/index.js.map +1 -1
  48. package/dist/cjs/json.extensions.d.ts +2 -0
  49. package/dist/cjs/json.extensions.js +107 -0
  50. package/dist/cjs/json.extensions.js.map +1 -0
  51. package/dist/{mjs/mapextensions.d.ts → cjs/map.extensions.d.ts} +1 -0
  52. package/dist/cjs/map.extensions.js +142 -0
  53. package/dist/cjs/map.extensions.js.map +1 -0
  54. package/dist/cjs/number.extension.d.ts +44 -0
  55. package/dist/cjs/number.extension.js +260 -0
  56. package/dist/cjs/number.extension.js.map +1 -0
  57. package/dist/cjs/object.extensions.d.ts +62 -0
  58. package/dist/cjs/object.extensions.js +1116 -0
  59. package/dist/cjs/object.extensions.js.map +1 -0
  60. package/dist/cjs/proxy.extensions.d.ts +2 -0
  61. package/dist/cjs/proxy.extensions.js +207 -0
  62. package/dist/cjs/proxy.extensions.js.map +1 -0
  63. package/dist/cjs/reflect.extensions.js +316 -0
  64. package/dist/cjs/reflect.extensions.js.map +1 -0
  65. package/dist/cjs/regular.expression.extensions.d.ts +2 -0
  66. package/dist/cjs/regular.expression.extensions.js +423 -0
  67. package/dist/cjs/regular.expression.extensions.js.map +1 -0
  68. package/dist/cjs/set.extensions.d.ts +40 -0
  69. package/dist/cjs/{setextensions.js → set.extensions.js} +150 -2
  70. package/dist/cjs/set.extensions.js.map +1 -0
  71. package/dist/cjs/string.extensions.js +471 -0
  72. package/dist/cjs/string.extensions.js.map +1 -0
  73. package/dist/{mjs/symbolextensions.d.ts → cjs/symbol.extensions.d.ts} +1 -0
  74. package/dist/cjs/symbol.extensions.js +259 -0
  75. package/dist/cjs/symbol.extensions.js.map +1 -0
  76. package/dist/cjs/{weakrefextensions.js → weakref.extensions.js} +1 -1
  77. package/dist/cjs/weakref.extensions.js.map +1 -0
  78. package/dist/mjs/array.extensions.d.ts +39 -0
  79. package/dist/mjs/array.extensions.js +300 -0
  80. package/dist/mjs/array.extensions.js.map +1 -0
  81. package/dist/mjs/big.int.extension.d.ts +31 -0
  82. package/dist/mjs/big.int.extension.js +161 -0
  83. package/dist/mjs/big.int.extension.js.map +1 -0
  84. package/dist/mjs/classes/asyncIterable.js.map +1 -0
  85. package/dist/mjs/classes/deferred.js.map +1 -0
  86. package/dist/mjs/{newClasses → classes}/descriptor.js +7 -4
  87. package/dist/mjs/classes/descriptor.js.map +1 -0
  88. package/dist/mjs/classes/index.d.ts +13 -0
  89. package/dist/mjs/classes/index.js +40 -0
  90. package/dist/mjs/classes/index.js.map +1 -0
  91. package/dist/mjs/classes/introspector.d.ts +20 -0
  92. package/dist/mjs/classes/introspector.js +126 -0
  93. package/dist/mjs/classes/introspector.js.map +1 -0
  94. package/dist/mjs/classes/iterable.js.map +1 -0
  95. package/dist/mjs/classes/param.parser.d.ts +227 -0
  96. package/dist/mjs/classes/param.parser.js +238 -0
  97. package/dist/mjs/classes/param.parser.js.map +1 -0
  98. package/dist/mjs/classes/pluggable.proxy.d.ts +152 -0
  99. package/dist/mjs/classes/pluggable.proxy.js +438 -0
  100. package/dist/mjs/classes/pluggable.proxy.js.map +1 -0
  101. package/dist/mjs/{newClasses → classes}/refmap.js +3 -3
  102. package/dist/mjs/classes/refmap.js.map +1 -0
  103. package/dist/mjs/classes/refset.js.map +1 -0
  104. package/dist/mjs/classes/symkeys.d.ts +292 -0
  105. package/dist/mjs/classes/symkeys.js +420 -0
  106. package/dist/mjs/classes/symkeys.js.map +1 -0
  107. package/dist/mjs/classes/type.d.ts +56 -0
  108. package/dist/mjs/classes/type.js +401 -0
  109. package/dist/mjs/classes/type.js.map +1 -0
  110. package/dist/mjs/function.extensions.js +754 -0
  111. package/dist/mjs/function.extensions.js.map +1 -0
  112. package/dist/mjs/global.this.js +258 -0
  113. package/dist/mjs/global.this.js.map +1 -0
  114. package/dist/mjs/index.d.ts +4 -3
  115. package/dist/mjs/index.js +49 -19
  116. package/dist/mjs/index.js.map +1 -1
  117. package/dist/mjs/json.extensions.d.ts +2 -0
  118. package/dist/mjs/json.extensions.js +104 -0
  119. package/dist/mjs/json.extensions.js.map +1 -0
  120. package/dist/{cjs/mapextensions.d.ts → mjs/map.extensions.d.ts} +1 -0
  121. package/dist/mjs/map.extensions.js +139 -0
  122. package/dist/mjs/map.extensions.js.map +1 -0
  123. package/dist/mjs/number.extension.d.ts +44 -0
  124. package/dist/mjs/number.extension.js +257 -0
  125. package/dist/mjs/number.extension.js.map +1 -0
  126. package/dist/mjs/object.extensions.d.ts +62 -0
  127. package/dist/mjs/object.extensions.js +1112 -0
  128. package/dist/mjs/object.extensions.js.map +1 -0
  129. package/dist/mjs/proxy.extensions.d.ts +2 -0
  130. package/dist/mjs/proxy.extensions.js +204 -0
  131. package/dist/mjs/proxy.extensions.js.map +1 -0
  132. package/dist/mjs/reflect.extensions.js +313 -0
  133. package/dist/mjs/reflect.extensions.js.map +1 -0
  134. package/dist/mjs/regular.expression.extensions.d.ts +2 -0
  135. package/dist/mjs/regular.expression.extensions.js +420 -0
  136. package/dist/mjs/regular.expression.extensions.js.map +1 -0
  137. package/dist/mjs/set.extensions.d.ts +40 -0
  138. package/dist/mjs/{setextensions.js → set.extensions.js} +149 -1
  139. package/dist/mjs/set.extensions.js.map +1 -0
  140. package/dist/mjs/string.extensions.js +468 -0
  141. package/dist/mjs/string.extensions.js.map +1 -0
  142. package/dist/{cjs/symbolextensions.d.ts → mjs/symbol.extensions.d.ts} +1 -0
  143. package/dist/mjs/symbol.extensions.js +256 -0
  144. package/dist/mjs/symbol.extensions.js.map +1 -0
  145. package/dist/mjs/{weakrefextensions.js → weakref.extensions.js} +1 -1
  146. package/dist/mjs/weakref.extensions.js.map +1 -0
  147. package/docs/index.html +24045 -5805
  148. package/package.json +6 -4
  149. package/repl.bootstrap.js +21 -0
  150. package/src/array.extensions.js +322 -0
  151. package/src/big.int.extension.js +163 -0
  152. package/src/{newClasses → classes}/descriptor.js +16 -12
  153. package/src/classes/index.js +51 -0
  154. package/src/classes/introspector.js +167 -0
  155. package/src/classes/param.parser.js +253 -0
  156. package/src/classes/pluggable.proxy.js +485 -0
  157. package/src/{newClasses → classes}/refmap.js +5 -3
  158. package/src/classes/symkeys.js +464 -0
  159. package/src/classes/type.js +427 -0
  160. package/src/function.extensions.js +818 -0
  161. package/src/global.this.js +304 -0
  162. package/src/index.js +56 -23
  163. package/src/json.extensions.js +108 -0
  164. package/src/map.extensions.js +144 -0
  165. package/src/number.extension.js +273 -0
  166. package/src/object.extensions.js +1222 -0
  167. package/src/proxy.extensions.js +229 -0
  168. package/src/reflect.extensions.js +346 -0
  169. package/src/regular.expression.extensions.js +451 -0
  170. package/src/{setextensions.js → set.extensions.js} +151 -2
  171. package/src/string.extensions.js +515 -0
  172. package/src/symbol.extensions.js +268 -0
  173. package/tests/newClasses/refmap.test.js +3 -2
  174. package/tsconfig.base.json +5 -3
  175. package/tsconfig.cjs.json +2 -2
  176. package/tsconfig.esm.json +2 -2
  177. package/dist/@nejs/basic-extensions.bundle.2.5.0.js +0 -8
  178. package/dist/@nejs/basic-extensions.bundle.2.5.0.js.map +0 -7
  179. package/dist/cjs/arrayextensions.d.ts +0 -10
  180. package/dist/cjs/arrayextensions.js +0 -73
  181. package/dist/cjs/arrayextensions.js.map +0 -1
  182. package/dist/cjs/functionextensions.js +0 -202
  183. package/dist/cjs/functionextensions.js.map +0 -1
  184. package/dist/cjs/globals.js +0 -166
  185. package/dist/cjs/globals.js.map +0 -1
  186. package/dist/cjs/mapextensions.js +0 -32
  187. package/dist/cjs/mapextensions.js.map +0 -1
  188. package/dist/cjs/newClasses/asyncIterable.js.map +0 -1
  189. package/dist/cjs/newClasses/deferred.js.map +0 -1
  190. package/dist/cjs/newClasses/descriptor.js.map +0 -1
  191. package/dist/cjs/newClasses/iterable.js.map +0 -1
  192. package/dist/cjs/newClasses/refmap.js.map +0 -1
  193. package/dist/cjs/newClasses/refset.js.map +0 -1
  194. package/dist/cjs/objectextensions.d.ts +0 -11
  195. package/dist/cjs/objectextensions.js +0 -232
  196. package/dist/cjs/objectextensions.js.map +0 -1
  197. package/dist/cjs/reflectextensions.js +0 -111
  198. package/dist/cjs/reflectextensions.js.map +0 -1
  199. package/dist/cjs/setextensions.d.ts +0 -2
  200. package/dist/cjs/setextensions.js.map +0 -1
  201. package/dist/cjs/stringextensions.js +0 -158
  202. package/dist/cjs/stringextensions.js.map +0 -1
  203. package/dist/cjs/symbolextensions.js +0 -69
  204. package/dist/cjs/symbolextensions.js.map +0 -1
  205. package/dist/cjs/weakrefextensions.js.map +0 -1
  206. package/dist/mjs/arrayextensions.d.ts +0 -10
  207. package/dist/mjs/arrayextensions.js +0 -70
  208. package/dist/mjs/arrayextensions.js.map +0 -1
  209. package/dist/mjs/functionextensions.js +0 -199
  210. package/dist/mjs/functionextensions.js.map +0 -1
  211. package/dist/mjs/globals.js +0 -163
  212. package/dist/mjs/globals.js.map +0 -1
  213. package/dist/mjs/mapextensions.js +0 -29
  214. package/dist/mjs/mapextensions.js.map +0 -1
  215. package/dist/mjs/newClasses/asyncIterable.js.map +0 -1
  216. package/dist/mjs/newClasses/deferred.js.map +0 -1
  217. package/dist/mjs/newClasses/descriptor.js.map +0 -1
  218. package/dist/mjs/newClasses/iterable.js.map +0 -1
  219. package/dist/mjs/newClasses/refmap.js.map +0 -1
  220. package/dist/mjs/newClasses/refset.js.map +0 -1
  221. package/dist/mjs/objectextensions.d.ts +0 -11
  222. package/dist/mjs/objectextensions.js +0 -229
  223. package/dist/mjs/objectextensions.js.map +0 -1
  224. package/dist/mjs/reflectextensions.js +0 -108
  225. package/dist/mjs/reflectextensions.js.map +0 -1
  226. package/dist/mjs/setextensions.d.ts +0 -2
  227. package/dist/mjs/setextensions.js.map +0 -1
  228. package/dist/mjs/stringextensions.js +0 -155
  229. package/dist/mjs/stringextensions.js.map +0 -1
  230. package/dist/mjs/symbolextensions.js +0 -66
  231. package/dist/mjs/symbolextensions.js.map +0 -1
  232. package/dist/mjs/weakrefextensions.js.map +0 -1
  233. package/src/arrayextensions.js +0 -75
  234. package/src/functionextensions.js +0 -225
  235. package/src/globals.js +0 -196
  236. package/src/mapextensions.js +0 -32
  237. package/src/objectextensions.js +0 -256
  238. package/src/reflectextensions.js +0 -118
  239. package/src/stringextensions.js +0 -166
  240. package/src/symbolextensions.js +0 -69
  241. /package/dist/cjs/{newClasses → classes}/asyncIterable.d.ts +0 -0
  242. /package/dist/cjs/{newClasses → classes}/deferred.d.ts +0 -0
  243. /package/dist/cjs/{newClasses → classes}/descriptor.d.ts +0 -0
  244. /package/dist/cjs/{newClasses → classes}/iterable.d.ts +0 -0
  245. /package/dist/cjs/{newClasses → classes}/refmap.d.ts +0 -0
  246. /package/dist/cjs/{newClasses → classes}/refset.d.ts +0 -0
  247. /package/dist/cjs/{functionextensions.d.ts → function.extensions.d.ts} +0 -0
  248. /package/dist/cjs/{globals.d.ts → global.this.d.ts} +0 -0
  249. /package/dist/cjs/{reflectextensions.d.ts → reflect.extensions.d.ts} +0 -0
  250. /package/dist/cjs/{stringextensions.d.ts → string.extensions.d.ts} +0 -0
  251. /package/dist/cjs/{weakrefextensions.d.ts → weakref.extensions.d.ts} +0 -0
  252. /package/dist/mjs/{newClasses → classes}/asyncIterable.d.ts +0 -0
  253. /package/dist/mjs/{newClasses → classes}/asyncIterable.js +0 -0
  254. /package/dist/mjs/{newClasses → classes}/deferred.d.ts +0 -0
  255. /package/dist/mjs/{newClasses → classes}/deferred.js +0 -0
  256. /package/dist/mjs/{newClasses → classes}/descriptor.d.ts +0 -0
  257. /package/dist/mjs/{newClasses → classes}/iterable.d.ts +0 -0
  258. /package/dist/mjs/{newClasses → classes}/iterable.js +0 -0
  259. /package/dist/mjs/{newClasses → classes}/refmap.d.ts +0 -0
  260. /package/dist/mjs/{newClasses → classes}/refset.d.ts +0 -0
  261. /package/dist/mjs/{newClasses → classes}/refset.js +0 -0
  262. /package/dist/mjs/{functionextensions.d.ts → function.extensions.d.ts} +0 -0
  263. /package/dist/mjs/{globals.d.ts → global.this.d.ts} +0 -0
  264. /package/dist/mjs/{reflectextensions.d.ts → reflect.extensions.d.ts} +0 -0
  265. /package/dist/mjs/{stringextensions.d.ts → string.extensions.d.ts} +0 -0
  266. /package/dist/mjs/{weakrefextensions.d.ts → weakref.extensions.d.ts} +0 -0
  267. /package/src/{newClasses → classes}/asyncIterable.js +0 -0
  268. /package/src/{newClasses → classes}/deferred.js +0 -0
  269. /package/src/{newClasses → classes}/iterable.js +0 -0
  270. /package/src/{newClasses → classes}/refset.js +0 -0
  271. /package/src/{weakrefextensions.js → weakref.extensions.js} +0 -0
@@ -0,0 +1,167 @@
1
+ import { Extension } from '@nejs/extension'
2
+
3
+ export class Introspector {
4
+ static addExpansion(array) {
5
+ const toEntriesFrom = (owner = globalThis) => {
6
+ return (accumulator, key) => {
7
+ const count = accumulator.length;
8
+
9
+ try {
10
+ const value = owner[key]
11
+ accumulator.splice(count, 0, [key, value], [value, key])
12
+ }
13
+ catch (error) { accumulator.splice(count, 0, [key, error]) }
14
+
15
+ return accumulator
16
+ }
17
+ }
18
+
19
+ return Object.defineProperty(array, 'expand', {
20
+ get() {
21
+ return new Map(
22
+ this.reduce(toEntriesFrom(globalThis), [])
23
+ )
24
+ },
25
+ configurable: true,
26
+ enumerable: true,
27
+ })
28
+ }
29
+
30
+ static accessors(owner = globalThis, keys = []) {
31
+ const entries = []
32
+
33
+ for (const key of keys) {
34
+ try {
35
+ const metadata = this.metadata(owner, key)
36
+ if (metadata.get || metadata.set) {
37
+ entries.push([key, metadata])
38
+ }
39
+ continue
40
+ }
41
+ catch (error) {
42
+ entries.push([key, error])
43
+ }
44
+ }
45
+
46
+ return new Map(entries)
47
+ }
48
+
49
+ static classes(owner = globalThis) {
50
+ return this.fetcher(
51
+ 'function', /^[A-Z]/, Object, 'getOwnPropertyNames', owner
52
+ )
53
+ }
54
+
55
+ static functions(owner = globalThis) {
56
+ return this.fetcher(
57
+ 'function', /^[a-z]/, Object, 'getOwnPropertyNames', owner
58
+ )
59
+ }
60
+
61
+ static objects(owner = globalThis) {
62
+ return this.fetcher('object', null, Object, 'getOwnPropertyNames', owner)
63
+ }
64
+
65
+ static properties(owner = globalThis) {
66
+ return this.fetcher(
67
+ (v,t,d) => t !== 'object' && t !== 'function',
68
+ null, Object, 'getOwnPropertyNames', owner
69
+ )
70
+ }
71
+
72
+ static symbols(owner = globalThis) {
73
+ return this.addExpansion(Object.getOwnPropertySymbols(owner))
74
+ }
75
+
76
+ static metadata(owner, key) {
77
+ const metadata = {
78
+ owner, key,
79
+ descriptor: undefined,
80
+ value: undefined,
81
+ get type() { return typeof this.value },
82
+ }
83
+
84
+ try { metadata.descriptor = Object.getOwnPropertyDescriptor(owner, key) }
85
+ catch(error) { metadata.descriptor = error }
86
+
87
+ try {
88
+ metadata.value = (
89
+ metadata.descriptor?.value ??
90
+ metadata.descriptor?.get?.bind(owner)?.() ??
91
+ owner[key]
92
+ )
93
+ }
94
+ catch(error) { metadata.value = error }
95
+
96
+ return metadata
97
+ }
98
+
99
+ static fetcher(
100
+ typeNameOrTyperFn,
101
+ regExp = undefined,
102
+ searchClass = Object,
103
+ searchFunction = 'getOwnPropertyNames',
104
+ owner = globalThis
105
+ ) {
106
+ let typer = typeNameOrTyperFn
107
+
108
+ if (typeof typeNameOrTyperFn !== 'function') {
109
+ const type = String(typeNameOrTyperFn)
110
+ typer = (function(value, typeName, descriptor) {
111
+ return typeName === type
112
+ }).bind(this)
113
+ }
114
+
115
+ return this.addExpansion(
116
+ searchClass[searchFunction](owner).filter(key => {
117
+ const metadata = this.metadata(owner, key)
118
+ return (
119
+ (!regExp || regExp.exec(String(key))) &&
120
+ typer(metadata.value, metadata.type, metadata.descriptor)
121
+ )
122
+ }).toSorted()
123
+ )
124
+ }
125
+
126
+ static makeReport(owner = globalThis) {
127
+ let names = [
128
+ 'classes', 'functions', 'objects', 'properties', 'symbols', 'accessors'
129
+ ];
130
+ let bound = names.reduce(
131
+ (a,n) => { a[n] = this[n].bind(this); return a },
132
+ {}
133
+ )
134
+ const { classes, functions, objects, properties, symbols, accessors } = bound
135
+ const result = { }
136
+
137
+ Object.assign(result, {
138
+ accessors: {
139
+ classes: undefined,
140
+ functions: undefined,
141
+ objects: undefined,
142
+ properties: undefined,
143
+ symbols: undefined,
144
+ },
145
+ classes: this[classes.name](),
146
+ functions: this[functions.name](),
147
+ objects: this[objects.name](),
148
+ properties: this[properties.name](),
149
+ symbols: this[symbols.name](),
150
+ expandAll() {
151
+ names.forEach(reportName => {
152
+ result[reportName] = result?.[reportName]?.expand
153
+ })
154
+ },
155
+ })
156
+
157
+ (names.forEach(type => {
158
+ debugger
159
+ result.accessors[type] = accessors(globalThis, result[type])
160
+ })
161
+ )
162
+
163
+ return result
164
+ }
165
+ }
166
+
167
+ export const IntrospectorExtensions = new Extension(Introspector);
@@ -0,0 +1,253 @@
1
+ import { Extension } from '@nejs/extension'
2
+
3
+ export class ParamParser {
4
+ /**
5
+ * Constructs an instance of ParamParser. It takes in parameters, an optional
6
+ * validator function, and an optional parser function. The parameters are
7
+ * validated and if successful, parsed.
8
+ *
9
+ * @param {any[]} parameters - Arguments passed in by the process.
10
+ * @param {((any[]) => boolean)?} [validator=() => {}] - An optional function
11
+ * to specify a validator without subclassing ParamParser. It should return
12
+ * a boolean indicating the validity of the parameters.
13
+ * @param {((any[]) => object)?} [parser=() => {}] - An optional function to
14
+ * specify a parser without subclassing ParamParser. It should return an
15
+ * object after parsing the input parameters.
16
+ *
17
+ * @example
18
+ * const parameters = ['param1', 'param2']
19
+ * const validator = params => params.every(param => typeof param === 'string')
20
+ * const parser = params => ({ params })
21
+ * const paramParser = new ParamParser(parameters, validator, parser)
22
+ * if (paramParser.success) {
23
+ * console.log('Parsing successful:', paramParser.results)
24
+ * } else {
25
+ * console.error('Parsing failed.')
26
+ * }
27
+ */
28
+ constructor(parameters, validator = () => {}, parser = () => {}) {
29
+ this.args = parameters
30
+ this.parser = parser
31
+ this.validator = validator
32
+ this.result = undefined
33
+ this.success = this.validate(this.args)
34
+
35
+ if (this.success) {
36
+ this.results = this.parse(this.args)
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @param {object} args arguments that were previously validated
42
+ * by either the overloaded validate() method or the supplied
43
+ * validator closure.
44
+ * @returns {object} returns the output object, or an empty
45
+ * object, after parsing the input arguments or parameters.
46
+ */
47
+ parse(args) {
48
+ return this.parser?.(args);
49
+ }
50
+
51
+ /**
52
+ * Walk the arguments and determine if the supplied input is
53
+ * a valid parsing.
54
+ *
55
+ * @param {any[]} args arguments supplied by the process.
56
+ * @returns {boolean} `true` if the validation is successful,
57
+ * `false` otherwise.
58
+ */
59
+ validate(args) {
60
+ return this.validator?.(args);
61
+ }
62
+
63
+ /**
64
+ * Attempts to parse the given parameters using the provided parsers, throwing an
65
+ * error if no valid parser is found. This method serves as a convenience wrapper
66
+ * around `safeTryParsers`, enforcing strict parsing by automatically enabling
67
+ * error throwing on failure.
68
+ *
69
+ * @param {any[]} parameters - The parameters to be parsed.
70
+ * @param {Function[]} parsers - An array of `ParamParser` subclasses to attempt
71
+ * parsing with.
72
+ * @returns {Object} An object containing the parsing result, with a `success`
73
+ * property indicating if parsing was successful, and a `data` property containing
74
+ * the parsed data if successful.
75
+ * @example
76
+ * const parameters = ['param1', 'param2'];
77
+ * const parsers = [Parser1, Parser2];
78
+ * const result = ParamParser.tryParsers(parameters, parsers);
79
+ * if (result.success) {
80
+ * console.log('Parsing successful:', result.data);
81
+ * } else {
82
+ * console.error('Parsing failed.');
83
+ * }
84
+ */
85
+ static tryParsers(parameters, parsers) {
86
+ return this.safeTryParsers(parameters, parsers, true)
87
+ }
88
+
89
+ /**
90
+ * Tries parsing `parameters` with each parser in `parsers`. If
91
+ * `throwOnFail` is true, throws an error when validation fails or
92
+ * no valid parser is found.
93
+ *
94
+ * This method attempts to parse the given parameters using the
95
+ * provided list of parsers. It validates the input to ensure both
96
+ * `parameters` and `parsers` are arrays and that `parsers`
97
+ * contains at least one valid `ParamParser` subclass. If
98
+ * `throwOnFail` is set to true, it will throw specific errors for
99
+ * invalid inputs or when no parser succeeds. Otherwise, it returns
100
+ * an object indicating the success status and the result of
101
+ * parsing, if successful.
102
+ *
103
+ * @param {any[]} parameters - The parameters to be parsed.
104
+ * @param {Function[]} parsers - An array of `ParamParser`
105
+ * subclasses to attempt parsing with.
106
+ * @param {boolean} [throwOnFail=false] - Whether to throw an
107
+ * error on failure.
108
+ * @returns {{success: boolean, data: any}} An object with a
109
+ * `success` flag and `data` containing the parsing result, if
110
+ * successful.
111
+ * @throws {ParametersMustBeArrayError} If `parameters` or
112
+ * `parsers` are not arrays when `throwOnFail` is true.
113
+ * @throws {ParsersArrayMustContainParsersError} If `parsers`
114
+ * does not contain at least one valid `ParamParser` subclass
115
+ * when `throwOnFail` is true.
116
+ * @throws {NoValidParsersFound} If no valid parser is found
117
+ * and `throwOnFail` is true.
118
+ * @example
119
+ * const parameters = ['param1', 'param2'];
120
+ * const parsers = [Parser1, Parser2];
121
+ * const result = ParamParser.safeTryParsers(
122
+ * parameters, parsers, true
123
+ * );
124
+ *
125
+ * if (result.success) {
126
+ * console.log('Parsing successful:', result.data);
127
+ * } else {
128
+ * console.error('Parsing failed.');
129
+ * }
130
+ */
131
+ static safeTryParsers(parameters, parsers, throwOnFail = false) {
132
+ if (!Array.isArray(parameters) || !Array.isArray(parsers)) {
133
+ if (throwOnFail) {
134
+ throw new this.ParametersMustBeArrayError(
135
+ `${this.name}.tryParsers must receive two arrays as args`
136
+ );
137
+ }
138
+ }
139
+
140
+ if (!parsers.some(parser => parser?.prototype instanceof ParamParser &&
141
+ typeof parser === 'function')) {
142
+ if (throwOnFail) {
143
+ throw new this.ParsersArrayMustContainParsersError(
144
+ `${this.name}.tryParsers parsers argument must contain at least one ` +
145
+ `ParamParser derived class`
146
+ );
147
+ }
148
+ }
149
+
150
+ let success = false;
151
+ let result = undefined;
152
+
153
+ for (let Parser of parsers) {
154
+ const parser = new Parser(parameters);
155
+ if (parser.success) {
156
+ success = true;
157
+ result = parser.result;
158
+ break;
159
+ }
160
+ }
161
+
162
+ if (!success && throwOnFail) {
163
+ throw new this.NoValidParsersFound('No valid parsers found');
164
+ }
165
+
166
+ return { success, data: result };
167
+ }
168
+
169
+ /**
170
+ * A custom error class that signifies no valid parsers were found
171
+ * during the parsing process. This error is thrown when all
172
+ * parsers fail to parse the given parameters and the `throwOnFail`
173
+ * flag is set to true in the `safeTryParsers` method.
174
+ *
175
+ * @returns {Function} A class extending Error, representing a
176
+ * specific error when no valid parsers are found.ound.
177
+ *
178
+ * @example
179
+ * try {
180
+ * const result = ParamParser.safeTryParsers(
181
+ * parameters, parsers, true
182
+ * );
183
+ * } catch (error) {
184
+ * if (error instanceof ParamParser.NoValidParsersFound) {
185
+ * console.error(
186
+ * 'No valid parsers could process the parameters.'
187
+ * );
188
+ * }
189
+ * }
190
+ */
191
+ static get NoValidParsersFound() {
192
+ return class NoValidParsersFound extends Error { }
193
+ }
194
+
195
+ /**
196
+ * Represents an error thrown when the parameters provided to a method
197
+ * are not in an array format as expected. This class extends the
198
+ * native JavaScript `Error` class, allowing for instances of this
199
+ * error to be thrown and caught using standard error handling
200
+ * mechanisms in JavaScript.
201
+ *
202
+ * This error is specifically used in scenarios where a method
203
+ * expects its arguments to be provided as an array, and the
204
+ * validation of those arguments fails because they were not
205
+ * provided in an array format. It serves as a clear indicator
206
+ * of the nature of the error to developers, enabling them to
207
+ * quickly identify and rectify the issue in their code.
208
+ *
209
+ * @example
210
+ * try {
211
+ * ParamParser.safeTryParsers(nonArrayParameters, parsers, true);
212
+ * } catch (error) {
213
+ * if (error instanceof ParamParser.ParametersMustBeArrayError) {
214
+ * console.error('Parameters must be provided as an array.');
215
+ * }
216
+ * }
217
+ */
218
+ static get ParametersMustBeArrayError() {
219
+ return class ParametersMustBeArrayError extends Error { }
220
+ }
221
+
222
+ /**
223
+ * A custom error class indicating that the parsers array does not
224
+ * contain valid parser functions. This error is thrown when the
225
+ * validation of parsers within `ParamParser.safeTryParsers` fails
226
+ * to find any instance that is a subclass of `ParamParser`. It
227
+ * extends the native JavaScript `Error` class, allowing it to be
228
+ * thrown and caught using standard error handling mechanisms.
229
+ *
230
+ * This error serves as a clear indicator to developers that the
231
+ * provided array of parsers does not meet the expected criteria,
232
+ * specifically that it must contain at least one valid parser
233
+ * that extends `ParamParser`. This ensures that the parsing
234
+ * process can be executed with at least one valid parser function.
235
+ *
236
+ * @example
237
+ * try {
238
+ * ParamParser.safeTryParsers(parameters, [], true);
239
+ * } catch (error) {
240
+ * const { ParsersArrayMustContainParsersError } = ParamParser
241
+ * if (error instanceof ParsersArrayMustContainParsersError) {
242
+ * console.error(
243
+ * 'The parsers array must contain at least one valid parser.'
244
+ * );
245
+ * }
246
+ * }
247
+ */
248
+ static get ParsersArrayMustContainParsersError() {
249
+ return class ParsersArrayMustContainParsersError extends Error { }
250
+ }
251
+ }
252
+
253
+ export const ParamParserExtensions = new Extension(ParamParser);