// Which requests the Nitro SEO middleware resolves. Pure, so `node --test` // drives it directly; the name starts with `is` like Nuxt's own helpers and // is unique enough for the auto-import into the consuming app. /** * File extensions that are never pages: build assets, images, fonts, data * and the root files (robots.txt, sitemap.xml, verification files), which * server/middleware/seo-root.ts handles. */ const ASSET_EXTENSIONS = new Set([ 'js', 'mjs', 'cjs', 'css', 'map', 'json', 'xml', 'txt', 'html', 'htm', 'xsl', 'webmanifest', 'ico', 'png', 'jpg', 'jpeg', 'gif', 'webp', 'avif', 'svg', 'bmp', 'tif', 'tiff', 'woff', 'woff2', 'ttf', 'otf', 'eot', 'mp3', 'mp4', 'webm', 'ogg', 'wav', 'mov', 'pdf', 'zip', 'gz', 'br', 'wasm', ]) /** * True when `path` (path and query, as h3's event.path) is a page the SEO * middleware resolves: not Nuxt's or the layers' internal paths (/_nuxt, * /__nuxt_error, /_journal, /_seo …), not /api, and not a file with one of * the asset extensions, unless the extension is listed in `resolveFiles` * (module option seo.resolveFiles, default ['pdf'], so an old PDF address * can still redirect). Pages a Nuxt route renders under a dotted path (an * author slug with ".com") are still resolved by the route middleware. */ export function isPagePath(path: string, resolveFiles: readonly string[] = []): boolean { if (typeof path !== 'string' || !path.startsWith('/') || path.startsWith('//')) return false const pathname = (path.split('?')[0] ?? '').split('#')[0] ?? '' if (pathname.startsWith('/_')) return false if (pathname === '/api' || pathname.startsWith('/api/')) return false const last = pathname.slice(pathname.lastIndexOf('/') + 1) const dot = last.lastIndexOf('.') if (dot > 0) { const ext = last.slice(dot + 1).toLowerCase() if (ASSET_EXTENSIONS.has(ext) && !resolveFiles.map((e) => e.toLowerCase()).includes(ext)) return false } return true }