sec-edgar-api 0.2.2 → 0.2.4

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 (58) hide show
  1. package/README.md +5 -3
  2. package/build/services/DocumentParser/XMLParser.d.ts +5 -20
  3. package/build/services/DocumentParser/XMLParser.js +118 -122
  4. package/build/services/DocumentParser/parsers/index.d.ts +3 -5
  5. package/build/services/DocumentParser/parsers/index.js +3 -5
  6. package/build/services/DocumentParser/parsers/parse-form-13g.js +2 -2
  7. package/build/services/DocumentParser/parsers/parse-form-4.d.ts +1 -6
  8. package/build/services/DocumentParser/parsers/parse-form-4.js +204 -134
  9. package/build/services/DocumentParser/parsers/parse-form-def14a.d.ts +2 -1
  10. package/build/services/DocumentParser/parsers/parse-form-def14a.js +106 -157
  11. package/build/services/ReportBuilder/FactFiscalCalculator.d.ts +4 -0
  12. package/build/services/ReportBuilder/FactFiscalCalculator.js +4 -0
  13. package/build/services/ReportBuilder/FactPeriodResolver.d.ts +6 -2
  14. package/build/services/ReportBuilder/FactPeriodResolver.js +6 -1
  15. package/build/services/ReportBuilder/FactRecordBuilder.d.ts +4 -1
  16. package/build/services/ReportBuilder/FactRecordBuilder.js +26 -4
  17. package/build/services/ReportBuilder/FactSplitAdjuster.d.ts +12 -1
  18. package/build/services/ReportBuilder/FactSplitAdjuster.js +41 -19
  19. package/build/services/ReportBuilder/ReportBuilder.d.ts +3 -0
  20. package/build/services/ReportBuilder/ReportBuilder.js +33 -13
  21. package/build/services/ReportParser/ReportParser.d.ts +3 -3
  22. package/build/services/ReportParser/ReportParser.js +7 -4
  23. package/build/services/ReportParser/ReportRawParser.d.ts +3 -9
  24. package/build/services/ReportParser/ReportRawParser.js +5 -33
  25. package/build/services/ReportParser/ReportWrapper.js +2 -0
  26. package/build/services/ReportParser/resolvers/resolve-fiscal-year-cumulative-properties.js +2 -1
  27. package/build/services/SecEdgarApi/SecEdgarApi.d.ts +45 -84
  28. package/build/services/SecEdgarApi/SecEdgarApi.js +108 -246
  29. package/build/types/index.d.ts +2 -2
  30. package/build/types/index.js +2 -2
  31. package/build/types/parsed-filings.type.d.ts +5 -144
  32. package/build/types/report-raw.type.d.ts +3 -1
  33. package/build/types/report-translated.type.d.ts +4 -1
  34. package/build/types/submission.type.d.ts +2 -3
  35. package/build/util/key-translations.js +5 -1
  36. package/package.json +2 -5
  37. package/build/services/DocumentParser/HtmlTableExtractor.d.ts +0 -41
  38. package/build/services/DocumentParser/HtmlTableExtractor.js +0 -408
  39. package/build/services/DocumentParser/parsers/parse-current-filings.d.ts +0 -3
  40. package/build/services/DocumentParser/parsers/parse-current-filings.js +0 -98
  41. package/build/services/DocumentParser/parsers/parse-form-13f.d.ts +0 -6
  42. package/build/services/DocumentParser/parsers/parse-form-13f.js +0 -91
  43. package/build/services/ReportParser/FactItem.d.ts +0 -66
  44. package/build/services/ReportParser/FactItem.js +0 -50
  45. package/build/services/ReportParser/FactItemFactory.d.ts +0 -22
  46. package/build/services/ReportParser/FactItemFactory.js +0 -150
  47. package/build/services/ReportParser/FactIterator.d.ts +0 -18
  48. package/build/services/ReportParser/FactIterator.js +0 -35
  49. package/build/services/ReportParser/FactSplitMap.d.ts +0 -16
  50. package/build/services/ReportParser/FactSplitMap.js +0 -101
  51. package/build/types/current-filings-xml.type.d.ts +0 -74
  52. package/build/types/current-filings-xml.type.js +0 -6
  53. package/build/types/current-filings.type.d.ts +0 -44
  54. package/build/types/current-filings.type.js +0 -2
  55. package/build/types/form-13f-xml.type.d.ts +0 -105
  56. package/build/types/form-13f-xml.type.js +0 -2
  57. package/build/types/form-4-xml.type.d.ts +0 -132
  58. package/build/types/form-4-xml.type.js +0 -2
@@ -1,177 +1,126 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseFormDef14a = void 0;
4
- var HtmlTableExtractor_1 = require("../HtmlTableExtractor");
4
+ var XMLParser_1 = require("../XMLParser");
5
5
  /**
6
6
  * Form DEF 14a - Proxy Statement
7
7
  *
8
8
  * example at https://www.sec.gov/Archives/edgar/data/320193/000130817923000019/laap2023_def14a.htm
9
9
  */
10
- function parseFormDef14a(params) {
11
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
10
+ function parseFormDef14a(params, xmlParser) {
11
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
12
+ if (xmlParser === void 0) { xmlParser = new XMLParser_1.default(); }
12
13
  var xml = params.xml;
13
- var parser = new HtmlTableExtractor_1.default();
14
- var tables = parser.extractTables(xml, {
15
- stripHtml: true,
16
- tagsToExclude: ['sup'],
17
- stripParenthesis: true,
18
- });
19
- var compensationTables = [];
20
- for (var _i = 0, tables_1 = tables; _i < tables_1.length; _i++) {
21
- var table = tables_1[_i];
22
- var compensationRows = [];
23
- var bodyIndex = table.rows.findIndex(function (row) { return row.some(function (col) { return !col.isHeaderRowCell; }); });
24
- var headerIndex = bodyIndex - 1;
25
- var textBefore = parser.stripHtml(table.htmlBefore, { tagsToExclude: ['sup'] }).toLowerCase();
26
- var hasNameRow = (_a = table.rows[headerIndex]) === null || _a === void 0 ? void 0 : _a.some(function (col) { return "".concat(col.valueParsed).toLowerCase().includes('name'); });
27
- var hasSalaryRow = (_b = table.rows[headerIndex]) === null || _b === void 0 ? void 0 : _b.some(function (col) {
28
- return "".concat(col.valueParsed).toLowerCase().includes('salary');
14
+ var doc = xmlParser.getDocumentNode({ xml: xml });
15
+ var tables = doc.parseTables();
16
+ var usedTables = [];
17
+ var compensationArr = [];
18
+ var holderArr = [];
19
+ var findCompensationTables = function (type) {
20
+ var tablesFound = tables.filter(function (table) {
21
+ var _a, _b, _c, _d, _e;
22
+ var hasNameRow = (_a = table.rows[0]) === null || _a === void 0 ? void 0 : _a.some(function (col) { return "".concat(col).toLowerCase().includes('name'); });
23
+ var hasTotalRow = (_b = table.rows[0]) === null || _b === void 0 ? void 0 : _b.some(function (col) { return "".concat(col).toLowerCase().includes('total'); });
24
+ var hasAwardRow = (_c = table.rows[0]) === null || _c === void 0 ? void 0 : _c.some(function (col) { return "".concat(col).toLowerCase().includes('award'); });
25
+ var titleLower = table.title.toLowerCase();
26
+ var textLower = (_e = (_d = table.textBefore) === null || _d === void 0 ? void 0 : _d.toLowerCase()) !== null && _e !== void 0 ? _e : '';
27
+ var isTitleMatch = titleLower.includes(type) && titleLower.includes('compensation');
28
+ var isTextMatch = hasNameRow && hasTotalRow && hasAwardRow && textLower.includes(type);
29
+ return (isTitleMatch || isTextMatch) && !usedTables.includes(table);
29
30
  });
30
- var hasTotalRow = (_c = table.rows[headerIndex]) === null || _c === void 0 ? void 0 : _c.some(function (col) { return "".concat(col.valueParsed).toLowerCase().includes('total'); });
31
- var isCompensationTable = Boolean(hasNameRow && hasTotalRow && hasSalaryRow);
32
- if (!isCompensationTable)
33
- continue;
34
- var defaultPosition = 'Executive';
35
- if (textBefore.includes('executive'))
36
- defaultPosition = 'Executive';
37
- else if (textBefore.includes('director'))
38
- defaultPosition = 'Director';
39
- var _loop_1 = function (i) {
40
- var row = table.rows[i];
41
- var getIndex = function (search, isNum, isYear) {
42
- if (isNum === void 0) { isNum = true; }
43
- if (isYear === void 0) { isYear = false; }
44
- return row.findIndex(function (col) {
45
- var hasType = isNum ? typeof col.valueParsed === 'number' : true;
46
- var hasSearch = "".concat(col.headerCol).toLowerCase().includes(search);
47
- var hasYear = !isYear || (Number(col.valueParsed) > 1900 && Number(col.valueParsed) < 2100);
48
- return hasType && hasSearch && hasYear;
49
- });
50
- };
51
- var indexName = getIndex('name', false);
52
- var indexYear = getIndex('year', true, true);
31
+ tablesFound.forEach(function (t) { return usedTables.push(t); });
32
+ return tablesFound;
33
+ };
34
+ var tablesHolder = tables.filter(function (table) {
35
+ var _a, _b;
36
+ var hasNameRow = (_a = table.rows[0]) === null || _a === void 0 ? void 0 : _a.some(function (col) { return "".concat(col).toLowerCase().includes('name'); });
37
+ var hasPercent = (_b = table.rows[0]) === null || _b === void 0 ? void 0 : _b.some(function (col) { return "".concat(col).toLowerCase().includes('percent'); });
38
+ var titleLower = table.title.toLowerCase();
39
+ var isTitleMatch = titleLower.includes('security') && titleLower.includes('owner') && titleLower.includes('beneficial');
40
+ return isTitleMatch && hasNameRow && hasPercent;
41
+ });
42
+ var foundHoldersKeys = new Set();
43
+ var _loop_1 = function (table) {
44
+ var header = table.rows[0];
45
+ var getIndex = function (search) { return header.findIndex(function (col) { return "".concat(col).toLowerCase().includes(search); }); };
46
+ var indexName = getIndex('name');
47
+ var indexPercent = getIndex('percent');
48
+ var indexShares = (_b = (_a = table.rows[1]) === null || _a === void 0 ? void 0 : _a.findIndex(function (col) { return typeof col === 'number' && !isNaN(col); })) !== null && _b !== void 0 ? _b : -1;
49
+ for (var i = 1; i < table.rows.length; i++) {
50
+ for (var i_1 = 1; i_1 < table.rows.length; i_1++) {
51
+ var nameVal = (_d = (_c = table.rows[i_1]) === null || _c === void 0 ? void 0 : _c[indexName]) !== null && _d !== void 0 ? _d : null;
52
+ if (typeof nameVal !== 'string')
53
+ continue;
54
+ var nameParts = nameVal.split('}}');
55
+ var namePartsSpaces = nameVal.split(' ');
56
+ var position = (_e = nameParts[1]) !== null && _e !== void 0 ? _e : namePartsSpaces.slice(2, namePartsSpaces.length).join(' ');
57
+ var name_1 = nameParts[1] ? nameParts[0] : namePartsSpaces.slice(0, 2).join(' ');
58
+ var holder = {
59
+ name: name_1.replace(/{{/g, '').replace(/}}/g, '').trim(),
60
+ position: position.replace(/{{/g, '').replace(/}}/g, '').trim() || null,
61
+ shares: Number((_f = table.rows[i_1]) === null || _f === void 0 ? void 0 : _f[indexShares]) || null,
62
+ percentOfClass: String((_g = table.rows[i_1]) === null || _g === void 0 ? void 0 : _g[indexPercent]) || null,
63
+ };
64
+ var key = "".concat(holder.name).concat(holder.position).concat(holder.shares).concat(holder.percentOfClass);
65
+ if (!foundHoldersKeys.has(key))
66
+ holderArr.push(holder);
67
+ foundHoldersKeys.add(key);
68
+ }
69
+ }
70
+ };
71
+ for (var _i = 0, tablesHolder_1 = tablesHolder; _i < tablesHolder_1.length; _i++) {
72
+ var table = tablesHolder_1[_i];
73
+ _loop_1(table);
74
+ }
75
+ for (var _t = 0, _u = ['director', 'executive', 'summary']; _t < _u.length; _t++) {
76
+ var type = _u[_t];
77
+ var _loop_2 = function (table) {
78
+ if (!table)
79
+ return "continue";
80
+ var header = table.rows[0];
81
+ var getIndex = function (search) { return header.findIndex(function (col) { return "".concat(col).toLowerCase().includes(search); }); };
82
+ var indexName = getIndex('name');
83
+ var indexYear = getIndex('year');
53
84
  var indexSalary = getIndex('salary') === -1 ? getIndex('cash') : getIndex('salary');
54
85
  var indexBonus = getIndex('bonus');
55
86
  var indexStock = getIndex('stock');
56
- var indexOption = getIndex('non-equity') === -1 ? getIndex('option') : getIndex('non-equity');
87
+ var indexNonEquity = getIndex('non-equity') === -1 ? getIndex('option') : getIndex('non-equity');
57
88
  var indexOther = getIndex('other');
58
89
  var indexTotal = getIndex('total');
59
- var nameHtml = String((_e = (_d = row[indexName]) === null || _d === void 0 ? void 0 : _d.html) !== null && _e !== void 0 ? _e : '');
60
- var nameParts = nameHtml
61
- .replace(/\n/g, ' ')
62
- .replace(/<sup.*?sup>/gi, '')
63
- .replace(/&.*?;/g, '')
64
- .split(/<.*?>/g)
65
- .filter(function (str) { return str.replace(/\W/gi, '').length > 0; })
66
- .map(function (str) { return str.replace(/(\s|\n|\t)+/g, ' ').trim(); });
67
- var year = Number((_f = row[indexYear]) === null || _f === void 0 ? void 0 : _f.valueParsed) ||
68
- Number(String((_g = row[indexYear]) === null || _g === void 0 ? void 0 : _g.valueParsed)
69
- .split(/\W/g)
70
- .find(function (str) { return str.length === 4; })) ||
71
- null;
72
- var name_1 = String(parser.parseValue(((_h = nameParts[0]) === null || _h === void 0 ? void 0 : _h.trim()) || '', { stripHtml: false, stripParenthesis: true }) || '');
73
- var position = String(parser.parseValue((_j = nameParts.slice(1)) === null || _j === void 0 ? void 0 : _j.join(' '), { stripHtml: false, stripParenthesis: true }) || '');
74
- var isValidPosition = position.replace(/\W/gi, '').length > 0 && isNaN(Number(position));
75
- compensationRows.push({
76
- name: name_1.replace(/\s+/g, ' '),
77
- position: isValidPosition ? position || defaultPosition : defaultPosition,
78
- year: year,
79
- positionLevel: defaultPosition || 'Executive',
80
- salaryDollars: Number((_k = row[indexSalary]) === null || _k === void 0 ? void 0 : _k.valueParsed) || null,
81
- bonusDollars: Number((_l = row[indexBonus]) === null || _l === void 0 ? void 0 : _l.valueParsed) || null,
82
- stockAwardDollars: Number((_m = row[indexStock]) === null || _m === void 0 ? void 0 : _m.valueParsed) || null,
83
- nonEquityDollars: Number((_o = row[indexOption]) === null || _o === void 0 ? void 0 : _o.valueParsed) || null,
84
- otherDollars: Number((_p = row[indexOther]) === null || _p === void 0 ? void 0 : _p.valueParsed) || null,
85
- totalDollars: Number((_q = row[indexTotal]) === null || _q === void 0 ? void 0 : _q.valueParsed) || null,
86
- });
90
+ var defaultPosition = {
91
+ director: 'Director',
92
+ executive: 'Executive',
93
+ summary: null,
94
+ }[type];
95
+ for (var i = 1; i < table.rows.length; i++) {
96
+ var nameVal = (_j = (_h = table.rows[i]) === null || _h === void 0 ? void 0 : _h[indexName]) !== null && _j !== void 0 ? _j : null;
97
+ if (typeof nameVal !== 'string')
98
+ continue;
99
+ var nameParts = nameVal.split('}}');
100
+ var namePartsSpaces = nameVal.split(' ');
101
+ var position = (_k = nameParts[1]) !== null && _k !== void 0 ? _k : namePartsSpaces.slice(2, namePartsSpaces.length).join(' ');
102
+ var name_2 = nameParts[1] ? nameParts[0] : namePartsSpaces.slice(0, 2).join(' ');
103
+ var compensation = {
104
+ name: name_2.replace(/{{/g, '').replace(/}}/g, '').trim(),
105
+ position: position.replace(/{{/g, '').replace(/}}/g, '').trim() || (defaultPosition !== null && defaultPosition !== void 0 ? defaultPosition : null),
106
+ year: Number((_l = table.rows[i]) === null || _l === void 0 ? void 0 : _l[indexYear]) || null,
107
+ salaryDollars: Number((_m = table.rows[i]) === null || _m === void 0 ? void 0 : _m[indexSalary]) || null,
108
+ bonusDollars: Number((_o = table.rows[i]) === null || _o === void 0 ? void 0 : _o[indexBonus]) || null,
109
+ stockAwardDollars: Number((_p = table.rows[i]) === null || _p === void 0 ? void 0 : _p[indexStock]) || null,
110
+ nonEquityDollars: Number((_q = table.rows[i]) === null || _q === void 0 ? void 0 : _q[indexNonEquity]) || null,
111
+ otherDollars: Number((_r = table.rows[i]) === null || _r === void 0 ? void 0 : _r[indexOther]) || null,
112
+ totalDollars: Number((_s = table.rows[i]) === null || _s === void 0 ? void 0 : _s[indexTotal]) || null,
113
+ };
114
+ if (compensation.totalDollars !== null) {
115
+ compensationArr.push(compensation);
116
+ }
117
+ }
87
118
  };
88
- for (var i = bodyIndex; i < table.rows.length; i++) {
89
- _loop_1(i);
119
+ for (var _v = 0, _w = findCompensationTables(type); _v < _w.length; _v++) {
120
+ var table = _w[_v];
121
+ _loop_2(table);
90
122
  }
91
- compensationTables.push(compensationRows);
92
123
  }
93
- mergeYearRows(compensationTables);
94
- var tablesFlat = flattenTables(compensationTables);
95
- return { executiveCompensation: tablesFlat };
124
+ return { executiveCompensation: compensationArr, holders: holderArr };
96
125
  }
97
126
  exports.parseFormDef14a = parseFormDef14a;
98
- function flattenTables(tables) {
99
- var isDefaultPosition = function (position) { return position === 'Director' || position === 'Executive'; };
100
- var compensationByNameYear = new Map();
101
- var resolveProperty = function (a, b) {
102
- if (a === null && b === null)
103
- return null;
104
- if (a === null && b !== null)
105
- return b;
106
- if (a !== null && b === null)
107
- return a;
108
- if (typeof a === 'number' && typeof b === 'number') {
109
- return Math.max(a, b);
110
- }
111
- if (typeof a === 'string' && typeof b === 'string') {
112
- return isDefaultPosition(a) ? b : a;
113
- }
114
- return b;
115
- };
116
- for (var _i = 0, tables_2 = tables; _i < tables_2.length; _i++) {
117
- var table = tables_2[_i];
118
- for (var _a = 0, table_1 = table; _a < table_1.length; _a++) {
119
- var row = table_1[_a];
120
- var key = "".concat(row.name, "_").concat(row.year);
121
- var curRow = compensationByNameYear.get(key) || row;
122
- compensationByNameYear.set(key, curRow);
123
- for (var key_1 in row) {
124
- var k = key_1;
125
- curRow[k] = resolveProperty(curRow[k], row[k]);
126
- }
127
- }
128
- }
129
- return Array.from(compensationByNameYear.values());
130
- }
131
- function mergeYearRows(compensationTables) {
132
- var _a;
133
- var isDefaultPosition = function (position) { return position === 'Director' || position === 'Executive'; };
134
- var positionByName = new Map();
135
- for (var _i = 0, compensationTables_1 = compensationTables; _i < compensationTables_1.length; _i++) {
136
- var table = compensationTables_1[_i];
137
- var uniqueYears = Array.from(new Set(table.map(function (row) { return row.year; }))).filter(Boolean);
138
- if (uniqueYears.length <= 1)
139
- continue;
140
- var isDesc = uniqueYears[0] > uniqueYears[1];
141
- for (var i = 1; i < table.length; i++) {
142
- var row = table[i];
143
- var rowPrev = table[i - 1];
144
- var year = Number(row.year);
145
- var yearPrev = Number(rowPrev.year);
146
- if (yearPrev && !year) {
147
- year = isDesc ? yearPrev - 1 : yearPrev + 1;
148
- row.year = year;
149
- }
150
- else if (!yearPrev && year) {
151
- yearPrev = isDesc ? year - 1 : year + 1;
152
- rowPrev.year = yearPrev;
153
- }
154
- var isIncrementYear = isDesc ? year < yearPrev : year > yearPrev;
155
- var isSamePersonDiffYear = isIncrementYear && year && yearPrev;
156
- var isSameName = row.name === rowPrev.name;
157
- var isSamePosition = row.position === rowPrev.position;
158
- var mergedNamePosition = "".concat(isSameName ? '' : row.name || '', " ").concat(isDefaultPosition(row.position) || isSamePosition ? '' : row.position || '').trim();
159
- var mergedPosition = isDefaultPosition(rowPrev.position)
160
- ? mergedNamePosition
161
- : "".concat(rowPrev.position || '', " ").concat(mergedNamePosition).trim();
162
- var nameNew = rowPrev.name || row.name;
163
- var positionNew = ((_a = rowPrev.position) === null || _a === void 0 ? void 0 : _a.includes(mergedNamePosition)) ? rowPrev.position : mergedPosition;
164
- if (isSamePersonDiffYear) {
165
- rowPrev.position = positionNew;
166
- row.position = positionNew;
167
- rowPrev.name = nameNew;
168
- row.name = nameNew;
169
- }
170
- positionByName.set(row.name, String(row.position));
171
- }
172
- for (var _b = 0, table_2 = table; _b < table_2.length; _b++) {
173
- var row = table_2[_b];
174
- row.position = positionByName.get(row.name) || row.position;
175
- }
176
- }
177
- }
@@ -6,6 +6,10 @@ export interface SetReportDatesParams {
6
6
  isAnnual: boolean;
7
7
  accn: string;
8
8
  }
9
+ /**
10
+ * Gets the fiscal period for a given date. does this by checking when the FY end periods are,
11
+ * Then measures the offset from the end date to the next/previous fiscal year end.
12
+ */
9
13
  export default class FactFiscalCalculator {
10
14
  private readonly endDateByYear;
11
15
  private readonly fiscalsByEndDate;
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Gets the fiscal period for a given date. does this by checking when the FY end periods are,
5
+ * Then measures the offset from the end date to the next/previous fiscal year end.
6
+ */
3
7
  var FactFiscalCalculator = /** @class */ (function () {
4
8
  function FactFiscalCalculator() {
5
9
  this.endDateByYear = new Map();
@@ -1,4 +1,9 @@
1
1
  import { FiscalPeriod } from '../../types/report-raw.type';
2
+ /**
3
+ * Resolves quarterly and annual values for a property. This is because filers provide total values for the
4
+ * current fiscal year, rather than values for the individual quarters
5
+ * ex: Net income for Q2 will give 6 months revenue, not 3 month.
6
+ */
2
7
  export default class FactPeriodResolver {
3
8
  /** Values for each quarter [numQ1, numQ2, numQ3, numQ4] */
4
9
  private readonly valueByQuarterByPropertyByYear;
@@ -30,8 +35,7 @@ export default class FactPeriodResolver {
30
35
  end: string;
31
36
  value: number | string;
32
37
  name: string;
33
- dateReport: string;
34
- dateFiled: string;
38
+ filed: string;
35
39
  }): void;
36
40
  private readonly unresolvedReports;
37
41
  private buildUnresolvedReports;
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  var ReportRawResolvable_1 = require("./ReportRawResolvable");
4
+ /**
5
+ * Resolves quarterly and annual values for a property. This is because filers provide total values for the
6
+ * current fiscal year, rather than values for the individual quarters
7
+ * ex: Net income for Q2 will give 6 months revenue, not 3 month.
8
+ */
4
9
  var FactPeriodResolver = /** @class */ (function () {
5
10
  function FactPeriodResolver(args) {
6
11
  /** Values for each quarter [numQ1, numQ2, numQ3, numQ4] */
@@ -111,7 +116,7 @@ var FactPeriodResolver = /** @class */ (function () {
111
116
  return report;
112
117
  };
113
118
  FactPeriodResolver.prototype.add = function (params) {
114
- var year = params.year, value = params.value, propertyName = params.name, quarter = params.quarter, start = params.start, end = params.end, dateReport = params.dateReport, dateFiled = params.dateFiled;
119
+ var year = params.year, value = params.value, propertyName = params.name, quarter = params.quarter, start = params.start, end = params.end, filed = params.filed;
115
120
  var period = this.getPeriod({ start: start, end: end });
116
121
  this.addPropertyByYear(this.propertiesByYear, year, propertyName);
117
122
  if (typeof value === 'string') {
@@ -1,7 +1,10 @@
1
1
  import { FactItem } from './ReportBuilder';
2
2
  import { CompanyFactListData } from '../../types';
3
+ /**
4
+ * Builds an array of fact records.
5
+ */
3
6
  export default class FactRecordBuilder {
4
- createFacts(data: CompanyFactListData): {
7
+ createFacts(data: CompanyFactListData, filterDuplicates?: boolean): {
5
8
  facts: FactItem[];
6
9
  };
7
10
  }
@@ -1,11 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Builds an array of fact records.
5
+ */
3
6
  var FactRecordBuilder = /** @class */ (function () {
4
7
  function FactRecordBuilder() {
5
8
  }
6
- FactRecordBuilder.prototype.createFacts = function (data) {
9
+ FactRecordBuilder.prototype.createFacts = function (data, filterDuplicates) {
10
+ if (filterDuplicates === void 0) { filterDuplicates = false; }
7
11
  var facts = data.facts, cik = data.cik;
8
- var factItems = [];
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
+ };
9
20
  for (var prefix in facts) {
10
21
  var factByPropertyName = facts[prefix];
11
22
  for (var propertyName in factByPropertyName) {
@@ -15,6 +26,7 @@ var FactRecordBuilder = /** @class */ (function () {
15
26
  for (var _i = 0, factValues_1 = factValues; _i < factValues_1.length; _i++) {
16
27
  var factValue = factValues_1[_i];
17
28
  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 });
18
30
  var name_1 = "".concat(prefix, ":").concat(propertyName);
19
31
  var item = {
20
32
  cik: cik,
@@ -37,12 +49,22 @@ var FactRecordBuilder = /** @class */ (function () {
37
49
  item.frame = frame;
38
50
  if (fy)
39
51
  item.fy = fy;
40
- factItems.push(item);
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
+ }
41
63
  }
42
64
  }
43
65
  }
44
66
  }
45
- return { facts: factItems };
67
+ return { facts: Array.from(factsByKey.values()) };
46
68
  };
47
69
  return FactRecordBuilder;
48
70
  }());
@@ -6,10 +6,15 @@ interface SplitData {
6
6
  value: number;
7
7
  firstFiled: string;
8
8
  fiscalYear: number;
9
+ fiscalPeriod: FiscalPeriod;
9
10
  }
10
11
  type FactItemWithFiscalsNumeric = Omit<FactItemWithFiscals, 'cik' | 'value'> & {
11
12
  value: number;
12
13
  };
14
+ /**
15
+ * Adjust share-based property values for splits. Checks where the split was applied,
16
+ * and adjusts all previously filed share facts accordingly.
17
+ */
13
18
  export default class FactSplitAdjuster {
14
19
  private readonly splitKey;
15
20
  private readonly splitByFiscalYearAmount;
@@ -18,10 +23,16 @@ export default class FactSplitAdjuster {
18
23
  private readonly resolvedProperties;
19
24
  private sortedSplits;
20
25
  private getMap;
21
- add(fact: FactItemWithFiscalsNumeric): void;
26
+ private filedFirstLastBySplitKey;
27
+ add(fact: FactItemWithFiscalsNumeric & {
28
+ filedLast?: string;
29
+ }): void;
22
30
  getSplitsAsc(): SplitData[];
23
31
  isSplitProperty(propertyName: string): boolean;
24
32
  addSplitData(data: Omit<SplitData, 'firstFiled'>): void;
33
+ /**
34
+ * TODO: Find a more reliable way of checking if the split has already been applied.
35
+ */
25
36
  private didApplySplit;
26
37
  isSplitAdjustableUnit(unit: string): boolean;
27
38
  isShareRatioUnit(unit: string): boolean;
@@ -11,6 +11,10 @@ var __assign = (this && this.__assign) || function () {
11
11
  return __assign.apply(this, arguments);
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
+ /**
15
+ * Adjust share-based property values for splits. Checks where the split was applied,
16
+ * and adjusts all previously filed share facts accordingly.
17
+ */
14
18
  var FactSplitAdjuster = /** @class */ (function () {
15
19
  function FactSplitAdjuster() {
16
20
  this.splitKey = 'StockholdersEquityNoteStockSplitConversionRatio1';
@@ -19,15 +23,17 @@ var FactSplitAdjuster = /** @class */ (function () {
19
23
  this.factsAnnaulByYearByPropertyName = new Map();
20
24
  this.resolvedProperties = new Set();
21
25
  this.sortedSplits = null;
26
+ this.filedFirstLastBySplitKey = new Map();
22
27
  }
23
28
  FactSplitAdjuster.prototype.getMap = function (map, propertyName) {
24
29
  var _a;
25
30
  return (_a = map.get(propertyName)) !== null && _a !== void 0 ? _a : map.set(propertyName, new Map()).get(propertyName);
26
31
  };
27
32
  FactSplitAdjuster.prototype.add = function (fact) {
33
+ var _a;
28
34
  var propertyName = fact.name, year = fact.year, fiscalPeriod = fact.fiscalPeriod, unit = fact.unit, filed = fact.filed, value = fact.value, end = fact.end;
29
35
  if (this.isSplitProperty(propertyName)) {
30
- this.addSplitData({ end: end, filed: filed, fiscalYear: year, value: Number(value) });
36
+ this.addSplitData({ end: end, filed: filed, fiscalYear: year, value: Number(value), fiscalPeriod: fiscalPeriod });
31
37
  return;
32
38
  }
33
39
  if (!this.isSplitAdjustableUnit(unit))
@@ -40,6 +46,10 @@ var FactSplitAdjuster = /** @class */ (function () {
40
46
  ? this.getMap(this.factsAnnaulByYearByPropertyName, propertyName)
41
47
  : this.getMap(this.factsByYearQuarterByPropertyName, propertyName);
42
48
  var key = "".concat(year, "_").concat(fiscalPeriod);
49
+ this.filedFirstLastBySplitKey.set(key, {
50
+ firstFiled: filed,
51
+ lastFiled: (_a = fact.filedLast) !== null && _a !== void 0 ? _a : filed,
52
+ });
43
53
  map.set(key, fact);
44
54
  };
45
55
  FactSplitAdjuster.prototype.getSplitsAsc = function () {
@@ -84,23 +94,30 @@ var FactSplitAdjuster = /** @class */ (function () {
84
94
  this.sortedSplits = null;
85
95
  }
86
96
  };
97
+ /**
98
+ * TODO: Find a more reliable way of checking if the split has already been applied.
99
+ */
87
100
  FactSplitAdjuster.prototype.didApplySplit = function (params) {
88
- var nextValue = params.nextValue, prevValue = params.prevValue, split = params.split, isShareRatio = params.isShareRatio, value = params.value, filed = params.filed;
89
- if (filed > split.filed) {
101
+ var _a;
102
+ var isShareRatio = params.isShareRatio, nextFact = params.nextFact, prevFact = params.prevFact, fact = params.fact, split = params.split;
103
+ var _b = (_a = this.filedFirstLastBySplitKey.get("".concat(split.fiscalYear, "_").concat(split.fiscalPeriod))) !== null && _a !== void 0 ? _a : {}, firstFiled = _b.firstFiled, lastFiled = _b.lastFiled;
104
+ if (fact.filed > lastFiled) {
90
105
  return true;
91
106
  }
92
- if (filed < split.firstFiled) {
107
+ if (fact.filed < firstFiled) {
93
108
  return false;
94
109
  }
95
- var valWithSplit = isShareRatio ? value / split.value : value * split.value;
96
- if (nextValue !== null) {
97
- var difference = Math.abs(nextValue - value);
98
- var differenceSplit = Math.abs(nextValue - valWithSplit);
110
+ var val = fact.value;
111
+ var splitVal = split.value;
112
+ var valWithSplit = isShareRatio ? splitVal * val : val / splitVal;
113
+ if (nextFact) {
114
+ var difference = Math.abs(nextFact.value - val);
115
+ var differenceSplit = Math.abs(nextFact.value - valWithSplit);
99
116
  return difference < differenceSplit;
100
117
  }
101
- if (prevValue !== null) {
102
- var difference = Math.abs(prevValue - value);
103
- var differenceSplit = Math.abs(prevValue - valWithSplit);
118
+ if (prevFact) {
119
+ var difference = Math.abs(prevFact.value - val);
120
+ var differenceSplit = Math.abs(prevFact.value - valWithSplit);
104
121
  return difference < differenceSplit;
105
122
  }
106
123
  return false;
@@ -154,7 +171,7 @@ var FactSplitAdjuster = /** @class */ (function () {
154
171
  });
155
172
  };
156
173
  FactSplitAdjuster.prototype.adjustValuesForSplits = function (params) {
157
- var _a, _b, _c, _d;
174
+ var _a, _b;
158
175
  var facts = params.facts;
159
176
  var splits = this.getSplitsAsc();
160
177
  if (facts.length === 0 || splits.length === 0)
@@ -165,17 +182,22 @@ var FactSplitAdjuster = /** @class */ (function () {
165
182
  for (var factIndex = facts.length - 1; factIndex >= 0; factIndex--) {
166
183
  var fact = facts[factIndex];
167
184
  var value = fact.value, filed = fact.filed;
168
- var nextValue = (_b = (_a = facts[factIndex + 1]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null;
169
- var prevValue = (_d = (_c = facts[factIndex - 1]) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : null;
185
+ var nextFact = (_a = facts[factIndex + 1]) !== null && _a !== void 0 ? _a : null;
186
+ var prevFact = (_b = facts[factIndex - 1]) !== null && _b !== void 0 ? _b : null;
187
+ // const nextValue = facts[factIndex + 1]?.value ?? null
188
+ // const prevValue = facts[factIndex - 1]?.value ?? null
170
189
  var didApplySplit = this.didApplySplit({
171
- filed: filed,
190
+ // filed,
172
191
  isShareRatio: isShareRatio,
173
- nextValue: nextValue,
174
- prevValue: prevValue,
192
+ // nextValue,
193
+ // prevValue,
194
+ fact: fact,
195
+ nextFact: nextFact,
196
+ prevFact: prevFact,
175
197
  split: split,
176
- value: value,
198
+ // value,
177
199
  });
178
- if (didApplySplit) {
200
+ if (didApplySplit || !split.value) {
179
201
  continue;
180
202
  }
181
203
  if (isShareRatio) {
@@ -25,6 +25,9 @@ export interface FactItemWithFiscals extends FactItem {
25
25
  fiscalPeriod: FiscalPeriod;
26
26
  year: number;
27
27
  }
28
+ /**
29
+ * Builds ReportRaw objects from facts. also applies splits and adjusts for fiscal periods.
30
+ */
28
31
  export default class ReportBuilder {
29
32
  private readonly factRecordBuilder;
30
33
  createFacts(companyFacts: CompanyFactListData): {