@cyanheads/secedgar-mcp-server 0.13.1 → 0.15.0
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.
- package/README.md +63 -7
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/prompts/definitions/company-analysis.prompt.d.ts.map +1 -1
- package/dist/mcp-server/prompts/definitions/company-analysis.prompt.js +11 -7
- package/dist/mcp-server/prompts/definitions/company-analysis.prompt.js.map +1 -1
- package/dist/mcp-server/resources/definitions/filing-types.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/filing-types.resource.js +24 -2
- package/dist/mcp-server/resources/definitions/filing-types.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/compare-companies.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/compare-companies.tool.js +25 -11
- package/dist/mcp-server/tools/definitions/compare-companies.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/find-holders.tool.d.ts +61 -0
- package/dist/mcp-server/tools/definitions/find-holders.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/find-holders.tool.js +396 -0
- package/dist/mcp-server/tools/definitions/find-holders.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.d.ts +93 -0
- package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.js +457 -0
- package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-financials.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-financials.tool.js +34 -17
- package/dist/mcp-server/tools/definitions/get-financials.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.d.ts +88 -0
- package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.js +674 -0
- package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-institutional-holdings.tool.d.ts +3 -2
- package/dist/mcp-server/tools/definitions/get-institutional-holdings.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-institutional-holdings.tool.js +11 -6
- package/dist/mcp-server/tools/definitions/get-institutional-holdings.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-material-events.tool.d.ts +63 -0
- package/dist/mcp-server/tools/definitions/get-material-events.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-material-events.tool.js +380 -0
- package/dist/mcp-server/tools/definitions/get-material-events.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-snapshot.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-snapshot.tool.js +30 -8
- package/dist/mcp-server/tools/definitions/get-snapshot.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-filings.tool.d.ts +10 -13
- package/dist/mcp-server/tools/definitions/search-filings.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-filings.tool.js +295 -133
- package/dist/mcp-server/tools/definitions/search-filings.tool.js.map +1 -1
- package/dist/services/edgar/beneficial-ownership-parser.d.ts +70 -0
- package/dist/services/edgar/beneficial-ownership-parser.d.ts.map +1 -0
- package/dist/services/edgar/beneficial-ownership-parser.js +157 -0
- package/dist/services/edgar/beneficial-ownership-parser.js.map +1 -0
- package/dist/services/edgar/concept-map.d.ts +3 -1
- package/dist/services/edgar/concept-map.d.ts.map +1 -1
- package/dist/services/edgar/concept-map.js +45 -5
- package/dist/services/edgar/concept-map.js.map +1 -1
- package/dist/services/edgar/concept-series.d.ts +94 -22
- package/dist/services/edgar/concept-series.d.ts.map +1 -1
- package/dist/services/edgar/concept-series.js +171 -33
- package/dist/services/edgar/concept-series.js.map +1 -1
- package/dist/services/edgar/edgar-api-service.d.ts +85 -0
- package/dist/services/edgar/edgar-api-service.d.ts.map +1 -1
- package/dist/services/edgar/edgar-api-service.js +153 -1
- package/dist/services/edgar/edgar-api-service.js.map +1 -1
- package/dist/services/edgar/eight-k-items.d.ts +62 -0
- package/dist/services/edgar/eight-k-items.d.ts.map +1 -0
- package/dist/services/edgar/eight-k-items.js +131 -0
- package/dist/services/edgar/eight-k-items.js.map +1 -0
- package/dist/services/edgar/nport-parser.d.ts +68 -0
- package/dist/services/edgar/nport-parser.d.ts.map +1 -0
- package/dist/services/edgar/nport-parser.js +102 -0
- package/dist/services/edgar/nport-parser.js.map +1 -0
- package/dist/services/edgar/types.d.ts +39 -0
- package/dist/services/edgar/types.d.ts.map +1 -1
- package/dist/services/edgar/xml-nodes.d.ts +31 -0
- package/dist/services/edgar/xml-nodes.d.ts.map +1 -0
- package/dist/services/edgar/xml-nodes.js +74 -0
- package/dist/services/edgar/xml-nodes.js.map +1 -0
- package/package.json +1 -1
- package/server.json +3 -3
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* than re-implementing the rules.
|
|
9
9
|
* @module services/edgar/concept-series
|
|
10
10
|
*/
|
|
11
|
-
import type { CompanyConceptUnit, CompanyFactsResponse } from './types.js';
|
|
11
|
+
import type { CompanyConceptUnit, CompanyFactsResponse, ConceptTaxonomy, TagSelection } from './types.js';
|
|
12
12
|
/** A reported value carrying the priority index of the tag that produced it. */
|
|
13
13
|
export interface TagPrioritizedUnit extends CompanyConceptUnit {
|
|
14
14
|
/** Position of the source tag in the concept's tag array. Lower wins a collision. */
|
|
@@ -20,33 +20,100 @@ export interface FramedUnit extends CompanyConceptUnit {
|
|
|
20
20
|
}
|
|
21
21
|
/** Period filter applied to a resolved series. */
|
|
22
22
|
export type PeriodType = 'annual' | 'quarterly' | 'all';
|
|
23
|
+
/**
|
|
24
|
+
* Original index of the tag that answers the concept for this filer, or
|
|
25
|
+
* `undefined` when no tag reported anything. This is the tag whose label,
|
|
26
|
+
* description, and unit describe the resolved series.
|
|
27
|
+
*/
|
|
28
|
+
export declare function preferredTagIndex(units: readonly TagPrioritizedUnit[], selection?: TagSelection): number | undefined;
|
|
23
29
|
/**
|
|
24
30
|
* Collapse a company's reported values to one per standard calendar period.
|
|
25
31
|
*
|
|
26
|
-
* Values with no `frame` are non-standard periods and are dropped.
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* `
|
|
31
|
-
*
|
|
32
|
-
*
|
|
32
|
+
* Values with no `frame` are non-standard periods and are dropped. What happens
|
|
33
|
+
* to the rest depends on the selection, because the two selections describe
|
|
34
|
+
* different relationships between the tags.
|
|
35
|
+
*
|
|
36
|
+
* Under the default `priority` the tags are a ladder, so the whole array
|
|
37
|
+
* contributes: a same-frame collision goes to the lower array index (index 0 is
|
|
38
|
+
* the preferred total, e.g. IFRS `Revenue` over the
|
|
39
|
+
* `RevenueFromContractsWithCustomers` sub-line) and a lower tag fills the frames
|
|
40
|
+
* the leader does not report.
|
|
41
|
+
*
|
|
42
|
+
* Under `coverage` the tags are alternates the filer chooses between, so only
|
|
43
|
+
* the tag it maintains contributes and the others drop out entirely. Letting a
|
|
44
|
+
* loser fill the winner's gaps would splice two definitions into one series: the
|
|
45
|
+
* filers that report both tags disagree on the years they overlap — Ferrari
|
|
46
|
+
* tags CY2022 at EUR 16.2M under the employee element and EUR 20.9M under the
|
|
47
|
+
* IFRS 2.51(a) total — so a gap-filled series prints a step that is a tag
|
|
48
|
+
* switch, not a business fact. A series that then ends years back is what
|
|
49
|
+
* {@link seriesStalenessCaveats} exists to report (#101, #102).
|
|
50
|
+
*
|
|
51
|
+
* Within one tag, the later `filed` date wins so an amended filing replaces the
|
|
52
|
+
* original. Returns an empty map when nothing carried a frame — the caller
|
|
53
|
+
* distinguishes that from "the concept is not reported at all".
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveFrameSeries(units: readonly TagPrioritizedUnit[], selection?: TagSelection): Map<string, FramedUnit>;
|
|
56
|
+
/** What a series' newest period is being measured against. */
|
|
57
|
+
export interface StalenessReference {
|
|
58
|
+
/** The date itself (YYYY-MM-DD). */
|
|
59
|
+
date: string;
|
|
60
|
+
/**
|
|
61
|
+
* `reported-period` — the newest period end this filer reports across every
|
|
62
|
+
* concept read from the same companyfacts payload. The strongest reference:
|
|
63
|
+
* it isolates a line that lags the filer's own reporting, and stays silent for
|
|
64
|
+
* a filer that stopped filing altogether, whose whole profile is equally old
|
|
65
|
+
* and would otherwise repeat one warning per concept.
|
|
66
|
+
*
|
|
67
|
+
* `current-date` — today. What a single-concept read has, since one
|
|
68
|
+
* companyconcept payload carries no filer-wide period to compare against and
|
|
69
|
+
* fetching one would cost an extra upstream call.
|
|
70
|
+
*/
|
|
71
|
+
kind: 'current-date' | 'reported-period';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Newest standard calendar period this filer reports anywhere in the supported
|
|
75
|
+
* concept catalog, as a `reported-period` reference for
|
|
76
|
+
* {@link seriesStalenessCaveats}. Empty string when the filer reports none of
|
|
77
|
+
* them under this taxonomy.
|
|
78
|
+
*
|
|
79
|
+
* Reads the whole catalog rather than only the concepts a caller asked about,
|
|
80
|
+
* because the reference has to be independent of the request: a comparison of
|
|
81
|
+
* one concept would otherwise measure that concept against itself and could
|
|
82
|
+
* never report it as lagging. Scans candidate tags directly instead of
|
|
83
|
+
* resolving series — only the newest framed period is needed, and the payload
|
|
84
|
+
* is already in hand, so this adds no upstream call.
|
|
85
|
+
*
|
|
86
|
+
* The `dei` namespace is excluded. Cover-page facts track the *filing*, not the
|
|
87
|
+
* financial statements, so a registrant that stopped reporting under this
|
|
88
|
+
* taxonomy keeps a current `dei` period anyway — Toyota migrated its XBRL from
|
|
89
|
+
* us-gaap to IFRS after fiscal 2020, and a reference that counted `dei` put its
|
|
90
|
+
* us-gaap profile six years behind a cover-page date and flagged all 28 of its
|
|
91
|
+
* lines at once. Excluding it is what keeps the reference a statement of what
|
|
92
|
+
* the filer reports and preserves the silence for a filer whose whole profile is
|
|
93
|
+
* equally old. It also makes the two taxonomies agree: `shares_outstanding` is
|
|
94
|
+
* the only `dei` concept, and an `ifrs-full` request never resolved it there.
|
|
33
95
|
*/
|
|
34
|
-
export declare function
|
|
96
|
+
export declare function newestReportedPeriod(facts: CompanyFactsResponse, taxonomy: ConceptTaxonomy): string;
|
|
35
97
|
/**
|
|
36
|
-
* Caveat for a
|
|
98
|
+
* Caveat for a resolved series whose newest value is far enough behind the
|
|
99
|
+
* reference that the caller should not read it as current.
|
|
100
|
+
*
|
|
101
|
+
* Two causes, one symptom. A friendly name is an ordered list of tags walked
|
|
102
|
+
* until one returns data, so a tag SEC retired can win when every current tag
|
|
103
|
+
* comes back empty for a filer, producing a series that looks complete but stops
|
|
104
|
+
* around the tag's retirement (#98) — SEC ships that tell in the taxonomy label
|
|
105
|
+
* it serves with the payload. A *current* tag produces the same shape with no
|
|
106
|
+
* tell at all when the filer migrates to another element or stops disclosing the
|
|
107
|
+
* line, so the fallback signal is the gap itself (#102).
|
|
37
108
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* that looks complete but stops around the tag's retirement — the failure is
|
|
42
|
-
* otherwise silent, since nothing in the values themselves says the tag is dead.
|
|
43
|
-
* The signal is the taxonomy label SEC already ships with the payload, so this
|
|
44
|
-
* generalizes to any concept whose fallback chain reaches a retired tag rather
|
|
45
|
-
* than to one hard-coded pair.
|
|
109
|
+
* At most one caveat: the retirement stamp names the concrete cause and already
|
|
110
|
+
* says the series can end years short, so restating that as an elapsed-time
|
|
111
|
+
* measurement would be the same warning twice in different words.
|
|
46
112
|
*
|
|
47
|
-
* Returns an empty array for a current tag
|
|
113
|
+
* Returns an empty array for a current tag reporting through the reference,
|
|
114
|
+
* which is the common case.
|
|
48
115
|
*/
|
|
49
|
-
export declare function
|
|
116
|
+
export declare function seriesStalenessCaveats(tag: string, label: string, newest: FramedUnit | undefined, reference: StalenessReference): string[];
|
|
50
117
|
/**
|
|
51
118
|
* Whether a frame belongs to the requested period type. `fp` reflects the source
|
|
52
119
|
* filing rather than the data point, so the frame label is the only reliable
|
|
@@ -72,9 +139,14 @@ export interface ConceptSeries {
|
|
|
72
139
|
}
|
|
73
140
|
/**
|
|
74
141
|
* Resolve one concept from a companyfacts payload, applying the same tag
|
|
75
|
-
*
|
|
142
|
+
* selection and frame dedup as {@link resolveFrameSeries}. Returns `undefined`
|
|
76
143
|
* when the filer reports none of the candidate tags under this taxonomy, which
|
|
77
144
|
* the caller surfaces as a gap alongside the tags it tried.
|
|
145
|
+
*
|
|
146
|
+
* The reported `tag`, `label`, `description`, and `unit` come from the tag that
|
|
147
|
+
* won for this filer, not from the first one present — under `coverage` those
|
|
148
|
+
* differ, and describing the series by a tag that lost every frame would misname
|
|
149
|
+
* the values.
|
|
78
150
|
*/
|
|
79
|
-
export declare function seriesFromCompanyFacts(facts: CompanyFactsResponse, taxonomy: string, tags: readonly string[]): ConceptSeries | undefined;
|
|
151
|
+
export declare function seriesFromCompanyFacts(facts: CompanyFactsResponse, taxonomy: string, tags: readonly string[], selection?: TagSelection): ConceptSeries | undefined;
|
|
80
152
|
//# sourceMappingURL=concept-series.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"concept-series.d.ts","sourceRoot":"","sources":["../../../src/services/edgar/concept-series.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"concept-series.d.ts","sourceRoot":"","sources":["../../../src/services/edgar/concept-series.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,gFAAgF;AAChF,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,6EAA6E;AAC7E,MAAM,WAAW,UAAW,SAAQ,kBAAkB;IACpD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,kDAAkD;AAClD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,KAAK,CAAC;AAkCxD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,kBAAkB,EAAE,EACpC,SAAS,GAAE,YAAyB,GACnC,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,kBAAkB,EAAE,EACpC,SAAS,GAAE,YAAyB,GACnC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAwBzB;AAgBD,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;;;OAUG;IACH,IAAI,EAAE,cAAc,GAAG,iBAAiB,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,oBAAoB,EAC3B,QAAQ,EAAE,eAAe,GACxB,MAAM,CAgBR;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,SAAS,EAAE,kBAAkB,GAC5B,MAAM,EAAE,CA2BV;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAIhF;AAED,0DAA0D;AAC1D,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,oBAAoB,EAC3B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,SAAS,GAAE,YAAyB,GACnC,aAAa,GAAG,SAAS,CAsC3B"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* than re-implementing the rules.
|
|
9
9
|
* @module services/edgar/concept-series
|
|
10
10
|
*/
|
|
11
|
+
import { listConcepts, resolveConceptTarget } from './concept-map.js';
|
|
11
12
|
/**
|
|
12
13
|
* SEC stamps a retired element's retirement date into the taxonomy label it
|
|
13
14
|
* serves with every companyconcept and companyfacts payload — e.g.
|
|
@@ -19,20 +20,65 @@ const DEPRECATED_LABEL = /\(Deprecated\s+(\d{4}-\d{2}-\d{2})\)/i;
|
|
|
19
20
|
const ANNUAL_FRAME = /^CY\d{4}$/;
|
|
20
21
|
/** Quarterly frame — `CY2023Q3` (duration) or `CY2023Q3I` (instant). */
|
|
21
22
|
const QUARTERLY_FRAME = /^CY\d{4}Q\d/;
|
|
23
|
+
/**
|
|
24
|
+
* Tag positions ordered by how many standard calendar periods each covers for
|
|
25
|
+
* this filer, widest first, with the declared order breaking a tie. A tag that
|
|
26
|
+
* reported only non-standard periods counts as zero and sorts last rather than
|
|
27
|
+
* dropping out, so it can still supply a label when it is all the filer has.
|
|
28
|
+
*/
|
|
29
|
+
function coverageOrder(units) {
|
|
30
|
+
const framesByTag = new Map();
|
|
31
|
+
for (const unit of units) {
|
|
32
|
+
const frames = framesByTag.get(unit.tagIndex) ?? new Set();
|
|
33
|
+
if (unit.frame)
|
|
34
|
+
frames.add(unit.frame);
|
|
35
|
+
framesByTag.set(unit.tagIndex, frames);
|
|
36
|
+
}
|
|
37
|
+
return [...framesByTag.keys()].sort((a, b) => (framesByTag.get(b)?.size ?? 0) - (framesByTag.get(a)?.size ?? 0) || a - b);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Original index of the tag that answers the concept for this filer, or
|
|
41
|
+
* `undefined` when no tag reported anything. This is the tag whose label,
|
|
42
|
+
* description, and unit describe the resolved series.
|
|
43
|
+
*/
|
|
44
|
+
export function preferredTagIndex(units, selection = 'priority') {
|
|
45
|
+
if (units.length === 0)
|
|
46
|
+
return;
|
|
47
|
+
if (selection === 'coverage')
|
|
48
|
+
return coverageOrder(units)[0];
|
|
49
|
+
return units.reduce((lowest, unit) => Math.min(lowest, unit.tagIndex), Number.POSITIVE_INFINITY);
|
|
50
|
+
}
|
|
22
51
|
/**
|
|
23
52
|
* Collapse a company's reported values to one per standard calendar period.
|
|
24
53
|
*
|
|
25
|
-
* Values with no `frame` are non-standard periods and are dropped.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* `
|
|
30
|
-
*
|
|
31
|
-
*
|
|
54
|
+
* Values with no `frame` are non-standard periods and are dropped. What happens
|
|
55
|
+
* to the rest depends on the selection, because the two selections describe
|
|
56
|
+
* different relationships between the tags.
|
|
57
|
+
*
|
|
58
|
+
* Under the default `priority` the tags are a ladder, so the whole array
|
|
59
|
+
* contributes: a same-frame collision goes to the lower array index (index 0 is
|
|
60
|
+
* the preferred total, e.g. IFRS `Revenue` over the
|
|
61
|
+
* `RevenueFromContractsWithCustomers` sub-line) and a lower tag fills the frames
|
|
62
|
+
* the leader does not report.
|
|
63
|
+
*
|
|
64
|
+
* Under `coverage` the tags are alternates the filer chooses between, so only
|
|
65
|
+
* the tag it maintains contributes and the others drop out entirely. Letting a
|
|
66
|
+
* loser fill the winner's gaps would splice two definitions into one series: the
|
|
67
|
+
* filers that report both tags disagree on the years they overlap — Ferrari
|
|
68
|
+
* tags CY2022 at EUR 16.2M under the employee element and EUR 20.9M under the
|
|
69
|
+
* IFRS 2.51(a) total — so a gap-filled series prints a step that is a tag
|
|
70
|
+
* switch, not a business fact. A series that then ends years back is what
|
|
71
|
+
* {@link seriesStalenessCaveats} exists to report (#101, #102).
|
|
72
|
+
*
|
|
73
|
+
* Within one tag, the later `filed` date wins so an amended filing replaces the
|
|
74
|
+
* original. Returns an empty map when nothing carried a frame — the caller
|
|
75
|
+
* distinguishes that from "the concept is not reported at all".
|
|
32
76
|
*/
|
|
33
|
-
export function resolveFrameSeries(units) {
|
|
77
|
+
export function resolveFrameSeries(units, selection = 'priority') {
|
|
78
|
+
const winner = selection === 'coverage' ? preferredTagIndex(units, selection) : undefined;
|
|
79
|
+
const considered = winner === undefined ? units : units.filter((unit) => unit.tagIndex === winner);
|
|
34
80
|
const byFrame = new Map();
|
|
35
|
-
for (const unit of
|
|
81
|
+
for (const unit of considered) {
|
|
36
82
|
const { frame } = unit;
|
|
37
83
|
if (!frame)
|
|
38
84
|
continue;
|
|
@@ -50,25 +96,106 @@ export function resolveFrameSeries(units) {
|
|
|
50
96
|
return resolved;
|
|
51
97
|
}
|
|
52
98
|
/**
|
|
53
|
-
*
|
|
99
|
+
* Two full fiscal years closed with no newer value.
|
|
54
100
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
101
|
+
* One year is the floor a current filer can reach on its own: an annual-only
|
|
102
|
+
* concept sits a whole fiscal year behind until the next report lands, and a
|
|
103
|
+
* 20-F is due four months after fiscal year end (Form 12b-25 adds fifteen days,
|
|
104
|
+
* and SEC assigns the frame weeks after that), so a foreign private issuer with
|
|
105
|
+
* nothing wrong can show a newest annual period around 500 days old. Two years
|
|
106
|
+
* clears that by a wide margin and is the first gap that cannot be a filing
|
|
107
|
+
* artifact — the filer has closed and reported two annual periods since this
|
|
108
|
+
* line last carried a value.
|
|
109
|
+
*/
|
|
110
|
+
const STALE_AFTER_DAYS = 730;
|
|
111
|
+
/**
|
|
112
|
+
* Newest standard calendar period this filer reports anywhere in the supported
|
|
113
|
+
* concept catalog, as a `reported-period` reference for
|
|
114
|
+
* {@link seriesStalenessCaveats}. Empty string when the filer reports none of
|
|
115
|
+
* them under this taxonomy.
|
|
63
116
|
*
|
|
64
|
-
*
|
|
117
|
+
* Reads the whole catalog rather than only the concepts a caller asked about,
|
|
118
|
+
* because the reference has to be independent of the request: a comparison of
|
|
119
|
+
* one concept would otherwise measure that concept against itself and could
|
|
120
|
+
* never report it as lagging. Scans candidate tags directly instead of
|
|
121
|
+
* resolving series — only the newest framed period is needed, and the payload
|
|
122
|
+
* is already in hand, so this adds no upstream call.
|
|
123
|
+
*
|
|
124
|
+
* The `dei` namespace is excluded. Cover-page facts track the *filing*, not the
|
|
125
|
+
* financial statements, so a registrant that stopped reporting under this
|
|
126
|
+
* taxonomy keeps a current `dei` period anyway — Toyota migrated its XBRL from
|
|
127
|
+
* us-gaap to IFRS after fiscal 2020, and a reference that counted `dei` put its
|
|
128
|
+
* us-gaap profile six years behind a cover-page date and flagged all 28 of its
|
|
129
|
+
* lines at once. Excluding it is what keeps the reference a statement of what
|
|
130
|
+
* the filer reports and preserves the silence for a filer whose whole profile is
|
|
131
|
+
* equally old. It also makes the two taxonomies agree: `shares_outstanding` is
|
|
132
|
+
* the only `dei` concept, and an `ifrs-full` request never resolved it there.
|
|
133
|
+
*/
|
|
134
|
+
export function newestReportedPeriod(facts, taxonomy) {
|
|
135
|
+
let newest = '';
|
|
136
|
+
for (const entry of listConcepts()) {
|
|
137
|
+
const target = resolveConceptTarget(entry.name, taxonomy);
|
|
138
|
+
if (target.taxonomy === 'dei')
|
|
139
|
+
continue;
|
|
140
|
+
const namespace = facts.facts[target.taxonomy];
|
|
141
|
+
if (!namespace)
|
|
142
|
+
continue;
|
|
143
|
+
for (const tag of target.tags) {
|
|
144
|
+
for (const values of Object.values(namespace[tag]?.units ?? {})) {
|
|
145
|
+
for (const value of values) {
|
|
146
|
+
if (value.frame && value.end > newest)
|
|
147
|
+
newest = value.end;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return newest;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Caveat for a resolved series whose newest value is far enough behind the
|
|
156
|
+
* reference that the caller should not read it as current.
|
|
157
|
+
*
|
|
158
|
+
* Two causes, one symptom. A friendly name is an ordered list of tags walked
|
|
159
|
+
* until one returns data, so a tag SEC retired can win when every current tag
|
|
160
|
+
* comes back empty for a filer, producing a series that looks complete but stops
|
|
161
|
+
* around the tag's retirement (#98) — SEC ships that tell in the taxonomy label
|
|
162
|
+
* it serves with the payload. A *current* tag produces the same shape with no
|
|
163
|
+
* tell at all when the filer migrates to another element or stops disclosing the
|
|
164
|
+
* line, so the fallback signal is the gap itself (#102).
|
|
165
|
+
*
|
|
166
|
+
* At most one caveat: the retirement stamp names the concrete cause and already
|
|
167
|
+
* says the series can end years short, so restating that as an elapsed-time
|
|
168
|
+
* measurement would be the same warning twice in different words.
|
|
169
|
+
*
|
|
170
|
+
* Returns an empty array for a current tag reporting through the reference,
|
|
171
|
+
* which is the common case.
|
|
65
172
|
*/
|
|
66
|
-
export function
|
|
67
|
-
const
|
|
68
|
-
if (
|
|
173
|
+
export function seriesStalenessCaveats(tag, label, newest, reference) {
|
|
174
|
+
const retired = DEPRECATED_LABEL.exec(label);
|
|
175
|
+
if (retired?.[1]) {
|
|
176
|
+
return [
|
|
177
|
+
`XBRL tag ${tag} was retired from the taxonomy on ${retired[1]} — SEC labels it "${label}". It matched only because every current tag ahead of it in this concept's priority list reports nothing for this filer, so the series can end years before the filer's latest report. Check secedgar_search_concepts for the concept's full tag list, or pass the tag this filer reports today.`,
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
if (!newest)
|
|
181
|
+
return [];
|
|
182
|
+
const gapDays = (Date.parse(reference.date) - Date.parse(newest.end)) / 86_400_000;
|
|
183
|
+
if (!(gapDays >= STALE_AFTER_DAYS))
|
|
69
184
|
return [];
|
|
185
|
+
/**
|
|
186
|
+
* A `reported-period` reference means the caller already holds the filer's
|
|
187
|
+
* whole profile and can see which lines are current, so pointing it back at
|
|
188
|
+
* the snapshot would be pointing it at itself.
|
|
189
|
+
*/
|
|
190
|
+
const fromReportedPeriod = reference.kind === 'reported-period';
|
|
191
|
+
const behind = fromReportedPeriod
|
|
192
|
+
? `the newest period this filer reports (ending ${reference.date})`
|
|
193
|
+
: `today (${reference.date})`;
|
|
194
|
+
const next = fromReportedPeriod
|
|
195
|
+
? 'Check secedgar_search_concepts for this concept’s other tags and pass the one this filer reports today.'
|
|
196
|
+
: 'Check secedgar_search_concepts for this concept’s other tags, or secedgar_get_snapshot for what this filer reports today.';
|
|
70
197
|
return [
|
|
71
|
-
`
|
|
198
|
+
`This series ends at ${newest.frame}, period ending ${newest.end} — ${(gapDays / 365.25).toFixed(1)} years before ${behind}. ${tag} is a current tag, so nothing in the payload marks the gap: a filer that migrates to a different XBRL element, or stops disclosing the line, leaves a series that looks complete and simply stops. ${next}`,
|
|
72
199
|
];
|
|
73
200
|
}
|
|
74
201
|
/**
|
|
@@ -85,36 +212,47 @@ export function matchesPeriodType(frame, periodType) {
|
|
|
85
212
|
}
|
|
86
213
|
/**
|
|
87
214
|
* Resolve one concept from a companyfacts payload, applying the same tag
|
|
88
|
-
*
|
|
215
|
+
* selection and frame dedup as {@link resolveFrameSeries}. Returns `undefined`
|
|
89
216
|
* when the filer reports none of the candidate tags under this taxonomy, which
|
|
90
217
|
* the caller surfaces as a gap alongside the tags it tried.
|
|
218
|
+
*
|
|
219
|
+
* The reported `tag`, `label`, `description`, and `unit` come from the tag that
|
|
220
|
+
* won for this filer, not from the first one present — under `coverage` those
|
|
221
|
+
* differ, and describing the series by a tag that lost every frame would misname
|
|
222
|
+
* the values.
|
|
91
223
|
*/
|
|
92
|
-
export function seriesFromCompanyFacts(facts, taxonomy, tags) {
|
|
224
|
+
export function seriesFromCompanyFacts(facts, taxonomy, tags, selection = 'priority') {
|
|
93
225
|
const namespace = facts.facts[taxonomy];
|
|
94
226
|
if (!namespace)
|
|
95
227
|
return;
|
|
96
228
|
const units = [];
|
|
97
229
|
const tagsTried = [];
|
|
98
|
-
|
|
230
|
+
/** Keyed by tag position, in declared order, so the winner can be looked up. */
|
|
231
|
+
const reported = new Map();
|
|
99
232
|
for (const [tagIndex, tag] of tags.entries()) {
|
|
100
233
|
tagsTried.push(tag);
|
|
101
234
|
const concept = namespace[tag];
|
|
102
235
|
if (!concept?.units)
|
|
103
236
|
continue;
|
|
104
237
|
for (const [unitKey, values] of Object.entries(concept.units)) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
238
|
+
if (!reported.has(tagIndex)) {
|
|
239
|
+
reported.set(tagIndex, {
|
|
240
|
+
tag,
|
|
241
|
+
label: concept.label ?? tag,
|
|
242
|
+
unit: unitKey,
|
|
243
|
+
...(concept.description !== undefined ? { description: concept.description } : {}),
|
|
244
|
+
});
|
|
245
|
+
}
|
|
111
246
|
for (const value of values)
|
|
112
247
|
units.push({ ...value, tagIndex });
|
|
113
248
|
}
|
|
114
249
|
}
|
|
250
|
+
const winner = preferredTagIndex(units, selection);
|
|
251
|
+
/** Falls back to the first reporting tag when nothing carried a value to rank. */
|
|
252
|
+
const resolved = (winner !== undefined ? reported.get(winner) : undefined) ?? [...reported.values()][0];
|
|
115
253
|
if (!resolved)
|
|
116
254
|
return;
|
|
117
|
-
const series = [...resolveFrameSeries(units).values()].sort((a, b) => b.end.localeCompare(a.end));
|
|
255
|
+
const series = [...resolveFrameSeries(units, selection).values()].sort((a, b) => b.end.localeCompare(a.end));
|
|
118
256
|
return { ...resolved, series, tagsTried, taxonomy };
|
|
119
257
|
}
|
|
120
258
|
//# sourceMappingURL=concept-series.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"concept-series.js","sourceRoot":"","sources":["../../../src/services/edgar/concept-series.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"concept-series.js","sourceRoot":"","sources":["../../../src/services/edgar/concept-series.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,23 @@ export interface EntityNameMatch {
|
|
|
17
17
|
cik: string;
|
|
18
18
|
name: string;
|
|
19
19
|
}
|
|
20
|
+
/** One fund series of a registrant, as listed in company_tickers_mf.json. */
|
|
21
|
+
export interface FundSeriesEntry {
|
|
22
|
+
seriesId: string;
|
|
23
|
+
/** Ticker of the first listed share class of the series. */
|
|
24
|
+
ticker: string | undefined;
|
|
25
|
+
}
|
|
26
|
+
/** A registrant's filings of one form type, scoped to a single fund series. */
|
|
27
|
+
export interface SeriesFilingFeed {
|
|
28
|
+
filings: Array<{
|
|
29
|
+
accessionNumber: string;
|
|
30
|
+
filingDate: string;
|
|
31
|
+
form: string;
|
|
32
|
+
}>;
|
|
33
|
+
/** Registrant trust the series belongs to. Absent when the series is unknown to EDGAR. */
|
|
34
|
+
registrantCik: string | undefined;
|
|
35
|
+
registrantName: string | undefined;
|
|
36
|
+
}
|
|
20
37
|
/**
|
|
21
38
|
* Dice-coefficient trigram similarity between two strings.
|
|
22
39
|
* Returns a value in [0, 1]; 1 means identical.
|
|
@@ -73,6 +90,30 @@ declare class EdgarApiService {
|
|
|
73
90
|
resolveEntityByName(name: string): Promise<EntityNameMatch[]>;
|
|
74
91
|
/** Reverse lookup: CIK → ticker symbol. */
|
|
75
92
|
cikToTicker(cik: string): Promise<string | undefined>;
|
|
93
|
+
/**
|
|
94
|
+
* Resolve a fund series ID (`S000002839`) to its registrant trust. Backed by
|
|
95
|
+
* company_tickers_mf.json, which lists a series only once one of its share classes has a
|
|
96
|
+
* ticker — a series with no listed class resolves to `undefined` rather than a wrong trust.
|
|
97
|
+
*/
|
|
98
|
+
resolveFundSeries(seriesId: string): Promise<CikMatch | undefined>;
|
|
99
|
+
/**
|
|
100
|
+
* List a registrant's fund series, from the same company_tickers_mf.json index. A trust
|
|
101
|
+
* files one NPORT-P per series per period, so this is what tells a caller holding only a
|
|
102
|
+
* registrant CIK which series it must name. Covers series with at least one listed share
|
|
103
|
+
* class only — a trust whose series carry no ticker returns an empty list, which is not
|
|
104
|
+
* the same as having no series.
|
|
105
|
+
*/
|
|
106
|
+
listFundSeries(cik: string): Promise<FundSeriesEntry[]>;
|
|
107
|
+
/**
|
|
108
|
+
* List a fund series' own filings of one form type. EDGAR's company browse accepts a
|
|
109
|
+
* series ID (`S000002839`) in place of a CIK and answers with just that series' filings,
|
|
110
|
+
* which is the only SEC surface that maps a series to its accession numbers — the
|
|
111
|
+
* submissions feed and the full-text index both report a fund filing under the registrant
|
|
112
|
+
* trust with no series field, and a trust files one report per series per period. The
|
|
113
|
+
* response also names the registrant, so a bare series ID resolves without a second call.
|
|
114
|
+
* Entries come back newest-filed first and include amendments of the form.
|
|
115
|
+
*/
|
|
116
|
+
getFundSeriesFilings(seriesId: string, formType: string, count: number): Promise<SeriesFilingFeed>;
|
|
76
117
|
/** Return the current in-memory entry list (used by the handler for trigram suggestions). */
|
|
77
118
|
getAllEntries(): Promise<CikMatch[]>;
|
|
78
119
|
/**
|
|
@@ -130,6 +171,28 @@ declare class EdgarApiService {
|
|
|
130
171
|
* Fetch a filing document, returning `null` when the archive path exists but this document does not.
|
|
131
172
|
*/
|
|
132
173
|
tryGetFilingDocument(cik: string, accessionNumber: string, document: string): Promise<string | null>;
|
|
174
|
+
/**
|
|
175
|
+
* Fetch the leading bytes of a filing document, stopping as soon as `stopAt` appears in
|
|
176
|
+
* the decoded text or `maxBytes` have arrived. Returns `null` on 404, and the whole
|
|
177
|
+
* document when it is shorter than the cutoff.
|
|
178
|
+
*
|
|
179
|
+
* SEC's archive host ignores `Range` — a ranged request answers 200 with the full body —
|
|
180
|
+
* so there is no server-side partial fetch. The saving here is client-side: the response
|
|
181
|
+
* body is cancelled mid-stream, so a routing scan that inspects a multi-megabyte report's
|
|
182
|
+
* header pays for the leading part of it instead of the whole file. Neither cutoff can cut
|
|
183
|
+
* below one read chunk, because both checks run between reads and the runtime picks the
|
|
184
|
+
* boundary — Bun hands SEC archive documents back in 262,144-byte reads, so a `stopAt` that
|
|
185
|
+
* appears 1.5 KB in still costs 256 KB, and a `maxBytes` below that costs the same. Treat
|
|
186
|
+
* both as "one chunk, not the file" rather than as a byte budget; `maxBytes` binds only on
|
|
187
|
+
* a document long enough to arrive in several chunks, which is what stops a document
|
|
188
|
+
* missing `stopAt` entirely from being read to the end. A runtime that hands back no
|
|
189
|
+
* readable body (a stubbed fetch, for one) falls through to reading it whole, which costs
|
|
190
|
+
* bandwidth but returns the same text.
|
|
191
|
+
*/
|
|
192
|
+
tryGetFilingDocumentHead(cik: string, accessionNumber: string, document: string, options: {
|
|
193
|
+
maxBytes: number;
|
|
194
|
+
stopAt: string;
|
|
195
|
+
}): Promise<string | null>;
|
|
133
196
|
/**
|
|
134
197
|
* Search EDGAR submissions for recent filings of specified form types, newest first.
|
|
135
198
|
* Returns up to `limit` matches from the submissions recent-filings window. Each carries
|
|
@@ -221,6 +284,13 @@ declare class EdgarApiService {
|
|
|
221
284
|
*/
|
|
222
285
|
private buildTickerCache;
|
|
223
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* EDGAR's EFTS `display_names[0]` embeds the ticker(s) and CIK in trailing
|
|
289
|
+
* parentheticals (e.g. "Apple Inc. (AAPL) (CIK 0000320193)"). Strip them so
|
|
290
|
+
* consumers see a clean entity name — ticker and CIK are already surfaced as
|
|
291
|
+
* their own fields.
|
|
292
|
+
*/
|
|
293
|
+
export declare function cleanDisplayName(displayName: string): string;
|
|
224
294
|
/**
|
|
225
295
|
* Range-based selection of submissions archive-page manifest entries (`filings.files[]`),
|
|
226
296
|
* returned newest-first (by `filingTo` descending). A page's [filingFrom, filingTo]
|
|
@@ -240,6 +310,21 @@ export declare function selectArchivePages(files: SubmissionsResponse['filings']
|
|
|
240
310
|
* → `0000320193-97-000010`). Exported for direct unit testing.
|
|
241
311
|
*/
|
|
242
312
|
export declare function parseMasterIndex(text: string): FullIndexEntry[];
|
|
313
|
+
/**
|
|
314
|
+
* Parse EDGAR's company-browse Atom feed into the registrant identity plus one row per
|
|
315
|
+
* filing. A series ID EDGAR does not know answers 200 with its HTML no-match page rather
|
|
316
|
+
* than a feed, which carries neither `company-info` nor entries and so parses to an empty
|
|
317
|
+
* result — the caller's cue that the series is unknown. Exported for direct unit testing.
|
|
318
|
+
*/
|
|
319
|
+
export declare function parseSeriesFilingFeed(xml: string): SeriesFilingFeed;
|
|
320
|
+
/**
|
|
321
|
+
* Name of the raw XML document inside a filing's archive directory. The submissions feed
|
|
322
|
+
* points at the human-readable rendering (`xslSCHEDULE_13D_X02/primary_doc.xml`,
|
|
323
|
+
* `xslFormNPORT-P_X01/primary_doc.xml`); the raw document is the same basename at the root
|
|
324
|
+
* of that directory. Idempotent, and answers the conventional default name for a filing
|
|
325
|
+
* whose primary document the feed does not name.
|
|
326
|
+
*/
|
|
327
|
+
export declare function rawDocumentName(primaryDocument: string | undefined): string;
|
|
243
328
|
/**
|
|
244
329
|
* Enumerate the calendar quarters overlapping the inclusive [startDate, endDate]
|
|
245
330
|
* range (both YYYY-MM-DD), returned NEWEST-first to mirror `selectArchivePages`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edgar-api-service.d.ts","sourceRoot":"","sources":["../../../src/services/edgar/edgar-api-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"edgar-api-service.d.ts","sourceRoot":"","sources":["../../../src/services/edgar/edgar-api-service.ts"],"names":[],"mappings":"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"}
|