@nxtedition/lib 23.10.5 → 23.11.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.
- package/app.js +4 -4
- package/http.js +1 -1
- package/package.json +1 -1
- package/util/template/index-common.d.ts +65 -0
- package/util/template/index-common.js +253 -0
- package/util/template/index-web.d.ts +1 -0
- package/util/template/index-web.js +28 -0
- package/util/template/index.d.ts +1 -58
- package/util/template/index.js +31 -250
- package/util/template/javascript.js +13 -14
- package/util/template/nextpressions.js +5 -7
- package/util/template/transform.js +1 -16
- package/util/template/transform.test.js +9 -0
package/app.js
CHANGED
|
@@ -480,13 +480,13 @@ export function makeApp(appConfig, onTerminate) {
|
|
|
480
480
|
compiler = makeTemplateCompiler({ ds, logger, ...appConfig.compiler })
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
-
const undiciDefaults = {
|
|
483
|
+
const undiciDefaults = Object.freeze({
|
|
484
484
|
connected: 0,
|
|
485
485
|
disconnected: 0,
|
|
486
486
|
connections: 0,
|
|
487
|
-
}
|
|
487
|
+
})
|
|
488
488
|
|
|
489
|
-
const undici$ = new rxjs.BehaviorSubject(undiciDefaults)
|
|
489
|
+
const undici$ = new rxjs.BehaviorSubject({ ...undiciDefaults })
|
|
490
490
|
{
|
|
491
491
|
function onConnect(origin, targets) {
|
|
492
492
|
const stats = { ...undici$.value }
|
|
@@ -517,7 +517,7 @@ export function makeApp(appConfig, onTerminate) {
|
|
|
517
517
|
currentDispatcher = null
|
|
518
518
|
}
|
|
519
519
|
|
|
520
|
-
undici$.next(undiciDefaults)
|
|
520
|
+
undici$.next({ ...undiciDefaults })
|
|
521
521
|
|
|
522
522
|
nextDispatcher.on('connect', onConnect).on('disconnect', onDisconnect)
|
|
523
523
|
|
package/http.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { FirstValueFromConfig } from 'rxjs/internal/firstValueFrom'
|
|
2
|
+
import type * as rx from 'rxjs'
|
|
3
|
+
import { DeepstreamClient } from '@nxtedition/deepstream.io-client-js'
|
|
4
|
+
|
|
5
|
+
export interface MakeTemplateCompilerParams {
|
|
6
|
+
ds?: DeepstreamClient
|
|
7
|
+
proxify?: unknown
|
|
8
|
+
logger?: unknown
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function makeTemplateCompiler(params: MakeTemplateCompilerParams): TemplateCompiler
|
|
12
|
+
|
|
13
|
+
export interface TemplateCompiler {
|
|
14
|
+
current: null
|
|
15
|
+
|
|
16
|
+
resolveTemplate: <ReturnValue, Context>(
|
|
17
|
+
template: Nxtpression<ReturnValue, Context> | string,
|
|
18
|
+
args$?: Context | rx.Observable<Context>,
|
|
19
|
+
options?: FirstValueFromConfig,
|
|
20
|
+
) => Promise<ResolveNxtpressionDeep<Nxtpression<ReturnValue, Context>>>
|
|
21
|
+
|
|
22
|
+
onResolveTemplate: <ReturnValue, Context>(
|
|
23
|
+
template: Nxtpression<ReturnValue, Context> | string,
|
|
24
|
+
args$?: Context | rx.Observable<Context>,
|
|
25
|
+
) => rx.Observable<ResolveNxtpressionDeep<Nxtpression<ReturnValue, Context>>>
|
|
26
|
+
|
|
27
|
+
compileTemplate: <ReturnValue, Context>(
|
|
28
|
+
template: Nxtpression<ReturnValue, Context> | string,
|
|
29
|
+
) => null | ((args$?: Context | rx.Observable<Context>) => rx.Observable<ReturnValue>)
|
|
30
|
+
|
|
31
|
+
isTemplate: (value: unknown) => value is Nxtpression
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type Nxtpression<ReturnValue = string, Context extends object = object> =
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-wrapper-object-types
|
|
36
|
+
| (String & {
|
|
37
|
+
/**
|
|
38
|
+
* TS-HACK: this property doesn't really exist on the nxtpression string,
|
|
39
|
+
* it is only here to make sure the generic Context won't get stripped.
|
|
40
|
+
*/
|
|
41
|
+
__context: Context
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* TS-HACK: this property doesn't really exist on the nxtpression string,
|
|
45
|
+
* it is only here to make sure the generic Context won't get stripped.
|
|
46
|
+
*/
|
|
47
|
+
__returnValue: ReturnValue
|
|
48
|
+
})
|
|
49
|
+
| string
|
|
50
|
+
| ReturnValue
|
|
51
|
+
|
|
52
|
+
export type ResolveNxtpressionDeep<T> =
|
|
53
|
+
ExtractReturn<T> extends never
|
|
54
|
+
? T extends Array<infer U>
|
|
55
|
+
? ResolveNxtpressionDeep<U>
|
|
56
|
+
: T extends object
|
|
57
|
+
? {
|
|
58
|
+
[K in keyof T]: ResolveNxtpressionDeep<T[K]>
|
|
59
|
+
}
|
|
60
|
+
: T
|
|
61
|
+
: ExtractReturn<T>
|
|
62
|
+
type TypeWithReturn<X> = {
|
|
63
|
+
__returnValue: X
|
|
64
|
+
}
|
|
65
|
+
type ExtractReturn<Type> = Type extends TypeWithReturn<infer X> ? X : never
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import * as rxjs from 'rxjs'
|
|
2
|
+
import fp from 'lodash/fp.js'
|
|
3
|
+
import getNxtpressionsCompiler from './nextpressions.js'
|
|
4
|
+
import getJavascriptCompiler from './javascript.js'
|
|
5
|
+
import JSON5 from 'json5'
|
|
6
|
+
import objectHash from 'object-hash'
|
|
7
|
+
import { makeWeakCache } from '../../weakCache.js'
|
|
8
|
+
import firstValueFrom from '../../rxjs/firstValueFrom.js'
|
|
9
|
+
|
|
10
|
+
export function makeTemplateCompiler({ ds, proxify, logger, sha512, fetch }) {
|
|
11
|
+
const compiler = {
|
|
12
|
+
current: null,
|
|
13
|
+
resolveTemplate,
|
|
14
|
+
onResolveTemplate,
|
|
15
|
+
compileTemplate,
|
|
16
|
+
isTemplate,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const compilers = {
|
|
20
|
+
nxt: getNxtpressionsCompiler({ ds, logger, sha512 }),
|
|
21
|
+
js: getJavascriptCompiler({ ds, proxify, compiler, logger, fetch }),
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function inner(str) {
|
|
25
|
+
const templateStart = str.lastIndexOf('{{')
|
|
26
|
+
if (templateStart === -1) {
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
let bodyStart = templateStart + 2
|
|
30
|
+
|
|
31
|
+
let templateEnd = str.indexOf('}}', templateStart + 2)
|
|
32
|
+
if (templateEnd === -1) {
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
const bodyEnd = templateEnd
|
|
36
|
+
templateEnd += 2
|
|
37
|
+
|
|
38
|
+
let type = 'nxt'
|
|
39
|
+
if (str[bodyStart] === '#') {
|
|
40
|
+
type = str.slice(bodyStart + 1).match(/^([a-z]*)/)[1]
|
|
41
|
+
bodyStart += type.length + 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
input: str,
|
|
46
|
+
pre: str.slice(0, templateStart),
|
|
47
|
+
type,
|
|
48
|
+
body: str.slice(bodyStart, bodyEnd),
|
|
49
|
+
post: str.slice(templateEnd),
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const hashTemplate = (template, prefix) => {
|
|
54
|
+
if (typeof template === 'string') {
|
|
55
|
+
return isTemplate(template) ? objectHash([prefix, template]) : ''
|
|
56
|
+
} else if (fp.isPlainObject(template)) {
|
|
57
|
+
let hashes
|
|
58
|
+
for (const key of Object.keys(template)) {
|
|
59
|
+
const hash = hashTemplate(template[key], key)
|
|
60
|
+
if (hash) {
|
|
61
|
+
hashes ??= []
|
|
62
|
+
hashes.push(hash)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return hashes ? objectHash([prefix, hashes]) : ''
|
|
66
|
+
} else if (fp.isArray(template)) {
|
|
67
|
+
let hashes
|
|
68
|
+
for (let idx = 0; idx < template.length; idx++) {
|
|
69
|
+
const hash = hashTemplate(template[idx], idx)
|
|
70
|
+
if (hash) {
|
|
71
|
+
hashes ??= []
|
|
72
|
+
hashes.push(hash)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return hashes ? objectHash([prefix, hashes]) : ''
|
|
76
|
+
} else {
|
|
77
|
+
return ''
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function compileArrayTemplate(template) {
|
|
82
|
+
let resolvers
|
|
83
|
+
let indices
|
|
84
|
+
|
|
85
|
+
for (let i = 0; i < template.length; i++) {
|
|
86
|
+
const resolver = _compileTemplate(template[i])
|
|
87
|
+
if (resolver) {
|
|
88
|
+
resolvers ??= []
|
|
89
|
+
resolvers.push(resolver)
|
|
90
|
+
indices ??= []
|
|
91
|
+
indices.push(i)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return resolvers
|
|
96
|
+
? (arr, args$) => {
|
|
97
|
+
const len = resolvers.length
|
|
98
|
+
const values = new Array(len)
|
|
99
|
+
for (let n = 0; n < len; n++) {
|
|
100
|
+
values[n] = resolvers[n](arr[indices[n]], args$)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return rxjs.combineLatest(values).pipe(
|
|
104
|
+
rxjs.map((values) => {
|
|
105
|
+
const ret = [...arr]
|
|
106
|
+
for (let n = 0; n < values.length; n++) {
|
|
107
|
+
ret[indices[n]] = values[n]
|
|
108
|
+
}
|
|
109
|
+
return ret
|
|
110
|
+
}),
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
: null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function compileObjectTemplate(template) {
|
|
117
|
+
let resolvers
|
|
118
|
+
let indices
|
|
119
|
+
|
|
120
|
+
const keys = Object.keys(template)
|
|
121
|
+
|
|
122
|
+
for (let i = 0; i < keys.length; i++) {
|
|
123
|
+
const resolver = _compileTemplate(template[keys[i]])
|
|
124
|
+
if (resolver) {
|
|
125
|
+
resolvers ??= []
|
|
126
|
+
resolvers.push(resolver)
|
|
127
|
+
indices ??= []
|
|
128
|
+
indices.push(keys[i])
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return resolvers
|
|
133
|
+
? (obj, args$) => {
|
|
134
|
+
const len = resolvers.length
|
|
135
|
+
const values = new Array(len)
|
|
136
|
+
for (let n = 0; n < len; n++) {
|
|
137
|
+
values[n] = resolvers[n](obj[indices[n]], args$)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return rxjs.combineLatest(values).pipe(
|
|
141
|
+
rxjs.map((values) => {
|
|
142
|
+
const ret = { ...obj }
|
|
143
|
+
for (let n = 0; n < values.length; n++) {
|
|
144
|
+
ret[indices[n]] = values[n]
|
|
145
|
+
}
|
|
146
|
+
return ret
|
|
147
|
+
}),
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
: null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function compileStringTemplate(template) {
|
|
154
|
+
const match = inner(template)
|
|
155
|
+
if (!match) {
|
|
156
|
+
return null
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const { pre, type, body, post } = match
|
|
160
|
+
|
|
161
|
+
if (type === 'js') {
|
|
162
|
+
const expr = compilers.js(body)
|
|
163
|
+
|
|
164
|
+
if (!pre && !post) {
|
|
165
|
+
return (str, args$) => expr(args$)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return (str, args$) =>
|
|
169
|
+
rxjs
|
|
170
|
+
.combineLatest([
|
|
171
|
+
compileStringTemplate(pre)?.(str, args$) ?? rxjs.of(pre),
|
|
172
|
+
expr(args$),
|
|
173
|
+
compileStringTemplate(post)?.(str, args$) ?? rxjs.of(post),
|
|
174
|
+
])
|
|
175
|
+
.pipe(
|
|
176
|
+
rxjs.map(([pre, body, post]) =>
|
|
177
|
+
pre || post ? `${pre}${stringify(body)}${post}` : body,
|
|
178
|
+
),
|
|
179
|
+
)
|
|
180
|
+
} else if (type === 'nxt') {
|
|
181
|
+
const expr = compilers.nxt(body)
|
|
182
|
+
|
|
183
|
+
if (!pre && !post) {
|
|
184
|
+
return (str, args$) => expr(args$)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return (str, args$) =>
|
|
188
|
+
expr(args$).pipe(
|
|
189
|
+
rxjs.switchMap((body) =>
|
|
190
|
+
onResolveTemplate(`${pre}${stringify(body, true)}${post}`, args$),
|
|
191
|
+
),
|
|
192
|
+
)
|
|
193
|
+
} else {
|
|
194
|
+
throw new Error('unknown expression type: ' + type)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function stringify(value, escape) {
|
|
199
|
+
if (value == null) {
|
|
200
|
+
return ''
|
|
201
|
+
} else if (fp.isArray(value) || fp.isPlainObject(value)) {
|
|
202
|
+
return JSON5.stringify(value)
|
|
203
|
+
} else if (fp.isString(value) && escape) {
|
|
204
|
+
return value.replace(/"/g, '\\"')
|
|
205
|
+
}
|
|
206
|
+
return value
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function isTemplate(val) {
|
|
210
|
+
return typeof val === 'string' && val.indexOf('{{') !== -1
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const _compileTemplateCache = makeWeakCache(
|
|
214
|
+
(template) => {
|
|
215
|
+
if (fp.isPlainObject(template)) {
|
|
216
|
+
return compileObjectTemplate(template)
|
|
217
|
+
} else if (fp.isArray(template)) {
|
|
218
|
+
return compileArrayTemplate(template)
|
|
219
|
+
} else if (isTemplate(template)) {
|
|
220
|
+
return compileStringTemplate(template)
|
|
221
|
+
} else {
|
|
222
|
+
return null
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
(template, hash) => hash,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
function _compileTemplate(template) {
|
|
229
|
+
const hash = hashTemplate(template)
|
|
230
|
+
const resolver = hash ? _compileTemplateCache(template, hash) : null
|
|
231
|
+
return resolver // ? (args$) => resolver(template, args$) : null
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function compileTemplate(template) {
|
|
235
|
+
const resolver = _compileTemplate(template)
|
|
236
|
+
return resolver ? (args$) => resolver(template, args$) : null
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function resolveTemplate(template, args$, options) {
|
|
240
|
+
const expr = _compileTemplate(template)
|
|
241
|
+
return expr ? firstValueFrom(expr(template, args$), options) : template
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function onResolveTemplate(template, args$) {
|
|
245
|
+
try {
|
|
246
|
+
return _compileTemplate(template)?.(template, args$) ?? rxjs.of(template)
|
|
247
|
+
} catch (err) {
|
|
248
|
+
return rxjs.throwError(() => err)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return compiler
|
|
253
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index-common.d.ts'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import init from '@swc/wasm-web'
|
|
2
|
+
import { makeTemplateCompiler as commonMakeTemplateCompiler } from './index-common.js'
|
|
3
|
+
|
|
4
|
+
await init()
|
|
5
|
+
|
|
6
|
+
export function makeTemplateCompiler({ ds, proxify, logger = console }) {
|
|
7
|
+
return commonMakeTemplateCompiler({
|
|
8
|
+
ds,
|
|
9
|
+
proxify,
|
|
10
|
+
logger,
|
|
11
|
+
sha512: (data) => {
|
|
12
|
+
throw new Error('sha512 is not supported')
|
|
13
|
+
},
|
|
14
|
+
fetch: async (resource, options) => {
|
|
15
|
+
// eslint-disable-next-line no-undef
|
|
16
|
+
const res = await window.fetch(resource, options)
|
|
17
|
+
return {
|
|
18
|
+
statusCode: res.status,
|
|
19
|
+
headers: Object.fromEntries(res.headers.entries()),
|
|
20
|
+
body: {
|
|
21
|
+
text: async () => {
|
|
22
|
+
return await res.text()
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
}
|
package/util/template/index.d.ts
CHANGED
|
@@ -1,58 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type * as rx from 'rxjs'
|
|
3
|
-
|
|
4
|
-
export function makeTemplateCompiler(params: MakeTemplateCompilerParams): TemplateCompiler
|
|
5
|
-
|
|
6
|
-
export interface TemplateCompiler {
|
|
7
|
-
current: null
|
|
8
|
-
|
|
9
|
-
resolveTemplate: <ReturnValue, Context>(
|
|
10
|
-
template: Nxtpression<ReturnValue, Context> | string,
|
|
11
|
-
args$?: Context | rx.Observable<Context>,
|
|
12
|
-
options?: FirstValueFromConfig,
|
|
13
|
-
) => Promise<ResolveNxtpressionDeep<Nxtpression<ReturnValue, Context>>>
|
|
14
|
-
|
|
15
|
-
onResolveTemplate: <ReturnValue, Context>(
|
|
16
|
-
template: Nxtpression<ReturnValue, Context> | string,
|
|
17
|
-
args$?: Context | rx.Observable<Context>,
|
|
18
|
-
) => rx.Observable<ResolveNxtpressionDeep<Nxtpression<ReturnValue, Context>>>
|
|
19
|
-
|
|
20
|
-
compileTemplate: <ReturnValue, Context>(
|
|
21
|
-
template: Nxtpression<ReturnValue, Context> | string,
|
|
22
|
-
) => null | ((args$?: Context | rx.Observable<Context>) => rx.Observable<ReturnValue>)
|
|
23
|
-
|
|
24
|
-
isTemplate: (value: unknown) => value is Nxtpression
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type Nxtpression<ReturnValue = string, Context extends object = object> =
|
|
28
|
-
// eslint-disable-next-line @typescript-eslint/no-wrapper-object-types
|
|
29
|
-
| (String & {
|
|
30
|
-
/**
|
|
31
|
-
* TS-HACK: this property doesn't really exist on the nxtpression string,
|
|
32
|
-
* it is only here to make sure the generic Context won't get stripped.
|
|
33
|
-
*/
|
|
34
|
-
__context: Context
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* TS-HACK: this property doesn't really exist on the nxtpression string,
|
|
38
|
-
* it is only here to make sure the generic Context won't get stripped.
|
|
39
|
-
*/
|
|
40
|
-
__returnValue: ReturnValue
|
|
41
|
-
})
|
|
42
|
-
| string
|
|
43
|
-
| ReturnValue
|
|
44
|
-
|
|
45
|
-
export type ResolveNxtpressionDeep<T> =
|
|
46
|
-
ExtractReturn<T> extends never
|
|
47
|
-
? T extends Array<infer U>
|
|
48
|
-
? ResolveNxtpressionDeep<U>
|
|
49
|
-
: T extends object
|
|
50
|
-
? {
|
|
51
|
-
[K in keyof T]: ResolveNxtpressionDeep<T[K]>
|
|
52
|
-
}
|
|
53
|
-
: T
|
|
54
|
-
: ExtractReturn<T>
|
|
55
|
-
type TypeWithReturn<X> = {
|
|
56
|
-
__returnValue: X
|
|
57
|
-
}
|
|
58
|
-
type ExtractReturn<Type> = Type extends TypeWithReturn<infer X> ? X : never
|
|
1
|
+
export * from './index-common.d.ts'
|
package/util/template/index.js
CHANGED
|
@@ -1,253 +1,34 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function inner(str) {
|
|
25
|
-
const templateStart = str.lastIndexOf('{{')
|
|
26
|
-
if (templateStart === -1) {
|
|
27
|
-
return null
|
|
28
|
-
}
|
|
29
|
-
let bodyStart = templateStart + 2
|
|
30
|
-
|
|
31
|
-
let templateEnd = str.indexOf('}}', templateStart + 2)
|
|
32
|
-
if (templateEnd === -1) {
|
|
33
|
-
return null
|
|
34
|
-
}
|
|
35
|
-
const bodyEnd = templateEnd
|
|
36
|
-
templateEnd += 2
|
|
37
|
-
|
|
38
|
-
let type = 'nxt'
|
|
39
|
-
if (str[bodyStart] === '#') {
|
|
40
|
-
type = str.slice(bodyStart + 1).match(/^([a-z]*)/)[1]
|
|
41
|
-
bodyStart += type.length + 1
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
input: str,
|
|
46
|
-
pre: str.slice(0, templateStart),
|
|
47
|
-
type,
|
|
48
|
-
body: str.slice(bodyStart, bodyEnd),
|
|
49
|
-
post: str.slice(templateEnd),
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const hashTemplate = (template, prefix) => {
|
|
54
|
-
if (typeof template === 'string') {
|
|
55
|
-
return isTemplate(template) ? objectHash([prefix, template]) : ''
|
|
56
|
-
} else if (fp.isPlainObject(template)) {
|
|
57
|
-
let hashes
|
|
58
|
-
for (const key of Object.keys(template)) {
|
|
59
|
-
const hash = hashTemplate(template[key], key)
|
|
60
|
-
if (hash) {
|
|
61
|
-
hashes ??= []
|
|
62
|
-
hashes.push(hash)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return hashes ? objectHash([prefix, hashes]) : ''
|
|
66
|
-
} else if (fp.isArray(template)) {
|
|
67
|
-
let hashes
|
|
68
|
-
for (let idx = 0; idx < template.length; idx++) {
|
|
69
|
-
const hash = hashTemplate(template[idx], idx)
|
|
70
|
-
if (hash) {
|
|
71
|
-
hashes ??= []
|
|
72
|
-
hashes.push(hash)
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return hashes ? objectHash([prefix, hashes]) : ''
|
|
76
|
-
} else {
|
|
77
|
-
return ''
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function compileArrayTemplate(template) {
|
|
82
|
-
let resolvers
|
|
83
|
-
let indices
|
|
84
|
-
|
|
85
|
-
for (let i = 0; i < template.length; i++) {
|
|
86
|
-
const resolver = _compileTemplate(template[i])
|
|
87
|
-
if (resolver) {
|
|
88
|
-
resolvers ??= []
|
|
89
|
-
resolvers.push(resolver)
|
|
90
|
-
indices ??= []
|
|
91
|
-
indices.push(i)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return resolvers
|
|
96
|
-
? (arr, args$) => {
|
|
97
|
-
const len = resolvers.length
|
|
98
|
-
const values = new Array(len)
|
|
99
|
-
for (let n = 0; n < len; n++) {
|
|
100
|
-
values[n] = resolvers[n](arr[indices[n]], args$)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return rxjs.combineLatest(values).pipe(
|
|
104
|
-
rxjs.map((values) => {
|
|
105
|
-
const ret = [...arr]
|
|
106
|
-
for (let n = 0; n < values.length; n++) {
|
|
107
|
-
ret[indices[n]] = values[n]
|
|
108
|
-
}
|
|
109
|
-
return ret
|
|
110
|
-
}),
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
: null
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function compileObjectTemplate(template) {
|
|
117
|
-
let resolvers
|
|
118
|
-
let indices
|
|
119
|
-
|
|
120
|
-
const keys = Object.keys(template)
|
|
121
|
-
|
|
122
|
-
for (let i = 0; i < keys.length; i++) {
|
|
123
|
-
const resolver = _compileTemplate(template[keys[i]])
|
|
124
|
-
if (resolver) {
|
|
125
|
-
resolvers ??= []
|
|
126
|
-
resolvers.push(resolver)
|
|
127
|
-
indices ??= []
|
|
128
|
-
indices.push(keys[i])
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return resolvers
|
|
133
|
-
? (obj, args$) => {
|
|
134
|
-
const len = resolvers.length
|
|
135
|
-
const values = new Array(len)
|
|
136
|
-
for (let n = 0; n < len; n++) {
|
|
137
|
-
values[n] = resolvers[n](obj[indices[n]], args$)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return rxjs.combineLatest(values).pipe(
|
|
141
|
-
rxjs.map((values) => {
|
|
142
|
-
const ret = { ...obj }
|
|
143
|
-
for (let n = 0; n < values.length; n++) {
|
|
144
|
-
ret[indices[n]] = values[n]
|
|
145
|
-
}
|
|
146
|
-
return ret
|
|
147
|
-
}),
|
|
148
|
-
)
|
|
149
|
-
}
|
|
150
|
-
: null
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function compileStringTemplate(template) {
|
|
154
|
-
const match = inner(template)
|
|
155
|
-
if (!match) {
|
|
156
|
-
return null
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const { pre, type, body, post } = match
|
|
160
|
-
|
|
161
|
-
if (type === 'js') {
|
|
162
|
-
const expr = compilers.js(body)
|
|
163
|
-
|
|
164
|
-
if (!pre && !post) {
|
|
165
|
-
return (str, args$) => expr(args$)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return (str, args$) =>
|
|
169
|
-
rxjs
|
|
170
|
-
.combineLatest([
|
|
171
|
-
compileStringTemplate(pre)?.(str, args$) ?? rxjs.of(pre),
|
|
172
|
-
expr(args$),
|
|
173
|
-
compileStringTemplate(post)?.(str, args$) ?? rxjs.of(post),
|
|
174
|
-
])
|
|
175
|
-
.pipe(
|
|
176
|
-
rxjs.map(([pre, body, post]) =>
|
|
177
|
-
pre || post ? `${pre}${stringify(body)}${post}` : body,
|
|
178
|
-
),
|
|
179
|
-
)
|
|
180
|
-
} else if (type === 'nxt') {
|
|
181
|
-
const expr = compilers.nxt(body)
|
|
182
|
-
|
|
183
|
-
if (!pre && !post) {
|
|
184
|
-
return (str, args$) => expr(args$)
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return (str, args$) =>
|
|
188
|
-
expr(args$).pipe(
|
|
189
|
-
rxjs.switchMap((body) =>
|
|
190
|
-
onResolveTemplate(`${pre}${stringify(body, true)}${post}`, args$),
|
|
191
|
-
),
|
|
192
|
-
)
|
|
193
|
-
} else {
|
|
194
|
-
throw new Error('unknown expression type: ' + type)
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function stringify(value, escape) {
|
|
199
|
-
if (value == null) {
|
|
200
|
-
return ''
|
|
201
|
-
} else if (fp.isArray(value) || fp.isPlainObject(value)) {
|
|
202
|
-
return JSON5.stringify(value)
|
|
203
|
-
} else if (fp.isString(value) && escape) {
|
|
204
|
-
return value.replace(/"/g, '\\"')
|
|
205
|
-
}
|
|
206
|
-
return value
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function isTemplate(val) {
|
|
210
|
-
return typeof val === 'string' && val.indexOf('{{') !== -1
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const _compileTemplateCache = makeWeakCache(
|
|
214
|
-
(template) => {
|
|
215
|
-
if (fp.isPlainObject(template)) {
|
|
216
|
-
return compileObjectTemplate(template)
|
|
217
|
-
} else if (fp.isArray(template)) {
|
|
218
|
-
return compileArrayTemplate(template)
|
|
219
|
-
} else if (isTemplate(template)) {
|
|
220
|
-
return compileStringTemplate(template)
|
|
221
|
-
} else {
|
|
222
|
-
return null
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
(template, hash) => hash,
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
function _compileTemplate(template) {
|
|
229
|
-
const hash = hashTemplate(template)
|
|
230
|
-
const resolver = hash ? _compileTemplateCache(template, hash) : null
|
|
231
|
-
return resolver // ? (args$) => resolver(template, args$) : null
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function compileTemplate(template) {
|
|
235
|
-
const resolver = _compileTemplate(template)
|
|
236
|
-
return resolver ? (args$) => resolver(template, args$) : null
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function resolveTemplate(template, args$, options) {
|
|
240
|
-
const expr = _compileTemplate(template)
|
|
241
|
-
return expr ? firstValueFrom(expr(template, args$), options) : template
|
|
242
|
-
}
|
|
1
|
+
import { createRequire } from 'node:module'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { initSync } from '@swc/wasm-web'
|
|
4
|
+
import { makeTemplateCompiler as commonMakeTemplateCompiler } from './index-common.js'
|
|
5
|
+
import { hashSync } from 'hasha'
|
|
6
|
+
import { request, Agent } from '@nxtedition/nxt-undici'
|
|
7
|
+
|
|
8
|
+
export * from './index-common.js'
|
|
9
|
+
|
|
10
|
+
const require = createRequire(import.meta.url)
|
|
11
|
+
const wasmPath = require.resolve('@swc/wasm-web').replace('wasm.js', 'wasm_bg.wasm')
|
|
12
|
+
const wasmBuffer = readFileSync(wasmPath)
|
|
13
|
+
|
|
14
|
+
initSync({ module: wasmBuffer })
|
|
15
|
+
|
|
16
|
+
export function makeTemplateCompiler({ logger = globalThis.__nxt_lib_app?.logger, ...args }) {
|
|
17
|
+
return commonMakeTemplateCompiler({
|
|
18
|
+
...args,
|
|
19
|
+
logger,
|
|
20
|
+
sha256: (data) => hashSync(data),
|
|
21
|
+
fetch,
|
|
22
|
+
})
|
|
23
|
+
}
|
|
243
24
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
} catch (err) {
|
|
248
|
-
return rxjs.throwError(() => err)
|
|
249
|
-
}
|
|
250
|
-
}
|
|
25
|
+
const fetchClient = new Agent({
|
|
26
|
+
connections: 128,
|
|
27
|
+
})
|
|
251
28
|
|
|
252
|
-
|
|
29
|
+
function fetch(resource, options) {
|
|
30
|
+
return request(resource, {
|
|
31
|
+
...options,
|
|
32
|
+
dispatcher: fetchClient,
|
|
33
|
+
})
|
|
253
34
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
1
|
import { makeWeakCache } from '../../weakCache.js'
|
|
3
2
|
import * as rxjs from 'rxjs'
|
|
4
3
|
import objectHash from 'object-hash'
|
|
5
4
|
import * as datefns from 'date-fns'
|
|
6
5
|
import JSON5 from 'json5'
|
|
7
|
-
import { request, Agent } from '@nxtedition/nxt-undici'
|
|
8
6
|
import fp from 'lodash/fp.js'
|
|
9
7
|
import moment from 'moment-timezone'
|
|
10
8
|
import Timecode from 'smpte-timecode'
|
|
@@ -30,12 +28,8 @@ class TimerEntry {
|
|
|
30
28
|
}
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
const fetchClient = new Agent({
|
|
34
|
-
connections: 128,
|
|
35
|
-
})
|
|
36
|
-
|
|
37
31
|
class FetchEntry {
|
|
38
|
-
constructor(key, refresh, { resource, options }) {
|
|
32
|
+
constructor(key, refresh, { resource, options, fetch }) {
|
|
39
33
|
this.key = key
|
|
40
34
|
this.counter = -1
|
|
41
35
|
this.ac = new AbortController()
|
|
@@ -57,12 +51,11 @@ class FetchEntry {
|
|
|
57
51
|
}
|
|
58
52
|
|
|
59
53
|
try {
|
|
60
|
-
|
|
54
|
+
fetch(resource, {
|
|
61
55
|
...options,
|
|
62
56
|
headers,
|
|
63
57
|
body,
|
|
64
58
|
signal: this.ac.signal,
|
|
65
|
-
dispatcher: fetchClient,
|
|
66
59
|
})
|
|
67
60
|
.then(async (res) => {
|
|
68
61
|
// TODO (fix): Check cache-control and invalidate entry...
|
|
@@ -202,8 +195,12 @@ class PromiseEntry {
|
|
|
202
195
|
}
|
|
203
196
|
|
|
204
197
|
function proxify(value, expression, handler, suspend = true) {
|
|
205
|
-
|
|
206
|
-
|
|
198
|
+
if (!expression) {
|
|
199
|
+
throw new Error('expression is not defined')
|
|
200
|
+
}
|
|
201
|
+
if (!handler) {
|
|
202
|
+
throw new Error('handler is not defined')
|
|
203
|
+
}
|
|
207
204
|
|
|
208
205
|
if (!value) {
|
|
209
206
|
return value
|
|
@@ -225,7 +222,7 @@ function makeWrapper(expression) {
|
|
|
225
222
|
return (value, suspend = true) => proxify(value, expression, handler, suspend)
|
|
226
223
|
}
|
|
227
224
|
|
|
228
|
-
export default function ({ ds, proxify, compiler, logger }) {
|
|
225
|
+
export default function ({ ds, proxify, compiler, logger, fetch: fetchFn }) {
|
|
229
226
|
class Expression {
|
|
230
227
|
constructor(script, expression, args, observer) {
|
|
231
228
|
this._expression = expression
|
|
@@ -358,7 +355,9 @@ export default function ({ ds, proxify, compiler, logger }) {
|
|
|
358
355
|
compiler.current = this
|
|
359
356
|
|
|
360
357
|
try {
|
|
361
|
-
|
|
358
|
+
if (this._suspended !== false) {
|
|
359
|
+
throw new Error('expression is already suspended')
|
|
360
|
+
}
|
|
362
361
|
|
|
363
362
|
const savedThis = {
|
|
364
363
|
fp: globalThis.fp,
|
|
@@ -469,7 +468,7 @@ export default function ({ ds, proxify, compiler, logger }) {
|
|
|
469
468
|
|
|
470
469
|
_getFetch(resource, options, suspend) {
|
|
471
470
|
const key = JSON.stringify({ resource, options })
|
|
472
|
-
const entry = this._getEntry(key, FetchEntry, { resource, options })
|
|
471
|
+
const entry = this._getEntry(key, FetchEntry, { resource, options, fetch: fetchFn })
|
|
473
472
|
|
|
474
473
|
if (entry.refresh === null) {
|
|
475
474
|
return null
|
|
@@ -2,8 +2,6 @@ import moment from 'moment-timezone'
|
|
|
2
2
|
import * as rxjs from 'rxjs'
|
|
3
3
|
import JSON5 from 'json5'
|
|
4
4
|
import fp from 'lodash/fp.js'
|
|
5
|
-
import NestedError from 'nested-error-stacks'
|
|
6
|
-
import { hashSync } from 'hasha'
|
|
7
5
|
import split from 'split-string'
|
|
8
6
|
import { makeWeakCache } from '../../weakCache.js'
|
|
9
7
|
|
|
@@ -27,7 +25,7 @@ function asFilter(transform, predicate, obj) {
|
|
|
27
25
|
)
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
export default function ({ ds, logger } = {}) {
|
|
28
|
+
export default function ({ ds, logger, sha512 } = {}) {
|
|
31
29
|
const FILTERS = {
|
|
32
30
|
// any
|
|
33
31
|
...asFilter(null, null, {
|
|
@@ -87,9 +85,9 @@ export default function ({ ds, logger } = {}) {
|
|
|
87
85
|
isString: () => (value) => fp.isString(value),
|
|
88
86
|
ternary: (a, b) => (value) => (value ? a : b),
|
|
89
87
|
cond: (a, b) => (value) => (value ? a : b),
|
|
90
|
-
hasha: (options) => (value) =>
|
|
88
|
+
hasha: (options) => (value) => sha512(JSON.stringify(value), options || {}),
|
|
91
89
|
hashaint: (options) => (value) =>
|
|
92
|
-
parseInt(
|
|
90
|
+
parseInt(sha512(JSON.stringify(value), options || {}).slice(-13), 16),
|
|
93
91
|
return: () => (value) => value || RETURN,
|
|
94
92
|
add:
|
|
95
93
|
(...args) =>
|
|
@@ -522,7 +520,7 @@ export default function ({ ds, logger } = {}) {
|
|
|
522
520
|
}
|
|
523
521
|
return x ? JSON5.parse(x) : x
|
|
524
522
|
} catch (err) {
|
|
525
|
-
throw new
|
|
523
|
+
throw new Error(`failed to parse token ${x}`, { cuase: err })
|
|
526
524
|
}
|
|
527
525
|
})
|
|
528
526
|
|
|
@@ -596,7 +594,7 @@ export default function ({ ds, logger } = {}) {
|
|
|
596
594
|
}),
|
|
597
595
|
)
|
|
598
596
|
} catch (err) {
|
|
599
|
-
throw new
|
|
597
|
+
throw new Error(`failed to parse expression ${expression}`, { cause: err })
|
|
600
598
|
}
|
|
601
599
|
})
|
|
602
600
|
}
|
|
@@ -1,19 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { readFileSync } from 'node:fs'
|
|
3
|
-
import { parseSync, printSync, initSync } from '@swc/wasm-web'
|
|
4
|
-
import init from '@swc/wasm-web'
|
|
5
|
-
|
|
6
|
-
const isNode = typeof process !== 'undefined' && process.toString() === '[object process]'
|
|
7
|
-
|
|
8
|
-
if (isNode) {
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
const wasmPath = require.resolve('@swc/wasm-web').replace('wasm.js', 'wasm_bg.wasm')
|
|
11
|
-
const wasmBuffer = readFileSync(wasmPath)
|
|
12
|
-
|
|
13
|
-
initSync({ module: wasmBuffer })
|
|
14
|
-
} else {
|
|
15
|
-
await init()
|
|
16
|
-
}
|
|
1
|
+
import { parseSync, printSync } from '@swc/wasm-web'
|
|
17
2
|
|
|
18
3
|
export default function (code) {
|
|
19
4
|
const ast = parseSync(code, { syntax: 'ecmascript', script: true })
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { test } from 'node:test'
|
|
2
2
|
import assert from 'node:assert'
|
|
3
3
|
import transform from './transform.js'
|
|
4
|
+
import { createRequire } from 'node:module'
|
|
5
|
+
import { readFileSync } from 'node:fs'
|
|
6
|
+
import { initSync } from '@swc/wasm-web'
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url)
|
|
9
|
+
const wasmPath = require.resolve('@swc/wasm-web').replace('wasm.js', 'wasm_bg.wasm')
|
|
10
|
+
const wasmBuffer = readFileSync(wasmPath)
|
|
11
|
+
|
|
12
|
+
initSync({ module: wasmBuffer })
|
|
4
13
|
|
|
5
14
|
test('transform', function () {
|
|
6
15
|
assert.strictEqual(transform('const x = 2; x;'), 'const x = 2;\nreturn x;\n')
|