@breakside/jskit 2023.10.0 → 2023.12.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.
- package/Frameworks/DOM.jsframework/Info.json +2 -2
- package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
- package/Frameworks/FontKit.jsframework/Info.json +2 -2
- package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
- package/Frameworks/Foundation.jsframework/Info.json +2 -2
- package/Frameworks/Foundation.jsframework/JS/JSFileManager+HTML.js +110 -48
- package/Frameworks/Foundation.jsframework/JS/JSFileManager+Node.js +8 -1
- package/Frameworks/Foundation.jsframework/JS/JSUserDefaults.js +0 -1
- package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
- package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
- package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
- package/Info.json +2 -2
- package/Node/io.breakside.jskit-bundle.js +2 -2
- package/Root/Frameworks/APIKit/Info.yaml +1 -1
- package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
- package/Root/Frameworks/AuthKit/Info.yaml +1 -1
- package/Root/Frameworks/CSSOM/Info.yaml +1 -1
- package/Root/Frameworks/ChartKit/Info.yaml +1 -1
- package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
- package/Root/Frameworks/DBKit/Info.yaml +1 -1
- package/Root/Frameworks/DOM/Info.yaml +1 -1
- package/Root/Frameworks/Dispatch/Info.yaml +1 -1
- package/Root/Frameworks/FontKit/Info.yaml +1 -1
- package/Root/Frameworks/Foundation/Info.yaml +1 -1
- package/Root/Frameworks/Foundation/JSFileManager+HTML.js +110 -48
- package/Root/Frameworks/Foundation/JSFileManager+Node.js +8 -1
- package/Root/Frameworks/Foundation/JSUserDefaults.js +0 -1
- package/Root/Frameworks/ImageKit/Info.yaml +1 -1
- package/Root/Frameworks/MediaKit/Info.yaml +1 -1
- package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
- package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
- package/Root/Frameworks/PDFKit/Info.yaml +1 -1
- package/Root/Frameworks/QRKit/Info.yaml +1 -1
- package/Root/Frameworks/SearchKit/Info.yaml +1 -1
- package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
- package/Root/Frameworks/ServerKit/Info.yaml +1 -1
- package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
- package/Root/Frameworks/TestKit/Info.yaml +1 -1
- package/Root/Frameworks/UIKit/Info.yaml +1 -1
- package/Root/Frameworks/UIKit/UIAccessibility.js +2 -1
- package/Root/Frameworks/UIKit/UICollectionReusableView.js +1 -0
- package/Root/Frameworks/UIKit/UICollectionViewGridLayout.js +2 -11
- package/Root/Frameworks/UIKit/UICollectionViewLayout.js +1 -0
- package/Root/Frameworks/UIKit/UIHTMLDisplayServerCanvasContext.js +6 -1
- package/Root/Frameworks/UIKit/UIHTMLWindowServer.js +18 -2
- package/Root/Frameworks/UIKit/UILayer.js +66 -4
- package/Root/Frameworks/UIKit/UIScreen.js +5 -1
- package/Root/Frameworks/UIKit/UITextLayer.js +1 -1
- package/Root/Frameworks/UIKit/UIView.js +27 -4
- package/Root/Frameworks/UIKit/UIWindow.js +12 -4
- package/Root/Frameworks/UIKit/UIWindowServer.js +2 -0
- package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "framework",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.JSKit.DOM",
|
|
4
|
-
"JSBundleVersion": "2023.
|
|
4
|
+
"JSBundleVersion": "2023.12.0",
|
|
5
5
|
"JSDevelopmentLanguage": "en",
|
|
6
6
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
7
7
|
"JSBundleEnvironments": {
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
"node": "DOM+Node.js"
|
|
10
10
|
},
|
|
11
11
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
12
|
-
"GitRevision": "
|
|
12
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
13
13
|
}
|
|
@@ -3,7 +3,7 @@ JSBundle.bundles['io.breakside.JSKit.DOM'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "framework",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.JSKit.DOM",
|
|
6
|
-
"JSBundleVersion": "2023.
|
|
6
|
+
"JSBundleVersion": "2023.12.0",
|
|
7
7
|
"JSDevelopmentLanguage": "en",
|
|
8
8
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
9
9
|
"JSBundleEnvironments": {
|
|
@@ -11,7 +11,7 @@ JSBundle.bundles['io.breakside.JSKit.DOM'] = {
|
|
|
11
11
|
"node": "DOM+Node.js"
|
|
12
12
|
},
|
|
13
13
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
14
|
-
"GitRevision": "
|
|
14
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
15
15
|
},
|
|
16
16
|
"Resources": [],
|
|
17
17
|
"ResourceLookup": {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "framework",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.JSKit.FontKit",
|
|
4
|
-
"JSBundleVersion": "2023.
|
|
4
|
+
"JSBundleVersion": "2023.12.0",
|
|
5
5
|
"JSDevelopmentLanguage": "en",
|
|
6
6
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
7
7
|
"JSBundleEnvironments": {
|
|
8
8
|
"html": "FontKit+HTML.js"
|
|
9
9
|
},
|
|
10
10
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
11
|
-
"GitRevision": "
|
|
11
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
12
12
|
}
|
|
@@ -3,14 +3,14 @@ JSBundle.bundles['io.breakside.JSKit.FontKit'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "framework",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.JSKit.FontKit",
|
|
6
|
-
"JSBundleVersion": "2023.
|
|
6
|
+
"JSBundleVersion": "2023.12.0",
|
|
7
7
|
"JSDevelopmentLanguage": "en",
|
|
8
8
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
9
9
|
"JSBundleEnvironments": {
|
|
10
10
|
"html": "FontKit+HTML.js"
|
|
11
11
|
},
|
|
12
12
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
13
|
-
"GitRevision": "
|
|
13
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
14
14
|
},
|
|
15
15
|
"Resources": [],
|
|
16
16
|
"ResourceLookup": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "framework",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.JSKit.Foundation",
|
|
4
|
-
"JSBundleVersion": "2023.
|
|
4
|
+
"JSBundleVersion": "2023.12.0",
|
|
5
5
|
"JSDevelopmentLanguage": "en",
|
|
6
6
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
7
7
|
"JSBundleEnvironments": {
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
"node": "Foundation+Node.js"
|
|
10
10
|
},
|
|
11
11
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
12
|
-
"GitRevision": "
|
|
12
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
13
13
|
}
|
|
@@ -45,6 +45,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
45
45
|
_identifier: null,
|
|
46
46
|
|
|
47
47
|
_db: null,
|
|
48
|
+
_rootURL: null,
|
|
48
49
|
|
|
49
50
|
error: null,
|
|
50
51
|
|
|
@@ -57,7 +58,6 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
57
58
|
// MARK: - Opening the File System
|
|
58
59
|
|
|
59
60
|
open: function(completion, target){
|
|
60
|
-
logger.info("opening indexeddb file manager");
|
|
61
61
|
if (!completion){
|
|
62
62
|
completion = Promise.completion(function JSFileManager_open_promise_completion(status){
|
|
63
63
|
if (status != JSFileManager.State.success){
|
|
@@ -68,6 +68,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
68
68
|
}
|
|
69
69
|
var request = indexedDB.open(this._identifier, CURRENT_DATABASE_VERSION);
|
|
70
70
|
var manager = this;
|
|
71
|
+
var oldVersion = 0;
|
|
71
72
|
request.onblocked = function JSFileManager_open_onblocked(e){
|
|
72
73
|
logger.info("indexeddb file manager upgrade blocked by other windows");
|
|
73
74
|
completion.call(target, JSFileManager.State.conflictingVersions);
|
|
@@ -81,6 +82,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
81
82
|
request.onupgradeneeded = function JSFileManager_open_onupgradeneeded(e){
|
|
82
83
|
logger.info("indexeddb upgrade needed");
|
|
83
84
|
logger.info("indexeddb upgrading");
|
|
85
|
+
oldVersion = e.oldVersion;
|
|
84
86
|
try{
|
|
85
87
|
manager._db = e.target.result;
|
|
86
88
|
manager.upgrade(e.oldVersion, e.newVersion);
|
|
@@ -90,10 +92,24 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
90
92
|
}
|
|
91
93
|
};
|
|
92
94
|
request.onsuccess = function JSFileManager_open_onsuccess(e){
|
|
93
|
-
logger.info("indexeddb open");
|
|
94
95
|
manager._db = e.target.result;
|
|
95
|
-
|
|
96
|
+
if (oldVersion === 1){
|
|
97
|
+
var v1url = manager._rootURL.appendingPathComponents(["Containers", "io.breakside.JSKit.Foundation.JSFileManager"], true);
|
|
98
|
+
var v2url = manager.persistentContainerURL;
|
|
99
|
+
logger.info("moving persistentContainerURL from %{public} to %{public}", v1url.encodedString, v2url.encodedString);
|
|
100
|
+
manager.moveItemAtURL(v1url, v2url, function(success){
|
|
101
|
+
if (success){
|
|
102
|
+
completion.call(target, JSFileManager.State.success);
|
|
103
|
+
}else{
|
|
104
|
+
logger.error("failed to move persistentContainerURL");
|
|
105
|
+
completion.call(target, JSFileManager.State.genericFailure);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}else{
|
|
109
|
+
completion.call(target, JSFileManager.State.success);
|
|
110
|
+
}
|
|
96
111
|
};
|
|
112
|
+
this._rootURL = this.urlForPath("/");
|
|
97
113
|
return completion.promise;
|
|
98
114
|
},
|
|
99
115
|
|
|
@@ -108,7 +124,6 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
108
124
|
url.path = path;
|
|
109
125
|
if (path.startsWith("/")){
|
|
110
126
|
url.scheme = JSFileManager.Scheme.jskitfile;
|
|
111
|
-
url.host = "";
|
|
112
127
|
}
|
|
113
128
|
if (baseURL){
|
|
114
129
|
url.resolveToBaseURL(baseURL);
|
|
@@ -132,7 +147,10 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
132
147
|
},
|
|
133
148
|
|
|
134
149
|
_getPersistentContainerURL: function(){
|
|
135
|
-
|
|
150
|
+
if (JSBundle.mainBundleIdentifier){
|
|
151
|
+
return this._rootURL.appendingPathComponents(["Containers", JSBundle.mainBundleIdentifier], true);
|
|
152
|
+
}
|
|
153
|
+
return this._rootURL;
|
|
136
154
|
},
|
|
137
155
|
|
|
138
156
|
_getWorkingDirectoryURL: function(){
|
|
@@ -140,7 +158,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
140
158
|
},
|
|
141
159
|
|
|
142
160
|
begin: function(permission, stores){
|
|
143
|
-
return new
|
|
161
|
+
return new JSHTMLFileManagerTransaction(this._db, stores, permission);
|
|
144
162
|
},
|
|
145
163
|
|
|
146
164
|
// --------------------------------------------------------------------
|
|
@@ -158,7 +176,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
158
176
|
throw new Error("JSFileManager.itemExistsAtURL unsupported scheme: %s".sprintf(url.scheme));
|
|
159
177
|
}
|
|
160
178
|
var exists = false;
|
|
161
|
-
var transaction = this.begin(
|
|
179
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.read, JSHTMLFileManager.Tables.metadata);
|
|
162
180
|
transaction.addCompletion(function JSFileManager_itemExists_completion(success){
|
|
163
181
|
completion.call(target, success && exists);
|
|
164
182
|
});
|
|
@@ -183,7 +201,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
183
201
|
throw new Error("JSFileManager.attributesOfItemAtURL unsupported scheme: %s".sprintf(url.scheme));
|
|
184
202
|
}
|
|
185
203
|
var metadata = null;
|
|
186
|
-
var transaction = this.begin(
|
|
204
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.read, JSHTMLFileManager.Tables.metadata);
|
|
187
205
|
transaction.addCompletion(function JSFileManager_attributesOfItem_completion(success){
|
|
188
206
|
completion.call(target, metadata);
|
|
189
207
|
});
|
|
@@ -196,12 +214,11 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
196
214
|
_metadataInTransactionAtURL: function(transaction, url, completion){
|
|
197
215
|
var parent = url.removingLastPathComponent();
|
|
198
216
|
try {
|
|
199
|
-
var index = transaction.metadata.index(
|
|
217
|
+
var index = transaction.metadata.index(JSHTMLFileManager.Indexes.metadataPath);
|
|
200
218
|
var lookup = [parent.path || '', url.lastPathComponent];
|
|
201
219
|
var request = index.get(lookup);
|
|
202
220
|
var metadata;
|
|
203
221
|
request.onsuccess = function JSFileManager_metadata_onsuccess(e){
|
|
204
|
-
logger.debug("metadata query success; exists: %b", !!e.target.result);
|
|
205
222
|
completion(e.target.result || null);
|
|
206
223
|
// FIXME: url could include a symlink folder, in which case we won't
|
|
207
224
|
// get a result here even if the url is valid after resolving the symlink.
|
|
@@ -219,7 +236,6 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
219
236
|
logger.error("Error querying metadata: %{error}", request.error);
|
|
220
237
|
completion(null);
|
|
221
238
|
};
|
|
222
|
-
logger.debug("looking up metadata");
|
|
223
239
|
}catch(e){
|
|
224
240
|
logger.error("Exception thrown querying metadata: %{error}", e);
|
|
225
241
|
}
|
|
@@ -242,7 +258,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
242
258
|
if (url.pathComponents.length === 1){
|
|
243
259
|
throw new Error("JSFileManager.createDirectoryAtURL cannot create root path");
|
|
244
260
|
}
|
|
245
|
-
var transaction = this.begin(
|
|
261
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.readwrite, JSHTMLFileManager.Tables.metadata);
|
|
246
262
|
transaction.addCompletion(completion, target);
|
|
247
263
|
this._createDirectoryInTransactionAtURL(transaction, url, function JSFileManager_createDirectory_completion(success){
|
|
248
264
|
if (!success){
|
|
@@ -309,8 +325,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
309
325
|
if (url.pathComponents.length === 1){
|
|
310
326
|
throw new Error("JSFileManager.createFileAtURL cannot create root path");
|
|
311
327
|
}
|
|
312
|
-
|
|
313
|
-
var transaction = this.begin(JSFileManager.Permission.readwrite, [JSFileManager.Tables.metadata, JSFileManager.Tables.data]);
|
|
328
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.readwrite, [JSHTMLFileManager.Tables.metadata, JSHTMLFileManager.Tables.data]);
|
|
314
329
|
transaction.addCompletion(completion, target);
|
|
315
330
|
var parent = url.removingLastPathComponent();
|
|
316
331
|
var manager = this;
|
|
@@ -318,7 +333,6 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
318
333
|
var metadata = null;
|
|
319
334
|
var create = function JSFileManager_createFile_create(parentExists){
|
|
320
335
|
if (parentExists){
|
|
321
|
-
logger.debug("writing file data");
|
|
322
336
|
var dataRequest;
|
|
323
337
|
if (metadata === null){
|
|
324
338
|
dataRequest = transaction.data.add(data);
|
|
@@ -354,16 +368,13 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
354
368
|
};
|
|
355
369
|
manager._metadataInTransactionAtURL(transaction, url, function JSFileManager_createFile_metadata(existingMetadata){
|
|
356
370
|
if (existingMetadata !== null){
|
|
357
|
-
logger.debug("overwriting file");
|
|
358
371
|
metadata = existingMetadata;
|
|
359
372
|
create(true);
|
|
360
373
|
}else{
|
|
361
|
-
logger.debug("new file, checking for parent");
|
|
362
374
|
manager._metadataInTransactionAtURL(transaction, parent, function JSFileManager_createFile_parent_metadata(parentMetadata){
|
|
363
375
|
if (parentMetadata !== null){
|
|
364
376
|
create(parentMetadata.itemType == JSFileManager.ItemType.directory);
|
|
365
377
|
}else{
|
|
366
|
-
logger.debug("creating parent");
|
|
367
378
|
manager._createDirectoryInTransactionAtURL(transaction, parent, create);
|
|
368
379
|
}
|
|
369
380
|
});
|
|
@@ -402,7 +413,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
402
413
|
if (url.path == toURL.path){
|
|
403
414
|
throw new Error("JSFileManager.moveItemAtURL target and destination are the same");
|
|
404
415
|
}
|
|
405
|
-
var transaction = this.begin(
|
|
416
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.readwrite, JSHTMLFileManager.Tables.metadata);
|
|
406
417
|
transaction.addCompletion(completion, target);
|
|
407
418
|
var parent = url.removingLastPathComponent();
|
|
408
419
|
var toParent = toURL.removingLastPathComponent();
|
|
@@ -414,18 +425,15 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
414
425
|
}else{
|
|
415
426
|
var move = function JSFileManager_moveItem_move(toParentExists){
|
|
416
427
|
if (toParentExists){
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
toMetadata.name = toURL.lastPathComponent;
|
|
420
|
-
var request = transaction.metadata.put(toMetadata);
|
|
421
|
-
request.onsuccess = function JSFileManager_moveItem_onsuccess(){
|
|
428
|
+
manager._moveItemInTransactionAtURL(transaction, url, toURL, toParent, metadata);
|
|
429
|
+
transaction.indexedDBTransaction.addEventListener("complete", function(){
|
|
422
430
|
try{
|
|
423
431
|
manager.postNotificationForURL(parent, JSFileManager.Notification.directoryDidRemoveItem, {url: url, name: metadata.name, itemType: metadata.itemType});
|
|
424
|
-
manager.postNotificationForURL(toParent, JSFileManager.Notification.directoryDidAddItem, {url: toURL, name:
|
|
432
|
+
manager.postNotificationForURL(toParent, JSFileManager.Notification.directoryDidAddItem, {url: toURL, name: toURL.lastPathComponent, itemType: metadata.itemType});
|
|
425
433
|
}catch (e){
|
|
426
434
|
logger.error("Error posting notification: %{error}", e);
|
|
427
435
|
}
|
|
428
|
-
};
|
|
436
|
+
});
|
|
429
437
|
}else{
|
|
430
438
|
logger.info("could not create parent directory, aborting move transaction");
|
|
431
439
|
transaction.abort();
|
|
@@ -443,6 +451,59 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
443
451
|
return completion.promise;
|
|
444
452
|
},
|
|
445
453
|
|
|
454
|
+
_moveItemInTransactionAtURL: function(transaction, url, toURL, toParent, metadata){
|
|
455
|
+
switch (metadata.itemType){
|
|
456
|
+
case JSFileManager.ItemType.directory:
|
|
457
|
+
this._moveDirectoryInTransactionAtURL(transaction, url, toURL, toParent, metadata);
|
|
458
|
+
break;
|
|
459
|
+
case JSFileManager.ItemType.file:
|
|
460
|
+
this._moveMetadataInTransactionAtURL(transaction, url, toURL, toParent, metadata);
|
|
461
|
+
break;
|
|
462
|
+
case JSFileManager.ItemType.symbolicLink:
|
|
463
|
+
this._moveMetadataInTransactionAtURL(transaction, url, toURL, toParent, metadata);
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
|
|
468
|
+
_moveMetadataInTransactionAtURL: function(transaction, url, toURL, toParent, metadata){
|
|
469
|
+
var manager = this;
|
|
470
|
+
var copiedMetadata = JSCopy(metadata);
|
|
471
|
+
copiedMetadata.parent = toParent.path;
|
|
472
|
+
copiedMetadata.name = toURL.lastPathComponent;
|
|
473
|
+
transaction.metadata.put(copiedMetadata);
|
|
474
|
+
var lookup = [url.removingLastPathComponent().path, url.lastPathComponent];
|
|
475
|
+
var index = transaction.metadata.index(JSHTMLFileManager.Indexes.metadataPath);
|
|
476
|
+
var keyRequest = index.getKey(lookup);
|
|
477
|
+
keyRequest.onsuccess = function JSFileManager_removeMetadata_onsuccess(e){
|
|
478
|
+
var key = e.target.result;
|
|
479
|
+
if (key !== undefined){
|
|
480
|
+
transaction.metadata.delete(key);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
},
|
|
484
|
+
|
|
485
|
+
_moveDirectoryInTransactionAtURL: function(transaction, url, toURL, toParent, metadata){
|
|
486
|
+
this._moveMetadataInTransactionAtURL(transaction, url, toURL, toParent, metadata);
|
|
487
|
+
var index = transaction.metadata.index(JSHTMLFileManager.Indexes.metadataParent);
|
|
488
|
+
var lookup = url.path;
|
|
489
|
+
var request = index.getAll(lookup);
|
|
490
|
+
var manager = this;
|
|
491
|
+
request.onsuccess = function JSFileManager_removeDirectory_onsuccess(e){
|
|
492
|
+
var results = e.target.result;
|
|
493
|
+
if (results){
|
|
494
|
+
var child;
|
|
495
|
+
var childURL;
|
|
496
|
+
var childToURL;
|
|
497
|
+
for (var i = 0, l = results.length; i < l; ++i){
|
|
498
|
+
child = results[i];
|
|
499
|
+
childURL = url.appendingPathComponent(child.name, child.itemType == JSFileManager.ItemType.directory);
|
|
500
|
+
childToURL = toURL.appendingPathComponent(child.name, child.itemType == JSFileManager.ItemType.directory);
|
|
501
|
+
manager._moveItemInTransactionAtURL(transaction, childURL, childToURL, toURL, child);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
},
|
|
506
|
+
|
|
446
507
|
copyItemAtURL: function(url, toURL, completion, target){
|
|
447
508
|
if (!completion){
|
|
448
509
|
completion = Promise.completion(Promise.resolveTrue);
|
|
@@ -470,7 +531,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
470
531
|
if (url.path == toURL.path){
|
|
471
532
|
throw new Error("JSFileManager.copyItemAtURL target and destination are the same");
|
|
472
533
|
}
|
|
473
|
-
var transaction = this.begin(
|
|
534
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.readwrite, [JSHTMLFileManager.Tables.metadata, JSHTMLFileManager.Tables.data]);
|
|
474
535
|
transaction.addCompletion(completion, target);
|
|
475
536
|
var toParent = toURL.removingLastPathComponent();
|
|
476
537
|
var manager = this;
|
|
@@ -539,6 +600,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
539
600
|
var manager = this;
|
|
540
601
|
var copiedMetadata = JSCopy(metadata);
|
|
541
602
|
copiedMetadata.parent = toParent.path;
|
|
603
|
+
copiedMetadata.name = toURL.lastPathComponent;
|
|
542
604
|
var request = transaction.metadata.put(copiedMetadata);
|
|
543
605
|
request.onsuccess = function JSFileManager_copyMetadata_onsuccess(){
|
|
544
606
|
try{
|
|
@@ -551,7 +613,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
551
613
|
|
|
552
614
|
_copyDirectoryInTransactionAtURL: function(transaction, url, toURL, toParent, metadata){
|
|
553
615
|
this._copyMetadataInTransactionAtURL(transaction, url, toURL, toParent, metadata);
|
|
554
|
-
var index = transaction.metadata.index(
|
|
616
|
+
var index = transaction.metadata.index(JSHTMLFileManager.Indexes.metadataParent);
|
|
555
617
|
var lookup = url.path;
|
|
556
618
|
var request = index.getAll(lookup);
|
|
557
619
|
var manager = this;
|
|
@@ -589,9 +651,9 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
589
651
|
throw new Error("JSFileManager.removeItemAtURL cannot remove root path");
|
|
590
652
|
}
|
|
591
653
|
var parent = url.removingLastPathComponent();
|
|
592
|
-
var transaction = this.begin(
|
|
654
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.readwrite, [JSHTMLFileManager.Tables.metadata, JSHTMLFileManager.Tables.data]);
|
|
593
655
|
transaction.addCompletion(completion, target);
|
|
594
|
-
var index = transaction.metadata.index(
|
|
656
|
+
var index = transaction.metadata.index(JSHTMLFileManager.Indexes.metadataPath);
|
|
595
657
|
var manager = this;
|
|
596
658
|
this._metadataInTransactionAtURL(transaction, url, function JSFileManager_removeItem_metadata(metadata){
|
|
597
659
|
if (metadata !== null){
|
|
@@ -626,7 +688,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
626
688
|
_removeMetadataInTransactionAtURL: function(transaction, url, parent, metadata){
|
|
627
689
|
var manager = this;
|
|
628
690
|
var lookup = [parent.path, url.lastPathComponent];
|
|
629
|
-
var index = transaction.metadata.index(
|
|
691
|
+
var index = transaction.metadata.index(JSHTMLFileManager.Indexes.metadataPath);
|
|
630
692
|
var keyRequest = index.getKey(lookup);
|
|
631
693
|
keyRequest.onsuccess = function JSFileManager_removeMetadata_onsuccess(e){
|
|
632
694
|
var key = e.target.result;
|
|
@@ -645,7 +707,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
645
707
|
|
|
646
708
|
_removeDirectoryInTransactionAtURL: function(transaction, url, parent, metadata){
|
|
647
709
|
this._removeMetadataInTransactionAtURL(transaction, url, parent, metadata);
|
|
648
|
-
var index = transaction.metadata.index(
|
|
710
|
+
var index = transaction.metadata.index(JSHTMLFileManager.Indexes.metadataParent);
|
|
649
711
|
var lookup = url.path;
|
|
650
712
|
var request = index.getAll(lookup);
|
|
651
713
|
var manager = this;
|
|
@@ -677,7 +739,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
677
739
|
if (url.scheme != JSFileManager.Scheme.jskitfile){
|
|
678
740
|
throw new Error("JSFileManager.contentsAtURL unsupported scheme: %s".sprintf(url.scheme));
|
|
679
741
|
}
|
|
680
|
-
var transaction = this.begin(
|
|
742
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.readonly, [JSHTMLFileManager.Tables.metadata, JSHTMLFileManager.Tables.data]);
|
|
681
743
|
var contents = null;
|
|
682
744
|
var visitedURLSet = {};
|
|
683
745
|
transaction.addCompletion(function JSFileManager_contents_completion(success){
|
|
@@ -737,9 +799,9 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
737
799
|
if (url.scheme != JSFileManager.Scheme.jskitfile){
|
|
738
800
|
throw new Error("JSFileManager.removeItemAtURL unsupported scheme: %s".sprintf(url.scheme));
|
|
739
801
|
}
|
|
740
|
-
var transaction = this.begin(
|
|
802
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.readwrite, [JSHTMLFileManager.Tables.metadata]);
|
|
741
803
|
transaction.addCompletion(completion, target);
|
|
742
|
-
var index = transaction.metadata.index(
|
|
804
|
+
var index = transaction.metadata.index(JSHTMLFileManager.Indexes.metadataParent);
|
|
743
805
|
var lookup = url.path;
|
|
744
806
|
var request = index.getAll(lookup);
|
|
745
807
|
var manager = this;
|
|
@@ -792,7 +854,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
792
854
|
if (url.isEqual(absoluteToURL)){
|
|
793
855
|
throw new Error("JSFileManager.createSymbolicLinkAtURL target and destination are the same");
|
|
794
856
|
}
|
|
795
|
-
var transaction = this.begin(
|
|
857
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.readwrite, JSHTMLFileManager.Tables.metadata);
|
|
796
858
|
transaction.addCompletion(completion, target);
|
|
797
859
|
var parent = url.removingLastPathComponent();
|
|
798
860
|
var manager = this;
|
|
@@ -836,7 +898,7 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
836
898
|
throw new Error("JSFileManager.attributesOfItemAtURL unsupported scheme: %s".sprintf(url.scheme));
|
|
837
899
|
}
|
|
838
900
|
var link = null;
|
|
839
|
-
var transaction = this.begin(
|
|
901
|
+
var transaction = this.begin(JSHTMLFileManager.Permission.read, JSHTMLFileManager.Tables.metadata);
|
|
840
902
|
transaction.addCompletion(function JSFileManager_destinationOfSymbolicLink_completion(success){
|
|
841
903
|
completion.call(target, link);
|
|
842
904
|
});
|
|
@@ -895,11 +957,11 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
895
957
|
},
|
|
896
958
|
|
|
897
959
|
_createCurrentVersion: function(){
|
|
898
|
-
var metadata = this._db.createObjectStore(
|
|
960
|
+
var metadata = this._db.createObjectStore(JSHTMLFileManager.Tables.metadata, {autoIncrement: true, keyPath: "id"});
|
|
899
961
|
var transaction = metadata.transaction;
|
|
900
|
-
var pathIndex = metadata.createIndex(
|
|
901
|
-
var parentIndex = metadata.createIndex(
|
|
902
|
-
var data = this._db.createObjectStore(
|
|
962
|
+
var pathIndex = metadata.createIndex(JSHTMLFileManager.Indexes.metadataPath, ["parent", "name"], {unique: true});
|
|
963
|
+
var parentIndex = metadata.createIndex(JSHTMLFileManager.Indexes.metadataParent, "parent", {unique: false});
|
|
964
|
+
var data = this._db.createObjectStore(JSHTMLFileManager.Tables.data, {autoIncrement: true});
|
|
903
965
|
var t = this.timestamp;
|
|
904
966
|
var root = {parent: '', name: '/', itemType: JSFileManager.ItemType.directory, created: t, updated: t, added: t, size: 0};
|
|
905
967
|
metadata.add(root);
|
|
@@ -911,9 +973,9 @@ JSClass("JSHTMLFileManager", JSFileManager, {
|
|
|
911
973
|
});
|
|
912
974
|
|
|
913
975
|
|
|
914
|
-
var
|
|
976
|
+
var JSHTMLFileManagerTransaction = function(db, storeName, permission){
|
|
915
977
|
if (this === undefined){
|
|
916
|
-
return new
|
|
978
|
+
return new JSHTMLFileManagerTransaction(db, storeName, permission);
|
|
917
979
|
}
|
|
918
980
|
this.indexedDBTransaction = db.transaction(storeName, permission);
|
|
919
981
|
this.indexedDBTransaction.addEventListener('abort', this);
|
|
@@ -929,7 +991,7 @@ var JSFileManagerTransaction = function(db, storeName, permission){
|
|
|
929
991
|
}
|
|
930
992
|
};
|
|
931
993
|
|
|
932
|
-
|
|
994
|
+
JSHTMLFileManagerTransaction.prototype = {
|
|
933
995
|
|
|
934
996
|
addCompletion: function(completion, target){
|
|
935
997
|
this.completion = completion;
|
|
@@ -991,21 +1053,21 @@ if (self){
|
|
|
991
1053
|
indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
|
|
992
1054
|
}
|
|
993
1055
|
|
|
994
|
-
var CURRENT_DATABASE_VERSION =
|
|
1056
|
+
var CURRENT_DATABASE_VERSION = 2;
|
|
995
1057
|
|
|
996
|
-
|
|
1058
|
+
JSHTMLFileManager.Tables = {
|
|
997
1059
|
// {parent: "/some/path", name: "filename.txt", itemType: 1, created: 1234, modified: 1234, added: 1234, dataKey: 1234}
|
|
998
1060
|
metadata: "metadata",
|
|
999
1061
|
// Blob
|
|
1000
1062
|
data: "data"
|
|
1001
1063
|
};
|
|
1002
1064
|
|
|
1003
|
-
|
|
1065
|
+
JSHTMLFileManager.Indexes = {
|
|
1004
1066
|
metadataPath: "path",
|
|
1005
1067
|
metadataParent: "parent"
|
|
1006
1068
|
};
|
|
1007
1069
|
|
|
1008
|
-
|
|
1070
|
+
JSHTMLFileManager.Permission = {
|
|
1009
1071
|
readonly: "readonly",
|
|
1010
1072
|
readwrite: "readwrite"
|
|
1011
1073
|
};
|
|
@@ -60,6 +60,13 @@ JSClass("JSNodeFileManager", JSFileManager, {
|
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
this._rootURL = this.urlForPath(pathLib.join(process.cwd(), this._identifier), true);
|
|
63
|
+
var v1Path = this.pathForURL(this._rootURL.appendingPathComponent(this._identifier, true));
|
|
64
|
+
var v1Exists = fs.existsSync();
|
|
65
|
+
if (v1Exists){
|
|
66
|
+
var v2Path = this.pathForURL(this.persistentContainerURL);
|
|
67
|
+
logger.info("Moving persistentContainerURL from %{public} to %{public}", v1Path, v2Path);
|
|
68
|
+
fs.renameSync(v1Path, v2Path);
|
|
69
|
+
}
|
|
63
70
|
completion.call(target, JSFileManager.State.success);
|
|
64
71
|
return completion.promise;
|
|
65
72
|
},
|
|
@@ -115,7 +122,7 @@ JSClass("JSNodeFileManager", JSFileManager, {
|
|
|
115
122
|
},
|
|
116
123
|
|
|
117
124
|
_getPersistentContainerURL: function(){
|
|
118
|
-
return this._rootURL.
|
|
125
|
+
return this._rootURL.appendingPathComponents(["Containers", JSBundle.mainBundleIdentifier], true);
|
|
119
126
|
},
|
|
120
127
|
|
|
121
128
|
// --------------------------------------------------------------------
|
|
@@ -194,7 +194,6 @@ JSClass("JSUserDefaults", JSObject, {
|
|
|
194
194
|
}
|
|
195
195
|
}else{
|
|
196
196
|
var data = JSON.stringify(this._values).utf8();
|
|
197
|
-
logger.info("saving user defaults");
|
|
198
197
|
this._fileManager.createFileAtURL(this._url, data, function JSUserDefaults_persist_createFile(success){
|
|
199
198
|
if (!success){
|
|
200
199
|
logger.error("failed to write user defaults");
|
|
@@ -3,7 +3,7 @@ JSBundle.bundles['io.breakside.JSKit.Foundation'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "framework",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.JSKit.Foundation",
|
|
6
|
-
"JSBundleVersion": "2023.
|
|
6
|
+
"JSBundleVersion": "2023.12.0",
|
|
7
7
|
"JSDevelopmentLanguage": "en",
|
|
8
8
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
9
9
|
"JSBundleEnvironments": {
|
|
@@ -11,7 +11,7 @@ JSBundle.bundles['io.breakside.JSKit.Foundation'] = {
|
|
|
11
11
|
"node": "Foundation+Node.js"
|
|
12
12
|
},
|
|
13
13
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
14
|
-
"GitRevision": "
|
|
14
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
15
15
|
},
|
|
16
16
|
"Resources": [
|
|
17
17
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "framework",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.JSKit.SecurityKit",
|
|
4
|
-
"JSBundleVersion": "2023.
|
|
4
|
+
"JSBundleVersion": "2023.12.0",
|
|
5
5
|
"JSDevelopmentLanguage": "en",
|
|
6
6
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
7
7
|
"JSBundleEnvironments": {
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
"node": "SecurityKit+Node.js"
|
|
10
10
|
},
|
|
11
11
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
12
|
-
"GitRevision": "
|
|
12
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
13
13
|
}
|
|
@@ -3,7 +3,7 @@ JSBundle.bundles['io.breakside.JSKit.SecurityKit'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "framework",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.JSKit.SecurityKit",
|
|
6
|
-
"JSBundleVersion": "2023.
|
|
6
|
+
"JSBundleVersion": "2023.12.0",
|
|
7
7
|
"JSDevelopmentLanguage": "en",
|
|
8
8
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
9
9
|
"JSBundleEnvironments": {
|
|
@@ -11,7 +11,7 @@ JSBundle.bundles['io.breakside.JSKit.SecurityKit'] = {
|
|
|
11
11
|
"node": "SecurityKit+Node.js"
|
|
12
12
|
},
|
|
13
13
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
14
|
-
"GitRevision": "
|
|
14
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
15
15
|
},
|
|
16
16
|
"Resources": [],
|
|
17
17
|
"ResourceLookup": {
|
package/Info.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "node",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.jskit",
|
|
4
|
-
"JSBundleVersion": "2023.
|
|
4
|
+
"JSBundleVersion": "2023.12.0",
|
|
5
5
|
"JSExecutableName": "jskit",
|
|
6
6
|
"NPMOrganization": "breakside",
|
|
7
7
|
"JSResources": [
|
|
8
8
|
"Tests/HTMLTestRunner.js",
|
|
9
9
|
"Tests/NodeTestRunner.js"
|
|
10
10
|
],
|
|
11
|
-
"GitRevision": "
|
|
11
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
12
12
|
}
|
|
@@ -3,14 +3,14 @@ JSBundle.bundles['io.breakside.jskit'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "node",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.jskit",
|
|
6
|
-
"JSBundleVersion": "2023.
|
|
6
|
+
"JSBundleVersion": "2023.12.0",
|
|
7
7
|
"JSExecutableName": "jskit",
|
|
8
8
|
"NPMOrganization": "breakside",
|
|
9
9
|
"JSResources": [
|
|
10
10
|
"Tests/HTMLTestRunner.js",
|
|
11
11
|
"Tests/NodeTestRunner.js"
|
|
12
12
|
],
|
|
13
|
-
"GitRevision": "
|
|
13
|
+
"GitRevision": "590b22d102229b09d1bd77087adbb6e91149ca9d"
|
|
14
14
|
},
|
|
15
15
|
"Resources": [
|
|
16
16
|
{
|