@@ -91,3 +91,112 @@ export function normalizeFilename(filename: string): string {
9191 return filename ;
9292 }
9393}
94+
95+ /**
96+ * Extract basename from a path (handles both / and \ separators)
97+ */
98+ export function getBasename ( path : string ) : string {
99+ return path . split ( / [ / \\ ] / ) . pop ( ) || path ;
100+ }
101+
102+ /**
103+ * Remove extension from a filename
104+ */
105+ export function removeExtension ( filename : string ) : string {
106+ const lastDot = filename . lastIndexOf ( '.' ) ;
107+ return lastDot > 0 ? filename . slice ( 0 , lastDot ) : filename ;
108+ }
109+
110+ /**
111+ * Remap page img_path values to match actual file names.
112+ * Handles cases where image formats have been converted (e.g., png->webp, jpg->avif).
113+ *
114+ * Returns the pages array with updated img_path values, or the original if no remapping needed.
115+ */
116+ export function remapPagePaths < T extends { img_path : string } > (
117+ pages : T [ ] ,
118+ files : Record < string , unknown >
119+ ) : T [ ] {
120+ const fileNames = Object . keys ( files ) ;
121+
122+ // Build lookup maps for matching strategies
123+ const normalizedToActual = new Map < string , string > ( ) ;
124+ const pathNoExtToActual = new Map < string , string > ( ) ;
125+ const basenameToActual = new Map < string , string > ( ) ;
126+ const basenameNoExtToActual = new Map < string , string > ( ) ;
127+
128+ for ( const fileName of fileNames ) {
129+ const normalized = normalizeFilename ( fileName ) ;
130+ normalizedToActual . set ( normalized , fileName ) ;
131+
132+ const pathNoExt = normalizeFilename ( removeExtension ( fileName ) ) ;
133+ pathNoExtToActual . set ( pathNoExt , fileName ) ;
134+
135+ const basename = normalizeFilename ( getBasename ( fileName ) ) ;
136+ basenameToActual . set ( basename , fileName ) ;
137+
138+ const basenameNoExt = normalizeFilename ( removeExtension ( getBasename ( fileName ) ) ) ;
139+ basenameNoExtToActual . set ( basenameNoExt , fileName ) ;
140+ }
141+
142+ // Check if any remapping is needed
143+ let needsRemapping = false ;
144+ for ( const page of pages ) {
145+ const imgPath = page . img_path ;
146+ // If exact match exists, no remapping needed for this page
147+ if ( files [ imgPath ] || normalizedToActual . has ( normalizeFilename ( imgPath ) ) ) {
148+ continue ;
149+ }
150+ // Check if we can find a match by path without ext, basename, or basename without extension
151+ const pathNoExt = normalizeFilename ( removeExtension ( imgPath ) ) ;
152+ const basename = normalizeFilename ( getBasename ( imgPath ) ) ;
153+ const basenameNoExt = normalizeFilename ( removeExtension ( getBasename ( imgPath ) ) ) ;
154+ if (
155+ pathNoExtToActual . has ( pathNoExt ) ||
156+ basenameToActual . has ( basename ) ||
157+ basenameNoExtToActual . has ( basenameNoExt )
158+ ) {
159+ needsRemapping = true ;
160+ break ;
161+ }
162+ }
163+
164+ if ( ! needsRemapping ) {
165+ return pages ;
166+ }
167+
168+ // Remap pages
169+ return pages . map ( ( page ) => {
170+ const imgPath = page . img_path ;
171+
172+ // Strategy 1: Exact match (with normalization)
173+ if ( files [ imgPath ] ) {
174+ return page ;
175+ }
176+ const normalized = normalizeFilename ( imgPath ) ;
177+ if ( normalizedToActual . has ( normalized ) ) {
178+ return { ...page , img_path : normalizedToActual . get ( normalized ) ! } ;
179+ }
180+
181+ // Strategy 2: Basename match
182+ const basename = normalizeFilename ( getBasename ( imgPath ) ) ;
183+ if ( basenameToActual . has ( basename ) ) {
184+ return { ...page , img_path : basenameToActual . get ( basename ) ! } ;
185+ }
186+
187+ // Strategy 3: Path without extension (handles format conversions with same path)
188+ const pathNoExt = normalizeFilename ( removeExtension ( imgPath ) ) ;
189+ if ( pathNoExtToActual . has ( pathNoExt ) ) {
190+ return { ...page , img_path : pathNoExtToActual . get ( pathNoExt ) ! } ;
191+ }
192+
193+ // Strategy 4: Basename without extension (handles format conversions)
194+ const basenameNoExt = normalizeFilename ( removeExtension ( getBasename ( imgPath ) ) ) ;
195+ if ( basenameNoExtToActual . has ( basenameNoExt ) ) {
196+ return { ...page , img_path : basenameNoExtToActual . get ( basenameNoExt ) ! } ;
197+ }
198+
199+ // No match found, keep original
200+ return page ;
201+ } ) ;
202+ }
0 commit comments