sec-edgar-api 0.2.4 → 0.3.1

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 (42) hide show
  1. package/README.md +1 -0
  2. package/build/services/DocumentParser/DocumentParser.d.ts +12 -0
  3. package/build/services/DocumentParser/DocumentParser.js +3 -0
  4. package/build/services/DocumentParser/parsers/index.d.ts +2 -0
  5. package/build/services/DocumentParser/parsers/index.js +2 -0
  6. package/build/services/DocumentParser/parsers/parse-current-filings-daily.d.ts +13 -0
  7. package/build/services/DocumentParser/parsers/parse-current-filings-daily.js +37 -0
  8. package/build/services/ReportParser/ReportParser.d.ts +10 -14
  9. package/build/services/ReportParser/ReportParser.js +17 -24
  10. package/build/services/ReportRawBuilder/FactGrouper.d.ts +27 -0
  11. package/build/services/ReportRawBuilder/FactGrouper.js +206 -0
  12. package/build/services/{ReportBuilder → ReportRawBuilder}/FactPeriodResolver.d.ts +46 -2
  13. package/build/services/{ReportBuilder → ReportRawBuilder}/FactPeriodResolver.js +82 -20
  14. package/build/services/ReportRawBuilder/FactRecordBuilder.d.ts +9 -0
  15. package/build/services/{ReportBuilder → ReportRawBuilder}/FactRecordBuilder.js +6 -24
  16. package/build/services/ReportRawBuilder/FactSplitAdjuster.d.ts +43 -0
  17. package/build/services/ReportRawBuilder/FactSplitAdjuster.js +242 -0
  18. package/build/services/ReportRawBuilder/ReportRawBuilder.d.ts +39 -0
  19. package/build/services/ReportRawBuilder/ReportRawBuilder.js +158 -0
  20. package/build/services/ReportRawBuilder/index.d.ts +2 -0
  21. package/build/services/ReportRawBuilder/index.js +4 -0
  22. package/build/services/SecEdgarApi/SecEdgarApi.d.ts +32 -5
  23. package/build/services/SecEdgarApi/SecEdgarApi.js +65 -13
  24. package/build/types/common.type.d.ts +41 -0
  25. package/build/types/company-facts.type.d.ts +29 -2
  26. package/build/types/parsed-filings.type.d.ts +1 -0
  27. package/package.json +1 -1
  28. package/build/services/ReportBuilder/FactRecordBuilder.d.ts +0 -10
  29. package/build/services/ReportBuilder/FactSplitAdjuster.d.ts +0 -50
  30. package/build/services/ReportBuilder/FactSplitAdjuster.js +0 -214
  31. package/build/services/ReportBuilder/ReportBuilder.d.ts +0 -40
  32. package/build/services/ReportBuilder/ReportBuilder.js +0 -200
  33. package/build/services/ReportBuilder/ReportRawResolvable.d.ts +0 -17
  34. package/build/services/ReportBuilder/ReportRawResolvable.js +0 -114
  35. package/build/services/ReportBuilder/index.d.ts +0 -2
  36. package/build/services/ReportBuilder/index.js +0 -4
  37. package/build/services/ReportParser/ReportRawParser.d.ts +0 -5
  38. package/build/services/ReportParser/ReportRawParser.js +0 -14
  39. package/build/util/calculation-map-by-ns.d.ts +0 -6
  40. package/build/util/calculation-map-by-ns.js +0 -9
  41. /package/build/services/{ReportBuilder → ReportRawBuilder}/FactFiscalCalculator.d.ts +0 -0
  42. /package/build/services/{ReportBuilder → ReportRawBuilder}/FactFiscalCalculator.js +0 -0
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- var ReportRawResolvable_1 = require("./ReportRawResolvable");
4
3
  /**
5
4
  * Resolves quarterly and annual values for a property. This is because filers provide total values for the
6
5
  * current fiscal year, rather than values for the individual quarters
@@ -21,9 +20,34 @@ var FactPeriodResolver = /** @class */ (function () {
21
20
  /** prevent values from being added multiple times */
22
21
  this.resolvedValues = new Set();
23
22
  this.unresolvedReports = new Map();
24
- var cik = args.cik;
23
+ var cik = args.cik, _a = args.preferOriginalFilingValues, preferOriginalFilingValues = _a === void 0 ? false : _a;
25
24
  this.cik = cik;
25
+ this.preferOriginalFilingValues = preferOriginalFilingValues;
26
26
  }
27
+ /**
28
+ * Some properties have a start and end that represent a period average, rather than a period total.
29
+ * These properties should be treated as instantaneous properties, meaning
30
+ * the value for Q4 and FY should be the same.
31
+ *
32
+ * I believe the only properties like this are share related:
33
+ * us-gaap:WeightedAverageNumberOfDilutedSharesOutstanding and us-gaap:WeightedAverageNumberOfSharesOutstandingBasic.
34
+ * May need to update this in the future if there are more
35
+ */
36
+ FactPeriodResolver.isAverageShares = function (params) {
37
+ var propertyName = params.propertyName;
38
+ return (propertyName.includes('Average') &&
39
+ (propertyName.includes('SharesOutstanding') || propertyName.includes('SharesIssued')));
40
+ };
41
+ FactPeriodResolver.prototype.isAverageShares = function (params) {
42
+ return FactPeriodResolver.isAverageShares(params);
43
+ };
44
+ /**
45
+ * Used to check if this should potentially overwrite a value that has already been set.
46
+ */
47
+ FactPeriodResolver.prototype.isPreferredValue = function (params) {
48
+ var bucket = params.bucket, end = params.end, filed = params.filed, bucketIndex = params.bucketIndex;
49
+ return !bucket.has(bucketIndex) || this.preferOriginalFilingValues || !this.isOriginalFiling({ end: end, filed: filed });
50
+ };
27
51
  FactPeriodResolver.prototype.getOrSetBucketArr = function (map, year, propertyName) {
28
52
  var _a, _b;
29
53
  var propertyMap = (_a = map.get(year)) !== null && _a !== void 0 ? _a : map.set(year, new Map()).get(year);
@@ -49,8 +73,8 @@ var FactPeriodResolver = /** @class */ (function () {
49
73
  var reportKey = "".concat(year, "_").concat(i + 1);
50
74
  var unresolvedReport = this.unresolvedReports.get(reportKey);
51
75
  var unresolvedReportPrev = this.unresolvedReports.get("".concat(year, "_").concat(i));
52
- var sumValue = (_b = unresolvedReport === null || unresolvedReport === void 0 ? void 0 : unresolvedReport.getNumber(propertyName)) !== null && _b !== void 0 ? _b : 0;
53
- var prevSum = (_c = unresolvedReportPrev === null || unresolvedReportPrev === void 0 ? void 0 : unresolvedReportPrev.getNumber(propertyName)) !== null && _c !== void 0 ? _c : 0;
76
+ var sumValue = (_b = unresolvedReport === null || unresolvedReport === void 0 ? void 0 : unresolvedReport[propertyName]) !== null && _b !== void 0 ? _b : 0;
77
+ var prevSum = (_c = unresolvedReportPrev === null || unresolvedReportPrev === void 0 ? void 0 : unresolvedReportPrev[propertyName]) !== null && _c !== void 0 ? _c : 0;
54
78
  if (quarterValue === undefined) {
55
79
  var bucketQuarter_1 = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYear, year, propertyName);
56
80
  bucketQuarter_1.set(i, (Number(sumValue) || 0) - (Number(prevSum) || 0));
@@ -82,7 +106,13 @@ var FactPeriodResolver = /** @class */ (function () {
82
106
  var bucketString = (_g = (_f = this.valueByQuarterByPropertyByYearString.get(year)) === null || _f === void 0 ? void 0 : _f.get(propertyName)) !== null && _g !== void 0 ? _g : new Map();
83
107
  return { bucketQuarter: bucketQuarter, bucketSum: bucketSum, bucketString: bucketString };
84
108
  };
85
- FactPeriodResolver.prototype.getPeriod = function (params) {
109
+ /**
110
+ * 0, 3, 6, 9, or 12 month period. 0 is instantaneous data that doesn't have a time period, (ex: assets)
111
+ * other facts have values that are for a period of time. (like revenue over the last 6 months).
112
+ *
113
+ * Use periods 0 and 3 for quarterly reports and 0 and 12 for annual reports.
114
+ */
115
+ FactPeriodResolver.getPeriod = function (params) {
86
116
  var start = params.start, end = params.end;
87
117
  if (!start || start === end)
88
118
  return 0;
@@ -96,11 +126,14 @@ var FactPeriodResolver = /** @class */ (function () {
96
126
  return 9;
97
127
  return 12;
98
128
  };
129
+ FactPeriodResolver.prototype.getPeriod = function (params) {
130
+ return FactPeriodResolver.getPeriod(params);
131
+ };
99
132
  FactPeriodResolver.prototype.getOrSetReport = function (params) {
100
133
  var _a;
101
134
  var year = params.year, quarter = params.quarter;
102
135
  var key = "".concat(year, "_").concat(quarter);
103
- var report = (_a = this.unresolvedReports.get(key)) !== null && _a !== void 0 ? _a : new ReportRawResolvable_1.default({
136
+ var report = (_a = this.unresolvedReports.get(key)) !== null && _a !== void 0 ? _a : {
104
137
  cik: this.cik,
105
138
  fiscalYear: year,
106
139
  fiscalPeriod: quarter === 4 ? 'FY' : "Q".concat(quarter),
@@ -109,35 +142,54 @@ var FactPeriodResolver = /** @class */ (function () {
109
142
  url: null,
110
143
  splitDate: null,
111
144
  splitRatio: null,
112
- });
145
+ };
113
146
  if (!this.unresolvedReports.has(key)) {
114
147
  this.unresolvedReports.set(key, report);
115
148
  }
116
149
  return report;
117
150
  };
151
+ /**
152
+ * True if the filed date is within 60 days of the end date. This indicates that it is likely
153
+ * the original filing of the fact because filers are required to submit within 45 days of the
154
+ * period end, and subsequent reports are filed 90 days apart.
155
+ */
156
+ FactPeriodResolver.prototype.isOriginalFiling = function (params) {
157
+ var end = params.end, filed = params.filed;
158
+ var DAY_60_MS = 5184000000;
159
+ return new Date(filed).getTime() - new Date(end).getTime() < DAY_60_MS;
160
+ };
118
161
  FactPeriodResolver.prototype.add = function (params) {
119
162
  var year = params.year, value = params.value, propertyName = params.name, quarter = params.quarter, start = params.start, end = params.end, filed = params.filed;
120
- var period = this.getPeriod({ start: start, end: end });
163
+ var bucketIndex = quarter - 1;
164
+ var period = this.isAverageShares({ propertyName: propertyName }) ? 0 : this.getPeriod({ start: start, end: end });
121
165
  this.addPropertyByYear(this.propertiesByYear, year, propertyName);
122
166
  if (typeof value === 'string') {
123
167
  var bucket = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYearString, year, propertyName);
124
- bucket.set(quarter - 1, value);
168
+ if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
169
+ bucket.set(bucketIndex, value);
170
+ }
125
171
  return;
126
172
  }
127
173
  if (period === 0) {
128
174
  var bucket = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYear, year, propertyName);
129
175
  var bucketSum = this.getOrSetBucketArr(this.sumByQuarterByPropertyByYear, year, propertyName);
130
- bucket.set(quarter - 1, value);
131
- bucketSum.set(quarter - 1, value);
176
+ if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
177
+ bucket.set(bucketIndex, value);
178
+ bucketSum.set(bucketIndex, value);
179
+ }
132
180
  return;
133
181
  }
134
182
  if (period === 3) {
135
183
  var bucket = this.getOrSetBucketArr(this.valueByQuarterByPropertyByYear, year, propertyName);
136
- bucket.set(quarter - 1, value);
184
+ if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
185
+ bucket.set(bucketIndex, value);
186
+ }
137
187
  }
138
188
  if (quarter === 1 || period > 3) {
139
189
  var bucket = this.getOrSetBucketArr(this.sumByQuarterByPropertyByYear, year, propertyName);
140
- bucket.set(quarter - 1, value);
190
+ if (this.isPreferredValue({ bucket: bucket, bucketIndex: bucketIndex, end: end, filed: filed })) {
191
+ bucket.set(bucketIndex, value);
192
+ }
141
193
  }
142
194
  this.addPropertyByYear(this.propertiesResolvableByYear, year, propertyName);
143
195
  };
@@ -163,7 +215,7 @@ var FactPeriodResolver = /** @class */ (function () {
163
215
  if (value === undefined)
164
216
  continue;
165
217
  var report = _this.getOrSetReport({ year: year, quarter: i + 1 });
166
- report.report[propertyName] = value;
218
+ report[propertyName] = value;
167
219
  }
168
220
  });
169
221
  });
@@ -173,14 +225,24 @@ var FactPeriodResolver = /** @class */ (function () {
173
225
  this.buildUnresolvedReports();
174
226
  this.propertiesByYear.forEach(function (properties, year) {
175
227
  properties.forEach(function (propertyName) {
176
- var _a;
228
+ var _a, _b;
177
229
  _this.resolveValues(propertyName, year);
178
- for (var i = 0; i < 5; i++) {
230
+ for (var i = 0; i < 4; i++) {
179
231
  var isAnnual = i === 4;
180
- var _b = _this.getPropertyBuckets(year, propertyName), bucketQuarter = _b.bucketQuarter, bucketSum = _b.bucketSum, bucketString = _b.bucketString;
181
- var value = (_a = (isAnnual ? bucketSum.get(3) : bucketQuarter.get(i))) !== null && _a !== void 0 ? _a : bucketString.get(i);
182
- var fiscalPeriod = isAnnual ? 'FY' : "Q".concat(i + 1);
183
- callback({ year: year, fiscalPeriod: fiscalPeriod, propertyName: propertyName, value: value });
232
+ var _c = _this.getPropertyBuckets(year, propertyName), bucketQuarter = _c.bucketQuarter, bucketSum = _c.bucketSum, bucketString = _c.bucketString;
233
+ var valueQuarter = (_a = bucketQuarter.get(i)) !== null && _a !== void 0 ? _a : bucketString.get(i);
234
+ var valueTrailing = bucketSum.get(i);
235
+ var value = (_b = (isAnnual ? bucketSum.get(3) : bucketQuarter.get(i))) !== null && _b !== void 0 ? _b : bucketString.get(i);
236
+ var quarter = i + 1;
237
+ callback({
238
+ year: year,
239
+ fiscalPeriod: "Q".concat(quarter),
240
+ propertyName: propertyName,
241
+ value: value,
242
+ quarter: quarter,
243
+ valueQuarter: valueQuarter,
244
+ valueTrailing: valueTrailing,
245
+ });
184
246
  }
185
247
  });
186
248
  });
@@ -0,0 +1,9 @@
1
+ import { CompanyFactListData, FactItem } from '../../types';
2
+ /**
3
+ * Builds an array of fact records.
4
+ */
5
+ export default class FactRecordBuilder {
6
+ createFacts(data: CompanyFactListData, includeNamePrefix?: boolean): {
7
+ facts: FactItem[];
8
+ };
9
+ }
@@ -6,17 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  var FactRecordBuilder = /** @class */ (function () {
7
7
  function FactRecordBuilder() {
8
8
  }
9
- FactRecordBuilder.prototype.createFacts = function (data, filterDuplicates) {
10
- if (filterDuplicates === void 0) { filterDuplicates = false; }
9
+ FactRecordBuilder.prototype.createFacts = function (data, includeNamePrefix) {
10
+ if (includeNamePrefix === void 0) { includeNamePrefix = true; }
11
11
  var facts = data.facts, cik = data.cik;
12
- var factsByKey = new Map();
13
- var keyIndex = 0;
14
- var createKey = function (params) {
15
- if (!filterDuplicates)
16
- return keyIndex++;
17
- var start = params.start, end = params.end, filed = params.filed, propertyName = params.propertyName;
18
- return "".concat(start !== null && start !== void 0 ? start : '', "_").concat(end, "_").concat(filed, "_").concat(propertyName);
19
- };
12
+ var factItems = [];
20
13
  for (var prefix in facts) {
21
14
  var factByPropertyName = facts[prefix];
22
15
  for (var propertyName in factByPropertyName) {
@@ -26,8 +19,7 @@ var FactRecordBuilder = /** @class */ (function () {
26
19
  for (var _i = 0, factValues_1 = factValues; _i < factValues_1.length; _i++) {
27
20
  var factValue = factValues_1[_i];
28
21
  var end = factValue.end, start = factValue.start, val = factValue.val, filed = factValue.filed, accn = factValue.accn, form = factValue.form, fp = factValue.fp, frame = factValue.frame, fy = factValue.fy;
29
- var mapKey = createKey({ propertyName: propertyName, end: end, filed: filed, start: start });
30
- var name_1 = "".concat(prefix, ":").concat(propertyName);
22
+ var name_1 = includeNamePrefix ? "".concat(prefix, ":").concat(propertyName) : propertyName;
31
23
  var item = {
32
24
  cik: cik,
33
25
  end: end,
@@ -49,22 +41,12 @@ var FactRecordBuilder = /** @class */ (function () {
49
41
  item.frame = frame;
50
42
  if (fy)
51
43
  item.fy = fy;
52
- var prevFact = factsByKey.get(mapKey);
53
- if (!prevFact) {
54
- factsByKey.set(mapKey, item);
55
- continue;
56
- }
57
- // use whichever is closer to the report end date
58
- var shouldPush = new Date(item.filed).getTime() - new Date(item.end).getTime() <
59
- new Date(prevFact.filed).getTime() - new Date(prevFact.end).getTime();
60
- if (shouldPush) {
61
- factsByKey.set(mapKey, item);
62
- }
44
+ factItems.push(item);
63
45
  }
64
46
  }
65
47
  }
66
48
  }
67
- return { facts: Array.from(factsByKey.values()) };
49
+ return { facts: factItems };
68
50
  };
69
51
  return FactRecordBuilder;
70
52
  }());
@@ -0,0 +1,43 @@
1
+ import { CompanyFactListData, FactGroup, FactItem, FactValue, SplitData } from '../../types';
2
+ /**
3
+ * Splits can be filed multiple times throughout different reports. There is no clear
4
+ * indication on when the split is executed or what facts the split has been applied to. This
5
+ * class tries to determine which splits have been applied and which need to be adjusted for
6
+ * each fact.
7
+ */
8
+ export default class FactSplitAdjuster {
9
+ private readonly keySplit;
10
+ private preferFirstValue;
11
+ private getGroupValue;
12
+ getSplits(params: {
13
+ splitFacts: FactValue[] | FactItem[];
14
+ }): SplitData[];
15
+ filterSplitFacts(params: {
16
+ facts: FactItem[];
17
+ }): FactItem[];
18
+ extractSplitsFromCompanyFacts(params: {
19
+ companyFactList: Pick<CompanyFactListData, 'facts'>;
20
+ }): FactValue[];
21
+ getSplitsFromCompanyFacts(params: {
22
+ companyFactList: Pick<CompanyFactListData, 'facts'>;
23
+ }): SplitData[];
24
+ /**
25
+ * Returns true if the fact value was adjusted, false if it was not,
26
+ * and null if the comparison does not match the split
27
+ */
28
+ private isAdjustedFromComparedFact;
29
+ /**
30
+ * Splits can be filed multiple times throughout different reports.
31
+ */
32
+ didApplySplit(params: {
33
+ isShareRatio: boolean;
34
+ split: SplitData;
35
+ factGroup: FactGroup;
36
+ isTrailing: boolean;
37
+ useOppositePeriodFallback?: boolean;
38
+ }): boolean;
39
+ adjustForSplits(params: {
40
+ factGroups: FactGroup[];
41
+ splits: SplitData[];
42
+ }): void;
43
+ }
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
14
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
15
+ if (ar || !(i in from)) {
16
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
17
+ ar[i] = from[i];
18
+ }
19
+ }
20
+ return to.concat(ar || Array.prototype.slice.call(from));
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ var FactPeriodResolver_1 = require("./FactPeriodResolver");
24
+ /**
25
+ * Splits can be filed multiple times throughout different reports. There is no clear
26
+ * indication on when the split is executed or what facts the split has been applied to. This
27
+ * class tries to determine which splits have been applied and which need to be adjusted for
28
+ * each fact.
29
+ */
30
+ var FactSplitAdjuster = /** @class */ (function () {
31
+ function FactSplitAdjuster() {
32
+ this.keySplit = 'StockholdersEquityNoteStockSplitConversionRatio1';
33
+ this.preferFirstValue = true;
34
+ }
35
+ FactSplitAdjuster.prototype.getGroupValue = function (factGroup, isTrailing) {
36
+ if (isTrailing) {
37
+ return Number(this.preferFirstValue ? factGroup.valueTrailingFirst : factGroup.valueTrailingLast);
38
+ }
39
+ else {
40
+ return Number(this.preferFirstValue ? factGroup.valuePeriodFirst : factGroup.valuePeriodLast);
41
+ }
42
+ };
43
+ FactSplitAdjuster.prototype.getSplits = function (params) {
44
+ var _a, _b;
45
+ var splitFacts = __spreadArray([], params.splitFacts, true).sort(function (a, b) { return (a.end < b.end ? -1 : 1); });
46
+ var YEAR_MS = 31536000000;
47
+ var splits = [];
48
+ var currentSplit = null;
49
+ for (var i = 0; i < splitFacts.length; i++) {
50
+ var prevFact = splitFacts[i - 1];
51
+ var fact = splitFacts[i];
52
+ var factValue = Number((_a = fact.value) !== null && _a !== void 0 ? _a : fact.val);
53
+ var factValuePrev = Number((_b = prevFact === null || prevFact === void 0 ? void 0 : prevFact.value) !== null && _b !== void 0 ? _b : prevFact === null || prevFact === void 0 ? void 0 : prevFact.val);
54
+ var isSameSplitLaterFiling = factValue === factValuePrev && new Date(fact.end).getTime() - new Date(prevFact.end).getTime() < YEAR_MS;
55
+ if (!isSameSplitLaterFiling && currentSplit) {
56
+ splits.push(currentSplit);
57
+ currentSplit = null;
58
+ }
59
+ if (!currentSplit) {
60
+ currentSplit = {
61
+ endFirst: fact.end,
62
+ endLast: fact.end,
63
+ filedFirst: fact.filed,
64
+ filedLast: fact.filed,
65
+ splitRatio: factValue,
66
+ };
67
+ }
68
+ else {
69
+ currentSplit.endFirst = fact.end < currentSplit.endFirst ? fact.end : currentSplit.endFirst;
70
+ currentSplit.endLast = fact.end > currentSplit.endLast ? fact.end : currentSplit.endLast;
71
+ currentSplit.filedFirst = fact.filed < currentSplit.filedFirst ? fact.filed : currentSplit.filedFirst;
72
+ currentSplit.filedLast = fact.filed > currentSplit.filedLast ? fact.filed : currentSplit.filedLast;
73
+ }
74
+ }
75
+ if (currentSplit) {
76
+ splits.push(currentSplit);
77
+ }
78
+ return splits;
79
+ };
80
+ FactSplitAdjuster.prototype.filterSplitFacts = function (params) {
81
+ var _this = this;
82
+ var facts = params.facts;
83
+ return facts.filter(function (f) { return f.name.endsWith(_this.keySplit); });
84
+ };
85
+ FactSplitAdjuster.prototype.extractSplitsFromCompanyFacts = function (params) {
86
+ var _a, _b, _c;
87
+ var companyFactList = params.companyFactList;
88
+ var factsByName = (_a = companyFactList.facts['us-gaap']) !== null && _a !== void 0 ? _a : {};
89
+ return (_c = (_b = factsByName[this.keySplit]) === null || _b === void 0 ? void 0 : _b.units.pure) !== null && _c !== void 0 ? _c : [];
90
+ };
91
+ FactSplitAdjuster.prototype.getSplitsFromCompanyFacts = function (params) {
92
+ var _a, _b, _c;
93
+ var companyFactList = params.companyFactList;
94
+ var factsByName = (_a = companyFactList.facts['us-gaap']) !== null && _a !== void 0 ? _a : {};
95
+ var splitFacts = __spreadArray([], ((_c = (_b = factsByName[this.keySplit]) === null || _b === void 0 ? void 0 : _b.units.pure) !== null && _c !== void 0 ? _c : []), true).sort(function (a, b) { return (a.end < b.end ? -1 : 1); });
96
+ var YEAR_MS = 31536000000;
97
+ var splits = [];
98
+ var currentSplit = null;
99
+ for (var i = 0; i < splitFacts.length; i++) {
100
+ var prevFact = splitFacts[i - 1];
101
+ var fact = splitFacts[i];
102
+ // Assume the split is executed within the first year of the first filing...
103
+ // sometimes a company will file the split fact mentioning that they plan on executing it later in the fiscal year
104
+ // (ex: when Google did their 20:1 split in July of 2020)
105
+ var isSameSplitLaterFiling = fact.val === (prevFact === null || prevFact === void 0 ? void 0 : prevFact.val) && new Date(fact.end).getTime() - new Date(prevFact.end).getTime() < YEAR_MS;
106
+ if (!isSameSplitLaterFiling && currentSplit) {
107
+ splits.push(currentSplit);
108
+ currentSplit = null;
109
+ }
110
+ if (!currentSplit) {
111
+ currentSplit = {
112
+ endFirst: fact.end,
113
+ endLast: fact.end,
114
+ filedFirst: fact.filed,
115
+ filedLast: fact.filed,
116
+ splitRatio: Number(fact.val),
117
+ };
118
+ }
119
+ else {
120
+ currentSplit.endFirst = fact.end < currentSplit.endFirst ? fact.end : currentSplit.endFirst;
121
+ currentSplit.endLast = fact.end > currentSplit.endLast ? fact.end : currentSplit.endLast;
122
+ currentSplit.filedFirst = fact.filed < currentSplit.filedFirst ? fact.filed : currentSplit.filedFirst;
123
+ currentSplit.filedLast = fact.filed > currentSplit.filedLast ? fact.filed : currentSplit.filedLast;
124
+ }
125
+ }
126
+ if (currentSplit) {
127
+ splits.push(currentSplit);
128
+ }
129
+ return splits;
130
+ };
131
+ /**
132
+ * Returns true if the fact value was adjusted, false if it was not,
133
+ * and null if the comparison does not match the split
134
+ */
135
+ FactSplitAdjuster.prototype.isAdjustedFromComparedFact = function (params) {
136
+ var _a, _b;
137
+ var factCompare = params.factCompare, factValue = params.factValue, isShareRatio = params.isShareRatio, splitVal = params.splitVal;
138
+ var minValue = Math.min(factValue, Number((_a = factCompare === null || factCompare === void 0 ? void 0 : factCompare.value) !== null && _a !== void 0 ? _a : factValue));
139
+ var maxValue = Math.max(factValue, Number((_b = factCompare === null || factCompare === void 0 ? void 0 : factCompare.value) !== null && _b !== void 0 ? _b : factValue));
140
+ var possiblePreSplitValue = isShareRatio ? maxValue : minValue;
141
+ var possiblePostSplitValue = isShareRatio ? minValue : maxValue;
142
+ var expectedPostSplitValue = isShareRatio
143
+ ? possiblePreSplitValue / splitVal
144
+ : possiblePreSplitValue * splitVal;
145
+ var nearnessThreshold = 0.01;
146
+ var isSplitAdjustment = Math.abs(expectedPostSplitValue - possiblePostSplitValue) < nearnessThreshold;
147
+ return isSplitAdjustment ? possiblePostSplitValue === factValue : null;
148
+ };
149
+ /**
150
+ * Splits can be filed multiple times throughout different reports.
151
+ */
152
+ FactSplitAdjuster.prototype.didApplySplit = function (params) {
153
+ var isShareRatio = params.isShareRatio, factGroup = params.factGroup, split = params.split, isTrailing = params.isTrailing, _a = params.useOppositePeriodFallback, useOppositePeriodFallback = _a === void 0 ? true : _a;
154
+ var splitVal = split.splitRatio;
155
+ if (!splitVal)
156
+ return true;
157
+ // these first two criteria will take care of the majority of cases...
158
+ if (factGroup.filedFirst > split.filedLast) {
159
+ return true;
160
+ }
161
+ if (factGroup.filedLast < split.filedFirst) {
162
+ return false;
163
+ }
164
+ var resolvedFact = factGroup.facts.find(function (f) {
165
+ return isTrailing ? f.value === factGroup.valueTrailingFirst : f.value === factGroup.valuePeriodFirst;
166
+ });
167
+ if (!resolvedFact && useOppositePeriodFallback) {
168
+ return this.didApplySplit(__assign(__assign({}, params), { isTrailing: !isTrailing, useOppositePeriodFallback: false }));
169
+ }
170
+ var refiledFacts = factGroup.facts.filter(function (f) {
171
+ var period = FactPeriodResolver_1.default.getPeriod(f);
172
+ var isSamePeriod = isTrailing ? period === 0 || period > 3 : period <= 3;
173
+ return f !== resolvedFact && isSamePeriod;
174
+ });
175
+ // check if one of the filed facts is the split adjustment
176
+ for (var _i = 0, refiledFacts_1 = refiledFacts; _i < refiledFacts_1.length; _i++) {
177
+ var fact = refiledFacts_1[_i];
178
+ var isAdjusted = this.isAdjustedFromComparedFact({
179
+ factCompare: fact,
180
+ factValue: Number(resolvedFact === null || resolvedFact === void 0 ? void 0 : resolvedFact.value),
181
+ isShareRatio: isShareRatio,
182
+ splitVal: splitVal,
183
+ });
184
+ if (isAdjusted !== null) {
185
+ return isAdjusted;
186
+ }
187
+ }
188
+ if ((resolvedFact === null || resolvedFact === void 0 ? void 0 : resolvedFact.filed) > split.filedLast) {
189
+ return true;
190
+ }
191
+ if ((resolvedFact === null || resolvedFact === void 0 ? void 0 : resolvedFact.filed) < split.filedFirst) {
192
+ return false;
193
+ }
194
+ // // if the filed date of the fact overlaps with the filed date of the split, try comparing the end dates
195
+ if (factGroup.endLast < split.endFirst && factGroup.values.length === 1) {
196
+ return false;
197
+ }
198
+ // if we still don't know, see if the split value puts us closer to the last known value or further
199
+ if (factGroup.valuePeriodLast !== null) {
200
+ var val = this.getGroupValue(factGroup, isTrailing);
201
+ var valueWithSplit = isShareRatio ? val / splitVal : val * splitVal;
202
+ return Math.abs(factGroup.valuePeriodLast - val) < Math.abs(factGroup.valuePeriodLast - valueWithSplit);
203
+ }
204
+ if (factGroup.valueTrailingLast !== null) {
205
+ var val = this.getGroupValue(factGroup, isTrailing);
206
+ var valueWithSplit = isShareRatio ? val / splitVal : val * splitVal;
207
+ return Math.abs(factGroup.valueTrailingLast - val) < Math.abs(factGroup.valueTrailingLast - valueWithSplit);
208
+ }
209
+ return true;
210
+ };
211
+ FactSplitAdjuster.prototype.adjustForSplits = function (params) {
212
+ var factGroups = params.factGroups, splits = params.splits;
213
+ for (var _i = 0, factGroups_1 = factGroups; _i < factGroups_1.length; _i++) {
214
+ var factGroup = factGroups_1[_i];
215
+ var unitLower = factGroup.unit.toLowerCase();
216
+ if (!unitLower.includes('share'))
217
+ continue;
218
+ var isShareRatio = unitLower !== 'shares';
219
+ for (var _a = 0, splits_1 = splits; _a < splits_1.length; _a++) {
220
+ var split = splits_1[_a];
221
+ var factValuePeriod = this.getGroupValue(factGroup, false);
222
+ var factValueTrailing = this.getGroupValue(factGroup, true);
223
+ var splitValue = split.splitRatio;
224
+ if (!splitValue)
225
+ continue;
226
+ // ratios (like EPS) get divided by splits, share counts get multiplied (like shares outstanding).
227
+ if (!this.didApplySplit({ factGroup: factGroup, split: split, isShareRatio: isShareRatio, isTrailing: false })) {
228
+ factGroup.valueSplitAdjustedPeriod = isShareRatio
229
+ ? factValuePeriod / splitValue
230
+ : factValuePeriod * splitValue;
231
+ }
232
+ if (!this.didApplySplit({ factGroup: factGroup, split: split, isShareRatio: isShareRatio, isTrailing: true })) {
233
+ factGroup.valueSplitAdjustedTrailing = isShareRatio
234
+ ? factValueTrailing / splitValue
235
+ : factValueTrailing * splitValue;
236
+ }
237
+ }
238
+ }
239
+ };
240
+ return FactSplitAdjuster;
241
+ }());
242
+ exports.default = FactSplitAdjuster;
@@ -0,0 +1,39 @@
1
+ import { CompanyFactListData, FactGroup, FactItem, ReportRaw, SplitData } from '../../types';
2
+ import FactFiscalCalculator, { SetReportDatesParams } from './FactFiscalCalculator';
3
+ interface BuildReportsParams {
4
+ facts: FactItem[];
5
+ /**
6
+ * for more accurate dates, add this. Otherwise, dates will be inferred
7
+ * using the fact periods. The filing and report dates can be found in the SubmissionList (segEdgarApi.getSubmissions)
8
+ */
9
+ reportDates?: SetReportDatesParams[];
10
+ /**
11
+ * Splits will be extracted from facts if not provided.
12
+ */
13
+ splits?: SplitData[];
14
+ resolvePeriodValues?: boolean;
15
+ adjustForSplits?: boolean;
16
+ }
17
+ /**
18
+ * Builds ReportRaw objects from company facts. Adjusts for splits and resolves period values.
19
+ */
20
+ export default class ReportRawBuilder {
21
+ private readonly factRecordBuilder;
22
+ createFacts(companyFacts: CompanyFactListData, includeNamePrefix?: boolean): {
23
+ facts: FactItem[];
24
+ };
25
+ private createFiscalCalculator;
26
+ buildReports(params: BuildReportsParams): ReportRaw[];
27
+ private createReportKey;
28
+ private createReport;
29
+ private round;
30
+ buildReportsFromGroups(params: {
31
+ factGroupsByReportKey: Map<string, FactGroup[]>;
32
+ fiscalCalculator: FactFiscalCalculator;
33
+ splits?: SplitData[];
34
+ minYear: number;
35
+ maxYear: number;
36
+ cik: number;
37
+ }): ReportRaw[];
38
+ }
39
+ export {};