openplanter 0.1.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 +210 -0
- package/dist/builder.d.ts +11 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +179 -0
- package/dist/builder.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +548 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +114 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials.d.ts +52 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +371 -0
- package/dist/credentials.js.map +1 -0
- package/dist/demo.d.ts +26 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/demo.js +95 -0
- package/dist/demo.js.map +1 -0
- package/dist/engine.d.ts +91 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +1036 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/investigation-tools/aph-holdings.d.ts +61 -0
- package/dist/investigation-tools/aph-holdings.d.ts.map +1 -0
- package/dist/investigation-tools/aph-holdings.js +459 -0
- package/dist/investigation-tools/aph-holdings.js.map +1 -0
- package/dist/investigation-tools/asic-officer-lookup.d.ts +42 -0
- package/dist/investigation-tools/asic-officer-lookup.d.ts.map +1 -0
- package/dist/investigation-tools/asic-officer-lookup.js +197 -0
- package/dist/investigation-tools/asic-officer-lookup.js.map +1 -0
- package/dist/investigation-tools/asx-calendar-fetcher.d.ts +42 -0
- package/dist/investigation-tools/asx-calendar-fetcher.d.ts.map +1 -0
- package/dist/investigation-tools/asx-calendar-fetcher.js +271 -0
- package/dist/investigation-tools/asx-calendar-fetcher.js.map +1 -0
- package/dist/investigation-tools/asx-parser.d.ts +66 -0
- package/dist/investigation-tools/asx-parser.d.ts.map +1 -0
- package/dist/investigation-tools/asx-parser.js +314 -0
- package/dist/investigation-tools/asx-parser.js.map +1 -0
- package/dist/investigation-tools/bulk-asx-announcements.d.ts +53 -0
- package/dist/investigation-tools/bulk-asx-announcements.d.ts.map +1 -0
- package/dist/investigation-tools/bulk-asx-announcements.js +204 -0
- package/dist/investigation-tools/bulk-asx-announcements.js.map +1 -0
- package/dist/investigation-tools/entity-resolver.d.ts +77 -0
- package/dist/investigation-tools/entity-resolver.d.ts.map +1 -0
- package/dist/investigation-tools/entity-resolver.js +346 -0
- package/dist/investigation-tools/entity-resolver.js.map +1 -0
- package/dist/investigation-tools/hotcopper-scraper.d.ts +73 -0
- package/dist/investigation-tools/hotcopper-scraper.d.ts.map +1 -0
- package/dist/investigation-tools/hotcopper-scraper.js +318 -0
- package/dist/investigation-tools/hotcopper-scraper.js.map +1 -0
- package/dist/investigation-tools/index.d.ts +15 -0
- package/dist/investigation-tools/index.d.ts.map +1 -0
- package/dist/investigation-tools/index.js +15 -0
- package/dist/investigation-tools/index.js.map +1 -0
- package/dist/investigation-tools/insider-graph.d.ts +173 -0
- package/dist/investigation-tools/insider-graph.d.ts.map +1 -0
- package/dist/investigation-tools/insider-graph.js +732 -0
- package/dist/investigation-tools/insider-graph.js.map +1 -0
- package/dist/investigation-tools/insider-suspicion-scorer.d.ts +97 -0
- package/dist/investigation-tools/insider-suspicion-scorer.d.ts.map +1 -0
- package/dist/investigation-tools/insider-suspicion-scorer.js +327 -0
- package/dist/investigation-tools/insider-suspicion-scorer.js.map +1 -0
- package/dist/investigation-tools/multi-forum-scraper.d.ts +104 -0
- package/dist/investigation-tools/multi-forum-scraper.d.ts.map +1 -0
- package/dist/investigation-tools/multi-forum-scraper.js +415 -0
- package/dist/investigation-tools/multi-forum-scraper.js.map +1 -0
- package/dist/investigation-tools/price-fetcher.d.ts +81 -0
- package/dist/investigation-tools/price-fetcher.d.ts.map +1 -0
- package/dist/investigation-tools/price-fetcher.js +268 -0
- package/dist/investigation-tools/price-fetcher.js.map +1 -0
- package/dist/investigation-tools/shared.d.ts +39 -0
- package/dist/investigation-tools/shared.d.ts.map +1 -0
- package/dist/investigation-tools/shared.js +203 -0
- package/dist/investigation-tools/shared.js.map +1 -0
- package/dist/investigation-tools/timeline-linker.d.ts +90 -0
- package/dist/investigation-tools/timeline-linker.d.ts.map +1 -0
- package/dist/investigation-tools/timeline-linker.js +219 -0
- package/dist/investigation-tools/timeline-linker.js.map +1 -0
- package/dist/investigation-tools/volume-scanner.d.ts +70 -0
- package/dist/investigation-tools/volume-scanner.d.ts.map +1 -0
- package/dist/investigation-tools/volume-scanner.js +227 -0
- package/dist/investigation-tools/volume-scanner.js.map +1 -0
- package/dist/model.d.ts +136 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +1071 -0
- package/dist/model.js.map +1 -0
- package/dist/patching.d.ts +45 -0
- package/dist/patching.d.ts.map +1 -0
- package/dist/patching.js +317 -0
- package/dist/patching.js.map +1 -0
- package/dist/prompts.d.ts +15 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +351 -0
- package/dist/prompts.js.map +1 -0
- package/dist/replay-log.d.ts +54 -0
- package/dist/replay-log.d.ts.map +1 -0
- package/dist/replay-log.js +94 -0
- package/dist/replay-log.js.map +1 -0
- package/dist/runtime.d.ts +53 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +259 -0
- package/dist/runtime.js.map +1 -0
- package/dist/settings.d.ts +39 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +146 -0
- package/dist/settings.js.map +1 -0
- package/dist/tool-defs.d.ts +58 -0
- package/dist/tool-defs.d.ts.map +1 -0
- package/dist/tool-defs.js +1029 -0
- package/dist/tool-defs.js.map +1 -0
- package/dist/tools.d.ts +72 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +1454 -0
- package/dist/tools.js.map +1 -0
- package/dist/tui.d.ts +49 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +699 -0
- package/dist/tui.js.map +1 -0
- package/package.json +126 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* asic-officer-lookup.ts – Query ASIC company officer/director data by ABN or
|
|
3
|
+
* ASX ticker.
|
|
4
|
+
*
|
|
5
|
+
* Data sources:
|
|
6
|
+
* - ASIC Connect Registry Search:
|
|
7
|
+
* https://connectonline.asic.gov.au/RegistrySearch/faces/landing/SearchRegisters.jspx
|
|
8
|
+
* - Australian Business Register (ABR) JSON API:
|
|
9
|
+
* https://abr.business.gov.au/json/AbnDetails.aspx?abn=XXX&callback=callback
|
|
10
|
+
* - ASX Company Info API:
|
|
11
|
+
* https://www.asx.com.au/asx/1/company/{ticker}
|
|
12
|
+
*/
|
|
13
|
+
import { fetchHtml, fetchWithDelay, fetchJson, cleanAbn, formatAbn, sleep, } from "./shared.js";
|
|
14
|
+
// ── Constants ────────────────────────────────────────────────────
|
|
15
|
+
const ASIC_SEARCH_URL = "https://connectonline.asic.gov.au/RegistrySearch/faces/landing/" +
|
|
16
|
+
"SearchRegisters.jspx";
|
|
17
|
+
const ABR_API_URL = "https://abr.business.gov.au/json/AbnDetails.aspx";
|
|
18
|
+
const ASX_COMPANY_URL = "https://www.asx.com.au/asx/1/company/{ticker}";
|
|
19
|
+
const DEFAULT_MAX_RESULTS = 20;
|
|
20
|
+
const DEFAULT_DELAY = 1.0;
|
|
21
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
22
|
+
function isAbnInput(value) {
|
|
23
|
+
const digits = value.replace(/\D/g, "");
|
|
24
|
+
return digits.length === 11;
|
|
25
|
+
}
|
|
26
|
+
// ── ASX company info lookup ──────────────────────────────────────
|
|
27
|
+
export async function resolveTicker(ticker, delay = DEFAULT_DELAY) {
|
|
28
|
+
const url = ASX_COMPANY_URL.replace("{ticker}", ticker.toUpperCase());
|
|
29
|
+
try {
|
|
30
|
+
return await fetchJson(url, { delay });
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
34
|
+
console.error(`[WARN] ASX company lookup failed for ${ticker}: ${msg}`);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ── ABR API lookup ───────────────────────────────────────────────
|
|
39
|
+
export async function queryAbr(abn, delay = DEFAULT_DELAY) {
|
|
40
|
+
const clean = cleanAbn(abn);
|
|
41
|
+
const url = `${ABR_API_URL}?abn=${clean}&callback=callback`;
|
|
42
|
+
try {
|
|
43
|
+
const resp = await fetchWithDelay(url, { delay });
|
|
44
|
+
if (!resp.ok) {
|
|
45
|
+
throw new Error(`HTTP ${resp.status}`);
|
|
46
|
+
}
|
|
47
|
+
const text = (await resp.text()).trim();
|
|
48
|
+
// Strip JSONP wrapper: callback({...})
|
|
49
|
+
const match = text.match(/^callback\((.+)\)\s*$/s);
|
|
50
|
+
if (match) {
|
|
51
|
+
return JSON.parse(match[1]);
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
57
|
+
console.error(`[WARN] ABR lookup failed for ABN ${clean}: ${msg}`);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ── ASIC Connect scraping (best-effort) ──────────────────────────
|
|
62
|
+
export async function queryAsic(_searchTerm, delay = DEFAULT_DELAY) {
|
|
63
|
+
const officers = [];
|
|
64
|
+
try {
|
|
65
|
+
// Step 1: GET the landing page to obtain ViewState
|
|
66
|
+
const ch = await fetchHtml(ASIC_SEARCH_URL, { delay });
|
|
67
|
+
const viewstateTag = ch('input[name="javax.faces.ViewState"]');
|
|
68
|
+
if (!viewstateTag.length) {
|
|
69
|
+
console.error("[WARN] ASIC Connect: could not locate ViewState – falling back to ABR.");
|
|
70
|
+
return officers;
|
|
71
|
+
}
|
|
72
|
+
const viewstate = viewstateTag.attr("value") ?? "";
|
|
73
|
+
// Step 2: POST a search form submission
|
|
74
|
+
// ASIC Connect form IDs change frequently; this is best-effort.
|
|
75
|
+
const formData = new URLSearchParams({
|
|
76
|
+
"javax.faces.ViewState": viewstate,
|
|
77
|
+
"javax.faces.partial.ajax": "true",
|
|
78
|
+
});
|
|
79
|
+
await sleep(delay * 1000);
|
|
80
|
+
const searchResp = await fetch(ASIC_SEARCH_URL, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
83
|
+
body: formData.toString(),
|
|
84
|
+
});
|
|
85
|
+
if (!searchResp.ok) {
|
|
86
|
+
throw new Error(`HTTP ${searchResp.status}`);
|
|
87
|
+
}
|
|
88
|
+
// Step 3: Parse officer table from results
|
|
89
|
+
const cheerio = await import("cheerio");
|
|
90
|
+
const resultHtml = await searchResp.text();
|
|
91
|
+
const result$ = cheerio.load(resultHtml);
|
|
92
|
+
const rows = result$("table.officer-table tr").toArray();
|
|
93
|
+
for (const row of rows) {
|
|
94
|
+
const cells = result$(row).find("td");
|
|
95
|
+
if (cells.length >= 3) {
|
|
96
|
+
officers.push({
|
|
97
|
+
company_name: null,
|
|
98
|
+
abn: null,
|
|
99
|
+
ticker: null,
|
|
100
|
+
officer_name: cells.eq(0).text().trim(),
|
|
101
|
+
role: cells.eq(1).text().trim(),
|
|
102
|
+
appointment_date: cells.eq(2).text().trim() || null,
|
|
103
|
+
cessation_date: cells.length > 3
|
|
104
|
+
? cells.eq(3).text().trim() || null
|
|
105
|
+
: null,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
112
|
+
console.error(`[WARN] ASIC Connect scraping failed: ${msg}`);
|
|
113
|
+
}
|
|
114
|
+
return officers;
|
|
115
|
+
}
|
|
116
|
+
// ── Composite lookup ─────────────────────────────────────────────
|
|
117
|
+
export async function lookupOfficers(abnOrTicker, maxResults = DEFAULT_MAX_RESULTS) {
|
|
118
|
+
const results = [];
|
|
119
|
+
let companyName = null;
|
|
120
|
+
let abn = null;
|
|
121
|
+
let ticker = null;
|
|
122
|
+
// Determine whether input is ABN or ticker
|
|
123
|
+
if (isAbnInput(abnOrTicker)) {
|
|
124
|
+
abn = cleanAbn(abnOrTicker);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
ticker = abnOrTicker.toUpperCase().trim();
|
|
128
|
+
}
|
|
129
|
+
// Resolve ticker via ASX
|
|
130
|
+
if (ticker) {
|
|
131
|
+
const asxInfo = await resolveTicker(ticker);
|
|
132
|
+
if (asxInfo) {
|
|
133
|
+
companyName = asxInfo.name_full ?? asxInfo.name_short ?? null;
|
|
134
|
+
console.error(`[INFO] ASX resolved ${ticker} → ${companyName}`);
|
|
135
|
+
}
|
|
136
|
+
await sleep(DEFAULT_DELAY * 1000);
|
|
137
|
+
}
|
|
138
|
+
// Query ABR for ABN details
|
|
139
|
+
if (abn) {
|
|
140
|
+
const abrData = await queryAbr(abn);
|
|
141
|
+
if (abrData) {
|
|
142
|
+
const entityName = abrData.EntityName ?? "";
|
|
143
|
+
const businessNames = abrData.BusinessName ?? [];
|
|
144
|
+
if (entityName) {
|
|
145
|
+
companyName = companyName ?? entityName;
|
|
146
|
+
}
|
|
147
|
+
if (Array.isArray(businessNames) && businessNames.length > 0) {
|
|
148
|
+
const firstBn = businessNames[0];
|
|
149
|
+
if (typeof firstBn === "string") {
|
|
150
|
+
companyName = companyName ?? firstBn;
|
|
151
|
+
}
|
|
152
|
+
else if (typeof firstBn === "object" && firstBn !== null) {
|
|
153
|
+
companyName =
|
|
154
|
+
companyName ?? firstBn.Value ?? null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const abnValue = abrData.Abn ?? abn;
|
|
158
|
+
abn = cleanAbn(String(abnValue));
|
|
159
|
+
console.error(`[INFO] ABR resolved ABN ${formatAbn(abn)} → ${companyName}`);
|
|
160
|
+
}
|
|
161
|
+
await sleep(DEFAULT_DELAY * 1000);
|
|
162
|
+
}
|
|
163
|
+
// Attempt ASIC Connect scraping
|
|
164
|
+
const searchTerm = abn ?? ticker ?? abnOrTicker;
|
|
165
|
+
const asicOfficers = await queryAsic(searchTerm);
|
|
166
|
+
if (asicOfficers.length > 0) {
|
|
167
|
+
for (const off of asicOfficers.slice(0, maxResults)) {
|
|
168
|
+
results.push({
|
|
169
|
+
company_name: companyName,
|
|
170
|
+
abn: abn ? formatAbn(abn) : null,
|
|
171
|
+
ticker,
|
|
172
|
+
officer_name: off.officer_name,
|
|
173
|
+
role: off.role,
|
|
174
|
+
appointment_date: off.appointment_date,
|
|
175
|
+
cessation_date: off.cessation_date,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// ASIC scraping failed – return a stub record with company metadata
|
|
181
|
+
console.error("[INFO] ASIC officer scraping returned no results; returning " +
|
|
182
|
+
"company-level metadata only.");
|
|
183
|
+
results.push({
|
|
184
|
+
company_name: companyName,
|
|
185
|
+
abn: abn ? formatAbn(abn) : null,
|
|
186
|
+
ticker,
|
|
187
|
+
officer_name: null,
|
|
188
|
+
role: null,
|
|
189
|
+
appointment_date: null,
|
|
190
|
+
cessation_date: null,
|
|
191
|
+
_note: "ASIC Connect scraping did not return officer details. " +
|
|
192
|
+
"Manual lookup may be required.",
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return results.slice(0, maxResults);
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=asic-officer-lookup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asic-officer-lookup.js","sourceRoot":"","sources":["../../src/investigation-tools/asic-officer-lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,SAAS,EACT,cAAc,EACd,SAAS,EACT,QAAQ,EACR,SAAS,EACT,KAAK,GACN,MAAM,aAAa,CAAC;AAKrB,oEAAoE;AAEpE,MAAM,eAAe,GACnB,iEAAiE;IACjE,sBAAsB,CAAC;AAEzB,MAAM,WAAW,GAAG,kDAAkD,CAAC;AAEvE,MAAM,eAAe,GAAG,+CAA+C,CAAC;AAExE,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAC/B,MAAM,aAAa,GAAG,GAAG,CAAC;AA8B1B,oEAAoE;AAEpE,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC,MAAM,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED,oEAAoE;AAEpE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,QAAgB,aAAa;IAE7B,MAAM,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,CAAiB,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,wCAAwC,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,oEAAoE;AAEpE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAW,EACX,QAAgB,aAAa;IAE7B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,GAAG,WAAW,QAAQ,KAAK,oBAAoB,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,uCAAuC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACnD,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAY,CAAC;QACzC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,oCAAoC,KAAK,KAAK,GAAG,EAAE,CAAC,CAAC;QACnE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,oEAAoE;AAEpE,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,WAAmB,EACnB,QAAgB,aAAa;IAE7B,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,IAAI,CAAC;QACH,mDAAmD;QACnD,MAAM,EAAE,GAAM,MAAM,SAAS,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAE1D,MAAM,YAAY,GAAG,EAAE,CAAC,qCAAqC,CAAC,CAAC;QAC/D,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CACX,wEAAwE,CACzE,CAAC;YACF,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAEnD,wCAAwC;QACxC,gEAAgE;QAChE,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC;YACnC,uBAAuB,EAAE,SAAS;YAClC,0BAA0B,EAAE,MAAM;SACnC,CAAC,CAAC;QAEH,MAAM,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;QAC1B,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,eAAe,EAAE;YAC9C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,QAAQ,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,2CAA2C;QAC3C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC,OAAO,EAAE,CAAC;QAEzD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;gBACtB,QAAQ,CAAC,IAAI,CAAC;oBACZ,YAAY,EAAE,IAAI;oBAClB,GAAG,EAAE,IAAI;oBACT,MAAM,EAAE,IAAI;oBACZ,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;oBACvC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;oBAC/B,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,IAAI;oBACnD,cAAc,EACZ,KAAK,CAAC,MAAM,GAAG,CAAC;wBACd,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,IAAI;wBACnC,CAAC,CAAC,IAAI;iBACX,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,wCAAwC,GAAG,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,oEAAoE;AAEpE,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,aAAqB,mBAAmB;IAExC,MAAM,OAAO,GAAoB,EAAE,CAAC;IAEpC,IAAI,WAAW,GAAkB,IAAI,CAAC;IACtC,IAAI,GAAG,GAAkB,IAAI,CAAC;IAC9B,IAAI,MAAM,GAAkB,IAAI,CAAC;IAEjC,2CAA2C;IAC3C,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC9B,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED,yBAAyB;IACzB,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,OAAO,EAAE,CAAC;YACZ,WAAW,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;YAC9D,OAAO,CAAC,KAAK,CAAC,uBAAuB,MAAM,MAAM,WAAW,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,4BAA4B;IAC5B,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;YAC5C,MAAM,aAAa,GAAG,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;YAEjD,IAAI,UAAU,EAAE,CAAC;gBACf,WAAW,GAAG,WAAW,IAAI,UAAU,CAAC;YAC1C,CAAC;YACD,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7D,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;gBACjC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;oBAChC,WAAW,GAAG,WAAW,IAAI,OAAO,CAAC;gBACvC,CAAC;qBAAM,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBAC3D,WAAW;wBACT,WAAW,IAAK,OAA8B,CAAC,KAAK,IAAI,IAAI,CAAC;gBACjE,CAAC;YACH,CAAC;YAED,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC;YACpC,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YACjC,OAAO,CAAC,KAAK,CACX,2BAA2B,SAAS,CAAC,GAAG,CAAC,MAAM,WAAW,EAAE,CAC7D,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,gCAAgC;IAChC,MAAM,UAAU,GAAG,GAAG,IAAI,MAAM,IAAI,WAAW,CAAC;IAChD,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;IAEjD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,KAAK,MAAM,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC;gBACX,YAAY,EAAE,WAAW;gBACzB,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;gBAChC,MAAM;gBACN,YAAY,EAAE,GAAG,CAAC,YAAY;gBAC9B,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;gBACtC,cAAc,EAAE,GAAG,CAAC,cAAc;aACnC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;SAAM,CAAC;QACN,oEAAoE;QACpE,OAAO,CAAC,KAAK,CACX,8DAA8D;YAC5D,8BAA8B,CACjC,CAAC;QACF,OAAO,CAAC,IAAI,CAAC;YACX,YAAY,EAAE,WAAW;YACzB,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;YAChC,MAAM;YACN,YAAY,EAAE,IAAI;YAClB,IAAI,EAAE,IAAI;YACV,gBAAgB,EAAE,IAAI;YACtB,cAAc,EAAE,IAAI;YACpB,KAAK,EACH,wDAAwD;gBACxD,gCAAgC;SACnC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* asx-calendar-fetcher.ts — ASX Appendix 4C Reporting Calendar Fetcher
|
|
3
|
+
*
|
|
4
|
+
* Scrapes scheduled ASX Appendix 4C (quarterly cashflow) due dates from
|
|
5
|
+
* Listcorp and outputs structured data for downstream analysis.
|
|
6
|
+
*/
|
|
7
|
+
declare const OUTPUT_COLUMNS: readonly ["ticker", "company_name", "quarter_end", "due_date", "lodged_date", "status"];
|
|
8
|
+
export interface CalendarEntry {
|
|
9
|
+
ticker: string;
|
|
10
|
+
company_name: string;
|
|
11
|
+
quarter_end: string;
|
|
12
|
+
due_date: string;
|
|
13
|
+
lodged_date: string | null;
|
|
14
|
+
status: "upcoming" | "overdue" | "lodged";
|
|
15
|
+
}
|
|
16
|
+
export interface PeriodRange {
|
|
17
|
+
start: Date;
|
|
18
|
+
end: Date;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parse a period string into a date range for filtering.
|
|
22
|
+
*
|
|
23
|
+
* Supported formats:
|
|
24
|
+
* - next_30d, next_90d, next_NNd — from today through NN days ahead
|
|
25
|
+
* - Q1_2026, Q2_2026, etc. — quarter due date window
|
|
26
|
+
*/
|
|
27
|
+
export declare function parsePeriod(period: string): PeriodRange;
|
|
28
|
+
export declare function fetchCalendarLive(): Promise<CalendarEntry[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Fetch and filter ASX 4C calendar entries.
|
|
31
|
+
*
|
|
32
|
+
* @param options.tickers - Comma-separated tickers or "all"
|
|
33
|
+
* @param options.period - Period string (next_30d, Q1_2026, etc.)
|
|
34
|
+
* @param options.records - Pre-fetched records (for testing / offline use)
|
|
35
|
+
*/
|
|
36
|
+
export declare function fetchCalendar(options?: {
|
|
37
|
+
tickers?: string;
|
|
38
|
+
period?: string;
|
|
39
|
+
records?: CalendarEntry[];
|
|
40
|
+
}): Promise<CalendarEntry[]>;
|
|
41
|
+
export { OUTPUT_COLUMNS };
|
|
42
|
+
//# sourceMappingURL=asx-calendar-fetcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asx-calendar-fetcher.d.ts","sourceRoot":"","sources":["../../src/investigation-tools/asx-calendar-fetcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,QAAA,MAAM,cAAc,yFAOV,CAAC;AAkDX,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;CAC3C;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;CACX;AAID;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAwCvD;AAwJD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CASlE;AAID;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;CAC3B,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAgC3B;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* asx-calendar-fetcher.ts — ASX Appendix 4C Reporting Calendar Fetcher
|
|
3
|
+
*
|
|
4
|
+
* Scrapes scheduled ASX Appendix 4C (quarterly cashflow) due dates from
|
|
5
|
+
* Listcorp and outputs structured data for downstream analysis.
|
|
6
|
+
*/
|
|
7
|
+
import { fetchHtml, normalizeTicker } from "./shared.js";
|
|
8
|
+
// ── Constants ────────────────────────────────────────────────────
|
|
9
|
+
const LISTCORP_UPCOMING_URL = "https://www.listcorp.com/asx/upcoming-reports";
|
|
10
|
+
const OUTPUT_COLUMNS = [
|
|
11
|
+
"ticker",
|
|
12
|
+
"company_name",
|
|
13
|
+
"quarter_end",
|
|
14
|
+
"due_date",
|
|
15
|
+
"lodged_date",
|
|
16
|
+
"status",
|
|
17
|
+
];
|
|
18
|
+
/** Quarter-end month mappings (calendar quarters) */
|
|
19
|
+
const QUARTER_END_MONTHS = {
|
|
20
|
+
Q1: 3,
|
|
21
|
+
Q2: 6,
|
|
22
|
+
Q3: 9,
|
|
23
|
+
Q4: 12,
|
|
24
|
+
};
|
|
25
|
+
const QUARTER_END_DAYS = {
|
|
26
|
+
Q1: 31,
|
|
27
|
+
Q2: 30,
|
|
28
|
+
Q3: 30,
|
|
29
|
+
Q4: 31,
|
|
30
|
+
};
|
|
31
|
+
/** 4C reports are due within ~1 month after quarter end */
|
|
32
|
+
const REPORT_DUE_OFFSET_DAYS = 31;
|
|
33
|
+
/** Date formats for parsing cell text */
|
|
34
|
+
const DATE_FORMATS = [
|
|
35
|
+
{
|
|
36
|
+
// DD/MM/YYYY
|
|
37
|
+
regex: /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/,
|
|
38
|
+
parse: (m) => new Date(+m[3], +m[2] - 1, +m[1]),
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
// YYYY-MM-DD
|
|
42
|
+
regex: /^(\d{4})-(\d{2})-(\d{2})$/,
|
|
43
|
+
parse: (m) => new Date(+m[1], +m[2] - 1, +m[3]),
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
// DD-MM-YYYY
|
|
47
|
+
regex: /^(\d{1,2})-(\d{1,2})-(\d{4})$/,
|
|
48
|
+
parse: (m) => new Date(+m[3], +m[2] - 1, +m[1]),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
// DD Mon YYYY (e.g. "15 Feb 2026")
|
|
52
|
+
regex: /^(\d{1,2})\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{4})$/i,
|
|
53
|
+
parse: (m) => new Date(`${m[2]} ${m[1]}, ${m[3]}`),
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
// ── Period Parsing ───────────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Parse a period string into a date range for filtering.
|
|
59
|
+
*
|
|
60
|
+
* Supported formats:
|
|
61
|
+
* - next_30d, next_90d, next_NNd — from today through NN days ahead
|
|
62
|
+
* - Q1_2026, Q2_2026, etc. — quarter due date window
|
|
63
|
+
*/
|
|
64
|
+
export function parsePeriod(period) {
|
|
65
|
+
const trimmed = period.trim();
|
|
66
|
+
const today = new Date();
|
|
67
|
+
today.setHours(0, 0, 0, 0);
|
|
68
|
+
// Handle next_Nd pattern
|
|
69
|
+
if (trimmed.startsWith("next_") && trimmed.endsWith("d")) {
|
|
70
|
+
const daysStr = trimmed.slice(5, -1);
|
|
71
|
+
const days = parseInt(daysStr, 10);
|
|
72
|
+
if (isNaN(days)) {
|
|
73
|
+
throw new Error(`Invalid period '${period}'. Expected format: next_30d`);
|
|
74
|
+
}
|
|
75
|
+
const end = new Date(today);
|
|
76
|
+
end.setDate(end.getDate() + days);
|
|
77
|
+
return { start: today, end };
|
|
78
|
+
}
|
|
79
|
+
// Handle QN_YYYY pattern
|
|
80
|
+
if (trimmed.includes("_")) {
|
|
81
|
+
const parts = trimmed.split("_", 2);
|
|
82
|
+
const quarterKey = parts[0].toUpperCase();
|
|
83
|
+
if (quarterKey in QUARTER_END_MONTHS && parts.length === 2) {
|
|
84
|
+
const year = parseInt(parts[1], 10);
|
|
85
|
+
if (isNaN(year)) {
|
|
86
|
+
throw new Error(`Invalid year in period '${period}'.`);
|
|
87
|
+
}
|
|
88
|
+
const month = QUARTER_END_MONTHS[quarterKey];
|
|
89
|
+
const day = QUARTER_END_DAYS[quarterKey];
|
|
90
|
+
const quarterEnd = new Date(year, month - 1, day);
|
|
91
|
+
const dueEnd = new Date(quarterEnd);
|
|
92
|
+
dueEnd.setDate(dueEnd.getDate() + REPORT_DUE_OFFSET_DAYS);
|
|
93
|
+
return { start: quarterEnd, end: dueEnd };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
throw new Error(`Unrecognised period '${period}'. Use next_30d, next_90d, Q1_2026, Q2_2026, etc.`);
|
|
97
|
+
}
|
|
98
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
99
|
+
function inferQuarterEnd(dueDate) {
|
|
100
|
+
const approxQtrEnd = new Date(dueDate);
|
|
101
|
+
approxQtrEnd.setDate(approxQtrEnd.getDate() - REPORT_DUE_OFFSET_DAYS);
|
|
102
|
+
const month = approxQtrEnd.getMonth() + 1; // 1-based
|
|
103
|
+
if (month <= 3) {
|
|
104
|
+
return `${approxQtrEnd.getFullYear()}-03-31`;
|
|
105
|
+
}
|
|
106
|
+
else if (month <= 6) {
|
|
107
|
+
return `${approxQtrEnd.getFullYear()}-06-30`;
|
|
108
|
+
}
|
|
109
|
+
else if (month <= 9) {
|
|
110
|
+
return `${approxQtrEnd.getFullYear()}-09-30`;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
return `${approxQtrEnd.getFullYear()}-12-31`;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function tryParseDate(text) {
|
|
117
|
+
const trimmed = text.trim();
|
|
118
|
+
for (const fmt of DATE_FORMATS) {
|
|
119
|
+
const m = trimmed.match(fmt.regex);
|
|
120
|
+
if (m) {
|
|
121
|
+
const d = fmt.parse(m);
|
|
122
|
+
if (!isNaN(d.getTime()))
|
|
123
|
+
return d;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
function formatDateIso(d) {
|
|
129
|
+
const year = d.getFullYear();
|
|
130
|
+
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
131
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
132
|
+
return `${year}-${month}-${day}`;
|
|
133
|
+
}
|
|
134
|
+
function determineStatus(dueDateStr, lodgedDateStr) {
|
|
135
|
+
if (lodgedDateStr)
|
|
136
|
+
return "lodged";
|
|
137
|
+
const dueDt = new Date(dueDateStr);
|
|
138
|
+
if (isNaN(dueDt.getTime()))
|
|
139
|
+
return "upcoming";
|
|
140
|
+
const today = new Date();
|
|
141
|
+
today.setHours(0, 0, 0, 0);
|
|
142
|
+
return dueDt < today ? "overdue" : "upcoming";
|
|
143
|
+
}
|
|
144
|
+
function filterByTickers(records, tickers) {
|
|
145
|
+
const tickerSet = new Set(tickers.map((t) => normalizeTicker(t)));
|
|
146
|
+
return records.filter((r) => tickerSet.has(r.ticker));
|
|
147
|
+
}
|
|
148
|
+
function filterByPeriod(records, startDate, endDate) {
|
|
149
|
+
return records.filter((rec) => {
|
|
150
|
+
if (!rec.due_date)
|
|
151
|
+
return false;
|
|
152
|
+
const dueDt = new Date(rec.due_date);
|
|
153
|
+
if (isNaN(dueDt.getTime()))
|
|
154
|
+
return false;
|
|
155
|
+
return dueDt >= startDate && dueDt <= endDate;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
// ── Live data fetching ───────────────────────────────────────────
|
|
159
|
+
function parseCalendarTable(ch) {
|
|
160
|
+
const records = [];
|
|
161
|
+
const table = ch("table").first();
|
|
162
|
+
if (!table.length)
|
|
163
|
+
return records;
|
|
164
|
+
const rows = table.find("tr").toArray();
|
|
165
|
+
for (const row of rows) {
|
|
166
|
+
const allCells = ch(row).find("td, th");
|
|
167
|
+
if (allCells.length < 3)
|
|
168
|
+
continue;
|
|
169
|
+
// Skip header rows
|
|
170
|
+
if (ch(row).find("th").length > 0)
|
|
171
|
+
continue;
|
|
172
|
+
const cellTexts = allCells
|
|
173
|
+
.toArray()
|
|
174
|
+
.map((cell) => ch(cell).text().trim());
|
|
175
|
+
// Heuristic: find a cell that looks like an ASX code (2-4 uppercase letters)
|
|
176
|
+
let ticker = "";
|
|
177
|
+
let companyName = "";
|
|
178
|
+
for (let i = 0; i < cellTexts.length; i++) {
|
|
179
|
+
const stripped = cellTexts[i].trim().toUpperCase();
|
|
180
|
+
if (stripped.length >= 2 &&
|
|
181
|
+
stripped.length <= 4 &&
|
|
182
|
+
/^[A-Z]+$/.test(stripped) &&
|
|
183
|
+
!ticker) {
|
|
184
|
+
ticker = stripped;
|
|
185
|
+
// Next cell is usually the company name
|
|
186
|
+
if (i + 1 < cellTexts.length) {
|
|
187
|
+
companyName = cellTexts[i + 1];
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!ticker)
|
|
193
|
+
continue;
|
|
194
|
+
// Look for date-like cells
|
|
195
|
+
let dueDateStr = "";
|
|
196
|
+
let lodgedDateStr = null;
|
|
197
|
+
for (const text of cellTexts) {
|
|
198
|
+
const parsed = tryParseDate(text);
|
|
199
|
+
if (parsed) {
|
|
200
|
+
const dateIso = formatDateIso(parsed);
|
|
201
|
+
if (!dueDateStr) {
|
|
202
|
+
dueDateStr = dateIso;
|
|
203
|
+
}
|
|
204
|
+
else if (!lodgedDateStr) {
|
|
205
|
+
lodgedDateStr = dateIso;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (!dueDateStr)
|
|
210
|
+
continue;
|
|
211
|
+
const quarterEnd = inferQuarterEnd(new Date(dueDateStr));
|
|
212
|
+
const status = determineStatus(dueDateStr, lodgedDateStr);
|
|
213
|
+
records.push({
|
|
214
|
+
ticker,
|
|
215
|
+
company_name: companyName,
|
|
216
|
+
quarter_end: quarterEnd,
|
|
217
|
+
due_date: dueDateStr,
|
|
218
|
+
lodged_date: lodgedDateStr,
|
|
219
|
+
status,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return records;
|
|
223
|
+
}
|
|
224
|
+
export async function fetchCalendarLive() {
|
|
225
|
+
try {
|
|
226
|
+
const ch = await fetchHtml(LISTCORP_UPCOMING_URL);
|
|
227
|
+
return parseCalendarTable(ch);
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
231
|
+
console.error(`[error] Failed to fetch calendar page: ${msg}`);
|
|
232
|
+
return [];
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// ── Main entry point ─────────────────────────────────────────────
|
|
236
|
+
/**
|
|
237
|
+
* Fetch and filter ASX 4C calendar entries.
|
|
238
|
+
*
|
|
239
|
+
* @param options.tickers - Comma-separated tickers or "all"
|
|
240
|
+
* @param options.period - Period string (next_30d, Q1_2026, etc.)
|
|
241
|
+
* @param options.records - Pre-fetched records (for testing / offline use)
|
|
242
|
+
*/
|
|
243
|
+
export async function fetchCalendar(options) {
|
|
244
|
+
const tickersInput = options?.tickers ?? "all";
|
|
245
|
+
const periodStr = options?.period ?? "next_30d";
|
|
246
|
+
const { start: startDate, end: endDate } = parsePeriod(periodStr);
|
|
247
|
+
// Parse ticker filter
|
|
248
|
+
let filterTickers = null;
|
|
249
|
+
if (tickersInput.trim().toLowerCase() !== "all") {
|
|
250
|
+
filterTickers = tickersInput
|
|
251
|
+
.split(",")
|
|
252
|
+
.map((t) => t.trim())
|
|
253
|
+
.filter(Boolean);
|
|
254
|
+
if (!filterTickers.length)
|
|
255
|
+
filterTickers = null;
|
|
256
|
+
}
|
|
257
|
+
// Fetch data
|
|
258
|
+
let records = options?.records ?? (await fetchCalendarLive());
|
|
259
|
+
if (!records.length)
|
|
260
|
+
return [];
|
|
261
|
+
// Apply filters
|
|
262
|
+
records = filterByPeriod(records, startDate, endDate);
|
|
263
|
+
if (filterTickers) {
|
|
264
|
+
records = filterByTickers(records, filterTickers);
|
|
265
|
+
}
|
|
266
|
+
// Sort by due_date ascending
|
|
267
|
+
records.sort((a, b) => a.due_date.localeCompare(b.due_date));
|
|
268
|
+
return records;
|
|
269
|
+
}
|
|
270
|
+
export { OUTPUT_COLUMNS };
|
|
271
|
+
//# sourceMappingURL=asx-calendar-fetcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asx-calendar-fetcher.js","sourceRoot":"","sources":["../../src/investigation-tools/asx-calendar-fetcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* asx-parser.ts – Parse ASX announcements into structured data.
|
|
3
|
+
*
|
|
4
|
+
* Supports:
|
|
5
|
+
* - Appendix 3Y (director interest changes / insider trades)
|
|
6
|
+
* - Appendix 4C (quarterly cashflow reports)
|
|
7
|
+
* - Trading halts
|
|
8
|
+
*
|
|
9
|
+
* Accepts raw text content (pre-extracted from HTML/PDF).
|
|
10
|
+
*/
|
|
11
|
+
/** Recognised ASX announcement types. */
|
|
12
|
+
export type AnnouncementType = "3y" | "4c" | "halt";
|
|
13
|
+
/** Parsed Appendix 3Y director interest notice. */
|
|
14
|
+
export interface Parsed3Y {
|
|
15
|
+
director_name: string | null;
|
|
16
|
+
company: string | null;
|
|
17
|
+
ticker: string | null;
|
|
18
|
+
date_of_change: string | null;
|
|
19
|
+
nature_of_interest: string | null;
|
|
20
|
+
securities_acquired: string | null;
|
|
21
|
+
securities_disposed: string | null;
|
|
22
|
+
consideration: number | null;
|
|
23
|
+
consideration_raw: string | null;
|
|
24
|
+
associated_entity: string | null;
|
|
25
|
+
}
|
|
26
|
+
/** Parsed Appendix 4C quarterly cashflow report. */
|
|
27
|
+
export interface Parsed4C {
|
|
28
|
+
company: string | null;
|
|
29
|
+
ticker: string | null;
|
|
30
|
+
period: string | null;
|
|
31
|
+
net_operating_cashflow: number | null;
|
|
32
|
+
net_investing_cashflow: number | null;
|
|
33
|
+
net_financing_cashflow: number | null;
|
|
34
|
+
cash_at_end_of_period: number | null;
|
|
35
|
+
}
|
|
36
|
+
/** Parsed trading halt / voluntary suspension notice. */
|
|
37
|
+
export interface ParsedHalt {
|
|
38
|
+
company: string | null;
|
|
39
|
+
ticker: string | null;
|
|
40
|
+
date: string | null;
|
|
41
|
+
reason: string | null;
|
|
42
|
+
expected_resumption: string | null;
|
|
43
|
+
}
|
|
44
|
+
/** Wrapper envelope around any parsed announcement. */
|
|
45
|
+
export interface ParsedEnvelope<T> {
|
|
46
|
+
type: AnnouncementType;
|
|
47
|
+
source: string;
|
|
48
|
+
parsed_at: string;
|
|
49
|
+
data: T;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Auto-detect announcement type from raw text content.
|
|
53
|
+
* Throws if no type can be determined.
|
|
54
|
+
*/
|
|
55
|
+
export declare function detectType(text: string): AnnouncementType;
|
|
56
|
+
/** Parse Appendix 3Y director interest notice from raw text. */
|
|
57
|
+
export declare function parse3y(text: string): Parsed3Y;
|
|
58
|
+
/** Parse Appendix 4C quarterly cashflow report from raw text. */
|
|
59
|
+
export declare function parse4c(text: string): Parsed4C;
|
|
60
|
+
/** Parse trading halt / voluntary suspension notice from raw text. */
|
|
61
|
+
export declare function parseHalt(text: string): ParsedHalt;
|
|
62
|
+
/** Wrap parsed announcement data in a standard envelope. */
|
|
63
|
+
export declare function buildEnvelope<T>(annType: AnnouncementType, source: string, data: T): ParsedEnvelope<T>;
|
|
64
|
+
/** Parse raw text with an explicit or auto-detected type. */
|
|
65
|
+
export declare function parseAnnouncement(text: string, type?: AnnouncementType | "auto", source?: string): ParsedEnvelope<Parsed3Y | Parsed4C | ParsedHalt>;
|
|
66
|
+
//# sourceMappingURL=asx-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asx-parser.d.ts","sourceRoot":"","sources":["../../src/investigation-tools/asx-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAmCH,yCAAyC;AACzC,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAEpD,mDAAmD;AACnD,MAAM,WAAW,QAAQ;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,oDAAoD;AACpD,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,yDAAyD;AACzD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,gBAAgB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,CAAC,CAAC;CACT;AAiCD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAyBzD;AA0DD,gEAAgE;AAChE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAqD9C;AAED,iEAAiE;AACjE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CA+D9C;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CA0ClD;AAID,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,CAAC,EAC7B,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,CAAC,GACN,cAAc,CAAC,CAAC,CAAC,CAOnB;AAID,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,gBAAgB,GAAG,MAAe,EACxC,MAAM,SAAW,GAChB,cAAc,CAAC,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC,CAWlD"}
|