@symbo.ls/utils 3.2.3 → 3.14.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 (122) hide show
  1. package/LICENSE +25 -12
  2. package/README.md +106 -0
  3. package/array.js +162 -0
  4. package/cache.js +7 -0
  5. package/cdn.js +83 -0
  6. package/component.js +25 -0
  7. package/cookie.js +71 -0
  8. package/{src/detectHeight.js → detectHeight.js} +3 -3
  9. package/dist/cjs/array.js +168 -0
  10. package/dist/cjs/browser.js +0 -2
  11. package/dist/cjs/cache.js +26 -0
  12. package/dist/cjs/cdn.js +85 -0
  13. package/dist/cjs/component.js +45 -0
  14. package/dist/cjs/cookie.js +75 -0
  15. package/dist/cjs/date.js +1 -3
  16. package/dist/cjs/detectHeight.js +4 -6
  17. package/dist/cjs/element.js +136 -0
  18. package/dist/cjs/env.js +43 -0
  19. package/dist/cjs/events.js +39 -0
  20. package/dist/cjs/extends.js +434 -0
  21. package/dist/cjs/fibonacci.js +1 -3
  22. package/dist/cjs/files.js +1 -3
  23. package/dist/cjs/function.js +114 -0
  24. package/dist/cjs/globals.js +30 -0
  25. package/dist/cjs/if.js +48 -0
  26. package/dist/cjs/index.js +38 -425
  27. package/dist/cjs/key.js +38 -0
  28. package/dist/cjs/keys.js +201 -0
  29. package/dist/cjs/load.js +5 -7
  30. package/dist/cjs/log.js +34 -0
  31. package/dist/cjs/metadata.js +310 -0
  32. package/dist/cjs/methods.js +599 -0
  33. package/dist/cjs/node.js +35 -0
  34. package/dist/cjs/object.js +634 -0
  35. package/dist/cjs/projectKeys.js +35 -0
  36. package/dist/cjs/props.js +282 -0
  37. package/dist/cjs/scaling.js +5 -169
  38. package/dist/cjs/scope.js +44 -0
  39. package/dist/cjs/sharedLibraries.js +146 -0
  40. package/dist/cjs/state.js +173 -0
  41. package/dist/cjs/string-extra.js +72 -0
  42. package/dist/cjs/string.js +183 -0
  43. package/dist/cjs/style.js +1 -3
  44. package/dist/cjs/tags.js +220 -0
  45. package/dist/cjs/triggerEvent.js +112 -0
  46. package/dist/cjs/types.js +74 -0
  47. package/dist/cjs/update.js +42 -0
  48. package/dist/esm/array.js +148 -0
  49. package/dist/esm/browser.js +14 -0
  50. package/dist/esm/cache.js +6 -0
  51. package/dist/esm/cdn.js +65 -0
  52. package/dist/esm/component.js +25 -0
  53. package/dist/esm/cookie.js +55 -0
  54. package/dist/esm/date.js +11 -0
  55. package/dist/esm/detectHeight.js +42 -0
  56. package/dist/esm/element.js +116 -0
  57. package/dist/esm/env.js +23 -0
  58. package/dist/esm/events.js +19 -0
  59. package/dist/esm/extends.js +414 -0
  60. package/dist/esm/fibonacci.js +10 -0
  61. package/dist/esm/files.js +4 -0
  62. package/dist/esm/function.js +94 -0
  63. package/dist/esm/globals.js +10 -0
  64. package/dist/esm/if.js +28 -0
  65. package/dist/esm/index.js +37 -0
  66. package/dist/esm/key.js +18 -0
  67. package/dist/esm/keys.js +181 -0
  68. package/dist/esm/load.js +151 -0
  69. package/dist/esm/log.js +14 -0
  70. package/dist/esm/metadata.js +290 -0
  71. package/dist/esm/methods.js +569 -0
  72. package/dist/esm/node.js +15 -0
  73. package/dist/esm/object.js +621 -0
  74. package/dist/esm/projectKeys.js +16 -0
  75. package/dist/esm/props.js +262 -0
  76. package/dist/esm/scaling.js +15 -0
  77. package/dist/esm/scope.js +24 -0
  78. package/dist/esm/sharedLibraries.js +126 -0
  79. package/dist/esm/state.js +163 -0
  80. package/dist/esm/string-extra.js +52 -0
  81. package/dist/esm/string.js +163 -0
  82. package/dist/esm/style.js +20 -0
  83. package/dist/esm/tags.js +200 -0
  84. package/dist/esm/triggerEvent.js +92 -0
  85. package/dist/esm/types.js +54 -0
  86. package/dist/esm/update.js +22 -0
  87. package/dist/iife/index.js +5818 -0
  88. package/element.js +148 -0
  89. package/env.js +15 -0
  90. package/events.js +19 -0
  91. package/extends.js +519 -0
  92. package/function.js +145 -0
  93. package/globals.js +8 -0
  94. package/if.js +30 -0
  95. package/index.js +41 -0
  96. package/key.js +20 -0
  97. package/keys.js +176 -0
  98. package/log.js +12 -0
  99. package/metadata.js +392 -0
  100. package/methods.js +636 -0
  101. package/node.js +37 -0
  102. package/object.js +803 -0
  103. package/package.json +38 -22
  104. package/projectKeys.js +30 -0
  105. package/props.js +327 -0
  106. package/{src/scaling.js → scaling.js} +1 -1
  107. package/scope.js +32 -0
  108. package/sharedLibraries.js +184 -0
  109. package/state.js +203 -0
  110. package/{src/index.js → string-extra.js} +11 -17
  111. package/string.js +206 -0
  112. package/tags.js +176 -0
  113. package/triggerEvent.js +102 -0
  114. package/types.js +55 -0
  115. package/update.js +27 -0
  116. package/dist/cjs/package.json +0 -4
  117. /package/{src/browser.js → browser.js} +0 -0
  118. /package/{src/date.js → date.js} +0 -0
  119. /package/{src/fibonacci.js → fibonacci.js} +0 -0
  120. /package/{src/files.js → files.js} +0 -0
  121. /package/{src/load.js → load.js} +0 -0
  122. /package/{src/style.js → style.js} +0 -0
package/methods.js ADDED
@@ -0,0 +1,636 @@
1
+ 'use strict'
2
+
3
+ import { triggerEventOn } from './triggerEvent.js'
4
+ import { DOMQ_PROPERTIES, METHODS, PARSED_DOMQ_PROPERTIES } from './keys.js'
5
+ import { isDefined, isFunction, isObject, isObjectLike } from './types.js'
6
+ import { deepClone } from './object.js'
7
+ import { isProduction } from './env.js'
8
+ import { removeValueFromArray } from './array.js'
9
+ import { OPTIONS } from './cache.js'
10
+ const ENV = process.env.NODE_ENV
11
+
12
+ // TODO: update these files
13
+ export function spotByPath (path) {
14
+ const element = this
15
+ const { __ref: ref } = element
16
+ const arr = [].concat(path)
17
+ let foundelement = ref.root[arr[0]]
18
+
19
+ if (!arr || !arr.length) {
20
+ return console.log(arr, 'on', element.key, 'is undefined')
21
+ }
22
+
23
+ while (foundelement.key === arr[0]) {
24
+ arr.shift()
25
+ if (!arr.length) break
26
+ foundelement = foundelement[arr[0]]
27
+ if (!foundelement) return
28
+ }
29
+
30
+ return foundelement
31
+ }
32
+
33
+ // TODO: update these files
34
+ export function lookup (param) {
35
+ const el = this
36
+ let { parent } = el
37
+
38
+ if (isFunction(param)) {
39
+ if (parent.state && param(parent, parent.state, parent.context)) {
40
+ return parent
41
+ } else if (parent.parent) return parent.lookup(param)
42
+ else return
43
+ }
44
+
45
+ if (el[param]) return el[param]
46
+
47
+ while (parent.param !== param) {
48
+ if (parent[param]) return parent[param]
49
+ parent = parent.parent
50
+ if (!parent) return
51
+ }
52
+
53
+ return parent
54
+ }
55
+
56
+ export function lookdown (param) {
57
+ const el = this
58
+ const { __ref: ref } = el
59
+ const children = ref?.__children
60
+
61
+ if (!children) return
62
+
63
+ for (let i = 0; i < children.length; i++) {
64
+ const v = children[i]
65
+ const childElem = el[v]
66
+
67
+ if (v === param) return childElem
68
+ else if (isFunction(param)) {
69
+ const exec = param(childElem, childElem.state, childElem.context)
70
+ if (childElem.state && exec) {
71
+ return childElem
72
+ }
73
+ }
74
+ const lookdown = childElem?.lookdown?.(param)
75
+ if (lookdown) return lookdown
76
+ }
77
+ }
78
+
79
+ export function lookdownAll (param, results = []) {
80
+ const el = this
81
+ const { __ref: ref } = el
82
+ const children = ref?.__children
83
+
84
+ if (!children) return
85
+
86
+ for (let i = 0; i < children.length; i++) {
87
+ const v = children[i]
88
+ const childElem = el[v]
89
+
90
+ if (v === param) results.push(childElem)
91
+ else if (isFunction(param)) {
92
+ const exec = param(childElem, childElem.state, childElem.context)
93
+ if (childElem.state && exec) results.push(childElem)
94
+ }
95
+ childElem?.lookdownAll?.(param, results)
96
+ }
97
+
98
+ return results.length ? results : undefined
99
+ }
100
+
101
+ export function setNodeStyles (params = {}) {
102
+ const el = this
103
+ if (!el.node?.style) return
104
+
105
+ for (const param in params) {
106
+ const value = params[param]
107
+ const childElem = el[param]
108
+ if (isObject(value) && childElem) setNodeStyles.call(childElem, value)
109
+ else el.node.style[param] = value
110
+ }
111
+
112
+ return el
113
+ }
114
+
115
+ export function remove (opts) {
116
+ const element = this
117
+ const beforeRemoveReturns = triggerEventOn('beforeRemove', element, opts)
118
+ if (beforeRemoveReturns === false) return element
119
+ if (isFunction(element.node.remove)) element.node.remove()
120
+ else if (!isProduction()) {
121
+ console.warn('This item cant be removed')
122
+ element.log()
123
+ }
124
+ delete element.parent[element.key]
125
+ if (element.parent.__ref) {
126
+ element.parent.__ref.__children = removeValueFromArray(
127
+ element.parent.__ref.__children,
128
+ element.key
129
+ )
130
+ }
131
+ triggerEventOn('remove', element, opts)
132
+ }
133
+
134
+ export function get (param) {
135
+ const element = this
136
+ return element[param]
137
+ }
138
+
139
+ export function setProps (param, options) {
140
+ const element = this
141
+ if (!param) return
142
+ element.update(param, options)
143
+ return element
144
+ }
145
+
146
+ export function getRef (key) {
147
+ if (key) return this.__ref && this.__ref[key]
148
+ return this.__ref
149
+ }
150
+
151
+ export function getChildren () {
152
+ const __children = this.getRef('__children')
153
+ return __children.map(k => this[k])
154
+ }
155
+
156
+ export function getPath () {
157
+ return this.getRef().path
158
+ }
159
+
160
+ export function getRootState (param) {
161
+ let state = null
162
+ const hasRootState = (obj) => obj.__element && obj.root?.isRootState
163
+ if (!this) {
164
+ state = window.platformState || window.smblsApp?.state
165
+ } else if (hasRootState(this)) {
166
+ state = this.root
167
+ } else if (this.__ref && this.__ref.path) {
168
+ const hasPlatformState = this.state && hasRootState(this.state)
169
+ const hasPlatformStateOnParent =
170
+ isFunction(this.state) &&
171
+ this.parent.state &&
172
+ hasRootState(this.parent.state)
173
+ if (hasPlatformState || hasPlatformStateOnParent) {
174
+ state = this.state.root || this.parent.state.root
175
+ }
176
+ }
177
+ if (!state) {
178
+ state = window.platformState || window.smblsApp?.state
179
+ }
180
+ return param ? state?.[param] : state
181
+ }
182
+
183
+ export function getRoot (key) {
184
+ const rootElem = this.getRootState()?.__element
185
+ return rootElem && Object.keys(rootElem).length > 0 && key
186
+ ? rootElem[key]
187
+ : rootElem
188
+ }
189
+
190
+ export function getRootData (key) {
191
+ return this.getRoot('data') &&
192
+ Object.keys(this.getRoot('data')).length > 0 &&
193
+ key
194
+ ? this.getRoot('data')[key]
195
+ : this.getRoot('data')
196
+ }
197
+
198
+ export function getRootContext (key) {
199
+ const ctx = this.getRoot()?.context
200
+ return key ? ctx[key] : ctx
201
+ }
202
+
203
+ export function getContext (key) {
204
+ const ctx = this.context
205
+ return key ? ctx[key] : ctx
206
+ }
207
+
208
+ export const defineSetter = (element, key, get, set) =>
209
+ Object.defineProperty(element, key, { get, set })
210
+
211
+ export function keys () {
212
+ const element = this
213
+ const keys = []
214
+ for (const param in element) {
215
+ if (
216
+ // (REGISTRY[param] && !DOMQ_PROPERTIES.has(param)) ||
217
+ !Object.prototype.hasOwnProperty.call(element, param) ||
218
+ (DOMQ_PROPERTIES.has(param) &&
219
+ !PARSED_DOMQ_PROPERTIES.has(param))
220
+ ) {
221
+ continue
222
+ }
223
+ keys.push(param)
224
+ }
225
+ return keys
226
+ }
227
+
228
+ export function parse (excl = []) {
229
+ const element = this
230
+ const obj = {}
231
+ const keyList = keys.call(element)
232
+ const hasChildren = keyList.includes('children')
233
+ const exclSet = excl.length ? new Set(excl) : null
234
+ for (let i = 0; i < keyList.length; i++) {
235
+ const v = keyList[i]
236
+ if ((exclSet && exclSet.has(v)) || !Object.prototype.hasOwnProperty.call(element, v)) continue
237
+ if (hasChildren && v === 'content') continue
238
+ const val = element[v]
239
+ if (v === 'state') {
240
+ if (element.__ref && !element.__ref.__hasRootState) continue
241
+ const parsedVal = isFunction(val && val.parse) ? val.parse() : val
242
+ obj[v] = isFunction(parsedVal)
243
+ ? parsedVal
244
+ : JSON.parse(JSON.stringify(parsedVal || {}))
245
+ } else if (v === 'scope') {
246
+ if (element.__ref && !element.__ref.__hasRootScope) continue
247
+ obj[v] = JSON.parse(JSON.stringify(val || {}))
248
+ } else if (v === 'props') {
249
+ const { __element, update, ...props } = element[v]
250
+ obj[v] = props
251
+ } else if (isDefined(val) && Object.prototype.hasOwnProperty.call(element, v)) {
252
+ obj[v] = val
253
+ }
254
+ }
255
+ return obj
256
+ }
257
+
258
+ export function parseDeep (excl = [], visited = new WeakSet()) {
259
+ const element = this
260
+ if (visited.has(element)) return undefined
261
+ visited.add(element)
262
+ const obj = parse.call(element, excl)
263
+ const exclSet = excl.length ? new Set(excl) : null
264
+ for (const v in obj) {
265
+ if ((exclSet && exclSet.has(v)) || !Object.prototype.hasOwnProperty.call(element, v)) continue
266
+ const val = obj[v]
267
+ if (Array.isArray(val)) {
268
+ obj[v] = val.map(item =>
269
+ isObjectLike(item) ? parseDeep.call(item, excl, visited) : item
270
+ )
271
+ } else if (isObjectLike(val)) {
272
+ obj[v] = parseDeep.call(val, excl, visited)
273
+ }
274
+ }
275
+ return obj
276
+ }
277
+
278
+ export function verbose (...args) {
279
+ if (ENV !== 'test' && ENV !== 'development') return
280
+
281
+ const element = this
282
+ const { __ref: ref } = element
283
+ console.groupCollapsed(element.key)
284
+ if (args.length) {
285
+ args.forEach(v => console.log(`%c${v}:\n`, 'font-weight: bold', element[v]))
286
+ } else {
287
+ console.log(ref.path)
288
+ const keys = element.keys()
289
+ keys.forEach(v => console.log(`%c${v}:`, 'font-weight: bold', element[v]))
290
+ }
291
+ console.log(element)
292
+ console.groupEnd(element.key)
293
+ return element
294
+ }
295
+
296
+ export function log (...params) {
297
+ if (ENV === 'test' || ENV === 'development') {
298
+ console.log(...params)
299
+ }
300
+ }
301
+
302
+ export function warn (...params) {
303
+ if (ENV === 'test' || ENV === 'development') {
304
+ console.warn(...params)
305
+ }
306
+ }
307
+
308
+ export function error (...params) {
309
+ if (ENV === 'test' || ENV === 'development') {
310
+ if (params[params.length - 1]?.debugger) debugger // eslint-disable-line
311
+ if (params[params.length - 1]?.verbose) verbose.call(this)
312
+ throw new Error(...params)
313
+ }
314
+ }
315
+
316
+ export function nextElement () {
317
+ const element = this
318
+ const { key, parent } = element
319
+ const { __children } = parent.__ref
320
+
321
+ const currentIndex = __children.indexOf(key)
322
+ const nextChild = __children[currentIndex + 1]
323
+
324
+ return parent[nextChild]
325
+ }
326
+
327
+ export function previousElement (el) {
328
+ const element = el || this
329
+ const { key, parent } = element
330
+ const { __children } = parent.__ref
331
+
332
+ if (!__children) return
333
+
334
+ const currentIndex = __children.indexOf(key)
335
+ return parent[__children[currentIndex - 1]]
336
+ }
337
+
338
+ export function variables (obj = {}) {
339
+ const element = this
340
+ if (!element.data) element.data = {}
341
+ if (!element.data.varCaches) element.data.varCaches = {}
342
+ const varCaches = element.data.varCaches
343
+ const changes = {}
344
+ let changed
345
+ for (const key in obj) {
346
+ if (obj[key] !== varCaches[key]) {
347
+ changed = true
348
+ changes[key] = obj[key]
349
+ }
350
+ }
351
+ return {
352
+ changed: cb => {
353
+ if (!changed) return
354
+ const returns = cb(changes, deepClone(varCaches))
355
+ for (const key in changes) {
356
+ varCaches[key] = changes[key]
357
+ }
358
+ return returns
359
+ },
360
+ timeout: (cb, timeout) => {
361
+ if (!changed) return
362
+ const t = setTimeout(() => {
363
+ cb(changes)
364
+ clearTimeout(t)
365
+ }, timeout)
366
+ }
367
+ }
368
+ }
369
+
370
+ /**
371
+ * A unified call function that detects the calling context and adapts accordingly.
372
+ * - When called in an async context (with await), it fully resolves promises
373
+ * - When called in a sync context, it returns sync results directly and handles promises appropriately
374
+ *
375
+ * @param {string} fnKey - The name of the function to call
376
+ * @param {...any} args - Arguments to pass to the function
377
+ * @returns {any|Promise} - The result or a Promise to the result
378
+ */
379
+ export function call (fnKey, ...args) {
380
+ const context = this.context
381
+ const fn = (
382
+ context.utils?.[fnKey] ||
383
+ context.functions?.[fnKey] ||
384
+ context.methods?.[fnKey] ||
385
+ context.snippets?.[fnKey]
386
+ )
387
+ if (!fn) return
388
+ try {
389
+ const result = fn.call(this, ...args)
390
+ if (result && typeof result.then === 'function') {
391
+ result.catch((err) => {
392
+ error.call(this, err)
393
+ })
394
+ }
395
+ return result
396
+ } catch (err) {
397
+ error.call(this, err)
398
+ if (context?.strictMode) throw err
399
+ }
400
+ }
401
+
402
+ export async function getDB () {
403
+ const element = this
404
+ const db = element.context?.fetch
405
+ if (!db) return null
406
+ if (typeof db.select === 'function') {
407
+ if (!db.__authInitialized && db.getSession) {
408
+ const { initAdapterAuth } = await import('@symbo.ls/fetch')
409
+ await initAdapterAuth(db, element.context)
410
+ }
411
+ return db
412
+ }
413
+ if (db.__resolved) {
414
+ if (!db.__resolved.__authInitialized && db.__resolved.getSession) {
415
+ const { initAdapterAuth } = await import('@symbo.ls/fetch')
416
+ await initAdapterAuth(db.__resolved, element.context)
417
+ }
418
+ return db.__resolved
419
+ }
420
+ if (db.__resolving) return db.__resolving
421
+ // Set __resolving synchronously BEFORE the async import to prevent
422
+ // resolveAdapter() from starting a parallel resolveDb() during the yield
423
+ const resolvePromise = import('@symbo.ls/fetch').then(({ resolveDb }) => resolveDb(db))
424
+ db.__resolving = resolvePromise
425
+ const resolved = await resolvePromise
426
+ db.__resolved = resolved
427
+ element.context.fetch = resolved
428
+ delete db.__resolving
429
+ if (resolved.getSession) {
430
+ const { initAdapterAuth } = await import('@symbo.ls/fetch')
431
+ await initAdapterAuth(resolved, element.context)
432
+ }
433
+ return resolved
434
+ }
435
+
436
+ export function getQuery (format) {
437
+ const element = this
438
+ const useStateQuery = format || OPTIONS.useStateQuery || element.context?.useStateQuery
439
+ if (!useStateQuery) return null
440
+
441
+ const query = {}
442
+ buildQueryFromElement(element, query)
443
+
444
+ if (useStateQuery === true) return query
445
+ const formatter = QUERY_FORMATTERS[useStateQuery]
446
+ return formatter ? formatter(query) : query
447
+ }
448
+
449
+ const buildQueryFromElement = (element, query) => {
450
+ const ref = element.__ref
451
+ if (!ref) return
452
+
453
+ const stateKey = ref.__state
454
+ if (stateKey && typeof stateKey === 'string') {
455
+ setQueryPath(query, stateKey)
456
+ }
457
+
458
+ const children = ref.__children
459
+ if (children) {
460
+ for (let i = 0; i < children.length; i++) {
461
+ const child = element[children[i]]
462
+ if (child && child.__ref) {
463
+ buildQueryFromElement(child, query)
464
+ }
465
+ }
466
+ }
467
+
468
+ const contentKey = ref.contentElementKey || 'content'
469
+ const content = element[contentKey]
470
+ if (content && content.__ref) {
471
+ buildQueryFromElement(content, query)
472
+ }
473
+ }
474
+
475
+ const setQueryPath = (query, path) => {
476
+ const clean = path.replaceAll('../', '').replaceAll('~/', '')
477
+ const parts = clean.split('/')
478
+ let current = query
479
+ for (let i = 0; i < parts.length; i++) {
480
+ const part = parts[i]
481
+ if (i === parts.length - 1) {
482
+ if (!current[part]) current[part] = true
483
+ } else {
484
+ if (current[part] === true) current[part] = {}
485
+ if (!current[part]) current[part] = {}
486
+ current = current[part]
487
+ }
488
+ }
489
+ }
490
+
491
+ // --- Query formatters ---
492
+
493
+ const queryToGraphQL = (query, indent = 0) => {
494
+ const pad = ' '.repeat(indent)
495
+ const entries = Object.entries(query)
496
+ if (!entries.length) return ''
497
+ const fields = entries.map(([key, value]) => {
498
+ if (value === true) return `${pad}${key}`
499
+ return `${pad}${key} {\n${queryToGraphQL(value, indent + 1)}\n${pad}}`
500
+ })
501
+ return fields.join('\n')
502
+ }
503
+
504
+ const formatGraphQL = query => {
505
+ return `{\n${queryToGraphQL(query, 1)}\n}`
506
+ }
507
+
508
+ const formatJsonApi = query => {
509
+ const result = { fields: {}, include: [] }
510
+ const walk = (obj, prefix) => {
511
+ const fields = []
512
+ for (const key in obj) {
513
+ if (obj[key] === true) {
514
+ fields.push(key)
515
+ } else {
516
+ const nested = prefix ? `${prefix}.${key}` : key
517
+ result.include.push(nested)
518
+ walk(obj[key], nested)
519
+ }
520
+ }
521
+ if (fields.length) {
522
+ result.fields[prefix || '_root'] = fields
523
+ }
524
+ }
525
+ walk(query, '')
526
+ return result
527
+ }
528
+
529
+ const formatOData = query => {
530
+ const build = obj => {
531
+ const select = []
532
+ const expand = []
533
+ for (const key in obj) {
534
+ if (obj[key] === true) {
535
+ select.push(key)
536
+ } else {
537
+ const nested = build(obj[key])
538
+ const parts = []
539
+ if (nested.select) parts.push(`$select=${nested.select}`)
540
+ if (nested.expand) parts.push(`$expand=${nested.expand}`)
541
+ expand.push(parts.length ? `${key}(${parts.join(';')})` : key)
542
+ }
543
+ }
544
+ return {
545
+ select: select.length ? select.join(',') : '',
546
+ expand: expand.length ? expand.join(',') : ''
547
+ }
548
+ }
549
+ const { select, expand } = build(query)
550
+ const parts = []
551
+ if (select) parts.push(`$select=${select}`)
552
+ if (expand) parts.push(`$expand=${expand}`)
553
+ return parts.join('&')
554
+ }
555
+
556
+ const formatSQL = (query, options) => {
557
+ const columns = []
558
+ const joins = []
559
+ const tables = new Set()
560
+
561
+ const walk = (obj, table, parentTable) => {
562
+ tables.add(table)
563
+ if (parentTable) {
564
+ joins.push(
565
+ `LEFT JOIN ${table} ON ${table}.${parentTable}_id = ${parentTable}.id`
566
+ )
567
+ }
568
+ for (const key in obj) {
569
+ if (obj[key] === true) {
570
+ columns.push(`${table}.${key}`)
571
+ } else {
572
+ walk(obj[key], key, table)
573
+ }
574
+ }
575
+ }
576
+
577
+ const roots = Object.keys(query)
578
+ if (roots.length === 1 && query[roots[0]] !== true) {
579
+ walk(query[roots[0]], roots[0], null)
580
+ } else {
581
+ walk(query, '_root', null)
582
+ }
583
+
584
+ const from = [...tables][0] || '_root'
585
+ const select = columns.length ? columns.join(', ') : '*'
586
+ const joinStr = joins.length ? '\n' + joins.join('\n') : ''
587
+ return `SELECT ${select}\nFROM ${from}${joinStr}`
588
+ }
589
+
590
+ const formatPaths = query => {
591
+ const paths = []
592
+ const walk = (obj, prefix) => {
593
+ for (const key in obj) {
594
+ const path = prefix ? `${prefix}/${key}` : key
595
+ if (obj[key] === true) {
596
+ paths.push(path)
597
+ } else {
598
+ walk(obj[key], path)
599
+ }
600
+ }
601
+ }
602
+ walk(query, '')
603
+ return paths
604
+ }
605
+
606
+ const formatSupabase = query => {
607
+ const build = obj => {
608
+ const parts = []
609
+ for (const key in obj) {
610
+ if (obj[key] === true) {
611
+ parts.push(key)
612
+ } else {
613
+ parts.push(`${key}(${build(obj[key])})`)
614
+ }
615
+ }
616
+ return parts.join(', ')
617
+ }
618
+ const roots = Object.keys(query)
619
+ if (roots.length === 1 && query[roots[0]] !== true) {
620
+ return { from: roots[0], select: build(query[roots[0]]) }
621
+ }
622
+ return { from: null, select: build(query) }
623
+ }
624
+
625
+ const QUERY_FORMATTERS = {
626
+ graphql: formatGraphQL,
627
+ 'json-api': formatJsonApi,
628
+ odata: formatOData,
629
+ sql: formatSQL,
630
+ supabase: formatSupabase,
631
+ paths: formatPaths
632
+ }
633
+
634
+ export function isMethod (param, element) {
635
+ return Boolean(METHODS.has(param) || element?.context?.methods?.[param])
636
+ }
package/node.js ADDED
@@ -0,0 +1,37 @@
1
+ 'use strict'
2
+
3
+ import { window } from './globals.js'
4
+
5
+ export const isNode = obj => {
6
+ return (
7
+ (typeof Node === 'object'
8
+ ? obj instanceof window.Node
9
+ : obj &&
10
+ typeof obj === 'object' &&
11
+ typeof obj.nodeType === 'number' &&
12
+ typeof obj.nodeName === 'string') || false
13
+ )
14
+ }
15
+
16
+ // Returns true if it is a DOM element
17
+ export const isHtmlElement = obj => {
18
+ return (
19
+ (typeof HTMLElement === 'object'
20
+ ? obj instanceof window.HTMLElement // DOM2
21
+ : obj &&
22
+ typeof obj === 'object' &&
23
+ obj !== null &&
24
+ obj.nodeType === 1 &&
25
+ typeof obj.nodeName === 'string') || false
26
+ )
27
+ }
28
+
29
+ export const isDOMNode = obj => {
30
+ return (
31
+ typeof window !== 'undefined' &&
32
+ ((window.Node && obj instanceof window.Node) ||
33
+ (window.Window && obj instanceof window.Window) ||
34
+ obj === window ||
35
+ obj === document)
36
+ )
37
+ }