@naanlang/naan 1.0.6 → 1.0.8

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 (45) hide show
  1. package/LICENSE.md +3 -4
  2. package/README.md +20 -2
  3. package/bin/index.js +2 -2
  4. package/dist/env_web.js +91 -18
  5. package/dist/naan.min.js +7 -7
  6. package/frameworks/browser/browser.nlg +92 -3
  7. package/frameworks/browser/https_request.nlg +2 -2
  8. package/frameworks/browser/sworker.js +17 -17
  9. package/frameworks/browser/terminals.nlg +14 -12
  10. package/frameworks/browser/workers.nlg +13 -6
  11. package/frameworks/client/psm_client.nlg +1 -0
  12. package/frameworks/common/common.nlg +39 -8
  13. package/frameworks/node/filesystem.nlg +32 -26
  14. package/frameworks/node/gitter.nlg +9 -4
  15. package/frameworks/node/https_request.nlg +19 -14
  16. package/frameworks/project/build.nlg +187 -74
  17. package/frameworks/project/projects.nlg +42 -17
  18. package/frameworks/running/running.nlg +33 -11
  19. package/frameworks/running/taskexec.nlg +1 -1
  20. package/frameworks/storage/file_manager.nlg +2 -1
  21. package/frameworks/storage/psm.nlg +20 -4
  22. package/frameworks/storage/psm_dbtables.nlg +13 -3
  23. package/lib/browser/env_web.js +93 -20
  24. package/lib/browser/env_webworker.js +10 -0
  25. package/lib/core/naanlib.js +7 -7
  26. package/package.json +2 -1
  27. package/plugins/serviceAws/aws/aws-sdk-node.min.js +1 -1
  28. package/plugins/serviceAws/aws/aws-sdk.min.js +1 -1
  29. package/plugins/serviceAws/aws/lambda_ws_init.nlg +2 -1
  30. package/plugins/serviceAws/aws_dynamo.nlg +45 -26
  31. package/plugins/serviceAws/aws_dynextra.nlg +157 -32
  32. package/plugins/serviceAws/aws_lambda.nlg +4 -8
  33. package/plugins/serviceAws/aws_s3.nlg +74 -28
  34. package/plugins/serviceAws/aws_sqs.nlg +113 -0
  35. package/plugins/serviceAws/dbt_aws.nlg +73 -24
  36. package/plugins/serviceAws/psm_aws.nlg +30 -11
  37. package/plugins/serviceAws/serviceAws.nlg +2 -4
  38. package/plugins/serviceYC/generic_api.yaml +36 -0
  39. package/plugins/serviceYC/naanide-relay-index.js +148 -0
  40. package/plugins/serviceYC/serviceYC.nlg +59 -0
  41. package/plugins/serviceYC/yc_function.nlg +161 -0
  42. package/test/test_01_core.nlg +2 -2
  43. package/test/test_02_context.nlg +2 -2
  44. package/test/test_05_strings.nlg +11 -1
  45. package/test/test_06_lingoparse.nlg +43 -14
@@ -6,11 +6,92 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2020-2021 by Richard C. Zulch
9
+ * Copyright (c) 2020-2023 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
13
13
 
14
+ /*
15
+ * FileReader
16
+ *
17
+ * Read file(s) from the browser's host machine. This is passed a File object and returns a
18
+ * nearly-standard (error, blob, size) tuple. If progress is specified then this function is called
19
+ * with a percentage of completion from zero to 100 if available, or true otherwise. The progress
20
+ * callback is called with "false" when completed, with or without success
21
+ *
22
+ */
23
+
24
+ closure FileReader(file, progress, local pending, freader, result) {
25
+ pending = new(nonce)
26
+ freader = xnew(window.FileReader)
27
+ freader.addEventListener("load", function(event, local blob) {
28
+ blob = xnew(window.Blob, [freader.result], {
29
+ type: file.type
30
+ })
31
+ pending.signal(list(false, blob, event.total))
32
+ })
33
+ freader.addEventListener("error", function(error) {
34
+ pending.signal(list(error))
35
+ })
36
+ freader.AddEventListener("progress", function(event) {
37
+ if event.lengthComputable && event.total
38
+ progress(toint((event.loaded * 100) / event.total))
39
+ else
40
+ progress(true)
41
+ })
42
+ freader.readAsArrayBuffer(file)
43
+ result = pending.wait()
44
+ progress(false)
45
+ result
46
+ };
47
+
48
+
49
+ /*
50
+ * FileDownload
51
+ *
52
+ * Download a file from the browser, returning a standard error tuple.
53
+ *
54
+ */
55
+
56
+ closure FileDownload(file, progress, local error, blob, sizez, url, link) {
57
+ `(error, blob, size) = FileReader(file, progress)
58
+ if error
59
+ list(error)
60
+ else {
61
+ url = window.URL.createObjectURL(blob)
62
+ link = document.createElement("a")
63
+ link.href = url
64
+ link.download = file.name
65
+ link.click()
66
+ window.URL.revokeObjectURL(url)
67
+ list(false, file.name)
68
+ }
69
+ };
70
+
71
+
72
+ /*
73
+ * Platform
74
+ *
75
+ * Return a string identifying the platform our browser is running on, or false if unknown.
76
+ *
77
+ */
78
+
79
+ function Platform(local agent, patterns, key, rx) {
80
+ agent = window.navigator.userAgent.toLowerCase()
81
+ patterns = {
82
+ macos: RegExp("macintosh|macintel|macppc|mac68k|macos")
83
+ windows: RegExp("win32|win64|windows|wince")
84
+ ios: RegExp("iphone|ipad|ipod")
85
+ android: RegExp("android")
86
+ linux: RegExp("linux")
87
+ }
88
+ for `(key, rx) in patterns
89
+ if rx.test(agent)
90
+ return (key)
91
+ false
92
+ };
93
+
94
+
14
95
  /*
15
96
  * brorInit
16
97
  *
@@ -20,11 +101,19 @@
20
101
  */
21
102
 
22
103
  function brorInit(local manifest) {
23
- manifest = `(brorInit)
104
+ manifest = `(FileReader, FileDownload, Platform, brorInit)
24
105
 
25
106
  Naan.module.build(module.id, "browser", function(modobj, compobj) {
26
107
  require("../common").LiveImport()
27
108
  compobj.manifest = manifest
28
- runningExecutors = require("../running/executors.nlg")
109
+ modobj.exports.FileReader = FileReader
110
+ modobj.exports.FileDownload = FileDownload
111
+ modobj.exports.Platform = Platform
112
+
113
+ function brorReload() {
114
+ window = js.w
115
+ document = window.document
116
+ }()
117
+ module.reload = brorReload
29
118
  })
30
119
  } ();
@@ -72,7 +72,7 @@ closure HttpsApiRequest(url, options,
72
72
  //
73
73
  // perform the fetch and return when complete
74
74
  //
75
- `(error, response) = await(js.w.fetch(urlq, fetchOptions))
75
+ `(error, response) = await(window.fetch(urlq, fetchOptions))
76
76
  if error
77
77
  return (list(Error("HttpsApiRequest fetch failed:", error, url)))
78
78
  contentType = response.headers.get("content-type")
@@ -113,7 +113,7 @@ function https_browserInit(local manifest) {
113
113
  manifest = `(HttpsApiRequest, https_browserInit)
114
114
 
115
115
  Naan.module.build(module.id, "https_request", function(modobj, compobj) {
116
- require("./browser.nlg")
116
+ require("browser.nlg")
117
117
  compobj.manifest = manifest
118
118
  modobj.exports.HttpsApiRequest = HttpsApiRequest
119
119
  })
@@ -36,7 +36,7 @@
36
36
  *
37
37
  */
38
38
 
39
- var CurrentCacheName = "Naanlang-1.0.6-2";
39
+ var CurrentCacheName = "Naanlang-1.0.8+1";
40
40
 
41
41
 
42
42
  //
@@ -89,11 +89,11 @@ var waitingForInit = []; // initialization functions, or
89
89
  var pubVersion = event.data.hereIsMyVersion;
90
90
  var sourceId = event.source.id; // client id of sender of message
91
91
  msgPorts[sourceId] = msgport;
92
- console.log("[1.0.6-2] received new msgport for", sourceId, pubID, "-", pubVersion);
93
- if (pubVersion != "1.0.6-2")
92
+ console.log("[1.0.8+1] received new msgport for", sourceId, pubID, "-", pubVersion);
93
+ if (pubVersion != "1.0.8+1")
94
94
  msgport.postMessage({ // notify new version available
95
95
  id: "upgrade",
96
- version: "1.0.6-2"
96
+ version: "1.0.8+1"
97
97
  });
98
98
  Reaper(); // clean up obsolete info
99
99
 
@@ -107,7 +107,7 @@ var waitingForInit = []; // initialization functions, or
107
107
  if (msg.id == "response")
108
108
  processResponse(msg);
109
109
  else if (msg.id == "text")
110
- console.log("[1.0.6-2] msg received:", msg.text);
110
+ console.log("[1.0.8+1] msg received:", msg.text);
111
111
  };
112
112
 
113
113
  // send text to IDE log
@@ -118,7 +118,7 @@ var waitingForInit = []; // initialization functions, or
118
118
  // don't clutter the log
119
119
  msgport.postMessage({
120
120
  id: "text",
121
- text: "port received by 1.0.6-2",
121
+ text: "port received by 1.0.8+1",
122
122
  });
123
123
  */
124
124
  if (--pending === 0)
@@ -135,7 +135,7 @@ var waitingForInit = []; // initialization functions, or
135
135
  includeUncontrolled: true
136
136
  }).then(function(clientList) {
137
137
  clientList.every(function(client) {
138
- console.log("[1.0.6-2] requesting new msgport for", client.id);
138
+ console.log("[1.0.8+1] requesting new msgport for", client.id);
139
139
  ++pending;
140
140
  client.postMessage({ // tell client(s) we need this fetch source
141
141
  msg: "Naan_need_fetch_port",
@@ -181,12 +181,12 @@ function Reaper() {
181
181
  clients[clientList[clidex].id] = clientList[clidex];
182
182
  for (var sourceId in msgPorts)
183
183
  if (!clients[sourceId]) {
184
- console.log("[1.0.6-2] source gone:", sourceId);
184
+ console.log("[1.0.8+1] source gone:", sourceId);
185
185
  delete msgPorts[sourceId]; // no longer a source
186
186
  }
187
187
  for (var clientId in fetchPorts)
188
188
  if (!clients[clientId]) {
189
- console.log("[1.0.6-2] client gone:", clientId);
189
+ console.log("[1.0.8+1] client gone:", clientId);
190
190
  delete fetchPorts[clientId]; // no longer a client
191
191
  }
192
192
  for (var fqdex = 0; fqdex < fetchQueue.length; ++fqdex) {
@@ -220,13 +220,13 @@ function ClearCaches() {
220
220
  return (Promise.all(
221
221
  cacheNames.map(function(cacheName) {
222
222
  if (cacheName != CurrentCacheName) {
223
- console.log('[1.0.6-2] deleting old cache:', cacheName);
223
+ console.log('[1.0.8+1] deleting old cache:', cacheName);
224
224
  return (caches.delete(cacheName));
225
225
  }
226
226
  })
227
227
  ));
228
228
  }).then(function() { // claim all clients
229
- console.log('[1.0.6-2] claiming clients');
229
+ console.log('[1.0.8+1] claiming clients');
230
230
  return (self.clients.claim());
231
231
  });
232
232
  return (promise);
@@ -269,7 +269,7 @@ function GetClientResponse(event, urlpath) {
269
269
  msgport.postMessage({
270
270
  id: "fetch",
271
271
  seq: seqno,
272
- version: "1.0.6-2",
272
+ version: "1.0.8+1",
273
273
  request: {
274
274
  method: event.request.method,
275
275
  url: event.request.url
@@ -317,7 +317,7 @@ function GetClientResponse(event, urlpath) {
317
317
  */
318
318
 
319
319
  self.addEventListener('install', function(event) {
320
- console.log("[1.0.6-2] install");
320
+ console.log("[1.0.8+1] install");
321
321
  self.skipWaiting();
322
322
  });
323
323
 
@@ -339,7 +339,7 @@ self.addEventListener('fetch', function(event) {
339
339
  var promise;
340
340
  var url = new URL(event.request.url);
341
341
  var nocache = event.request.method != "GET"
342
- || url.search.length !== 0
342
+ || url.search.length !== 0 && url.searchParams.get("naanver") !== "09e820a5a47c4b099bacaa5d8a7d3f7a"
343
343
  || event.request.headers.get('range');
344
344
  if (url.pathname.startsWith("/run/")) {
345
345
  nocache = true;
@@ -356,7 +356,7 @@ self.addEventListener('fetch', function(event) {
356
356
  }
357
357
  else
358
358
  promise = fetch(event.request).catch(function (e) {
359
- console.log("[1.0.6-2] fetch failed", e);
359
+ console.log("[1.0.8+1] fetch failed", e);
360
360
  return (new Response(undefined, {
361
361
  status: 404,
362
362
  statusText: "Fetch Failed"
@@ -385,14 +385,14 @@ self.addEventListener('fetch', function(event) {
385
385
  */
386
386
 
387
387
  self.addEventListener('activate', function(event) {
388
- console.log("[1.0.6-2] activate");
388
+ console.log("[1.0.8+1] activate");
389
389
  self.clients.matchAll({ // for debugging, list controlled clients
390
390
  includeUncontrolled: true
391
391
  }).then(function(clientList) {
392
392
  var urls = clientList.map(function(client) {
393
393
  return (client.url);
394
394
  });
395
- console.log('[1.0.6-2] matching clients:', urls.join(', '));
395
+ console.log('[1.0.8+1] matching clients:', urls.join(', '));
396
396
  });
397
397
  var promise = ClearCaches();
398
398
  if (event.waitUntil)
@@ -21,7 +21,7 @@
21
21
  closure TermHost(track, api, name, workerID, options,
22
22
  local target, nlregex, clientID, serverID)
23
23
  {
24
- target = runningExecutors.ExecutorBase(track, "Host", name)
24
+ target = require("../running/executors.nlg").ExecutorBase(track, "Host", name)
25
25
  clientID = "DebugWorkers"
26
26
  serverID = "Workers"
27
27
  nlregex = RegExp("\\n", "g")
@@ -35,7 +35,7 @@ closure TermHost(track, api, name, workerID, options,
35
35
  closure connect(local pending) {
36
36
  if target.ws
37
37
  return
38
- target.ws = xnew(js.w.WebSocket,"ws://".concat(js.w.location.host)) // ### use api parameter
38
+ target.ws = xnew(window.WebSocket,"ws://".concat(window.location.host)) // ### use api parameter
39
39
  pending = new(nonce)
40
40
 
41
41
  // onopen
@@ -52,7 +52,7 @@ closure TermHost(track, api, name, workerID, options,
52
52
 
53
53
  target.ws.onmessage = function onmessage(e, message, local msg) {
54
54
  try {
55
- message = new(js.w.JSON.parse(e.data))
55
+ message = new(window.JSON.parse(e.data))
56
56
  } catch {
57
57
  if true {
58
58
  debuglog("can't decode incoming ws message:", exception)
@@ -169,7 +169,7 @@ closure TermHost(track, api, name, workerID, options,
169
169
  // Send a message to the worker controller.
170
170
 
171
171
  target.sendControl = function sendControl(workerOp, payload) {
172
- target.ws.send(js.w.JSON.stringify({
172
+ target.ws.send(window.JSON.stringify({
173
173
  guid: api.guid
174
174
  clientID: clientID
175
175
  serverID: serverID
@@ -368,23 +368,23 @@ closure TermLocal(track, name, workerID, options,
368
368
  options = new(options)
369
369
  else
370
370
  options = { }
371
- target = runningExecutors.ExecutorBase(track, "Local", name)
371
+ target = require("../running/executors.nlg").ExecutorBase(track, "Local", name)
372
372
  nlregex = RegExp("\\n", "g")
373
373
  target.workerID = workerID
374
374
  target.msgQueue = []
375
375
  if workerID == "NaanIDE-Debug" {
376
- target.worker = js.w.open(js.w.location.href, "_blank")
376
+ target.worker = window.open(window.location.href, "_blank")
377
377
  target.worker.addEventListener("beforeunload", function(e) { // our target is closing
378
378
  destroy()
379
379
  })
380
- js.w.addEventListener("beforeunload", function(e) { // we are closing
380
+ window.addEventListener("beforeunload", function(e) { // we are closing
381
381
  // ### tell target we are closing (if needed)
382
382
  })
383
- listener = js.w
383
+ listener = window
384
384
  } else {
385
- if not js.w.Worker
385
+ if not window.Worker
386
386
  return (list(Error("Local environment does not support workers")))
387
- target.worker = xnew(js.w.Worker, "env_webworker.js")
387
+ target.worker = xnew(window.Worker, "env_webworker.js")
388
388
  listener = target.worker
389
389
  }
390
390
 
@@ -460,6 +460,8 @@ closure TermLocal(track, name, workerID, options,
460
460
  target.statusCB(target, msg.status)
461
461
  else if msg.id == "debugout"
462
462
  target.debugger.debugData(target, msg.data)
463
+ else if msg.id == "download"
464
+ FileDownload(xnew(window.File, msg.bits, msg.name, msg.options))
463
465
  else if msg.id == "loaded" {
464
466
  if !target.started
465
467
  target.worker.postMessage({
@@ -610,7 +612,7 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
610
612
  track.update(target)
611
613
  return (target)
612
614
  }
613
- target = runningExecutors.ExecutorBase(track, "Local", name)
615
+ target = require("../running/executors.nlg").ExecutorBase(track, "Local", name)
614
616
  target.name = name
615
617
  target.title = title
616
618
  target.workerID = workerID
@@ -778,7 +780,7 @@ closure termInstallVirtualWatcher(track, naancont) {
778
780
  }
779
781
  }
780
782
 
781
- runningExecutors.TaskOnMessageHook(watchVsites)
783
+ require("../running/executors.nlg").TaskOnMessageHook(watchVsites)
782
784
  };
783
785
 
784
786
 
@@ -29,7 +29,7 @@ closure ServiceWorker(pubID, pubVersion, local serv, callback) {
29
29
  closure updateReg(local mchan) {
30
30
  if !serv.sw
31
31
  return
32
- mchan = xnew(js.w.MessageChannel)
32
+ mchan = xnew(window.MessageChannel)
33
33
  serv.msgport = mchan.port2
34
34
  serv.msgport.onmessage = workerMsg.proc
35
35
  serv.sw.postMessage({
@@ -56,6 +56,7 @@ closure ServiceWorker(pubID, pubVersion, local serv, callback) {
56
56
  })
57
57
  } else if msg.id == "upgrade" {
58
58
  if serv.upgrade != msg.version {
59
+ debuglog("service worker upgrade:", serv.upgrade, "to", msg.version)
59
60
  serv.upgrade = msg.version // only report once
60
61
  callback(false, {
61
62
  message: "upgrade"
@@ -112,13 +113,13 @@ closure ServiceWorker(pubID, pubVersion, local serv, callback) {
112
113
  serv.scope = scope
113
114
  if !scope
114
115
  return (makeResult(Error("service worker scope required")))
115
- if !js.w.navigator.serviceWorker
116
+ if !window.navigator.serviceWorker
116
117
  return (makeResult(Error("service workers not supported")))
117
- js.w.navigator.serviceWorker.addEventListener("message", function(event) {
118
+ window.navigator.serviceWorker.addEventListener("message", function(event) {
118
119
  if event.data.msg == "Naan_need_fetch_port"
119
120
  updateReg()
120
121
  })
121
- await(js.w.navigator.serviceWorker.register("sworker.js", { scope: scope }).then(function (reg) {
122
+ await(window.navigator.serviceWorker.register("sworker.js", { scope: scope }).then(function (reg) {
122
123
  return (reg.update())
123
124
  }).then(function (reg) {
124
125
  serv.reg = reg
@@ -134,6 +135,12 @@ closure ServiceWorker(pubID, pubVersion, local serv, callback) {
134
135
  serv.sw = serv.reg.installing // worker version was updated
135
136
  updateReg()
136
137
  })
138
+ reg.addEventListener("statechange", function() {
139
+ debuglog("service worker state change:", serv.reg.state)
140
+ })
141
+ reg.addEventListener("controllerchange", function() {
142
+ debuglog("service worker controller change:", serv.upgrade)
143
+ })
137
144
  result = makeResult(false, {
138
145
  message: "opened"
139
146
  })
@@ -211,7 +218,7 @@ closure ScopedServiceWorker(pubID, pubVersion, callback, local scoper, result) {
211
218
  }
212
219
 
213
220
  // read resource
214
- filepath = xnew(js.w.URL, data.request.url).pathname
221
+ filepath = xnew(window.URL, data.request.url).pathname
215
222
  filepath = DecodeURIComponent(filepath) // "/run/<scope>/path..."
216
223
  filepath = filepath.slice(4) // "/<scope>/path..."
217
224
  error = true // stays true iff not in scope
@@ -308,7 +315,7 @@ closure TrackedScope(track, scope, fs, rootpath, local trope, result) {
308
315
  trope = findTrackedScope(track, scope)
309
316
  if trope
310
317
  return (list(false, trope))
311
- trope = runningExecutors.ExecutorBase(track, "ServiceWorkers", scope)
318
+ trope = require("../running/executors.nlg").ExecutorBase(track, "ServiceWorkers", scope)
312
319
  serviceWorker.register(scope, closure(filepath, scope, init,
313
320
  local options, mimeType, error, data) {
314
321
  mimeType = {
@@ -63,6 +63,7 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
63
63
  pathmod = JSpath.win32
64
64
  else
65
65
  pathmod = JSpath.posix
66
+ view.path.sep = pathmod.sep
66
67
  false
67
68
  }
68
69
  }
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2020-2022 by Richard C. Zulch
9
+ * Copyright (c) 2020-2023 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -96,6 +96,27 @@ function UUID(local rando, cc) {
96
96
  };
97
97
 
98
98
 
99
+ /*
100
+ * VersionCheck
101
+ *
102
+ * Check if the test version is new enough compared to the reference version. This returns false
103
+ * if the test version is out of date, or the difference between the build numbers otherwise, which
104
+ * is positive if the test is larger than the reference.
105
+ *
106
+ */
107
+
108
+ function VersionCheck(testv, refv, local rxver, test, ref) {
109
+ rxver = RegExp("([0-9]+)[.]([0-9]+)[.]([0-9]+)-?[A-Za-z_]*[+]?([0-9]+)")
110
+ function numerify(x){ Number.parseInt(x) }
111
+ test = testv.match(rxver).map(numerify.proc)
112
+ ref = refv.match(rxver).map(numerify.proc)
113
+ if test.1 == ref.1 && test.2 == ref.2 && test.3 == ref.3
114
+ test.4 - ref.4 // build number difference
115
+ else
116
+ false
117
+ };
118
+
119
+
99
120
  /*
100
121
  * JsonParse
101
122
  *
@@ -143,7 +164,7 @@ function JsonStringify(data) {
143
164
  jsScripts = { }; // script values become false on reload
144
165
 
145
166
  function JsLoadScript(libpath, globalID, local scriptTag, fpath) {
146
- if jsScripts[jsScripts]
167
+ if jsScripts[libpath]
147
168
  return // already loaded
148
169
  if libpath.startsWith("/")
149
170
  fpath = libpath
@@ -155,10 +176,10 @@ function JsLoadScript(libpath, globalID, local scriptTag, fpath) {
155
176
  } else if js.w { // load in browser context
156
177
  pending = new(nonce)
157
178
  scriptTag = js.w.document.createElement("script")
158
- scriptTag.src = js.w.location.origin.concat(fpath)
179
+ scriptTag.src = js.w.location.origin.concat(fpath, requireQuery())
159
180
  scriptTag.onload = function (event) {
160
181
  jsScripts[libpath] = js.w[globalID]
161
- pending.signal(JSZipLib)
182
+ pending.signal(js.w[globalID])
162
183
  true
163
184
  }
164
185
  scriptTag.onerror = function (event) {
@@ -303,7 +324,8 @@ JSONparse = false;
303
324
  Uint8ArrayFromString = false;
304
325
 
305
326
  function comrInit(local manifest) {
306
- manifest = `(EncodeQuery, ContentTypeFromFileExt, UUID, JsLoadScript, LoadComponentOnDemand, LiveExport, comrInit)
327
+ manifest = `(EncodeQuery, ContentTypeFromFileExt, UUID, VersionCheck, JsonParse, JsonStringify,
328
+ JsLoadScript, LoadComponentOnDemand, LiveExport, comrInit)
307
329
 
308
330
  Naan.module.build(module.id, "common", closure(modobj, compobj) {
309
331
  compobj.manifest = manifest
@@ -418,7 +440,9 @@ function comrInit(local manifest) {
418
440
  }
419
441
  //
420
442
  // MD5 functions
421
- JsLoadScript("frameworks/browser/spark-md5/spark-md5.min.js", "SparkMD5")
443
+ if symbol(NideBuild) { // execute if we are not building
444
+ JsLoadScript("frameworks/browser/spark-md5/spark-md5.min.js", "SparkMD5")
445
+ }
422
446
  //
423
447
  // hasMD5 in hex
424
448
  HashMD5 = function browserMD5(data, raw) {
@@ -474,12 +498,18 @@ function comrInit(local manifest) {
474
498
  //
475
499
  // binary to Base64
476
500
  EncodeBase64 = function nodejsEncodeBase64(data) {
477
- wsg.Buffer.from(data, "binary").toString("base64")
501
+ if data
502
+ wsg.Buffer.from(data, "binary").toString("base64")
503
+ else
504
+ ""
478
505
  }
479
506
  //
480
507
  // Base64 to binary
481
508
  DecodeBase64 = function nodejsDecodeBase64(data) {
482
- wsg.Buffer.from(data, "base64").toString("binary")
509
+ if data
510
+ wsg.Buffer.from(data, "base64").toString("binary")
511
+ else
512
+ xnew(wsg.Buffer, "") // empty buffer
483
513
  }
484
514
  if !crypto
485
515
  crypto = js.r("crypto")
@@ -532,6 +562,7 @@ function comrInit(local manifest) {
532
562
  modobj.exports.JSONparse = JSONparse
533
563
  modobj.exports.JsonStringify = JsonStringify
534
564
  modobj.exports.JsonParse = JsonParse
565
+ modobj.exports.VersionCheck = VersionCheck
535
566
  modobj.exports.Uint8ArrayFromString = Uint8ArrayFromString
536
567
  modobj.exports.EncodeBase64url = EncodeBase64url
537
568
  modobj.exports.DecodeBase64url = DecodeBase64url
@@ -567,7 +567,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
567
567
  // info for each file as well.
568
568
 
569
569
  files.dirList = closure dirList(path, options, callback, local error, localpath, output, nodelist, file) {
570
- if path == "" && js.g.process.platform == "win32" && rootpath == "\\"
570
+ if js.g.process.platform == "win32" && rootpath == "\\" && (path == "" || path == "\\")
571
571
  return (files.winDrives(callback)) // top level is drive letters in Windows
572
572
  if !callback
573
573
  return (syncAdapter(dirList, path, options))
@@ -867,31 +867,37 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
867
867
  if !callback
868
868
  return (syncAdapter(reveal, path))
869
869
 
870
- function addpath(path, local error, localpath) {
871
- `(error, localpath) = localPath(path)
872
- if error
873
- errors.push(error)
874
- else
875
- pathargs.push("file://localhost".concat(localpath))
876
- }
877
-
878
- errors = []
879
- pathargs = ["-R", "--"] // reveal, then stop using '-' for ags
880
- if array(path)
881
- for item in path
882
- addpath(item)
883
- else
884
- addpath(path)
885
- nodecp.execFile("open",
886
- pathargs, // command-line options
887
- { }, // execution options
888
- function(err, stdout, stderr) {
889
- if err
890
- callback(Error("open failed", err, stderr))
891
- else
892
- callback(false, errors)
893
- }
894
- )
870
+ if js.g.process.platform == "win32" { // ### windows only allows one path
871
+ nodecp.exec('explorer.exe /select,"'.concat(path, '"'), function(err, stdout, stderr) {
872
+ callback(false, { ok: true }) // reports failure even if it works
873
+ })
874
+ } else {
875
+ function addpath(path, local error, localpath) {
876
+ `(error, localpath) = localPath(path)
877
+ if error
878
+ errors.push(error)
879
+ else
880
+ pathargs.push("file://localhost".concat(localpath))
881
+ }
882
+
883
+ errors = []
884
+ pathargs = ["-R", "--"] // reveal, then stop using '-' for ags
885
+ if array(path)
886
+ for item in path
887
+ addpath(item)
888
+ else
889
+ addpath(path)
890
+ nodecp.execFile("open",
891
+ pathargs, // command-line options
892
+ { }, // execution options
893
+ function(err, stdout, stderr) {
894
+ if err
895
+ callback(Error("open failed", err, stderr))
896
+ else
897
+ callback(false, errors)
898
+ }
899
+ )
900
+ }
895
901
  }
896
902
 
897
903
  //
@@ -76,10 +76,15 @@ closure Gitter(fs, local gitt) {
76
76
  // Compute the bridge path to an absolute repopath (which can point inside a repo) from the
77
77
  // phyiscal repo root. If these are the same, or an error occurs, then the result is "".
78
78
  //
79
- function bridgePath(repopath, local top) {
80
- top = repoRoot(repopath).1
81
- if top && repopath.startsWith(top) && repopath.length > top.length
82
- top = repopath.slice(top.length+1).concat(fs.path.sep) // move leading "/" of bridge path to trailing
79
+ function bridgePath(repopath, local above) {
80
+ above = repoRoot(repopath).1
81
+ if above
82
+ above = fs.path.normalize(above)
83
+ if above && repopath.startsWith(above) && repopath.length > above.length {
84
+ above = fs.path.relative(above, repopath).split(fs.path.sep).join("/")
85
+ if above != ""
86
+ above = above.concat("/")
87
+ }
83
88
  else
84
89
  "" // we are looking at the root, or an error
85
90
  }