@naanlang/naan 1.0.6 → 1.0.7

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.
@@ -11,6 +11,64 @@
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
+
14
72
  /*
15
73
  * brorInit
16
74
  *
@@ -20,11 +78,18 @@
20
78
  */
21
79
 
22
80
  function brorInit(local manifest) {
23
- manifest = `(brorInit)
81
+ manifest = `(FileReader, FileDownload, brorInit)
24
82
 
25
83
  Naan.module.build(module.id, "browser", function(modobj, compobj) {
26
84
  require("../common").LiveImport()
27
85
  compobj.manifest = manifest
28
- runningExecutors = require("../running/executors.nlg")
86
+ modobj.exports.FileReader = FileReader
87
+ modobj.exports.FileDownload = FileDownload
88
+
89
+ function brorReload() {
90
+ window = js.w
91
+ document = window.document
92
+ }()
93
+ module.reload = brorReload
29
94
  })
30
95
  } ();
@@ -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.7+2";
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.7+2] received new msgport for", sourceId, pubID, "-", pubVersion);
93
+ if (pubVersion != "1.0.7+2")
94
94
  msgport.postMessage({ // notify new version available
95
95
  id: "upgrade",
96
- version: "1.0.6-2"
96
+ version: "1.0.7+2"
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.7+2] 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.7+2",
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.7+2] 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.7+2] 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.7+2] 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.7+2] 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.7+2] 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.7+2",
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.7+2] 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") !== "cb-1.0.7+2"
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.7+2] 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.7+2] 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.7+2] 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({
@@ -112,13 +112,13 @@ closure ServiceWorker(pubID, pubVersion, local serv, callback) {
112
112
  serv.scope = scope
113
113
  if !scope
114
114
  return (makeResult(Error("service worker scope required")))
115
- if !js.w.navigator.serviceWorker
115
+ if !window.navigator.serviceWorker
116
116
  return (makeResult(Error("service workers not supported")))
117
- js.w.navigator.serviceWorker.addEventListener("message", function(event) {
117
+ window.navigator.serviceWorker.addEventListener("message", function(event) {
118
118
  if event.data.msg == "Naan_need_fetch_port"
119
119
  updateReg()
120
120
  })
121
- await(js.w.navigator.serviceWorker.register("sworker.js", { scope: scope }).then(function (reg) {
121
+ await(window.navigator.serviceWorker.register("sworker.js", { scope: scope }).then(function (reg) {
122
122
  return (reg.update())
123
123
  }).then(function (reg) {
124
124
  serv.reg = reg
@@ -211,7 +211,7 @@ closure ScopedServiceWorker(pubID, pubVersion, callback, local scoper, result) {
211
211
  }
212
212
 
213
213
  // read resource
214
- filepath = xnew(js.w.URL, data.request.url).pathname
214
+ filepath = xnew(window.URL, data.request.url).pathname
215
215
  filepath = DecodeURIComponent(filepath) // "/run/<scope>/path..."
216
216
  filepath = filepath.slice(4) // "/<scope>/path..."
217
217
  error = true // stays true iff not in scope
@@ -308,7 +308,7 @@ closure TrackedScope(track, scope, fs, rootpath, local trope, result) {
308
308
  trope = findTrackedScope(track, scope)
309
309
  if trope
310
310
  return (list(false, trope))
311
- trope = runningExecutors.ExecutorBase(track, "ServiceWorkers", scope)
311
+ trope = require("../running/executors.nlg").ExecutorBase(track, "ServiceWorkers", scope)
312
312
  serviceWorker.register(scope, closure(filepath, scope, init,
313
313
  local options, mimeType, error, data) {
314
314
  mimeType = {
@@ -143,7 +143,7 @@ function JsonStringify(data) {
143
143
  jsScripts = { }; // script values become false on reload
144
144
 
145
145
  function JsLoadScript(libpath, globalID, local scriptTag, fpath) {
146
- if jsScripts[jsScripts]
146
+ if jsScripts[libpath]
147
147
  return // already loaded
148
148
  if libpath.startsWith("/")
149
149
  fpath = libpath
@@ -155,10 +155,10 @@ function JsLoadScript(libpath, globalID, local scriptTag, fpath) {
155
155
  } else if js.w { // load in browser context
156
156
  pending = new(nonce)
157
157
  scriptTag = js.w.document.createElement("script")
158
- scriptTag.src = js.w.location.origin.concat(fpath)
158
+ scriptTag.src = js.w.location.origin.concat(fpath, requireQuery())
159
159
  scriptTag.onload = function (event) {
160
160
  jsScripts[libpath] = js.w[globalID]
161
- pending.signal(JSZipLib)
161
+ pending.signal(js.w[globalID])
162
162
  true
163
163
  }
164
164
  scriptTag.onerror = function (event) {
@@ -303,7 +303,8 @@ JSONparse = false;
303
303
  Uint8ArrayFromString = false;
304
304
 
305
305
  function comrInit(local manifest) {
306
- manifest = `(EncodeQuery, ContentTypeFromFileExt, UUID, JsLoadScript, LoadComponentOnDemand, LiveExport, comrInit)
306
+ manifest = `(EncodeQuery, ContentTypeFromFileExt, UUID, JsonParse, JsonStringify, JsLoadScript,
307
+ LoadComponentOnDemand, LiveExport, comrInit)
307
308
 
308
309
  Naan.module.build(module.id, "common", closure(modobj, compobj) {
309
310
  compobj.manifest = manifest
@@ -418,7 +419,9 @@ function comrInit(local manifest) {
418
419
  }
419
420
  //
420
421
  // MD5 functions
421
- JsLoadScript("frameworks/browser/spark-md5/spark-md5.min.js", "SparkMD5")
422
+ if symbol(NideBuild) { // execute if we are not building
423
+ JsLoadScript("frameworks/browser/spark-md5/spark-md5.min.js", "SparkMD5")
424
+ }
422
425
  //
423
426
  // hasMD5 in hex
424
427
  HashMD5 = function browserMD5(data, raw) {
@@ -716,6 +716,10 @@ closure Builder(rules, operation, fs, srcpath, destpath, local build, group, new
716
716
  entry.unzip = true
717
717
  entry.writepath = outdirpath
718
718
  }
719
+ if group.tasks.indexOf("catenate") >= 0
720
+ entry.catenate = true
721
+ if group.tasks.indexOf("zip") >= 0
722
+ entry.zip = true
719
723
  if group.tasks.indexOf("naanpack") >= 0 || group.tasks.indexOf("jspack") >= 0 || group.tasks.indexOf("syntax") >= 0 {
720
724
  let (inpar, outpar, extension) { // change extension for package output
721
725
  inpar = JSpath.parse(infile)
@@ -740,12 +744,12 @@ closure Builder(rules, operation, fs, srcpath, destpath, local build, group, new
740
744
  inpar.base = inpar.name.concat(extension)
741
745
  entry.insource = JSpath.format(inpar)
742
746
  }
743
- } else
747
+ } else if !entry.zip && !entry.catenate
744
748
  entry.copy = true // fall back to copy
745
749
  } ()
746
750
  }
747
751
  if group.tasks.indexOf("minimize") >= 0 {
748
- if infile.endsWith(".js") {
752
+ if infile.endsWith(".js") || outfile.endsWith(".js") {
749
753
  entry.minimize = true
750
754
  if group.minprefix
751
755
  entry.minprefix = group.minprefix // use group minify prefix
@@ -753,10 +757,7 @@ closure Builder(rules, operation, fs, srcpath, destpath, local build, group, new
753
757
  entry.minprefix = build.minprefix // use generic minify prefix
754
758
  }
755
759
  }
756
- if group.tasks.indexOf("catenate") >= 0
757
- entry.catenate = true
758
- if group.tasks.indexOf("zip") >= 0 {
759
- entry.zip = true
760
+ if entry.zip {
760
761
  if !entry.writepath.toLowerCase().endsWith(".zip")
761
762
  entry.writepath = entry.writepath.concat(".zip") // always ends with .zip
762
763
  outfile = entry.writepath
@@ -844,7 +845,8 @@ closure Builder(rules, operation, fs, srcpath, destpath, local build, group, new
844
845
  // checked and any that have all the parts are written out. Catenates that don't have all their
845
846
  // parts are reported as an error in addition to the error that caused them to be incomplete.
846
847
  //
847
- closure execute(local error, entries, pending, licFileDefs, buildno, verFileDefs, baddestpaths, catenates) {
848
+ closure execute(local error, licFileDefs, buildno, verFileDefs, version, entries, pending,
849
+ baddestpaths, catenates) {
848
850
  if build.tasks.license > 0
849
851
  `(error, licFileDefs) = readSubstitutionFile(build.licfilepath)
850
852
  if build.tasks.version > 0 {
@@ -858,6 +860,8 @@ closure Builder(rules, operation, fs, srcpath, destpath, local build, group, new
858
860
  `(error, verFileDefs) = readSubstitutionFile(build.verfilepath, {
859
861
  BuildNumber: buildno
860
862
  })
863
+ build.version = verFileDefs["Version"]
864
+ verFileDefs["CacheBuster"] = HashMD5(build.version.concat(Math.random()))
861
865
  }
862
866
  if build.tasks.catenate > 0 || build.tasks.zip > 0 {
863
867
  build.templates = { }
@@ -962,7 +966,7 @@ closure Builder(rules, operation, fs, srcpath, destpath, local build, group, new
962
966
 
963
967
  let (writepath, template, entry, content, catsub, dozip, docat, fsoptions, zipmap, error, result) {
964
968
  for :out1 writepath in catenates {
965
- template = build.templates[writepath] // optional
969
+ template = build.templates[writepath] // optional in some cases ### should warn in others
966
970
  catsub = { }
967
971
  for entry in catenates[writepath] { // error check and substitution build
968
972
  if !entry.content {
@@ -1054,7 +1058,7 @@ closure Builder(rules, operation, fs, srcpath, destpath, local build, group, new
1054
1058
  "\nfrom: ", JSpath.join(fs.rootpath, build.srcpath),
1055
1059
  "\n to: ", build.destpath,
1056
1060
  "\ntype: ", options.stage,
1057
- "\nvers: ", options.buildnum,
1061
+ "\nvers: ", build.version,
1058
1062
  "\n", sink.taketext())
1059
1063
  `(error) = fs.writeFile(JSpath.join(build.destpath, "build_log.txt"), outext)
1060
1064
  if error
@@ -296,7 +296,7 @@ closure projConnector(projman, projtype, local connector, watch) {
296
296
  *
297
297
  * Nide.proj/
298
298
  * nide_cliser.cfg - JSON definition of the project (see below)
299
- * NaanIDE_version.txt - [default] substitution file defining 1.0.6-1 etc.
299
+ * NaanIDE_version.txt - [default] substitution file defining 1.0.7+1 etc.
300
300
  * NaanIDE_version_builds.txt - [default] contains current build number as decimal string
301
301
  * build/ - [optional] default build output location
302
302
  * NaanIDE.lic - [optional] defines Zulch Laboratories, Inc. and other license info
@@ -408,7 +408,11 @@ closure projConfig(projman, where, projID, local procon, fs, configpath) {
408
408
  if error
409
409
  debuglog("projConfig.writeConfig cannot write local storage:", ErrorString(error))
410
410
  }
411
- `(error, data) = fs.writeFile(configpath, JSONstringify(procon.configDict))
411
+ if procon.configMD5 { // don't overwrite existing file
412
+ data = HashMD5(JSONstringify(procon.configDict)) // ### it messes up the formatting and
413
+ error = false // is manually maintained anyway
414
+ } else
415
+ `(error, data) = fs.writeFile(configpath, JSONstringify(procon.configDict))
412
416
  if !error {
413
417
  procon.configMD5 = data
414
418
  `(error, info) = fs.info(configpath)
@@ -561,37 +565,44 @@ closure projConfig(projman, where, projID, local procon, fs, configpath) {
561
565
 
562
566
  // buildrules
563
567
  //
564
- // Get the build rules for the named stage.
568
+ // Get the build rules for the named stage, reloading the project configuration if changed.
565
569
  //
566
- function buildrules(stage, local rules, common, rule, key) {
570
+ function buildrules(stage, local error, data, rules, common, rule, key) {
571
+ if !procon.loaded
572
+ return (list(Error("project not loaded")))
573
+ `(error, data) = procon.changed()
574
+ if error
575
+ return (list(error))
567
576
  rules = procon.configDict."build-rules"[stage]
568
577
  if !rules
569
578
  rules = procon.configDict.build // fallback to old config structure
570
579
  rules = new(rules)
571
- common = procon.configDict."build-common"
580
+ if !rules["no-common"]
581
+ common = procon.configDict."build-common"
572
582
  if common {
573
583
  for rule in common
574
584
  if !rules[rule]
575
585
  rules[rule] = common[rule] // common rule was not overridden
576
- else if array(common[rule], rules[rule])
586
+ else if array(common[rule], rules[rule]) // ### array only tests first argument 20220909 Rcz
577
587
  rules[rule] = common[rule].concat(rules[rule]) // merge common array with rule
578
- else if dictionary(common[rule], rules[rule]) {
588
+ else if dictionary(common[rule], rules[rule]) { // ### dictionary only tests first argument 20220909 Rcz
579
589
  for key in common[rule] // merge common dictionary with rule
580
590
  if !rules[rule][key]
581
591
  rules[rule][key] = common[rule][key]
582
592
  }
583
593
  }
584
- rules
594
+ list(false, rules)
585
595
  }
586
596
 
587
597
  // run
588
598
  //
589
599
  // Run the project by building and then launching.
590
600
  //
591
- procon.run = closure run(stage, buildonly, local rules, builder, buildpath, error, buildnum) {
592
- if !procon.loaded
593
- return (list(Error("project not loaded")))
594
- rules = buildrules(stage)
601
+ procon.run = closure run(stage, buildonly,
602
+ local error, rules, builder, buildpath, error, buildnum) {
603
+ `(error, rules) = buildrules(stage)
604
+ if error
605
+ return (list(error))
595
606
  if !rules || !rules.products
596
607
  return (list(Error("build rules missing or incomplete")))
597
608
  buildpath = fs.path.join(proj_configDataFolder, rules.products)
@@ -628,13 +639,27 @@ closure projConfig(projman, where, projID, local procon, fs, configpath) {
628
639
  //
629
640
  // Publish the project to its configured location.
630
641
  //
631
- procon.publish = closure publish(stage, local rules, where, publish, error, outfs, inpath) {
632
- rules = buildrules(stage)
642
+ // {
643
+ // input: "tutorApp/www/"
644
+ // sources: [""]
645
+ // output: ""
646
+ // cacheControl: "max-age=2592000"
647
+ // }
648
+ //
649
+ procon.publish = closure publish(stage,
650
+ local error, rules, where, publish, error, outOptions, outfs, inpath) {
651
+ `(error, rules) = buildrules(stage)
652
+ if error
653
+ return (list(error))
633
654
  publish = rules.publish
634
655
  where = procon.localDict.publish[stage].where
635
656
  if !rules || !where
636
657
  return (list(Error("no project publish location configured")))
637
- `(error, outfs) = projman.locate.connect(where.locationID, "NideFS", where.path)
658
+ if publish.cacheControl
659
+ outOptions = {
660
+ cacheControl: publish.cacheControl
661
+ }
662
+ `(error, outfs) = projman.locate.connect(where.locationID, "NideFS", where.path, outOptions)
638
663
  if error
639
664
  return (list(Error("can't access publishing filesystem", error)))
640
665
  inpath = fs.path.join(proj_configDataFolder, rules.products, publish.input)
@@ -671,8 +696,8 @@ closure projConfig(projman, where, projID, local procon, fs, configpath) {
671
696
  */
672
697
 
673
698
  function projInit(local manifest) {
674
-
675
- manifest = `(ProjectManager, projTracker, projConnector, projConfig, projInit)
699
+ manifest = `(ProjectManager, projTracker, projConnector, proj_configDataFolder,
700
+ proj_cliserConfigFile, projConfig, projInit)
676
701
 
677
702
  Naan.module.build(module.id, "projects", function(modobj, compobj) {
678
703
  require("./project.nlg")
@@ -144,7 +144,7 @@ function procstring(procdef, options, local name, output, parm) {
144
144
  function runnInit(local manifest) {
145
145
  manifest = `(rootproc, baseproc, pathmatch, procpath, procname, procstring, runnInit)
146
146
 
147
- build(module.id, "running", closure(modobj, compobj) {
147
+ Naan.module.build(module.id, "running", closure(modobj, compobj) {
148
148
  require("../common").LiveImport()
149
149
  compobj.manifest = manifest
150
150
  })
@@ -119,7 +119,7 @@ closure taskDispatcher(replier, local contexts, gohome, util) {
119
119
  }
120
120
  }
121
121
  else
122
- call(onMessageHook, data)
122
+ onMessageHook(data)
123
123
  } catch {
124
124
  if true {
125
125
  if tuple(exception)
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2020-2021 by Richard C. Zulch
9
+ * Copyright (c) 2020-2022 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -287,6 +287,7 @@ closure FileManager(fs, options, local files, watch, opqueue, willgit, hadgit) {
287
287
  fixed: true
288
288
  ignoreCase: true
289
289
  returnText: true
290
+ excludeDirs: []
290
291
  }
291
292
  }
292
293