ixbrl-viewer 1.4.1__py3-none-any.whl → 1.4.86__py3-none-any.whl

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 (190) hide show
  1. iXBRLViewerPlugin/__init__.py +231 -127
  2. iXBRLViewerPlugin/_version.py +33 -3
  3. iXBRLViewerPlugin/constants.py +96 -2
  4. iXBRLViewerPlugin/featureConfig.py +8 -1
  5. iXBRLViewerPlugin/iXBRLViewer.py +356 -214
  6. iXBRLViewerPlugin/plugin.py +12 -0
  7. iXBRLViewerPlugin/ui.py +81 -50
  8. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
  9. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt +12 -5
  10. iXBRLViewerPlugin/viewer/i18next-parser.config.js +1 -1
  11. iXBRLViewerPlugin/viewer/src/data/utr.json +1244 -0
  12. iXBRLViewerPlugin/viewer/src/html/fact-details.html +69 -38
  13. iXBRLViewerPlugin/viewer/src/html/footer-logo.html +4 -0
  14. iXBRLViewerPlugin/viewer/src/html/footnote-details.html +2 -2
  15. iXBRLViewerPlugin/viewer/src/html/inspector.html +352 -197
  16. iXBRLViewerPlugin/viewer/src/i18n/cy/balancetypes.json +1 -0
  17. iXBRLViewerPlugin/viewer/src/i18n/cy/currencies.json +13 -0
  18. iXBRLViewerPlugin/viewer/src/i18n/cy/datatypes.json +9 -0
  19. iXBRLViewerPlugin/viewer/src/i18n/cy/labelroles.json +24 -0
  20. iXBRLViewerPlugin/viewer/src/i18n/cy/referenceparts.json +10 -0
  21. iXBRLViewerPlugin/viewer/src/i18n/cy/scale.json +16 -0
  22. iXBRLViewerPlugin/viewer/src/i18n/cy/tooltips.json +17 -0
  23. iXBRLViewerPlugin/viewer/src/i18n/cy/translation.json +179 -0
  24. iXBRLViewerPlugin/viewer/src/i18n/da/balancetypes.json +4 -0
  25. iXBRLViewerPlugin/viewer/src/i18n/da/currencies.json +13 -0
  26. iXBRLViewerPlugin/viewer/src/i18n/da/datatypes.json +9 -0
  27. iXBRLViewerPlugin/viewer/src/i18n/da/labelroles.json +24 -0
  28. iXBRLViewerPlugin/viewer/src/i18n/da/referenceparts.json +10 -0
  29. iXBRLViewerPlugin/viewer/src/i18n/da/scale.json +15 -0
  30. iXBRLViewerPlugin/viewer/src/i18n/da/tooltips.json +17 -0
  31. iXBRLViewerPlugin/viewer/src/i18n/da/translation.json +179 -0
  32. iXBRLViewerPlugin/viewer/src/i18n/de/balancetypes.json +4 -0
  33. iXBRLViewerPlugin/viewer/src/i18n/de/currencies.json +13 -0
  34. iXBRLViewerPlugin/viewer/src/i18n/de/datatypes.json +9 -0
  35. iXBRLViewerPlugin/viewer/src/i18n/de/labelroles.json +24 -0
  36. iXBRLViewerPlugin/viewer/src/i18n/de/referenceparts.json +10 -0
  37. iXBRLViewerPlugin/viewer/src/i18n/de/scale.json +15 -0
  38. iXBRLViewerPlugin/viewer/src/i18n/de/tooltips.json +17 -0
  39. iXBRLViewerPlugin/viewer/src/i18n/de/translation.json +179 -0
  40. iXBRLViewerPlugin/viewer/src/i18n/en/balancetypes.json +4 -0
  41. iXBRLViewerPlugin/viewer/src/i18n/en/datatypes.json +10 -0
  42. iXBRLViewerPlugin/viewer/src/i18n/en/labelroles.json +4 -0
  43. iXBRLViewerPlugin/viewer/src/i18n/en/scale.json +16 -0
  44. iXBRLViewerPlugin/viewer/src/i18n/en/tooltips.json +17 -0
  45. iXBRLViewerPlugin/viewer/src/i18n/en/translation.json +73 -23
  46. iXBRLViewerPlugin/viewer/src/i18n/es/balancetypes.json +4 -0
  47. iXBRLViewerPlugin/viewer/src/i18n/es/datatypes.json +10 -0
  48. iXBRLViewerPlugin/viewer/src/i18n/es/labelroles.json +24 -0
  49. iXBRLViewerPlugin/viewer/src/i18n/es/scale.json +16 -0
  50. iXBRLViewerPlugin/viewer/src/i18n/es/tooltips.json +17 -0
  51. iXBRLViewerPlugin/viewer/src/i18n/es/translation.json +87 -37
  52. iXBRLViewerPlugin/viewer/src/i18n/fr/balancetypes.json +4 -0
  53. iXBRLViewerPlugin/viewer/src/i18n/fr/currencies.json +13 -0
  54. iXBRLViewerPlugin/viewer/src/i18n/fr/datatypes.json +9 -0
  55. iXBRLViewerPlugin/viewer/src/i18n/fr/labelroles.json +24 -0
  56. iXBRLViewerPlugin/viewer/src/i18n/fr/referenceparts.json +10 -0
  57. iXBRLViewerPlugin/viewer/src/i18n/fr/scale.json +15 -0
  58. iXBRLViewerPlugin/viewer/src/i18n/fr/tooltips.json +17 -0
  59. iXBRLViewerPlugin/viewer/src/i18n/fr/translation.json +179 -0
  60. iXBRLViewerPlugin/viewer/src/i18n/nl/balancetypes.json +4 -0
  61. iXBRLViewerPlugin/viewer/src/i18n/nl/currencies.json +13 -0
  62. iXBRLViewerPlugin/viewer/src/i18n/nl/datatypes.json +9 -0
  63. iXBRLViewerPlugin/viewer/src/i18n/nl/labelroles.json +24 -0
  64. iXBRLViewerPlugin/viewer/src/i18n/nl/referenceparts.json +10 -0
  65. iXBRLViewerPlugin/viewer/src/i18n/nl/scale.json +15 -0
  66. iXBRLViewerPlugin/viewer/src/i18n/nl/tooltips.json +17 -0
  67. iXBRLViewerPlugin/viewer/src/i18n/nl/translation.json +179 -0
  68. iXBRLViewerPlugin/viewer/src/i18n/uk/balancetypes.json +4 -0
  69. iXBRLViewerPlugin/viewer/src/i18n/uk/currencies.json +13 -0
  70. iXBRLViewerPlugin/viewer/src/i18n/uk/datatypes.json +9 -0
  71. iXBRLViewerPlugin/viewer/src/i18n/uk/labelroles.json +24 -0
  72. iXBRLViewerPlugin/viewer/src/i18n/uk/referenceparts.json +10 -0
  73. iXBRLViewerPlugin/viewer/src/i18n/uk/scale.json +15 -0
  74. iXBRLViewerPlugin/viewer/src/i18n/uk/tooltips.json +17 -0
  75. iXBRLViewerPlugin/viewer/src/i18n/uk/translation.json +179 -0
  76. iXBRLViewerPlugin/viewer/src/icons/calculator.svg +13 -0
  77. iXBRLViewerPlugin/viewer/src/icons/circle-cross.svg +11 -0
  78. iXBRLViewerPlugin/viewer/src/icons/circle-tick.svg +11 -0
  79. iXBRLViewerPlugin/viewer/src/icons/dark-mode.svg +4 -0
  80. iXBRLViewerPlugin/viewer/src/icons/dimension.svg +1 -5
  81. iXBRLViewerPlugin/viewer/src/icons/member.svg +2 -5
  82. iXBRLViewerPlugin/viewer/src/icons/multi-tag.svg +10 -0
  83. iXBRLViewerPlugin/viewer/src/img/arelle-dark.svg +179 -0
  84. iXBRLViewerPlugin/viewer/src/img/inline-viewer-dark.svg +59 -0
  85. iXBRLViewerPlugin/viewer/src/js/accordian.js +5 -4
  86. iXBRLViewerPlugin/viewer/src/js/aspect.js +29 -10
  87. iXBRLViewerPlugin/viewer/src/js/aspect.test.js +40 -31
  88. iXBRLViewerPlugin/viewer/src/js/balance.js +14 -0
  89. iXBRLViewerPlugin/viewer/src/js/calculation.js +213 -0
  90. iXBRLViewerPlugin/viewer/src/js/calculation.test.js +306 -0
  91. iXBRLViewerPlugin/viewer/src/js/calculationInspector.js +187 -0
  92. iXBRLViewerPlugin/viewer/src/js/chart.js +26 -24
  93. iXBRLViewerPlugin/viewer/src/js/chart.test.js +10 -9
  94. iXBRLViewerPlugin/viewer/src/js/concept.js +37 -4
  95. iXBRLViewerPlugin/viewer/src/js/concept.test.js +30 -6
  96. iXBRLViewerPlugin/viewer/src/js/datatype.js +20 -0
  97. iXBRLViewerPlugin/viewer/src/js/datatype.test.js +62 -0
  98. iXBRLViewerPlugin/viewer/src/js/dialog.js +6 -4
  99. iXBRLViewerPlugin/viewer/src/js/docOrderIndex.js +7 -7
  100. iXBRLViewerPlugin/viewer/src/js/fact.js +156 -59
  101. iXBRLViewerPlugin/viewer/src/js/fact.test.js +160 -29
  102. iXBRLViewerPlugin/viewer/src/js/factset.js +64 -15
  103. iXBRLViewerPlugin/viewer/src/js/factset.test.js +102 -31
  104. iXBRLViewerPlugin/viewer/src/js/footnote.js +8 -2
  105. iXBRLViewerPlugin/viewer/src/js/index.js +11 -3
  106. iXBRLViewerPlugin/viewer/src/js/inspector.js +747 -221
  107. iXBRLViewerPlugin/viewer/src/js/inspector.test.js +143 -25
  108. iXBRLViewerPlugin/viewer/src/js/interval.js +70 -0
  109. iXBRLViewerPlugin/viewer/src/js/interval.test.js +153 -0
  110. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +391 -262
  111. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js +134 -20
  112. iXBRLViewerPlugin/viewer/src/js/ixnode.js +1 -1
  113. iXBRLViewerPlugin/viewer/src/js/menu.js +25 -7
  114. iXBRLViewerPlugin/viewer/src/js/number-matcher.js +7 -3
  115. iXBRLViewerPlugin/viewer/src/js/number-matcher.test.js +4 -0
  116. iXBRLViewerPlugin/viewer/src/js/outline.js +34 -13
  117. iXBRLViewerPlugin/viewer/src/js/outline.test.js +97 -91
  118. iXBRLViewerPlugin/viewer/src/js/period.js +0 -1
  119. iXBRLViewerPlugin/viewer/src/js/report.js +260 -351
  120. iXBRLViewerPlugin/viewer/src/js/report.test.js +95 -27
  121. iXBRLViewerPlugin/viewer/src/js/reportset.js +264 -0
  122. iXBRLViewerPlugin/viewer/src/js/reportset.test.js +357 -0
  123. iXBRLViewerPlugin/viewer/src/js/search.js +72 -38
  124. iXBRLViewerPlugin/viewer/src/js/search.test.js +184 -84
  125. iXBRLViewerPlugin/viewer/src/js/summary.js +34 -8
  126. iXBRLViewerPlugin/viewer/src/js/summary.test.js +69 -25
  127. iXBRLViewerPlugin/viewer/src/js/tableExport.js +9 -9
  128. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.js +34 -0
  129. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.test.js +32 -0
  130. iXBRLViewerPlugin/viewer/src/js/test-utils.js +46 -0
  131. iXBRLViewerPlugin/viewer/src/js/theme.js +50 -0
  132. iXBRLViewerPlugin/viewer/src/js/unit.js +90 -32
  133. iXBRLViewerPlugin/viewer/src/js/unit.test.js +62 -25
  134. iXBRLViewerPlugin/viewer/src/js/util.js +94 -0
  135. iXBRLViewerPlugin/viewer/src/js/util.test.js +33 -1
  136. iXBRLViewerPlugin/viewer/src/js/utr.js +27 -0
  137. iXBRLViewerPlugin/viewer/src/js/viewer.js +205 -181
  138. iXBRLViewerPlugin/viewer/src/js/viewerOptions.js +0 -2
  139. iXBRLViewerPlugin/viewer/src/less/accordian.less +10 -6
  140. iXBRLViewerPlugin/viewer/src/less/block-list.less +16 -5
  141. iXBRLViewerPlugin/viewer/src/less/calculation-inspector.less +83 -0
  142. iXBRLViewerPlugin/viewer/src/less/chart.less +8 -5
  143. iXBRLViewerPlugin/viewer/src/less/colours-dark-mode.less +40 -0
  144. iXBRLViewerPlugin/viewer/src/less/colours.less +32 -20
  145. iXBRLViewerPlugin/viewer/src/less/common.less +3 -3
  146. iXBRLViewerPlugin/viewer/src/less/components.less +6 -4
  147. iXBRLViewerPlugin/viewer/src/less/core.less +2 -0
  148. iXBRLViewerPlugin/viewer/src/less/dialog.less +21 -14
  149. iXBRLViewerPlugin/viewer/src/less/form-controls.less +33 -11
  150. iXBRLViewerPlugin/viewer/src/less/inspector.less +1045 -726
  151. iXBRLViewerPlugin/viewer/src/less/loader.less +2 -2
  152. iXBRLViewerPlugin/viewer/src/less/menu.less +33 -15
  153. iXBRLViewerPlugin/viewer/src/less/summary.less +16 -6
  154. iXBRLViewerPlugin/viewer/src/less/tabs.less +9 -9
  155. iXBRLViewerPlugin/viewer/src/less/text-block-viewer.less +2 -0
  156. iXBRLViewerPlugin/viewer/src/less/text-mixins.less +2 -1
  157. iXBRLViewerPlugin/viewer/src/less/validation-report.less +2 -3
  158. iXBRLViewerPlugin/viewer/src/less/viewer.less +105 -74
  159. iXBRLViewerPlugin/viewer/webpack.common.js +19 -9
  160. iXBRLViewerPlugin/xhtmlserialize.py +59 -45
  161. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/METADATA +181 -50
  162. ixbrl_viewer-1.4.86.dist-info/RECORD +217 -0
  163. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/WHEEL +1 -1
  164. ixbrl_viewer-1.4.1.dist-info/LICENSE → ixbrl_viewer-1.4.86.dist-info/licenses/LICENSE.md +8 -14
  165. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/top_level.txt +0 -1
  166. iXBRLViewerPlugin/viewer/src/js/calculations.js +0 -111
  167. iXBRLViewerPlugin/viewer/src/js/interact.min.js +0 -6
  168. ixbrl_viewer-1.4.1.dist-info/RECORD +0 -155
  169. tests/__init__.py +0 -0
  170. tests/puppeteer/framework/core_elements.js +0 -117
  171. tests/puppeteer/framework/page_objects/doc_frame.js +0 -105
  172. tests/puppeteer/framework/page_objects/fact_details_panel.js +0 -80
  173. tests/puppeteer/framework/page_objects/search_panel.js +0 -76
  174. tests/puppeteer/framework/page_objects/toolbar.js +0 -18
  175. tests/puppeteer/framework/utils.js +0 -3
  176. tests/puppeteer/framework/viewer_page.js +0 -103
  177. tests/puppeteer/puppeteer_test_run_via_intellij.jpg +0 -0
  178. tests/puppeteer/test_filings/filing_documents_smoke_test.zip +0 -0
  179. tests/puppeteer/test_filings/highlights.zip +0 -0
  180. tests/puppeteer/tests/fact_properties.test.js +0 -78
  181. tests/puppeteer/tests/highlight.test.js +0 -186
  182. tests/puppeteer/tests/search.test.js +0 -86
  183. tests/puppeteer/tools/generate.sh +0 -15
  184. tests/unit_tests/__init__.py +0 -0
  185. tests/unit_tests/iXBRLViewerPlugin/__init__.py +0 -0
  186. tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py +0 -39
  187. tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +0 -641
  188. tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py +0 -310
  189. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/entry_points.txt +0 -0
  190. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info/licenses}/NOTICE +0 -0
@@ -1,419 +1,328 @@
1
1
  // See COPYRIGHT.md for copyright information
2
2
 
3
- import { Fact } from "./fact.js"
4
- import { Footnote } from "./footnote.js"
5
- import { QName } from "./qname.js"
6
3
  import { Concept } from "./concept.js";
7
- import { Unit } from "./unit";
8
- import { ViewerOptions } from "./viewerOptions.js";
9
- import { setDefault, titleCase } from "./util.js";
10
- import $ from 'jquery'
4
+ import { setDefault } from "./util.js";
11
5
  import i18next from "i18next";
12
6
 
13
- export function iXBRLReport (data) {
14
- this.data = data;
15
- // A map of IDs to Fact and Footnote objects
16
- this._items = {};
17
- this._ixNodeMap = {};
18
- this._viewerOptions = new ViewerOptions();
19
- this._reverseRelationshipCache = {};
20
- }
7
+ // Class to represent the XBRL data from a single target document in a single
8
+ // Inline XBRL Document or Document Set.
21
9
 
22
- /*
23
- * Set additional information about facts obtained from parsing the iXBRL.
24
- */
25
- iXBRLReport.prototype.setIXNodeMap = function(ixData) {
26
- this._ixNodeMap = ixData;
27
- this._initialize();
28
- }
10
+ export class XBRLReport {
29
11
 
30
- iXBRLReport.prototype._initialize = function () {
12
+ constructor(reportSet, reportData) {
13
+ this.reportSet = reportSet;
14
+ this._reportData = reportData;
15
+ // A map of IDs to Fact and Footnote objects
16
+ this._reverseRelationshipCache = {};
17
+ }
31
18
 
32
- // Build an array of footnotes IDs in document order so that we can assign
33
- // numbers to foonotes
34
- var fnorder = Object.keys(this._ixNodeMap).filter((id) => this._ixNodeMap[id].footnote);
35
- fnorder.sort((a,b) => this._ixNodeMap[a].docOrderindex - this._ixNodeMap[b].docOrderindex);
19
+ availableLanguages() {
20
+ if (!this._availableLanguages) {
21
+ this._availableLanguages = new Set()
22
+ for (const c of Object.values(this._reportData.concepts)) {
23
+ for (const ll of Object.values(c.labels)) {
24
+ for (const lang of Object.keys(ll)) {
25
+ this._availableLanguages.add(lang);
26
+ }
27
+ }
28
+ }
29
+ }
30
+ return this._availableLanguages;
31
+ }
36
32
 
37
- // Create Fact objects for all facts.
38
- for (const id in this.data.facts) {
39
- this._items[id] = new Fact(this, id);
33
+ facts() {
34
+ return this.reportSet.factsForReport(this);
40
35
  }
41
36
 
42
- // Now resolve footnote references, creating footnote objects for "normal"
43
- // footnotes, and finding Fact objects for fact->fact footnotes.
44
- //
45
- // Associate source facts with target footnote/facts to allow two way
46
- // navigation.
47
- for (const id in this.data.facts) {
48
- const f = this._items[id];
49
- const fns = this.data.facts[id].fn || [];
50
- fns.forEach((fnid) => {
51
- var fn = this._items[fnid];
52
- if (fn === undefined) {
53
- fn = new Footnote(this, fnid, "Footnote " + (fnorder.indexOf(fnid) + 1));
54
- this._items[fnid] = fn;
55
- }
56
- // Associate fact with footnote
57
- fn.addLinkedFact(f);
58
- });
37
+ targetDocument() {
38
+ return this._reportData.target ?? null;
59
39
  }
60
- }
61
40
 
62
- iXBRLReport.prototype.isCalculationContributor = function(c) {
63
- if (this._calculationContributors === undefined) {
64
- if (this.data.rels?.calc) {
65
- this._calculationContributors = new Set(Object.values(this.data.rels.calc).flatMap(calculations => {
66
- return Object.values(calculations).flatMap(contributors => {
67
- return contributors.map(c => c.t);
68
- });
69
- }));
70
- } else {
71
- this._calculationContributors = new Set();
41
+ getChildRelationships(conceptName, arcrole) {
42
+ const rels = {}
43
+ const elrs = this._reportData.rels[arcrole] || {};
44
+ for (const elr in elrs) {
45
+ if (conceptName in elrs[elr]) {
46
+ rels[elr] = elrs[elr][conceptName];
47
+ }
72
48
  }
49
+ return rels;
73
50
  }
74
- return this._calculationContributors.has(c);
75
- }
76
51
 
77
- iXBRLReport.prototype.isCalculationSummation = function(c) {
78
- if (this._calculationSummations === undefined) {
79
- if (this.data.rels?.calc) {
80
- this._calculationSummations = new Set(Object.values(this.data.rels.calc).flatMap(calculations => {
81
- return Object.keys(calculations);
82
- }));
83
- } else {
84
- this._calculationSummations = new Set();
52
+ /*
53
+ * Build and cache an inverse map of relationships for a given arcrole for
54
+ * efficient lookup of parents concept from a child.
55
+ *
56
+ * Map is arcrole => elr => target => [ rel, ... ]
57
+ *
58
+ * "rel" is modified to have a "src" property with the source concept.
59
+ */
60
+ _reverseRelationships(arcrole) {
61
+ if (!(arcrole in this._reverseRelationshipCache)) {
62
+ const rrc = {};
63
+ const elrs = this._reportData.rels[arcrole] || {};
64
+ for (const [elr, relSet] of Object.entries(elrs)) {
65
+ for (const [src, rels] of Object.entries(relSet)) {
66
+ for (const r of rels) {
67
+ r.src = src;
68
+ setDefault(setDefault(rrc, elr, {}), r.t, []).push(r);
69
+ }
70
+ }
71
+ }
72
+ this._reverseRelationshipCache[arcrole] = rrc;
85
73
  }
74
+ return this._reverseRelationshipCache[arcrole];
86
75
  }
87
- return this._calculationSummations.has(c);
88
- }
89
76
 
90
- iXBRLReport.prototype.getLabel = function(c, rolePrefix, showPrefix) {
91
- rolePrefix = rolePrefix || 'std';
92
- var lang = this._viewerOptions.language;
93
- const concept = this.data.concepts[c];
94
- if (concept === undefined) {
95
- console.log("Attempt to get label for undefined concept: " + c);
96
- return "<no label>";
97
- }
98
- const labels = concept.labels[rolePrefix]
99
- if (labels === undefined || Object.keys(labels).length == 0) {
100
- return undefined;
101
- }
102
- else {
103
- var label;
104
- if (lang && labels[lang]) {
105
- label = labels[lang];
106
- }
107
- else {
108
- // Fall back on English, then any label deterministically.
109
- label = labels["en"] || labels["en-us"] || labels[Object.keys(labels).sort()[0]];
110
- }
111
- if (label === undefined) {
112
- return undefined;
113
- }
114
- var s = '';
115
- if (showPrefix && this._viewerOptions.showPrefixes) {
116
- s = "(" + this.qname(c).prefix + ") ";
77
+ getParentRelationships(conceptName, arcrole) {
78
+ const rels = {}
79
+ for (const [elr, relSet] of Object.entries(this._reverseRelationships(arcrole))) {
80
+ if (conceptName in relSet) {
81
+ rels[elr] = relSet[conceptName];
82
+ }
117
83
  }
118
- s += label;
119
- return s;
84
+ return rels;
120
85
  }
121
- }
122
86
 
123
- iXBRLReport.prototype.getLabelOrName = function(c, rolePrefix, showPrefix) {
124
- const label = this.getLabel(c, rolePrefix, showPrefix);
125
- if (label === undefined) {
126
- return c;
87
+ getParentRelationshipsInGroup(conceptName, arcrole, elr) {
88
+ const relSet = this._reverseRelationships(arcrole)[elr] || {};
89
+ return relSet[conceptName] || [];
127
90
  }
128
- return label;
129
- }
130
-
131
- iXBRLReport.prototype.availableLanguages = function() {
132
- if (!this._availableLanguages) {
133
- var map = {};
134
- $.each(this.data.concepts, function (k,v) {
135
- $.each(v.labels, function (rolePrefx, ll) {
136
- $.each(ll, function (lang, v) {
137
- map[lang] = 1;
138
- });
139
- });
140
- });
141
- this._availableLanguages = Object.keys(map);
142
91
 
92
+ dimensionDefault(dimensionName) {
93
+ // ELR is irrelevant for dimension-default relationships, so check all of
94
+ // them, and return the first (illegal for there to be more than one
95
+ for (const rel of Object.values(this._reportData.rels["d-d"] || {})) {
96
+ if (dimensionName in rel) {
97
+ return rel[dimensionName][0].t;
98
+ }
99
+ }
100
+ return undefined;
143
101
  }
144
- return this._availableLanguages;
145
- }
146
-
147
- iXBRLReport.prototype.languageNames = function() {
148
- return this.data.languages;
149
- }
150
-
151
- iXBRLReport.prototype.getItemById = function(id) {
152
- return this._items[id];
153
- }
154
-
155
- iXBRLReport.prototype.getIXNodeForItemId = function(id) {
156
- return this._ixNodeMap[id] || {};
157
- }
158
-
159
- iXBRLReport.prototype.facts = function() {
160
- return Object.keys(this.data.facts).map(id => this.getItemById(id));
161
- }
162
-
163
- iXBRLReport.prototype.filingDocuments = function() {
164
- return this.data.filingDocuments;
165
- }
166
-
167
- iXBRLReport.prototype.prefixMap = function() {
168
- return this.data.prefixes;
169
- }
170
102
 
171
- iXBRLReport.prototype.getUsedPrefixes = function() {
172
- if (this._usedPrefixes === undefined) {
173
- this._usedPrefixes = new Set(Object.values(this._items)
174
- .filter(f => f instanceof Fact)
175
- .map(f => f.getConceptPrefix()));
103
+ relationshipGroups(arcrole) {
104
+ return Object.keys(this._reportData.rels[arcrole] || {});
176
105
  }
177
- return this._usedPrefixes;
178
- }
179
106
 
180
- /**
181
- * Returns a set of OIM format unit strings used by facts on this report. Lazy-loaded.
182
- * @return {Set[String]} Set of OIM format unit strings
183
- */
184
- iXBRLReport.prototype.getUsedUnits = function() {
185
- if (this._usedUnits === undefined) {
186
- this._usedUnits = new Set(Object.values(this._items)
187
- .filter(f => f instanceof Fact)
188
- .map(f => f.unit()?.value())
189
- .filter(f => f)
190
- .sort());
107
+ relationshipGroupRoots(arcrole, elr) {
108
+ const roots = [];
109
+ for (const conceptName in this._reportData.rels[arcrole][elr]) {
110
+ if (!(elr in this.getParentRelationships(conceptName, arcrole))) {
111
+ roots.push(conceptName);
112
+ }
113
+ }
114
+ return roots;
191
115
  }
192
- return this._usedUnits;
193
- }
194
116
 
195
- /**
196
- * Returns details about the provided unit. Lazy-loaded once per unit.
197
- * @param {String} unitKey Unit in OIM format
198
- * @return {Unit} Unit instance corresponding with provided key
199
- */
200
- iXBRLReport.prototype.getUnit = function(unitKey) {
201
- if (this._unitsMap === undefined) {
202
- this._unitsMap = {};
203
- }
204
- if (this._unitsMap[unitKey] === undefined) {
205
- this._unitsMap[unitKey] = new Unit(this, unitKey)
117
+ getAlignedFacts(f, coveredAspects) {
118
+ // XXX should filter to current report facts?
119
+ const all = this.reportSet.facts();
120
+ const aligned = [];
121
+ if (!coveredAspects) {
122
+ coveredAspects = {};
123
+ }
124
+ for (const ff of all) {
125
+ if (ff.isAligned(f, coveredAspects)) {
126
+ aligned.push(ff);
127
+ }
128
+ }
129
+ return aligned;
206
130
  }
207
- return this._unitsMap[unitKey];
208
- }
209
131
 
210
- iXBRLReport.prototype.getUsedScalesMap = function() {
211
- // Do not lazy load. This is language-dependent so needs to re-evaluate after language changes.
212
- const usedScalesMap = {};
213
- Object.values(this._items)
214
- .filter(f => f instanceof Fact)
215
- .forEach(fact => {
216
- const scale = fact.scale();
217
- if (scale !== null && scale !== undefined) {
218
- if (!(scale in usedScalesMap)) {
219
- usedScalesMap[scale] = new Set();
220
- }
221
- const labels = usedScalesMap[scale];
222
- const label = titleCase(fact.getScaleLabel(scale));
223
- if (label && !labels.has(label)) {
224
- labels.add(label);
132
+ deduplicate(facts) {
133
+ const ff = [];
134
+ for (const f of facts) {
135
+ let dupe = false;
136
+ for (const other of ff) {
137
+ if (other.isAligned(f,{})) {
138
+ dupe = true;
225
139
  }
226
140
  }
227
- });
228
- return usedScalesMap;
229
- }
230
-
231
- iXBRLReport.prototype.roleMap = function() {
232
- return this.data.roles;
233
- }
234
-
235
- iXBRLReport.prototype.qname = function(v) {
236
- return new QName(this.prefixMap(), v);
237
- }
238
-
239
- iXBRLReport.prototype.getChildRelationships = function(conceptName, arcrole) {
240
- var rels = {}
241
- const elrs = this.data.rels[arcrole] || {};
242
- for (const elr in elrs) {
243
- if (conceptName in elrs[elr]) {
244
- rels[elr] = elrs[elr][conceptName];
141
+ if (!dupe) {
142
+ ff.push(f);
143
+ }
245
144
  }
145
+ return ff;
246
146
  }
247
- return rels;
248
- }
249
147
 
250
- /*
251
- * Build and cache an inverse map of relationships for a given arcrole for
252
- * efficient lookup of parents concept from a child.
253
- *
254
- * Map is arcrole => elr => target => [ rel, ... ]
255
- *
256
- * "rel" is modified to have a "src" property with the source concept.
257
- */
258
- iXBRLReport.prototype._reverseRelationships = function(arcrole) {
259
- if (!(arcrole in this._reverseRelationshipCache)) {
260
- const rrc = {};
261
- const elrs = this.data.rels[arcrole] || {};
262
- for (const [elr, relSet] of Object.entries(elrs)) {
263
- for (const [src, rels] of Object.entries(relSet)) {
264
- for (const r of rels) {
265
- r.src = src;
266
- setDefault(setDefault(rrc, elr, {}), r.t, []).push(r);
267
- }
148
+ getConcept(name) {
149
+ return new Concept(this, name);
150
+ }
151
+
152
+ getRoleLabel(rolePrefix) {
153
+ /* This is currently hard-coded to "en" as the generator does not yet
154
+ * support generic labels, and instead provides the (non-localisable) role
155
+ * definition as a single "en" label.
156
+ *
157
+ * Returns the ELR URI if there is no label
158
+ */
159
+ const labels = this._reportData.roleDefs[rolePrefix];
160
+ if (labels !== undefined) {
161
+ const label = labels["en"];
162
+ // Earlier versions of the generator added a "null" label if no labels
163
+ // were available.
164
+ if (label !== undefined && label !== null) {
165
+ return label;
268
166
  }
269
167
  }
270
- this._reverseRelationshipCache[arcrole] = rrc;
168
+ return undefined;
271
169
  }
272
- return this._reverseRelationshipCache[arcrole];
273
- }
274
170
 
275
- iXBRLReport.prototype.getParentRelationships = function(conceptName, arcrole) {
276
- var rels = {}
277
- for (const [elr, relSet] of Object.entries(this._reverseRelationships(arcrole))) {
278
- if (conceptName in relSet) {
279
- rels[elr] = relSet[conceptName];
280
- }
171
+ getRoleLabelOrURI(rolePrefix) {
172
+ return this.getRoleLabel(rolePrefix) ?? this.reportSet.roleMap()[rolePrefix];
281
173
  }
282
- return rels;
283
- }
284
174
 
285
- iXBRLReport.prototype.getParentRelationshipsInGroup = function(conceptName, arcrole, elr) {
286
- var rels = {}
287
- const relSet = this._reverseRelationships(arcrole)[elr] || {};
288
- return relSet[conceptName] || [];
289
- }
175
+ getLabelRoleLabel(rolePrefix) {
176
+ const roleURI = this.reportSet.roleMap()[rolePrefix];
177
+ if (roleURI === undefined) {
178
+ return undefined;
179
+ }
290
180
 
291
- iXBRLReport.prototype.dimensionDefault = function(dimensionName) {
292
- // ELR is irrelevant for dimension-default relationships, so check all of
293
- // them, and return the first (illegal for there to be more than one
294
- for (const rel of Object.values(this.data.rels["d-d"] || {})) {
295
- if (dimensionName in rel) {
296
- return rel[dimensionName][0].t;
181
+ // Built-in label roles don't have a definition in the taxonomy. Do an
182
+ // i18n look-up on the last part of the URI. For "en" the camel-case
183
+ // splitter will do what we want for everything except standard label
184
+ // and documentation label
185
+ const suffix = roleURI.split("/").pop();
186
+ if (roleURI.startsWith("http://www.xbrl.org/2003/role/") && i18next.exists(`labelRoles:${suffix}`)) {
187
+ return i18next.t(`labelRoles:${suffix}`);
297
188
  }
298
- }
299
- return undefined;
300
- }
301
189
 
302
- iXBRLReport.prototype.relationshipGroups = function(arcrole) {
303
- return Object.keys(this.data.rels[arcrole] || {});
304
- }
190
+ // Attempt to get a label from the role definition
191
+ const label = this.getRoleLabel(rolePrefix);
192
+ if (label !== undefined) {
193
+ return label;
194
+ }
195
+
196
+ // Fall back on de-camel-casing the last part of the URI
197
+ return suffix
198
+ .replaceAll(/([A-Z][a-z]+)/g, ' $1')
199
+ .trim()
200
+ .replace(/^./, s => s.toUpperCase());
201
+ }
305
202
 
306
- iXBRLReport.prototype.relationshipGroupRoots = function(arcrole, elr) {
307
- var roots = [];
308
- for (const conceptName in this.data.rels[arcrole][elr]) {
309
- if (!(elr in this.getParentRelationships(conceptName, arcrole))) {
310
- roots.push(conceptName);
203
+ localDocuments() {
204
+ if (this._reportData.localDocs === undefined) {
205
+ return {}
311
206
  }
207
+ return this._reportData.localDocs;
312
208
  }
313
- return roots;
314
- }
315
209
 
316
- iXBRLReport.prototype.getAlignedFacts = function(f, coveredAspects) {
317
- var all = this.facts();
318
- var aligned = [];
319
- if (!coveredAspects) {
320
- coveredAspects = {};
210
+ qname(v) {
211
+ return this.reportSet.qname(v);
321
212
  }
322
- $.each(all, function (i, ff) {
323
- if (ff.isAligned(f, coveredAspects)) {
324
- aligned.push(ff);
325
- }
326
- });
327
- return aligned;
328
- }
329
213
 
330
- iXBRLReport.prototype.deduplicate = function (facts) {
331
- var ff = [];
332
- $.each(facts, function (i, f) {
333
- var dupe = false;
334
- $.each(ff, function (j, of) {
335
- if (of.isAligned(f,{})) {
336
- dupe = true;
214
+ getScaleLabel(scale, unit) {
215
+ let label = i18next.t(`scale:${scale}`, {defaultValue:"noName"});
216
+ if (unit && unit.isMonetary() && scale === -2) {
217
+ let measure = unit.value() ?? '';
218
+ if (measure) {
219
+ measure = this.qname(measure).localname;
337
220
  }
338
- });
339
- if (!dupe){
340
- ff.push(f);
221
+ label = i18next.t(`currencies:cents${measure}`, {defaultValue: label});
341
222
  }
342
- });
343
- return ff;
344
- }
345
-
346
- iXBRLReport.prototype.setViewerOptions = function (vo) {
347
- this._viewerOptions = vo;
348
- }
223
+ if (label === "noName") {
224
+ return null;
225
+ }
226
+ return label;
227
+ }
349
228
 
350
- iXBRLReport.prototype.namespaceGroups = function () {
351
- var counts = {};
352
- $.each(this.facts(), function (i, f) {
353
- counts[f.conceptQName().prefix] = counts[f.conceptQName().prefix] || 0;
354
- counts[f.conceptQName().prefix]++;
355
- });
356
- var prefixes = Object.keys(counts);
357
- prefixes.sort(function (a, b) { return counts[b] - counts[a] });
358
- return prefixes;
359
- }
229
+ concepts() {
230
+ return this._reportData.concepts;
231
+ }
360
232
 
361
- iXBRLReport.prototype.getConcept = function(name) {
362
- return new Concept(this, name);
363
- }
233
+ getLabel(c, rolePrefix, showPrefix) {
234
+ return this.getLabelAndLang(c, rolePrefix, showPrefix).label;
235
+ }
364
236
 
365
- iXBRLReport.prototype.getRoleLabel = function(rolePrefix, viewerOptions) {
366
- /* This is currently hard-coded to "en" as the generator does not yet
367
- * support generic labels, and instead provides the (non-localisable) role
368
- * definition as a single "en" label.
369
- *
370
- * Returns the ELR URI if there is no label
371
- */
372
- const labels = this.data.roleDefs[rolePrefix];
373
- if (labels !== undefined) {
374
- const label = labels["en"];
375
- // Earlier versions of the generator added a "null" label if no labels
376
- // were available.
377
- if (label !== undefined && label !== null) {
378
- return label;
237
+ getLabelAndLang(c, rolePrefix, showPrefix) {
238
+ rolePrefix = rolePrefix || 'std';
239
+ const lang = this.reportSet.viewerOptions.language;
240
+ const concept = this._reportData.concepts[c];
241
+ if (concept === undefined) {
242
+ console.log("Attempt to get label for undefined concept: " + c);
243
+ return { label: "<no label>" };
244
+ }
245
+ const labels = concept.labels[rolePrefix]
246
+ if (labels === undefined || Object.keys(labels).length == 0) {
247
+ return { label: undefined };
248
+ }
249
+ else {
250
+ let label;
251
+ let actualLang;
252
+ if (lang && labels[lang]) {
253
+ label = labels[lang];
254
+ actualLang = lang;
255
+ }
256
+ else {
257
+ // Fall back on English, then any label deterministically.
258
+ for (const l of ["en", "en-us", Object.keys(labels).sort()[0]]) {
259
+ if (labels[l] !== undefined) {
260
+ label = labels[l];
261
+ actualLang = l;
262
+ break;
263
+ }
264
+ }
265
+ }
266
+ if (label === undefined) {
267
+ return {label: undefined};
268
+ }
269
+ let s = '';
270
+ if (showPrefix && this.reportSet.viewerOptions.showPrefixes) {
271
+ s = "(" + this.reportSet.taxonomyNamer.fromQName(this.qname(c)).prefix + ") ";
272
+ }
273
+ s += label;
274
+ return { label: s, lang: actualLang };
379
275
  }
380
276
  }
381
- return this.roleMap()[rolePrefix];
382
- }
383
277
 
384
- iXBRLReport.prototype.localDocuments = function() {
385
- if (this.data.localDocs === undefined) {
386
- return {}
278
+ getLabelOrName(c, rolePrefix, showPrefix) {
279
+ const label = this.getLabel(c, rolePrefix, showPrefix);
280
+ if (label === undefined) {
281
+ return c;
282
+ }
283
+ return label;
387
284
  }
388
- return this.data.localDocs;
389
- }
390
285
 
391
- iXBRLReport.prototype.documentSetFiles = function() {
392
- if (this.data.docSetFiles === undefined) {
393
- return []
286
+ getLabelOrNameAndLang(c, rolePrefix, showPrefix) {
287
+ const labelLang = this.getLabelAndLang(c, rolePrefix, showPrefix);
288
+ if (labelLang.label === undefined) {
289
+ return { label: c };
290
+ }
291
+ return labelLang;
394
292
  }
395
- return this.data.docSetFiles;
396
- }
397
-
398
- iXBRLReport.prototype.isDocumentSet = function() {
399
- return this.documentSetFiles().length > 1;
400
- }
401
-
402
- iXBRLReport.prototype.usesAnchoring = function() {
403
- return this.data.rels["w-n"] !== undefined;
404
- }
405
293
 
406
- iXBRLReport.prototype.hasValidationErrors = function() {
407
- return this.data.validation !== undefined && this.data.validation.length > 0;
408
- }
294
+ isCalculationContributor(c) {
295
+ if (this._calculationContributors === undefined) {
296
+ if (this._reportData.rels?.calc) {
297
+ this._calculationContributors = new Set(Object.values(this._reportData.rels.calc).flatMap(calculations => {
298
+ return Object.values(calculations).flatMap(contributors => {
299
+ return contributors.map(c => c.t);
300
+ });
301
+ }));
302
+ } else {
303
+ this._calculationContributors = new Set();
304
+ }
305
+ }
306
+ return this._calculationContributors.has(c);
307
+ }
409
308
 
410
- iXBRLReport.prototype.getScaleLabel = function(scale, isMonetaryValue, currency=null) {
411
- var label = i18next.t(`scale.${scale}`, {defaultValue:"noName"});
412
- if (isMonetaryValue && scale === -2) {
413
- label = i18next.t(`currencies:cents${currency}`, {defaultValue: label});
309
+ isCalculationSummation(c) {
310
+ if (this._calculationSummations === undefined) {
311
+ if (this._reportData.rels?.calc) {
312
+ this._calculationSummations = new Set(Object.values(this._reportData.rels.calc).flatMap(calculations => {
313
+ return Object.keys(calculations);
314
+ }));
315
+ } else {
316
+ this._calculationSummations = new Set();
317
+ }
318
+ }
319
+ return this._calculationSummations.has(c);
414
320
  }
415
- if (label === "noName") {
416
- return null;
321
+
322
+ /**
323
+ * @return {Array[String]} Software credit text labels provided with this report for display purposes.
324
+ */
325
+ softwareCredits() {
326
+ return this._reportData.softwareCredits ?? [];
417
327
  }
418
- return label;
419
328
  }