@rdfc/js-runner 2.0.0-alpha.7 → 2.0.0-alpha.9

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 (62) hide show
  1. package/.idea/LNKD.tech Editor.xml +194 -0
  2. package/.idea/codeStyles/Project.xml +52 -0
  3. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  4. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  5. package/.idea/js-runner.iml +12 -0
  6. package/{examples/echo/.idea → .idea}/modules.xml +1 -1
  7. package/.idea/vcs.xml +6 -0
  8. package/dist/args.d.ts +4 -0
  9. package/dist/args.js +58 -0
  10. package/dist/connectors/file.d.ts +15 -0
  11. package/dist/connectors/file.js +89 -0
  12. package/dist/connectors/http.d.ts +14 -0
  13. package/dist/connectors/http.js +82 -0
  14. package/dist/connectors/kafka.d.ts +48 -0
  15. package/dist/connectors/kafka.js +68 -0
  16. package/dist/connectors/ws.d.ts +10 -0
  17. package/dist/connectors/ws.js +72 -0
  18. package/dist/connectors.d.ts +73 -0
  19. package/dist/connectors.js +168 -0
  20. package/dist/index.cjs +732 -0
  21. package/dist/index.d.ts +42 -0
  22. package/dist/index.js +83 -0
  23. package/dist/tsconfig.tsbuildinfo +1 -0
  24. package/dist/util.d.ts +71 -0
  25. package/dist/util.js +92 -0
  26. package/examples/echo/src/processors.ts +29 -31
  27. package/lib/index.d.ts +2 -1
  28. package/lib/index.js +3 -2
  29. package/lib/jsonld.js +3 -2
  30. package/lib/logger.d.ts +3 -1
  31. package/lib/logger.js +23 -1
  32. package/lib/reader.js +8 -16
  33. package/lib/reexports.d.ts +2 -2
  34. package/lib/reexports.js +3 -3
  35. package/lib/runner.js +27 -16
  36. package/lib/testUtils.js +6 -4
  37. package/lib/tsconfig.tsbuildinfo +1 -1
  38. package/lib/util_processors.js +1 -1
  39. package/lib/writer.js +1 -1
  40. package/package.json +1 -1
  41. package/src/index.ts +2 -1
  42. package/src/jsonld.ts +4 -1
  43. package/src/logger.ts +27 -1
  44. package/src/reader.ts +124 -130
  45. package/src/reexports.ts +5 -2
  46. package/src/runner.ts +158 -143
  47. package/src/testUtils.ts +34 -25
  48. package/src/util_processors.ts +1 -1
  49. package/src/writer.ts +66 -66
  50. package/examples/echo/.idea/echo.iml +0 -9
  51. package/examples/echo/.idea/misc.xml +0 -6
  52. package/examples/echo/.idea/vcs.xml +0 -7
  53. package/examples/echo/.swls/config.json +0 -1
  54. package/examples/echo/index.ttl +0 -3
  55. package/examples/echo/minimal.ttl +0 -90
  56. package/examples/echo/shacl.ttl +0 -9
  57. package/examples/echo/shape.ttl +0 -1339
  58. package/examples/echo/test.ttl +0 -11
  59. package/examples/echo/untitled:/types/MyType.ttl +0 -0
  60. package/file:/home/silvius/Projects/mumo-pipeline/ldes/http_3A_2F_2Fdata.mumo.be_2Fstreams_2Fnodes_2Fdefault/root/index.trig +0 -3
  61. package/ldes/http_3A_2F_2Fdata.mumo.be_2Fstreams_2Fnodes_2Fdefault/root/index.trig +0 -3
  62. package/minimal.ttl +0 -99
package/dist/index.cjs ADDED
@@ -0,0 +1,732 @@
1
+ 'use strict'
2
+
3
+ var n3 = require('n3')
4
+ var commandLineArgs = require('command-line-args')
5
+ var commandLineUsage = require('command-line-usage')
6
+ var fs = require('fs')
7
+ var http = require('http')
8
+ var https = require('https')
9
+ var types = require('@treecg/types')
10
+ var debug = require('debug')
11
+ var path = require('path')
12
+ var promises = require('fs/promises')
13
+ var node_fs = require('node:fs')
14
+ var ws = require('ws')
15
+ var kafkajs = require('kafkajs')
16
+ var rdfLens = require('rdf-lens')
17
+
18
+ function _interopNamespaceDefault(e) {
19
+ var n = Object.create(null)
20
+ if (e) {
21
+ Object.keys(e).forEach(function (k) {
22
+ if (k !== 'default') {
23
+ var d = Object.getOwnPropertyDescriptor(e, k)
24
+ Object.defineProperty(
25
+ n,
26
+ k,
27
+ d.get
28
+ ? d
29
+ : {
30
+ enumerable: true,
31
+ get: function () {
32
+ return e[k]
33
+ },
34
+ },
35
+ )
36
+ }
37
+ })
38
+ }
39
+ n.default = e
40
+ return Object.freeze(n)
41
+ }
42
+
43
+ var http__namespace = /*#__PURE__*/ _interopNamespaceDefault(http)
44
+
45
+ const optionDefinitions = [
46
+ {
47
+ name: 'input',
48
+ type: String,
49
+ defaultOption: true,
50
+ summary: 'Specify what input file to start up',
51
+ },
52
+ {
53
+ name: 'help',
54
+ alias: 'h',
55
+ type: Boolean,
56
+ description: 'Display this help message',
57
+ },
58
+ ]
59
+ const sections = [
60
+ {
61
+ header: 'Js-runner',
62
+ content:
63
+ 'JS-runner is part of the {italic connector architecture}. Starting from an input file start up all JsProcessors that are defined. Please do not use blank nodes, skolemize your data somewhere else!',
64
+ },
65
+ {
66
+ header: 'Synopsis',
67
+ content: '$ js-runner <input>',
68
+ },
69
+ {
70
+ header: 'Command List',
71
+ content: [
72
+ { name: 'input', summary: 'Specify what input file to start up' },
73
+ ],
74
+ },
75
+ {
76
+ optionList: [optionDefinitions[1]],
77
+ },
78
+ ]
79
+ function validArgs(args) {
80
+ if (!args.input) return false
81
+ return true
82
+ }
83
+ function printUsage() {
84
+ const usage = commandLineUsage(sections)
85
+ console.log(usage)
86
+ process.exit(0)
87
+ }
88
+ function getArgs() {
89
+ let args
90
+ try {
91
+ args = commandLineArgs(optionDefinitions)
92
+ } catch (e) {
93
+ console.error(e)
94
+ printUsage()
95
+ }
96
+ if (args.help || !validArgs(args)) {
97
+ printUsage()
98
+ }
99
+ return args
100
+ }
101
+
102
+ const LOG = (function () {
103
+ const main = debug('js-runner')
104
+ const channel = main.extend('channel')
105
+ const util = main.extend('util')
106
+ return { main, channel, util }
107
+ })()
108
+ function toArray(stream) {
109
+ const output = []
110
+ return new Promise((res, rej) => {
111
+ stream.on('data', (x) => output.push(x))
112
+ stream.on('end', () => res(output))
113
+ stream.on('close', () => res(output))
114
+ stream.on('error', rej)
115
+ })
116
+ }
117
+ const OWL = types.createUriAndTermNamespace(
118
+ 'http://www.w3.org/2002/07/owl#',
119
+ 'imports',
120
+ )
121
+ types.createUriAndTermNamespace(
122
+ 'https://w3id.org/conn#',
123
+ 'install',
124
+ 'build',
125
+ 'GitInstall',
126
+ 'LocalInstall',
127
+ 'url',
128
+ 'procFile',
129
+ 'path',
130
+ 'EnvVariable',
131
+ 'envKey',
132
+ 'envDefault',
133
+ )
134
+ const { namedNode, literal } = n3.DataFactory
135
+ async function get_readstream(location) {
136
+ if (location.startsWith('https')) {
137
+ return new Promise((res) => {
138
+ https.get(location, res)
139
+ })
140
+ } else if (location.startsWith('http')) {
141
+ return new Promise((res) => {
142
+ http.get(location, res)
143
+ })
144
+ } else {
145
+ return fs.createReadStream(location)
146
+ }
147
+ }
148
+ async function load_quads(location, baseIRI) {
149
+ try {
150
+ LOG.util('Loading quads %s', location)
151
+ const parser = new n3.StreamParser({ baseIRI: baseIRI || location })
152
+ const rdfStream = await get_readstream(location)
153
+ rdfStream.pipe(parser)
154
+ const quads = await toArray(parser)
155
+ return quads
156
+ } catch (ex) {
157
+ console.error('Failed to load_quads', location, baseIRI)
158
+ console.error(ex)
159
+ return []
160
+ }
161
+ }
162
+ function load_memory_quads(value, baseIRI) {
163
+ const parser = new n3.Parser({ baseIRI })
164
+ return parser.parse(value)
165
+ }
166
+ const loaded = new Set()
167
+ async function load_store(location, store, recursive = true) {
168
+ if (loaded.has(location)) return
169
+ loaded.add(location)
170
+ const quads =
171
+ location.type === 'remote'
172
+ ? await load_quads(location.location)
173
+ : load_memory_quads(location.value, location.baseIRI)
174
+ store.addQuads(quads)
175
+ if (recursive) {
176
+ const loc =
177
+ location.type === 'remote' ? location.location : location.baseIRI
178
+ const other_imports = store.getObjects(
179
+ namedNode(loc),
180
+ OWL.terms.imports,
181
+ null,
182
+ )
183
+ for (const other of other_imports) {
184
+ await load_store({ location: other.value, type: 'remote' }, store, true)
185
+ }
186
+ }
187
+ }
188
+
189
+ async function getFileSize(path) {
190
+ return (await promises.stat(path)).size
191
+ }
192
+ function readPart(path, start, end, encoding) {
193
+ return new Promise((res) => {
194
+ const stream = fs.createReadStream(path, { encoding, start, end })
195
+ let buffer = ''
196
+ stream.on('data', (chunk) => {
197
+ buffer += chunk
198
+ })
199
+ stream.on('close', () => res(buffer))
200
+ })
201
+ }
202
+ function debounce(func, timeout = 100) {
203
+ let timer
204
+ return (...args) => {
205
+ clearTimeout(timer)
206
+ timer = setTimeout(() => {
207
+ func(...args)
208
+ }, timeout)
209
+ }
210
+ }
211
+ const startFileStreamReader = (config) => {
212
+ const path$1 = path.isAbsolute(config.path)
213
+ ? config.path
214
+ : `${process.cwd()}/${config.path}`
215
+ fs.openSync(path$1, 'a+')
216
+ const encoding = config.encoding || 'utf-8'
217
+ const reader = new SimpleStream()
218
+ const init = async () => {
219
+ let currentPos = await getFileSize(path$1)
220
+ const watcher = node_fs.watch(path$1, { encoding: 'utf-8' })
221
+ watcher.on(
222
+ 'change',
223
+ debounce(async () => {
224
+ try {
225
+ let content
226
+ if (config.onReplace) {
227
+ content = await promises.readFile(path$1, { encoding })
228
+ } else {
229
+ const newSize = await getFileSize(path$1)
230
+ if (newSize <= currentPos) {
231
+ currentPos = newSize
232
+ return
233
+ }
234
+ content = await readPart(path$1, currentPos, newSize, encoding)
235
+ currentPos = newSize
236
+ }
237
+ await reader.push(content)
238
+ } catch (error) {
239
+ if (error.code === 'ENOENT') {
240
+ return
241
+ }
242
+ throw error
243
+ }
244
+ }),
245
+ )
246
+ if (config.onReplace && config.readFirstContent) {
247
+ const content = await promises.readFile(path$1, { encoding })
248
+ await reader.push(content)
249
+ }
250
+ }
251
+ return { reader, init }
252
+ }
253
+ const startFileStreamWriter = (config) => {
254
+ const path$1 = path.isAbsolute(config.path)
255
+ ? config.path
256
+ : `${process.cwd()}/${config.path}`
257
+ const encoding = config.encoding || 'utf-8'
258
+ const writer = new SimpleStream()
259
+ const init = async () => {
260
+ if (!config.onReplace) {
261
+ await promises.writeFile(path$1, '', { encoding })
262
+ }
263
+ }
264
+ writer.push = async (item) => {
265
+ if (config.onReplace) {
266
+ await promises.writeFile(path$1, item, { encoding })
267
+ } else {
268
+ await promises.appendFile(path$1, item, { encoding })
269
+ }
270
+ }
271
+ return { writer, init }
272
+ }
273
+
274
+ function _connectWs(url, res) {
275
+ const ws$1 = new ws.WebSocket(url, {})
276
+ ws$1.on('error', () => {
277
+ setTimeout(() => _connectWs(url, res), 300)
278
+ })
279
+ ws$1.on('ping', () => ws$1.pong())
280
+ ws$1.on('open', () => {
281
+ res(ws$1)
282
+ })
283
+ }
284
+ function connectWs(url) {
285
+ return new Promise((res) => _connectWs(url, res))
286
+ }
287
+ const startWsStreamReader = (config) => {
288
+ const server = new ws.WebSocketServer(config)
289
+ server.on('error', (error) => {
290
+ console.error('Ws server error:')
291
+ console.error(error)
292
+ })
293
+ const connections = []
294
+ const interval = setInterval(() => {
295
+ connections.forEach((instance, i) => {
296
+ if (!instance) {
297
+ return
298
+ }
299
+ if (!instance.alive) {
300
+ instance.socket.terminate()
301
+ delete connections[i]
302
+ return
303
+ }
304
+ instance.socket.ping()
305
+ instance.alive = false
306
+ })
307
+ }, 30_000)
308
+ const reader = new SimpleStream(
309
+ () =>
310
+ new Promise((res) => {
311
+ clearInterval(interval)
312
+ server.close(() => res())
313
+ }),
314
+ )
315
+ server.on('connection', (ws) => {
316
+ const instance = { socket: ws, alive: true }
317
+ connections.push(instance)
318
+ ws.on('message', async (msg) => {
319
+ reader.push(msg.toString()).catch((error) => {
320
+ throw error
321
+ })
322
+ })
323
+ ws.on('pong', () => {
324
+ instance.alive = true
325
+ })
326
+ })
327
+ return { reader, init: async () => {} }
328
+ }
329
+ const startWsStreamWriter = (config) => {
330
+ let ws
331
+ const init = async () => {
332
+ ws = await connectWs(config.url)
333
+ ws.on('open', () => console.log('open'))
334
+ }
335
+ const writer = new SimpleStream(async () => {
336
+ ws.close()
337
+ })
338
+ writer.push = async (item) => {
339
+ ws.send(item)
340
+ }
341
+ return { writer, init }
342
+ }
343
+
344
+ const startKafkaStreamReader = (config) => {
345
+ const brokerConfig = {}
346
+ if (typeof config.broker === 'string' || config.broker instanceof String) {
347
+ Object.assign(
348
+ brokerConfig,
349
+ JSON.parse(node_fs.readFileSync(config.broker, 'utf-8')),
350
+ )
351
+ } else {
352
+ Object.assign(brokerConfig, config.broker)
353
+ }
354
+ if (brokerConfig && brokerConfig.hosts) {
355
+ brokerConfig.brokers = brokerConfig.hosts
356
+ }
357
+ const kafka = new kafkajs.Kafka(brokerConfig)
358
+ const consumer = kafka.consumer(config.consumer)
359
+ const stream = new SimpleStream(async () => {
360
+ await consumer.disconnect()
361
+ await consumer.stop()
362
+ })
363
+ const init = async () => {
364
+ await consumer.connect()
365
+ await consumer.subscribe({
366
+ topic: config.topic.name,
367
+ fromBeginning: config.topic.fromBeginning,
368
+ })
369
+ consumer
370
+ .run({
371
+ async eachMessage({ topic, message }) {
372
+ if (topic === config.topic.name) {
373
+ const element = message.value?.toString() ?? ''
374
+ stream.push(element).catch((error) => {
375
+ throw error
376
+ })
377
+ }
378
+ },
379
+ })
380
+ .catch((error) => {
381
+ throw error
382
+ })
383
+ }
384
+ return { reader: stream, init }
385
+ }
386
+ const startKafkaStreamWriter = (config) => {
387
+ const topic = config.topic.name
388
+ const brokerConfig = {}
389
+ if (typeof config.broker === 'string' || config.broker instanceof String) {
390
+ Object.assign(
391
+ brokerConfig,
392
+ JSON.parse(node_fs.readFileSync(config.broker, 'utf-8')),
393
+ )
394
+ } else {
395
+ Object.assign(brokerConfig, config.broker)
396
+ }
397
+ if (brokerConfig && brokerConfig.hosts) {
398
+ brokerConfig.brokers = brokerConfig.hosts
399
+ }
400
+ const kafka = new kafkajs.Kafka(brokerConfig)
401
+ const producer = kafka.producer(config.producer)
402
+ const writer = new SimpleStream(async () => {
403
+ await producer.disconnect()
404
+ })
405
+ const init = () => producer.connect()
406
+ writer.push = async (item) => {
407
+ await producer.send({ topic, messages: [{ value: item }] })
408
+ }
409
+ return { writer, init }
410
+ }
411
+
412
+ function streamToString(stream, binary) {
413
+ const datas = []
414
+ return new Promise((res) => {
415
+ stream.on('data', (data) => {
416
+ datas.push(data)
417
+ })
418
+ stream.on('end', () => {
419
+ const streamData = Buffer.concat(datas)
420
+ res(binary ? streamData : streamData.toString())
421
+ })
422
+ })
423
+ }
424
+ const startHttpStreamReader = (config) => {
425
+ let server = undefined
426
+ const stream = new SimpleStream(
427
+ () =>
428
+ new Promise((res) => {
429
+ if (server !== undefined) {
430
+ server.close(() => {
431
+ res()
432
+ })
433
+ } else {
434
+ res()
435
+ }
436
+ }),
437
+ )
438
+ const requestListener = async function (req, res) {
439
+ try {
440
+ const content = await streamToString(req, config.binary)
441
+ const promise = stream.push(content).catch((error) => {
442
+ throw error
443
+ })
444
+ if (config.waitHandled) {
445
+ await promise
446
+ }
447
+ } catch (error) {
448
+ console.error('Failed', error)
449
+ }
450
+ res.writeHead(config.responseCode || 200)
451
+ res.end('OK')
452
+ }
453
+ server = http.createServer(requestListener)
454
+ const init = () => {
455
+ return new Promise((res) => {
456
+ const cb = () => res(undefined)
457
+ if (server) {
458
+ server.listen(config.port, config.endpoint, cb)
459
+ } else {
460
+ cb()
461
+ }
462
+ })
463
+ }
464
+ return { reader: stream, init }
465
+ }
466
+ const startHttpStreamWriter = (config) => {
467
+ const requestConfig = new URL(config.endpoint)
468
+ const writer = new SimpleStream()
469
+ writer.push = async (item) => {
470
+ await new Promise((resolve) => {
471
+ const options = {
472
+ hostname: requestConfig.hostname,
473
+ path: requestConfig.path,
474
+ method: config.method,
475
+ port: requestConfig.port,
476
+ }
477
+ const cb = (response) => {
478
+ response.on('data', () => {})
479
+ response.on('end', () => {
480
+ resolve(null)
481
+ })
482
+ }
483
+ const req = http__namespace.request(options, cb)
484
+ req.write(item, () => {
485
+ req.end()
486
+ })
487
+ })
488
+ }
489
+ return { writer, init: async () => {} }
490
+ }
491
+
492
+ const Conn = types.createTermNamespace(
493
+ 'https://w3id.org/conn#',
494
+ 'FileReaderChannel',
495
+ 'FileWriterChannel',
496
+ 'HttpReaderChannel',
497
+ 'HttpWriterChannel',
498
+ 'KafkaReaderChannel',
499
+ 'KafkaWriterChannel',
500
+ 'WsReaderChannel',
501
+ 'WsWriterChannel',
502
+ 'WriterChannel',
503
+ 'ReaderChannel',
504
+ )
505
+ const JsOntology = types.createTermNamespace(
506
+ 'https://w3id.org/conn/js#',
507
+ 'JsProcess',
508
+ 'JsChannel',
509
+ 'JsReaderChannel',
510
+ 'JsWriterChannel',
511
+ )
512
+ class ChannelFactory {
513
+ inits = []
514
+ jsChannelsNamedNodes = {}
515
+ jsChannelsBlankNodes = {}
516
+ createReader(config) {
517
+ LOG.channel('Creating reader %s: a %s', config.id.value, config.ty.value)
518
+ if (config.ty.equals(Conn.FileReaderChannel)) {
519
+ const { reader, init } = startFileStreamReader(config.config)
520
+ this.inits.push(init)
521
+ return reader
522
+ }
523
+ if (config.ty.equals(Conn.WsReaderChannel)) {
524
+ const { reader, init } = startWsStreamReader(config.config)
525
+ this.inits.push(init)
526
+ return reader
527
+ }
528
+ if (config.ty.equals(Conn.KafkaReaderChannel)) {
529
+ const { reader, init } = startKafkaStreamReader(config.config)
530
+ this.inits.push(init)
531
+ return reader
532
+ }
533
+ if (config.ty.equals(Conn.HttpReaderChannel)) {
534
+ const { reader, init } = startHttpStreamReader(config.config)
535
+ this.inits.push(init)
536
+ return reader
537
+ }
538
+ if (config.ty.equals(JsOntology.JsReaderChannel)) {
539
+ const c = config.config
540
+ if (c.channel) {
541
+ const id = c.channel.id.value
542
+ if (c.channel.id.termType === 'NamedNode') {
543
+ if (!this.jsChannelsNamedNodes[id]) {
544
+ this.jsChannelsNamedNodes[id] = new SimpleStream()
545
+ }
546
+ return this.jsChannelsNamedNodes[id]
547
+ }
548
+ if (c.channel.id.termType === 'BlankNode') {
549
+ if (!this.jsChannelsBlankNodes[id]) {
550
+ this.jsChannelsBlankNodes[id] = new SimpleStream()
551
+ }
552
+ return this.jsChannelsBlankNodes[id]
553
+ }
554
+ throw 'Should have found a thing'
555
+ }
556
+ }
557
+ throw 'Unknown reader channel ' + config.ty.value
558
+ }
559
+ createWriter(config) {
560
+ LOG.channel('Creating writer %s: a %s', config.id.value, config.ty.value)
561
+ if (config.ty.equals(Conn.FileWriterChannel)) {
562
+ const { writer, init } = startFileStreamWriter(config.config)
563
+ this.inits.push(init)
564
+ return writer
565
+ }
566
+ if (config.ty.equals(Conn.WsWriterChannel)) {
567
+ const { writer, init } = startWsStreamWriter(config.config)
568
+ this.inits.push(init)
569
+ return writer
570
+ }
571
+ if (config.ty.equals(Conn.KafkaWriterChannel)) {
572
+ const { writer, init } = startKafkaStreamWriter(config.config)
573
+ this.inits.push(init)
574
+ return writer
575
+ }
576
+ if (config.ty.equals(Conn.HttpWriterChannel)) {
577
+ const { writer, init } = startHttpStreamWriter(config.config)
578
+ this.inits.push(init)
579
+ return writer
580
+ }
581
+ if (config.ty.equals(JsOntology.JsWriterChannel)) {
582
+ const c = config.config
583
+ if (c.channel) {
584
+ const id = c.channel.id.value
585
+ if (c.channel.id.termType === 'NamedNode') {
586
+ if (!this.jsChannelsNamedNodes[id]) {
587
+ this.jsChannelsNamedNodes[id] = new SimpleStream()
588
+ }
589
+ return this.jsChannelsNamedNodes[id]
590
+ }
591
+ if (c.channel.id.termType === 'BlankNode') {
592
+ if (!this.jsChannelsBlankNodes[id]) {
593
+ this.jsChannelsBlankNodes[id] = new SimpleStream()
594
+ }
595
+ return this.jsChannelsBlankNodes[id]
596
+ }
597
+ throw 'Should have found a thing'
598
+ }
599
+ }
600
+ throw 'Unknown writer channel ' + config.ty.value
601
+ }
602
+ async init() {
603
+ await Promise.all(this.inits.map((x) => x()))
604
+ }
605
+ }
606
+ class SimpleStream {
607
+ dataHandlers = []
608
+ endHandlers = []
609
+ disconnect
610
+ lastElement
611
+ ended = false
612
+ constructor(onDisconnect) {
613
+ this.disconnect = onDisconnect || (async () => {})
614
+ }
615
+ data(listener) {
616
+ this.dataHandlers.push(listener)
617
+ return this
618
+ }
619
+ async push(data) {
620
+ if (this.ended) {
621
+ throw new Error('Trying to push to a stream that has ended!')
622
+ }
623
+ this.lastElement = data
624
+ await Promise.all(this.dataHandlers.map((handler) => handler(data)))
625
+ }
626
+ async end() {
627
+ await this.disconnect()
628
+ await Promise.all(this.endHandlers.map((handler) => handler()))
629
+ this.ended = true
630
+ }
631
+ on(event, listener) {
632
+ if (event === 'data') {
633
+ this.dataHandlers.push(listener)
634
+ }
635
+ if (event === 'end') {
636
+ this.endHandlers.push(listener)
637
+ }
638
+ return this
639
+ }
640
+ }
641
+
642
+ function safeJoin(a, b) {
643
+ if (b.startsWith('/')) {
644
+ return b
645
+ }
646
+ return path.join(a, b)
647
+ }
648
+ async function extractProcessors(source, apply) {
649
+ const store = new n3.Store()
650
+ await load_store(source, store)
651
+ const quads = store.getQuads(null, null, null, null)
652
+ const config = rdfLens.extractShapes(quads, apply)
653
+ const subjects = quads
654
+ .filter(
655
+ (x) =>
656
+ x.predicate.equals(types.RDF.terms.type) &&
657
+ x.object.equals(JsOntology.JsProcess),
658
+ )
659
+ .map((x) => x.subject)
660
+ const processorLens = config.lenses[JsOntology.JsProcess.value]
661
+ const processors = subjects.map((id) => processorLens.execute({ id, quads }))
662
+ return { processors, quads, shapes: config }
663
+ }
664
+ function extractSteps(proc, quads, config) {
665
+ const out = []
666
+ const subjects = quads
667
+ .filter(
668
+ (x) =>
669
+ x.predicate.equals(types.RDF.terms.type) && x.object.equals(proc.ty),
670
+ )
671
+ .map((x) => x.subject)
672
+ const processorLens = config.lenses[proc.ty.value]
673
+ const fields = proc.mapping.parameters
674
+ for (const id of subjects) {
675
+ const obj = processorLens.execute({ id, quads })
676
+ const functionArgs = new Array(fields.length)
677
+ for (const field of fields) {
678
+ functionArgs[field.position] = obj[field.parameter]
679
+ }
680
+ out.push(functionArgs)
681
+ }
682
+ return out
683
+ }
684
+ async function jsRunner() {
685
+ const args = getArgs()
686
+ const cwd = process.cwd()
687
+ const source = {
688
+ location: safeJoin(cwd, args.input).replaceAll('\\', '/'),
689
+ type: 'remote',
690
+ }
691
+ const factory = new ChannelFactory()
692
+ const apply = {}
693
+ apply[Conn.ReaderChannel.value] = factory.createReader.bind(factory)
694
+ apply[Conn.WriterChannel.value] = factory.createWriter.bind(factory)
695
+ const {
696
+ processors,
697
+ quads,
698
+ shapes: config,
699
+ } = await extractProcessors(source, apply)
700
+ LOG.main('Found %d processors', processors.length)
701
+ const starts = []
702
+ for (const proc of processors) {
703
+ const argss = extractSteps(proc, quads, config)
704
+ const jsProgram = await import('file://' + proc.file)
705
+ process.chdir(proc.location)
706
+ for (const args of argss) {
707
+ starts.push(await jsProgram[proc.func](...args))
708
+ }
709
+ }
710
+ await factory.init()
711
+ for (const s of starts) {
712
+ if (s && typeof s === 'function') {
713
+ s()
714
+ }
715
+ }
716
+ }
717
+
718
+ exports.ChannelFactory = ChannelFactory
719
+ exports.Conn = Conn
720
+ exports.JsOntology = JsOntology
721
+ exports.SimpleStream = SimpleStream
722
+ exports.extractProcessors = extractProcessors
723
+ exports.extractSteps = extractSteps
724
+ exports.jsRunner = jsRunner
725
+ exports.startFileStreamReader = startFileStreamReader
726
+ exports.startFileStreamWriter = startFileStreamWriter
727
+ exports.startHttpStreamReader = startHttpStreamReader
728
+ exports.startHttpStreamWriter = startHttpStreamWriter
729
+ exports.startKafkaStreamReader = startKafkaStreamReader
730
+ exports.startKafkaStreamWriter = startKafkaStreamWriter
731
+ exports.startWsStreamReader = startWsStreamReader
732
+ exports.startWsStreamWriter = startWsStreamWriter