sec-edgar-api
Version:
Fetch and parse SEC earnings reports and other filings. Useful for financial analysis.
96 lines (95 loc) • 4.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTaxonomyFromId = exports.getLabelByTaxonomy = exports.getPrimaryDocumentation = exports.getPrimaryLabel = exports.getLabelsByTypeByTaxonomy = void 0;
function getLabelsByTypeByTaxonomy(labelLinkbase) {
var _a;
var labelsByTypeByTaxonomy = {};
(_a = labelLinkbase === null || labelLinkbase === void 0 ? void 0 : labelLinkbase.labelLink) === null || _a === void 0 ? void 0 : _a.forEach(function (link) {
var _a;
(_a = link.label) === null || _a === void 0 ? void 0 : _a.forEach(function (_a) {
var _b;
var _c = _a.label, label = _c === void 0 ? '' : _c, _d = _a.text, text = _d === void 0 ? '' : _d, _e = _a.role, role = _e === void 0 ? '' : _e;
var taxonomy = getTaxonomyFromId(label);
var labelType = role.substring(role.lastIndexOf('/') + 1);
(_b = labelsByTypeByTaxonomy[taxonomy]) !== null && _b !== void 0 ? _b : (labelsByTypeByTaxonomy[taxonomy] = {});
labelsByTypeByTaxonomy[taxonomy][labelType] = text;
});
});
return labelsByTypeByTaxonomy;
}
exports.getLabelsByTypeByTaxonomy = getLabelsByTypeByTaxonomy;
/**
* The primary label based on priority: verboseLabel > terseLabel > label > periodEndLabel > first available label (excluding periodStartLabel)
*
* @param labelsByType The result of getLabelsByTypeByTaxonomy[key]
*/
function getPrimaryLabel(labelsByType) {
var _a, _b;
var preferredLabel = labelsByType.verboseLabel || labelsByType.terseLabel || labelsByType.label || labelsByType.periodEndLabel;
if (preferredLabel)
return preferredLabel;
// return the first available label that is not periodStartLabel
return (_b = (_a = Object.entries(labelsByType).find(function (_a) {
var k = _a[0], v = _a[1];
return k !== 'periodStartLabel' && v.length > 0;
})) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : '';
}
exports.getPrimaryLabel = getPrimaryLabel;
/**
* The primary documentation based on priority: documentation > longest available label
*
* @param labelsByType The result of getLabelsByTypeByTaxonomy[key]
*/
function getPrimaryDocumentation(labelsByType) {
if (labelsByType.documentation)
return labelsByType.documentation;
var validKeys = Object.keys(labelsByType).filter(function (key) { return key !== 'periodStartLabel'; });
return validKeys.reduce(function (acc, curr) { return (acc.length > curr.length ? acc : curr); }, '');
}
exports.getPrimaryDocumentation = getPrimaryDocumentation;
/**
* Gets labels by taxonomy from the label linkbase. priority level: verboseLabel > terseLabel > label.
*/
function getLabelByTaxonomy(labelLinkbase) {
var labelByTaxonomy = {};
var labelsByTypeByTaxonomy = getLabelsByTypeByTaxonomy(labelLinkbase);
for (var taxonomy in labelsByTypeByTaxonomy) {
labelByTaxonomy[taxonomy] = getPrimaryLabel(labelsByTypeByTaxonomy[taxonomy]);
}
return labelByTaxonomy;
}
exports.getLabelByTaxonomy = getLabelByTaxonomy;
function isPascaleCase(str) {
var startsWithUpperCase = str && str[0].toLowerCase() !== str[0];
return startsWithUpperCase && str.split('').some(function (c) { return c.toLowerCase() === c; });
}
var knownPrefixes = {
'us-gaap': true,
'ifrs-full': true,
dei: true,
srt: true,
country: true,
};
function getTaxonomyFromId(id) {
var parts = id.split('_');
var isLabelIndicatorPosition3 = parts[2] === 'lbl';
var isKnownPrefixPosition1 = knownPrefixes[parts[0]] === true;
var isNameInPosition2 = parts.length <= 2 || isLabelIndicatorPosition3 || isKnownPrefixPosition1 || isPascaleCase(parts[1]);
var result = isNameInPosition2 ? parts.slice(0, 2).join(':') : parts.slice(1, 3).join(':');
// this happens when the prefix is touching the concept name like "loc_us-gaapAssetsCurrent_lab".
// The symbol "GAN" has this issue.
if (result.startsWith('loc:')) {
var idWithoutLoc_1 = id.substring(4);
var knownPrefix = Object.keys(knownPrefixes).find(function (prefix) { return idWithoutLoc_1.startsWith(prefix); });
if (knownPrefix) {
return "".concat(knownPrefix, ":").concat(idWithoutLoc_1.substring(knownPrefix.length).split('_')[0]);
}
// custom taxonomy, assume the first capital letter followed by a lowercase is the concept name. ex: GANAssetsCurrentCustomConcept.match(/([A-Z][a-z]+)/)
var indexUpperFollowedByLower = idWithoutLoc_1.search(/[a-z]/) - 1;
var customPrefix = idWithoutLoc_1.substring(0, indexUpperFollowedByLower);
var conceptName = idWithoutLoc_1.substring(indexUpperFollowedByLower).split('_')[0];
return "".concat(customPrefix, ":").concat(conceptName.replace(/'|"/g, ''));
}
return result.replace(/'|"/g, '');
}
exports.getTaxonomyFromId = getTaxonomyFromId;