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
3
  import { ReportSearch } from "./search.js"
4
- import {iXBRLReport} from "./report";
4
+ import { ReportSet } from "./reportset.js";
5
+ import { viewerUniqueId } from "./util.js";
6
+ import { createSimpleFact, createNumericFact } from './test-utils.js';
5
7
 
6
8
  const testReportData = {
7
9
  "concepts": {},
@@ -13,6 +15,7 @@ const testReportData = {
13
15
  "rels": {},
14
16
  };
15
17
 
18
+
16
19
  function getReportSearch(report) {
17
20
  const reportSearch = new ReportSearch(report);
18
21
  const searchIndex = reportSearch.buildSearchIndex(() => {});
@@ -25,6 +28,7 @@ function createDimensionConcept(name, label, isExplicit= true) {
25
28
  c[name]["d"] = isExplicit ? "e": "t";
26
29
  return c;
27
30
  }
31
+
28
32
  function createSimpleConcept(name, label=null) {
29
33
  return {
30
34
  [name]: {
@@ -49,58 +53,63 @@ function createDimensionalizedFact(id, concept, options=null, dimensions= {}) {
49
53
  return fact;
50
54
  }
51
55
 
52
- function createSimpleFact(id, concept, options=null) {
53
- options = options || {};
54
- return {
55
- [id]: {
56
- "a": {
57
- "c": concept,
58
- "u": options["unit"],
59
- "p": options["period"],
60
- },
61
- "d": options["decimals"],
62
- "v": options["value"]
63
- }
64
- };
56
+ // Returns a report set with a single report
57
+ function testReport(testData, sourceIXData) {
58
+ return testReportSet([ {data: testData, ixData: sourceIXData ?? { } } ])
65
59
  }
66
60
 
67
- function createNumericFact(id, concept, unit, period, value) {
68
- return createSimpleFact(id, concept, {
69
- "unit": unit,
70
- "period": period,
71
- "value": value
72
- });
61
+ function mergeDicts(a, b) {
62
+ a ??= {};
63
+ b ??= {};
64
+ return { ...a, ...b };
73
65
  }
74
66
 
75
- function testReport(ixData, testData) {
76
- // Deep copy of standing data
77
- const data = {
78
- ...JSON.parse(JSON.stringify(testReportData)),
79
- ...testData
80
- }
81
- Object.keys(data['facts']).forEach(id => {
82
- if (!(id in ixData)) {
83
- ixData[id] = {};
67
+ function testReportSet(reports) {
68
+ const targetReports = [];
69
+ const reportSetData = {
70
+ "sourceReports": [{ "targetReports": targetReports }],
71
+ };
72
+
73
+ const ixData = {};
74
+ for (const report of reports.values()) {
75
+ const targetReport = {};
76
+ for (const key of ["languages", "prefixes", "roles"]) {
77
+ reportSetData[key] = mergeDicts(reportSetData[key], report.data[key]);
78
+ }
79
+ for (const key of ["concepts", "facts", "roleDefs", "rels"]) {
80
+ targetReport[key] = report.data[key] ?? {};
84
81
  }
85
- })
86
- const report = new iXBRLReport(data);
87
- report.setIXNodeMap(ixData);
88
- return report;
82
+ targetReport["target"] = report.data["target"] ?? null;
83
+
84
+ for (const id of Object.keys(targetReport.facts)) {
85
+ if (!(id in ixData)) {
86
+ ixData[viewerUniqueId(0, id)] = report.ixData?.[id] ?? {};
87
+ }
88
+ }
89
+ targetReports.push(targetReport);
90
+ }
91
+ const reportSet = new ReportSet(reportSetData);
92
+ for (const [id, data] of Object.entries(ixData)) {
93
+ ixData[id].isHidden ??= false;
94
+ }
95
+ reportSet.setIXNodeMap(ixData);
96
+ return reportSet;
89
97
  }
90
98
 
91
99
  function testSearchSpec(searchString='') {
92
100
  const spec = {};
93
101
  spec.searchString = searchString;
94
- spec.showVisibleFacts = true;
95
- spec.showHiddenFacts = true;
102
+ spec.visibilityFilter = '*';
96
103
  spec.namespacesFilter = [];
97
104
  spec.unitsFilter = [];
98
105
  spec.scalesFilter = [];
99
106
  spec.periodFilter = [];
100
107
  spec.conceptTypeFilter = '*';
108
+ spec.dataTypesFilter = [];
101
109
  spec.dimensionTypeFilter = [];
102
110
  spec.factValueFilter = '*';
103
111
  spec.calculationsFilter = [];
112
+ spec.targetDocumentFilter = [];
104
113
  return spec;
105
114
  }
106
115
 
@@ -108,7 +117,6 @@ describe("Search fact value filter", () => {
108
117
  const cashConcept = 'us-gaap:Cash';
109
118
  const cashUnit = 'iso4217:USD';
110
119
  const report = testReport(
111
- {'positive': {}, 'negative': {}, 'zero': {}, 'text': {}, 'undefined': {}},
112
120
  {
113
121
  'concepts': {
114
122
  ...createSimpleConcept(cashConcept, 'Cash')
@@ -129,7 +137,7 @@ describe("Search fact value filter", () => {
129
137
  spec.factValueFilter = 'negative'
130
138
  const results = reportSearch.search(spec);
131
139
  expect(results.length).toEqual(1)
132
- expect(results[0]["fact"]["id"]).toEqual("negative")
140
+ expect(results[0]["fact"].localId()).toEqual("negative")
133
141
  });
134
142
 
135
143
  test("Fact Value Negative filter works with other filter", () => {
@@ -138,7 +146,7 @@ describe("Search fact value filter", () => {
138
146
  spec.periodFilter = ['2018-01-01/2019-01-01']
139
147
  const results = reportSearch.search(spec);
140
148
  expect(results.length).toEqual(1)
141
- expect(results[0]["fact"]["id"]).toEqual("negative")
149
+ expect(results[0]["fact"].localId()).toEqual("negative")
142
150
  });
143
151
 
144
152
  test("Fact Value Positive filter works", () => {
@@ -146,7 +154,7 @@ describe("Search fact value filter", () => {
146
154
  spec.factValueFilter = 'positive'
147
155
  const results = reportSearch.search(spec);
148
156
  expect(results.length).toEqual(1)
149
- expect(results[0]["fact"]["id"]).toEqual("positive")
157
+ expect(results[0]["fact"].localId()).toEqual("positive")
150
158
  });
151
159
 
152
160
  test("Fact Value Positive filter works with other filter", () => {
@@ -155,13 +163,12 @@ describe("Search fact value filter", () => {
155
163
  spec.periodFilter = ['2018-01-01/2019-01-01']
156
164
  const results = reportSearch.search(spec);
157
165
  expect(results.length).toEqual(1)
158
- expect(results[0]["fact"]["id"]).toEqual("positive")
166
+ expect(results[0]["fact"].localId()).toEqual("positive")
159
167
  });
160
168
  });
161
169
 
162
170
  describe("Search calculation filter", () => {
163
171
  const report = testReport(
164
- {'summation': {}, 'item1': {}, 'item2': {}, 'other': {}},
165
172
  {
166
173
  "concepts": {
167
174
  ...createSimpleConcept("test:Summation", "Summation"),
@@ -192,32 +199,31 @@ describe("Search calculation filter", () => {
192
199
  test("Calculations 'all' filter works", () => {
193
200
  const spec = testSearchSpec();
194
201
  spec.calculationsFilter = [];
195
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
202
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
196
203
  expect(results).toEqual(['item1', 'item2', 'other', 'summation']);
197
204
  });
198
205
 
199
206
  test("Calculations 'contributor' filter works", () => {
200
207
  const spec = testSearchSpec();
201
208
  spec.calculationsFilter = ['contributor'];
202
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
209
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
203
210
  expect(results).toEqual(['item1', 'item2']);
204
211
  });
205
212
 
206
213
  test("Calculations 'summation' filter works", () => {
207
214
  const spec = testSearchSpec();
208
215
  spec.calculationsFilter = ['summation'];
209
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
216
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
210
217
  expect(results).toEqual(['summation']);
211
218
  });
212
219
 
213
220
  test("Calculations 'summation' and 'contributor' filter works", () => {
214
221
  const spec = testSearchSpec();
215
222
  spec.calculationsFilter = ['summation', 'contributor'];
216
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
223
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
217
224
  expect(results).toEqual(['item1', 'item2', 'summation']);
218
225
  });
219
226
  const emptyReport = testReport(
220
- {'fact': {}},
221
227
  {
222
228
  "concepts": {
223
229
  ...createSimpleConcept("test:Concept", "Concept"),
@@ -232,14 +238,13 @@ describe("Search calculation filter", () => {
232
238
  test("Calculations filter works on empty report", () => {
233
239
  const spec = testSearchSpec();
234
240
  spec.calculationsFilter = ['summation', 'contributor'];
235
- const results = emptyReportSearch.search(spec).map(r => r.fact.id).sort();
241
+ const results = emptyReportSearch.search(spec).map(r => r.fact.localId()).sort();
236
242
  expect(results).toEqual([]);
237
243
  });
238
244
  });
239
245
 
240
246
  describe("Search namespaces filter", () => {
241
247
  const report = testReport(
242
- {'itemA1': {}, 'itemA2': {}, 'itemB1': {}, 'itemC1': {}},
243
248
  {
244
249
  "concepts": {
245
250
  ...createSimpleConcept("a:ItemA1", "ItemA1"),
@@ -264,45 +269,44 @@ describe("Search namespaces filter", () => {
264
269
  const reportSearch = getReportSearch(report)
265
270
 
266
271
  test("Namespaces filter only shows used prefixes", () => {
267
- const prefixes = Array.from(report.getUsedPrefixes()).sort();
272
+ const prefixes = Array.from(report.getUsedConceptPrefixes()).sort();
268
273
  expect(prefixes).toEqual(['a', 'b', 'c']);
269
274
  });
270
275
 
271
276
  test("Namespaces filter works without selection", () => {
272
277
  const spec = testSearchSpec();
273
278
  spec.namespacesFilter = [];
274
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
279
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
275
280
  expect(results).toEqual(['itemA1', 'itemA2', 'itemB1', 'itemC1']);
276
281
  });
277
282
 
278
283
  test("Namespaces filter works with single selection", () => {
279
284
  const spec = testSearchSpec();
280
285
  spec.namespacesFilter = ['a'];
281
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
286
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
282
287
  expect(results).toEqual(['itemA1', 'itemA2']);
283
288
  });
284
289
 
285
290
  test("Namespaces filter works with multiple selections", () => {
286
291
  const spec = testSearchSpec();
287
292
  spec.namespacesFilter = ['a', 'b'];
288
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
293
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
289
294
  expect(results).toEqual(['itemA1', 'itemA2', 'itemB1']);
290
295
  });
291
296
 
292
297
  test("Namespaces filter works with all selections", () => {
293
298
  const spec1 = testSearchSpec();
294
- spec1.namespacesFilter = Array.from(report.getUsedPrefixes());
295
- const results1 = reportSearch.search(spec1).map(r => r.fact.id).sort();
299
+ spec1.namespacesFilter = Array.from(report.getUsedConceptPrefixes());
300
+ const results1 = reportSearch.search(spec1).map(r => r.fact.localId()).sort();
296
301
  const spec2 = testSearchSpec();
297
302
  spec2.namespacesFilter = [];
298
- const results2 = reportSearch.search(spec2).map(r => r.fact.id).sort();
303
+ const results2 = reportSearch.search(spec2).map(r => r.fact.localId()).sort();
299
304
  expect(results1).toEqual(results2);
300
305
  expect(results1).toEqual(['itemA1', 'itemA2', 'itemB1', 'itemC1'])
301
306
  });
302
307
  });
303
308
 
304
309
  describe("Search units filter", () => {
305
-
306
310
  const cashUnit = 'test:USD';
307
311
  const shareUnit = 'test:share';
308
312
  const cashShareUnit = `${cashUnit} / ${shareUnit}`
@@ -314,7 +318,6 @@ describe("Search units filter", () => {
314
318
 
315
319
  beforeAll(() => {
316
320
  report = testReport(
317
- {'itemA': {}, 'itemAB': {}, 'itemB': {}, 'itemBA': {}},
318
321
  {
319
322
  "concepts": {
320
323
  ...createSimpleConcept("a:ItemA", "ItemA"),
@@ -343,31 +346,31 @@ describe("Search units filter", () => {
343
346
  test("Units filter works without selection", () => {
344
347
  const spec = testSearchSpec();
345
348
  spec.unitsFilter = [];
346
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
349
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
347
350
  expect(results).toEqual(['itemA', 'itemAB', 'itemB', 'itemBA', 'other']);
348
351
  });
349
352
 
350
353
  test("Units filter works with single selection", () => {
351
354
  const spec = testSearchSpec();
352
355
  spec.unitsFilter = [cashShareUnit];
353
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
356
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
354
357
  expect(results).toEqual(['itemAB']);
355
358
  });
356
359
 
357
360
  test("Units filter works with multiple selections", () => {
358
361
  const spec = testSearchSpec();
359
362
  spec.unitsFilter = [cashUnit, cashShareUnit];
360
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
363
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
361
364
  expect(results).toEqual(['itemA', 'itemAB']);
362
365
  });
363
366
 
364
367
  test("Units filter with all selections matches numeric filter", () => {
365
368
  const spec1 = testSearchSpec();
366
369
  spec1.unitsFilter = Array.from(report.getUsedUnits());
367
- const results1 = reportSearch.search(spec1).map(r => r.fact.id).sort();
370
+ const results1 = reportSearch.search(spec1).map(r => r.fact.localId()).sort();
368
371
  const spec2 = testSearchSpec()
369
372
  spec2.conceptTypeFilter = 'numeric';
370
- const results2 = reportSearch.search(spec2).map(r => r.fact.id).sort();
373
+ const results2 = reportSearch.search(spec2).map(r => r.fact.localId()).sort();
371
374
  expect(results1).toEqual(results2);
372
375
  expect(results1).toEqual(['itemA', 'itemAB', 'itemB', 'itemBA'])
373
376
  });
@@ -375,7 +378,6 @@ describe("Search units filter", () => {
375
378
 
376
379
  describe("Search dimension type filter", () => {
377
380
  const report = testReport(
378
- {},
379
381
  {
380
382
  "concepts": {
381
383
  ...createSimpleConcept("test:Concept", "Concept"),
@@ -403,33 +405,32 @@ describe("Search dimension type filter", () => {
403
405
  test("Dimension 'all' filter works", () => {
404
406
  const spec = testSearchSpec();
405
407
  spec.dimensionTypeFilter = [];
406
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
408
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
407
409
  expect(results).toEqual(['explicit', 'explicit2', 'explicitAndTyped', 'explicitAndTyped2', 'simple', 'simple2', 'typed', 'typed2']);
408
410
  });
409
411
 
410
412
  test("Dimension 'explicit' filter works", () => {
411
413
  const spec = testSearchSpec();
412
414
  spec.dimensionTypeFilter = ['explicit'];
413
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
415
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
414
416
  expect(results).toEqual(['explicit', 'explicit2', 'explicitAndTyped', 'explicitAndTyped2']);
415
417
  });
416
418
 
417
419
  test("Dimension 'typed' filter works", () => {
418
420
  const spec = testSearchSpec();
419
421
  spec.dimensionTypeFilter = ['typed'];
420
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
422
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
421
423
  expect(results).toEqual(['explicitAndTyped', 'explicitAndTyped2', 'typed', 'typed2']);
422
424
  });
423
425
 
424
426
  test("Dimension 'explicit' and 'typed' filter works", () => {
425
427
  const spec = testSearchSpec();
426
428
  spec.dimensionTypeFilter = ['explicit', 'typed'];
427
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
429
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
428
430
  expect(results).toEqual(['explicit', 'explicit2', 'explicitAndTyped', 'explicitAndTyped2', 'typed', 'typed2']);
429
431
  });
430
432
 
431
433
  const emptyReport = testReport(
432
- {'fact': {}},
433
434
  {
434
435
  "concepts": {
435
436
  ...createSimpleConcept("test:Concept", "Concept"),
@@ -444,7 +445,7 @@ describe("Search dimension type filter", () => {
444
445
  test("Dimension filter works on empty report", () => {
445
446
  const spec = testSearchSpec();
446
447
  spec.dimensionTypeFilter = ['explicit'];
447
- const results = emptyReportSearch.search(spec).map(r => r.fact.id).sort();
448
+ const results = emptyReportSearch.search(spec).map(r => r.fact.localId()).sort();
448
449
  expect(results).toEqual([]);
449
450
  });
450
451
  });
@@ -453,18 +454,6 @@ describe("Search scales filter", () => {
453
454
  const cashUnit = 'test:USD';
454
455
  const period = '2018-01-01/2019-01-01';
455
456
  const report = testReport(
456
- {
457
- "item-3": { "scale": -3 },
458
- "item-2": { "scale": -2 },
459
- "item-1": { "scale": -1 },
460
- "item0": { },
461
- "item1": { "scale": 1 },
462
- "item2": { "scale": 2 },
463
- "item3": { "scale": 3 },
464
- "item6": { "scale": 6 },
465
- "item9": { "scale": 9 },
466
- "item12": { "scale": 12 },
467
- },
468
457
  {
469
458
  "concepts": {
470
459
  ...createSimpleConcept("a:Item-3"),
@@ -492,6 +481,18 @@ describe("Search scales filter", () => {
492
481
  ...createNumericFact("item12", "a:Item12", cashUnit, period, 1000000000000),
493
482
  ...createSimpleFact("itemOther", "a:Other"),
494
483
  },
484
+ },
485
+ {
486
+ "item-3": { "scale": -3 },
487
+ "item-2": { "scale": -2 },
488
+ "item-1": { "scale": -1 },
489
+ "item0": { },
490
+ "item1": { "scale": 1 },
491
+ "item2": { "scale": 2 },
492
+ "item3": { "scale": 3 },
493
+ "item6": { "scale": 6 },
494
+ "item9": { "scale": 9 },
495
+ "item12": { "scale": 12 },
495
496
  }
496
497
  )
497
498
  const reportSearch = getReportSearch(report);
@@ -499,21 +500,120 @@ describe("Search scales filter", () => {
499
500
  test("Scales filter works without selection", () => {
500
501
  const spec = testSearchSpec();
501
502
  spec.scalesFilter = [];
502
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
503
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
503
504
  expect(results).toEqual(['item-1', 'item-2', 'item-3', 'item0', 'item1', 'item12', 'item2', 'item3', 'item6', 'item9', 'itemOther']);
504
505
  });
505
506
 
506
507
  test("Scales filter works with single selection", () => {
507
508
  const spec = testSearchSpec();
508
509
  spec.scalesFilter = [-2];
509
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
510
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
510
511
  expect(results).toEqual(['item-2']);
511
512
  });
512
513
 
513
514
  test("Scales filter works with multiple selections", () => {
514
515
  const spec = testSearchSpec();
515
516
  spec.scalesFilter = [-2, 2];
516
- const results = reportSearch.search(spec).map(r => r.fact.id).sort();
517
+ const results = reportSearch.search(spec).map(r => r.fact.localId()).sort();
517
518
  expect(results).toEqual(['item-2', 'item2']);
518
519
  });
519
520
  });
521
+
522
+ describe("Search target document filter", () => {
523
+ const cashUnit = 'test:USD';
524
+ const period = '2018-01-01/2019-01-01';
525
+ const singleReport = testReport(
526
+ {
527
+ "concepts": {
528
+ ...createSimpleConcept("a:Item0"),
529
+ ...createSimpleConcept("a:Item1"),
530
+ ...createSimpleConcept("a:Item2"),
531
+ },
532
+ "facts": {
533
+ ...createNumericFact("item0", "a:Item0", cashUnit, period, 1),
534
+ ...createNumericFact("item1", "a:Item1", cashUnit, period, 10),
535
+ ...createNumericFact("item2", "a:Item2", cashUnit, period, 100),
536
+ },
537
+ },
538
+ );
539
+ const singleReportSearch = getReportSearch(singleReport);
540
+
541
+ test("Target document filter works without selection", () => {
542
+ const spec = testSearchSpec();
543
+ spec.targetDocumentFilter = [];
544
+ const results = singleReportSearch.search(spec).map(r => r.fact.localId()).sort();
545
+ expect(results).toEqual(['item0', 'item1', 'item2' ]);
546
+ });
547
+
548
+ test("Target document filter with default document", () => {
549
+ const spec = testSearchSpec();
550
+ spec.targetDocumentFilter = [ ':default' ];
551
+ const results = singleReportSearch.search(spec).map(r => r.fact.localId()).sort();
552
+ expect(results).toEqual(['item0', 'item1', 'item2' ]);
553
+ });
554
+
555
+ const multiReport = testReportSet([
556
+ {
557
+ data: {
558
+ target: null,
559
+ "concepts": {
560
+ ...createSimpleConcept("a:Item0"),
561
+ ...createSimpleConcept("a:Item1"),
562
+ ...createSimpleConcept("a:Item2"),
563
+ },
564
+ "facts": {
565
+ ...createNumericFact("item0", "a:Item0", cashUnit, period, 1),
566
+ ...createNumericFact("item1", "a:Item1", cashUnit, period, 10),
567
+ ...createNumericFact("item2", "a:Item2", cashUnit, period, 100),
568
+ },
569
+ },
570
+ },
571
+ {
572
+ data: {
573
+ target: "ABC",
574
+ "concepts": {
575
+ ...createSimpleConcept("a:Item3"),
576
+ ...createSimpleConcept("a:Item4"),
577
+ ...createSimpleConcept("a:Item5"),
578
+ },
579
+ "facts": {
580
+ ...createNumericFact("item3", "a:Item3", cashUnit, period, 1),
581
+ ...createNumericFact("item4", "a:Item4", cashUnit, period, 10),
582
+ ...createNumericFact("item5", "a:Item5", cashUnit, period, 100),
583
+ },
584
+ },
585
+ }
586
+
587
+ ]);
588
+
589
+ const multiReportSearch = getReportSearch(multiReport);
590
+
591
+ test("Target document filter works without selection (multiple targets)", () => {
592
+ const spec = testSearchSpec();
593
+ spec.targetDocumentFilter = [];
594
+ const results = multiReportSearch.search(spec).map(r => r.fact.localId()).sort();
595
+ expect(results).toEqual(['item0', 'item1', 'item2', 'item3', 'item4', 'item5' ]);
596
+ });
597
+
598
+ test("Target document filter works with default (multiple targets)", () => {
599
+ const spec = testSearchSpec();
600
+ spec.targetDocumentFilter = [ ':default' ];
601
+ const results = multiReportSearch.search(spec).map(r => r.fact.localId()).sort();
602
+ expect(results).toEqual(['item0', 'item1', 'item2']);
603
+ });
604
+
605
+ test("Target document filter works with second target (multiple targets)", () => {
606
+ const spec = testSearchSpec();
607
+ spec.targetDocumentFilter = [ 'ABC' ];
608
+ const results = multiReportSearch.search(spec).map(r => r.fact.localId()).sort();
609
+ expect(results).toEqual(['item3', 'item4', 'item5']);
610
+ });
611
+
612
+ test("Target document filter works with multi-select (multiple targets)", () => {
613
+ const spec = testSearchSpec();
614
+ spec.targetDocumentFilter = [ ':default', 'ABC' ];
615
+ const results = multiReportSearch.search(spec).map(r => r.fact.localId()).sort();
616
+ expect(results).toEqual(['item0', 'item1', 'item2', 'item3', 'item4', 'item5' ]);
617
+ });
618
+
619
+ });
@@ -68,8 +68,8 @@ class LocalDocuments {
68
68
  }
69
69
 
70
70
  export class DocumentSummary {
71
- constructor(report) {
72
- this._report = report;
71
+ constructor(reportSet) {
72
+ this._reportSet = reportSet;
73
73
  }
74
74
 
75
75
  _getTagCounter(tagCounts, element) {
@@ -86,21 +86,25 @@ export class DocumentSummary {
86
86
 
87
87
  _buildTagCounts() {
88
88
  const tagCounts = new Map();
89
- for (const fact of this._report.facts()) {
89
+ for (const fact of this._reportSet.facts()) {
90
90
  let counter = this._getTagCounter(tagCounts, fact.conceptName());
91
91
  counter.addPrimaryItem(fact.conceptName());
92
92
  for (const [dimension, member] of Object.entries(fact.dimensions())) {
93
93
  counter = this._getTagCounter(tagCounts, dimension);
94
94
  counter.addDimension(dimension);
95
95
 
96
- const dimensionConcept = this._report.getConcept(dimension);
97
- if (dimensionConcept.isTypedDimension()) {
96
+ const dimensionConcept = fact.report.getConcept(dimension);
97
+ if (!dimensionConcept.hasDefinition) {
98
+ console.log("Missing definition for dimension: " + dimension);
99
+ }
100
+ else if (dimensionConcept.isTypedDimension()) {
98
101
  const typedDomainElement = dimensionConcept.typedDomainElement();
99
102
  if (typedDomainElement) {
100
103
  counter = this._getTagCounter(tagCounts, typedDomainElement);
101
104
  counter.addMember(typedDomainElement);
102
105
  }
103
- } else {
106
+ }
107
+ else {
104
108
  counter = this._getTagCounter(tagCounts, member);
105
109
  counter.addMember(member);
106
110
  }
@@ -113,18 +117,32 @@ export class DocumentSummary {
113
117
 
114
118
  _buildLocalFileSummary() {
115
119
  this._localFileSummary = new LocalDocuments();
116
- for (const [document, documentTypes] of Object.entries(this._report.localDocuments())) {
120
+ for (const [document, documentTypes] of this._reportSet.reports.flatMap(r => Object.entries(r.localDocuments()))) {
117
121
  this._localFileSummary.addDocument(document, documentTypes);
118
122
  }
119
123
  }
120
124
 
121
125
  totalFacts() {
122
126
  if (this._totalFacts === undefined) {
123
- this._totalFacts = this._report.facts().length;
127
+ this._totalFacts = this._reportSet.facts().length;
124
128
  }
125
129
  return this._totalFacts;
126
130
  }
127
131
 
132
+ hiddenFacts() {
133
+ if (this._hiddenFacts === undefined) {
134
+ this._hiddenFacts = this._reportSet.facts().filter(f => f.isHidden()).length;
135
+ }
136
+ return this._hiddenFacts;
137
+ }
138
+
139
+ mandatoryFacts() {
140
+ if (this._mandatoryFacts === undefined) {
141
+ this._mandatoryFacts = this._reportSet.facts().filter(f => f.isMandatory()).length;
142
+ }
143
+ return this._mandatoryFacts;
144
+ }
145
+
128
146
  tagCounts() {
129
147
  if (this._tagCounts === undefined) {
130
148
  this._buildTagCounts();
@@ -138,4 +156,12 @@ export class DocumentSummary {
138
156
  }
139
157
  return this._localFileSummary.getDocuments()
140
158
  }
159
+
160
+
161
+ /**
162
+ * @return {Array[String]} Report set's list of software credit text values.
163
+ */
164
+ getSoftwareCredits() {
165
+ return this._reportSet.getSoftwareCredits();
166
+ }
141
167
  }