@breakside/jskit 2026.9.0 → 2026.11.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 (73) 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/JSColor.js +5 -0
  7. package/Frameworks/Foundation.jsframework/JS/JSNodeHTTPClient.js +34 -14
  8. package/Frameworks/Foundation.jsframework/JS/JSNodeURLSessionDataTask.js +2 -2
  9. package/Frameworks/Foundation.jsframework/JS/JSPath.js +482 -49
  10. package/Frameworks/Foundation.jsframework/JS/JSSpec.js +5 -1
  11. package/Frameworks/Foundation.jsframework/JS/JSURLRequest.js +3 -0
  12. package/Frameworks/Foundation.jsframework/JS/JSZip.js +155 -1
  13. package/Frameworks/Foundation.jsframework/JS/String+JS.js +78 -2
  14. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  15. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  16. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  17. package/Info.json +2 -2
  18. package/Node/DocCommand.js +5 -2
  19. package/Node/Docs/DocClass.js +40 -3
  20. package/Node/Docs/DocComponent.js +32 -5
  21. package/Node/Docs/DocDictionaryProperty.js +10 -2
  22. package/Node/Docs/DocEnum.js +35 -2
  23. package/Node/Docs/DocEnumOption.js +5 -2
  24. package/Node/Docs/DocExtension.js +130 -0
  25. package/Node/Docs/DocFunction.js +10 -2
  26. package/Node/Docs/DocMethod.js +3 -0
  27. package/Node/Docs/DocProperty.js +13 -2
  28. package/Node/Docs/DocProtocol.js +5 -1
  29. package/Node/Docs/DocSpec.js +5 -1
  30. package/Node/Docs/DocSpecProperty.js +10 -2
  31. package/Node/Docs/DocTopicBasedComponent.js +75 -65
  32. package/Node/Documentation.js +83 -6
  33. package/Node/HTMLBuilder.js +3 -1
  34. package/Node/HTMLProjectServer.js +40 -2
  35. package/Node/Markdown.js +2 -2
  36. package/Node/io.breakside.jskit-bundle.js +4 -4
  37. package/Node/jskit +1 -0
  38. package/Resources/doc-default.css +3 -11
  39. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  40. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  41. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  42. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  43. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  44. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  45. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  46. package/Root/Frameworks/DOM/Info.yaml +1 -1
  47. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  48. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  49. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  50. package/Root/Frameworks/Foundation/JSColor.js +5 -0
  51. package/Root/Frameworks/Foundation/JSNodeHTTPClient.js +34 -14
  52. package/Root/Frameworks/Foundation/JSNodeURLSessionDataTask.js +2 -2
  53. package/Root/Frameworks/Foundation/JSPath.js +482 -49
  54. package/Root/Frameworks/Foundation/JSSpec.js +5 -1
  55. package/Root/Frameworks/Foundation/JSURLRequest.js +3 -0
  56. package/Root/Frameworks/Foundation/JSZip.js +155 -1
  57. package/Root/Frameworks/Foundation/String+JS.js +78 -2
  58. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  59. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  60. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  61. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  62. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  63. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  64. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  65. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  66. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  67. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  68. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  69. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  70. package/Root/Frameworks/UIKit/UIListView.js +11 -3
  71. package/Root/Frameworks/UIKit/UIOutlineView.js +65 -5
  72. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  73. package/package.json +1 -1
@@ -11,9 +11,160 @@ JSClass("JSZip", JSObject, {
11
11
  init: function(){
12
12
  this.chunks = [];
13
13
  this.directory = [];
14
+ this.directoryIndexByFilename = {};
14
15
  this.offset = 0;
15
16
  },
16
17
 
18
+ initWithData: function(data){
19
+ if (data === null || data === undefined){
20
+ return null;
21
+ }
22
+ if (data.length < 22){
23
+ return null;
24
+ }
25
+ this._data = data;
26
+ this.directory = [];
27
+ this.directoryIndexByFilename = {};
28
+ var offset = this._data.length - 22;
29
+ var minOffset = Math.max(0, offset - 0xFFFF);
30
+ while (offset >= minOffset && !(this._data[offset] === 0x50 && this._data[offset+1] === 0x4b && this._data[offset+2] === 0x05 && this._data[offset+3] === 0x06)){
31
+ offset -= 1;
32
+ }
33
+ if (offset < minOffset){
34
+ return null;
35
+ }
36
+ var end = this._data.subdataInRange(JSRange(offset, this._data.length - offset));
37
+ var dataView = end.dataView();
38
+ // End of Central Directory Record (APPNOTE.txt 4.3.16)
39
+ // everything is little-endian
40
+ var signature = dataView.getUint32(0, true);
41
+ if (signature !== 0x06054b50){
42
+ return null;
43
+ }
44
+ var diskNumber = dataView.getUint16(4, true);
45
+ var diskNumberWithDirectoryStart = dataView.getUint16(6, true);
46
+ var numberOfItemsOnDisk = dataView.getUint16(8, true);
47
+ var numberOfItemsTotal = dataView.getUint16(10, true);
48
+ var sizeOfDirectory = dataView.getUint32(12, true);
49
+ var offsetOfDirectoryStart = dataView.getUint32(16, true);
50
+ var commentLength = dataView.getUint16(20, true);
51
+ if (diskNumber !== 0 || diskNumberWithDirectoryStart !== 0){
52
+ return null;
53
+ }
54
+ if (offsetOfDirectoryStart + sizeOfDirectory > this._data.length){
55
+ return null;
56
+ }
57
+ var directory = this._data.subdataInRange(JSRange(offsetOfDirectoryStart, sizeOfDirectory));
58
+ dataView = directory.dataView();
59
+ var crc;
60
+ var compressedLength;
61
+ var uncompressedLength;
62
+ var nameLength;
63
+ var extraFieldLength;
64
+ var name;
65
+ var headerOffset;
66
+ var offset = 0;
67
+ for (var i = 0; i < numberOfItemsTotal; ++i){
68
+ // Central Directory File Header (APPNOTE.txt 4.3.12)
69
+ // Everything is little-endian
70
+ if (offset + 46 > sizeOfDirectory){
71
+ return null;
72
+ }
73
+ signature = dataView.getUint32(offset + 0, true);
74
+ if (signature !== 0x02014b50){
75
+ return null;
76
+ }
77
+ crc = dataView.getUint32(offset + 16, true);
78
+ compressedLength = dataView.getUint32(offset + 20, true);
79
+ uncompressedLength = dataView.getUint32(offset + 24, true);
80
+ nameLength = dataView.getUint16(offset + 28, true);
81
+ extraFieldLength = dataView.getUint16(offset + 30, true);
82
+ commentLength = dataView.getUint16(offset + 32, true);
83
+ headerOffset = dataView.getUint32(offset + 42, true);
84
+ if (offset + 46 + nameLength > sizeOfDirectory){
85
+ return null;
86
+ }
87
+ name = directory.subdataInRange(JSRange(offset + 46, nameLength)).stringByDecodingUTF8();
88
+ this.directory.push({
89
+ name: name,
90
+ offset: headerOffset,
91
+ header: this.data.subdataInRange(JSRange(headerOffset, 30 + nameLength + extraFieldLength)),
92
+ crc: crc,
93
+ compressedLength: compressedLength,
94
+ uncompressedLength: uncompressedLength
95
+ });
96
+ this.directoryIndexByFilename[name] = i;
97
+ offset += 46 + nameLength + extraFieldLength + commentLength;
98
+ }
99
+
100
+ },
101
+
102
+ directoryIndexByFilename: null,
103
+ filenames: JSReadOnlyProperty(),
104
+
105
+ getFilenames: function(){
106
+ var filenames = [];
107
+ for (var i = 0, l = this.directory.length; i < l; ++i){
108
+ filenames.push(this.directory[i].name);
109
+ }
110
+ return filenames;
111
+ },
112
+
113
+ dataForFilename: function(filename){
114
+ var index = this.directoryIndexByFilename[filename];
115
+ if (index === undefined){
116
+ return null;
117
+ }
118
+ var file = this.directory[index];
119
+ var dataView = file.header.dataView();
120
+ var signature = dataView.getUint32(0, true);
121
+ if (signature !== 0x04034b50){
122
+ return null;
123
+ }
124
+ var version = dataView.getUint16(4, true);
125
+ var flags = dataView.getUint16(6, true);
126
+ var method = dataView.getUint16(8, true);
127
+ var crc = dataView.getUint32(14, true);
128
+ var compressedLength = dataView.getUint32(18, true);
129
+ var uncompressedLength = dataView.getUint32(22, true);
130
+ var nameLength = dataView.getUint16(26, true);
131
+ var extraFieldLength = dataView.getUint16(28, true);
132
+ var offset = file.offset + 30 + nameLength + extraFieldLength;
133
+ if (version > 20){
134
+ return null;
135
+ }
136
+ if (method !== 8){
137
+ return null;
138
+ }
139
+ if ((flags & 0x8) !== 0){
140
+ crc = file.crc;
141
+ compressedLength = file.compressedLength;
142
+ uncompressedLength = file.uncompressedLength;
143
+ }
144
+ if (offset + compressedLength > this.data.length){
145
+ return null;
146
+ }
147
+ if (compressedLength === 0 || uncompressedLength === 0){
148
+ return null;
149
+ }
150
+ var compressedData = this.data.subdataInRange(JSRange(offset, compressedLength));
151
+ var data = JSData.initWithLength(uncompressedLength);
152
+ var stream = DeflateStream();
153
+ stream.input = compressedData;
154
+ stream.output = data;
155
+ stream.inflate(true);
156
+ if (stream.state !== DeflateStream.State.done){
157
+ data = null;
158
+ }
159
+ if (data === null){
160
+ return;
161
+ }
162
+ if (JSCRC32(data) !== crc){
163
+ return null;
164
+ }
165
+ return data;
166
+ },
167
+
17
168
  offset: 0,
18
169
 
19
170
  addFile: function(file, completion, target){
@@ -83,7 +234,10 @@ JSClass("JSZip", JSObject, {
83
234
  this.directory.push({
84
235
  name: name,
85
236
  offset: this.offset,
86
- header: header
237
+ header: header,
238
+ crc: crc,
239
+ compressedLength: storedData.length,
240
+ uncompressedLength: data.length
87
241
  });
88
242
  this.chunks.push(header);
89
243
  this.chunks.push(storedData);
@@ -1592,7 +1592,7 @@ String.printf_formatter = {
1592
1592
 
1593
1593
  x: function(arg, options){
1594
1594
  // TODO: obey any other options
1595
- var str = arg.toString(16);
1595
+ var str = Math.floor(arg).toString(16);
1596
1596
  if (options.width){
1597
1597
  if (options.zero){
1598
1598
  str = str.leftPaddedString('0', options.width);
@@ -1633,7 +1633,83 @@ String.printf_formatter = {
1633
1633
  if (Math.abs(arg) < 0.000001){
1634
1634
  arg = 0;
1635
1635
  }
1636
- return (arg !== null && arg !== undefined && arg.toString) ? arg.toString() : arg;
1636
+ var n = arg;
1637
+ if (n === null){
1638
+ return "null";
1639
+ }
1640
+ if (n === undefined){
1641
+ return "undefined";
1642
+ }
1643
+ if (isNaN(n)){
1644
+ return "NaN";
1645
+ }
1646
+ if (!isFinite(n)){
1647
+ if (n < 0){
1648
+ return "-Inf";
1649
+ }
1650
+ return "Inf";
1651
+ }
1652
+
1653
+ // Prefix & Suffix
1654
+ var negative = n < 0;
1655
+ var prefix = "";
1656
+ if (negative){
1657
+ n = -n;
1658
+ prefix = "-";
1659
+ }
1660
+
1661
+ // Integer
1662
+ var maximumFractionDigits = options.precision || 6;
1663
+ var minimumFractionDigits = options.precision || 0;
1664
+ var minimumIntegerDigits = options.zero ? 1 : 0;
1665
+ var integer = Math.floor(n);
1666
+ var fraction = n - integer;
1667
+ var maximumFraction = Math.pow(10, maximumFractionDigits);
1668
+ fraction = Math.round(fraction * maximumFraction);
1669
+ if (fraction >= maximumFraction){
1670
+ integer += 1;
1671
+ fraction = 0;
1672
+ }
1673
+ var str = (integer !== 0 || (minimumIntegerDigits === 0 && minimumFractionDigits === 0)) ? integer.toString() : "";
1674
+ var zeroFillCount = minimumIntegerDigits - str.length;
1675
+ var i, l;
1676
+ if (zeroFillCount > 0){
1677
+ var fill = "";
1678
+ for (i = 0; i < zeroFillCount; ++i){
1679
+ fill += "0";
1680
+ }
1681
+ str = fill + str;
1682
+ }
1683
+
1684
+ // Decimal
1685
+ if (maximumFraction > 0){
1686
+ if (minimumFractionDigits > 0 || fraction !== 0){
1687
+ if (minimumFractionDigits > 0 || fraction !== 0){
1688
+ str += ".";
1689
+ var fractionString = fraction.toString();
1690
+ while (fractionString.length < maximumFractionDigits){
1691
+ fractionString = "0" + fractionString;
1692
+ }
1693
+ while (fractionString.length > minimumFractionDigits && fractionString[fractionString.length - 1] === "0"){
1694
+ fractionString = fractionString.substr(0, fractionString.length - 1);
1695
+ }
1696
+ str += fractionString;
1697
+ }
1698
+ }
1699
+ }
1700
+ str = prefix + str;
1701
+ if (options.width){
1702
+ if (options.zero){
1703
+ str = str.leftPaddedString('0', options.width);
1704
+ }else if (options.left_justified){
1705
+ str = str.rightPaddedString(' ', options.width);
1706
+ }else{
1707
+ str = str.leftPaddedString(' ', options.width);
1708
+ }
1709
+ }else if (str === ""){
1710
+ str = "0";
1711
+ }
1712
+ return str;
1637
1713
  },
1638
1714
 
1639
1715
  b: function(arg, options){
@@ -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": "2026.9.0",
6
+ "JSBundleVersion": "2026.11.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": "7481a2557e5555dbf2a58e88ba6720b16de86277"
14
+ "GitRevision": "812100aa4c3e5b1ec1d0d432be903bba4db01b0e"
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": "2026.9.0",
4
+ "JSBundleVersion": "2026.11.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": "7481a2557e5555dbf2a58e88ba6720b16de86277"
12
+ "GitRevision": "812100aa4c3e5b1ec1d0d432be903bba4db01b0e"
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": "2026.9.0",
6
+ "JSBundleVersion": "2026.11.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": "7481a2557e5555dbf2a58e88ba6720b16de86277"
14
+ "GitRevision": "812100aa4c3e5b1ec1d0d432be903bba4db01b0e"
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": "2026.9.0",
4
+ "JSBundleVersion": "2026.11.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": "7481a2557e5555dbf2a58e88ba6720b16de86277"
11
+ "GitRevision": "812100aa4c3e5b1ec1d0d432be903bba4db01b0e"
12
12
  }
@@ -26,8 +26,8 @@ JSClass("DocCommand", Command, {
26
26
  options: {
27
27
  input: {kind: "positional", help: "The root documentation file to start with"},
28
28
  output: {kind: "positional", help: "The directory in which to output the generated documentation"},
29
- sublime: {kind: "flag", help: "Generate Sublime Text completions"}
30
- // style: {default: null, help: "The stylesheet to use"}
29
+ sublime: {kind: "flag", help: "Generate Sublime Text completions"},
30
+ stylesheet: {default: null, help: "Path to the stylesheet to use for docs"},
31
31
  },
32
32
 
33
33
  run: async function(){
@@ -37,6 +37,9 @@ JSClass("DocCommand", Command, {
37
37
  var documentation = Documentation.initWithRootURL(rootURL, this.fileManager);
38
38
  documentation.printer = printer;
39
39
  documentation.outputDirectoryURL = this.fileManager.urlForPath(this.arguments.output, workspaceURL);
40
+ if (this.arguments.stylesheet){
41
+ documentation.customStylesheetURL = this.fileManager.urlForPath(this.arguments.stylesheet, workspaceURL);
42
+ }
40
43
 
41
44
  if (this.arguments.sublime){
42
45
  await documentation.sublime();
@@ -35,11 +35,34 @@
35
35
  if (info.implements){
36
36
  this.implements = info.implements;
37
37
  }
38
+
38
39
  },
39
40
 
40
41
  inherits: null,
41
42
  anonymous: false,
42
43
  implements: null,
44
+ extensions: null,
45
+
46
+ addExtension: function(extension){
47
+ if (this.extensions === null){
48
+ this.extensions = [];
49
+ }
50
+ this.extensions.push(extension);
51
+ },
52
+
53
+ extensionChildForName: function(name){
54
+ if (this.extensions === null){
55
+ return null;
56
+ }
57
+ for (let i = 0, l = this.extensions.length; i < l; ++i){
58
+ let extension = this.extensions[i];
59
+ let component = extension.childForName(name);
60
+ if (component !== null){
61
+ return component;
62
+ }
63
+ }
64
+ return null;
65
+ },
43
66
 
44
67
  // --------------------------------------------------------------------
45
68
  // MARK: - Naming
@@ -62,12 +85,18 @@
62
85
  elements.splice(1, 0, declaration);
63
86
  }
64
87
 
88
+ if (this.extensions !== null){
89
+ for (let extension of this.extensions){
90
+ elements = elements.concat(this.htmlArticleTopicsElements(document, extension.extensionName + " Extensions", extension.topics));
91
+ }
92
+ }
93
+
65
94
  if (this.inherits){
66
95
  let inherits = document.createElement('section');
67
96
  elements.push(inherits);
68
97
  inherits.setAttribute("class", "inherits");
69
98
  let header = inherits.appendChild(document.createElement("header"));
70
- let h1 = header.appendChild(document.createElement("h1"));
99
+ let h1 = header.appendChild(document.createElement("h2"));
71
100
  h1.setAttribute("outline-level", "1");
72
101
  h1.appendChild(document.createTextNode("Inherits From"));
73
102
  let p = inherits.appendChild(document.createElement("p"));
@@ -76,6 +105,10 @@
76
105
  if (url !== null){
77
106
  let a = code.appendChild(document.createElement("a"));
78
107
  a.setAttribute("href", url.encodedString);
108
+ if (url.isAbsolute){
109
+ a.setAttribute("target", "_blank");
110
+ a.setAttribute("rel", "noopener noreferrer");
111
+ }
79
112
  a.appendChild(document.createTextNode(this.inherits));
80
113
  }else{
81
114
  code.appendChild(document.createTextNode(this.inherits));
@@ -87,7 +120,7 @@
87
120
  elements.push(section);
88
121
  section.setAttribute("class", "implements");
89
122
  let header = section.appendChild(document.createElement("header"));
90
- let h1 = header.appendChild(document.createElement("h1"));
123
+ let h1 = header.appendChild(document.createElement("h2"));
91
124
  h1.setAttribute("outline-level", "1");
92
125
  h1.appendChild(document.createTextNode("Implements"));
93
126
  let ul = section.appendChild(document.createElement("ul"));
@@ -99,6 +132,10 @@
99
132
  if (url !== null){
100
133
  let a = code.appendChild(document.createElement("a"));
101
134
  a.setAttribute("href", url.encodedString);
135
+ if (url.isAbsolute){
136
+ a.setAttribute("target", "_blank");
137
+ a.setAttribute("rel", "noopener noreferrer");
138
+ }
102
139
  a.appendChild(document.createTextNode(protocol));
103
140
  }else{
104
141
  code.appendChild(document.createTextNode(protocol));
@@ -129,6 +166,6 @@
129
166
  }
130
167
  }
131
168
  return component;
132
- },
169
+ }
133
170
 
134
171
  });
@@ -300,7 +300,7 @@ JSClass("DocComponent", JSObject, {
300
300
  let section = document.createElement('section');
301
301
  section.setAttribute('class', 'see');
302
302
  let header = document.createElement('header');
303
- let h1 = header.appendChild(document.createElement("h1"));
303
+ let h1 = header.appendChild(document.createElement("h2"));
304
304
  h1.appendChild(document.createTextNode('See Also'));
305
305
  let p = document.createElement('p');
306
306
  section.appendChild(header);
@@ -313,6 +313,10 @@ JSClass("DocComponent", JSObject, {
313
313
  if (url){
314
314
  let a = document.createElement('a');
315
315
  a.setAttribute('href', url.encodedString);
316
+ if (url.isAbsolute){
317
+ a.setAttribute("target", "_blank");
318
+ a.setAttribute("rel", "noopener noreferrer");
319
+ }
316
320
  a.appendChild(document.createTextNode(name));
317
321
  code.appendChild(a);
318
322
  }else{
@@ -428,10 +432,10 @@ JSClass("DocComponent", JSObject, {
428
432
  let description = document.createElement("section");
429
433
  elements.push(description);
430
434
  description.setAttribute("class", "description");
431
- let markdown = this.createMarkdownWithString(this.description);
435
+ let markdown = this.createMarkdownWithString(this.description,);
432
436
  let children = markdown.htmlElementsForDocument(document);
433
437
  if (children.length === 0 || children[0].tagName != markdown.htmlOptions.firstLevelHeaderTagName){
434
- let h1 = description.appendChild(document.createElement("h1"));
438
+ let h1 = description.appendChild(document.createElement(markdown.htmlOptions.firstLevelHeaderTagName));
435
439
  h1.appendChild(document.createTextNode(this.titleForDescriptionSection));
436
440
  h1.setAttribute("outline-level", "1");
437
441
  }
@@ -591,7 +595,7 @@ JSClass("DocComponent", JSObject, {
591
595
  codeSectionElement: function(document, title, lines){
592
596
  var section = document.createElement("section");
593
597
  var header = section.appendChild(document.createElement("header"));
594
- var h1 = header.appendChild(document.createElement("h1"));
598
+ var h1 = header.appendChild(document.createElement("h2"));
595
599
  h1.appendChild(document.createTextNode(title));
596
600
  var code = section.appendChild(document.createElement("div"));
597
601
  code.setAttribute("class", "code");
@@ -619,6 +623,10 @@ JSClass("DocComponent", JSObject, {
619
623
  if (url !== null){
620
624
  span = line.appendChild(document.createElement('a'));
621
625
  span.setAttribute("href", url.encodedString);
626
+ if (url.isAbsolute){
627
+ span.setAttribute("target", "_blank");
628
+ span.setAttribute("rel", "noopener noreferrer");
629
+ }
622
630
  }
623
631
  }
624
632
  if (span === null){
@@ -628,7 +636,7 @@ JSClass("DocComponent", JSObject, {
628
636
  if (token.className){
629
637
  span.setAttribute("class", token.className);
630
638
  }
631
- if (i < l - 1 && tokens[i + 1].value != ','){
639
+ if (i < l - 1 && tokens[i + 1].value != ',' && tokens[i + 1].value[0] != '.'){
632
640
  line.appendChild(document.createTextNode(' '));
633
641
  }
634
642
  }
@@ -669,6 +677,12 @@ JSClass("DocComponent", JSObject, {
669
677
  };
670
678
  },
671
679
 
680
+ populateRelationships: function(){
681
+ for (let child of this.children){
682
+ child.populateRelationships();
683
+ }
684
+ },
685
+
672
686
  output: async function(documentation){
673
687
  let document = this.htmlDocument(documentation);
674
688
  let indexURL = this.outputURL;
@@ -777,6 +791,13 @@ JSClass("DocComponent", JSObject, {
777
791
  if (candidates.length > 0){
778
792
  return candidates[0];
779
793
  }
794
+
795
+ // Extensions
796
+ let component = this.extensionChildForName(name);
797
+ if (component !== null){
798
+ return component;
799
+ }
800
+
780
801
  return null;
781
802
  },
782
803
 
@@ -827,6 +848,10 @@ JSClass("DocComponent", JSObject, {
827
848
  return null;
828
849
  },
829
850
 
851
+ extensionChildForName: function(name){
852
+ return null;
853
+ },
854
+
830
855
  componentForSourceURL: function(sourceURL){
831
856
  if (this.parent !== null){
832
857
  return this.parent.componentForSourceURL(sourceURL);
@@ -865,6 +890,8 @@ JSClass("DocComponent", JSObject, {
865
890
 
866
891
  createMarkdownWithString: function(string){
867
892
  let markdown = Markdown.initWithString(string);
893
+ markdown.htmlOptions.firstLevelHeaderTagName = "h2";
894
+ markdown.htmlOptions.secondLevelHeaderTagName = "h3";
868
895
  markdown.delegate = this;
869
896
  return markdown;
870
897
  },
@@ -45,7 +45,7 @@
45
45
  elements.splice(index++, 0, typeSection);
46
46
  typeSection.setAttribute("class", "return");
47
47
  let header = typeSection.appendChild(document.createElement("header"));
48
- let h1 = header.appendChild(document.createElement("h1"));
48
+ let h1 = header.appendChild(document.createElement("h2"));
49
49
  h1.appendChild(document.createTextNode("Value Type"));
50
50
  let p = typeSection.appendChild(document.createElement("p"));
51
51
  let code = p.appendChild(document.createElement("code"));
@@ -53,6 +53,10 @@
53
53
  if (url){
54
54
  let a = code.appendChild(document.createElement("a"));
55
55
  a.setAttribute("href", url.encodedString);
56
+ if (url.isAbsolute){
57
+ a.setAttribute("target", "_blank");
58
+ a.setAttribute("rel", "noopener noreferrer");
59
+ }
56
60
  a.appendChild(document.createTextNode(this.valueType));
57
61
  }else{
58
62
  code.appendChild(document.createTextNode(this.valueType));
@@ -65,7 +69,7 @@
65
69
  section.setAttribute("class", "variations");
66
70
  elements.push(section);
67
71
  let header = section.appendChild(document.createElement("header"));
68
- let h1 = header.appendChild(document.createElement("h1"));
72
+ let h1 = header.appendChild(document.createElement("h2"));
69
73
  h1.appendChild(document.createTextNode("Alternate Forms"));
70
74
 
71
75
  let ul = section.appendChild(document.createElement("ul"));
@@ -76,6 +80,10 @@
76
80
  let li = ul.appendChild(document.createElement("li"));
77
81
  li.setAttribute("class", variation.kind);
78
82
  let a = document.createElement("a");
83
+ if (url.isAbsolute){
84
+ a.setAttribute("target", "_blank");
85
+ a.setAttribute("rel", "noopener noreferrer");
86
+ }
79
87
  a.setAttribute("href", url.encodedString);
80
88
  let code = li.appendChild(document.createElement('code'));
81
89
  code.appendChild(a);
@@ -36,6 +36,29 @@
36
36
  }
37
37
  },
38
38
 
39
+ extensions: null,
40
+
41
+ addExtension: function(extension){
42
+ if (this.extensions === null){
43
+ this.extensions = [];
44
+ }
45
+ this.extensions.push(extension);
46
+ },
47
+
48
+ extensionChildForName: function(name){
49
+ if (this.extensions === null){
50
+ return null;
51
+ }
52
+ for (let i = 0, l = this.extensions.length; i < l; ++i){
53
+ let extension = this.extensions[i];
54
+ let component = extension.childForName(name);
55
+ if (component !== null){
56
+ return component;
57
+ }
58
+ }
59
+ return null;
60
+ },
61
+
39
62
  suffixForMember: function(member){
40
63
  if (member.isKindOfClass(DocEnumOption) && member.value !== null){
41
64
  return ": %s".sprintf(member.value);
@@ -61,12 +84,22 @@
61
84
  var declaration = this.codeSectionElement(document, "Declaration", this.declarationCode());
62
85
  declaration.setAttribute("class", "declaration");
63
86
  elements.splice(index++, 0, declaration);
87
+ if (this.extensions !== null){
88
+ for (let extension of this.extensions){
89
+ elements = elements.concat(this.htmlArticleTopicsElements(document, extension.extensionName + " Extensions", extension.topics));
90
+ }
91
+ }
64
92
  return elements;
65
93
  },
66
94
 
67
95
  declarationCode: function(){
68
- if (this.parent && this.parent.kind == 'class' || this.parent.kind == 'protocol'){
69
- return ["%s.%s = { ... }".sprintf(this.parent.name, this.name)];
96
+ if (this.parent){
97
+ if (this.parent.kind == 'class' || this.parent.kind == 'protocol'){
98
+ return ["%s.%s = { ... }".sprintf(this.parent.name, this.name)];
99
+ }
100
+ if (this.parent.kind === "extension"){
101
+ return ["%s.%s = { ... }".sprintf(this.parent.extends, this.name)];
102
+ }
70
103
  }
71
104
  return ["%s = { ... }".sprintf(this.name)];
72
105
  },