@naanlang/naan 1.0.3 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +8 -6
- package/bin/index.js +2 -2
- package/dist/env_web.js +30 -6
- package/dist/naan.min.js +4 -4
- package/frameworks/browser/https_request.nlg +120 -0
- package/frameworks/browser/sworker.js +29 -39
- package/frameworks/browser/terminals.nlg +6 -4
- package/frameworks/browser/workers.nlg +13 -6
- package/frameworks/client/apiclient.nlg +1 -1
- package/frameworks/client/psm_client.nlg +80 -32
- package/frameworks/common/common.nlg +104 -26
- package/frameworks/common/preferences.nlg +1 -0
- package/frameworks/common/watching.nlg +1 -0
- package/frameworks/node/apiserver.nlg +9 -5
- package/frameworks/node/filesystem.nlg +89 -31
- package/frameworks/node/gitter.nlg +27 -6
- package/frameworks/node/https_request.nlg +119 -0
- package/frameworks/node/node.nlg +1 -0
- package/frameworks/node/psm_server.nlg +29 -7
- package/frameworks/project/build.nlg +13 -7
- package/frameworks/project/proj_cliser.nlg +11 -3
- package/frameworks/project/proj_console.nlg +13 -4
- package/frameworks/project/proj_folder.nlg +10 -1
- package/frameworks/project/proj_lambda.nlg +13 -4
- package/frameworks/project/proj_static.nlg +11 -3
- package/frameworks/project/projects.nlg +102 -20
- package/lib/browser/env_web.js +32 -8
- package/lib/core/naanlib.js +4 -4
- package/package.json +2 -1
- package/plugins/serviceAws/aws/aws-sdk-node.min.js +2 -0
- package/plugins/serviceAws/aws/aws-sdk.min.js +2 -88
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +7 -6
- package/plugins/serviceAws/aws_dynamo.nlg +128 -45
- package/plugins/serviceAws/aws_lambda.nlg +11 -4
- package/plugins/serviceAws/aws_s3.nlg +44 -14
- package/plugins/serviceAws/dbt_aws.nlg +29 -36
- package/plugins/serviceAws/psm_aws.nlg +21 -16
- package/plugins/serviceAws/serviceAws.nlg +6 -4
- package/test/harness.nlg +3 -1
- package/test/test_01_core.nlg +5 -5
- package/test/test_02_context.nlg +4 -4
- package/test/test_03_jsinterop.nlg +9 -3
- package/plugins/serviceAws/aws_cognito.nlg +0 -76
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* https_browser.nlg
|
|
3
|
+
*
|
|
4
|
+
* Https operations for the browser.
|
|
5
|
+
*
|
|
6
|
+
* column positioning: // // !
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2021-2022 by Richard C. Zulch
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* HttpsApiRequest
|
|
15
|
+
*
|
|
16
|
+
* Perform an API request from the browser. This operates the same as HttpsApiRequest for NodeJS.
|
|
17
|
+
*
|
|
18
|
+
* Options:
|
|
19
|
+
* {
|
|
20
|
+
* method: <string> // HTTP method (defaults to GET/PUT)
|
|
21
|
+
* query: <dictionary> // query variables added to the URL
|
|
22
|
+
* putdata: <data> // data to put
|
|
23
|
+
* contentType: <string> // sets Content-Type header, otherwise auto-determined
|
|
24
|
+
* encoding: <string> // "binary" to receive binary data as arrayBuffer
|
|
25
|
+
* range: <string> // sets range header
|
|
26
|
+
* headers: [`(key, value)] // add header(s) to the request, overriding defaults
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
closure HttpsApiRequest(url, options,
|
|
32
|
+
local urlq, fetchOptions, putdata, error, response, contentType, content) {
|
|
33
|
+
if !options
|
|
34
|
+
options = { }
|
|
35
|
+
if options.query
|
|
36
|
+
urlq = url.concat(EncodeQuery("?", options.query))
|
|
37
|
+
else
|
|
38
|
+
urlq = url
|
|
39
|
+
putdata = options.putdata
|
|
40
|
+
fetchOptions = {
|
|
41
|
+
mode: 'cors'
|
|
42
|
+
cache: 'no-cache'
|
|
43
|
+
credentials: 'same-origin'
|
|
44
|
+
headers: { }
|
|
45
|
+
redirect: 'follow'
|
|
46
|
+
referrerPolicy: 'no-referrer'
|
|
47
|
+
}
|
|
48
|
+
if options.method
|
|
49
|
+
fetchOptions.method = options.method
|
|
50
|
+
else if putdata
|
|
51
|
+
fetchOptions.method = "POST"
|
|
52
|
+
else
|
|
53
|
+
fetchOptions.method = "GET"
|
|
54
|
+
if putdata {
|
|
55
|
+
if options.contentType
|
|
56
|
+
fetchOptions.headers['Content-Type'] = options.contentType
|
|
57
|
+
else if jsTypedArray(options.putdata)
|
|
58
|
+
fetchOptions.headers['Content-Type'] = "application/octet-stream"
|
|
59
|
+
else if member(typeof(options.putdata), `(dictionary, array, xobject)) {
|
|
60
|
+
fetchOptions.headers['Content-Type'] = "application/json"
|
|
61
|
+
`(error, putdata) = JsonStringify(options.putdata)
|
|
62
|
+
if error
|
|
63
|
+
return (list(Error("HttpsApiRequest encode:", url)))
|
|
64
|
+
}
|
|
65
|
+
fetchOptions.body = putdata
|
|
66
|
+
}
|
|
67
|
+
if options.range
|
|
68
|
+
fetchOptions.headers.Range = options.range
|
|
69
|
+
if array(options.headers)
|
|
70
|
+
for item in options.headers
|
|
71
|
+
fetchOptions.headers[item.0] = item.1
|
|
72
|
+
//
|
|
73
|
+
// perform the fetch and return when complete
|
|
74
|
+
//
|
|
75
|
+
`(error, response) = await(js.w.fetch(urlq, fetchOptions))
|
|
76
|
+
if error
|
|
77
|
+
return (list(Error("HttpsApiRequest fetch failed:", error, url)))
|
|
78
|
+
contentType = response.headers.get("content-type")
|
|
79
|
+
if response.status < 200 || response.status >= 300
|
|
80
|
+
return (list(Error("HttpsApiRequest status:", url, response.status, {
|
|
81
|
+
status: response.status
|
|
82
|
+
})))
|
|
83
|
+
if contentType.startsWith("application/json") {
|
|
84
|
+
`(error, content) = await(response.text())
|
|
85
|
+
if !error
|
|
86
|
+
`(error, content) = JsonParse(content)
|
|
87
|
+
if error
|
|
88
|
+
error = Error("HttpsApiRequest decode:", url, error)
|
|
89
|
+
else
|
|
90
|
+
content = new(content)
|
|
91
|
+
if array(content) { // deencapsulate to get API result
|
|
92
|
+
content = totuple(content)
|
|
93
|
+
error = content.0
|
|
94
|
+
content = content.1
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if options.encoding == "binary"
|
|
98
|
+
`(error, content) = await(response.arrayBuffer())
|
|
99
|
+
else
|
|
100
|
+
`(error, content) = await(response.text())
|
|
101
|
+
list(error, content)
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
* https_browserInit
|
|
107
|
+
*
|
|
108
|
+
* Initialize HTTPS request operations for browsers.
|
|
109
|
+
*
|
|
110
|
+
*/
|
|
111
|
+
|
|
112
|
+
function https_browserInit(local manifest) {
|
|
113
|
+
manifest = `(HttpsApiRequest, https_browserInit)
|
|
114
|
+
|
|
115
|
+
Naan.module.build(module.id, "https_request", function(modobj, compobj) {
|
|
116
|
+
require("./browser.nlg")
|
|
117
|
+
compobj.manifest = manifest
|
|
118
|
+
modobj.exports.HttpsApiRequest = HttpsApiRequest
|
|
119
|
+
})
|
|
120
|
+
}();
|
|
@@ -27,10 +27,8 @@
|
|
|
27
27
|
* knowledge of which ones are responding. If a request takes longer than a second to respond then
|
|
28
28
|
* this executes a validate operation, which eliminates any clients that have gone away and rejects
|
|
29
29
|
* their pending operations.
|
|
30
|
-
* One potential problem is stale caches
|
|
31
|
-
*
|
|
32
|
-
* its ID and version along with the mesage port. If that is different from the previous version then
|
|
33
|
-
* the old caches are cleared and data re-fetched.
|
|
30
|
+
* One potential problem is stale caches. When an older version is discovered then we notify the
|
|
31
|
+
* client and invalidate the old cache.
|
|
34
32
|
*
|
|
35
33
|
* column positioning: // // !
|
|
36
34
|
*
|
|
@@ -38,7 +36,7 @@
|
|
|
38
36
|
*
|
|
39
37
|
*/
|
|
40
38
|
|
|
41
|
-
var CurrentCacheName = "Naanlang
|
|
39
|
+
var CurrentCacheName = "Naanlang-1.0.6-2";
|
|
42
40
|
|
|
43
41
|
|
|
44
42
|
//
|
|
@@ -76,8 +74,8 @@ var waitingForInit = []; // initialization functions, or
|
|
|
76
74
|
return; // already done
|
|
77
75
|
var waiters = waitingForInit;
|
|
78
76
|
waitingForInit = false; // no more waiters allowed
|
|
79
|
-
for (var
|
|
80
|
-
|
|
77
|
+
for (var wdex in waiters)
|
|
78
|
+
waiters[wdex](); // call each waiter
|
|
81
79
|
}
|
|
82
80
|
|
|
83
81
|
// self.onmessage events
|
|
@@ -91,18 +89,13 @@ var waitingForInit = []; // initialization functions, or
|
|
|
91
89
|
var pubVersion = event.data.hereIsMyVersion;
|
|
92
90
|
var sourceId = event.source.id; // client id of sender of message
|
|
93
91
|
msgPorts[sourceId] = msgport;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
version: pubVersion
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
ClearCaches(newCacheName)
|
|
105
|
-
.then(Reaper); // clean up obsolete info
|
|
92
|
+
console.log("[1.0.6-2] received new msgport for", sourceId, pubID, "-", pubVersion);
|
|
93
|
+
if (pubVersion != "1.0.6-2")
|
|
94
|
+
msgport.postMessage({ // notify new version available
|
|
95
|
+
id: "upgrade",
|
|
96
|
+
version: "1.0.6-2"
|
|
97
|
+
});
|
|
98
|
+
Reaper(); // clean up obsolete info
|
|
106
99
|
|
|
107
100
|
// msgport.onmessage events
|
|
108
101
|
//
|
|
@@ -114,7 +107,7 @@ var waitingForInit = []; // initialization functions, or
|
|
|
114
107
|
if (msg.id == "response")
|
|
115
108
|
processResponse(msg);
|
|
116
109
|
else if (msg.id == "text")
|
|
117
|
-
console.log("[1.0.
|
|
110
|
+
console.log("[1.0.6-2] msg received:", msg.text);
|
|
118
111
|
};
|
|
119
112
|
|
|
120
113
|
// send text to IDE log
|
|
@@ -125,7 +118,7 @@ var waitingForInit = []; // initialization functions, or
|
|
|
125
118
|
// don't clutter the log
|
|
126
119
|
msgport.postMessage({
|
|
127
120
|
id: "text",
|
|
128
|
-
text: "port received by 1.0.
|
|
121
|
+
text: "port received by 1.0.6-2",
|
|
129
122
|
});
|
|
130
123
|
*/
|
|
131
124
|
if (--pending === 0)
|
|
@@ -142,13 +135,13 @@ var waitingForInit = []; // initialization functions, or
|
|
|
142
135
|
includeUncontrolled: true
|
|
143
136
|
}).then(function(clientList) {
|
|
144
137
|
clientList.every(function(client) {
|
|
145
|
-
console.log("[1.0.
|
|
138
|
+
console.log("[1.0.6-2] requesting new msgport for", client.id);
|
|
146
139
|
++pending;
|
|
147
140
|
client.postMessage({ // tell client(s) we need this fetch source
|
|
148
141
|
msg: "Naan_need_fetch_port",
|
|
149
142
|
});
|
|
150
143
|
});
|
|
151
|
-
setTimeout(doneInit,
|
|
144
|
+
setTimeout(doneInit, 10000); // release fetches
|
|
152
145
|
});
|
|
153
146
|
|
|
154
147
|
// processResponse
|
|
@@ -188,12 +181,12 @@ function Reaper() {
|
|
|
188
181
|
clients[clientList[clidex].id] = clientList[clidex];
|
|
189
182
|
for (var sourceId in msgPorts)
|
|
190
183
|
if (!clients[sourceId]) {
|
|
191
|
-
console.log("[1.0.
|
|
184
|
+
console.log("[1.0.6-2] source gone:", sourceId);
|
|
192
185
|
delete msgPorts[sourceId]; // no longer a source
|
|
193
186
|
}
|
|
194
187
|
for (var clientId in fetchPorts)
|
|
195
188
|
if (!clients[clientId]) {
|
|
196
|
-
console.log("[1.0.
|
|
189
|
+
console.log("[1.0.6-2] client gone:", clientId);
|
|
197
190
|
delete fetchPorts[clientId]; // no longer a client
|
|
198
191
|
}
|
|
199
192
|
for (var fqdex = 0; fqdex < fetchQueue.length; ++fqdex) {
|
|
@@ -218,25 +211,22 @@ function Reaper() {
|
|
|
218
211
|
/*
|
|
219
212
|
* ClearCaches
|
|
220
213
|
*
|
|
221
|
-
* Clear obsolete caches
|
|
214
|
+
* Clear obsolete caches, returning a promise.
|
|
222
215
|
*
|
|
223
216
|
*/
|
|
224
217
|
|
|
225
|
-
function ClearCaches(
|
|
226
|
-
if (CurrentCacheName == newCacheName)
|
|
227
|
-
return (Promise.resolve()); // no change
|
|
228
|
-
CurrentCacheName = newCacheName;
|
|
218
|
+
function ClearCaches() {
|
|
229
219
|
var promise = caches.keys().then(function(cacheNames) { // delete old cache entries
|
|
230
220
|
return (Promise.all(
|
|
231
221
|
cacheNames.map(function(cacheName) {
|
|
232
|
-
if (cacheName
|
|
233
|
-
console.log('[1.0.
|
|
222
|
+
if (cacheName != CurrentCacheName) {
|
|
223
|
+
console.log('[1.0.6-2] deleting old cache:', cacheName);
|
|
234
224
|
return (caches.delete(cacheName));
|
|
235
225
|
}
|
|
236
226
|
})
|
|
237
227
|
));
|
|
238
228
|
}).then(function() { // claim all clients
|
|
239
|
-
console.log('[1.0.
|
|
229
|
+
console.log('[1.0.6-2] claiming clients');
|
|
240
230
|
return (self.clients.claim());
|
|
241
231
|
});
|
|
242
232
|
return (promise);
|
|
@@ -279,7 +269,7 @@ function GetClientResponse(event, urlpath) {
|
|
|
279
269
|
msgport.postMessage({
|
|
280
270
|
id: "fetch",
|
|
281
271
|
seq: seqno,
|
|
282
|
-
version: "1.0.
|
|
272
|
+
version: "1.0.6-2",
|
|
283
273
|
request: {
|
|
284
274
|
method: event.request.method,
|
|
285
275
|
url: event.request.url
|
|
@@ -327,7 +317,7 @@ function GetClientResponse(event, urlpath) {
|
|
|
327
317
|
*/
|
|
328
318
|
|
|
329
319
|
self.addEventListener('install', function(event) {
|
|
330
|
-
console.log("[1.0.
|
|
320
|
+
console.log("[1.0.6-2] install");
|
|
331
321
|
self.skipWaiting();
|
|
332
322
|
});
|
|
333
323
|
|
|
@@ -366,7 +356,7 @@ self.addEventListener('fetch', function(event) {
|
|
|
366
356
|
}
|
|
367
357
|
else
|
|
368
358
|
promise = fetch(event.request).catch(function (e) {
|
|
369
|
-
console.log("[1.0.
|
|
359
|
+
console.log("[1.0.6-2] fetch failed", e);
|
|
370
360
|
return (new Response(undefined, {
|
|
371
361
|
status: 404,
|
|
372
362
|
statusText: "Fetch Failed"
|
|
@@ -395,16 +385,16 @@ self.addEventListener('fetch', function(event) {
|
|
|
395
385
|
*/
|
|
396
386
|
|
|
397
387
|
self.addEventListener('activate', function(event) {
|
|
398
|
-
console.log("[1.0.
|
|
388
|
+
console.log("[1.0.6-2] activate");
|
|
399
389
|
self.clients.matchAll({ // for debugging, list controlled clients
|
|
400
390
|
includeUncontrolled: true
|
|
401
391
|
}).then(function(clientList) {
|
|
402
392
|
var urls = clientList.map(function(client) {
|
|
403
393
|
return (client.url);
|
|
404
394
|
});
|
|
405
|
-
console.log('[1.0.
|
|
395
|
+
console.log('[1.0.6-2] matching clients:', urls.join(', '));
|
|
406
396
|
});
|
|
407
|
-
var promise = ClearCaches(
|
|
397
|
+
var promise = ClearCaches();
|
|
408
398
|
if (event.waitUntil)
|
|
409
399
|
event.waitUntil(promise);
|
|
410
400
|
});
|
|
@@ -77,7 +77,7 @@ closure TermHost(track, api, name, workerID, options,
|
|
|
77
77
|
if !target.written
|
|
78
78
|
target.term.WriteLn("(reconnected)")
|
|
79
79
|
}, 1000).run()
|
|
80
|
-
else
|
|
80
|
+
else if message.respOp
|
|
81
81
|
debuglog("unknown host response message:", message.respOp)
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -602,14 +602,17 @@ closure findIDEtarget(track, name, workerID, naancont, local target) {
|
|
|
602
602
|
*
|
|
603
603
|
*/
|
|
604
604
|
|
|
605
|
-
closure termIDE(track, name, workerID, naancont, local target, connected) {
|
|
605
|
+
closure termIDE(track, name, workerID, naancont, title, local target, connected) {
|
|
606
606
|
target = findIDEtarget(track, name, workerID, naancont)
|
|
607
607
|
if target { // new naancont on existing target
|
|
608
608
|
target.updateController(naancont)
|
|
609
|
+
target.title = title
|
|
610
|
+
track.update(target)
|
|
609
611
|
return (target)
|
|
610
612
|
}
|
|
611
613
|
target = runningExecutors.ExecutorBase(track, "Local", name)
|
|
612
614
|
target.name = name
|
|
615
|
+
target.title = title
|
|
613
616
|
target.workerID = workerID
|
|
614
617
|
target.naancont = naancont
|
|
615
618
|
connected = []
|
|
@@ -756,7 +759,6 @@ closure termIDE(track, name, workerID, naancont, local target, connected) {
|
|
|
756
759
|
/*
|
|
757
760
|
* termInstallVirtualWatcher
|
|
758
761
|
*
|
|
759
|
-
* column positioning: // // !
|
|
760
762
|
* Install a persistent watcher to note when virtual terminals come and go, and manage their
|
|
761
763
|
* execution target lifetimes.
|
|
762
764
|
*
|
|
@@ -766,7 +768,7 @@ closure termInstallVirtualWatcher(track, naancont) {
|
|
|
766
768
|
|
|
767
769
|
function watchVsites(msg, local error, target) {
|
|
768
770
|
if msg.op == "VsiteOpen" {
|
|
769
|
-
`(error, target) = termIDE(track, msg.name, "NaanVsite", msg.naancont)
|
|
771
|
+
`(error, target) = termIDE(track, msg.name, "NaanVsite", msg.naancont, msg.title)
|
|
770
772
|
target.attention()
|
|
771
773
|
}
|
|
772
774
|
else if msg.op == "VsiteClose" {
|
|
@@ -55,8 +55,13 @@ closure ServiceWorker(pubID, pubVersion, local serv, callback) {
|
|
|
55
55
|
version: msg.version
|
|
56
56
|
})
|
|
57
57
|
} else if msg.id == "upgrade" {
|
|
58
|
-
if
|
|
59
|
-
|
|
58
|
+
if serv.upgrade != msg.version {
|
|
59
|
+
serv.upgrade = msg.version // only report once
|
|
60
|
+
callback(false, {
|
|
61
|
+
message: "upgrade"
|
|
62
|
+
version: msg.version
|
|
63
|
+
})
|
|
64
|
+
}
|
|
60
65
|
}
|
|
61
66
|
else if msg.id == "text"
|
|
62
67
|
debuglog("sw[".concat(serv.scope, "]: "), msg.text) // handy remote debug capability
|
|
@@ -182,7 +187,7 @@ closure ServiceWorker(pubID, pubVersion, local serv, callback) {
|
|
|
182
187
|
*
|
|
183
188
|
*/
|
|
184
189
|
|
|
185
|
-
closure ScopedServiceWorker(pubID, pubVersion, local scoper, result) {
|
|
190
|
+
closure ScopedServiceWorker(pubID, pubVersion, callback, local scoper, result) {
|
|
186
191
|
scoper = new(object, ScopedServiceWorker)
|
|
187
192
|
scoper.scopes = {}
|
|
188
193
|
scoper.serv = ServiceWorker(pubID, pubVersion)
|
|
@@ -232,7 +237,8 @@ closure ScopedServiceWorker(pubID, pubVersion, local scoper, result) {
|
|
|
232
237
|
response.body = data
|
|
233
238
|
scoper.serv.msgport.postMessage(response)
|
|
234
239
|
return
|
|
235
|
-
}
|
|
240
|
+
} else if data.message == "upgrade"
|
|
241
|
+
callback(data.version)
|
|
236
242
|
})
|
|
237
243
|
if result.0 {
|
|
238
244
|
ErrorDebuglog("ScopedServiceWorker failed", result)
|
|
@@ -308,6 +314,7 @@ closure TrackedScope(track, scope, fs, rootpath, local trope, result) {
|
|
|
308
314
|
mimeType = {
|
|
309
315
|
"css": "text/css",
|
|
310
316
|
"csv": "text/csv",
|
|
317
|
+
"gif": "image/gif",
|
|
311
318
|
"htm": "text/html",
|
|
312
319
|
"html": "text/html",
|
|
313
320
|
"ico": "image/x-icon",
|
|
@@ -365,8 +372,8 @@ closure TrackedScope(track, scope, fs, rootpath, local trope, result) {
|
|
|
365
372
|
*
|
|
366
373
|
*/
|
|
367
374
|
|
|
368
|
-
closure TrackServiceWorkers(track, pubID, pubVersion, local error) {
|
|
369
|
-
`(error, serviceWorker) = ScopedServiceWorker(pubID, pubVersion)
|
|
375
|
+
closure TrackServiceWorkers(track, pubID, pubVersion, callback, local error) {
|
|
376
|
+
`(error, serviceWorker) = ScopedServiceWorker(pubID, pubVersion, callback)
|
|
370
377
|
if error
|
|
371
378
|
ErrorDebugLog("TrackServiceWorkers: cannot load service worker", error)
|
|
372
379
|
track.register(TrackedScope, "V-Site")
|
|
@@ -37,7 +37,7 @@ closure MakeNideAPIclient(url, guid, local client) {
|
|
|
37
37
|
request.addEventListener("error", function reqFailed(event, local errtext) {
|
|
38
38
|
if request.status == 0
|
|
39
39
|
errtext = "connectivity"
|
|
40
|
-
|
|
40
|
+
else
|
|
41
41
|
errtext = "request failed"
|
|
42
42
|
error = Error(errtext, {
|
|
43
43
|
status: request.status
|
|
@@ -22,6 +22,50 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
22
22
|
view = new(object, this)
|
|
23
23
|
view.api = api
|
|
24
24
|
view.rootpath = rootpath
|
|
25
|
+
|
|
26
|
+
// data
|
|
27
|
+
//
|
|
28
|
+
// Return the filesystem data, i.e. the tree data field. The minimum information is:
|
|
29
|
+
// platform -- e.g. "darwin" or "win32"
|
|
30
|
+
// semantics -- e.g. "win32" or "posix"
|
|
31
|
+
// pathsep -- e.g. / or \
|
|
32
|
+
|
|
33
|
+
view.data = closure data(callback) {
|
|
34
|
+
if !callback
|
|
35
|
+
return (syncAdapter(data))
|
|
36
|
+
params = {
|
|
37
|
+
path: ""
|
|
38
|
+
op: "tree"
|
|
39
|
+
depthlimit: 0
|
|
40
|
+
}
|
|
41
|
+
api.psmRemote(params, false, function(error, tree) {
|
|
42
|
+
if error
|
|
43
|
+
debuglog("psmcFsView.data: can't get initial filesystem data:", ErrorString(error))
|
|
44
|
+
else {
|
|
45
|
+
view.fsdata = tree.data
|
|
46
|
+
if rootpath == ""
|
|
47
|
+
rootpath = tree.data.pathsep
|
|
48
|
+
}
|
|
49
|
+
callback(error, tree.data)
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// pathInit
|
|
54
|
+
//
|
|
55
|
+
// Initialize our path module for the applicable path type.
|
|
56
|
+
|
|
57
|
+
closure pathInit(local result) {
|
|
58
|
+
result = view.data()
|
|
59
|
+
if result.0
|
|
60
|
+
pathmod = false
|
|
61
|
+
else {
|
|
62
|
+
if view.fsdata.pathsep == "\\"
|
|
63
|
+
pathmod = JSpath.win32
|
|
64
|
+
else
|
|
65
|
+
pathmod = JSpath.posix
|
|
66
|
+
false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
25
69
|
|
|
26
70
|
// psmRemote
|
|
27
71
|
//
|
|
@@ -30,10 +74,14 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
30
74
|
closure psmRemote(path, op, options, putdata, callback, local params, item) {
|
|
31
75
|
if !callback
|
|
32
76
|
return (syncAdapter(psmRemote, path, op, options, putdata))
|
|
77
|
+
if !pathmod && pathInit()
|
|
78
|
+
return // failed to initialize path module
|
|
33
79
|
if !string(path)
|
|
34
80
|
return (asyncResult(callback, Error("invalid path:", typeof(path))))
|
|
81
|
+
if rootpath != ""
|
|
82
|
+
path = pathmod.resolve(rootpath, path)
|
|
35
83
|
params = {
|
|
36
|
-
path:
|
|
84
|
+
path: path
|
|
37
85
|
op: op
|
|
38
86
|
}
|
|
39
87
|
for item in options
|
|
@@ -59,47 +107,39 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
59
107
|
|
|
60
108
|
// path
|
|
61
109
|
//
|
|
62
|
-
//
|
|
110
|
+
// Redirect path calls to module chosen for filesystem semantics. It is possible for this to fail
|
|
111
|
+
// on first connection to the filesystem, in which case we return false for the path result.
|
|
112
|
+
// Throwing an error would complicate our callers and testing. This way there's a small chance
|
|
113
|
+
// that a transient error will give a bad path, but that will be detected downstream.
|
|
63
114
|
|
|
64
115
|
view.path = new(object, this)
|
|
65
|
-
view.path[".undefined"] =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if error
|
|
70
|
-
return (list(error))
|
|
71
|
-
if info.pathsep == "\\"
|
|
72
|
-
pathmod = JSpath.win32
|
|
73
|
-
else
|
|
74
|
-
pathmod = JSpath.posix
|
|
75
|
-
}
|
|
76
|
-
xapply(pathmod, selector, arglist)
|
|
77
|
-
} (args.0, args.-1)
|
|
116
|
+
view.path[".undefined"] = function path args {
|
|
117
|
+
if !pathmod
|
|
118
|
+
pathInit()
|
|
119
|
+
xapply(pathmod, args.0, args.-1)
|
|
78
120
|
}
|
|
79
121
|
|
|
80
|
-
//
|
|
122
|
+
// folderPath
|
|
81
123
|
//
|
|
82
|
-
// Return the
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
callback(error, tree.data)
|
|
93
|
-
})
|
|
124
|
+
// Return the path of the specified special folder:
|
|
125
|
+
// "HomeDir"
|
|
126
|
+
// "TempDir"
|
|
127
|
+
// "PackageDir"
|
|
128
|
+
// The returned path is relative to our root if within it, or absolute otherwise.
|
|
129
|
+
|
|
130
|
+
view.folderPath = function folderPath(folderID, callback) {
|
|
131
|
+
psmRemote("", "folderPath", {
|
|
132
|
+
folderid: folderID
|
|
133
|
+
}, false, callback)
|
|
94
134
|
}
|
|
95
135
|
|
|
96
136
|
// readLines
|
|
97
137
|
//
|
|
98
138
|
// Read a lines of a file at the specified path with options:
|
|
99
|
-
// matchRE:
|
|
100
|
-
// ignoreCase:
|
|
101
|
-
// invert:
|
|
102
|
-
// returnText:
|
|
139
|
+
// matchRE: -- JavaScript regex
|
|
140
|
+
// ignoreCase: -- ignore case during match
|
|
141
|
+
// invert: -- return lines that DO NOT match the regex
|
|
142
|
+
// returnText: -- return text of matched lines
|
|
103
143
|
// When using a matchRE, the return value is an array of [ lineNumber, text ] pairs if
|
|
104
144
|
// returnText is specified, or just an array of one-based line numbers otherwise.
|
|
105
145
|
//
|
|
@@ -248,6 +288,10 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
248
288
|
// Search the specified file or recursive directory.
|
|
249
289
|
|
|
250
290
|
view.dirSearch = function dirSearch(path, options, callback) {
|
|
291
|
+
if options.excludeDirs {
|
|
292
|
+
options = new(options)
|
|
293
|
+
options.excludeDirs = JSONstringify(options.excludeDirs)
|
|
294
|
+
}
|
|
251
295
|
psmRemote(path, "dirSearch", options, false, callback)
|
|
252
296
|
}
|
|
253
297
|
|
|
@@ -317,6 +361,10 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
317
361
|
// Grep the specified file or recursive directory.
|
|
318
362
|
|
|
319
363
|
view.grepLines = function grepLines(path, options, callback) {
|
|
364
|
+
if options.excludeDirs {
|
|
365
|
+
options = new(options)
|
|
366
|
+
options.excludeDirs = JSONstringify(options.excludeDirs)
|
|
367
|
+
}
|
|
320
368
|
psmRemote(path, "grepLines", options, false, callback)
|
|
321
369
|
}
|
|
322
370
|
|