mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
refactor: split into idx-core library and idx-cli binary workspace
Phase 2 of docs/DESIGN.md, no behavior change: - crates/idx-core (library): api, analysis, cache, config file handling and provider selection, curl_impersonate, error, ownership, runtime, plus the shared test fixtures. clap derives are behind an optional `clap` feature so the library does not require clap. - crates/idx-cli (binary `idx`): cli/, output/, and IdxConfig (output format and color resolution). Package and binary names are unchanged. - config.rs is split: file read/write and validation move to core; a CLI test keeps core's OUTPUT_VALUES in sync with OutputSetting. - ownership::db::open_db/db_path drop their unused IdxConfig argument. - One workspace version; shared dependency versions; no third-party version changes in Cargo.lock. LICENSE is symlinked into each crate. - flake: workspace version, new source paths, and a per-crate package check (idx-cli is built from its tarball against packaged idx-core, since idx-core is not on crates.io yet). CI cache key, release path filter, and the golden whitespace-hook exclusion follow the new layout. Parity: all 143 golden outputs match byte for byte without regeneration; 157 core + 17 CLI unit tests (173 before plus the new OUTPUT_VALUES sync test), 62 CLI tests pass. Live A/B against main: 16/16 stocks cases identical; ownership discover got IDX 403 on both (exit 4 vs 1 is the phase 1 exit-code change). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
22b6dabaeb
commit
15947de51a
238 changed files with 544 additions and 375 deletions
2318
tests/cli.rs
2318
tests/cli.rs
File diff suppressed because it is too large
Load diff
47
tests/fixtures/bing_buyers_bbca.json
vendored
47
tests/fixtures/bing_buyers_bbca.json
vendored
|
|
@ -1,47 +0,0 @@
|
|||
[
|
||||
{
|
||||
"investorName": "Norges Bank Investment Management",
|
||||
"investorType": "Government / Sovereign Wealth",
|
||||
"sharesHeld": 278330000.0,
|
||||
"sharesChanged": 3200000.0,
|
||||
"percentageOfSharesOutstanding": 1.13,
|
||||
"value": 275196270000.0,
|
||||
"reportDate": "2024-12-31"
|
||||
},
|
||||
{
|
||||
"investorName": "Dimensional Fund Advisors LP",
|
||||
"investorType": "Institutional",
|
||||
"sharesHeld": 156920000.0,
|
||||
"sharesChanged": 14750000.0,
|
||||
"percentageOfSharesOutstanding": 0.64,
|
||||
"value": 155110680000.0,
|
||||
"reportDate": "2024-12-31"
|
||||
},
|
||||
{
|
||||
"investorName": "Baillie Gifford & Co",
|
||||
"investorType": "Institutional",
|
||||
"sharesHeld": 132450000.0,
|
||||
"sharesChanged": 11200000.0,
|
||||
"percentageOfSharesOutstanding": 0.54,
|
||||
"value": 130965450000.0,
|
||||
"reportDate": "2024-12-31"
|
||||
},
|
||||
{
|
||||
"investorName": "BlackRock Inc",
|
||||
"investorType": "Institutional",
|
||||
"sharesHeld": 498112750.0,
|
||||
"sharesChanged": 5600000.0,
|
||||
"percentageOfSharesOutstanding": 2.02,
|
||||
"value": 492523521250.0,
|
||||
"reportDate": "2024-12-31"
|
||||
},
|
||||
{
|
||||
"investorName": "Fidelity Management & Research",
|
||||
"investorType": "Institutional",
|
||||
"sharesHeld": 89340000.0,
|
||||
"sharesChanged": 4100000.0,
|
||||
"percentageOfSharesOutstanding": 0.36,
|
||||
"value": 88346060000.0,
|
||||
"reportDate": "2024-12-31"
|
||||
}
|
||||
]
|
||||
56
tests/fixtures/bing_holders_bbca.json
vendored
56
tests/fixtures/bing_holders_bbca.json
vendored
|
|
@ -1,56 +0,0 @@
|
|||
[
|
||||
{
|
||||
"investorName": "PT Dwimuria Investama Andalan",
|
||||
"investorType": "Corporate",
|
||||
"sharesHeld": 13533682440.0,
|
||||
"sharesChanged": 0.0,
|
||||
"percentageOfSharesOutstanding": 54.94,
|
||||
"value": 13380524934600.0,
|
||||
"reportDate": "2024-12-31"
|
||||
},
|
||||
{
|
||||
"investorName": "Vanguard Group Inc",
|
||||
"investorType": "Institutional",
|
||||
"sharesHeld": 621438200.0,
|
||||
"sharesChanged": -12000000.0,
|
||||
"percentageOfSharesOutstanding": 2.52,
|
||||
"value": 614321778000.0,
|
||||
"reportDate": "2024-12-31"
|
||||
},
|
||||
{
|
||||
"investorName": "BlackRock Inc",
|
||||
"investorType": "Institutional",
|
||||
"sharesHeld": 498112750.0,
|
||||
"sharesChanged": 5600000.0,
|
||||
"percentageOfSharesOutstanding": 2.02,
|
||||
"value": 492523521250.0,
|
||||
"reportDate": "2024-12-31"
|
||||
},
|
||||
{
|
||||
"investorName": "Government Pension Investment Fund (Japan)",
|
||||
"investorType": "Government / Sovereign Wealth",
|
||||
"sharesHeld": 312045000.0,
|
||||
"sharesChanged": 0.0,
|
||||
"percentageOfSharesOutstanding": 1.27,
|
||||
"value": 308564505000.0,
|
||||
"reportDate": "2024-12-31"
|
||||
},
|
||||
{
|
||||
"investorName": "Norges Bank Investment Management",
|
||||
"investorType": "Government / Sovereign Wealth",
|
||||
"sharesHeld": 278330000.0,
|
||||
"sharesChanged": 3200000.0,
|
||||
"percentageOfSharesOutstanding": 1.13,
|
||||
"value": 275196270000.0,
|
||||
"reportDate": "2024-12-31"
|
||||
},
|
||||
{
|
||||
"investorName": "Capital Research and Management",
|
||||
"investorType": "Institutional",
|
||||
"sharesHeld": 248760000.0,
|
||||
"sharesChanged": -8000000.0,
|
||||
"percentageOfSharesOutstanding": 1.01,
|
||||
"value": 245971800000.0,
|
||||
"reportDate": "2024-12-31"
|
||||
}
|
||||
]
|
||||
30
tests/fixtures/chart_bbca_1d.json
vendored
30
tests/fixtures/chart_bbca_1d.json
vendored
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"chart": {
|
||||
"result": [
|
||||
{
|
||||
"meta": {
|
||||
"symbol": "BBCA.JK",
|
||||
"regularMarketPrice": 9875.0,
|
||||
"previousClose": 9758.0,
|
||||
"regularMarketVolume": 12300000,
|
||||
"marketCap": 1215200000000000,
|
||||
"fiftyTwoWeekHigh": 10250.0,
|
||||
"fiftyTwoWeekLow": 7800.0,
|
||||
"averageDailyVolume3Month": 10000000
|
||||
},
|
||||
"timestamp": [1709251200],
|
||||
"indicators": {
|
||||
"quote": [
|
||||
{
|
||||
"open": [9800.0],
|
||||
"high": [9900.0],
|
||||
"low": [9750.0],
|
||||
"close": [9875.0],
|
||||
"volume": [12300000]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
25
tests/fixtures/chart_bbca_3mo.json
vendored
25
tests/fixtures/chart_bbca_3mo.json
vendored
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"chart": {
|
||||
"result": [
|
||||
{
|
||||
"meta": {
|
||||
"symbol": "BBCA.JK",
|
||||
"regularMarketPrice": 9875.0,
|
||||
"previousClose": 9758.0
|
||||
},
|
||||
"timestamp": [1709251200, 1709337600, 1709424000],
|
||||
"indicators": {
|
||||
"quote": [
|
||||
{
|
||||
"open": [9800.0, 9850.0, 9860.0],
|
||||
"high": [9900.0, 9920.0, 9950.0],
|
||||
"low": [9750.0, 9800.0, 9820.0],
|
||||
"close": [9875.0, 9880.0, 9925.0],
|
||||
"volume": [12300000, 11000000, 14000000]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
17
tests/fixtures/chart_bbca_with_gap.json
vendored
17
tests/fixtures/chart_bbca_with_gap.json
vendored
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"chart": {
|
||||
"result": [{
|
||||
"timestamp": [1709251200, 1709337600],
|
||||
"indicators": {
|
||||
"quote": [{
|
||||
"open": [9800.0, 9850.0],
|
||||
"high": [9900.0, 9900.0],
|
||||
"low": [9750.0, 9800.0],
|
||||
"close": [9875.0, null],
|
||||
"volume": [12300000, 11000000]
|
||||
}]
|
||||
}
|
||||
}],
|
||||
"error": null
|
||||
}
|
||||
}
|
||||
48
tests/fixtures/idx_announcement_kepemilikan.json
vendored
48
tests/fixtures/idx_announcement_kepemilikan.json
vendored
|
|
@ -1,48 +0,0 @@
|
|||
{
|
||||
"Items": [
|
||||
{
|
||||
"Id": "20260327163420-Peng-LKS-00043/BEI.PLP/03-2026_id-id",
|
||||
"AnnouncementNo": "Peng-LKS-00043/BEI.PLP/03-2026",
|
||||
"PublishDate": "2026-03-27T16:34:20",
|
||||
"Title": "Pemegang Saham di atas 5% (KSEI)",
|
||||
"AnnouncementType": "",
|
||||
"Code": "Semua Emiten Saham",
|
||||
"Attachments": [
|
||||
{
|
||||
"PDFFilename": "20260327_Semua Emiten Saham_Pengumuman Bursa_32055594.pdf",
|
||||
"FullSavePath": "https://www.idx.co.id/StaticData/NewsAndAnnouncement/ANNOUNCEMENTSTOCK/From_EREP/202603/5d31bb6f49_announcement.pdf",
|
||||
"IsAttachment": 0,
|
||||
"OriginalFilename": "20260327_Semua Emiten Saham_Pengumuman Bursa_32055594.pdf"
|
||||
},
|
||||
{
|
||||
"PDFFilename": "20260327_Semua Emiten Saham_Pengumuman Bursa_32055594_lamp1.pdf",
|
||||
"FullSavePath": "https://www.idx.co.id/StaticData/NewsAndAnnouncement/ANNOUNCEMENTSTOCK/From_EREP/202603/4f5c4efc6f_bf70f249ac_lamp1.pdf",
|
||||
"IsAttachment": 1,
|
||||
"OriginalFilename": "20260327_Semua Emiten Saham_Pengumuman Bursa_32055594_lamp1.pdf"
|
||||
}
|
||||
],
|
||||
"PdfPath": "[{\"PDFFilename\":\"20260327_Semua Emiten Saham_Pengumuman Bursa_32055594.pdf\",\"FullSavePath\":\"https://www.idx.co.id/StaticData/NewsAndAnnouncement/ANNOUNCEMENTSTOCK/From_EREP/202603/5d31bb6f49_announcement.pdf\",\"IsAttachment\":\"0\",\"OriginalFilename\":\"20260327_Semua Emiten Saham_Pengumuman Bursa_32055594.pdf\"},{\"PDFFilename\":\"20260327_Semua Emiten Saham_Pengumuman Bursa_32055594_lamp1.pdf\",\"FullSavePath\":\"https://www.idx.co.id/StaticData/NewsAndAnnouncement/ANNOUNCEMENTSTOCK/From_EREP/202603/4f5c4efc6f_bf70f249ac_lamp1.pdf\",\"IsAttachment\":\"1\",\"OriginalFilename\":\"20260327_Semua Emiten Saham_Pengumuman Bursa_32055594_lamp1.pdf\"}]"
|
||||
},
|
||||
{
|
||||
"Id": "20260328114739-LK/28032026/0001/1_id-id",
|
||||
"AnnouncementNo": "LK/28032026/0001/1",
|
||||
"PublishDate": "2026-03-28T11:47:39",
|
||||
"Title": "LAPORAN KEPEMILIKAN ATAU SETIAP PERUBAHAN KEPEMILIKAN SAHAM PERUSAHAAN TERBUKA",
|
||||
"AnnouncementType": "LKS",
|
||||
"Code": "CASH",
|
||||
"Attachments": [
|
||||
{
|
||||
"PDFFilename": "LK-28032026-2468-00.pdf-0",
|
||||
"FullSavePath": "https://www.idx.co.id/StaticData/NewsAndAnnouncement/ANNOUNCEMENTSTOCK/From_KSEI/LK-28032026-2468-00.pdf-0.pdf",
|
||||
"IsAttachment": 1,
|
||||
"OriginalFilename": "LK-28032026-2468-00.pdf"
|
||||
}
|
||||
],
|
||||
"PdfPath": "[{\"PDFFilename\":\"LK-28032026-2468-00.pdf-0\",\"FullSavePath\":\"https://www.idx.co.id/StaticData/NewsAndAnnouncement/ANNOUNCEMENTSTOCK/From_KSEI/LK-28032026-2468-00.pdf-0.pdf\",\"IsAttachment\":1,\"OriginalFilename\":\"LK-28032026-2468-00.pdf\"}]"
|
||||
}
|
||||
],
|
||||
"ItemCount": 2,
|
||||
"PageSize": 10,
|
||||
"PageNumber": 1,
|
||||
"PageCount": 1
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="id"><head><title>Data Kepemilikan Saham - Bursa Efek Indonesia</title></head>
|
||||
<body><div id="__nuxt"><!-- trimmed excerpt of https://www.idx.co.id/id/perusahaan-tercatat/data-kepemilikan-saham/ (2026-09-24) --></div>
|
||||
<script>window.__NUXT__=(function(a,r){return {fetch:{"data-v-8c8e470a:0":{tableData:[{Description:"Pemegang Saham di Atas 5% per 23 September 2026",Prospectus:"https:\u002F\u002Fwww.idx.co.id\u002FMedia\u002Fsucngcwy\u002Fpeng-2026-09-23-00080-lima-persen.xlsx",ListingDate:"2026-09-23T12:00:00"},{Description:"Pemegang Saham di Atas 5% per 31 Agustus 2026",Prospectus:"https:\u002F\u002Fwww.idx.co.id\u002FMedia\u002Fumrls4il\u002Fpeng-2026-08-31-00063-lima-persen.xlsx",ListingDate:r},{Description:"Data Kepemilikan Saham Perusahaan Tercatat Berdasarkan Klasifikasi Investor per 31 Agustus 2026",Prospectus:"https:\u002F\u002Fwww.idx.co.id\u002FMedia\u002Fy0vjakdz\u002Fpeng-2026-08-00018-klasifikasi.xlsx",ListingDate:r},{Description:"Data Kepemilikan Saham Perusahaan Tercatat per Tipe Investor per 31 Agustus 2026",Prospectus:"https:\u002F\u002Fwww.idx.co.id\u002FMedia\u002Fwkjfudt3\u002Fpeng-2026-08-00019-tipe.xlsx",ListingDate:r},{Description:"Pemegang Saham di Atas 1% per 31 Agustus 2026",Prospectus:"https:\u002F\u002Fwww.idx.co.id\u002FMedia\u002Ffahlw1o2\u002Fpeng-2026-08-00017-satu-persen.xlsx",ListingDate:r},{Description:"Pemegang Saham di Atas 1% per 31 Juli 2026",Prospectus:"https:\u002F\u002Fwww.idx.co.id\u002FMedia\u002Ffjelt0en\u002Fpeng-2026-07-00016-satu-persen.xlsx",ListingDate:s},{Description:"Pemegang Saham di Atas 1% per 27 Februari 2026",Prospectus:"https:\u002F\u002Fwww.idx.co.id\u002FMedia\u002Fr2kjzpk5\u002Fpeng-02-00011-satu-persen.xlsx",ListingDate:K}]}}}}(null,"2026-09-01T12:00:00"));</script>
|
||||
</body></html>
|
||||
BIN
tests/fixtures/ksei_above1_20260831_excerpt.xlsx
vendored
BIN
tests/fixtures/ksei_above1_20260831_excerpt.xlsx
vendored
Binary file not shown.
|
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<document>
|
||||
<page id="page1" width="612" height="792">
|
||||
<line bbox="58.2 135.37999 63.566404 137.78" wmode="0" dir="1 0" flags="0" text="DATE"></line>
|
||||
<line bbox="73.944 135.37999 87.46321 137.78" wmode="0" dir="1 0" flags="0" text="SHARE CODE"></line>
|
||||
<line bbox="111.26 135.37999 125.50881 137.78" wmode="0" dir="1 0" flags="0" text="ISSUER NAME"></line>
|
||||
<line bbox="199.73 135.37999 217.21158 137.78" wmode="0" dir="1 0" flags="0" text="INVESTOR NAME"></line>
|
||||
<line bbox="288.53 135.37999 315.77238 137.78" wmode="0" dir="1 0" flags="0" text="INVESTOR CLASSIFICATION"></line>
|
||||
<line bbox="337.63 135.37999 354.19963 137.78" wmode="0" dir="1 0" flags="0" text="LOCAL FOREIGN"></line>
|
||||
<line bbox="363.31 135.37999 376.7908 137.78" wmode="0" dir="1 0" flags="0" text="NATIONALITY"></line>
|
||||
<line bbox="398.11 135.37999 408.034 137.78" wmode="0" dir="1 0" flags="0" text="DOMICILE"></line>
|
||||
<line bbox="432.55 135.37999 454.30836 137.78" wmode="0" dir="1 0" flags="0" text="HOLDINGS SCRIPLESS"></line>
|
||||
<line bbox="466.78 135.37999 484.1248 137.78" wmode="0" dir="1 0" flags="0" text="HOLDINGS SCRIP"></line>
|
||||
<line bbox="496.9 135.37999 522.97366 137.78" wmode="0" dir="1 0" flags="0" text="TOTAL HOLDING SHARES"></line>
|
||||
<line bbox="534.34 135.37999 547.6168 137.78" wmode="0" dir="1 0" flags="0" text="PERCENTAGE"></line>
|
||||
<line bbox="55.68 138.49999 75.26399 140.9" wmode="0" dir="1 0" flags="0" text="29-May-2026 AADI"></line>
|
||||
<line bbox="91.944 138.49999 125.39758 140.9" wmode="0" dir="1 0" flags="0" text="ADARO ANDALAN INDONESIA Tbk"></line>
|
||||
<line bbox="145.7 138.49999 175.97843 140.9" wmode="0" dir="1 0" flags="0" text="PERSADA CAPITAL INVESTAMA"></line>
|
||||
<line bbox="272.09 138.49999 282.27076 140.9" wmode="0" dir="1 0" flags="0" text="Corporate"></line>
|
||||
<line bbox="330.0 138.49999 332.0 140.9" wmode="0" dir="1 0" flags="0" text="D"></line>
|
||||
<line bbox="360.0 138.49999 380.0 140.9" wmode="0" dir="1 0" flags="0" text="INDONESIA"></line>
|
||||
<line bbox="430.0 138.49999 460.0 140.9" wmode="0" dir="1 0" flags="0" text="3.200.142.830"></line>
|
||||
<line bbox="465.0 138.49999 470.0 140.9" wmode="0" dir="1 0" flags="0" text="0"></line>
|
||||
<line bbox="495.0 138.49999 525.0 140.9" wmode="0" dir="1 0" flags="0" text="3.200.142.830"></line>
|
||||
<line bbox="533.0 138.49999 548.0 140.9" wmode="0" dir="1 0" flags="0" text="41,10"></line>
|
||||
</page>
|
||||
</document>
|
||||
29
tests/fixtures/ksei_above1_stext_excerpt.xml
vendored
29
tests/fixtures/ksei_above1_stext_excerpt.xml
vendored
|
|
@ -1,29 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<document>
|
||||
<page id="page1" width="792" height="612">
|
||||
<block bbox="28.68 86.33 767.71438 600.02999" justify="unknown">
|
||||
<line bbox="31.56 86.33 39.25776 89.810009" wmode="0" dir="1 0" flags="0" text="DATE"></line>
|
||||
<line bbox="56.64 86.33 75.974887 89.810009" wmode="0" dir="1 0" flags="0" text="SHARE_CODE"></line>
|
||||
<line bbox="121.22 86.33 142.22878 89.810009" wmode="0" dir="1 0" flags="0" text="ISSUER_NAME"></line>
|
||||
<line bbox="267.17 86.33 292.6193 89.810009" wmode="0" dir="1 0" flags="0" text="INVESTOR_NAME"></line>
|
||||
<line bbox="390.89 86.33 414.18165 89.810009" wmode="0" dir="1 0" flags="0" text="INVESTOR_TYPE"></line>
|
||||
<line bbox="434.11 86.33 457.99674 89.810009" wmode="0" dir="1 0" flags="0" text="LOCAL_FOREIGN"></line>
|
||||
<line bbox="475.87 86.33 495.66777 89.810009" wmode="0" dir="1 0" flags="0" text="NATIONALITY"></line>
|
||||
<line bbox="525.19 86.33 539.60067 89.810009" wmode="0" dir="1 0" flags="0" text="DOMICILE"></line>
|
||||
<line bbox="574.63 86.33 606.14498 89.810009" wmode="0" dir="1 0" flags="0" text="HOLDINGS_SCRIPLESS"></line>
|
||||
<line bbox="629.98 86.33 655.1021 89.810009" wmode="0" dir="1 0" flags="0" text="HOLDINGS_SCRIP"></line>
|
||||
<line bbox="680.02 86.33 717.5414 89.810009" wmode="0" dir="1 0" flags="0" text="TOTAL_HOLDING_SHARES"></line>
|
||||
<line bbox="741.22 86.33 760.0782 89.810009" wmode="0" dir="1 0" flags="0" text="PERCENTAGE"></line>
|
||||
<line bbox="28.68 91.009998 55.722299 94.49" wmode="0" dir="1 0" flags="0" text="27-Feb-2026 AADI"></line>
|
||||
<line bbox="85.104 91.009998 133.29856 94.49" wmode="0" dir="1 0" flags="0" text="ADARO ANDALAN INDONESIA Tbk"></line>
|
||||
<line bbox="179.3 91.009998 226.93775 94.49" wmode="0" dir="1 0" flags="0" text="ADARO STRATEGIC INVESTMENTS"></line>
|
||||
<line bbox="381.41 91.009998 385.00923 94.49" wmode="0" dir="1 0" flags="0" text="CP"></line>
|
||||
<line bbox="424.75 91.009998 426.8902 94.49" wmode="0" dir="1 0" flags="0" text="D"></line>
|
||||
<line bbox="504.07 91.009998 519.99099 94.49" wmode="0" dir="1 0" flags="0" text="INDONESIA"></line>
|
||||
<line bbox="597.58 91.009998 618.0213 94.49" wmode="0" dir="1 0" flags="0" text="3.200.142.830"></line>
|
||||
<line bbox="662.26 91.009998 664.02438 94.49" wmode="0" dir="1 0" flags="0" text="0"></line>
|
||||
<line bbox="710.26 91.009998 730.7013 94.49" wmode="0" dir="1 0" flags="0" text="3.200.142.830"></line>
|
||||
<line bbox="759.72 91.009998 767.70999 94.49" wmode="0" dir="1 0" flags="0" text="41,10"></line>
|
||||
</block>
|
||||
</page>
|
||||
</document>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<document>
|
||||
<page id="page1" width="792" height="612">
|
||||
<block bbox="28.68 86.33 767.71438 600.02999" justify="unknown">
|
||||
<line bbox="31.56 86.33 39.25776 89.810009" wmode="0" dir="1 0" flags="0" text="DATE"></line>
|
||||
<line bbox="56.64 86.33 75.974887 89.810009" wmode="0" dir="1 0" flags="0" text="SHARE_CODE"></line>
|
||||
<line bbox="121.22 86.33 142.22878 89.810009" wmode="0" dir="1 0" flags="0" text="ISSUER_NAME"></line>
|
||||
<line bbox="267.17 86.33 292.6193 89.810009" wmode="0" dir="1 0" flags="0" text="INVESTOR_NAME"></line>
|
||||
<line bbox="390.89 86.33 414.18165 89.810009" wmode="0" dir="1 0" flags="0" text="INVESTOR_TYPE"></line>
|
||||
<line bbox="434.11 86.33 457.99674 89.810009" wmode="0" dir="1 0" flags="0" text="LOCAL_FOREIGN"></line>
|
||||
<line bbox="475.87 86.33 495.66777 89.810009" wmode="0" dir="1 0" flags="0" text="NATIONALITY"></line>
|
||||
<line bbox="525.19 86.33 539.60067 89.810009" wmode="0" dir="1 0" flags="0" text="DOMICILE"></line>
|
||||
<line bbox="574.63 86.33 606.14498 89.810009" wmode="0" dir="1 0" flags="0" text="HOLDINGS_SCRIPLESS"></line>
|
||||
<line bbox="629.98 86.33 655.1021 89.810009" wmode="0" dir="1 0" flags="0" text="HOLDINGS_SCRIP"></line>
|
||||
<line bbox="680.02 86.33 717.5414 89.810009" wmode="0" dir="1 0" flags="0" text="TOTAL_HOLDING_SHARES"></line>
|
||||
<line bbox="741.22 86.33 760.0782 89.810009" wmode="0" dir="1 0" flags="0" text="PERCENTAGE"></line>
|
||||
<line bbox="28.68 91.009998 55.722299 94.49" wmode="0" dir="1 0" flags="0" text="31-Jan-2026 AADI"></line>
|
||||
<line bbox="85.104 91.009998 133.29856 94.49" wmode="0" dir="1 0" flags="0" text="ADARO ANDALAN INDONESIA Tbk"></line>
|
||||
<line bbox="179.3 91.009998 226.93775 94.49" wmode="0" dir="1 0" flags="0" text="ADARO STRATEGIC INVESTMENTS"></line>
|
||||
<line bbox="381.41 91.009998 385.00923 94.49" wmode="0" dir="1 0" flags="0" text="CP"></line>
|
||||
<line bbox="424.75 91.009998 426.8902 94.49" wmode="0" dir="1 0" flags="0" text="D"></line>
|
||||
<line bbox="504.07 91.009998 519.99099 94.49" wmode="0" dir="1 0" flags="0" text="INDONESIA"></line>
|
||||
<line bbox="597.58 91.009998 618.0213 94.49" wmode="0" dir="1 0" flags="0" text="3.050.000.000"></line>
|
||||
<line bbox="662.26 91.009998 664.02438 94.49" wmode="0" dir="1 0" flags="0" text="0"></line>
|
||||
<line bbox="710.26 91.009998 730.7013 94.49" wmode="0" dir="1 0" flags="0" text="3.050.000.000"></line>
|
||||
<line bbox="759.72 91.009998 767.70999 94.49" wmode="0" dir="1 0" flags="0" text="39,82"></line>
|
||||
</block>
|
||||
</page>
|
||||
</document>
|
||||
BIN
tests/fixtures/ksei_above5_20260923_excerpt.xlsx
vendored
BIN
tests/fixtures/ksei_above5_20260923_excerpt.xlsx
vendored
Binary file not shown.
8
tests/fixtures/ksei_above5_stext_excerpt.xml
vendored
8
tests/fixtures/ksei_above5_stext_excerpt.xml
vendored
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<document>
|
||||
<page id="page1" width="595" height="842">
|
||||
<line bbox="0 0 10 10" text="Pemegang Saham di atas 5% (KSEI)"></line>
|
||||
<line bbox="0 12 10 22" text="INVS"></line>
|
||||
<line bbox="0 24 10 34" text="PT MAGNUS Capital (REKENING TAMPUNGAN KSEI UNTUK CLOSED MEMBER-ABC)"></line>
|
||||
</page>
|
||||
</document>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<document>
|
||||
<page id="page1" width="595" height="842">
|
||||
<line bbox="0 0 10 10" text="PENGUMUMAN"></line>
|
||||
<line bbox="0 12 10 22" text="PT Bursa Efek Indonesia (BEI)"></line>
|
||||
<line bbox="0 24 10 34" text="Pemegang Saham di atas 1% (KSEI)"></line>
|
||||
</page>
|
||||
</document>
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
Date|Code|Type|Sec. Num|Price|Local IS|Local CP|Local PF|Local IB|Local ID|Local MF|Local SC|Local FD|Local OT|Total|Foreign IS|Foreign CP|Foreign PF|Foreign IB|Foreign ID|Foreign MF|Foreign SC|Foreign FD|Foreign OT|Total
|
||||
30-JAN-2026|AADI|EQUITY|7786891760|7600|58704495|5046580437|13135269|41|1868661103|91475881|27984191|1966845|85275|7108593537|1150700|55820749|58897143|207783974|2127405|239139003|39765137|2493100|71121012|678298223
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
Date|Code|Type|Sec. Num|Price|Local IS|Local CP|Local PF|Local IB|Local ID|Local MF|Local SC|Local FD|Local OT|Total|Foreign IS|Foreign CP|Foreign PF|Foreign IB|Foreign ID|Foreign MF|Foreign SC|Foreign FD|Foreign OT|Total
|
||||
27-FEB-2026|AADI|EQUITY|7786891760|9250|100730965|5035745466|15622269|41|1817092689|117982099|22932698|2060140|105275|7112271642|1150700|66705786|43311343|204936195|1261705|262226503|42723690|2493100|49811096|674620118
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<document>
|
||||
<page id="page1" width="595" height="842">
|
||||
<line bbox="0 0 10 10" text="DATE"></line>
|
||||
<line bbox="0 12 10 22" text="STOCK_CODE"></line>
|
||||
<line bbox="0 24 10 34" text="NUMBER_OF_SHARES"></line>
|
||||
<line bbox="0 36 10 46" text="FOREIGN"></line>
|
||||
<line bbox="0 48 10 58" text="LOCAL INDIVIDUAL"></line>
|
||||
</page>
|
||||
</document>
|
||||
328
tests/fixtures/ksei_stext_sample.xml
vendored
328
tests/fixtures/ksei_stext_sample.xml
vendored
|
|
@ -1,328 +0,0 @@
|
|||
<document>
|
||||
<page id="page1" width="792" height="612">
|
||||
<char x="40.0" y="40.0" c="P"/>
|
||||
<char x="41.2" y="40.0" c="E"/>
|
||||
<char x="42.4" y="40.0" c="N"/>
|
||||
<char x="43.6" y="40.0" c="G"/>
|
||||
</page>
|
||||
<page id="page2" width="792" height="612">
|
||||
<char x="21.7" y="100.0" c="2"/>
|
||||
<char x="22.8" y="100.0" c="7"/>
|
||||
<char x="23.9" y="100.0" c="-"/>
|
||||
<char x="25.0" y="100.0" c="F"/>
|
||||
<char x="26.1" y="100.0" c="e"/>
|
||||
<char x="27.2" y="100.0" c="b"/>
|
||||
<char x="28.3" y="100.0" c="-"/>
|
||||
<char x="29.4" y="100.0" c="2"/>
|
||||
<char x="30.5" y="100.0" c="0"/>
|
||||
<char x="31.6" y="100.0" c="2"/>
|
||||
<char x="32.7" y="100.0" c="6"/>
|
||||
<char x="55.3" y="100.0" c="B"/>
|
||||
<char x="56.4" y="100.0" c="B"/>
|
||||
<char x="57.5" y="100.0" c="C"/>
|
||||
<char x="58.6" y="100.0" c="A"/>
|
||||
<char x="75.0" y="100.0" c="B"/>
|
||||
<char x="76.1" y="100.0" c="A"/>
|
||||
<char x="77.2" y="100.0" c="N"/>
|
||||
<char x="78.3" y="100.0" c="K"/>
|
||||
<char x="79.4" y="100.0" c=" "/>
|
||||
<char x="80.8" y="100.0" c="C"/>
|
||||
<char x="81.9" y="100.0" c="E"/>
|
||||
<char x="83.0" y="100.0" c="N"/>
|
||||
<char x="84.1" y="100.0" c="T"/>
|
||||
<char x="85.2" y="100.0" c="R"/>
|
||||
<char x="86.3" y="100.0" c="A"/>
|
||||
<char x="87.4" y="100.0" c="L"/>
|
||||
<char x="88.5" y="100.0" c=" "/>
|
||||
<char x="89.9" y="100.0" c="A"/>
|
||||
<char x="91.0" y="100.0" c="S"/>
|
||||
<char x="92.1" y="100.0" c="I"/>
|
||||
<char x="93.2" y="100.0" c="A"/>
|
||||
<char x="94.3" y="100.0" c=" "/>
|
||||
<char x="95.7" y="100.0" c="T"/>
|
||||
<char x="96.8" y="100.0" c="b"/>
|
||||
<char x="97.9" y="100.0" c="k"/>
|
||||
<char x="167.9" y="100.0" c="P"/>
|
||||
<char x="169.0" y="100.0" c="T"/>
|
||||
<char x="170.1" y="100.0" c=" "/>
|
||||
<char x="171.5" y="100.0" c="D"/>
|
||||
<char x="172.6" y="100.0" c="W"/>
|
||||
<char x="173.7" y="100.0" c="I"/>
|
||||
<char x="174.8" y="100.0" c="M"/>
|
||||
<char x="175.9" y="100.0" c="U"/>
|
||||
<char x="177.0" y="100.0" c="R"/>
|
||||
<char x="178.1" y="100.0" c="I"/>
|
||||
<char x="179.2" y="100.0" c="A"/>
|
||||
<char x="180.3" y="100.0" c=" "/>
|
||||
<char x="181.7" y="100.0" c="I"/>
|
||||
<char x="182.8" y="100.0" c="N"/>
|
||||
<char x="183.9" y="100.0" c="V"/>
|
||||
<char x="185.0" y="100.0" c="E"/>
|
||||
<char x="186.1" y="100.0" c="S"/>
|
||||
<char x="187.2" y="100.0" c="T"/>
|
||||
<char x="188.3" y="100.0" c="A"/>
|
||||
<char x="189.4" y="100.0" c="M"/>
|
||||
<char x="190.5" y="100.0" c="A"/>
|
||||
<char x="191.6" y="100.0" c=" "/>
|
||||
<char x="193.0" y="100.0" c="A"/>
|
||||
<char x="194.1" y="100.0" c="N"/>
|
||||
<char x="195.2" y="100.0" c="D"/>
|
||||
<char x="196.3" y="100.0" c="A"/>
|
||||
<char x="197.4" y="100.0" c="L"/>
|
||||
<char x="198.5" y="100.0" c="A"/>
|
||||
<char x="199.6" y="100.0" c="N"/>
|
||||
<char x="435.0" y="100.0" c="C"/>
|
||||
<char x="436.1" y="100.0" c="P"/>
|
||||
<char x="468.0" y="100.0" c="L"/>
|
||||
<char x="500.0" y="100.0" c="I"/>
|
||||
<char x="501.1" y="100.0" c="D"/>
|
||||
<char x="560.0" y="100.0" c="I"/>
|
||||
<char x="561.1" y="100.0" c="D"/>
|
||||
<char x="620.0" y="100.0" c="1"/>
|
||||
<char x="621.1" y="100.0" c="3"/>
|
||||
<char x="622.2" y="100.0" c="."/>
|
||||
<char x="623.3" y="100.0" c="5"/>
|
||||
<char x="624.4" y="100.0" c="3"/>
|
||||
<char x="625.5" y="100.0" c="3"/>
|
||||
<char x="626.6" y="100.0" c="."/>
|
||||
<char x="627.7" y="100.0" c="6"/>
|
||||
<char x="628.8" y="100.0" c="8"/>
|
||||
<char x="629.9" y="100.0" c="2"/>
|
||||
<char x="631.0" y="100.0" c="."/>
|
||||
<char x="632.1" y="100.0" c="4"/>
|
||||
<char x="633.2" y="100.0" c="4"/>
|
||||
<char x="634.3" y="100.0" c="0"/>
|
||||
<char x="656.0" y="100.0" c="0"/>
|
||||
<char x="696.0" y="100.0" c="1"/>
|
||||
<char x="697.1" y="100.0" c="3"/>
|
||||
<char x="698.2" y="100.0" c="."/>
|
||||
<char x="699.3" y="100.0" c="5"/>
|
||||
<char x="700.4" y="100.0" c="3"/>
|
||||
<char x="701.5" y="100.0" c="3"/>
|
||||
<char x="702.6" y="100.0" c="."/>
|
||||
<char x="703.7" y="100.0" c="6"/>
|
||||
<char x="704.8" y="100.0" c="8"/>
|
||||
<char x="705.9" y="100.0" c="2"/>
|
||||
<char x="707.0" y="100.0" c="."/>
|
||||
<char x="708.1" y="100.0" c="4"/>
|
||||
<char x="709.2" y="100.0" c="4"/>
|
||||
<char x="710.3" y="100.0" c="0"/>
|
||||
<char x="748.0" y="100.0" c="5"/>
|
||||
<char x="749.1" y="100.0" c="4"/>
|
||||
<char x="750.2" y="100.0" c=","/>
|
||||
<char x="751.3" y="100.0" c="9"/>
|
||||
<char x="752.4" y="100.0" c="4"/>
|
||||
<char x="21.7" y="101.9" c="2"/>
|
||||
<char x="22.8" y="101.9" c="7"/>
|
||||
<char x="23.9" y="101.9" c="-"/>
|
||||
<char x="25.0" y="101.9" c="F"/>
|
||||
<char x="26.1" y="101.9" c="e"/>
|
||||
<char x="27.2" y="101.9" c="b"/>
|
||||
<char x="28.3" y="101.9" c="-"/>
|
||||
<char x="29.4" y="101.9" c="2"/>
|
||||
<char x="30.5" y="101.9" c="0"/>
|
||||
<char x="31.6" y="101.9" c="2"/>
|
||||
<char x="32.7" y="101.9" c="6"/>
|
||||
<char x="55.3" y="101.9" c="B"/>
|
||||
<char x="56.4" y="101.9" c="B"/>
|
||||
<char x="57.5" y="101.9" c="C"/>
|
||||
<char x="58.6" y="101.9" c="A"/>
|
||||
<char x="75.0" y="101.9" c="B"/>
|
||||
<char x="76.1" y="101.9" c="A"/>
|
||||
<char x="77.2" y="101.9" c="N"/>
|
||||
<char x="78.3" y="101.9" c="K"/>
|
||||
<char x="79.4" y="101.9" c=" "/>
|
||||
<char x="80.8" y="101.9" c="C"/>
|
||||
<char x="81.9" y="101.9" c="E"/>
|
||||
<char x="83.0" y="101.9" c="N"/>
|
||||
<char x="84.1" y="101.9" c="T"/>
|
||||
<char x="85.2" y="101.9" c="R"/>
|
||||
<char x="86.3" y="101.9" c="A"/>
|
||||
<char x="87.4" y="101.9" c="L"/>
|
||||
<char x="88.5" y="101.9" c=" "/>
|
||||
<char x="89.9" y="101.9" c="A"/>
|
||||
<char x="91.0" y="101.9" c="S"/>
|
||||
<char x="92.1" y="101.9" c="I"/>
|
||||
<char x="93.2" y="101.9" c="A"/>
|
||||
<char x="94.3" y="101.9" c=" "/>
|
||||
<char x="95.7" y="101.9" c="T"/>
|
||||
<char x="96.8" y="101.9" c="b"/>
|
||||
<char x="97.9" y="101.9" c="k"/>
|
||||
<char x="167.9" y="101.9" c="P"/>
|
||||
<char x="169.0" y="101.9" c="T"/>
|
||||
<char x="170.1" y="101.9" c=" "/>
|
||||
<char x="171.5" y="101.9" c="G"/>
|
||||
<char x="172.6" y="101.9" c="I"/>
|
||||
<char x="173.7" y="101.9" c="T"/>
|
||||
<char x="174.8" y="101.9" c="A"/>
|
||||
<char x="175.9" y="101.9" c=" "/>
|
||||
<char x="177.3" y="101.9" c="S"/>
|
||||
<char x="178.4" y="101.9" c="U"/>
|
||||
<char x="179.5" y="101.9" c="R"/>
|
||||
<char x="180.6" y="101.9" c="Y"/>
|
||||
<char x="181.7" y="101.9" c="A"/>
|
||||
<char x="182.8" y="101.9" c=" "/>
|
||||
<char x="184.2" y="101.9" c="H"/>
|
||||
<char x="185.3" y="101.9" c="A"/>
|
||||
<char x="186.4" y="101.9" c="S"/>
|
||||
<char x="187.5" y="101.9" c="T"/>
|
||||
<char x="188.6" y="101.9" c="A"/>
|
||||
<char x="435.0" y="101.9" c="C"/>
|
||||
<char x="436.1" y="101.9" c="P"/>
|
||||
<char x="468.0" y="101.9" c="L"/>
|
||||
<char x="500.0" y="101.9" c="I"/>
|
||||
<char x="501.1" y="101.9" c="D"/>
|
||||
<char x="560.0" y="101.9" c="I"/>
|
||||
<char x="561.1" y="101.9" c="D"/>
|
||||
<char x="620.0" y="101.9" c="5"/>
|
||||
<char x="621.1" y="101.9" c="."/>
|
||||
<char x="622.2" y="101.9" c="2"/>
|
||||
<char x="623.3" y="101.9" c="0"/>
|
||||
<char x="624.4" y="101.9" c="0"/>
|
||||
<char x="625.5" y="101.9" c="."/>
|
||||
<char x="626.6" y="101.9" c="0"/>
|
||||
<char x="627.7" y="101.9" c="0"/>
|
||||
<char x="628.8" y="101.9" c="0"/>
|
||||
<char x="629.9" y="101.9" c="."/>
|
||||
<char x="631.0" y="101.9" c="0"/>
|
||||
<char x="632.1" y="101.9" c="0"/>
|
||||
<char x="633.2" y="101.9" c="0"/>
|
||||
<char x="656.0" y="101.9" c="0"/>
|
||||
<char x="696.0" y="101.9" c="5"/>
|
||||
<char x="697.1" y="101.9" c="."/>
|
||||
<char x="698.2" y="101.9" c="2"/>
|
||||
<char x="699.3" y="101.9" c="0"/>
|
||||
<char x="700.4" y="101.9" c="0"/>
|
||||
<char x="701.5" y="101.9" c="."/>
|
||||
<char x="702.6" y="101.9" c="0"/>
|
||||
<char x="703.7" y="101.9" c="0"/>
|
||||
<char x="704.8" y="101.9" c="0"/>
|
||||
<char x="705.9" y="101.9" c="."/>
|
||||
<char x="707.0" y="101.9" c="0"/>
|
||||
<char x="708.1" y="101.9" c="0"/>
|
||||
<char x="709.2" y="101.9" c="0"/>
|
||||
<char x="748.0" y="101.9" c="2"/>
|
||||
<char x="749.1" y="101.9" c="1"/>
|
||||
<char x="750.2" y="101.9" c=","/>
|
||||
<char x="751.3" y="101.9" c="1"/>
|
||||
<char x="752.4" y="101.9" c="1"/>
|
||||
</page>
|
||||
<page id="page3" width="792" height="612">
|
||||
<char x="21.7" y="120.0" c="2"/>
|
||||
<char x="22.8" y="120.0" c="7"/>
|
||||
<char x="23.9" y="120.0" c="-"/>
|
||||
<char x="25.0" y="120.0" c="F"/>
|
||||
<char x="26.1" y="120.0" c="e"/>
|
||||
<char x="27.2" y="120.0" c="b"/>
|
||||
<char x="28.3" y="120.0" c="-"/>
|
||||
<char x="29.4" y="120.0" c="2"/>
|
||||
<char x="30.5" y="120.0" c="0"/>
|
||||
<char x="31.6" y="120.0" c="2"/>
|
||||
<char x="32.7" y="120.0" c="6"/>
|
||||
<char x="55.3" y="120.0" c="B"/>
|
||||
<char x="56.4" y="120.0" c="B"/>
|
||||
<char x="57.5" y="120.0" c="R"/>
|
||||
<char x="58.6" y="120.0" c="I"/>
|
||||
<char x="75.0" y="120.0" c="B"/>
|
||||
<char x="76.1" y="120.0" c="A"/>
|
||||
<char x="77.2" y="120.0" c="N"/>
|
||||
<char x="78.3" y="120.0" c="K"/>
|
||||
<char x="79.4" y="120.0" c=" "/>
|
||||
<char x="80.8" y="120.0" c="R"/>
|
||||
<char x="81.9" y="120.0" c="A"/>
|
||||
<char x="83.0" y="120.0" c="K"/>
|
||||
<char x="84.1" y="120.0" c="Y"/>
|
||||
<char x="85.2" y="120.0" c="A"/>
|
||||
<char x="86.3" y="120.0" c="T"/>
|
||||
<char x="87.4" y="120.0" c=" "/>
|
||||
<char x="88.8" y="120.0" c="I"/>
|
||||
<char x="89.9" y="120.0" c="N"/>
|
||||
<char x="91.0" y="120.0" c="D"/>
|
||||
<char x="92.1" y="120.0" c="O"/>
|
||||
<char x="93.2" y="120.0" c="N"/>
|
||||
<char x="94.3" y="120.0" c="E"/>
|
||||
<char x="95.4" y="120.0" c="S"/>
|
||||
<char x="96.5" y="120.0" c="I"/>
|
||||
<char x="97.6" y="120.0" c="A"/>
|
||||
<char x="98.7" y="120.0" c=" "/>
|
||||
<char x="100.1" y="120.0" c="("/>
|
||||
<char x="101.2" y="120.0" c="P"/>
|
||||
<char x="102.3" y="120.0" c="E"/>
|
||||
<char x="103.4" y="120.0" c="R"/>
|
||||
<char x="104.5" y="120.0" c="S"/>
|
||||
<char x="105.6" y="120.0" c="E"/>
|
||||
<char x="106.7" y="120.0" c="R"/>
|
||||
<char x="107.8" y="120.0" c="O"/>
|
||||
<char x="108.9" y="120.0" c=")"/>
|
||||
<char x="110.0" y="120.0" c=" "/>
|
||||
<char x="111.4" y="120.0" c="T"/>
|
||||
<char x="112.5" y="120.0" c="b"/>
|
||||
<char x="113.6" y="120.0" c="k"/>
|
||||
<char x="167.9" y="120.0" c="N"/>
|
||||
<char x="169.0" y="120.0" c="E"/>
|
||||
<char x="170.1" y="120.0" c="G"/>
|
||||
<char x="171.2" y="120.0" c="A"/>
|
||||
<char x="172.3" y="120.0" c="R"/>
|
||||
<char x="173.4" y="120.0" c="A"/>
|
||||
<char x="174.5" y="120.0" c=" "/>
|
||||
<char x="175.9" y="120.0" c="R"/>
|
||||
<char x="177.0" y="120.0" c="E"/>
|
||||
<char x="178.1" y="120.0" c="P"/>
|
||||
<char x="179.2" y="120.0" c="U"/>
|
||||
<char x="180.3" y="120.0" c="B"/>
|
||||
<char x="181.4" y="120.0" c="L"/>
|
||||
<char x="182.5" y="120.0" c="I"/>
|
||||
<char x="183.6" y="120.0" c="K"/>
|
||||
<char x="184.7" y="120.0" c=" "/>
|
||||
<char x="186.1" y="120.0" c="I"/>
|
||||
<char x="187.2" y="120.0" c="N"/>
|
||||
<char x="188.3" y="120.0" c="D"/>
|
||||
<char x="189.4" y="120.0" c="O"/>
|
||||
<char x="190.5" y="120.0" c="N"/>
|
||||
<char x="191.6" y="120.0" c="E"/>
|
||||
<char x="192.7" y="120.0" c="S"/>
|
||||
<char x="193.8" y="120.0" c="I"/>
|
||||
<char x="194.9" y="120.0" c="A"/>
|
||||
<char x="435.0" y="120.0" c="C"/>
|
||||
<char x="436.1" y="120.0" c="P"/>
|
||||
<char x="468.0" y="120.0" c="L"/>
|
||||
<char x="500.0" y="120.0" c="I"/>
|
||||
<char x="501.1" y="120.0" c="D"/>
|
||||
<char x="560.0" y="120.0" c="I"/>
|
||||
<char x="561.1" y="120.0" c="D"/>
|
||||
<char x="620.0" y="120.0" c="6"/>
|
||||
<char x="621.1" y="120.0" c="7"/>
|
||||
<char x="622.2" y="120.0" c="."/>
|
||||
<char x="623.3" y="120.0" c="0"/>
|
||||
<char x="624.4" y="120.0" c="0"/>
|
||||
<char x="625.5" y="120.0" c="0"/>
|
||||
<char x="626.6" y="120.0" c="."/>
|
||||
<char x="627.7" y="120.0" c="0"/>
|
||||
<char x="628.8" y="120.0" c="0"/>
|
||||
<char x="629.9" y="120.0" c="0"/>
|
||||
<char x="631.0" y="120.0" c="."/>
|
||||
<char x="632.1" y="120.0" c="0"/>
|
||||
<char x="633.2" y="120.0" c="0"/>
|
||||
<char x="634.3" y="120.0" c="0"/>
|
||||
<char x="656.0" y="120.0" c="0"/>
|
||||
<char x="696.0" y="120.0" c="6"/>
|
||||
<char x="697.1" y="120.0" c="7"/>
|
||||
<char x="698.2" y="120.0" c="."/>
|
||||
<char x="699.3" y="120.0" c="0"/>
|
||||
<char x="700.4" y="120.0" c="0"/>
|
||||
<char x="701.5" y="120.0" c="0"/>
|
||||
<char x="702.6" y="120.0" c="."/>
|
||||
<char x="703.7" y="120.0" c="0"/>
|
||||
<char x="704.8" y="120.0" c="0"/>
|
||||
<char x="705.9" y="120.0" c="0"/>
|
||||
<char x="707.0" y="120.0" c="."/>
|
||||
<char x="708.1" y="120.0" c="0"/>
|
||||
<char x="709.2" y="120.0" c="0"/>
|
||||
<char x="710.3" y="120.0" c="0"/>
|
||||
<char x="748.0" y="120.0" c="5"/>
|
||||
<char x="749.1" y="120.0" c="3"/>
|
||||
<char x="750.2" y="120.0" c=","/>
|
||||
<char x="751.3" y="120.0" c="1"/>
|
||||
<char x="752.4" y="120.0" c="9"/>
|
||||
</page>
|
||||
</document>
|
||||
17
tests/fixtures/msn_chart_bbca_3m.json
vendored
17
tests/fixtures/msn_chart_bbca_3m.json
vendored
|
|
@ -1,17 +0,0 @@
|
|||
[
|
||||
{
|
||||
"_p": "bn91jc",
|
||||
"chartType": "3M",
|
||||
"symbol": "BBCA",
|
||||
"series": {
|
||||
"timeStamps": [
|
||||
"2026-01-13T17:00:00Z",
|
||||
"2026-01-14T17:00:00Z",
|
||||
"2026-01-15T17:00:00Z"
|
||||
],
|
||||
"prices": [8000.0, 8075.0, 8025.0],
|
||||
"startTime": "2026-01-13T17:00:00Z",
|
||||
"endTime": "2026-01-15T17:00:00Z"
|
||||
}
|
||||
}
|
||||
]
|
||||
22
tests/fixtures/msn_chart_bbca_3mo.json
vendored
22
tests/fixtures/msn_chart_bbca_3mo.json
vendored
|
|
@ -1,22 +0,0 @@
|
|||
[
|
||||
{
|
||||
"_p": "bn91jc",
|
||||
"chartType": "3M",
|
||||
"symbol": "BBCA",
|
||||
"series": {
|
||||
"timeStamps": [
|
||||
"2025-01-06T00:00:00Z",
|
||||
"2025-01-07T00:00:00Z",
|
||||
"2025-01-08T00:00:00Z",
|
||||
"2025-01-13T00:00:00Z",
|
||||
"2025-01-14T00:00:00Z",
|
||||
"2025-01-15T00:00:00Z"
|
||||
],
|
||||
"prices": [9875.0, 9880.0, 9895.0, 9910.0, 9925.0, 9940.0],
|
||||
"openPrices": [9800.0, 9850.0, 9870.0, 9890.0, 9905.0, 9920.0],
|
||||
"pricesHigh": [9900.0, 9905.0, 9910.0, 9930.0, 9940.0, 9950.0],
|
||||
"pricesLow": [9750.0, 9825.0, 9855.0, 9880.0, 9890.0, 9910.0],
|
||||
"volumes": [12300000.0, 11000000.0, 11300000.0, 12500000.0, 11800000.0, 12000000.0]
|
||||
}
|
||||
}
|
||||
]
|
||||
46
tests/fixtures/msn_earnings_bbca.json
vendored
46
tests/fixtures/msn_earnings_bbca.json
vendored
|
|
@ -1,46 +0,0 @@
|
|||
{
|
||||
"EpsLastYear": 1200.0,
|
||||
"RevenueLastYear": 100000000000.0,
|
||||
"Forecast": {
|
||||
"annual": {
|
||||
"2026": {
|
||||
"EpsForecast": 1300.0,
|
||||
"RevenueForecast": 110000000000.0,
|
||||
"EarningReleaseDate": "2026-03-15",
|
||||
"CiqFiscalPeriodType": "2026"
|
||||
}
|
||||
},
|
||||
"quarterly": {
|
||||
"Q12026": {
|
||||
"EpsForecast": 330.0,
|
||||
"RevenueForecast": 28000000000.0,
|
||||
"EarningReleaseDate": "2026-04-20",
|
||||
"CiqFiscalPeriodType": "Q12026"
|
||||
}
|
||||
}
|
||||
},
|
||||
"History": {
|
||||
"annual": {
|
||||
"2025": {
|
||||
"EpsActual": 1250.0,
|
||||
"EpsSurprise": 20.0,
|
||||
"EpsSurprisePercent": 1.6,
|
||||
"RevenueActual": 105000000000.0,
|
||||
"RevenueSurprise": 500000000.0,
|
||||
"EarningReleaseDate": "2025-03-15",
|
||||
"CiqFiscalPeriodType": "2025"
|
||||
}
|
||||
},
|
||||
"quarterly": {
|
||||
"Q42025": {
|
||||
"EpsActual": 320.0,
|
||||
"EpsSurprise": 5.0,
|
||||
"EpsSurprisePercent": 1.5,
|
||||
"RevenueActual": 27000000000.0,
|
||||
"RevenueSurprise": 200000000.0,
|
||||
"EarningReleaseDate": "2025-11-20",
|
||||
"CiqFiscalPeriodType": "Q42025"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
tests/fixtures/msn_financials_bbca.json
vendored
40
tests/fixtures/msn_financials_bbca.json
vendored
|
|
@ -1,40 +0,0 @@
|
|||
[
|
||||
{
|
||||
"underlyingInstrument": {
|
||||
"instrumentId": "bn91jc",
|
||||
"displayName": "Bank Central Asia Tbk PT",
|
||||
"shortName": "BBCA",
|
||||
"symbol": "BBCA.JK"
|
||||
},
|
||||
"balanceSheets": {
|
||||
"currency": "IDR",
|
||||
"reportDate": "2025-12-31",
|
||||
"endDate": "2025-12-31",
|
||||
"currentAssets": {
|
||||
"cashAndShortTermInvestments": 500000000
|
||||
},
|
||||
"equity": {
|
||||
"totalEquity": 900000000
|
||||
}
|
||||
},
|
||||
"cashFlow": {
|
||||
"currency": "IDR",
|
||||
"reportDate": "2025-12-31",
|
||||
"endDate": "2025-12-31",
|
||||
"operating": {
|
||||
"operatingCashFlow": 600000000
|
||||
}
|
||||
},
|
||||
"incomeStatement": {
|
||||
"currency": "IDR",
|
||||
"reportDate": "2025-12-31",
|
||||
"endDate": "2025-12-31",
|
||||
"revenue": {
|
||||
"totalRevenue": 1000000000
|
||||
},
|
||||
"income": {
|
||||
"netIncome": 400000000
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
39
tests/fixtures/msn_insights_bbca.json
vendored
39
tests/fixtures/msn_insights_bbca.json
vendored
|
|
@ -1,39 +0,0 @@
|
|||
[
|
||||
{
|
||||
"instrumentId": "bn91jc",
|
||||
"displayName": "Bank Central Asia Tbk PT",
|
||||
"timeLastUpdated": "2026-03-26T04:14:57.9197955Z",
|
||||
"insights": [
|
||||
{
|
||||
"insightName": "P/E ratio",
|
||||
"category": "Valuation",
|
||||
"insightStatement": "Unable to compare with peers due to missing earnings data",
|
||||
"shortInsightStatement": "Earnings data unavailable, can't compare P/E ratio with peers",
|
||||
"details": {
|
||||
"evaluationStatus": "NA"
|
||||
},
|
||||
"timeLastUpdated": "0001-01-01T00:00:00"
|
||||
},
|
||||
{
|
||||
"insightName": "Analyst price target",
|
||||
"category": "Valuation",
|
||||
"insightStatement": "BBCA target price is more than 20% higher than the current share price based on analyst forecast",
|
||||
"shortInsightStatement": "Analysts forecast more than 20% upside for 12-month price target",
|
||||
"details": {
|
||||
"evaluationStatus": "good"
|
||||
},
|
||||
"timeLastUpdated": "0001-01-01T00:00:00"
|
||||
},
|
||||
{
|
||||
"insightName": "Quarterly Revenue YoY Growth",
|
||||
"category": "Earnings",
|
||||
"insightStatement": "BBCA revenue declined by 6.09% YoY, which is 31.46% worse than its peers (25.37%)",
|
||||
"shortInsightStatement": "Revenue grew worse than peers",
|
||||
"details": {
|
||||
"evaluationStatus": "bad"
|
||||
},
|
||||
"timeLastUpdated": "0001-01-01T00:00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
64
tests/fixtures/msn_keyratios_bbca.json
vendored
64
tests/fixtures/msn_keyratios_bbca.json
vendored
|
|
@ -1,64 +0,0 @@
|
|||
[
|
||||
{
|
||||
"stockId": "bn91jc",
|
||||
"symbol": "BBCA",
|
||||
"displayName": "Bank Central Asia Tbk",
|
||||
"shortName": "Bank Central Asia",
|
||||
"industryMetrics": [
|
||||
{
|
||||
"year": "2025",
|
||||
"fiscalPeriodType": "FY",
|
||||
"revenueGrowthRate": 0.081,
|
||||
"earningsGrowthRate": 0.121,
|
||||
"netMargin": 0.324,
|
||||
"roe": 0.198,
|
||||
"returnOnAssetCurrent": 0.031,
|
||||
"debtToEquityRatio": 0.42,
|
||||
"currentRatio": 1.18,
|
||||
"priceToEarningsRatio": 25.4,
|
||||
"priceToBookRatio": 4.6
|
||||
},
|
||||
{
|
||||
"year": "2024",
|
||||
"fiscalPeriodType": "FY",
|
||||
"revenueGrowthRate": 0.073,
|
||||
"earningsGrowthRate": 0.102,
|
||||
"netMargin": 0.311,
|
||||
"roe": 0.187,
|
||||
"returnOnAssetCurrent": 0.029,
|
||||
"debtToEquityRatio": 0.45,
|
||||
"currentRatio": 1.14,
|
||||
"priceToEarningsRatio": 24.1,
|
||||
"priceToBookRatio": 4.2
|
||||
}
|
||||
],
|
||||
"companyMetrics": [
|
||||
{
|
||||
"year": "2025",
|
||||
"fiscalPeriodType": "FY",
|
||||
"revenueGrowthRate": 0.081,
|
||||
"earningsGrowthRate": 0.121,
|
||||
"netMargin": 0.324,
|
||||
"roe": 0.198,
|
||||
"returnOnAssetCurrent": 0.031,
|
||||
"debtToEquityRatio": 0.42,
|
||||
"currentRatio": 1.18,
|
||||
"priceToEarningsRatio": 25.4,
|
||||
"priceToBookRatio": 4.6
|
||||
},
|
||||
{
|
||||
"year": "2024",
|
||||
"fiscalPeriodType": "FY",
|
||||
"revenueGrowthRate": 0.073,
|
||||
"earningsGrowthRate": 0.102,
|
||||
"netMargin": 0.311,
|
||||
"roe": 0.187,
|
||||
"returnOnAssetCurrent": 0.029,
|
||||
"debtToEquityRatio": 0.45,
|
||||
"currentRatio": 1.14,
|
||||
"priceToEarningsRatio": 24.1,
|
||||
"priceToBookRatio": 4.2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
20
tests/fixtures/msn_keyratios_industry_only.json
vendored
20
tests/fixtures/msn_keyratios_industry_only.json
vendored
|
|
@ -1,20 +0,0 @@
|
|||
[
|
||||
{
|
||||
"industryMetrics": [
|
||||
{
|
||||
"year": "2025",
|
||||
"fiscalPeriodType": "TTM",
|
||||
"priceToEarningsRatio": 12.5,
|
||||
"forwardPriceToEPS": 11.8,
|
||||
"priceToBookRatio": 1.7,
|
||||
"roe": 18.4,
|
||||
"profitMargin": 22.1,
|
||||
"revenueGrowthRate": 9.4,
|
||||
"earningsGrowthRate": 8.1,
|
||||
"debtToEquityRatio": 0.4,
|
||||
"currentRatio": 1.3
|
||||
}
|
||||
],
|
||||
"companyMetrics": []
|
||||
}
|
||||
]
|
||||
19
tests/fixtures/msn_keyratios_infinity.json
vendored
19
tests/fixtures/msn_keyratios_infinity.json
vendored
|
|
@ -1,19 +0,0 @@
|
|||
[
|
||||
{
|
||||
"companyMetrics": [
|
||||
{
|
||||
"year": "2025",
|
||||
"fiscalPeriodType": "TTM",
|
||||
"revenueGrowthRate": 8.1,
|
||||
"earningsGrowthRate": 12.1,
|
||||
"priceToEarningsRatio": "Infinity",
|
||||
"priceToBookRatio": 4.6,
|
||||
"roe": 19.8,
|
||||
"profitMargin": 44.2,
|
||||
"debtToEquityRatio": 0.75,
|
||||
"currentRatio": 1.4,
|
||||
"roaTTM": 3.79
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
[
|
||||
{
|
||||
"companyMetrics": [
|
||||
{
|
||||
"year": "2025",
|
||||
"fiscalPeriodType": "TTM",
|
||||
"revenueGrowthRate": 8.1,
|
||||
"earningsGrowthRate": 12.1,
|
||||
"priceToEarningsRatio": "-Infinity",
|
||||
"priceToBookRatio": 4.6,
|
||||
"roe": 19.8,
|
||||
"profitMargin": 44.2,
|
||||
"debtToEquityRatio": "-Infinity",
|
||||
"currentRatio": 1.4,
|
||||
"roaTTM": 3.79
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
15
tests/fixtures/msn_news_bbca.json
vendored
15
tests/fixtures/msn_news_bbca.json
vendored
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"value": [
|
||||
{
|
||||
"id": "news-1",
|
||||
"title": "BCA reports steady growth",
|
||||
"url": "https://example.com/news/bca-growth",
|
||||
"abstract": "BCA delivered steady quarterly growth across lending and deposits.",
|
||||
"provider": {
|
||||
"name": "Contoso News"
|
||||
},
|
||||
"publishedDateTime": "2026-03-20T10:00:00Z",
|
||||
"readTimeMin": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
37
tests/fixtures/msn_profile_bbca.json
vendored
37
tests/fixtures/msn_profile_bbca.json
vendored
|
|
@ -1,37 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": "feee16af-c94c-465d-a59d-a9727c22bd0e",
|
||||
"symbol": "BBCA",
|
||||
"shortName": "Bank Cntrl Asia",
|
||||
"displayName": "Bank Central Asia Tbk PT",
|
||||
"country": "ID",
|
||||
"company": {
|
||||
"address": {
|
||||
"street": "Menara BCA, Grand, Jl. MH Thamrin No. 1",
|
||||
"city": "JAKARTA PUSAT",
|
||||
"country": "Indonesia",
|
||||
"phone": "+62 21 23588000"
|
||||
},
|
||||
"description": "PT Bank Central Asia Tbk (the Bank) is an Indonesia-based commercial bank.",
|
||||
"employees": 27937,
|
||||
"industry": "Banking Services",
|
||||
"sector": "Financials",
|
||||
"website": "https://www.bca.co.id/"
|
||||
},
|
||||
"localizedAttributes": {
|
||||
"en-us": {
|
||||
"displayName": "PT Bank Central Asia Tbk",
|
||||
"description": "PT Bank Central Asia Tbk (the Bank) is an Indonesia-based commercial bank."
|
||||
}
|
||||
},
|
||||
"officers": [
|
||||
{
|
||||
"name": "Jahja Setiaatmadja",
|
||||
"title": "President Director",
|
||||
"age": 69,
|
||||
"yearBorn": 1955,
|
||||
"totalPay": 12000000000
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
18
tests/fixtures/msn_quote_bbca.json
vendored
18
tests/fixtures/msn_quote_bbca.json
vendored
|
|
@ -1,18 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": "bn91jc",
|
||||
"instrumentId": "bn91jc",
|
||||
"symbol": "BBCA",
|
||||
"shortName": "Bank Central Asia",
|
||||
"displayName": "Bank Central Asia Tbk",
|
||||
"price": 9875.0,
|
||||
"priceChange": 117.0,
|
||||
"priceChangePercent": 1.2,
|
||||
"pricePreviousClose": 9758.0,
|
||||
"price52wHigh": 10250.0,
|
||||
"price52wLow": 7800.0,
|
||||
"accumulatedVolume": 12300000.0,
|
||||
"averageVolume": 10000000.0,
|
||||
"marketCap": 1215200000000000.0
|
||||
}
|
||||
]
|
||||
31
tests/fixtures/msn_screener_id_topperfs.json
vendored
31
tests/fixtures/msn_screener_id_topperfs.json
vendored
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"count": 2,
|
||||
"quote": [
|
||||
{
|
||||
"symbol": "BBCA.XIDX",
|
||||
"shortName": "BBCA",
|
||||
"price": 9875,
|
||||
"priceChange": 117,
|
||||
"priceChangePercent": 1.2,
|
||||
"pricePreviousClose": 9758,
|
||||
"price52wHigh": 10500,
|
||||
"price52wLow": 8000,
|
||||
"accumulatedVolume": 12300000,
|
||||
"averageVolume": 10000000,
|
||||
"marketCap": 1215200000000000
|
||||
},
|
||||
{
|
||||
"symbol": "BBRI.XIDX",
|
||||
"shortName": "BBRI",
|
||||
"price": 5100,
|
||||
"priceChange": 210,
|
||||
"priceChangePercent": 4.3,
|
||||
"pricePreviousClose": 4890,
|
||||
"price52wHigh": 5400,
|
||||
"price52wLow": 3900,
|
||||
"accumulatedVolume": 22200000,
|
||||
"averageVolume": 18000000,
|
||||
"marketCap": 780000000000000
|
||||
}
|
||||
]
|
||||
}
|
||||
20
tests/fixtures/msn_sentiment_bbca.json
vendored
20
tests/fixtures/msn_sentiment_bbca.json
vendored
|
|
@ -1,20 +0,0 @@
|
|||
[
|
||||
{
|
||||
"symbol": "BBCA.JK",
|
||||
"displayName": "Bank Central Asia Tbk PT",
|
||||
"sentimentStatistics": [
|
||||
{
|
||||
"timeRangeName": "1D",
|
||||
"bullish": 10,
|
||||
"bearish": 2,
|
||||
"neutral": 3
|
||||
},
|
||||
{
|
||||
"timeRangeName": "1W",
|
||||
"bullish": 25,
|
||||
"bearish": 5,
|
||||
"neutral": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
82
tests/fixtures/quotesummary_bbca.json
vendored
82
tests/fixtures/quotesummary_bbca.json
vendored
|
|
@ -1,82 +0,0 @@
|
|||
{
|
||||
"quoteSummary": {
|
||||
"result": [
|
||||
{
|
||||
"defaultKeyStatistics": {
|
||||
"forwardPE": {
|
||||
"raw": 23.1,
|
||||
"fmt": "23.10"
|
||||
},
|
||||
"priceToBook": {
|
||||
"raw": 4.6,
|
||||
"fmt": "4.60"
|
||||
},
|
||||
"enterpriseValue": {
|
||||
"raw": 1245000000000000,
|
||||
"fmt": "1.25T"
|
||||
},
|
||||
"trailingEps": {
|
||||
"raw": 384.25,
|
||||
"fmt": "384.25"
|
||||
},
|
||||
"forwardEps": {
|
||||
"raw": 410.18,
|
||||
"fmt": "410.18"
|
||||
}
|
||||
},
|
||||
"financialData": {
|
||||
"trailingPE": {
|
||||
"raw": 25.4,
|
||||
"fmt": "25.40"
|
||||
},
|
||||
"marketCap": {
|
||||
"raw": 1215200000000000,
|
||||
"fmt": "1.22T"
|
||||
},
|
||||
"currentPrice": {
|
||||
"raw": 9875,
|
||||
"fmt": "9,875.00"
|
||||
},
|
||||
"returnOnEquity": {
|
||||
"raw": 0.202,
|
||||
"fmt": "20.20%"
|
||||
},
|
||||
"returnOnAssets": {
|
||||
"raw": 0.038,
|
||||
"fmt": "3.80%"
|
||||
},
|
||||
"profitMargins": {
|
||||
"raw": 0.385,
|
||||
"fmt": "38.50%"
|
||||
},
|
||||
"revenueGrowth": {
|
||||
"raw": 0.118,
|
||||
"fmt": "11.80%"
|
||||
},
|
||||
"earningsGrowth": {
|
||||
"raw": 0.121,
|
||||
"fmt": "12.10%"
|
||||
},
|
||||
"debtToEquity": {
|
||||
"raw": 18.5,
|
||||
"fmt": "18.50"
|
||||
},
|
||||
"currentRatio": {
|
||||
"raw": 1.21,
|
||||
"fmt": "1.21"
|
||||
},
|
||||
"ebitda": {
|
||||
"raw": 58500000000000,
|
||||
"fmt": "58.50B"
|
||||
},
|
||||
"totalRevenue": {
|
||||
"raw": 147900000000000,
|
||||
"fmt": "147.90B"
|
||||
}
|
||||
},
|
||||
"incomeStatementHistory": {}
|
||||
}
|
||||
],
|
||||
"error": null
|
||||
}
|
||||
}
|
||||
231
tests/golden.rs
231
tests/golden.rs
|
|
@ -1,231 +0,0 @@
|
|||
//! Golden output tests: byte-for-byte parity of CLI stdout, stderr, and exit
|
||||
//! code for every shipped command (see "Parity and Verification" in
|
||||
//! docs/DESIGN.md).
|
||||
//!
|
||||
//! Cases live in `tests/golden/cases.toml`; expected output in
|
||||
//! `tests/golden/<case>.golden`. Regenerate only for an intentional, reviewed
|
||||
//! output change, and commit the diff with the reason:
|
||||
//!
|
||||
//! UPDATE_GOLDEN=1 cargo test --test golden
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
const IDX: &str = env!("CARGO_BIN_EXE_idx");
|
||||
const REPO: &str = env!("CARGO_MANIFEST_DIR");
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CaseFile {
|
||||
case: Vec<Case>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Case {
|
||||
name: String,
|
||||
args: Vec<String>,
|
||||
/// Output formats to expand the case into (`-o <format>` is prepended and
|
||||
/// `.<format>` appended to the name). Empty means run the args as given.
|
||||
#[serde(default = "default_formats")]
|
||||
formats: Vec<String>,
|
||||
#[serde(default)]
|
||||
env: BTreeMap<String, String>,
|
||||
/// Seed the fixture ownership DB before running.
|
||||
#[serde(default)]
|
||||
ownership: bool,
|
||||
/// Commands run first in the same environment; their output is ignored.
|
||||
#[serde(default)]
|
||||
before: Vec<Vec<String>>,
|
||||
/// Text piped to the command's stdin.
|
||||
#[serde(default)]
|
||||
stdin: Option<String>,
|
||||
}
|
||||
|
||||
fn default_formats() -> Vec<String> {
|
||||
vec!["table".into(), "json".into()]
|
||||
}
|
||||
|
||||
fn golden_dir() -> PathBuf {
|
||||
Path::new(REPO).join("tests").join("golden")
|
||||
}
|
||||
|
||||
fn work_dir() -> PathBuf {
|
||||
std::env::temp_dir().join(format!("idx-golden-{}", std::process::id()))
|
||||
}
|
||||
|
||||
/// Runs idx with an isolated home under `root` and only the given IDX_* env.
|
||||
fn idx(root: &Path, args: &[String], env: &BTreeMap<String, String>) -> std::process::Output {
|
||||
idx_with_stdin(root, args, env, None)
|
||||
}
|
||||
|
||||
fn idx_with_stdin(
|
||||
root: &Path,
|
||||
args: &[String],
|
||||
env: &BTreeMap<String, String>,
|
||||
stdin: Option<&str>,
|
||||
) -> std::process::Output {
|
||||
let mut cmd = Command::new(IDX);
|
||||
cmd.current_dir(REPO).args(args);
|
||||
for (key, _) in std::env::vars_os() {
|
||||
if key.to_string_lossy().starts_with("IDX_") || key == "NO_COLOR" {
|
||||
cmd.env_remove(key);
|
||||
}
|
||||
}
|
||||
cmd.env("HOME", root)
|
||||
.env("XDG_CONFIG_HOME", root.join("config"))
|
||||
.env("XDG_CACHE_HOME", root.join("cache"))
|
||||
.env("XDG_DATA_HOME", root.join("data"))
|
||||
.env("IDX_USE_MOCK_PROVIDER", "1")
|
||||
.envs(env)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
let mut child = cmd.spawn().expect("spawn idx");
|
||||
let mut pipe = child.stdin.take().expect("stdin pipe");
|
||||
if let Some(input) = stdin {
|
||||
pipe.write_all(input.as_bytes()).expect("write stdin");
|
||||
}
|
||||
drop(pipe);
|
||||
child.wait_with_output().expect("run idx")
|
||||
}
|
||||
|
||||
/// Fixture ownership DB: the above-1% XLSX (2026-08-31) plus two KSEI archive
|
||||
/// months (2026-01-30, 2026-02-27), with wall-clock columns pinned.
|
||||
fn seeded_ownership_db() -> &'static Path {
|
||||
static DB: OnceLock<PathBuf> = OnceLock::new();
|
||||
DB.get_or_init(|| {
|
||||
let root = work_dir().join("seed");
|
||||
let _ = fs::remove_dir_all(&root);
|
||||
fs::create_dir_all(&root).expect("create seed dir");
|
||||
// The importer derives the release from the IDX file name.
|
||||
let xlsx = root.join("peng-2026-08-00017-satu-persen.xlsx");
|
||||
fs::copy(
|
||||
Path::new(REPO).join("tests/fixtures/ksei_above1_20260831_excerpt.xlsx"),
|
||||
&xlsx,
|
||||
)
|
||||
.expect("copy xlsx fixture");
|
||||
let inputs = [
|
||||
xlsx,
|
||||
Path::new(REPO).join("tests/fixtures/ksei_balancepos_20260130_excerpt.txt"),
|
||||
Path::new(REPO).join("tests/fixtures/ksei_balancepos_20260227_excerpt.txt"),
|
||||
];
|
||||
for input in inputs {
|
||||
let args = ["ownership", "import", "--file", input.to_str().unwrap()]
|
||||
.map(String::from)
|
||||
.to_vec();
|
||||
let out = idx(&root, &args, &BTreeMap::new());
|
||||
assert!(out.status.success(), "seed import failed: {out:?}");
|
||||
}
|
||||
let db = root.join("data/idx/ownership.db");
|
||||
let conn = rusqlite::Connection::open(&db).expect("open seed db");
|
||||
conn.execute_batch(
|
||||
"UPDATE ownership_releases SET imported_at = 0;
|
||||
UPDATE entities SET created_at = 0, updated_at = 0;
|
||||
UPDATE bing_holdings SET fetched_at = 0;",
|
||||
)
|
||||
.expect("pin timestamps");
|
||||
db
|
||||
})
|
||||
}
|
||||
|
||||
fn render(root: &Path, out: &std::process::Output) -> String {
|
||||
let normalize = |bytes: &[u8]| {
|
||||
String::from_utf8_lossy(bytes)
|
||||
.replace(root.to_str().unwrap(), "<ROOT>")
|
||||
.replace(REPO, "<REPO>")
|
||||
};
|
||||
format!(
|
||||
"exit: {}\n--- stdout\n{}--- stderr\n{}",
|
||||
out.status.code().map_or("signal".into(), |c| c.to_string()),
|
||||
normalize(&out.stdout),
|
||||
normalize(&out.stderr),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cli_output_matches_golden_files() {
|
||||
let raw = fs::read_to_string(golden_dir().join("cases.toml")).expect("read cases.toml");
|
||||
let cases: CaseFile = toml::from_str(&raw).expect("parse cases.toml");
|
||||
let update = std::env::var_os("UPDATE_GOLDEN").is_some();
|
||||
let mut seen = BTreeSet::new();
|
||||
let mut failures = Vec::new();
|
||||
|
||||
for case in &cases.case {
|
||||
let runs: Vec<(String, Vec<String>)> = if case.formats.is_empty() {
|
||||
vec![(case.name.clone(), case.args.clone())]
|
||||
} else {
|
||||
case.formats
|
||||
.iter()
|
||||
.map(|format| {
|
||||
let mut args = vec!["-o".to_string(), format.clone()];
|
||||
args.extend(case.args.iter().cloned());
|
||||
(format!("{}.{format}", case.name), args)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
for (name, args) in runs {
|
||||
assert!(seen.insert(name.clone()), "duplicate golden case {name}");
|
||||
let root = work_dir().join(&name);
|
||||
let _ = fs::remove_dir_all(&root);
|
||||
fs::create_dir_all(&root).expect("create case dir");
|
||||
if case.ownership {
|
||||
let target = root.join("data/idx/ownership.db");
|
||||
fs::create_dir_all(target.parent().unwrap()).expect("create data dir");
|
||||
fs::copy(seeded_ownership_db(), &target).expect("copy seeded db");
|
||||
}
|
||||
for before in &case.before {
|
||||
idx(&root, before, &case.env);
|
||||
}
|
||||
|
||||
let output = idx_with_stdin(&root, &args, &case.env, case.stdin.as_deref());
|
||||
let actual = render(&root, &output);
|
||||
let path = golden_dir().join(format!("{name}.golden"));
|
||||
if update {
|
||||
fs::write(&path, &actual).expect("write golden");
|
||||
} else {
|
||||
match fs::read_to_string(&path) {
|
||||
Ok(expected) if expected == actual => {}
|
||||
Ok(expected) => failures.push(format!(
|
||||
"{name}: output differs\n--- expected\n{expected}\n--- actual\n{actual}"
|
||||
)),
|
||||
Err(_) => failures.push(format!("{name}: missing {}", path.display())),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for entry in fs::read_dir(golden_dir()).expect("read golden dir") {
|
||||
let path = entry.expect("dir entry").path();
|
||||
let Some(stem) = path
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.strip_suffix(".golden")
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if !seen.contains(stem) {
|
||||
if update {
|
||||
fs::remove_file(&path).expect("remove orphan golden");
|
||||
} else {
|
||||
failures.push(format!("{stem}: golden file has no case in cases.toml"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = fs::remove_dir_all(work_dir());
|
||||
assert!(
|
||||
failures.is_empty(),
|
||||
"{} golden mismatch(es); if the change is intentional, rerun with UPDATE_GOLDEN=1 \
|
||||
and commit the diff with the reason\n\n{}",
|
||||
failures.len(),
|
||||
failures.join("\n\n")
|
||||
);
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
┌─────────┬───────┬──────┬────────┬────────────┬───────────────────────┬────────────┐
|
||||
│ SYMBOL ┆ PRICE ┆ CHG ┆ CHG% ┆ VOLUME ┆ MKT CAP ┆ 52W RANGE │
|
||||
╞═════════╪═══════╪══════╪════════╪════════════╪═══════════════════════╪════════════╡
|
||||
│ BBCA.JK ┆ 9,875 ┆ +117 ┆ +1.20% ┆ 12,300,000 ┆ 1,215,200,000,000,000 ┆ ████████░░ │
|
||||
└─────────┴───────┴──────┴────────┴────────────┴───────────────────────┴────────────┘
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
[{"symbol":"BBCA.JK","price":9875,"change":117,"change_pct":1.2,"volume":12300000,"market_cap":1215200000000000,"week52_high":10250,"week52_low":7800,"week52_position":0.8469387755102041,"range_signal":"upper","prev_close":9758,"avg_volume":10000000,"as_of":null},{"symbol":"BBRI.JK","price":9875,"change":117,"change_pct":1.2,"volume":12300000,"market_cap":1215200000000000,"week52_high":10250,"week52_low":7800,"week52_position":0.8469387755102041,"range_signal":"upper","prev_close":9758,"avg_volume":10000000,"as_of":null}]
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
{"failed":[],"removed":0}
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
cleared 0 files
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
{"files":0,"newest":null,"oldest":null,"path":"<ROOT>/cache/idx","size_bytes":0}
|
||||
--- stderr
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
path: <ROOT>/cache/idx
|
||||
files: 0
|
||||
size_bytes: 0
|
||||
oldest: -
|
||||
newest: -
|
||||
--- stderr
|
||||
|
|
@ -1,382 +0,0 @@
|
|||
# Golden output cases for tests/golden.rs.
|
||||
#
|
||||
# Each case runs once per entry in `formats` (default: table and json) with
|
||||
# `-o <format>` prepended; `formats = []` runs the args as given, which means
|
||||
# the auto format: stdout is a pipe here, so auto resolves to compact JSON.
|
||||
# Every run uses the mock provider (IDX_USE_MOCK_PROVIDER=1) and an isolated
|
||||
# home directory. `ownership = true` seeds the fixture DB; `before` runs setup
|
||||
# commands first; `stdin` is piped to the command.
|
||||
#
|
||||
# `idx version` is excluded on purpose: its output changes with every release.
|
||||
|
||||
# --- help and shell completions ---------------------------------------------
|
||||
|
||||
[[case]]
|
||||
name = "help-root"
|
||||
args = ["--help"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "help-stocks"
|
||||
args = ["stocks", "--help"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "help-ownership"
|
||||
args = ["ownership", "--help"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "help-config"
|
||||
args = ["config", "--help"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "help-cache"
|
||||
args = ["cache", "--help"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "completions-bash"
|
||||
args = ["completions", "bash"]
|
||||
formats = []
|
||||
|
||||
# --- config and cache ---------------------------------------------------------
|
||||
|
||||
[[case]]
|
||||
name = "config-path"
|
||||
args = ["config", "path"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "config-init"
|
||||
args = ["config", "init"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "config-get"
|
||||
args = ["config", "get", "general.provider"]
|
||||
formats = []
|
||||
before = [["config", "init"]]
|
||||
|
||||
[[case]]
|
||||
name = "config-set"
|
||||
args = ["config", "set", "general.provider", "yahoo"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "config-set-output-jsonl"
|
||||
args = ["config", "set", "general.output", "jsonl"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "config-set-output-invalid"
|
||||
args = ["config", "set", "general.output", "yaml"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "config-output-table-pins-format"
|
||||
args = ["stocks", "quote", "BBCA"]
|
||||
formats = []
|
||||
before = [["config", "set", "general.output", "table"]]
|
||||
|
||||
[[case]]
|
||||
name = "cache-info-empty"
|
||||
args = ["cache", "info"]
|
||||
|
||||
[[case]]
|
||||
name = "cache-clear"
|
||||
args = ["cache", "clear"]
|
||||
|
||||
# --- stocks: MSN (default provider) --------------------------------------------
|
||||
|
||||
[[case]]
|
||||
name = "stocks-quote"
|
||||
args = ["stocks", "quote", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-quote-multi"
|
||||
formats = ["table", "json", "jsonl"]
|
||||
args = ["stocks", "quote", "BBCA,BBRI"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-history"
|
||||
formats = ["table", "json", "jsonl"]
|
||||
args = ["stocks", "history", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-history-msn"
|
||||
args = ["stocks", "history", "BBCA", "--history-provider", "msn"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-technical"
|
||||
args = ["stocks", "technical", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-growth"
|
||||
args = ["stocks", "growth", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-valuation"
|
||||
args = ["stocks", "valuation", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-valuation-nonfinite"
|
||||
args = ["stocks", "valuation", "BBCA"]
|
||||
env = { IDX_MOCK_MSN_KEYRATIOS_FIXTURE = "tests/fixtures/msn_keyratios_infinity.json" }
|
||||
|
||||
[[case]]
|
||||
name = "stocks-risk"
|
||||
args = ["stocks", "risk", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-fundamental"
|
||||
formats = ["table", "json", "jsonl"]
|
||||
args = ["stocks", "fundamental", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-compare"
|
||||
args = ["stocks", "compare", "BBCA", "BBRI"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-profile"
|
||||
args = ["stocks", "profile", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-financials"
|
||||
args = ["stocks", "financials", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-financials-income"
|
||||
args = ["stocks", "financials", "BBCA", "--statement", "income"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-earnings"
|
||||
args = ["stocks", "earnings", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-earnings-history-quarterly"
|
||||
args = ["stocks", "earnings", "BBCA", "--history", "--quarterly"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-earnings-forecast-annual"
|
||||
args = ["stocks", "earnings", "BBCA", "--forecast", "--annual"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-sentiment"
|
||||
args = ["stocks", "sentiment", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-insights"
|
||||
args = ["stocks", "insights", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-news"
|
||||
args = ["stocks", "news", "BBCA", "--limit", "5"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-screen"
|
||||
args = ["stocks", "screen"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-screen-worst"
|
||||
args = ["stocks", "screen", "--filter", "worst-performers", "--limit", "5"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-screen-high-volume"
|
||||
args = ["stocks", "screen", "--filter", "high-volume"]
|
||||
|
||||
[[case]]
|
||||
name = "stocks-screen-large-cap"
|
||||
args = ["stocks", "screen", "--filter", "large-cap"]
|
||||
|
||||
[[case]]
|
||||
name = "auto-format-piped"
|
||||
args = ["stocks", "quote", "BBCA,BBRI"]
|
||||
formats = []
|
||||
|
||||
[[case]]
|
||||
name = "auto-format-env-table"
|
||||
args = ["stocks", "quote", "BBCA"]
|
||||
formats = []
|
||||
env = { IDX_OUTPUT = "table" }
|
||||
|
||||
[[case]]
|
||||
name = "stocks-quote-stdin"
|
||||
args = ["stocks", "quote", "-"]
|
||||
stdin = "BBCA\nBBRI\n"
|
||||
|
||||
[[case]]
|
||||
name = "stocks-compare-stdin"
|
||||
args = ["stocks", "compare", "-"]
|
||||
stdin = "BBCA, BBRI"
|
||||
|
||||
[[case]]
|
||||
name = "error-stdin-empty"
|
||||
args = ["stocks", "quote", "-"]
|
||||
stdin = ""
|
||||
|
||||
[[case]]
|
||||
name = "error-invalid-output-env"
|
||||
args = ["stocks", "quote", "BBCA"]
|
||||
formats = []
|
||||
env = { IDX_OUTPUT = "yaml" }
|
||||
|
||||
[[case]]
|
||||
name = "stocks-quote-offline-warm"
|
||||
args = ["--offline", "stocks", "quote", "BBCA"]
|
||||
before = [["stocks", "quote", "BBCA"]]
|
||||
|
||||
# --- stocks: Yahoo provider -----------------------------------------------------
|
||||
|
||||
[[case]]
|
||||
name = "yahoo-quote"
|
||||
args = ["stocks", "quote", "BBCA"]
|
||||
env = { IDX_PROVIDER = "yahoo" }
|
||||
|
||||
[[case]]
|
||||
name = "yahoo-history"
|
||||
args = ["stocks", "history", "BBCA"]
|
||||
env = { IDX_PROVIDER = "yahoo" }
|
||||
|
||||
[[case]]
|
||||
name = "yahoo-fundamental"
|
||||
args = ["stocks", "fundamental", "BBCA"]
|
||||
env = { IDX_PROVIDER = "yahoo" }
|
||||
|
||||
# --- errors ---------------------------------------------------------------------
|
||||
|
||||
[[case]]
|
||||
name = "error-usage-missing-symbol"
|
||||
args = ["stocks", "quote"]
|
||||
|
||||
[[case]]
|
||||
name = "error-invalid-provider"
|
||||
args = ["stocks", "quote", "BBCA"]
|
||||
env = { IDX_PROVIDER = "bogus" }
|
||||
|
||||
[[case]]
|
||||
name = "error-yahoo-profile-unsupported"
|
||||
args = ["stocks", "profile", "BBCA"]
|
||||
env = { IDX_PROVIDER = "yahoo" }
|
||||
|
||||
[[case]]
|
||||
name = "error-industry-only-fundamentals"
|
||||
args = ["stocks", "valuation", "BBCA"]
|
||||
env = { IDX_MOCK_MSN_KEYRATIOS_FIXTURE = "tests/fixtures/msn_keyratios_industry_only.json" }
|
||||
|
||||
[[case]]
|
||||
name = "error-screen-region"
|
||||
formats = ["table", "json", "jsonl"]
|
||||
args = ["stocks", "screen", "--region", "eu"]
|
||||
|
||||
[[case]]
|
||||
name = "error-offline-no-cache-flags"
|
||||
args = ["--offline", "--no-cache", "stocks", "quote", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "error-offline-cache-miss"
|
||||
args = ["--offline", "stocks", "quote", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "error-provider-failure"
|
||||
args = ["stocks", "quote", "BBCA"]
|
||||
env = { IDX_MOCK_ERROR = "1" }
|
||||
|
||||
[[case]]
|
||||
name = "error-compare-total-failure"
|
||||
args = ["stocks", "compare", "BBCA", "BBRI"]
|
||||
env = { IDX_MOCK_ERROR = "1" }
|
||||
|
||||
[[case]]
|
||||
name = "error-fetch-bing-unsupported"
|
||||
args = ["ownership", "import", "--fetch-bing", "BBCA"]
|
||||
|
||||
# --- ownership --------------------------------------------------------------------
|
||||
|
||||
[[case]]
|
||||
name = "ownership-releases-empty"
|
||||
args = ["ownership", "releases"]
|
||||
|
||||
[[case]]
|
||||
name = "ownership-ticker-empty"
|
||||
args = ["ownership", "ticker", "BBCA"]
|
||||
|
||||
[[case]]
|
||||
name = "ownership-import-xlsx"
|
||||
args = ["ownership", "import", "--file", "tests/fixtures/ksei_above1_20260831_excerpt.xlsx"]
|
||||
|
||||
[[case]]
|
||||
name = "ownership-import-archive-txt"
|
||||
args = ["ownership", "import", "--file", "tests/fixtures/ksei_balancepos_20260227_excerpt.txt"]
|
||||
|
||||
[[case]]
|
||||
name = "ownership-releases"
|
||||
args = ["ownership", "releases"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-ticker"
|
||||
args = ["ownership", "ticker", "BBCA"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-ticker-ksei"
|
||||
args = ["ownership", "ticker", "BBCA", "--source", "ksei"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-entity"
|
||||
args = ["ownership", "entity", "ANTHONI SALIM"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-search"
|
||||
args = ["ownership", "search", "salim"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-cross-holders"
|
||||
args = ["ownership", "cross-holders", "--min-tickers", "1"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-concentration"
|
||||
args = ["ownership", "concentration"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-flow"
|
||||
args = ["ownership", "flow", "BBCA"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-changes"
|
||||
formats = ["table", "json", "jsonl"]
|
||||
args = ["ownership", "changes", "--from", "2026-01-30", "--to", "2026-02-27"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-graph"
|
||||
args = ["ownership", "graph", "BBCA"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-graph-dot"
|
||||
args = ["ownership", "graph", "BBCA", "--format", "dot"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-resolve-unresolved"
|
||||
args = ["ownership", "resolve", "unresolved"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-resolve-map"
|
||||
args = ["ownership", "resolve", "map", "SALIM ANTHONI", "ANTHONI SALIM"]
|
||||
ownership = true
|
||||
|
||||
[[case]]
|
||||
name = "ownership-resolve-merge"
|
||||
args = ["ownership", "resolve", "merge", "1", "2"]
|
||||
ownership = true
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
msn
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
<ROOT>/config/idx/config.toml
|
||||
--- stderr
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
┌─────────┬───────┬──────┬────────┬────────────┬───────────────────────┬────────────┐
|
||||
│ SYMBOL ┆ PRICE ┆ CHG ┆ CHG% ┆ VOLUME ┆ MKT CAP ┆ 52W RANGE │
|
||||
╞═════════╪═══════╪══════╪════════╪════════════╪═══════════════════════╪════════════╡
|
||||
│ BBCA.JK ┆ 9,875 ┆ +117 ┆ +1.20% ┆ 12,300,000 ┆ 1,215,200,000,000,000 ┆ ████████░░ │
|
||||
└─────────┴───────┴──────┴────────┴────────────┴───────────────────────┴────────────┘
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
<ROOT>/config/idx/config.toml
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"INVALIDINPUT","error":true,"message":"invalid input: invalid output format 'yaml': expected 'auto', 'table', 'json', or 'jsonl'"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
ok
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
ok
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 4
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"PROVIDERUNAVAILABLE","error":true,"message":"provider unavailable"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 4
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: provider unavailable
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 5
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"UNSUPPORTED","error":true,"message":"unsupported: --fetch-bing import is not implemented yet"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 5
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: unsupported: --fetch-bing import is not implemented yet
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 1
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"PARSEERROR","error":true,"message":"parse error: unsupported: company fundamentals unavailable from MSN; industry fallback is disabled"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 1
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: parse error: unsupported: company fundamentals unavailable from MSN; industry fallback is disabled
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"CONFIGERROR","error":true,"message":"config error: invalid IDX_OUTPUT value: 'yaml', expected 'auto', 'table', 'json', or 'jsonl'"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"CONFIGERROR","error":true,"message":"config error: invalid provider 'bogus' (expected yahoo or msn)"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: config error: invalid provider 'bogus' (expected yahoo or msn)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 3
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"CACHEMISS","error":true,"message":"cache miss: msn-quote/BBCA.JK"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 3
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: cache miss: msn-quote/BBCA.JK
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"INVALIDINPUT","error":true,"message":"invalid input: cannot combine --offline with --no-cache"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: invalid input: cannot combine --offline with --no-cache
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 4
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"PROVIDERUNAVAILABLE","error":true,"message":"provider unavailable"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 4
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: provider unavailable
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"INVALIDINPUT","error":true,"message":"invalid input: invalid screener region 'eu' (expected one of: id, us, sg, hk, jp)"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"INVALIDINPUT","error":true,"message":"invalid input: invalid screener region 'eu' (expected one of: id, us, sg, hk, jp)"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: invalid input: invalid screener region 'eu' (expected one of: id, us, sg, hk, jp)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"INVALIDINPUT","error":true,"message":"invalid input: no symbols read from stdin"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: invalid input: no symbols read from stdin
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
error: the following required arguments were not provided:
|
||||
<SYMBOLS>...
|
||||
|
||||
Usage: idx stocks quote <SYMBOLS>...
|
||||
|
||||
For more information, try '--help'.
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
exit: 2
|
||||
--- stdout
|
||||
--- stderr
|
||||
error: the following required arguments were not provided:
|
||||
<SYMBOLS>...
|
||||
|
||||
Usage: idx stocks quote <SYMBOLS>...
|
||||
|
||||
For more information, try '--help'.
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 5
|
||||
--- stdout
|
||||
--- stderr
|
||||
{"code":"UNSUPPORTED","error":true,"message":"unsupported: BBCA.JK: command requires --provider msn"}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 5
|
||||
--- stdout
|
||||
--- stderr
|
||||
Error: unsupported: BBCA.JK: command requires --provider msn
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
Manage local cache
|
||||
|
||||
Usage: idx cache [OPTIONS] <COMMAND>
|
||||
|
||||
Commands:
|
||||
info Show cache usage information
|
||||
clear Clear all cached files
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-o, --output <OUTPUT> Output format [default: auto = table on a terminal, json when piped] [possible values: auto, table, json, jsonl]
|
||||
--no-color Disable colored output
|
||||
-q, --quiet Suppress non-essential output
|
||||
-v, --verbose... Increase verbosity (-v, -vv)
|
||||
--offline Run without network requests
|
||||
--no-cache Bypass local cache
|
||||
-h, --help Print help
|
||||
--- stderr
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
Manage configuration
|
||||
|
||||
Usage: idx config [OPTIONS] <COMMAND>
|
||||
|
||||
Commands:
|
||||
init Create default configuration file
|
||||
get Get a configuration value by key
|
||||
set Set a configuration value by key
|
||||
path Print configuration file path
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-o, --output <OUTPUT> Output format [default: auto = table on a terminal, json when piped] [possible values: auto, table, json, jsonl]
|
||||
--no-color Disable colored output
|
||||
-q, --quiet Suppress non-essential output
|
||||
-v, --verbose... Increase verbosity (-v, -vv)
|
||||
--offline Run without network requests
|
||||
--no-cache Bypass local cache
|
||||
-h, --help Print help
|
||||
--- stderr
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
Ownership intelligence (KSEI + Bing).
|
||||
|
||||
Preferred bootstrap path:
|
||||
1. Run `idx ownership sync` to install or refresh a maintained SQLite snapshot.
|
||||
2. If no snapshot manifest is available, run `idx ownership discover` and then `idx ownership import --url <pdf-url>`.
|
||||
3. Local `.xlsx`, `.pdf`, `.zip`, and `.txt` imports remain available for manual or fallback workflows.
|
||||
|
||||
Usage: idx ownership [OPTIONS] <COMMAND>
|
||||
|
||||
Commands:
|
||||
discover Discover the latest IDX-hosted ownership report URLs
|
||||
import Import ownership data directly from source files
|
||||
sync Install or refresh a maintained ownership SQLite snapshot
|
||||
ticker Show all holders for a ticker (KSEI + Bing combined)
|
||||
entity Show all holdings for an entity across tickers
|
||||
search Search entities by name
|
||||
cross-holders Rank entities by cross-ownership breadth
|
||||
concentration Rank tickers by ownership concentration
|
||||
flow Show Bing institutional flow for a ticker
|
||||
changes Diff two KSEI releases
|
||||
graph Ownership network graph
|
||||
resolve Manual entity resolution workflow
|
||||
releases List imported KSEI releases
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-o, --output <OUTPUT>
|
||||
Output format [default: auto = table on a terminal, json when piped]
|
||||
|
||||
[possible values: auto, table, json, jsonl]
|
||||
|
||||
--no-color
|
||||
Disable colored output
|
||||
|
||||
-q, --quiet
|
||||
Suppress non-essential output
|
||||
|
||||
-v, --verbose...
|
||||
Increase verbosity (-v, -vv)
|
||||
|
||||
--offline
|
||||
Run without network requests
|
||||
|
||||
--no-cache
|
||||
Bypass local cache
|
||||
|
||||
-h, --help
|
||||
Print help (see a summary with '-h')
|
||||
|
||||
Examples:
|
||||
idx ownership sync
|
||||
idx ownership sync --manifest /path/to/ownership-snapshot-manifest.json
|
||||
idx ownership discover --limit 1
|
||||
idx ownership import --url <pdf-url>
|
||||
idx ownership releases
|
||||
--- stderr
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
idx-cli is a Rust command-line tool for Indonesian stock market (IDX) analysis.
|
||||
It supports quote lookup, historical data, local caching, and output formats for both humans and AI agents.
|
||||
|
||||
Usage: idx [OPTIONS] <COMMAND>
|
||||
|
||||
Commands:
|
||||
stocks Stock data and analysis
|
||||
config Manage configuration
|
||||
cache Manage local cache
|
||||
ownership Ownership intelligence (bootstrap with `ownership sync`)
|
||||
completions Generate shell completions
|
||||
version Show idx-cli version
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-o, --output <OUTPUT>
|
||||
Output format [default: auto = table on a terminal, json when piped]
|
||||
|
||||
[possible values: auto, table, json, jsonl]
|
||||
|
||||
--no-color
|
||||
Disable colored output
|
||||
|
||||
-q, --quiet
|
||||
Suppress non-essential output
|
||||
|
||||
-v, --verbose...
|
||||
Increase verbosity (-v, -vv)
|
||||
|
||||
--offline
|
||||
Run without network requests
|
||||
|
||||
--no-cache
|
||||
Bypass local cache
|
||||
|
||||
-h, --help
|
||||
Print help (see a summary with '-h')
|
||||
--- stderr
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
Stock data and analysis
|
||||
|
||||
Usage: idx stocks [OPTIONS] <COMMAND>
|
||||
|
||||
Commands:
|
||||
quote Get real-time stock quotes
|
||||
history Get historical OHLC data
|
||||
technical Run technical analysis on a stock
|
||||
growth Run growth analysis on a stock
|
||||
valuation Run valuation analysis on a stock
|
||||
risk Run risk analysis on a stock
|
||||
fundamental Run full fundamental analysis on a stock
|
||||
profile Get company profile
|
||||
financials Get financial statements
|
||||
earnings Get earnings report
|
||||
sentiment Get crowd sentiment
|
||||
insights Get AI insights
|
||||
news Get stock news
|
||||
screen MSN screener
|
||||
compare Compare fundamentals across stocks
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-o, --output <OUTPUT> Output format [default: auto = table on a terminal, json when piped] [possible values: auto, table, json, jsonl]
|
||||
--no-color Disable colored output
|
||||
-q, --quiet Suppress non-essential output
|
||||
-v, --verbose... Increase verbosity (-v, -vv)
|
||||
--offline Run without network requests
|
||||
--no-cache Bypass local cache
|
||||
-h, --help Print help
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
[{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL ID","change_type":"decreased","old_bps":2400,"new_bps":2334,"delta_bps":-66},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL IS","change_type":"increased","old_bps":75,"new_bps":129,"delta_bps":54},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL MF","change_type":"increased","old_bps":117,"new_bps":152,"delta_bps":35},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN MF","change_type":"increased","old_bps":307,"new_bps":337,"delta_bps":30},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN OT","change_type":"decreased","old_bps":91,"new_bps":64,"delta_bps":-27},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN PF","change_type":"decreased","old_bps":76,"new_bps":56,"delta_bps":-20},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN CP","change_type":"increased","old_bps":72,"new_bps":86,"delta_bps":14},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL CP","change_type":"decreased","old_bps":6481,"new_bps":6467,"delta_bps":-14},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL SC","change_type":"decreased","old_bps":36,"new_bps":29,"delta_bps":-7},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN IB","change_type":"decreased","old_bps":267,"new_bps":263,"delta_bps":-4},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN SC","change_type":"increased","old_bps":51,"new_bps":55,"delta_bps":4},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL PF","change_type":"increased","old_bps":17,"new_bps":20,"delta_bps":3},{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN ID","change_type":"decreased","old_bps":3,"new_bps":2,"delta_bps":-1}]
|
||||
--- stderr
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL ID","change_type":"decreased","old_bps":2400,"new_bps":2334,"delta_bps":-66}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL IS","change_type":"increased","old_bps":75,"new_bps":129,"delta_bps":54}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL MF","change_type":"increased","old_bps":117,"new_bps":152,"delta_bps":35}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN MF","change_type":"increased","old_bps":307,"new_bps":337,"delta_bps":30}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN OT","change_type":"decreased","old_bps":91,"new_bps":64,"delta_bps":-27}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN PF","change_type":"decreased","old_bps":76,"new_bps":56,"delta_bps":-20}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN CP","change_type":"increased","old_bps":72,"new_bps":86,"delta_bps":14}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL CP","change_type":"decreased","old_bps":6481,"new_bps":6467,"delta_bps":-14}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL SC","change_type":"decreased","old_bps":36,"new_bps":29,"delta_bps":-7}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN IB","change_type":"decreased","old_bps":267,"new_bps":263,"delta_bps":-4}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN SC","change_type":"increased","old_bps":51,"new_bps":55,"delta_bps":4}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE LOCAL PF","change_type":"increased","old_bps":17,"new_bps":20,"delta_bps":3}
|
||||
{"ticker_code":"AADI","entity_name":"KSEI AGGREGATE FOREIGN ID","change_type":"decreased","old_bps":3,"new_bps":2,"delta_bps":-1}
|
||||
--- stderr
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
┌────────┬───────────────────────────┬───────────┬────────┬────────┬────────┐
|
||||
│ TICKER ┆ ENTITY ┆ CHANGE ┆ OLD% ┆ NEW% ┆ DELTA% │
|
||||
╞════════╪═══════════════════════════╪═══════════╪════════╪════════╪════════╡
|
||||
│ AADI ┆ KSEI AGGREGATE LOCAL ID ┆ DECREASED ┆ 24.00% ┆ 23.34% ┆ -0.66% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE LOCAL IS ┆ INCREASED ┆ 0.75% ┆ 1.29% ┆ +0.54% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE LOCAL MF ┆ INCREASED ┆ 1.17% ┆ 1.52% ┆ +0.35% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE FOREIGN MF ┆ INCREASED ┆ 3.07% ┆ 3.37% ┆ +0.30% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE FOREIGN OT ┆ DECREASED ┆ 0.91% ┆ 0.64% ┆ -0.27% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE FOREIGN PF ┆ DECREASED ┆ 0.76% ┆ 0.56% ┆ -0.20% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE FOREIGN CP ┆ INCREASED ┆ 0.72% ┆ 0.86% ┆ +0.14% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE LOCAL CP ┆ DECREASED ┆ 64.81% ┆ 64.67% ┆ -0.14% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE LOCAL SC ┆ DECREASED ┆ 0.36% ┆ 0.29% ┆ -0.07% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE FOREIGN IB ┆ DECREASED ┆ 2.67% ┆ 2.63% ┆ -0.04% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE FOREIGN SC ┆ INCREASED ┆ 0.51% ┆ 0.55% ┆ +0.04% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE LOCAL PF ┆ INCREASED ┆ 0.17% ┆ 0.20% ┆ +0.03% │
|
||||
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
|
||||
│ AADI ┆ KSEI AGGREGATE FOREIGN ID ┆ DECREASED ┆ 0.03% ┆ 0.02% ┆ -0.01% │
|
||||
└────────┴───────────────────────────┴───────────┴────────┴────────┴────────┘
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
[["AALI",{"top1_bps":7968,"top3_bps":7968,"hhi":6348,"free_float_bps":2032,"holder_count":1}],["BBCA",{"top1_bps":5494,"top3_bps":5716,"hhi":3021,"free_float_bps":4182,"holder_count":4}],["AADI",{"top1_bps":4110,"top3_bps":6230,"hhi":2009,"free_float_bps":2030,"holder_count":10}],["ABBA",{"top1_bps":283,"top3_bps":418,"hhi":9,"free_float_bps":9582,"holder_count":2}]]
|
||||
--- stderr
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
┌──────┬────────┬────────┬────────┬──────┬─────────────┬─────────┐
|
||||
│ RANK ┆ TICKER ┆ TOP1% ┆ TOP3% ┆ HHI ┆ FREE_FLOAT% ┆ HOLDERS │
|
||||
╞══════╪════════╪════════╪════════╪══════╪═════════════╪═════════╡
|
||||
│ 1 ┆ AALI ┆ 79.68% ┆ 79.68% ┆ 6348 ┆ 20.32% ┆ 1 │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
|
||||
│ 2 ┆ BBCA ┆ 54.94% ┆ 57.16% ┆ 3021 ┆ 41.82% ┆ 4 │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
|
||||
│ 3 ┆ AADI ┆ 41.10% ┆ 62.30% ┆ 2009 ┆ 20.30% ┆ 10 │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
|
||||
│ 4 ┆ ABBA ┆ 2.83% ┆ 4.18% ┆ 9 ┆ 95.82% ┆ 2 │
|
||||
└──────┴────────┴────────┴────────┴──────┴─────────────┴─────────┘
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
[{"entity":{"id":11,"canonical_name":"ASTRA INTERNATIONAL","entity_type":null,"country":null},"ticker_count":1,"total_bps":7968},{"entity":{"id":14,"canonical_name":"DWIMURIA INVESTAMA ANDALAN","entity_type":null,"country":null},"ticker_count":1,"total_bps":5494},{"entity":{"id":4,"canonical_name":"ADARO STRATEGIC INVESTMENTS","entity_type":null,"country":null},"ticker_count":1,"total_bps":4110},{"entity":{"id":5,"canonical_name":"ALAMTRI RESOURCES INDONESIA TBK PT","entity_type":null,"country":null},"ticker_count":1,"total_bps":1537},{"entity":{"id":7,"canonical_name":"GARIBALDI THOHIR","entity_type":null,"country":null},"ticker_count":1,"total_bps":583},{"entity":{"id":2,"canonical_name":"SARATOGA INVESTAMA SEDAYA","entity_type":null,"country":null},"ticker_count":1,"total_bps":438},{"entity":{"id":9,"canonical_name":"EDWIN SOERYADJAYA","entity_type":null,"country":null},"ticker_count":1,"total_bps":352},{"entity":{"id":8,"canonical_name":"IR. T. PERMADI RACHMAT","entity_type":null,"country":null},"ticker_count":1,"total_bps":348},{"entity":{"id":13,"canonical_name":"YAYASAN ABDI BANGSA","entity_type":null,"country":null},"ticker_count":1,"total_bps":283},{"entity":{"id":10,"canonical_name":"SANDIAGA SALAHUDDIN UNO","entity_type":null,"country":null},"ticker_count":1,"total_bps":204},{"entity":{"id":1,"canonical_name":"PERSADA CAPITAL INVESTAMA","entity_type":null,"country":null},"ticker_count":1,"total_bps":154},{"entity":{"id":12,"canonical_name":"YAYASAN BINA SEJAHTERA WARGA BULOG","entity_type":null,"country":null},"ticker_count":1,"total_bps":135},{"entity":{"id":6,"canonical_name":"FTAG INVESTMENT BANK","entity_type":null,"country":null},"ticker_count":1,"total_bps":129},{"entity":{"id":17,"canonical_name":"ANTHONI SALIM","entity_type":null,"country":null},"ticker_count":1,"total_bps":115},{"entity":{"id":3,"canonical_name":"TRINUGRAHA THOHIR","entity_type":null,"country":null},"ticker_count":1,"total_bps":115},{"entity":{"id":16,"canonical_name":"TRICIPTA MANDHALA GUMILANG","entity_type":null,"country":null},"ticker_count":1,"total_bps":107},{"entity":{"id":15,"canonical_name":"CATURGUWIRATNA SUMAPALA","entity_type":null,"country":null},"ticker_count":1,"total_bps":102}]
|
||||
--- stderr
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
┌──────┬────────────────────────────────────┬─────────┬───────────┐
|
||||
│ RANK ┆ ENTITY ┆ TICKERS ┆ TOTAL_BPS │
|
||||
╞══════╪════════════════════════════════════╪═════════╪═══════════╡
|
||||
│ 1 ┆ ASTRA INTERNATIONAL ┆ 1 ┆ 79.68% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 2 ┆ DWIMURIA INVESTAMA ANDALAN ┆ 1 ┆ 54.94% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 3 ┆ ADARO STRATEGIC INVESTMENTS ┆ 1 ┆ 41.10% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 4 ┆ ALAMTRI RESOURCES INDONESIA TBK PT ┆ 1 ┆ 15.37% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 5 ┆ GARIBALDI THOHIR ┆ 1 ┆ 5.83% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 6 ┆ SARATOGA INVESTAMA SEDAYA ┆ 1 ┆ 4.38% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 7 ┆ EDWIN SOERYADJAYA ┆ 1 ┆ 3.52% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 8 ┆ IR. T. PERMADI RACHMAT ┆ 1 ┆ 3.48% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 9 ┆ YAYASAN ABDI BANGSA ┆ 1 ┆ 2.83% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 10 ┆ SANDIAGA SALAHUDDIN UNO ┆ 1 ┆ 2.04% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 11 ┆ PERSADA CAPITAL INVESTAMA ┆ 1 ┆ 1.54% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 12 ┆ YAYASAN BINA SEJAHTERA WARGA BULOG ┆ 1 ┆ 1.35% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 13 ┆ FTAG INVESTMENT BANK ┆ 1 ┆ 1.29% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 14 ┆ ANTHONI SALIM ┆ 1 ┆ 1.15% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 15 ┆ TRINUGRAHA THOHIR ┆ 1 ┆ 1.15% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 16 ┆ TRICIPTA MANDHALA GUMILANG ┆ 1 ┆ 1.07% │
|
||||
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┤
|
||||
│ 17 ┆ CATURGUWIRATNA SUMAPALA ┆ 1 ┆ 1.02% │
|
||||
└──────┴────────────────────────────────────┴─────────┴───────────┘
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
{"entity":{"id":17,"canonical_name":"ANTHONI SALIM","entity_type":null,"country":null},"ticker_count":1,"holdings":[{"ticker":{"id":4,"code":"BBCA","name":"BANK CENTRAL ASIA Tbk","sector":null},"source":"ksei","shares":1416306835,"percentage_bps":115,"report_date":"2026-08-31"}]}
|
||||
--- stderr
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
Entity: ANTHONI SALIM
|
||||
┌────────┬────────┬───────────────┬───────┬─────────────┐
|
||||
│ TICKER ┆ SOURCE ┆ SHARES ┆ % ┆ REPORT_DATE │
|
||||
╞════════╪════════╪═══════════════╪═══════╪═════════════╡
|
||||
│ BBCA ┆ KSEI ┆ 1,416,306,835 ┆ 1.15% ┆ 2026-08-31 │
|
||||
└────────┴────────┴───────────────┴───────┴─────────────┘
|
||||
Total tickers: 1
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
null
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
No institutional flow data available for BBCA.
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
{"nodes":[{"id":"entity:14","label":"DWIMURIA INVESTAMA ANDALAN","node_type":"entity"},{"id":"entity:15","label":"CATURGUWIRATNA SUMAPALA","node_type":"entity"},{"id":"entity:16","label":"TRICIPTA MANDHALA GUMILANG","node_type":"entity"},{"id":"entity:17","label":"ANTHONI SALIM","node_type":"entity"},{"id":"ticker:BBCA","label":"BBCA","node_type":"ticker"}],"edges":[{"from":"entity:17","to":"ticker:BBCA","percentage_bps":115,"source":"ksei"},{"from":"entity:15","to":"ticker:BBCA","percentage_bps":102,"source":"ksei"},{"from":"entity:14","to":"ticker:BBCA","percentage_bps":5494,"source":"ksei"},{"from":"entity:16","to":"ticker:BBCA","percentage_bps":107,"source":"ksei"}]}
|
||||
--- stderr
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
digraph ownership {
|
||||
rankdir=LR;
|
||||
graph [fontname="Helvetica"];
|
||||
node [fontname="Helvetica"];
|
||||
edge [fontname="Helvetica"];
|
||||
|
||||
"entity:14" [label="DWIMURIA INVESTAMA ANDALAN", shape=ellipse];
|
||||
"entity:15" [label="CATURGUWIRATNA SUMAPALA", shape=ellipse];
|
||||
"entity:16" [label="TRICIPTA MANDHALA GUMILANG", shape=ellipse];
|
||||
"entity:17" [label="ANTHONI SALIM", shape=ellipse];
|
||||
"ticker:BBCA" [label="BBCA", shape=box];
|
||||
|
||||
"entity:17" -> "ticker:BBCA" [label="1.15% (ksei)"];
|
||||
"entity:15" -> "ticker:BBCA" [label="1.02% (ksei)"];
|
||||
"entity:14" -> "ticker:BBCA" [label="54.94% (ksei)"];
|
||||
"entity:16" -> "ticker:BBCA" [label="1.07% (ksei)"];
|
||||
}
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
{"nodes":[{"id":"entity:14","label":"DWIMURIA INVESTAMA ANDALAN","node_type":"entity"},{"id":"entity:15","label":"CATURGUWIRATNA SUMAPALA","node_type":"entity"},{"id":"entity:16","label":"TRICIPTA MANDHALA GUMILANG","node_type":"entity"},{"id":"entity:17","label":"ANTHONI SALIM","node_type":"entity"},{"id":"ticker:BBCA","label":"BBCA","node_type":"ticker"}],"edges":[{"from":"entity:17","to":"ticker:BBCA","percentage_bps":115,"source":"ksei"},{"from":"entity:15","to":"ticker:BBCA","percentage_bps":102,"source":"ksei"},{"from":"entity:14","to":"ticker:BBCA","percentage_bps":5494,"source":"ksei"},{"from":"entity:16","to":"ticker:BBCA","percentage_bps":107,"source":"ksei"}]}
|
||||
--- stderr
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
nodes: 5 edges: 4
|
||||
|
||||
BBCA [TICKER]
|
||||
├─ DWIMURIA INVESTAMA ANDALAN (54.94%, ksei)
|
||||
├─ ANTHONI SALIM (1.15%, ksei)
|
||||
├─ TRICIPTA MANDHALA GUMILANG (1.07%, ksei)
|
||||
└─ CATURGUWIRATNA SUMAPALA (1.02%, ksei)
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
{"action":"imported","inserted_rows":18,"ticker_count":1,"as_of_date":"2026-02-27","sha256":"7b8da1d820f67062410c48988bb6c70fec2088c24961d481d1c0fce8b9372547","source_url":null}
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
Imported 18 rows for 1 tickers (as of 2026-02-27).
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
{"action":"imported","inserted_rows":17,"ticker_count":4,"as_of_date":"2026-08-31","sha256":"7c1a4c209b8ce5bde9112436a0c64d66b042915995b584d2bbf7ca7b15ce81e3","source_url":null}
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
Imported 17 rows for 4 tickers (as of 2026-08-31).
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
[]
|
||||
--- stderr
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
exit: 0
|
||||
--- stdout
|
||||
No ownership releases imported yet.
|
||||
--- stderr
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue