@@ -132,7 +132,7 @@ function outputFundLine(index: number, total: number, ticker: string, status: st
132132 field ( 'sec' , outputPercent ( data . secYield ?? data . yields ?. secYield ?? metrics . secYield ) ) ,
133133 field ( 'wp' , data . workplaceRaw ) ,
134134 ] . filter ( part => part !== '' ) . join ( ' ' ) ;
135- return `[ ${ String ( index ) . padStart ( width ) } /${ String ( total ) . padEnd ( width ) } ] ${ outputClean ( ticker ) . padEnd ( 5 ) } ${ status . padEnd ( 9 ) } ${ detail ? ` ${ detail } ` : '' } ${ reason ? ` reason=${ outputClean ( reason ) } ` : '' } ` ;
135+ return `[ ${ ` ${ String ( index ) . padStart ( width ) } /${ total } ` . padEnd ( 8 ) } ] ${ outputClean ( ticker ) . padEnd ( 5 ) } ${ status . padEnd ( 9 ) } ${ detail ? ` ${ detail } ` : '' } ${ reason ? ` reason=${ outputClean ( reason ) } ` : '' } ` ;
136136}
137137function outputCreateReporter ( root : URL | string , total : number ) {
138138 let completed = 0 ;
@@ -848,7 +848,7 @@ async function fetchCatalog(config: UpdaterConfig): Promise<{ funds: CatalogFund
848848 const { text, via } = await fetchWisdomTreePage ( WISDOMTREE_FUND_LIST_URL , WISDOMTREE_FUND_LIST_PROXY_URL , 'WisdomTree fund list' , config , looksLikeFundList , 'application/json' ) ;
849849 return { funds : parseFundListJson ( text ) , raw : text , rawName : 'fund-list' , source : `WisdomTree official fund list${ viaLabel ( via ) } ` } ;
850850 } catch ( error ) {
851- console . warn ( `[ ${ 'catalog' . padEnd ( 9 ) } ] ${ error instanceof Error ? error . message : String ( error ) } - trying the product table` ) ;
851+ console . warn ( `[ ${ 'catalog' . padEnd ( 8 ) } ] ${ error instanceof Error ? error . message : String ( error ) } - trying the product table` ) ;
852852 }
853853 const { text, via } = await fetchWisdomTreePage ( WISDOMTREE_CATALOG_URL , WISDOMTREE_CATALOG_PROXY_URL , 'WisdomTree product table' , config , looksLikeCatalog ) ;
854854 return { funds : parseCatalogMarkdown ( text ) , raw : text , rawName : 'product-table' , source : `WisdomTree official product table${ viaLabel ( via ) } ` } ;
@@ -1186,7 +1186,7 @@ export function resetSecState(): void {
11861186/** SEC's ticker -> registrant CIK + series id table, loaded once per run (a failed load is asked again by the next fund). */
11871187function loadFundTickerTable ( config : UpdaterConfig ) : Promise < Map < string , NportSeriesRef > > {
11881188 if ( ! secState . funds ) {
1189- const loading = fetchJson ( SEC_FUND_TICKERS_URL , '[edgar ] fund ticker table' , config , secHeaders ( ) ) . then ( ( payload ) => parseSecFundTickers ( payload ) ) ;
1189+ const loading = fetchJson ( SEC_FUND_TICKERS_URL , '[ edgar ] fund ticker table' , config , secHeaders ( ) ) . then ( ( payload ) => parseSecFundTickers ( payload ) ) ;
11901190 secState . funds = loading ;
11911191 loading . catch ( ( ) => { if ( secState . funds === loading ) secState . funds = null ; } ) ;
11921192 }
@@ -1196,7 +1196,7 @@ function loadFundTickerTable(config: UpdaterConfig): Promise<Map<string, NportSe
11961196/** SEC's company name -> ticker table (N-PORT rows and product-page top holdings), loaded once per run. */
11971197function loadCompanyNames ( config : UpdaterConfig ) : Promise < Map < string , string > > {
11981198 if ( ! secState . names ) {
1199- const loading = fetchJson ( SEC_COMPANY_TICKERS_URL , '[edgar ] company ticker table' , config , secHeaders ( ) ) . then ( ( payload ) => parseSecCompanyNames ( payload ) ) ;
1199+ const loading = fetchJson ( SEC_COMPANY_TICKERS_URL , '[ edgar ] company ticker table' , config , secHeaders ( ) ) . then ( ( payload ) => parseSecCompanyNames ( payload ) ) ;
12001200 secState . names = loading ;
12011201 loading . catch ( ( ) => { if ( secState . names === loading ) secState . names = null ; } ) ;
12021202 }
@@ -1692,7 +1692,7 @@ async function processFund(fund: CatalogFund, config: UpdaterConfig, previous: J
16921692 let productVia : 'direct' | 'proxy' | null = null ;
16931693 if ( ! config . skipWisdomTree && fund . fundPage ) {
16941694 try {
1695- const page = await fetchWisdomTreePage ( fund . fundPage , productProxyUrl ( fund . fundPage ) , `[product ] ${ fund . ticker } ` , config , looksLikeProductPage ) ;
1695+ const page = await fetchWisdomTreePage ( fund . fundPage , productProxyUrl ( fund . fundPage ) , `[ product ] ${ fund . ticker } ` , config , looksLikeProductPage ) ;
16961696 productPageMarkdown = page . text ;
16971697 productVia = page . via ;
16981698 productSummary = parseProductPageSummary ( productPageMarkdown ) ;
@@ -1707,7 +1707,7 @@ async function processFund(fund: CatalogFund, config: UpdaterConfig, previous: J
17071707 } catch ( error ) {
17081708 productPageMarkdown = null ;
17091709 productSummary = null ;
1710- outputNote ( `[ ${ 'product' . padEnd ( 9 ) } ] ${ fund . ticker } : ${ error instanceof Error ? error . message : String ( error ) } ` ) ;
1710+ outputNote ( `[ ${ 'product' . padEnd ( 8 ) } ] ${ fund . ticker } : ${ error instanceof Error ? error . message : String ( error ) } ` ) ;
17111711 }
17121712 }
17131713 const productFetched = productSummary !== null ;
@@ -1719,7 +1719,7 @@ async function processFund(fund: CatalogFund, config: UpdaterConfig, previous: J
17191719 const distributionsFailed = ! productFetched || ( partialPage && ! productSummary ! . sections . distributions ) ;
17201720 if ( partialPage ) {
17211721 const lacking = [ pricingFailed && 'NAV/price/premium' , returnsFailed && 'returns' , distributionsFailed && 'distributions' ] . filter ( Boolean ) . join ( ', ' ) ;
1722- outputNote ( `[ ${ 'kept' . padEnd ( 9 ) } ] ${ fund . ticker } : product page came back partial, kept the published ${ lacking } ` ) ;
1722+ outputNote ( `[ ${ 'kept' . padEnd ( 8 ) } ] ${ fund . ticker } : product page came back partial, kept the published ${ lacking } ` ) ;
17231723 }
17241724 if ( ! productFetched || ( partialPage && fund . secYield === null ) ) fund . secYield = fund . secYield ?? numberOrNull ( previous . metrics ?. secYield ) ;
17251725 fund . cusip = fund . cusip || String ( previous . cusip || '' ) ;
@@ -1742,11 +1742,11 @@ async function processFund(fund: CatalogFund, config: UpdaterConfig, previous: J
17421742 const published = { asOf : calendarIso ( previousMeta ?. holdings ?. asOfDate ) , rows : topList ? 0 : numberOrNull ( previousMeta ?. holdings ?. totalRows ) ?? 0 } ;
17431743 const ref = ( await loadFundTickerTable ( config ) ) . get ( fund . ticker ) ;
17441744 const read = ref
1745- ? await readNportHoldings ( { ticker : fund . ticker , cik : ref . cik , seriesId : ref . seriesId } , published , ( url , label ) => fetchText ( url , `[nport ] ${ label } ` , config , secHeaders ( ) ) , { cache : secState . reader } )
1745+ ? await readNportHoldings ( { ticker : fund . ticker , cik : ref . cik , seriesId : ref . seriesId } , published , ( url , label ) => fetchText ( url , `[ nport ] ${ label } ` , config , secHeaders ( ) ) , { cache : secState . reader } )
17461746 : { problem : `${ fund . ticker } : not in the SEC fund ticker table` } ;
1747- if ( 'problem' in read ) outputNote ( `[ ${ 'nport' . padEnd ( 9 ) } ] ${ read . problem } ` ) ;
1747+ if ( 'problem' in read ) outputNote ( `[ ${ 'nport' . padEnd ( 8 ) } ] ${ read . problem } ` ) ;
17481748 else {
1749- const sheet = nportHoldingsSheet ( read . filing , nportTickers ( read . filing . positions , await loadCompanyNames ( config ) . catch ( ( ) => null ) , await loadUsListings ( ( url , label ) => fetchText ( url , `[nport ] ${ label } ` , config , secHeaders ( ) ) ) ) ) ;
1749+ const sheet = nportHoldingsSheet ( read . filing , nportTickers ( read . filing . positions , await loadCompanyNames ( config ) . catch ( ( ) => null ) , await loadUsListings ( ( url , label ) => fetchText ( url , `[ nport ] ${ label } ` , config , secHeaders ( ) ) ) ) ) ;
17501750 holdingsRows = sheet . rows ;
17511751 holdingsHeaders = sheet . headers ;
17521752 holdingsFresh = true ;
@@ -1756,13 +1756,13 @@ async function processFund(fund: CatalogFund, config: UpdaterConfig, previous: J
17561756 holdingsSource = `SEC EDGAR Form N-PORT-P (accession ${ read . candidate . accession } , report period ${ read . filing . repPdDate || 'n/a' } )` ;
17571757 }
17581758 } catch ( error ) {
1759- outputNote ( `[ ${ 'nport' . padEnd ( 9 ) } ] ${ fund . ticker } : ${ error instanceof Error ? error . message : String ( error ) } ` ) ;
1759+ outputNote ( `[ ${ 'nport' . padEnd ( 8 ) } ] ${ fund . ticker } : ${ error instanceof Error ? error . message : String ( error ) } ` ) ;
17601760 }
17611761 }
17621762
17631763 if ( ! holdingsRows . length && config . edgarFallback && productPageMarkdown ) {
17641764 const top = parseTopHoldingsMarkdown ( productPageMarkdown , fund . ticker , ( await loadCompanyNames ( config ) . catch ( ( ) => null ) ) || new Map ( ) ) ;
1765- if ( top . rejected ) outputNote ( `[ ${ 'holdings' . padEnd ( 9 ) } ] ${ fund . ticker } : product page top holdings rejected: ${ top . rejected } ` ) ;
1765+ if ( top . rejected ) outputNote ( `[ ${ 'holdings' . padEnd ( 8 ) } ] ${ fund . ticker } : product page top holdings rejected: ${ top . rejected } ` ) ;
17661766 if ( top . rows . length && ( ! previousMeta ?. holdings ?. totalRows || / ^ W i s d o m T r e e p r o d u c t p a g e / . test ( String ( previousMeta . holdings . source || '' ) ) ) ) {
17671767 holdingsRows = top . rows ;
17681768 holdingsFresh = true ;
@@ -1779,7 +1779,7 @@ async function processFund(fund: CatalogFund, config: UpdaterConfig, previous: J
17791779 // summary, weights adding up to 581 and 600): it is not republished, the fund has no holdings until a valid source exists.
17801780 const junk = previousSheet . length ? holdingsGuard ( previousHeaders , previousSheet , null , HOLDINGS_GUARD_RELAX [ fund . ticker ] ?? HOLDINGS_GUARD_RELAX [ '*' ] ?? [ ] , holdingsWeightCount ( previousHeaders , previousSheet ) ) : null ;
17811781 if ( junk ) {
1782- console . warn ( `[ ${ 'holdings' . padEnd ( 9 ) } ] ${ fund . ticker } : published holdings dropped (${ junk } ); none until a valid source exists` ) ;
1782+ console . warn ( `[ ${ 'holdings' . padEnd ( 8 ) } ] ${ fund . ticker } : published holdings dropped (${ junk } ); none until a valid source exists` ) ;
17831783 } else {
17841784 holdingsRows = previousSheet ;
17851785 holdingsHeaders = previousHeaders ;
@@ -1795,7 +1795,7 @@ async function processFund(fund: CatalogFund, config: UpdaterConfig, previous: J
17951795 if ( ! config . skipYahoo ) {
17961796 try {
17971797 const query = yahooChartQuery ( config . historyRange ) ;
1798- const payload = await fetchJson ( `${ YAHOO_CHART_URL } /${ encodeURIComponent ( fund . ticker ) } ?${ query . toString ( ) } ` , `[chart ] ${ fund . ticker } ` , config , { 'User-Agent' : 'Mozilla/5.0' } ) ;
1798+ const payload = await fetchJson ( `${ YAHOO_CHART_URL } /${ encodeURIComponent ( fund . ticker ) } ?${ query . toString ( ) } ` , `[ chart ] ${ fund . ticker } ` , config , { 'User-Agent' : 'Mozilla/5.0' } ) ;
17991799 const fetched = parseChart ( payload ) ;
18001800 // A HISTORY_RANGE window never shrinks the published history (and with it 3y, 5y, 10y and since inception); the published
18011801 // distributions table is [Ex-Date, ..., Total Distribution], the window merge reads [date, amount]
@@ -1805,7 +1805,7 @@ async function processFund(fund: CatalogFund, config: UpdaterConfig, previous: J
18051805 days = chart . days ;
18061806 fresh = fresh || days . length > 0 ;
18071807 } catch ( error ) {
1808- outputNote ( `[ ${ 'chart' . padEnd ( 9 ) } ] ${ fund . ticker } : ${ error instanceof Error ? error . message : String ( error ) } ` ) ;
1808+ outputNote ( `[ ${ 'chart' . padEnd ( 8 ) } ] ${ fund . ticker } : ${ error instanceof Error ? error . message : String ( error ) } ` ) ;
18091809 }
18101810 }
18111811 // A new fund that no source answered publishes nothing (never an empty meta.json reported updated): it fails and keeps a catalog-only row.
@@ -2377,7 +2377,7 @@ export async function runUpdate(config: UpdaterConfig, deadlineMs: number = SOFT
23772377 await writeFile ( new URL ( `${ fetched . rawName } -${ new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) } .${ fetched . rawName === 'fund-list' ? 'json' : 'md' } ` , raw ) , fetched . raw , 'utf8' ) ;
23782378 }
23792379 } catch ( error ) {
2380- console . warn ( `[ ${ 'catalog' . padEnd ( 9 ) } ] ${ error instanceof Error ? error . message : String ( error ) } - keeping the published feed` ) ;
2380+ console . warn ( `[ ${ 'catalog' . padEnd ( 8 ) } ] ${ error instanceof Error ? error . message : String ( error ) } - keeping the published feed` ) ;
23812381 }
23822382 }
23832383 // The live catalog (null when only the published feed is known): a catalog-only row it no longer lists is dropped, never retried.
@@ -2387,15 +2387,15 @@ export async function runUpdate(config: UpdaterConfig, deadlineMs: number = SOFT
23872387
23882388 const universe = [ ...catalog . values ( ) ] . sort ( ( a , b ) => a . ticker . localeCompare ( b . ticker ) ) ;
23892389 if ( ! universe . length ) throw new Error ( 'No catalog rows available. Run this where www.wisdomtree.com is reachable or seed api/wisdomtree/index.json first.' ) ;
2390- console . log ( `[ ${ 'catalog' . padEnd ( 9 ) } ] ${ universe . length } WisdomTree ETFs (${ catalogSource } )` ) ;
2390+ console . log ( `[ ${ 'catalog' . padEnd ( 8 ) } ] ${ universe . length } WisdomTree ETFs (${ catalogSource } )` ) ;
23912391 const noteLines : string [ ] = [ ] ;
23922392 if ( live && previous . size ) {
23932393 const listed = new Set ( live ) ;
23942394 // A catalog that lost more than half of the known funds is treated as truncated: nothing is reported then.
23952395 const dropped = Array . from ( previous . keys ( ) ) . filter ( ( ticker ) => ! listed . has ( ticker ) && previous . get ( ticker ) ?. dataFile ) . sort ( ) ;
23962396 if ( dropped . length && listed . size * 2 >= previous . size ) noteLines . push ( `DROPPED FUNDS: ${ dropped . join ( ', ' ) } (no longer in the live catalog; their published data is kept)` ) ;
23972397 }
2398- for ( const line of noteLines ) console . log ( `[ ${ 'catalog' . padEnd ( 9 ) } ] ${ line } ` ) ;
2398+ for ( const line of noteLines ) console . log ( `[ ${ 'catalog' . padEnd ( 8 ) } ] ${ line } ` ) ;
23992399 // Q27: a TICKERS entry outside the live catalog and the published funds stops the run before any fund request
24002400 assertKnownTickers ( config . tickers ? Array . from ( config . tickers ) : null , knownTickers ( live , Array . from ( previous . values ( ) ) ) , 'the WisdomTree catalog or published feed' ) ;
24012401
@@ -2464,14 +2464,14 @@ export async function runUpdate(config: UpdaterConfig, deadlineMs: number = SOFT
24642464 for ( const line of newFunds ) console . log ( line ) ;
24652465 // A TICKERS run never touches the cursor; a full run resets it.
24662466 if ( ! config . tickers ) await writeIfChanged ( STATE_FILE , { cursor : config . maxFetches > 0 ? lastDispatched ?? ( cursor || null ) : null , savedAt : new Date ( ) . toISOString ( ) . replace ( / \. \d { 3 } Z $ / , 'Z' ) } ) ;
2467- if ( stoppedAtDeadline ) console . warn ( `[ ${ 'deadline' . padEnd ( 9 ) } ] soft deadline reached; ${ queue . length } funds were not taken this run (the index was still written)` ) ;
2467+ if ( stoppedAtDeadline ) console . warn ( `[ ${ 'deadline' . padEnd ( 8 ) } ] soft deadline reached; ${ queue . length } funds were not taken this run (the index was still written)` ) ;
24682468 console . log ( output . summary ( startedAt ) ) ;
24692469 console . log ( outputCounts ( counts . funds , counts . holdings , counts . history ) ) ;
24702470 if ( process . env . GITHUB_STEP_SUMMARY ) await appendFile ( process . env . GITHUB_STEP_SUMMARY , `### WisdomTree data update\n\n- updated: ${ results . length } \n- failed: ${ failures } \n- counts: ${ counts . funds } funds / ${ counts . holdings . toLocaleString ( 'en-US' ) } holdings rows / ${ counts . history . toLocaleString ( 'en-US' ) } history rows\n${ noteLines . map ( ( line ) => `- ${ line } \n` ) . join ( '' ) } ${ stoppedAtDeadline ? '- soft deadline reached before every fund was taken\n' : '' } ${ newFunds . length ? `\n### NEW FUNDS\n\n${ newFunds . join ( '\n' ) } \n` : '' } ` , 'utf8' ) ;
24712471 // Every fund failed (or no fund got fresh data from any enabled source): the run is red.
24722472 const sourcesEnabled = ! config . skipWisdomTree || ! config . skipYahoo || config . edgarFallback ;
24732473 if ( ( processed > 0 && failures === processed ) || ( sourcesEnabled && results . length > 0 && fundsWithFreshData === 0 ) ) {
2474- console . error ( `[ ${ 'failed' . padEnd ( 9 ) } ] no fund was updated from a live source` ) ;
2474+ console . error ( `[ ${ 'failed' . padEnd ( 8 ) } ] no fund was updated from a live source` ) ;
24752475 process . exitCode = 1 ;
24762476 }
24772477}
0 commit comments