@naanlang/naan 1.0.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 (98) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +46 -0
  3. package/dist/env_web.js +431 -0
  4. package/dist/naan.min.js +73 -0
  5. package/frameworks/browser/browser.nlg +30 -0
  6. package/frameworks/browser/pouchdb/pouchdb.min.js +7 -0
  7. package/frameworks/browser/spark-md5/spark-md5.min.js +1 -0
  8. package/frameworks/browser/sworker.js +192 -0
  9. package/frameworks/browser/terminals.nlg +787 -0
  10. package/frameworks/browser/workers.nlg +386 -0
  11. package/frameworks/client/apiclient.nlg +183 -0
  12. package/frameworks/client/client.nlg +29 -0
  13. package/frameworks/client/psm_client.nlg +572 -0
  14. package/frameworks/common/common.nlg +464 -0
  15. package/frameworks/common/preferences.nlg +131 -0
  16. package/frameworks/common/repltools.nlg +100 -0
  17. package/frameworks/common/watching.nlg +97 -0
  18. package/frameworks/node/apiserver.nlg +399 -0
  19. package/frameworks/node/filesystem.nlg +1012 -0
  20. package/frameworks/node/gitter.nlg +234 -0
  21. package/frameworks/node/node.nlg +81 -0
  22. package/frameworks/node/psm_server.nlg +465 -0
  23. package/frameworks/node/worker.nlg +560 -0
  24. package/frameworks/project/build.nlg +1229 -0
  25. package/frameworks/project/jszip.js +30 -0
  26. package/frameworks/project/jszip.nlg +87 -0
  27. package/frameworks/project/proj_cliser.nlg +139 -0
  28. package/frameworks/project/proj_console.nlg +137 -0
  29. package/frameworks/project/proj_folder.nlg +143 -0
  30. package/frameworks/project/proj_lambda.nlg +137 -0
  31. package/frameworks/project/proj_static.nlg +138 -0
  32. package/frameworks/project/project.nlg +29 -0
  33. package/frameworks/project/projects.nlg +587 -0
  34. package/frameworks/project/uglifyjs.js +1 -0
  35. package/frameworks/project/uglifyjs.nlg +79 -0
  36. package/frameworks/running/debugcom.nlg +163 -0
  37. package/frameworks/running/debugnub.nlg +565 -0
  38. package/frameworks/running/debugutil.nlg +510 -0
  39. package/frameworks/running/executors.nlg +767 -0
  40. package/frameworks/running/running.nlg +151 -0
  41. package/frameworks/running/sourcecode.nlg +346 -0
  42. package/frameworks/running/taskexec.nlg +196 -0
  43. package/frameworks/storage/dbt_pouch.nlg +773 -0
  44. package/frameworks/storage/file_manager.nlg +772 -0
  45. package/frameworks/storage/psm.nlg +326 -0
  46. package/frameworks/storage/psm_dbtables.nlg +814 -0
  47. package/frameworks/storage/resources.nlg +445 -0
  48. package/frameworks/storage/storage.nlg +52 -0
  49. package/lib/browser/env_web.js +431 -0
  50. package/lib/browser/env_webworker.js +146 -0
  51. package/lib/browser/require.js +1653 -0
  52. package/lib/core/naanlib.js +73 -0
  53. package/lib/env_node.js +282 -0
  54. package/lib/env_nodeworker.js +165 -0
  55. package/lib/node_repl.js +25 -0
  56. package/lib/node_repl_init.nlg +52 -0
  57. package/package.json +13 -0
  58. package/plugins/gitClient/clientops.nlg +317 -0
  59. package/plugins/gitClient/gitClient.nlg +63 -0
  60. package/plugins/gitClient/gitutils.nlg +1331 -0
  61. package/plugins/gitClient/minimatch.js +945 -0
  62. package/plugins/gitClient/minimatch_license.txt +15 -0
  63. package/plugins/gitClient/minimatch_readme.md +208 -0
  64. package/plugins/nodeLib/nodeLib.nlg +26 -0
  65. package/plugins/nodeLib/node_cp.nlg +65 -0
  66. package/plugins/nodeLib/node_fs.nlg +137 -0
  67. package/plugins/nodeLib/node_https.nlg +172 -0
  68. package/plugins/nodeLib/node_util.nlg +180 -0
  69. package/plugins/serviceAws/aws/aws-sdk.min.js +88 -0
  70. package/plugins/serviceAws/aws/lambda_rest_index.js +122 -0
  71. package/plugins/serviceAws/aws/lambda_rest_init.nlg +58 -0
  72. package/plugins/serviceAws/aws/lambda_ws_index.js +498 -0
  73. package/plugins/serviceAws/aws/lambda_ws_init.nlg +49 -0
  74. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +122 -0
  75. package/plugins/serviceAws/aws_cognito.nlg +76 -0
  76. package/plugins/serviceAws/aws_dynamo.nlg +509 -0
  77. package/plugins/serviceAws/aws_lambda.nlg +95 -0
  78. package/plugins/serviceAws/aws_s3.nlg +134 -0
  79. package/plugins/serviceAws/aws_utils.nlg +86 -0
  80. package/plugins/serviceAws/dbt_aws.nlg +769 -0
  81. package/plugins/serviceAws/lambda_naan_control.nlg +175 -0
  82. package/plugins/serviceAws/psm_aws.nlg +258 -0
  83. package/plugins/serviceAws/serviceAws.nlg +38 -0
  84. package/plugins/serviceGitHub/gitops.nlg +522 -0
  85. package/plugins/serviceGitHub/psm_github.nlg +205 -0
  86. package/plugins/serviceGitHub/serviceGitHub.nlg +65 -0
  87. package/plugins/serviceGitLab/gitops.nlg +528 -0
  88. package/plugins/serviceGitLab/psm_gitlab.nlg +205 -0
  89. package/plugins/serviceGitLab/serviceGitLab.nlg +65 -0
  90. package/test/harness.nlg +312 -0
  91. package/test/node_test.js +33 -0
  92. package/test/test_01_core.nlg +768 -0
  93. package/test/test_02_context.nlg +269 -0
  94. package/test/test_03_jsinterop.nlg +137 -0
  95. package/test/test_04_numerics.nlg +450 -0
  96. package/test/test_05_strings.nlg +63 -0
  97. package/test/test_06_lingoparse.nlg +500 -0
  98. package/test/test_07_lingo.nlg +623 -0
@@ -0,0 +1,97 @@
1
+ /*
2
+ * watching.nlg
3
+ * naanlib/frameworks/common/watching
4
+ *
5
+ * A simple notificaiton system to broadcast change to interested parties.
6
+ *
7
+ * column positioning: // // !
8
+ *
9
+ * Copyright (c) 2019-2021 by Richard C. Zulch
10
+ *
11
+ */
12
+
13
+
14
+ /*
15
+ * Watchable
16
+ *
17
+ * Watchable objects provide a common protocol to broadcast change notifications and to allow
18
+ * interested parties to subscribe using register and unregister. A watchable is an instance for a
19
+ * particular broadcast topic. Watchers are procedures that subscribe to a watchable to be notified.
20
+ * The owner of the watchable is responsible for telling it about changes by calling the notify
21
+ * method with a changes dictionary. Each notification can report any number of changes to multiple
22
+ * items.
23
+ *
24
+ * A {changes} dictionary has the following structure, where each field is optional:
25
+ * {
26
+ * added: [<item>,<item>...<item>]
27
+ * changed: [<item>,<item>...<item>]
28
+ * deleted: [<item>,<item>...<item>]
29
+ * <custom>: [<item>,<item>...<item>]
30
+ * }
31
+ *
32
+ */
33
+
34
+ closure Watchable(local watch, watchers) {
35
+ watch = new(object, this)
36
+ reset()
37
+
38
+ // notify
39
+ //
40
+ // Notify watchers using:
41
+ // watcher(classID, {changes})
42
+ watch.notify = function notify(classID, changes, local watcher) {
43
+ for watcher in watchers
44
+ call(watcher, classID, changes)
45
+ }
46
+
47
+ // watch
48
+ //
49
+ // Call the specified watch function after changes occur:
50
+ // watcher(classID, {changes})
51
+ watch.watch = function watch(proc, local wadex) {
52
+ wadex = watchers.findIndex(function(item) {
53
+ item eq proc
54
+ })
55
+ if wadex < 0
56
+ watchers.push(proc)
57
+ }
58
+
59
+ // unWatch
60
+ //
61
+ // Stop calling the specified watch function after changes occur.
62
+ watch.unWatch = function unWatch(proc, local wadex) {
63
+ wadex = watchers.findIndex(function(item) {
64
+ item eq proc
65
+ })
66
+ if wadex >= 0
67
+ watchers.splice(wadex)
68
+ }
69
+
70
+ // reset
71
+ //
72
+ // Reset the watch list.
73
+ watch.reset = function reset() {
74
+ watchers = []
75
+ }
76
+
77
+ // finis
78
+ watch
79
+ };
80
+
81
+
82
+ /*
83
+ * wachInit
84
+ *
85
+ * Initialize the component.
86
+ *
87
+ */
88
+
89
+ function wachInit(local manifest) {
90
+ manifest = `(Watchable, wachInit)
91
+
92
+ Naan.module.build(module.id, "watching", function(modobj, compobj) {
93
+ require("./common.nlg")
94
+ compobj.manifest = manifest
95
+ module.exports.Watchable = Watchable
96
+ })
97
+ } ();
@@ -0,0 +1,399 @@
1
+ /*
2
+ * apiserver.nlg
3
+ * Naanlib/frameworks/node
4
+ *
5
+ * NaanIDE API server with HTTP using Expressjs.
6
+ *
7
+ * column positioning: // // !
8
+ *
9
+ * Copyright (c) 2017-2021 by Richard C. Zulch
10
+ *
11
+ */
12
+
13
+
14
+ /*
15
+ * MakeAPI
16
+ *
17
+ * Make an API server object.
18
+ *
19
+ */
20
+
21
+ closure MakeAPI(port, options, callback, local chroot, server) {
22
+ if !options
23
+ options = { }
24
+ else
25
+ options = new(options)
26
+ if !options.relpath
27
+ options.relpath = ""
28
+
29
+ chroot = JSpath.join(js.d, options.relpath)
30
+ if not string(chroot) || chroot.length < 2 {
31
+ debuglog("APIserver: invalid path", chroot)
32
+ return (false)
33
+ }
34
+
35
+ server = new(object, this)
36
+ server.psm = require("./psm_server.nlg").MakeServerPSM(server)
37
+ server.root = chroot
38
+ server.app = express()
39
+ server.notifyq = []
40
+ server.responseq = []
41
+ server.projects = { }
42
+
43
+ // close
44
+ //
45
+ // Close the server.
46
+
47
+ server.close = function close() {
48
+ if server.ws
49
+ server.ws.close()
50
+ server.http.close(function(){debuglog("API Server closed")})
51
+ }
52
+
53
+ // Register
54
+ //
55
+ // Register a subsystem to receive websocket messages from client connections. The caller will
56
+ // have the wsReceive method invoked:
57
+ // wsReceive(message, conn)
58
+ // And can send a reply on the specified connection.
59
+
60
+ server.Register = function Register(serverID, subsystem) {
61
+ server.ws.subsystems[serverID] = subsystem
62
+ }
63
+
64
+ //
65
+ // status and message notification
66
+ //
67
+
68
+ function notifyReaper(maxage, local oldest) {
69
+ oldest = Date.now() - maxage
70
+ server.notifyq = server.notifyq.filter(function(item,index,array){
71
+ item.stamp >= oldest
72
+ })
73
+ server.responseq.forEach(function(item,index,array){
74
+ item.poll()
75
+ })
76
+ server.responseq = server.responseq.filter(function(item,index,array){
77
+ item.active
78
+ })
79
+ }
80
+ // Notification responses are only removed from the response queue by the reaper, which means
81
+ // that the reaper must run periodically so that they don't accumulate if no new messages are
82
+ // created for a long period. Note that responses don't delete themselves from the queue when
83
+ // they complete because that can happen inside responseq.forEach(), which could be quite bad.
84
+ // A response timeout can even happen inside the forEach, so it's safest just to remove the
85
+ // responses in one place.
86
+ closure scheduleReaper(interval) {
87
+ future(function reaper(){ scheduleReaper(interval), notifyReaper(interval) }, interval)
88
+ } (30000)
89
+
90
+ server.notify = function notify(message) {
91
+ if not dictionary(message)
92
+ message = {type: "status", message: message}
93
+ message.stamp = Date.now()
94
+ server.notifyq.push(message)
95
+ notifyReaper(30000)
96
+ }
97
+
98
+ //
99
+ // body parsing
100
+ //
101
+
102
+ server.app.use(bodyParser.text({limit: "20mb"}))
103
+ server.app.use(bodyParser.raw({limit: "20mb"}))
104
+
105
+ //
106
+ // Express.js endpoints
107
+ //
108
+
109
+ server.app.use(function(req,res,next) {
110
+ res.header("Access-Control-Allow-Origin", "*")
111
+ res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
112
+ next()
113
+ })
114
+
115
+ server.app.use("", express.static(chroot))
116
+ let (pathpair) {
117
+ for pathpair in options.statics
118
+ server.app.use(pathpair.0, express.static(pathpair.1))
119
+ }()
120
+
121
+ // "/"
122
+
123
+ server.app.get("/", function(req, res) {
124
+ res.send("<u>NaanIDE API</u><br>\r\n"
125
+ " /readfile?path=<i>filepath</i><br>\r\n"
126
+ " /status?timeout=<i>msec</i>&after=<i>stamp</i><br>\r\n")
127
+ })
128
+
129
+ // "/readfile"
130
+
131
+ server.app.get("/readfile", closure(req, res) {
132
+ if not string(req.query.path)
133
+ res.status(400).send("Invalid filename")
134
+ else if RegExp("^\\.\\.[/\\\\]|[/\\\\]\\.\\.$|[/\\\\]\\.\\.[/\\\\]").test(req.query.path)
135
+ res.status(403).send("\"Parent path references forbidden\"")
136
+ else
137
+ closure (local filepath, options) {
138
+ filepath = req.query.path
139
+ options = {
140
+ dotfiles: "allow"
141
+ }
142
+ if filepath.charAt(0) != JSpath.sep
143
+ options.root = chroot
144
+ res.sendFile(filepath, options, function (err, local status) {
145
+ if err {
146
+ if err.code == "ENOENT"
147
+ status = 404
148
+ else
149
+ status = 500
150
+ res.status(status).end()
151
+ ErrorDebuglog(Error("Server: /readfile", filepath, err))
152
+ }
153
+ })
154
+ }()
155
+ })
156
+
157
+ // "/status"
158
+
159
+ server.app.get("/status", closure(req,res, local timeoutms, after, responder) {
160
+ timeoutms = toint(req.query.timeout)
161
+ after = toint(req.query.after)
162
+ if not integer(timeoutms) or timeoutms > 10000
163
+ res.status(400).send("timeout is integer milliseconds no greater than 10000")
164
+ else if not integer(after)
165
+ res.status(400).send("after must be an integer")
166
+ else {
167
+ responder = new(dictionary)
168
+ responder.active = true
169
+ responder.poll = function(timeout, local queued) {
170
+ if responder.active {
171
+ queued = server.notifyq.filter(function(item,index,array) { item.stamp > after })
172
+ if queued.length > 0
173
+ res.send(js.g.JSON.stringify(queued))
174
+ else if timeout
175
+ res.status(200).end()
176
+ else
177
+ return (true)
178
+ }
179
+ responder.active = false
180
+ }
181
+ if responder.poll() {
182
+ future(function poll(){ responder.poll(true) }, timeoutms)
183
+ server.responseq.push(responder)
184
+ }
185
+ }
186
+ })
187
+
188
+ // "/psm"
189
+
190
+ server.app.all("/psm", closure(req, res) {
191
+ if !server.hostfs
192
+ res.status(503).send("host filesystem not available")
193
+ else
194
+ server.hostfs.api(req, res)
195
+ })
196
+
197
+ //
198
+ // initialize the server
199
+ //
200
+
201
+ let(local pending, result) {
202
+ pending = new(nonce)
203
+
204
+ // find our port
205
+
206
+ loop {
207
+ server.http = server.app.listen(port, function(){
208
+ pending.signal({}) // success
209
+ }).on("error", function (err) {
210
+ if err.code == "EADDRINUSE"
211
+ ++port // try next port
212
+ else {
213
+ pending.result = Error("server listen error", err) // permanent failure
214
+ callback(err, false)
215
+ }
216
+ pending.signal(pending.result)
217
+ })
218
+ if pending.wait()
219
+ break
220
+ pending.reset()
221
+ }
222
+ if pending.result
223
+ return (false) // failed to open
224
+
225
+ // start the services
226
+
227
+ server.ws = WebSocketServer(server)
228
+ server.port = port
229
+ callback(false, port, server) // notify of success
230
+ debuglog("server open on port", port)
231
+ result = server.psm.conns.NodeFS.connect("Host", "NideFS", list("")) // ### this should go through resource tracker
232
+ if result.0
233
+ ErrorDebuglog(Error("can't access HostFS", result.0))
234
+ else
235
+ server.hostfs = result.1
236
+ }()
237
+
238
+ // return new API server object
239
+ server
240
+ };
241
+
242
+
243
+ /*
244
+ * WebSocketServer
245
+ *
246
+ * WebSocket server objects. This is used by the HTTP server for websocket communications.
247
+ *
248
+ */
249
+
250
+ closure WebSocketServer(server, local websocks) {
251
+ websocks = new(object, this)
252
+ websocks.conns = [] // our connections
253
+ websocks.subsystems = { } // registered subsystems
254
+ websocks.wss = xnew(ws.Server, { noServer: true })
255
+
256
+ // Server upgrade handler
257
+
258
+ server.http.on("upgrade", function(request, socket, head) {
259
+ websocks.wss.handleUpgrade(request, socket, head, function (csock) {
260
+ websocks.wss.emit("connection", csock, request)
261
+ })
262
+ })
263
+
264
+ // Event handlers
265
+
266
+ websocks.wss.on("connection", function(socket, request) {
267
+ websocks.conns.push(WesCon(websocks, socket, request))
268
+ })
269
+
270
+ server.wss.on("error", function(error) {
271
+ ErrorDebuglog(Error("ws server error:", error))
272
+ })
273
+
274
+ server.wss.on("close", function() {
275
+ debuglog("WebSocketServer has closed")
276
+ websocks.closed = true // note that we are closed
277
+ })
278
+
279
+ // closeConn
280
+ // respond to connection closing
281
+
282
+ websocks.closeConn = function closeConn(conn) {
283
+ websocks.conns = websocks.conns.filter(function(item) {
284
+ !(item eq conn)
285
+ })
286
+ }
287
+
288
+ // finis
289
+ websocks
290
+ };
291
+
292
+
293
+ /*
294
+ * WesCon
295
+ *
296
+ * WebSocket socket objects, which represent a connection with a particular client. These are
297
+ * created automatically by an API server instance when a client connects. The protocol is JSON with
298
+ * the top level being a dictionary having the following static keys specified by the client:
299
+ * serverID: defined by the server, this string defines where requests should be routed.
300
+ * clientID: defined by the client, this string defines where replies should be sent.
301
+ * These are class (code) designators. Further keys can be defined to identify a specific instance on
302
+ * the client or server.
303
+ *
304
+ */
305
+
306
+ closure WesCon(websocks, socket, request, local wescon) {
307
+ wescon = new(object, this)
308
+ wescon.socket = socket
309
+ wescon.serverIDs = []
310
+
311
+ // on message
312
+ //
313
+ // Incoming data.
314
+
315
+ socket.on("message", function onmessage(text, local message, error) {
316
+ try {
317
+ message = new(js.g.JSON.parse(text))
318
+ if message.clientID && websocks.subsystems[message.serverID] {
319
+ wescon.serverIDs.push(message.serverID) // ### track subsystems for closing
320
+ websocks.subsystems[message.serverID].wsReceive(message, wescon)
321
+ }
322
+ else
323
+ error = Error("can't route message")
324
+ } catch {
325
+ if true
326
+ error = Error("can't decode message JSON", exception)
327
+ }
328
+ if error
329
+ socket.send(js.g.JSON.stringify([error]))
330
+ })
331
+
332
+ // on error
333
+ //
334
+ // Error has occurred on this connection.
335
+
336
+ socket.on("error", function onerror(error) {
337
+ debuglog("connection error", error)
338
+ })
339
+
340
+ // on close
341
+ //
342
+ // Connection has closed.
343
+
344
+ socket.on("close", function onclose(code, reason, local serverID) {
345
+ if code != 1000 && code != 1001 && code != 1005
346
+ debuglog("connection has closed:", code, reason)
347
+ websocks.closeConn(wescon)
348
+ wecson.closed = {
349
+ code: code
350
+ reason: reason
351
+ }
352
+ for serverID in wescon.serverIDs
353
+ websocks.subsystems[message.serverID].wsClose(wescon) // notify of our closures
354
+ })
355
+
356
+ // send
357
+ //
358
+ // Send a dictionary, which must have a clientID defined.
359
+
360
+ wescon.send = function send(message) {
361
+ if !message.clientID || !message.serverID
362
+ throw("Wescon.send: client and server IDs required")
363
+ if wescon.closed
364
+ list(Error("Socket connection closed", wescon.closed))
365
+ socket.send(js.g.JSON.stringify(message)),
366
+ [false, {ok: true}]
367
+ }
368
+
369
+ // finis
370
+ wescon
371
+ };
372
+
373
+
374
+ /*
375
+ * ApisInit
376
+ *
377
+ * Initialize the module.
378
+ *
379
+ */
380
+
381
+ function ApisInit(local manifest) {
382
+
383
+ manifest = `(MakeAPI, WebSocketServer, WesCon, ApisInit)
384
+
385
+ Naan.module.build(module.id, "API", function(modobj, compobj) {
386
+ require("./node.nlg")
387
+ compobj.manifest = manifest
388
+ modobj.exports.MakeAPI = MakeAPI
389
+
390
+ express = js.r("express")
391
+ bodyParser = js.r("body-parser")
392
+ textParser = bodyParser.text()
393
+ ws = js.r("ws")
394
+
395
+ require("./filesystem.nlg")
396
+ require("./psm_server.nlg")
397
+ require("./worker.nlg")
398
+ })
399
+ }();