@breakside/jskit 2025.10.0 → 2025.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  3. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  4. package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
  5. package/Frameworks/Foundation.jsframework/Info.json +2 -2
  6. package/Frameworks/Foundation.jsframework/JS/JSDiff.js +148 -53
  7. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  8. package/Frameworks/Foundation.jsframework/sources.json +1 -0
  9. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  10. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  11. package/Info.json +2 -2
  12. package/Node/io.breakside.jskit-bundle.js +2 -2
  13. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  14. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  15. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  16. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  17. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  18. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  19. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  20. package/Root/Frameworks/DOM/Info.yaml +1 -1
  21. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  22. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  23. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  24. package/Root/Frameworks/Foundation/JSDiff.js +148 -53
  25. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  26. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  27. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  28. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  29. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  30. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  31. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  32. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  33. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  34. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  35. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  36. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  37. package/Root/Frameworks/UIKit/UIHTMLWindowServer.js +3 -3
  38. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  39. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "JSBundleType": "framework",
3
3
  "JSBundleIdentifier": "io.breakside.JSKit.DOM",
4
- "JSBundleVersion": "2025.10.0",
4
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
12
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
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": "2025.10.0",
6
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
14
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
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": "2025.10.0",
4
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
11
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
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": "2025.10.0",
6
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
13
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
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": "2025.10.0",
4
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
12
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
13
13
  }
@@ -20,80 +20,175 @@ JSClass("JSDiff", JSObject, {
20
20
  this.initWithArrays(a, b);
21
21
  },
22
22
 
23
+ operations: JSLazyInitProperty(function(){
24
+ return this.shortestOperationList();
25
+ }),
26
+
23
27
  commonIndexes: JSLazyInitProperty(function(){
28
+ var operations = this.operations;
29
+ var operationIndex = 0;
30
+ var operationCount = operations.length;
31
+ var m = this.a.length;
32
+ var n = this.b.length;
33
+ var commonIndexes = [];
34
+ var i = 0;
35
+ var j = 0;
36
+ while (i < m && j < n){
37
+ if (operationIndex < operationCount && operations[operationIndex].originalIndex === i){
38
+ if (operations[operationIndex].operator === JSDiff.Operator.delete){
39
+ ++i;
40
+ }else{
41
+ ++j;
42
+ }
43
+ ++operationIndex;
44
+ }else{
45
+ commonIndexes.push([i, j]);
46
+ ++i;
47
+ ++j;
48
+ }
49
+ }
50
+ return commonIndexes;
51
+ }),
52
+
53
+ shortestOperationList: function(){
54
+ var operations = [];
24
55
  var a = this.a;
25
56
  var b = this.b;
26
57
  if (this.mapFunction !== null){
27
58
  a = a.map(this.mapFunction);
28
59
  b = b.map(this.mapFunction);
29
60
  }
30
- return this.indexesOfLongestCommonSubsequence(a, 0, a.length - 1, b, 0, b.length - 1);
31
- }),
32
-
33
- recursionCount: 0,
34
- comparisonCount: 0,
61
+ var m = a.length;
62
+ var n = b.length;
63
+ var i = 0;
64
+ var j = 0;
35
65
 
36
- indexesOfLongestCommonSubsequence: function(a, i0, i1, b, j0, j1){
37
- ++this.recursionCount;
38
- if (i1 >= i0 && j1 >= j0){
66
+ // common prefix
67
+ for (; i < m && j < n; ++i, ++j){
39
68
  ++this.comparisonCount;
40
- if (a[i0] === b[j0]){
41
- var head = [];
42
- ++this.comparisonCount;
43
- while (i1 >= i0 && j1 >= j0 && a[i0] === b[i0]){
44
- head.push([i0, j0]);
45
- ++i0;
46
- ++j0;
47
- ++this.comparisonCount;
48
- }
49
- return head.concat(this.indexesOfLongestCommonSubsequence(a, i0, i1, b, j0, j1));
69
+ if (a[i] !== b[j]){
70
+ break;
50
71
  }
72
+ }
73
+
74
+ // common suffix
75
+ for (; m > i && n > j; --m, --n){
51
76
  ++this.comparisonCount;
52
- if (a[i1] === b[j1]){
53
- var tail = [];
77
+ if (a[m - 1] !== b[n - 1]){
78
+ break;
79
+ }
80
+ }
81
+
82
+ // special case, a and b are equal
83
+ if (i === m && j === n){
84
+ return operations;
85
+ }
86
+
87
+ // special case, b contains all of a plus extra at the end
88
+ if (i === m){
89
+ for (; j < n; ++j){
90
+ operations.push(JSDiffOperation(JSDiff.Operator.insert, i, j));
91
+ }
92
+ return operations;
93
+ }
94
+
95
+ // special case, b contains only the start of a
96
+ if (j === n){
97
+ for (; i < m; ++i){
98
+ operations.push(JSDiffOperation(JSDiff.Operator.delete, i, j));
99
+ }
100
+ return operations;
101
+ }
102
+
103
+ var operationCount = 1;
104
+ var maximumOperationCount = Math.min(m + n, this.maximumOperationCount);
105
+ var diagonalNumber;
106
+ var minimumDiagonalNumber = -1;
107
+ var maximumDiagonalNumber = 1;
108
+ var diagonals = {};
109
+ var diagonal;
110
+ var referenceDiagonal;
111
+ var operation;
112
+ var operator;
113
+ diagonals[0] = {
114
+ i: i,
115
+ operation: null
116
+ };
117
+ for (; operationCount <= maximumOperationCount; ++operationCount){
118
+ for (diagonalNumber = minimumDiagonalNumber; diagonalNumber <= maximumDiagonalNumber; diagonalNumber += 2){
54
119
  ++this.comparisonCount;
55
- while (i1 >= i0 && j1 >= j0 && a[i1] === b[j1]){
56
- tail.unshift([i1, j1]);
57
- --i1;
58
- --j1;
120
+ if (diagonalNumber === -operationCount || (diagonalNumber !== operationCount && diagonals[diagonalNumber + 1].i >= diagonals[diagonalNumber - 1].i)){
121
+ referenceDiagonal = diagonals[diagonalNumber + 1];
122
+ i = referenceDiagonal.i + 1;
123
+ j = i + diagonalNumber;
124
+ operation = JSDiffOperation(JSDiff.Operator.delete, i - 1, j);
125
+ }else{
126
+ referenceDiagonal = diagonals[diagonalNumber - 1];
127
+ i = referenceDiagonal.i;
128
+ j = i + diagonalNumber;
129
+ operation = JSDiffOperation(JSDiff.Operator.insert, i, j - 1);
130
+ }
131
+ operation.previous = referenceDiagonal.operation;
132
+ for (; i < m && j < n; ++i, ++j){
59
133
  ++this.comparisonCount;
134
+ if (a[i] !== b[j]){
135
+ break;
136
+ }
137
+ }
138
+ diagonal = diagonals[diagonalNumber];
139
+ if (diagonal === undefined){
140
+ diagonal = {
141
+ i: i,
142
+ operation: operation,
143
+ };
144
+ diagonals[diagonalNumber] = diagonal;
145
+ }else{
146
+ diagonal.i = i;
147
+ diagonal.operation = operation;
148
+ }
149
+ if (i === m && j === n){
150
+ while (operation !== null){
151
+ operations.unshift(operation);
152
+ operation = operation.previous;
153
+ }
154
+ return operations;
155
+ }
156
+ if (i === m){
157
+ minimumDiagonalNumber = diagonalNumber + 2;
158
+ }
159
+ if (j === n){
160
+ maximumDiagonalNumber = diagonalNumber - 2;
60
161
  }
61
- return this.indexesOfLongestCommonSubsequence(a, i0, i1, b, j0, j1).concat(tail);
62
- }
63
- var sequence1 = this.indexesOfLongestCommonSubsequence(a, i0, i1, b, j0, j1 - 1);
64
- var sequence2 = this.indexesOfLongestCommonSubsequence(a, i0, i1 - 1, b, j0, j1);
65
- if (sequence1.length >= sequence2.length){
66
- return sequence1;
67
162
  }
68
- return sequence2;
163
+ --minimumDiagonalNumber;
164
+ ++maximumDiagonalNumber;
69
165
  }
70
- return [];
71
- },
72
166
 
73
- operations: function(){
74
- var a = [];
75
- var b = [];
76
- var i, l;
77
- var j, k;
78
- var commonIndexes = this.commonIndexes;
79
- for (i = 0, l = a.length; i < l; ++i){
80
- }
81
- return [a, b];
167
+ return null;
82
168
  },
83
169
 
84
- longestCommonSubsequence: function(){
85
- var commonIndexes = this.commonIndexes;
86
- var sequence = [];
87
- var i, l;
88
- for (i = 0, l = commonIndexes.length; i < l; ++i){
89
- sequence.push(this.a[commonIndexes[i][0]]);
90
- }
91
- return sequence;
92
- }
170
+ maximumOperationCount: Infinity,
171
+ comparisonCount: 0,
93
172
 
94
173
  });
95
174
 
96
- JSDiff.Operation = {
175
+ JSGlobalObject.JSDiffOperation = function(operator, originalIndex, modifiedIndex){
176
+ if (this === undefined){
177
+ return new JSDiffOperation(operator, originalIndex, modifiedIndex);
178
+ }
179
+ if (operator instanceof JSDiffOperation){
180
+ this.operator = operator.operator;
181
+ this.originalIndex = operator.originalIndex;
182
+ this.modifiedIndex = operator.modifiedIndex;
183
+ }else{
184
+ this.operator = operator;
185
+ this.originalIndex = originalIndex;
186
+ this.modifiedIndex = modifiedIndex;
187
+ }
188
+ this.previous = null;
189
+ };
190
+
191
+ JSDiff.Operator = {
97
192
  insert: 1,
98
193
  delete: 2
99
- };
194
+ };
@@ -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": "2025.10.0",
6
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
14
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
15
15
  },
16
16
  "Resources": [
17
17
  {
@@ -268,6 +268,7 @@
268
268
  "JSDistributedNotificationCenter",
269
269
  "JSSynchronizer",
270
270
  "JSDiff",
271
+ "JSDiffOperation",
271
272
  "JSCRC32",
272
273
  "JSZip",
273
274
  "JSMD5Hash",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "JSBundleType": "framework",
3
3
  "JSBundleIdentifier": "io.breakside.JSKit.SecurityKit",
4
- "JSBundleVersion": "2025.10.0",
4
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
12
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
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": "2025.10.0",
6
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
14
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
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": "2025.10.0",
4
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
11
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
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": "2025.10.0",
6
+ "JSBundleVersion": "2025.20.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": "5812a1dd94c9bf9b769a5911e6de85e02afbef0a"
13
+ "GitRevision": "39a7679e215d45ade564b5d488c67e099c0ba599"
14
14
  },
15
15
  "Resources": [
16
16
  {
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.APIKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSIncludeDirectories:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.APIKitTesting
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.AuthKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.CSSOM
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ChartKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2021 Breakside Inc.
6
6
  # JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ConferenceKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.DBKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.DOM
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.Dispatch
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSCopyright: Copyright © 2020 Breakside Inc.
5
5
  JSBundleEnvironments:
6
6
  html: Dispatch+HTML.js
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.FontKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.Foundation
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -20,80 +20,175 @@ JSClass("JSDiff", JSObject, {
20
20
  this.initWithArrays(a, b);
21
21
  },
22
22
 
23
+ operations: JSLazyInitProperty(function(){
24
+ return this.shortestOperationList();
25
+ }),
26
+
23
27
  commonIndexes: JSLazyInitProperty(function(){
28
+ var operations = this.operations;
29
+ var operationIndex = 0;
30
+ var operationCount = operations.length;
31
+ var m = this.a.length;
32
+ var n = this.b.length;
33
+ var commonIndexes = [];
34
+ var i = 0;
35
+ var j = 0;
36
+ while (i < m && j < n){
37
+ if (operationIndex < operationCount && operations[operationIndex].originalIndex === i){
38
+ if (operations[operationIndex].operator === JSDiff.Operator.delete){
39
+ ++i;
40
+ }else{
41
+ ++j;
42
+ }
43
+ ++operationIndex;
44
+ }else{
45
+ commonIndexes.push([i, j]);
46
+ ++i;
47
+ ++j;
48
+ }
49
+ }
50
+ return commonIndexes;
51
+ }),
52
+
53
+ shortestOperationList: function(){
54
+ var operations = [];
24
55
  var a = this.a;
25
56
  var b = this.b;
26
57
  if (this.mapFunction !== null){
27
58
  a = a.map(this.mapFunction);
28
59
  b = b.map(this.mapFunction);
29
60
  }
30
- return this.indexesOfLongestCommonSubsequence(a, 0, a.length - 1, b, 0, b.length - 1);
31
- }),
32
-
33
- recursionCount: 0,
34
- comparisonCount: 0,
61
+ var m = a.length;
62
+ var n = b.length;
63
+ var i = 0;
64
+ var j = 0;
35
65
 
36
- indexesOfLongestCommonSubsequence: function(a, i0, i1, b, j0, j1){
37
- ++this.recursionCount;
38
- if (i1 >= i0 && j1 >= j0){
66
+ // common prefix
67
+ for (; i < m && j < n; ++i, ++j){
39
68
  ++this.comparisonCount;
40
- if (a[i0] === b[j0]){
41
- var head = [];
42
- ++this.comparisonCount;
43
- while (i1 >= i0 && j1 >= j0 && a[i0] === b[i0]){
44
- head.push([i0, j0]);
45
- ++i0;
46
- ++j0;
47
- ++this.comparisonCount;
48
- }
49
- return head.concat(this.indexesOfLongestCommonSubsequence(a, i0, i1, b, j0, j1));
69
+ if (a[i] !== b[j]){
70
+ break;
50
71
  }
72
+ }
73
+
74
+ // common suffix
75
+ for (; m > i && n > j; --m, --n){
51
76
  ++this.comparisonCount;
52
- if (a[i1] === b[j1]){
53
- var tail = [];
77
+ if (a[m - 1] !== b[n - 1]){
78
+ break;
79
+ }
80
+ }
81
+
82
+ // special case, a and b are equal
83
+ if (i === m && j === n){
84
+ return operations;
85
+ }
86
+
87
+ // special case, b contains all of a plus extra at the end
88
+ if (i === m){
89
+ for (; j < n; ++j){
90
+ operations.push(JSDiffOperation(JSDiff.Operator.insert, i, j));
91
+ }
92
+ return operations;
93
+ }
94
+
95
+ // special case, b contains only the start of a
96
+ if (j === n){
97
+ for (; i < m; ++i){
98
+ operations.push(JSDiffOperation(JSDiff.Operator.delete, i, j));
99
+ }
100
+ return operations;
101
+ }
102
+
103
+ var operationCount = 1;
104
+ var maximumOperationCount = Math.min(m + n, this.maximumOperationCount);
105
+ var diagonalNumber;
106
+ var minimumDiagonalNumber = -1;
107
+ var maximumDiagonalNumber = 1;
108
+ var diagonals = {};
109
+ var diagonal;
110
+ var referenceDiagonal;
111
+ var operation;
112
+ var operator;
113
+ diagonals[0] = {
114
+ i: i,
115
+ operation: null
116
+ };
117
+ for (; operationCount <= maximumOperationCount; ++operationCount){
118
+ for (diagonalNumber = minimumDiagonalNumber; diagonalNumber <= maximumDiagonalNumber; diagonalNumber += 2){
54
119
  ++this.comparisonCount;
55
- while (i1 >= i0 && j1 >= j0 && a[i1] === b[j1]){
56
- tail.unshift([i1, j1]);
57
- --i1;
58
- --j1;
120
+ if (diagonalNumber === -operationCount || (diagonalNumber !== operationCount && diagonals[diagonalNumber + 1].i >= diagonals[diagonalNumber - 1].i)){
121
+ referenceDiagonal = diagonals[diagonalNumber + 1];
122
+ i = referenceDiagonal.i + 1;
123
+ j = i + diagonalNumber;
124
+ operation = JSDiffOperation(JSDiff.Operator.delete, i - 1, j);
125
+ }else{
126
+ referenceDiagonal = diagonals[diagonalNumber - 1];
127
+ i = referenceDiagonal.i;
128
+ j = i + diagonalNumber;
129
+ operation = JSDiffOperation(JSDiff.Operator.insert, i, j - 1);
130
+ }
131
+ operation.previous = referenceDiagonal.operation;
132
+ for (; i < m && j < n; ++i, ++j){
59
133
  ++this.comparisonCount;
134
+ if (a[i] !== b[j]){
135
+ break;
136
+ }
137
+ }
138
+ diagonal = diagonals[diagonalNumber];
139
+ if (diagonal === undefined){
140
+ diagonal = {
141
+ i: i,
142
+ operation: operation,
143
+ };
144
+ diagonals[diagonalNumber] = diagonal;
145
+ }else{
146
+ diagonal.i = i;
147
+ diagonal.operation = operation;
148
+ }
149
+ if (i === m && j === n){
150
+ while (operation !== null){
151
+ operations.unshift(operation);
152
+ operation = operation.previous;
153
+ }
154
+ return operations;
155
+ }
156
+ if (i === m){
157
+ minimumDiagonalNumber = diagonalNumber + 2;
158
+ }
159
+ if (j === n){
160
+ maximumDiagonalNumber = diagonalNumber - 2;
60
161
  }
61
- return this.indexesOfLongestCommonSubsequence(a, i0, i1, b, j0, j1).concat(tail);
62
- }
63
- var sequence1 = this.indexesOfLongestCommonSubsequence(a, i0, i1, b, j0, j1 - 1);
64
- var sequence2 = this.indexesOfLongestCommonSubsequence(a, i0, i1 - 1, b, j0, j1);
65
- if (sequence1.length >= sequence2.length){
66
- return sequence1;
67
162
  }
68
- return sequence2;
163
+ --minimumDiagonalNumber;
164
+ ++maximumDiagonalNumber;
69
165
  }
70
- return [];
71
- },
72
166
 
73
- operations: function(){
74
- var a = [];
75
- var b = [];
76
- var i, l;
77
- var j, k;
78
- var commonIndexes = this.commonIndexes;
79
- for (i = 0, l = a.length; i < l; ++i){
80
- }
81
- return [a, b];
167
+ return null;
82
168
  },
83
169
 
84
- longestCommonSubsequence: function(){
85
- var commonIndexes = this.commonIndexes;
86
- var sequence = [];
87
- var i, l;
88
- for (i = 0, l = commonIndexes.length; i < l; ++i){
89
- sequence.push(this.a[commonIndexes[i][0]]);
90
- }
91
- return sequence;
92
- }
170
+ maximumOperationCount: Infinity,
171
+ comparisonCount: 0,
93
172
 
94
173
  });
95
174
 
96
- JSDiff.Operation = {
175
+ JSGlobalObject.JSDiffOperation = function(operator, originalIndex, modifiedIndex){
176
+ if (this === undefined){
177
+ return new JSDiffOperation(operator, originalIndex, modifiedIndex);
178
+ }
179
+ if (operator instanceof JSDiffOperation){
180
+ this.operator = operator.operator;
181
+ this.originalIndex = operator.originalIndex;
182
+ this.modifiedIndex = operator.modifiedIndex;
183
+ }else{
184
+ this.operator = operator;
185
+ this.originalIndex = originalIndex;
186
+ this.modifiedIndex = modifiedIndex;
187
+ }
188
+ this.previous = null;
189
+ };
190
+
191
+ JSDiff.Operator = {
97
192
  insert: 1,
98
193
  delete: 2
99
- };
194
+ };
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ImageKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.MediaKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.MediaKitUI
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.NotificationKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2021 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.PDFKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.QRKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.SearchKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.SecurityKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ServerKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ServerKitTesting
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.TestKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.UIKit
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -168,7 +168,7 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
168
168
  this.rootElement.addEventListener('touchend', this, {passive: false, capture: false});
169
169
  this.rootElement.addEventListener('touchcancel', this, {passive: false, capture: false});
170
170
  this.rootElement.addEventListener('touchmove', this, {passive: false, capture: false});
171
- if (this.domWindow.visualViewport !== null){
171
+ if (this.domWindow.visualViewport !== null && this.domWindow.visualViewport !== undefined){
172
172
  this.domWindow.visualViewport.addEventListener('resize', this, false);
173
173
  }
174
174
  },
@@ -205,7 +205,7 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
205
205
  this.rootElement.removeEventListener('touchend', this, {passive: false, capture: false});
206
206
  this.rootElement.removeEventListener('touchcancel', this, {passive: false, capture: false});
207
207
  this.rootElement.removeEventListener('touchmove', this, {passive: false, capture: false});
208
- if (this.domWindow.visualViewport !== null){
208
+ if (this.domWindow.visualViewport !== null && this.domWindow.visualViewport !== undefined){
209
209
  this.domWindow.visualViewport.removeEventListener('resize', this, false);
210
210
  }
211
211
  },
@@ -760,7 +760,7 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
760
760
  this.screen.frame = JSRect(JSPoint.Zero, this.rootElementSize());
761
761
  this.screenDidChangeFrame(oldFrame);
762
762
  this.displayServer.setScreenSize(this.screen.frame.size);
763
- }else if (e.currentTarget === this.domWindow.visualViewport){
763
+ }else if (this.domWindow.visualViewport !== null && this.domWindow.visualViewport !== undefined && e.currentTarget === this.domWindow.visualViewport){
764
764
  // using touch screen as proxy for "has virtual keyboard"
765
765
  // not a perfect match, but good enough for now
766
766
  if (UIDevice.shared.primaryPointerType === UIUserInterface.PointerType.touch){
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.UIKitTesting
3
- JSBundleVersion: 2025.10.0
3
+ JSBundleVersion: 2025.20.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "node": ">=10.10.0"
10
10
  },
11
11
  "name": "@breakside/jskit",
12
- "version": "2025.10.0",
12
+ "version": "2025.20.0",
13
13
  "license": "SEE LICENSE IN LICENSE.txt",
14
14
  "files": [
15
15
  "*"