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.
- iXBRLViewerPlugin/__init__.py +231 -127
- iXBRLViewerPlugin/_version.py +33 -3
- iXBRLViewerPlugin/constants.py +96 -2
- iXBRLViewerPlugin/featureConfig.py +8 -1
- iXBRLViewerPlugin/iXBRLViewer.py +356 -214
- iXBRLViewerPlugin/plugin.py +12 -0
- iXBRLViewerPlugin/ui.py +81 -50
- iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
- iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt +12 -5
- iXBRLViewerPlugin/viewer/i18next-parser.config.js +1 -1
- iXBRLViewerPlugin/viewer/src/data/utr.json +1244 -0
- iXBRLViewerPlugin/viewer/src/html/fact-details.html +69 -38
- iXBRLViewerPlugin/viewer/src/html/footer-logo.html +4 -0
- iXBRLViewerPlugin/viewer/src/html/footnote-details.html +2 -2
- iXBRLViewerPlugin/viewer/src/html/inspector.html +352 -197
- iXBRLViewerPlugin/viewer/src/i18n/cy/balancetypes.json +1 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/scale.json +16 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/datatypes.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/labelroles.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/scale.json +16 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/translation.json +73 -23
- iXBRLViewerPlugin/viewer/src/i18n/es/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/datatypes.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/scale.json +16 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/translation.json +87 -37
- iXBRLViewerPlugin/viewer/src/i18n/fr/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/icons/calculator.svg +13 -0
- iXBRLViewerPlugin/viewer/src/icons/circle-cross.svg +11 -0
- iXBRLViewerPlugin/viewer/src/icons/circle-tick.svg +11 -0
- iXBRLViewerPlugin/viewer/src/icons/dark-mode.svg +4 -0
- iXBRLViewerPlugin/viewer/src/icons/dimension.svg +1 -5
- iXBRLViewerPlugin/viewer/src/icons/member.svg +2 -5
- iXBRLViewerPlugin/viewer/src/icons/multi-tag.svg +10 -0
- iXBRLViewerPlugin/viewer/src/img/arelle-dark.svg +179 -0
- iXBRLViewerPlugin/viewer/src/img/inline-viewer-dark.svg +59 -0
- iXBRLViewerPlugin/viewer/src/js/accordian.js +5 -4
- iXBRLViewerPlugin/viewer/src/js/aspect.js +29 -10
- iXBRLViewerPlugin/viewer/src/js/aspect.test.js +40 -31
- iXBRLViewerPlugin/viewer/src/js/balance.js +14 -0
- iXBRLViewerPlugin/viewer/src/js/calculation.js +213 -0
- iXBRLViewerPlugin/viewer/src/js/calculation.test.js +306 -0
- iXBRLViewerPlugin/viewer/src/js/calculationInspector.js +187 -0
- iXBRLViewerPlugin/viewer/src/js/chart.js +26 -24
- iXBRLViewerPlugin/viewer/src/js/chart.test.js +10 -9
- iXBRLViewerPlugin/viewer/src/js/concept.js +37 -4
- iXBRLViewerPlugin/viewer/src/js/concept.test.js +30 -6
- iXBRLViewerPlugin/viewer/src/js/datatype.js +20 -0
- iXBRLViewerPlugin/viewer/src/js/datatype.test.js +62 -0
- iXBRLViewerPlugin/viewer/src/js/dialog.js +6 -4
- iXBRLViewerPlugin/viewer/src/js/docOrderIndex.js +7 -7
- iXBRLViewerPlugin/viewer/src/js/fact.js +156 -59
- iXBRLViewerPlugin/viewer/src/js/fact.test.js +160 -29
- iXBRLViewerPlugin/viewer/src/js/factset.js +64 -15
- iXBRLViewerPlugin/viewer/src/js/factset.test.js +102 -31
- iXBRLViewerPlugin/viewer/src/js/footnote.js +8 -2
- iXBRLViewerPlugin/viewer/src/js/index.js +11 -3
- iXBRLViewerPlugin/viewer/src/js/inspector.js +747 -221
- iXBRLViewerPlugin/viewer/src/js/inspector.test.js +143 -25
- iXBRLViewerPlugin/viewer/src/js/interval.js +70 -0
- iXBRLViewerPlugin/viewer/src/js/interval.test.js +153 -0
- iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +391 -262
- iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js +134 -20
- iXBRLViewerPlugin/viewer/src/js/ixnode.js +1 -1
- iXBRLViewerPlugin/viewer/src/js/menu.js +25 -7
- iXBRLViewerPlugin/viewer/src/js/number-matcher.js +7 -3
- iXBRLViewerPlugin/viewer/src/js/number-matcher.test.js +4 -0
- iXBRLViewerPlugin/viewer/src/js/outline.js +34 -13
- iXBRLViewerPlugin/viewer/src/js/outline.test.js +97 -91
- iXBRLViewerPlugin/viewer/src/js/period.js +0 -1
- iXBRLViewerPlugin/viewer/src/js/report.js +260 -351
- iXBRLViewerPlugin/viewer/src/js/report.test.js +95 -27
- iXBRLViewerPlugin/viewer/src/js/reportset.js +264 -0
- iXBRLViewerPlugin/viewer/src/js/reportset.test.js +357 -0
- iXBRLViewerPlugin/viewer/src/js/search.js +72 -38
- iXBRLViewerPlugin/viewer/src/js/search.test.js +184 -84
- iXBRLViewerPlugin/viewer/src/js/summary.js +34 -8
- iXBRLViewerPlugin/viewer/src/js/summary.test.js +69 -25
- iXBRLViewerPlugin/viewer/src/js/tableExport.js +9 -9
- iXBRLViewerPlugin/viewer/src/js/taxonomynamer.js +34 -0
- iXBRLViewerPlugin/viewer/src/js/taxonomynamer.test.js +32 -0
- iXBRLViewerPlugin/viewer/src/js/test-utils.js +46 -0
- iXBRLViewerPlugin/viewer/src/js/theme.js +50 -0
- iXBRLViewerPlugin/viewer/src/js/unit.js +90 -32
- iXBRLViewerPlugin/viewer/src/js/unit.test.js +62 -25
- iXBRLViewerPlugin/viewer/src/js/util.js +94 -0
- iXBRLViewerPlugin/viewer/src/js/util.test.js +33 -1
- iXBRLViewerPlugin/viewer/src/js/utr.js +27 -0
- iXBRLViewerPlugin/viewer/src/js/viewer.js +205 -181
- iXBRLViewerPlugin/viewer/src/js/viewerOptions.js +0 -2
- iXBRLViewerPlugin/viewer/src/less/accordian.less +10 -6
- iXBRLViewerPlugin/viewer/src/less/block-list.less +16 -5
- iXBRLViewerPlugin/viewer/src/less/calculation-inspector.less +83 -0
- iXBRLViewerPlugin/viewer/src/less/chart.less +8 -5
- iXBRLViewerPlugin/viewer/src/less/colours-dark-mode.less +40 -0
- iXBRLViewerPlugin/viewer/src/less/colours.less +32 -20
- iXBRLViewerPlugin/viewer/src/less/common.less +3 -3
- iXBRLViewerPlugin/viewer/src/less/components.less +6 -4
- iXBRLViewerPlugin/viewer/src/less/core.less +2 -0
- iXBRLViewerPlugin/viewer/src/less/dialog.less +21 -14
- iXBRLViewerPlugin/viewer/src/less/form-controls.less +33 -11
- iXBRLViewerPlugin/viewer/src/less/inspector.less +1045 -726
- iXBRLViewerPlugin/viewer/src/less/loader.less +2 -2
- iXBRLViewerPlugin/viewer/src/less/menu.less +33 -15
- iXBRLViewerPlugin/viewer/src/less/summary.less +16 -6
- iXBRLViewerPlugin/viewer/src/less/tabs.less +9 -9
- iXBRLViewerPlugin/viewer/src/less/text-block-viewer.less +2 -0
- iXBRLViewerPlugin/viewer/src/less/text-mixins.less +2 -1
- iXBRLViewerPlugin/viewer/src/less/validation-report.less +2 -3
- iXBRLViewerPlugin/viewer/src/less/viewer.less +105 -74
- iXBRLViewerPlugin/viewer/webpack.common.js +19 -9
- iXBRLViewerPlugin/xhtmlserialize.py +59 -45
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/METADATA +181 -50
- ixbrl_viewer-1.4.86.dist-info/RECORD +217 -0
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/WHEEL +1 -1
- ixbrl_viewer-1.4.1.dist-info/LICENSE → ixbrl_viewer-1.4.86.dist-info/licenses/LICENSE.md +8 -14
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/top_level.txt +0 -1
- iXBRLViewerPlugin/viewer/src/js/calculations.js +0 -111
- iXBRLViewerPlugin/viewer/src/js/interact.min.js +0 -6
- ixbrl_viewer-1.4.1.dist-info/RECORD +0 -155
- tests/__init__.py +0 -0
- tests/puppeteer/framework/core_elements.js +0 -117
- tests/puppeteer/framework/page_objects/doc_frame.js +0 -105
- tests/puppeteer/framework/page_objects/fact_details_panel.js +0 -80
- tests/puppeteer/framework/page_objects/search_panel.js +0 -76
- tests/puppeteer/framework/page_objects/toolbar.js +0 -18
- tests/puppeteer/framework/utils.js +0 -3
- tests/puppeteer/framework/viewer_page.js +0 -103
- tests/puppeteer/puppeteer_test_run_via_intellij.jpg +0 -0
- tests/puppeteer/test_filings/filing_documents_smoke_test.zip +0 -0
- tests/puppeteer/test_filings/highlights.zip +0 -0
- tests/puppeteer/tests/fact_properties.test.js +0 -78
- tests/puppeteer/tests/highlight.test.js +0 -186
- tests/puppeteer/tests/search.test.js +0 -86
- tests/puppeteer/tools/generate.sh +0 -15
- tests/unit_tests/__init__.py +0 -0
- tests/unit_tests/iXBRLViewerPlugin/__init__.py +0 -0
- tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py +0 -39
- tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +0 -641
- tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py +0 -310
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/entry_points.txt +0 -0
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info/licenses}/NOTICE +0 -0
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
// See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
3
|
import { Fact } from "./fact.js";
|
|
4
|
-
import {
|
|
4
|
+
import { ReportSet } from "./reportset.js";
|
|
5
5
|
import { TestInspector } from "./test-utils.js";
|
|
6
|
+
import { NAMESPACE_ISO4217 } from "./util";
|
|
6
7
|
|
|
7
8
|
var testReportData = {
|
|
8
9
|
"prefixes": {
|
|
9
10
|
"eg": "http://www.example.com",
|
|
10
|
-
"
|
|
11
|
+
"aa": "http://www.example.com/aa",
|
|
12
|
+
"zz": "http://www.example.com/zz",
|
|
13
|
+
"iso4217": NAMESPACE_ISO4217,
|
|
11
14
|
"e": "http://example.com/entity",
|
|
12
15
|
},
|
|
13
16
|
"concepts": {
|
|
@@ -32,6 +35,14 @@ var testReportData = {
|
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
},
|
|
38
|
+
"eg:TextBlockConcept1": {
|
|
39
|
+
"labels": {
|
|
40
|
+
"std": {
|
|
41
|
+
"en": "Text block concept"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"t": true,
|
|
45
|
+
},
|
|
35
46
|
"eg:EnumConcept": {
|
|
36
47
|
"labels": {
|
|
37
48
|
"std": {
|
|
@@ -48,6 +59,30 @@ var testReportData = {
|
|
|
48
59
|
},
|
|
49
60
|
"d": "e"
|
|
50
61
|
},
|
|
62
|
+
"eg:Dimension2": {
|
|
63
|
+
"labels": {
|
|
64
|
+
"std": {
|
|
65
|
+
"en": "Dimension Two"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"d": "e"
|
|
69
|
+
},
|
|
70
|
+
"zz:Axis1": {
|
|
71
|
+
"labels": {
|
|
72
|
+
"std": {
|
|
73
|
+
"en": "Axis One"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"d": "e"
|
|
77
|
+
},
|
|
78
|
+
"aa:Dimension3": {
|
|
79
|
+
"labels": {
|
|
80
|
+
"std": {
|
|
81
|
+
"en": "Dimension Three"
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"d": "e"
|
|
85
|
+
},
|
|
51
86
|
"eg:Member1": {
|
|
52
87
|
"labels": {
|
|
53
88
|
"std": {
|
|
@@ -62,6 +97,20 @@ var testReportData = {
|
|
|
62
97
|
}
|
|
63
98
|
}
|
|
64
99
|
},
|
|
100
|
+
"eg:Member3": {
|
|
101
|
+
"labels": {
|
|
102
|
+
"std": {
|
|
103
|
+
"en": "Member Three"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"eg:Member4": {
|
|
108
|
+
"labels": {
|
|
109
|
+
"std": {
|
|
110
|
+
"en": "Member Four"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
65
114
|
"eg:UnlabelledMember": {
|
|
66
115
|
"labels": {
|
|
67
116
|
}
|
|
@@ -75,16 +124,16 @@ function testReport(facts, ixData) {
|
|
|
75
124
|
// Deep copy of standing data
|
|
76
125
|
var data = JSON.parse(JSON.stringify(testReportData));
|
|
77
126
|
data.facts = facts;
|
|
78
|
-
var
|
|
79
|
-
|
|
80
|
-
return
|
|
127
|
+
var reportSet = new ReportSet(data);
|
|
128
|
+
reportSet.setIXNodeMap(ixData);
|
|
129
|
+
return reportSet.reports[0];
|
|
81
130
|
}
|
|
82
131
|
|
|
83
132
|
function testFact(factData, ixData) {
|
|
84
133
|
factData.a = factData.a || {};
|
|
85
134
|
factData.a.c = factData.a.c || 'eg:Concept1';
|
|
86
135
|
ixData = ixData || {};
|
|
87
|
-
return new Fact(testReport({"f1": factData}, {"f1": ixData }), "f1");
|
|
136
|
+
return new Fact(testReport({"f1": factData}, {"f1": ixData }), "f1", factData);
|
|
88
137
|
}
|
|
89
138
|
|
|
90
139
|
var insp = new TestInspector();
|
|
@@ -108,7 +157,6 @@ describe("Simple fact properties", () => {
|
|
|
108
157
|
expect(f.isMonetaryValue()).toBeTruthy();
|
|
109
158
|
expect(f.readableValue()).toEqual("US $ 1,000");
|
|
110
159
|
expect(f.unit().value()).toEqual("iso4217:USD");
|
|
111
|
-
expect(f.measure()).toEqual("iso4217:USD");
|
|
112
160
|
expect(f.conceptQName().prefix).toEqual("eg");
|
|
113
161
|
expect(f.conceptQName().localname).toEqual("Concept1");
|
|
114
162
|
expect(f.conceptQName().namespace).toEqual("http://www.example.com");
|
|
@@ -128,9 +176,8 @@ describe("Simple fact properties", () => {
|
|
|
128
176
|
expect(f.isNumeric()).toBeTruthy();
|
|
129
177
|
expect(f.decimals()).toEqual(-3);
|
|
130
178
|
expect(f.isMonetaryValue()).toBeFalsy();
|
|
131
|
-
expect(f.readableValue()).toEqual("1,000
|
|
179
|
+
expect(f.readableValue()).toEqual("1,000 USD");
|
|
132
180
|
expect(f.unit().value()).toEqual("eg:USD");
|
|
133
|
-
expect(f.measure()).toEqual("eg:USD");
|
|
134
181
|
expect(f.conceptQName().prefix).toEqual("eg");
|
|
135
182
|
expect(f.conceptQName().localname).toEqual("Concept1");
|
|
136
183
|
expect(f.conceptQName().namespace).toEqual("http://www.example.com");
|
|
@@ -149,9 +196,8 @@ describe("Simple fact properties", () => {
|
|
|
149
196
|
expect(f.decimals()).toBeUndefined();
|
|
150
197
|
expect(f.isNumeric()).toBeTruthy();
|
|
151
198
|
expect(f.isMonetaryValue()).toBeFalsy();
|
|
152
|
-
expect(f.readableValue()).toEqual("1,000,000.0125
|
|
199
|
+
expect(f.readableValue()).toEqual("1,000,000.0125 USD");
|
|
153
200
|
expect(f.unit().value()).toEqual("eg:USD");
|
|
154
|
-
expect(f.measure()).toEqual("eg:USD");
|
|
155
201
|
expect(f.conceptQName().prefix).toEqual("eg");
|
|
156
202
|
expect(f.conceptQName().localname).toEqual("Concept1");
|
|
157
203
|
expect(f.conceptQName().namespace).toEqual("http://www.example.com");
|
|
@@ -539,7 +585,7 @@ describe("Readable value", () => {
|
|
|
539
585
|
test("Other numeric", () => {
|
|
540
586
|
|
|
541
587
|
expect(testFact({ "v": "10", d: -2, a: { u: "xbrli:foo" } }).readableValue())
|
|
542
|
-
.toBe("10
|
|
588
|
+
.toBe("10 foo");
|
|
543
589
|
|
|
544
590
|
});
|
|
545
591
|
|
|
@@ -552,20 +598,43 @@ describe("Readable value", () => {
|
|
|
552
598
|
|
|
553
599
|
});
|
|
554
600
|
|
|
555
|
-
test("
|
|
601
|
+
test("Escaped string", () => {
|
|
556
602
|
|
|
557
603
|
expect(testFact({ "v": "<b>foo</b>" }, {"escaped": true }).readableValue())
|
|
558
|
-
.toBe("foo");
|
|
604
|
+
.toBe("<b>foo</b>");
|
|
559
605
|
|
|
560
606
|
expect(testFact({ "v": " <b>foo</b>bar" }, {"escaped": true }).readableValue())
|
|
561
|
-
.toBe("
|
|
607
|
+
.toBe(" <b>foo</b>bar");
|
|
562
608
|
|
|
563
609
|
expect(testFact({ "v": "\u00a0<b>foo</b>" }, {"escaped": true }).readableValue())
|
|
610
|
+
.toBe("\u00a0<b>foo</b>");
|
|
611
|
+
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
test("Strip HTML tags and normalise whitespace", () => {
|
|
615
|
+
|
|
616
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "<b>foo</b>" }, {"escaped": true }).readableValue())
|
|
617
|
+
.toBe("foo");
|
|
618
|
+
|
|
619
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": " <b>foo</b>bar" }, {"escaped": true }).readableValue())
|
|
620
|
+
.toBe("foobar");
|
|
621
|
+
|
|
622
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "\u00a0<b>foo</b>" }, {"escaped": true }).readableValue())
|
|
623
|
+
.toBe("foo");
|
|
624
|
+
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
test("Strip non-escaped text block facts", () => {
|
|
628
|
+
|
|
629
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "\u00a0<b>foo</b>" }, {"escaped": false }).readableValue())
|
|
630
|
+
.toBe("foo");
|
|
631
|
+
|
|
632
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "\u00a0<b>foo</b>" }, { }).readableValue())
|
|
564
633
|
.toBe("foo");
|
|
565
634
|
|
|
566
635
|
});
|
|
567
636
|
|
|
568
|
-
test("Don't strip non-
|
|
637
|
+
test("Don't strip non-text-block facts", () => {
|
|
569
638
|
|
|
570
639
|
expect(testFact({ "v": "\u00a0<b>foo</b>" }, {"escaped": false }).readableValue())
|
|
571
640
|
.toBe("\u00a0<b>foo</b>");
|
|
@@ -576,40 +645,40 @@ describe("Readable value", () => {
|
|
|
576
645
|
});
|
|
577
646
|
|
|
578
647
|
test("Detect and strip HTML tags - XHTML tags and attributes", () => {
|
|
579
|
-
expect(testFact({ "v": "<xhtml:b>foo</xhtml:b>" }, {"escaped": true }).readableValue())
|
|
648
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "<xhtml:b>foo</xhtml:b>" }, {"escaped": true }).readableValue())
|
|
580
649
|
.toBe("foo");
|
|
581
650
|
|
|
582
|
-
expect(testFact({ "v": '<xhtml:span style="font-weight: bold">foo</xhtml:span>' }, {"escaped": true }).readableValue())
|
|
651
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": '<xhtml:span style="font-weight: bold">foo</xhtml:span>' }, {"escaped": true }).readableValue())
|
|
583
652
|
.toBe("foo");
|
|
584
653
|
});
|
|
585
654
|
|
|
586
655
|
test("Detect and strip HTML tags - check behaviour with invalid HTML", () => {
|
|
587
656
|
/* Invalid HTML */
|
|
588
|
-
expect(testFact({ "v": "<b:b:b>foo</b:b:b>" }, {"escaped": true }).readableValue())
|
|
657
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "<b:b:b>foo</b:b:b>" }, {"escaped": true }).readableValue())
|
|
589
658
|
.toBe("foo");
|
|
590
659
|
|
|
591
|
-
expect(testFact({ "v": "<foo<bar>baz</bar>" }, {"escaped": true }).readableValue())
|
|
660
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "<foo<bar>baz</bar>" }, {"escaped": true }).readableValue())
|
|
592
661
|
.toBe("baz");
|
|
593
662
|
});
|
|
594
663
|
|
|
595
664
|
test("Text in consecutive inline elements should be contiguous", () => {
|
|
596
665
|
|
|
597
|
-
expect(testFact({ "v": "<b>foo</b><i>bar</i>" }, {"escaped":true }).readableValue())
|
|
666
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "<b>foo</b><i>bar</i>" }, {"escaped":true }).readableValue())
|
|
598
667
|
.toBe("foobar");
|
|
599
668
|
|
|
600
669
|
});
|
|
601
670
|
|
|
602
671
|
test("Text in block/table elements should be separated.", () => {
|
|
603
672
|
|
|
604
|
-
expect(testFact({ "v": "<p>foo</p><p>bar</p>" }, {"escaped":true }).readableValue())
|
|
673
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "<p>foo</p><p>bar</p>" }, {"escaped":true }).readableValue())
|
|
605
674
|
.toBe("foo bar");
|
|
606
675
|
|
|
607
676
|
/* This should really return "foo bar", but we don't correctly detect
|
|
608
677
|
* block tags in prefixed XHTML */
|
|
609
|
-
expect(testFact({ "v": '<xhtml:p xmlns:xhtml="https://www.w3.org/1999/xhtml/">foo</xhtml:p><xhtml:p>bar</xhtml:p>' }, {"escaped":true }).readableValue())
|
|
678
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": '<xhtml:p xmlns:xhtml="https://www.w3.org/1999/xhtml/">foo</xhtml:p><xhtml:p>bar</xhtml:p>' }, {"escaped":true }).readableValue())
|
|
610
679
|
.toBe("foobar");
|
|
611
680
|
|
|
612
|
-
expect(testFact({ "v": "<table><tr><td>cell1</td><td>cell2</td></tr></table>" }, {"escaped":true })
|
|
681
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "<table><tr><td>cell1</td><td>cell2</td></tr></table>" }, {"escaped":true })
|
|
613
682
|
.readableValue())
|
|
614
683
|
.toBe("cell1 cell2");
|
|
615
684
|
|
|
@@ -617,7 +686,7 @@ describe("Readable value", () => {
|
|
|
617
686
|
|
|
618
687
|
test("Whitespace normalisation", () => {
|
|
619
688
|
|
|
620
|
-
expect(testFact({ "v": "<p>bar foo</p> <p>bar</p>" }, {"escaped":true }).readableValue())
|
|
689
|
+
expect(testFact({ "a": { "c": "eg:TextBlockConcept1" }, "v": "<p>bar foo</p> <p>bar</p>" }, {"escaped":true }).readableValue())
|
|
621
690
|
.toBe("bar foo bar");
|
|
622
691
|
|
|
623
692
|
});
|
|
@@ -635,8 +704,7 @@ describe("Unit aspect handling", () => {
|
|
|
635
704
|
expect(f.isNumeric()).toBeTruthy();
|
|
636
705
|
expect(f.isMonetaryValue()).toBeFalsy();
|
|
637
706
|
expect(f.unit()).toBeUndefined();
|
|
638
|
-
expect(f.
|
|
639
|
-
expect(f.measureLabel()).toBe("<NOUNIT>");
|
|
707
|
+
expect(f.unitLabel()).toBe("<NOUNIT>");
|
|
640
708
|
});
|
|
641
709
|
|
|
642
710
|
test("Non-numeric, no unit", () => {
|
|
@@ -647,7 +715,6 @@ describe("Unit aspect handling", () => {
|
|
|
647
715
|
});
|
|
648
716
|
expect(f.isNumeric()).toBeFalsy();
|
|
649
717
|
expect(f.unit()).toBeUndefined();
|
|
650
|
-
expect(f.measure()).toBeUndefined();
|
|
651
718
|
});
|
|
652
719
|
});
|
|
653
720
|
|
|
@@ -663,10 +730,13 @@ describe("Get Label", () => {
|
|
|
663
730
|
|
|
664
731
|
test("Get standard label", () => {
|
|
665
732
|
expect(f.getLabel("std")).toEqual("English label")
|
|
733
|
+
expect(f.getLabelAndLang("std").label).toEqual("English label")
|
|
734
|
+
expect(f.getLabelAndLang("std").lang).toEqual("en")
|
|
666
735
|
});
|
|
667
736
|
|
|
668
737
|
test("Get non-existent label", () => {
|
|
669
738
|
expect(f.getLabel("doc")).toBeUndefined();
|
|
739
|
+
expect(f.getLabelAndLang("doc").label).toBeUndefined();
|
|
670
740
|
});
|
|
671
741
|
|
|
672
742
|
});
|
|
@@ -690,6 +760,68 @@ describe("Aspect methods", () => {
|
|
|
690
760
|
});
|
|
691
761
|
});
|
|
692
762
|
|
|
763
|
+
describe("Aspect sorting", () => {
|
|
764
|
+
var f = testFact({
|
|
765
|
+
"d": -3,
|
|
766
|
+
"v": 1000,
|
|
767
|
+
"a": {
|
|
768
|
+
"c": "eg:Concept1",
|
|
769
|
+
"u": "iso4217:USD",
|
|
770
|
+
"p": "2018-01-01/2019-01-01",
|
|
771
|
+
"eg:Dimension2": "eg:Member1",
|
|
772
|
+
"aa:Dimension3": "eg:Member2",
|
|
773
|
+
"zz:Axis1": "eg:Member3",
|
|
774
|
+
"eg:Dimension1": "eg:Member4"
|
|
775
|
+
}});
|
|
776
|
+
test("Fact.aspects() is sorted", () => {
|
|
777
|
+
expect(f.aspects().length).toEqual(7);
|
|
778
|
+
expect(f.aspects().filter(a => a.isTaxonomyDefined()).length).toEqual(4);
|
|
779
|
+
|
|
780
|
+
expect(f.aspects().filter(a => a.isTaxonomyDefined())[0].name()).toEqual("aa:Dimension3");
|
|
781
|
+
expect(f.aspects().filter(a => a.isTaxonomyDefined())[0].label()).toEqual("Dimension Three");
|
|
782
|
+
expect(f.aspects().filter(a => a.isTaxonomyDefined())[0].value()).toEqual("eg:Member2");
|
|
783
|
+
expect(f.aspects().filter(a => a.isTaxonomyDefined())[0].valueLabel()).toEqual("Member Two");
|
|
784
|
+
|
|
785
|
+
expect(f.aspects().filter(a => a.isTaxonomyDefined()).at(-1).label()).toEqual("Axis One");
|
|
786
|
+
expect(f.aspects().filter(a => a.isTaxonomyDefined()).at(-1).valueLabel()).toEqual("Member Three");
|
|
787
|
+
|
|
788
|
+
expect(f.aspects().filter(a => a.isTaxonomyDefined()).map(k => k.name())).toEqual(["aa:Dimension3", "eg:Dimension1", "eg:Dimension2", "zz:Axis1"]);
|
|
789
|
+
expect(f.aspects().filter(a => !a.isTaxonomyDefined()).map(k => k.name())).toEqual(["c", "p", "u"]);
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
describe("Aspect sorting consistent between facts", () => {
|
|
794
|
+
var fact1 = testFact({
|
|
795
|
+
"d": -3,
|
|
796
|
+
"v": 1000,
|
|
797
|
+
"a": {
|
|
798
|
+
"c": "eg:Concept1",
|
|
799
|
+
"u": "iso4217:USD",
|
|
800
|
+
"p": "2018-01-01/2019-01-01",
|
|
801
|
+
"eg:Dimension2": "eg:Member1",
|
|
802
|
+
"aa:Dimension3": "eg:Member2",
|
|
803
|
+
"zz:Axis1": "eg:Member3",
|
|
804
|
+
"eg:Dimension1": "eg:Member4"
|
|
805
|
+
}});
|
|
806
|
+
var fact2 = testFact({
|
|
807
|
+
"d": -3,
|
|
808
|
+
"v": 1001,
|
|
809
|
+
"a": {
|
|
810
|
+
"c": "eg:Concept2",
|
|
811
|
+
"u": "iso4217:USD",
|
|
812
|
+
"p": "2018-01-01/2019-01-01",
|
|
813
|
+
"zz:Axis1": "eg:Member1",
|
|
814
|
+
"eg:Dimension2": "eg:Member2",
|
|
815
|
+
"aa:Dimension3": "eg:Member3",
|
|
816
|
+
"eg:Dimension1": "eg:Member4"
|
|
817
|
+
}});
|
|
818
|
+
test("fact1 dims are sorted as expected and in exactly the same order as fact2 dims", () => {
|
|
819
|
+
expect(fact1.aspects().filter(a => a.isTaxonomyDefined()).map(k => k.name())).toEqual(["aa:Dimension3", "eg:Dimension1", "eg:Dimension2", "zz:Axis1"]);
|
|
820
|
+
expect(fact1.aspects().filter(a => a.isTaxonomyDefined()).map(k => k.name())).toEqual(fact2.aspects().filter(a => a.isTaxonomyDefined()).map(k => k.name()));
|
|
821
|
+
});
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
|
|
693
825
|
describe("Fact errors", () => {
|
|
694
826
|
test("iXBRL Invalid", () => {
|
|
695
827
|
var f = testFact({
|
|
@@ -707,7 +839,6 @@ describe("Fact errors", () => {
|
|
|
707
839
|
expect(f.isMonetaryValue()).toBeTruthy();
|
|
708
840
|
expect(f.readableValue()).toEqual("Invalid value");
|
|
709
841
|
expect(f.unit().value()).toEqual("iso4217:USD");
|
|
710
|
-
expect(f.measure()).toEqual("iso4217:USD");
|
|
711
842
|
expect(f.conceptQName().prefix).toEqual("eg");
|
|
712
843
|
expect(f.conceptQName().localname).toEqual("Concept1");
|
|
713
844
|
expect(f.conceptQName().namespace).toEqual("http://www.example.com");
|
|
@@ -2,18 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
import { Fact } from "./fact.js";
|
|
4
4
|
import { Footnote } from "./footnote.js";
|
|
5
|
+
import { Interval } from './interval.js';
|
|
5
6
|
|
|
6
7
|
export class FactSet {
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
constructor (items) {
|
|
10
|
+
this.itemMap = new Map();
|
|
11
|
+
for (const item of items ?? []) {
|
|
12
|
+
this.add(item)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
add(item) {
|
|
17
|
+
this.itemMap.set(item.vuid, item);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
items() {
|
|
21
|
+
return Array.from(this.itemMap.values());
|
|
9
22
|
}
|
|
10
23
|
|
|
11
24
|
/* Returns the union of dimensions present on facts in the set */
|
|
12
25
|
_allDimensions() {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
for (
|
|
16
|
-
|
|
26
|
+
const dims = {};
|
|
27
|
+
const facts = this.items().filter((item) => item instanceof Fact);
|
|
28
|
+
for (const fact of facts) {
|
|
29
|
+
const dd = Object.keys(fact.dimensions());
|
|
17
30
|
for (var j = 0; j < dd.length; j++) {
|
|
18
31
|
dims[dd[j]] = true;
|
|
19
32
|
}
|
|
@@ -30,17 +43,17 @@ export class FactSet {
|
|
|
30
43
|
*/
|
|
31
44
|
minimallyUniqueLabel(fact) {
|
|
32
45
|
if (!this._minimallyUniqueLabels) {
|
|
33
|
-
var facts = this.
|
|
46
|
+
var facts = this.items().filter((item) => item instanceof Fact);
|
|
34
47
|
var allLabels = {};
|
|
35
48
|
var allAspects = ["c", "p"].concat(this._allDimensions());
|
|
36
49
|
/* Assemble a map of arrays of all aspect labels for all facts, in a
|
|
37
50
|
* consistent order */
|
|
38
51
|
for (var i = 0; i < facts.length; i++) {
|
|
39
52
|
var f = facts[i];
|
|
40
|
-
allLabels[f.
|
|
53
|
+
allLabels[f.vuid] = [];
|
|
41
54
|
for (var j = 0; j < allAspects.length; j++) {
|
|
42
55
|
var dd = f.aspect(allAspects[j]);
|
|
43
|
-
allLabels[f.
|
|
56
|
+
allLabels[f.vuid].push(dd ? dd.valueLabel() : null);
|
|
44
57
|
}
|
|
45
58
|
}
|
|
46
59
|
/* Iterate each aspect label and compare that label across all facts in
|
|
@@ -49,7 +62,7 @@ export class FactSet {
|
|
|
49
62
|
for (var j = 0; j < allAspects.length; j++) {
|
|
50
63
|
var labelMap = {};
|
|
51
64
|
for (var i = 0; i < facts.length; i++) {
|
|
52
|
-
labelMap[allLabels[facts[i].
|
|
65
|
+
labelMap[allLabels[facts[i].vuid][j]] = true;
|
|
53
66
|
}
|
|
54
67
|
|
|
55
68
|
var uniqueLabelsByLabel = {};
|
|
@@ -57,7 +70,7 @@ export class FactSet {
|
|
|
57
70
|
/* We have at least two different labels, so include this
|
|
58
71
|
* aspect in the label for all facts in the set */
|
|
59
72
|
for (var i = 0; i < facts.length; i++) {
|
|
60
|
-
var fid = facts[i].
|
|
73
|
+
var fid = facts[i].vuid;
|
|
61
74
|
var l = allLabels[fid][j];
|
|
62
75
|
var ul = uniqueLabels[fid] || [];
|
|
63
76
|
if (l !== null) {
|
|
@@ -79,19 +92,55 @@ export class FactSet {
|
|
|
79
92
|
* of them */
|
|
80
93
|
if (Object.keys(uniqueLabels).length < facts.length) {
|
|
81
94
|
for (var i = 0; i < facts.length; i++) {
|
|
82
|
-
var fid = facts[i].
|
|
95
|
+
var fid = facts[i].vuid;
|
|
83
96
|
var ul = uniqueLabels[fid] || [];
|
|
84
97
|
ul.unshift(allLabels[fid][0]);
|
|
85
98
|
uniqueLabels[fid] = ul;
|
|
86
99
|
}
|
|
87
100
|
}
|
|
88
101
|
|
|
89
|
-
this.
|
|
90
|
-
uniqueLabels[fn.
|
|
102
|
+
this.items().filter((item) => item instanceof Footnote).forEach((fn) => {
|
|
103
|
+
uniqueLabels[fn.vuid] = [fn.title];
|
|
91
104
|
});
|
|
92
105
|
|
|
93
106
|
this._minimallyUniqueLabels = uniqueLabels;
|
|
94
107
|
}
|
|
95
|
-
return this._minimallyUniqueLabels[fact.
|
|
108
|
+
return this._minimallyUniqueLabels[fact.vuid].join(", ");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
isEmpty() {
|
|
112
|
+
return this.itemMap.size == 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/*
|
|
116
|
+
* Returns an Interval for the intersection of all values in the set, or
|
|
117
|
+
* undefined if there is no intersection (inconsistent duplicates)
|
|
118
|
+
*/
|
|
119
|
+
valueIntersection() {
|
|
120
|
+
const duplicates = this.items().map(fact => Interval.fromFact(fact));
|
|
121
|
+
return Interval.intersection(...duplicates);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
completeDuplicates() {
|
|
125
|
+
return this.items().every(f => f.isCompleteDuplicate(this.items()[0]));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
isConsistent() {
|
|
129
|
+
if (this.itemMap.size == 0) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
const duplicates = this.items().map(fact => Interval.fromFact(fact));
|
|
133
|
+
return Interval.intersection(...duplicates) !== undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
size() {
|
|
137
|
+
return this.itemMap.size;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* Return the most precise (highest decimals) value within the set.
|
|
142
|
+
*/
|
|
143
|
+
mostPrecise() {
|
|
144
|
+
return this.items().reduce((a, b) => b.isMorePrecise(a) ? b : a);
|
|
96
145
|
}
|
|
97
146
|
}
|