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,7 +1,9 @@
1
1
  // See COPYRIGHT.md for copyright information
2
2
 
3
- import { iXBRLReport } from "./report.js";
3
+ import { ReportSet } from "./reportset.js";
4
4
  import { ViewerOptions } from "./viewerOptions.js";
5
+ import { TestInspector } from "./test-utils.js";
6
+ import { NAMESPACE_ISO4217 } from "./util";
5
7
 
6
8
  var testReportData = {
7
9
  "languages": {
@@ -10,13 +12,17 @@ var testReportData = {
10
12
  },
11
13
  "prefixes": {
12
14
  "eg": "http://www.example.com",
13
- "iso4217": "http://www.xbrl.org/2003/iso4217"
15
+ "iso4217": NAMESPACE_ISO4217
14
16
  },
15
17
  "roles": {
16
18
  "role1": "https://www.example.com/role1",
17
19
  "role2": "https://www.example.com/role2",
18
20
  "role3": "https://www.example.com/role3",
19
- "role4": "https://www.example.com/role4"
21
+ "role4": "https://www.example.com/role4MoreWords",
22
+ "std": "http://www.xbrl.org/2003/role/label",
23
+ "doc": "http://www.xbrl.org/2003/role/documentation",
24
+ "verbose": "http://www.xbrl.org/2003/role/verboseLabel",
25
+ "total": "http://www.xbrl.org/2003/role/totalLabel",
20
26
  },
21
27
  "roleDefs": {
22
28
  "role1": { "en": "Role 1 Label" },
@@ -61,68 +67,78 @@ var testReportData = {
61
67
  "p": "2018-01-01/2019-01-01",
62
68
  }
63
69
  }
64
- }
70
+ },
71
+
72
+ "softwareCredits": ["Example credit text A", "Example credit text B"],
65
73
  };
66
74
 
75
+ var insp = new TestInspector();
76
+ beforeAll(() => {
77
+ return insp.i18nInit();
78
+ });
67
79
 
68
80
  describe("Language options", () => {
69
- var testReport = new iXBRLReport(testReportData);
70
- testReport._initialize();
81
+ const testReportSet = new ReportSet(testReportData);
82
+ testReportSet._initialize();
71
83
  test("Available languages", () => {
72
- var al = testReport.availableLanguages();
84
+ const al = testReportSet.availableLanguages();
73
85
  expect(al).toHaveLength(6);
74
86
  expect(al).toEqual(expect.arrayContaining(["en", "en-us", "en-gb", "fr", "de", "es"]));
75
87
  });
76
-
77
- test("Names for available languages", () => {
78
- var ln = testReport.languageNames();
79
- expect(Object.keys(ln)).toHaveLength(2);
80
- expect(ln['en']).toBe("English");
81
- expect(ln['en-us']).toBe("English (US)");
82
- });
83
88
  });
84
89
 
85
90
  describe("Fetching facts", () => {
86
- var testReport = new iXBRLReport(testReportData);
87
- testReport._initialize();
91
+ const testReportSet = new ReportSet(testReportData);
92
+ testReportSet._initialize();
88
93
 
89
94
  test("Successful", () => {
90
- var f = testReport.getItemById("f1");
91
- testReport._initialize();
95
+ const f = testReportSet.getItemById("0-f1");
92
96
  expect(f).not.toBeNull();
93
97
  expect(f.decimals()).toEqual(-3);
94
98
  });
95
99
 
96
100
  test("Non-existent fact", () => {
97
- var f = testReport.getItemById("fact-does-not-exist");
101
+ const f = testReportSet.getItemById("fact-does-not-exist");
98
102
  expect(f).toBeUndefined();
99
103
  });
100
104
  });
101
105
 
102
106
  describe("Concept labels", () => {
103
- var testReport = new iXBRLReport(testReportData);
104
- var vo = new ViewerOptions();
105
- testReport.setViewerOptions(vo);
107
+ const testReportSet = new ReportSet(testReportData);
108
+ testReportSet._initialize();
109
+ const testReport = testReportSet.reports[0];
110
+ const vo = new ViewerOptions();
111
+ testReportSet.viewerOptions = vo;
106
112
  test("Label fallback", () => {
107
113
  vo.language = 'fr';
108
114
  expect(testReport.getLabel('eg:Concept3', 'std')).toBe("Concept trois");
115
+ expect(testReport.getLabelAndLang('eg:Concept3', 'std').label).toBe("Concept trois");
116
+ expect(testReport.getLabelAndLang('eg:Concept3', 'std').lang).toBe("fr");
109
117
  expect(testReport.getLabelOrName('eg:Concept3', 'std')).toBe("Concept trois");
110
118
  vo.language = 'es';
111
119
  expect(testReport.getLabel('eg:Concept3', 'std')).toBe("Concept cuatro");
120
+ expect(testReport.getLabelAndLang('eg:Concept3', 'std').label).toBe("Concept cuatro");
121
+ expect(testReport.getLabelAndLang('eg:Concept3', 'std').lang).toBe("es");
112
122
  expect(testReport.getLabelOrName('eg:Concept3', 'std')).toBe("Concept cuatro");
113
123
  // No English label, so fall back on German (de is first alphabetically)
114
124
  vo.language = 'en';
115
125
  expect(testReport.getLabel('eg:Concept3', 'std')).toBe("Concept vier");
126
+ expect(testReport.getLabelAndLang('eg:Concept3', 'std').label).toBe("Concept vier");
127
+ expect(testReport.getLabelAndLang('eg:Concept3', 'std').lang).toBe("de");
116
128
  expect(testReport.getLabelOrName('eg:Concept3', 'std')).toBe("Concept vier");
117
129
 
118
130
  // Attempt to get an undefined label type
119
131
  expect(testReport.getLabel('eg:Concept3', 'doc')).toBeUndefined();
132
+ expect(testReport.getLabelAndLang('eg:Concept3', 'doc').label).toBeUndefined();
133
+ expect(testReport.getLabelAndLang('eg:Concept3', 'doc').lang).toBeUndefined();
120
134
  expect(testReport.getLabelOrName('eg:Concept3', 'doc')).toBe('eg:Concept3');
121
135
  });
122
136
 
123
137
  test("With prefix", () => {
124
138
  vo.language = 'fr';
125
139
  expect(testReport.getLabel('eg:Concept3', 'std', true)).toBe("(eg) Concept trois");
140
+ expect(testReport.getLabelAndLang('eg:Concept3', 'std', true).label).toBe("(eg) Concept trois");
141
+ expect(testReport.getLabelAndLang('eg:Concept3', 'std', true).lang).toBe("fr");
126
142
  expect(testReport.getLabelOrName('eg:Concept3', 'std', true)).toBe("(eg) Concept trois");
127
143
 
128
144
  expect(testReport.getLabel('eg:Concept3', 'doc', true)).toBeUndefined();
@@ -132,18 +148,70 @@ describe("Concept labels", () => {
132
148
  });
133
149
 
134
150
  describe("ELR labels", () => {
135
- const testReport = new iXBRLReport(testReportData);
151
+ const testReportSet = new ReportSet(testReportData);
152
+ testReportSet._initialize();
153
+ const testReport = testReportSet.reports[0];
136
154
  test("Present", () => {
137
- expect(testReport.getRoleLabel("role1")).toBe("Role 1 Label");
155
+ expect(testReport.getRoleLabelOrURI("role1")).toBe("Role 1 Label");
138
156
  });
139
157
  test("Null", () => {
140
- expect(testReport.getRoleLabel("role2")).toBe("https://www.example.com/role2");
158
+ expect(testReport.getRoleLabelOrURI("role2")).toBe("https://www.example.com/role2");
141
159
  });
142
160
  test("No label", () => {
143
- expect(testReport.getRoleLabel("role3")).toBe("https://www.example.com/role3");
161
+ expect(testReport.getRoleLabelOrURI("role3")).toBe("https://www.example.com/role3");
144
162
  });
145
163
  test("Not present in roleDef", () => {
146
- expect(testReport.getRoleLabel("role4")).toBe("https://www.example.com/role4");
164
+ expect(testReport.getRoleLabelOrURI("role4")).toBe("https://www.example.com/role4MoreWords");
147
165
  });
166
+ });
148
167
 
168
+ describe("Label role labels", () => {
169
+ const testReportSet = new ReportSet(testReportData);
170
+ testReportSet._initialize();
171
+ const testReport = testReportSet.reports[0];
172
+ test("Built-in (via i18n)", () => {
173
+ expect(testReport.getLabelRoleLabel("std")).toBe("Standard Label");
174
+ });
175
+ test("Built-in (via i18n)", () => {
176
+ expect(testReport.getLabelRoleLabel("doc")).toBe("Documentation Label");
177
+ });
178
+ test("Built-in (via de-camelcase)", () => {
179
+ expect(testReport.getLabelRoleLabel("verbose")).toBe("Verbose Label");
180
+ });
181
+ test("Present", () => {
182
+ expect(testReport.getLabelRoleLabel("role1")).toBe("Role 1 Label");
183
+ });
184
+ test("Null", () => {
185
+ expect(testReport.getLabelRoleLabel("role2")).toBe("Role2");
186
+ });
187
+ test("No label", () => {
188
+ expect(testReport.getLabelRoleLabel("role3")).toBe("Role3");
189
+ });
190
+ test("Not present in roleDef", () => {
191
+ expect(testReport.getLabelRoleLabel("role4")).toBe("Role4 More Words");
192
+ });
193
+
194
+ });
195
+
196
+ describe("Fetching software credit", () => {
197
+
198
+ test("Successful", () => {
199
+ const testReportSet = new ReportSet(testReportData);
200
+ testReportSet._initialize();
201
+ const report = testReportSet.reports[0];
202
+
203
+ const softwareCredits = report.softwareCredits();
204
+ expect(softwareCredits).toEqual(["Example credit text A", "Example credit text B"]);
205
+ });
206
+
207
+ test("Unset", () => {
208
+ let alternateData = JSON.parse(JSON.stringify(testReportData));
209
+ delete alternateData.softwareCredits;
210
+ const testReportSet = new ReportSet(alternateData);
211
+ testReportSet._initialize();
212
+ const report = testReportSet.reports[0];
213
+
214
+ const softwareCredits = report.softwareCredits();
215
+ expect(softwareCredits).toEqual([]);
216
+ });
149
217
  });
@@ -0,0 +1,264 @@
1
+ // See COPYRIGHT.md for copyright information
2
+
3
+ import { XBRLReport } from './report.js';
4
+ import { Fact } from "./fact.js"
5
+ import { Footnote } from "./footnote.js"
6
+ import { Unit } from "./unit";
7
+ import { titleCase, viewerUniqueId } from "./util.js";
8
+ import { QName } from "./qname.js";
9
+ import { ViewerOptions } from './viewerOptions.js';
10
+ import { TaxonomyNamer } from './taxonomynamer.js';
11
+
12
+ // Class represents the set of XBRL "target" reports shown in the viewer.
13
+ // Each contained report represents the data from a single target document in a
14
+ // single iXBRL Document or iXBRL Document Set
15
+
16
+ export class ReportSet {
17
+ constructor(data) {
18
+ this._data = data;
19
+ this._ixNodeMap = {};
20
+ this.viewerOptions = new ViewerOptions()
21
+ this.taxonomyNamer = new TaxonomyNamer(new Map());
22
+ }
23
+
24
+ /*
25
+ * Set additional information about facts obtained from parsing the iXBRL.
26
+ */
27
+ setIXNodeMap(ixData) {
28
+ this._ixNodeMap = ixData;
29
+ this._initialize();
30
+ }
31
+
32
+ _initialize() {
33
+ this._items = {};
34
+ this.reports = [];
35
+ // Build an array of footnotes IDs in document order so that we can assign
36
+ // numbers to foonotes
37
+ const fnorder = Object.keys(this._ixNodeMap).filter((id) => this._ixNodeMap[id].footnote);
38
+ fnorder.sort((a,b) => this._ixNodeMap[a].docOrderindex - this._ixNodeMap[b].docOrderindex);
39
+
40
+ // Create Fact objects for all facts.
41
+ for (const [reportIndex, sourceReport] of (this._data.sourceReports ?? [ { "targetReports": [ this._data ] } ]).entries()) {
42
+ for (const reportData of sourceReport.targetReports) {
43
+ const report = new XBRLReport(this, reportData);
44
+ this.reports.push(report);
45
+ for (const [id, factData] of Object.entries(reportData.facts)) {
46
+ const vuid = viewerUniqueId(reportIndex, id);
47
+ this._items[vuid] = new Fact(report, vuid, factData);
48
+ }
49
+
50
+ // Now resolve footnote references, creating footnote objects for "normal"
51
+ // footnotes, and finding Fact objects for fact->fact footnotes.
52
+ //
53
+ // Associate source facts with target footnote/facts to allow two way
54
+ // navigation.
55
+ for (const [id, factData] of Object.entries(reportData.facts)) {
56
+ const vuid = viewerUniqueId(reportIndex, id);
57
+ const fact = this._items[vuid];
58
+ const fns = factData.fn || [];
59
+ fns.forEach((fnid) => {
60
+ const fnvuid = viewerUniqueId(reportIndex, fnid);
61
+ var fn = this._items[fnvuid];
62
+ if (fn === undefined) {
63
+ fn = new Footnote(fact.report, fnvuid, "Footnote " + (fnorder.indexOf(fnvuid) + 1));
64
+ this._items[fnvuid] = fn;
65
+ }
66
+ // Associate fact with footnote
67
+ fn.addLinkedFact(fact);
68
+ fact.addFootnote(fn);
69
+ });
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ availableLanguages() {
76
+ return Array.from(this.reports.reduce(
77
+ (langs, report) => new Set([...langs, ...report.availableLanguages()]),
78
+ new Set()
79
+ ));
80
+ }
81
+
82
+ getItemById(vuid) {
83
+ return this._items[vuid];
84
+ }
85
+
86
+ getIXNodeForItemId(vuid) {
87
+ return this._ixNodeMap[vuid] || {};
88
+ }
89
+
90
+ facts() {
91
+ return Object.values(this._items).filter(i => i instanceof Fact);
92
+ }
93
+
94
+ filingDocuments() {
95
+ return this._data.filingDocuments;
96
+ }
97
+
98
+ prefixMap() {
99
+ return this._data.prefixes;
100
+ }
101
+
102
+ preferredPrefix(prefix) {
103
+ return this.taxonomyNamer.getName(prefix, this._data.prefixes[prefix]).prefix;
104
+ }
105
+
106
+ namespaceGroups() {
107
+ const counts = {};
108
+ for (const f of this.facts()) {
109
+ counts[f.conceptQName().prefix] = (counts[f.conceptQName().prefix] || 0) + 1;
110
+ }
111
+ const prefixes = Object.keys(counts);
112
+ prefixes.sort((a, b) => counts[b] - counts[a]);
113
+ return prefixes;
114
+ }
115
+
116
+ getUsedConceptPrefixes() {
117
+ if (this._usedPrefixes === undefined) {
118
+ this._usedPrefixes = new Set(Object.values(this._items)
119
+ .filter(f => f instanceof Fact)
120
+ .map(f => f.getConceptPrefix()));
121
+ }
122
+ return this._usedPrefixes;
123
+ }
124
+
125
+ getUsedConceptDataTypes() {
126
+ if (this._usedDataTypes === undefined) {
127
+ const map = new Map()
128
+ for (const dt of Object.values(this._items)
129
+ .filter(f => f instanceof Fact)
130
+ .map(f => ({ dataType: f.concept().dataType(), isNumeric: f.isNumeric() }))
131
+ .filter(t => t.dataType !== undefined)) {
132
+ map.set(dt.dataType.name, dt);
133
+ }
134
+ this._usedDataTypes = map.values().toArray();
135
+ }
136
+ return this._usedDataTypes;
137
+ }
138
+
139
+ /**
140
+ * @return {Array[String]} Sorted list of unique software credit text values
141
+ */
142
+ getSoftwareCredits() {
143
+ let softwareCredits = new Set(this.reports.flatMap(r => r.softwareCredits()));
144
+ return Array.from(softwareCredits).sort();
145
+ }
146
+
147
+ getTargetDocuments() {
148
+ if (this._targetDocuments === undefined) {
149
+ this._targetDocuments = new Set(Object.values(this._items)
150
+ .filter(f => f instanceof Fact)
151
+ .map(f => f.targetDocument()));
152
+ }
153
+ return this._targetDocuments;
154
+ }
155
+
156
+ /**
157
+ * Returns a set of OIM format unit strings used by facts on this report. Lazy-loaded.
158
+ * @return {Set[String]} Set of OIM format unit strings
159
+ */
160
+ getUsedUnits() {
161
+ if (this._usedUnits === undefined) {
162
+ this._usedUnits = new Set(Object.values(this._items)
163
+ .filter(f => f instanceof Fact)
164
+ .map(f => f.unit()?.value())
165
+ .filter(f => f)
166
+ .sort());
167
+ }
168
+ return this._usedUnits;
169
+ }
170
+
171
+ /**
172
+ * Returns details about the provided unit. Lazy-loaded once per unit.
173
+ * @param {String} unitKey Unit in OIM format
174
+ * @return {Unit} Unit instance corresponding with provided key
175
+ */
176
+ getUnit(unitKey) {
177
+ if (this._unitsMap === undefined) {
178
+ this._unitsMap = {};
179
+ }
180
+ if (this._unitsMap[unitKey] === undefined) {
181
+ this._unitsMap[unitKey] = new Unit(this, unitKey)
182
+ }
183
+ return this._unitsMap[unitKey];
184
+ }
185
+
186
+ getUsedScalesMap() {
187
+ // Do not lazy load. This is language-dependent so needs to re-evaluate after language changes.
188
+ const usedScalesMap = {};
189
+ Object.values(this._items)
190
+ .filter(f => f instanceof Fact)
191
+ .forEach(fact => {
192
+ const scale = fact.scale();
193
+ if (scale !== null && scale !== undefined) {
194
+ if (!(scale in usedScalesMap)) {
195
+ usedScalesMap[scale] = new Set();
196
+ }
197
+ const labels = usedScalesMap[scale];
198
+ const label = titleCase(fact.getScaleLabel(scale));
199
+ if (label && !labels.has(label)) {
200
+ labels.add(label);
201
+ }
202
+ }
203
+ });
204
+ return usedScalesMap;
205
+ }
206
+
207
+ roleMap() {
208
+ return this._data.roles;
209
+ }
210
+
211
+ qname(v) {
212
+ return new QName(this.prefixMap(), v);
213
+ }
214
+
215
+ reportsData() {
216
+ return this._data.sourceReports?.flatMap(sr => sr.targetReports) ?? [ this._data ];
217
+ }
218
+
219
+ /**
220
+ * Returns a flat list of source files for all reports in the report set.
221
+ * Each entry in the list is an object with:
222
+ * file - name of the file
223
+ * index - index of the report that it is for
224
+ * May return an empty list for single file, non-stub viewers.
225
+ * @return {List} A list of objects describing each file
226
+ */
227
+ reportFiles() {
228
+ const sourceReports = this._data.sourceReports ?? [ this._data ];
229
+ return sourceReports.map((x, n) => (x.docSetFiles ?? []).map(file => ({ index: n, file: file }))).flat();
230
+ }
231
+
232
+ /**
233
+ * Returns true if the viewer is for more than one Inline XBRL document
234
+ * This may be a single document set with multiple files, or multiple
235
+ * document sets
236
+ * @return {Boolean} true if the viewer covers more than one iXBRL
237
+ * document
238
+ */
239
+
240
+ isMultiDocumentViewer() {
241
+ return this.reportFiles().length > 1;
242
+ }
243
+
244
+ usesAnchoring() {
245
+ return this.reportsData().some(r => r.rels?.["w-n"] !== undefined);
246
+ }
247
+
248
+ usesCalculations() {
249
+ return this.reportsData().some(r => Object.keys(r.rels?.calc ?? {}).length > 0);
250
+ }
251
+
252
+ hasValidationErrors() {
253
+ return this._data.validation !== undefined && this._data.validation.length > 0;
254
+ }
255
+
256
+ validation() {
257
+ return this._data.validation;
258
+ }
259
+
260
+ factsForReport(report) {
261
+ return Object.values(this._items).filter(i => i instanceof Fact && i.report == report);
262
+ }
263
+
264
+ }