@@ -37,7 +37,7 @@ const V8_URLS = [
3737 'https://videojs.org/blog/the-end-of-html-first/' ,
3838 'https://videojs.org/blog/video-js-5-11-0-prelease/' ,
3939 'https://videojs.org/blog/video-js-5-s-fluid-mode-and-playlist-picker/' ,
40- ' https://videojs.org/blog/video-js-5-the-only-thing-that’ s-changed-is-everything-except-for-like-3-things-that-didn-t-including-the-name/' ,
40+ " https://videojs.org/blog/video-js-5-the-only-thing-that' s-changed-is-everything-except-for-like-3-things-that-didn-t-including-the-name/" ,
4141 'https://videojs.org/blog/it-s-here-5-0-release-candidates/' ,
4242 'https://videojs.org/blog/video-js-4-12-the-last-of-the-4-minors/' ,
4343 'https://videojs.org/blog/video-js-4-9-now-can-join-the-party/' ,
@@ -178,35 +178,40 @@ interface V8UrlStatus {
178178 status : 'migrated' | 'redirected' | 'needs migration' ;
179179}
180180
181- interface VercelRedirect {
182- source : string ;
183- destination : string ;
184- statusCode ?: number ;
185- permanent ?: boolean ;
181+ interface NetlifyRedirect {
182+ from : string ;
183+ to : string ;
184+ status : number ;
186185}
187186
188- /**
189- * Check if a pathname matches a Vercel redirect source pattern
190- * Supports exact matches and :path(.*) wildcard patterns
191- */
192- function matchesVercelPattern ( pathname : string , pattern : string ) : boolean {
193- // Remove trailing slash for consistent matching
187+ function parseNetlifyToml ( content : string ) : NetlifyRedirect [ ] {
188+ const redirects : NetlifyRedirect [ ] = [ ] ;
189+ const redirectRegex = / \[ \[ r e d i r e c t s \] \] \s + f r o m \s * = \s * " ( [ ^ " ] + ) " \s + t o \s * = \s * " ( [ ^ " ] + ) " \s + s t a t u s \s * = \s * ( \d + ) / g;
190+
191+ let match : RegExpExecArray | null ;
192+ while ( ( match = redirectRegex . exec ( content ) ) !== null ) {
193+ redirects . push ( {
194+ from : match [ 1 ] ,
195+ to : match [ 2 ] ,
196+ status : parseInt ( match [ 3 ] , 10 ) ,
197+ } ) ;
198+ }
199+
200+ return redirects ;
201+ }
202+
203+ function matchesNetlifyPattern ( pathname : string , pattern : string ) : boolean {
194204 const normalizedPath = pathname . replace ( / \/ $ / , '' ) ;
195205 const normalizedPattern = pattern . replace ( / \/ $ / , '' ) ;
196206
197- // Exact match
198207 if ( normalizedPattern === normalizedPath ) {
199208 return true ;
200209 }
201210
202- // Handle :path(.*) wildcard pattern
203- // Convert /tags/:path(.*) to a regex that matches /tags/anything
204- if ( normalizedPattern . includes ( ':path(' ) ) {
205- const regexPattern = normalizedPattern
206- . replace ( / : [ ^ / ] + \( \. \* \) / g, '.*' ) // :path(.*) -> .*
207- . replace ( / \/ / g, '\\/' ) ; // Escape slashes
208- const regex = new RegExp ( `^${ regexPattern } $` ) ;
209- return regex . test ( normalizedPath ) ;
211+ // Handle * splat pattern (e.g., /tags/* matches /tags/anything)
212+ if ( normalizedPattern . endsWith ( '/*' ) ) {
213+ const prefix = normalizedPattern . slice ( 0 , - 2 ) ;
214+ return normalizedPath === prefix || normalizedPath . startsWith ( `${ prefix } /` ) ;
210215 }
211216
212217 return false ;
@@ -220,20 +225,18 @@ export default function checkV8Urls(): AstroIntegration {
220225 // Convert URL to file path
221226 const buildDir = fileURLToPath ( dir ) ;
222227
223- // Check for Vercel config files
224- // buildDir is dist/client/, so go up two levels to site/
225- const siteDir = resolve ( buildDir , '..' , '..' ) ;
226- const vercelConfigPath = resolve ( siteDir , '.vercel' , 'output' , 'config.json' ) ;
227- const vercelJsonPath = resolve ( siteDir , 'vercel.json' ) ;
228+ // buildDir is dist/, so go up one level to site/
229+ const siteDir = resolve ( buildDir , '..' ) ;
230+ const netlifyTomlPath = resolve ( siteDir , 'netlify.toml' ) ;
228231
229- // Read vercel.json redirects if it exists
230- let vercelJsonRedirects : VercelRedirect [ ] = [ ] ;
231- if ( existsSync ( vercelJsonPath ) ) {
232+ // Read netlify.toml redirects if it exists
233+ let netlifyRedirects : NetlifyRedirect [ ] = [ ] ;
234+ if ( existsSync ( netlifyTomlPath ) ) {
232235 try {
233- const vercelJson = JSON . parse ( readFileSync ( vercelJsonPath , 'utf-8' ) ) ;
234- vercelJsonRedirects = vercelJson . redirects || [ ] ;
236+ const content = readFileSync ( netlifyTomlPath , 'utf-8' ) ;
237+ netlifyRedirects = parseNetlifyToml ( content ) ;
235238 } catch {
236- // Ignore JSON parse errors
239+ // Ignore parse errors
237240 }
238241 }
239242
@@ -254,49 +257,17 @@ export default function checkV8Urls(): AstroIntegration {
254257 if ( existsSync ( htmlPath1 ) || existsSync ( htmlPath2 ) ) {
255258 status = 'migrated' ;
256259 } else {
257- // Check for redirects in vercel.json first
258- const hasVercelJsonRedirect = vercelJsonRedirects . some ( ( redirect ) => {
259- // Check if redirect has a redirect status code (or permanent flag)
260- const isRedirect = redirect . statusCode
261- ? redirect . statusCode >= 301 && redirect . statusCode <= 308
262- : redirect . permanent !== undefined ;
263-
260+ // Check for redirects in netlify.toml
261+ const hasNetlifyRedirect = netlifyRedirects . some ( ( redirect ) => {
262+ const isRedirect = redirect . status >= 301 && redirect . status <= 308 ;
264263 if ( isRedirect ) {
265- return matchesVercelPattern ( pathname , redirect . source ) ;
264+ return matchesNetlifyPattern ( pathname , redirect . from ) ;
266265 }
267266 return false ;
268267 } ) ;
269268
270- if ( hasVercelJsonRedirect ) {
269+ if ( hasNetlifyRedirect ) {
271270 status = 'redirected' ;
272- } else {
273- // Fall back to checking .vercel/output/config.json (adapter-generated)
274- if ( existsSync ( vercelConfigPath ) ) {
275- try {
276- const vercelConfig = JSON . parse ( readFileSync ( vercelConfigPath , 'utf-8' ) ) ;
277- const routes = vercelConfig . routes || [ ] ;
278-
279- // Check if this pathname has a redirect (status 301/302/307/308)
280- const hasRedirect = routes . some ( ( route : any ) => {
281- if ( route . status && route . status >= 301 && route . status <= 308 ) {
282- // Route has a redirect status code
283- const src = route . src ;
284- // Match against pathname (src is a regex pattern)
285- // Simple check: convert pathname to regex pattern
286- const pathPattern = `^${ pathname . replace ( / \/ $ / , '' ) } $` ;
287- const pathPatternWithSlash = `^${ pathname } $` ;
288- return src === pathPattern || src === pathPatternWithSlash ;
289- }
290- return false ;
291- } ) ;
292-
293- if ( hasRedirect ) {
294- status = 'redirected' ;
295- }
296- } catch {
297- // Ignore JSON parse errors
298- }
299- }
300271 }
301272 }
302273
0 commit comments