@nxtedition/lib 14.0.12 → 14.0.14

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "14.0.12",
3
+ "version": "14.0.14",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "files": [
@@ -7,10 +7,18 @@ const JSON5 = require('json5')
7
7
  const objectHash = require('object-hash')
8
8
  const weakCache = require('../../weakCache')
9
9
 
10
- module.exports = (options) => {
10
+ module.exports = ({ ds, proxify }) => {
11
+ const compiler = {
12
+ current: null,
13
+ resolveTemplate,
14
+ onResolveTemplate,
15
+ compileTemplate,
16
+ isTemplate,
17
+ }
18
+
11
19
  const compilers = {
12
- nxt: getNxtpressionsCompiler(options),
13
- js: getJavascriptCompiler(options),
20
+ nxt: getNxtpressionsCompiler({ ds }),
21
+ js: getJavascriptCompiler({ ds, proxify, compiler }),
14
22
  }
15
23
 
16
24
  function inner(str) {
@@ -192,7 +200,7 @@ module.exports = (options) => {
192
200
  return null
193
201
  }
194
202
  },
195
- (template, hash) => hash ?? hashTemplate(template)
203
+ (template, hash) => hash
196
204
  )
197
205
 
198
206
  function compileTemplate(template) {
@@ -212,10 +220,5 @@ module.exports = (options) => {
212
220
  }
213
221
  }
214
222
 
215
- return {
216
- resolveTemplate,
217
- onResolveTemplate,
218
- compileTemplate,
219
- isTemplate,
220
- }
223
+ return compiler
221
224
  }
@@ -1,3 +1,4 @@
1
+ const assert = require('node:assert')
1
2
  const weakCache = require('../../weakCache')
2
3
  const rxjs = require('rxjs')
3
4
  const vm = require('node:vm')
@@ -14,13 +15,13 @@ class TimerEntry {
14
15
  constructor(key, refresh, delay) {
15
16
  this.key = key
16
17
  this.counter = null
18
+
17
19
  this.timer = setTimeout(refresh, delay)
18
20
  }
19
21
 
20
22
  dispose() {
21
23
  clearTimeout(this.timer)
22
24
 
23
- this.refresh = null
24
25
  this.timer = null
25
26
  }
26
27
  }
@@ -29,12 +30,12 @@ class FetchEntry {
29
30
  constructor(key, refresh, { resource, options }) {
30
31
  this.key = key
31
32
  this.counter = null
33
+
32
34
  this.refresh = refresh
33
35
  this.ac = new AbortController()
34
36
  this.signal = this.ac.signal
35
37
  this.body = null
36
38
  this.status = null
37
- this.options = options
38
39
  this.error = null
39
40
 
40
41
  // TODO (fix): options.signal
@@ -42,9 +43,9 @@ class FetchEntry {
42
43
  // TODO (fix): expire...
43
44
 
44
45
  undici
45
- .fetch(resource, { ...this.options, signal: this.signal })
46
+ .fetch(resource, { ...options, signal: this.signal })
46
47
  .then(async (res) => {
47
- if (!this.signal.aborted) {
48
+ if (this.refresh) {
48
49
  // TODO (fix): max size...
49
50
  this.body = Buffer.from(await res.arrayBuffer())
50
51
  this.status = res.status
@@ -53,7 +54,7 @@ class FetchEntry {
53
54
  }
54
55
  })
55
56
  .catch((err) => {
56
- if (!this.signal.aborted) {
57
+ if (this.refresh) {
57
58
  this.error = err
58
59
  this.refresh()
59
60
  }
@@ -61,9 +62,10 @@ class FetchEntry {
61
62
  }
62
63
 
63
64
  dispose() {
64
- this.ac.abort()
65
-
66
65
  this.refresh = null
66
+
67
+ this.ac.abort()
68
+ this.ac = null
67
69
  }
68
70
  }
69
71
 
@@ -71,6 +73,7 @@ class RecordEntry {
71
73
  constructor(key, refresh, ds) {
72
74
  this.key = key
73
75
  this.counter = null
76
+
74
77
  this.refresh = refresh
75
78
  this.record = ds.record.getRecord(key)
76
79
 
@@ -116,6 +119,36 @@ class ObservableEntry {
116
119
  dispose() {
117
120
  this.subscription.unsubscribe()
118
121
  this.subscription = null
122
+ this.refresh = null
123
+ }
124
+ }
125
+
126
+ class PromiseEntry {
127
+ constructor(key, refresh, promise) {
128
+ this.key = key
129
+ this.counter = null
130
+ this.value = kEmpty
131
+ this.error = null
132
+ this.refresh = refresh
133
+
134
+ promise.then(
135
+ (value) => {
136
+ if (this.refresh) {
137
+ this.value = value
138
+ this.refresh()
139
+ }
140
+ },
141
+ (err) => {
142
+ if (this.refresh) {
143
+ this.error = err
144
+ this.refresh()
145
+ }
146
+ }
147
+ )
148
+ }
149
+
150
+ dispose() {
151
+ this.refresh = null
119
152
  }
120
153
  }
121
154
 
@@ -141,13 +174,18 @@ const globals = {
141
174
  nxt: null,
142
175
  }
143
176
 
144
- function proxyify(value, expression) {
177
+ function proxify(value, expression, handler) {
178
+ assert(expression)
179
+ assert(handler)
180
+
145
181
  if (!value) {
146
182
  return value
147
183
  } else if (rxjs.isObservable(value)) {
148
- return proxyify(expression.observe(value), expression)
184
+ return proxify(expression.observe(value), expression, handler)
185
+ } else if (typeof value?.then === 'function') {
186
+ return proxify(expression.wait(value), expression, handler)
149
187
  } else if (typeof value === 'object') {
150
- return new Proxy(value, expression._handler)
188
+ return new Proxy(value, handler)
151
189
  } else {
152
190
  return value
153
191
  }
@@ -155,7 +193,14 @@ function proxyify(value, expression) {
155
193
 
156
194
  const MAP_POOL = []
157
195
 
158
- module.exports = ({ ds, ...options }) => {
196
+ function makeWrapper(expression) {
197
+ const handler = {
198
+ get: (target, prop) => proxify(target[prop], expression, handler),
199
+ }
200
+ return (value) => proxify(value, expression, handler)
201
+ }
202
+
203
+ module.exports = ({ ds, proxify, compiler }) => {
159
204
  class Expression {
160
205
  constructor(context, script, expression, args, observer) {
161
206
  this._context = context
@@ -172,19 +217,13 @@ module.exports = ({ ds, ...options }) => {
172
217
  this._disposing = false
173
218
  this._destroyed = false
174
219
  this._subscription = null
175
- this._args = null
176
- this._ready = false
177
- this._handler = options.proxyify
178
- ? {
179
- get: (target, prop) => proxyify(target[prop], this),
180
- }
181
- : null
220
+ this._args = kEmpty
221
+ this._wrap = null
182
222
 
183
223
  if (rxjs.isObservable(args)) {
184
224
  this._subscription = args.subscribe({
185
225
  next: (args) => {
186
- this._args = this._handler ? proxyify(args, this) : args
187
- this._ready = true
226
+ this._args = proxify ? this.wrap(args) : args
188
227
  this._refresh()
189
228
  },
190
229
  error: (err) => {
@@ -196,12 +235,16 @@ module.exports = ({ ds, ...options }) => {
196
235
  },
197
236
  })
198
237
  } else {
199
- this._args = this._handler ? proxyify(args, this) : args
200
- this._ready = true
238
+ this._args = proxify ? this.wrap(args) : args
201
239
  this._refreshNT(this)
202
240
  }
203
241
  }
204
242
 
243
+ wrap(value) {
244
+ this._wrap ??= makeWrapper(this)
245
+ return this._wrap(value)
246
+ }
247
+
205
248
  suspend() {
206
249
  throw kSuspend
207
250
  }
@@ -214,6 +257,10 @@ module.exports = ({ ds, ...options }) => {
214
257
  return this._getObservable(observable, throws)
215
258
  }
216
259
 
260
+ wait(promise, throws) {
261
+ return this._getWait(promise, throws)
262
+ }
263
+
217
264
  ds(id, state, throws) {
218
265
  return this._getRecord(id, state, throws)
219
266
  }
@@ -267,7 +314,7 @@ module.exports = ({ ds, ...options }) => {
267
314
  _refreshNT(self) {
268
315
  self._refreshing = false
269
316
 
270
- if (self._destroyed || self._disposing || !self._ready) {
317
+ if (self._destroyed || self._disposing || self._args === kEmpty) {
271
318
  return
272
319
  }
273
320
 
@@ -276,6 +323,10 @@ module.exports = ({ ds, ...options }) => {
276
323
  // TODO (fix): freeze?
277
324
  self._context.$ = self._args
278
325
  self._context.nxt = self
326
+
327
+ const previous = compiler.current
328
+ compiler.current = self
329
+
279
330
  try {
280
331
  const value = self._script.runInContext(self._context)
281
332
  if (value !== self._value) {
@@ -294,6 +345,8 @@ module.exports = ({ ds, ...options }) => {
294
345
  })
295
346
  )
296
347
  } finally {
348
+ compiler.current = previous
349
+
297
350
  self._context.$ = null
298
351
  self._context.nxt = null
299
352
 
@@ -321,7 +374,7 @@ module.exports = ({ ds, ...options }) => {
321
374
  }
322
375
 
323
376
  _refresh = () => {
324
- if (this._refreshing || this._destroyed || this._disposing || !this._ready) {
377
+ if (this._refreshing || this._destroyed || this._disposing || this._args === kEmpty) {
325
378
  return
326
379
  }
327
380
 
@@ -381,6 +434,28 @@ module.exports = ({ ds, ...options }) => {
381
434
  return entry.value
382
435
  }
383
436
 
437
+ _getWait(promise, throws) {
438
+ if (typeof promise?.then !== 'function') {
439
+ throw new Error(`invalid argument: Promise (${promise})`)
440
+ }
441
+
442
+ const entry = this._getEntry(promise, PromiseEntry, promise)
443
+
444
+ if (entry.error) {
445
+ throw entry.error
446
+ }
447
+
448
+ if (entry.value === kEmpty) {
449
+ if (throws ?? true) {
450
+ throw kSuspend
451
+ } else {
452
+ return null
453
+ }
454
+ }
455
+
456
+ return entry.value
457
+ }
458
+
384
459
  _getRecord(key, state, throws) {
385
460
  if (!key || typeof key !== 'string') {
386
461
  throw new Error(`invalid argument: key (${key})`)