{"version":3,"file":"index.mjs","names":[],"sources":["../src/css-parser.ts","../src/font-resolver.ts","../src/fallback.ts","../src/cache.ts","../src/plugin.ts"],"sourcesContent":["import { transform, type Visitor, type Declaration } from \"lightningcss\"\nimport type { DetectedFont } from \"./types.js\"\n\n/**\n * Generic font families that should not be resolved\n */\nconst GENERIC_FAMILIES = new Set([\n  \"serif\",\n  \"sans-serif\",\n  \"monospace\",\n  \"cursive\",\n  \"fantasy\",\n  \"system-ui\",\n  \"ui-serif\",\n  \"ui-sans-serif\",\n  \"ui-monospace\",\n  \"ui-rounded\",\n  \"emoji\",\n  \"math\",\n  \"fangsong\",\n  \"inherit\",\n  \"initial\",\n  \"revert\",\n  \"revert-layer\",\n  \"unset\",\n])\n\n/**\n * System fonts that should not be resolved\n */\nconst SYSTEM_FONTS = new Set([\n  \"arial\",\n  \"helvetica\",\n  \"times\",\n  \"times new roman\",\n  \"georgia\",\n  \"verdana\",\n  \"tahoma\",\n  \"trebuchet ms\",\n  \"courier\",\n  \"courier new\",\n  \"comic sans ms\",\n  \"impact\",\n  \"lucida console\",\n  \"lucida sans unicode\",\n  \"palatino linotype\",\n  \"book antiqua\",\n  \"segoe ui\",\n  \"roboto\", // Android system font, might want to resolve\n  \"san francisco\", // macOS/iOS system font\n  \"-apple-system\",\n  \"blinkmacsystemfont\",\n])\n\n/**\n * Parse a font-family CSS value and extract individual font names\n */\nfunction parseFontFamilyValue(value: string): string[] {\n  const fonts: string[] = []\n  let current = \"\"\n  let inQuotes = false\n  let quoteChar = \"\"\n\n  for (let i = 0; i < value.length; i++) {\n    const char = value[i]!\n\n    if (!inQuotes && (char === '\"' || char === \"'\")) {\n      inQuotes = true\n      quoteChar = char\n    } else if (inQuotes && char === quoteChar) {\n      inQuotes = false\n      quoteChar = \"\"\n    } else if (!inQuotes && char === \",\") {\n      const trimmed = current.trim()\n      if (trimmed) {\n        fonts.push(trimmed)\n      }\n      current = \"\"\n    } else {\n      current += char\n    }\n  }\n\n  const trimmed = current.trim()\n  if (trimmed) {\n    fonts.push(trimmed)\n  }\n\n  // Clean up quotes from font names\n  return fonts.map((f) => f.replace(/^[\"']|[\"']$/g, \"\").trim()).filter(Boolean)\n}\n\n/**\n * Check if a font name is a generic or system font that shouldn't be resolved\n */\nfunction shouldSkipFont(fontName: string): boolean {\n  const normalized = fontName.toLowerCase()\n  return GENERIC_FAMILIES.has(normalized) || SYSTEM_FONTS.has(normalized)\n}\n\n/**\n * Extract font-family declarations from CSS using LightningCSS\n */\nexport function extractFontsFromCSS(\n  css: string,\n  filename: string\n): DetectedFont[] {\n  const detectedFonts = new Map<string, DetectedFont>()\n\n  try {\n    // Use LightningCSS transform with a visitor to walk the AST\n    transform({\n      filename,\n      code: Buffer.from(css),\n      minify: false,\n      visitor: {\n        Declaration(decl) {\n          // Check if this is a font-family or font shorthand declaration\n          if (decl.property === \"font-family\") {\n            const families = extractFamiliesFromDeclaration(decl)\n            processFontFamilies(families, filename, detectedFonts)\n          } else if (decl.property === \"font\") {\n            // Handle font shorthand - need to extract font-family part\n            const families = extractFamiliesFromFontShorthand(decl)\n            processFontFamilies(families, filename, detectedFonts)\n          }\n          return decl\n        },\n      } satisfies Visitor<{}>,\n    })\n  } catch {\n    // If LightningCSS fails, fall back to regex-based extraction\n    console.warn(\n      `[vite-fonts] LightningCSS parse warning for ${filename}, using fallback parser`\n    )\n    return extractFontsWithRegex(css, filename)\n  }\n\n  return Array.from(detectedFonts.values())\n}\n\n/**\n * Extract font families from a font-family declaration\n */\nfunction extractFamiliesFromDeclaration(decl: Declaration): string[] {\n  if (decl.property !== \"font-family\" || !(\"value\" in decl)) {\n    return []\n  }\n\n  const value = decl.value\n  if (!Array.isArray(value)) {\n    return []\n  }\n\n  const families: string[] = []\n\n  for (const family of value) {\n    if (typeof family === \"string\") {\n      // Generic family like 'serif', 'sans-serif'\n      families.push(family)\n    } else if (family && typeof family === \"object\") {\n      const f = family as Record<string, unknown>\n      if (f.type === \"family-name\" && typeof f.name === \"string\") {\n        // Specific font family name\n        families.push(f.name)\n      }\n    }\n  }\n\n  return families\n}\n\n/**\n * Extract font families from font shorthand declaration\n */\nfunction extractFamiliesFromFontShorthand(decl: Declaration): string[] {\n  if (decl.property !== \"font\" || !(\"value\" in decl)) {\n    return []\n  }\n\n  const value = decl.value\n  if (!value || typeof value !== \"object\" || !(\"family\" in value)) {\n    return []\n  }\n\n  const familyValue = (value as unknown as Record<string, unknown>).family\n  if (!Array.isArray(familyValue)) {\n    return []\n  }\n\n  const families: string[] = []\n\n  for (const family of familyValue) {\n    if (typeof family === \"string\") {\n      families.push(family)\n    } else if (family && typeof family === \"object\") {\n      const f = family as Record<string, unknown>\n      if (f.type === \"family-name\" && typeof f.name === \"string\") {\n        families.push(f.name)\n      }\n    }\n  }\n\n  return families\n}\n\n/**\n * Process extracted font families and add them to the detected fonts map\n */\nfunction processFontFamilies(\n  families: string[],\n  filename: string,\n  detectedFonts: Map<string, DetectedFont>\n): void {\n  if (families.length === 0) return\n\n  // First non-generic font is the primary font to resolve\n  const primaryIndex = families.findIndex((f) => !shouldSkipFont(f))\n  if (primaryIndex === -1) return\n\n  const primary = families[primaryIndex]!\n  const fallbacks = families.slice(primaryIndex + 1)\n\n  // Use normalized name as key to avoid duplicates\n  const key = primary.toLowerCase()\n\n  if (!detectedFonts.has(key)) {\n    detectedFonts.set(key, {\n      family: primary,\n      source: filename,\n      fallbacks,\n    })\n  }\n}\n\n/**\n * Fallback regex-based extraction for when LightningCSS fails\n */\nfunction extractFontsWithRegex(css: string, filename: string): DetectedFont[] {\n  const detectedFonts = new Map<string, DetectedFont>()\n\n  // Match font-family declarations\n  const fontFamilyRegex = /font-family\\s*:\\s*([^;{}]+)/gi\n  let match\n\n  while ((match = fontFamilyRegex.exec(css)) !== null) {\n    const value = match[1]?.trim()\n    if (!value) continue\n\n    const families = parseFontFamilyValue(value)\n    processFontFamilies(families, filename, detectedFonts)\n  }\n\n  // Match font shorthand (simplified - just look for font-family-like values after font:)\n  const fontShorthandRegex = /font\\s*:\\s*[^;{}]*?(?:\\/[^;{}]*?)?\\s+([^;{}]+)/gi\n\n  while ((match = fontShorthandRegex.exec(css)) !== null) {\n    const value = match[1]?.trim()\n    if (!value) continue\n\n    const families = parseFontFamilyValue(value)\n    processFontFamilies(families, filename, detectedFonts)\n  }\n\n  return Array.from(detectedFonts.values())\n}\n\n/**\n * Check if a file should be processed for font extraction\n */\nexport function shouldProcessFile(id: string): boolean {\n  // Process CSS files and Vue/Svelte/Astro files (which may contain CSS)\n  return /\\.(css|scss|sass|less|styl|stylus|vue|svelte|astro)(\\?.*)?$/.test(id)\n}\n\n/**\n * Extract CSS from Vue SFC, Svelte, or Astro files\n */\nexport function extractCSSFromFile(code: string, id: string): string[] {\n  const cssBlocks: string[] = []\n\n  if (id.endsWith(\".css\") || /\\.css\\?/.test(id)) {\n    // Pure CSS file\n    cssBlocks.push(code)\n  } else if (id.includes(\".vue\") || id.includes(\".svelte\")) {\n    // Extract <style> blocks from Vue/Svelte SFCs\n    const styleRegex = /<style[^>]*>([\\s\\S]*?)<\\/style>/gi\n    let match\n    while ((match = styleRegex.exec(code)) !== null) {\n      if (match[1]) {\n        cssBlocks.push(match[1])\n      }\n    }\n  } else if (id.includes(\".astro\")) {\n    // Extract <style> blocks from Astro files\n    const styleRegex = /<style[^>]*>([\\s\\S]*?)<\\/style>/gi\n    let match\n    while ((match = styleRegex.exec(code)) !== null) {\n      if (match[1]) {\n        cssBlocks.push(match[1])\n      }\n    }\n  }\n\n  return cssBlocks\n}\n","import { createUnifont, providers } from \"unifont\"\nimport type { Storage } from \"unstorage\"\nimport type {\n  DetectedFont,\n  ResolvedFontFace,\n  ResolvedOptions,\n  FontFamilyConfig,\n  FontWeight,\n} from \"./types.js\"\n\n/**\n * Unifont instance type - use any to avoid complex generic issues\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Unifont = Awaited<ReturnType<typeof createUnifont<any>>>\n\nlet unifontInstance: Unifont | null = null\n\n/**\n * Initialize unifont with configured providers\n */\nexport async function initializeUnifont(\n  options: ResolvedOptions,\n  storage?: Storage\n): Promise<Unifont> {\n  // Build provider list - unifont requires at least one provider\n  const providerList = []\n\n  // Add providers based on configuration\n  if (options.providers.google) {\n    providerList.push(providers.google())\n  }\n\n  if (options.providers.bunny) {\n    providerList.push(providers.bunny())\n  }\n\n  if (options.providers.fontsource) {\n    providerList.push(providers.fontsource())\n  }\n\n  // Ensure at least one provider is configured\n  if (providerList.length === 0) {\n    // Default to bunny if nothing is configured\n    providerList.push(providers.bunny())\n  }\n\n  unifontInstance = await createUnifont(\n    providerList as Parameters<typeof createUnifont>[0],\n    { storage }\n  )\n\n  return unifontInstance\n}\n\n/**\n * Get the unifont instance, initializing if needed\n */\nexport function getUnifont(): Unifont | null {\n  return unifontInstance\n}\n\n/**\n * Normalize font weight to unifont format (string)\n */\nfunction normalizeWeight(weight: FontWeight): string {\n  if (typeof weight === \"number\") {\n    return String(weight)\n  }\n  if (weight === \"normal\") {\n    return \"400\"\n  }\n  if (weight === \"bold\") {\n    return \"700\"\n  }\n  // Variable font range like \"100 900\"\n  return weight\n}\n\n/**\n * Resolve a single font family using unifont\n */\nexport async function resolveFont(\n  detected: DetectedFont,\n  config: FontFamilyConfig,\n  defaults: ResolvedOptions[\"defaults\"]\n): Promise<ResolvedFontFace[]> {\n  const unifont = getUnifont()\n  if (!unifont) {\n    throw new Error(\"[vite-fonts] Unifont not initialized\")\n  }\n\n  const weights = config.weights ?? defaults.weights\n  const styles = config.styles ?? defaults.styles\n  const subsets = config.subsets ?? defaults.subsets\n  const display = config.display ?? defaults.display\n\n  try {\n    const result = await unifont.resolveFont(detected.family, {\n      weights: weights.map(normalizeWeight),\n      styles: styles as (\"normal\" | \"italic\" | \"oblique\")[],\n      subsets: subsets,\n    })\n\n    if (!result || !result.fonts || result.fonts.length === 0) {\n      if (process.env.DEBUG || process.env.VITE_FONTS_DEBUG) {\n        console.warn(\n          `[vite-fonts] Could not resolve font: ${detected.family}`\n        )\n      }\n      return []\n    }\n\n    // Convert unifont result to our format\n    const faces: ResolvedFontFace[] = result.fonts.map((font) => {\n      // Handle weight which can be number, string, or [number, number]\n      let weight: number | string = 400\n      if (font.weight !== undefined) {\n        if (Array.isArray(font.weight)) {\n          weight = `${font.weight[0]} ${font.weight[1]}`\n        } else {\n          weight = font.weight\n        }\n      }\n\n      // Extract URLs from src array, filtering out local sources\n      const srcWithUrls = font.src\n        .filter((s): s is { url: string; format?: string } => \"url\" in s)\n        .map((s) => ({\n          url: s.url,\n          format: s.format,\n        }))\n\n      return {\n        family: detected.family,\n        weight,\n        style: font.style ?? \"normal\",\n        display,\n        src: srcWithUrls,\n        unicodeRange: font.unicodeRange?.join(\", \"),\n      }\n    })\n\n    return faces\n  } catch (error) {\n    console.warn(\n      `[vite-fonts] Error resolving font \"${detected.family}\":`,\n      error instanceof Error ? error.message : error\n    )\n    return []\n  }\n}\n\n/**\n * Resolve multiple fonts\n */\nexport async function resolveFonts(\n  detected: DetectedFont[],\n  options: ResolvedOptions\n): Promise<ResolvedFontFace[]> {\n  const allFaces: ResolvedFontFace[] = []\n\n  for (const font of detected) {\n    // Get config for this specific font, or use an empty config (defaults will apply)\n    const familyConfig =\n      options.families[font.family.toLowerCase()] ??\n      options.families[font.family] ??\n      {}\n\n    const faces = await resolveFont(font, familyConfig, options.defaults)\n    allFaces.push(...faces)\n  }\n\n  return allFaces\n}\n\n/**\n * Generate @font-face CSS from resolved faces\n */\nexport function generateFontFaceCSS(faces: ResolvedFontFace[]): string {\n  if (faces.length === 0) {\n    return \"\"\n  }\n\n  const rules = faces.map((face) => {\n    const srcParts = face.src.map((s) => {\n      const format = s.format ? ` format('${s.format}')` : \"\"\n      return `url('${s.url}')${format}`\n    })\n\n    const properties = [\n      `font-family: '${face.family}'`,\n      `font-style: ${face.style}`,\n      `font-weight: ${face.weight}`,\n      `font-display: ${face.display}`,\n      `src: ${srcParts.join(\", \")}`,\n    ]\n\n    if (face.unicodeRange) {\n      properties.push(`unicode-range: ${face.unicodeRange}`)\n    }\n\n    return `@font-face {\\n  ${properties.join(\";\\n  \")};\\n}`\n  })\n\n  return rules.join(\"\\n\\n\")\n}\n\n/**\n * Generate CSS with local URLs (for production builds)\n */\nexport function generateFontFaceCSSWithLocalUrls(\n  faces: ResolvedFontFace[],\n  urlMap: Map<string, string>\n): string {\n  if (faces.length === 0) {\n    return \"\"\n  }\n\n  const rules = faces.map((face) => {\n    const srcParts = face.src.map((s) => {\n      // Replace remote URL with local URL if available\n      const localUrl = urlMap.get(s.url) ?? s.url\n      const format = s.format ? ` format('${s.format}')` : \"\"\n      return `url('${localUrl}')${format}`\n    })\n\n    const properties = [\n      `font-family: '${face.family}'`,\n      `font-style: ${face.style}`,\n      `font-weight: ${face.weight}`,\n      `font-display: ${face.display}`,\n      `src: ${srcParts.join(\", \")}`,\n    ]\n\n    if (face.unicodeRange) {\n      properties.push(`unicode-range: ${face.unicodeRange}`)\n    }\n\n    return `@font-face {\\n  ${properties.join(\";\\n  \")};\\n}`\n  })\n\n  return rules.join(\"\\n\\n\")\n}\n\n/**\n * Extract all font URLs from resolved faces\n */\nexport function extractFontUrls(faces: ResolvedFontFace[]): string[] {\n  const urls = new Set<string>()\n\n  for (const face of faces) {\n    for (const src of face.src) {\n      if (src.url.startsWith(\"http://\") || src.url.startsWith(\"https://\")) {\n        urls.add(src.url)\n      }\n    }\n  }\n\n  return Array.from(urls)\n}\n\n/**\n * Clean up unifont instance\n */\nexport function destroyUnifont(): void {\n  unifontInstance = null\n}\n","import type { ResolvedFontFace, DetectedFont } from \"./types.js\"\n\n/**\n * System font stacks for fallback generation\n */\nconst SYSTEM_FONT_STACKS = {\n  \"sans-serif\": [\n    \"BlinkMacSystemFont\",\n    \"Segoe UI\",\n    \"Roboto\",\n    \"Helvetica Neue\",\n    \"Arial\",\n  ],\n  serif: [\"Georgia\", \"Cambria\", \"Times New Roman\", \"Times\"],\n  monospace: [\n    \"SFMono-Regular\",\n    \"Menlo\",\n    \"Monaco\",\n    \"Consolas\",\n    \"Liberation Mono\",\n    \"Courier New\",\n  ],\n} as const\n\n/**\n * Default font metrics for common system fonts\n * These are approximations - fontaine provides more accurate metrics\n */\nconst DEFAULT_METRICS: Record<\n  string,\n  {\n    ascent: number\n    descent: number\n    lineGap: number\n    unitsPerEm: number\n    xWidthAvg: number\n  }\n> = {\n  arial: {\n    ascent: 1854,\n    descent: -434,\n    lineGap: 67,\n    unitsPerEm: 2048,\n    xWidthAvg: 904,\n  },\n  \"times new roman\": {\n    ascent: 1825,\n    descent: -443,\n    lineGap: 87,\n    unitsPerEm: 2048,\n    xWidthAvg: 819,\n  },\n  georgia: {\n    ascent: 1878,\n    descent: -449,\n    lineGap: 0,\n    unitsPerEm: 2048,\n    xWidthAvg: 873,\n  },\n  verdana: {\n    ascent: 2059,\n    descent: -430,\n    lineGap: 0,\n    unitsPerEm: 2048,\n    xWidthAvg: 1041,\n  },\n  courier: {\n    ascent: 1705,\n    descent: -615,\n    lineGap: 0,\n    unitsPerEm: 2048,\n    xWidthAvg: 1229,\n  },\n}\n\n/**\n * Determine the generic font category based on font name or fallbacks\n */\nfunction detectFontCategory(\n  font: DetectedFont\n): \"sans-serif\" | \"serif\" | \"monospace\" {\n  const name = font.family.toLowerCase()\n  const fallbacks = font.fallbacks.map((f) => f.toLowerCase())\n\n  // Check explicit fallbacks first\n  if (fallbacks.includes(\"monospace\") || fallbacks.includes(\"ui-monospace\")) {\n    return \"monospace\"\n  }\n  if (fallbacks.includes(\"serif\") || fallbacks.includes(\"ui-serif\")) {\n    return \"serif\"\n  }\n  if (fallbacks.includes(\"sans-serif\") || fallbacks.includes(\"ui-sans-serif\")) {\n    return \"sans-serif\"\n  }\n\n  // Heuristics based on font name\n  const monoKeywords = [\"mono\", \"code\", \"console\", \"courier\", \"fira code\"]\n  const serifKeywords = [\n    \"serif\",\n    \"georgia\",\n    \"times\",\n    \"garamond\",\n    \"palatino\",\n    \"baskerville\",\n    \"cambria\",\n    \"merriweather\",\n    \"playfair\",\n    \"lora\",\n  ]\n\n  if (monoKeywords.some((k) => name.includes(k))) {\n    return \"monospace\"\n  }\n  if (serifKeywords.some((k) => name.includes(k))) {\n    return \"serif\"\n  }\n\n  // Default to sans-serif\n  return \"sans-serif\"\n}\n\n/**\n * Generate a fallback font name\n */\nfunction getFallbackName(family: string): string {\n  return `${family} Fallback`\n}\n\n/**\n * Try to import fontaine dynamically for accurate metrics\n */\nasync function tryGetFontaineMetrics(\n  _fontUrl: string\n): Promise<{\n  ascent: number\n  descent: number\n  lineGap: number\n  unitsPerEm: number\n  xWidthAvg: number\n} | null> {\n  try {\n    // Dynamic import of fontaine\n    // fontaine expects a font family name and tries to look it up\n    // For remote URLs, we need to fetch and analyze the font file\n    // This is a simplified approach - fontaine has more capabilities\n    await import(\"fontaine\")\n\n    return null // Let the caller use default metrics for now\n  } catch {\n    // fontaine not available or failed\n    return null\n  }\n}\n\n/**\n * Generate fallback @font-face CSS that adjusts system fonts to match web font metrics\n */\nexport async function generateFallbackCSS(\n  detectedFonts: DetectedFont[],\n  resolvedFaces: ResolvedFontFace[]\n): Promise<string> {\n  const rules: string[] = []\n\n  // Group faces by family\n  const facesByFamily = new Map<string, ResolvedFontFace[]>()\n  for (const face of resolvedFaces) {\n    const existing = facesByFamily.get(face.family) ?? []\n    existing.push(face)\n    facesByFamily.set(face.family, existing)\n  }\n\n  for (const detected of detectedFonts) {\n    const faces = facesByFamily.get(detected.family)\n    if (!faces || faces.length === 0) continue\n\n    const category = detectFontCategory(detected)\n    const systemFonts = SYSTEM_FONT_STACKS[category]\n    const fallbackName = getFallbackName(detected.family)\n\n    // Get the primary face for metrics reference\n    const primaryFace = faces[0]!\n    const fontUrl = primaryFace.src[0]?.url\n\n    // Try to get accurate metrics from fontaine\n    let metrics = fontUrl ? await tryGetFontaineMetrics(fontUrl) : null\n\n    // Fall back to default metrics for the first system font\n    if (!metrics) {\n      const systemFont = systemFonts[0]?.toLowerCase()\n      metrics = systemFont\n        ? DEFAULT_METRICS[systemFont] ?? null\n        : DEFAULT_METRICS[\"arial\"] ?? null\n    }\n\n    if (!metrics) continue\n\n    // Calculate size-adjust to match x-height\n    // This is a simplified calculation - fontaine does more sophisticated adjustments\n    // const sizeAdjust = 100 // Would be calculated from actual font metrics\n\n    // Generate fallback @font-face for each unique weight/style combination\n    const seenCombos = new Set<string>()\n\n    for (const face of faces) {\n      const combo = `${face.weight}-${face.style}`\n      if (seenCombos.has(combo)) continue\n      seenCombos.add(combo)\n\n      const fallbackRule = `@font-face {\n  font-family: '${fallbackName}';\n  font-style: ${face.style};\n  font-weight: ${face.weight};\n  src: local('${systemFonts[0]}'), local('${systemFonts[1] ?? systemFonts[0]}');\n  ascent-override: ${((metrics.ascent / metrics.unitsPerEm) * 100).toFixed(2)}%;\n  descent-override: ${(Math.abs(metrics.descent / metrics.unitsPerEm) * 100).toFixed(2)}%;\n  line-gap-override: ${((metrics.lineGap / metrics.unitsPerEm) * 100).toFixed(2)}%;\n}`\n\n      rules.push(fallbackRule)\n    }\n  }\n\n  return rules.join(\"\\n\\n\")\n}\n\n/**\n * Get the fallback font family declaration to append to font-family\n */\nexport function getFallbackFamilyName(originalFamily: string): string {\n  return getFallbackName(originalFamily)\n}\n\n/**\n * Modify a font-family value to include the fallback\n */\nexport function injectFallbackIntoFontFamily(\n  fontFamilyValue: string,\n  originalFamily: string\n): string {\n  const fallbackName = getFallbackName(originalFamily)\n\n  // Insert fallback right after the original family\n  // e.g., \"Inter, sans-serif\" -> \"Inter, 'Inter Fallback', sans-serif\"\n  const escapedFamily = originalFamily.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n  const regex = new RegExp(\n    `(['\"]?)${escapedFamily}\\\\1`,\n    \"i\"\n  )\n\n  return fontFamilyValue.replace(\n    regex,\n    `$&, '${fallbackName}'`\n  )\n}\n","import { createStorage, type Storage } from \"unstorage\"\nimport fsDriver from \"unstorage/drivers/fs-lite\"\nimport type { ResolvedOptions } from \"./types.js\"\n\nlet storageInstance: Storage | null = null\n\n/**\n * Initialize the cache storage\n */\nexport function initializeCache(options: ResolvedOptions): Storage {\n  if (!options.cache) {\n    // Return a no-op storage if caching is disabled\n    storageInstance = createStorage()\n    return storageInstance\n  }\n\n  storageInstance = createStorage({\n    driver: fsDriver({\n      base: options.cacheDir,\n    }),\n  })\n\n  return storageInstance\n}\n\n/**\n * Get the cache storage instance\n */\nexport function getCache(): Storage | null {\n  return storageInstance\n}\n\n/**\n * Generate a cache key for a font URL\n */\nexport function getFontCacheKey(url: string): string {\n  // Create a safe filename from the URL\n  const urlHash = simpleHash(url)\n  const extension = getExtensionFromUrl(url)\n  return `fonts/${urlHash}${extension}`\n}\n\n/**\n * Generate a cache key for font metadata\n */\nexport function getMetadataCacheKey(family: string): string {\n  const normalized = family.toLowerCase().replace(/\\s+/g, \"-\")\n  return `metadata/${normalized}.json`\n}\n\n/**\n * Simple hash function for cache keys\n */\nfunction simpleHash(str: string): string {\n  let hash = 0\n  for (let i = 0; i < str.length; i++) {\n    const char = str.charCodeAt(i)\n    hash = ((hash << 5) - hash) + char\n    hash = hash & hash // Convert to 32-bit integer\n  }\n  return Math.abs(hash).toString(36)\n}\n\n/**\n * Extract file extension from URL\n */\nfunction getExtensionFromUrl(url: string): string {\n  try {\n    const pathname = new URL(url).pathname\n    const ext = pathname.substring(pathname.lastIndexOf(\".\"))\n    if (ext && /^\\.\\w+$/.test(ext)) {\n      return ext\n    }\n  } catch {\n    // Invalid URL, try regex\n    const match = url.match(/\\.(\\w+)(?:\\?|$)/)\n    if (match?.[1]) {\n      return `.${match[1]}`\n    }\n  }\n  return \".woff2\" // Default to woff2\n}\n\n/**\n * Get a cached font file\n */\nexport async function getCachedFont(url: string): Promise<Buffer | null> {\n  const cache = getCache()\n  if (!cache) return null\n\n  const key = getFontCacheKey(url)\n  try {\n    const data = await cache.getItemRaw(key)\n    if (data instanceof Buffer) {\n      return data\n    }\n    if (data instanceof Uint8Array) {\n      return Buffer.from(data)\n    }\n    return null\n  } catch {\n    return null\n  }\n}\n\n/**\n * Cache a font file\n */\nexport async function setCachedFont(url: string, data: Buffer): Promise<void> {\n  const cache = getCache()\n  if (!cache) return\n\n  const key = getFontCacheKey(url)\n  try {\n    await cache.setItemRaw(key, data)\n  } catch (error) {\n    console.warn(`[vite-fonts] Failed to cache font ${url}:`, error)\n  }\n}\n\n/**\n * Get cached metadata for a font family\n */\nexport async function getCachedMetadata<T>(family: string): Promise<T | null> {\n  const cache = getCache()\n  if (!cache) return null\n\n  const key = getMetadataCacheKey(family)\n  try {\n    const data = await cache.getItem<T>(key)\n    return data ?? null\n  } catch {\n    return null\n  }\n}\n\n/**\n * Cache metadata for a font family\n */\nexport async function setCachedMetadata<T>(\n  family: string,\n  data: T\n): Promise<void> {\n  const cache = getCache()\n  if (!cache) return\n\n  const key = getMetadataCacheKey(family)\n  try {\n    await cache.setItem(key, data as unknown as Parameters<typeof cache.setItem>[1])\n  } catch (error) {\n    console.warn(`[vite-fonts] Failed to cache metadata for ${family}:`, error)\n  }\n}\n\n/**\n * Download a font file with caching\n */\nexport async function downloadFont(url: string): Promise<Buffer> {\n  // Check cache first\n  const cached = await getCachedFont(url)\n  if (cached) {\n    return cached\n  }\n\n  // Download the font\n  try {\n    const response = await fetch(url, {\n      headers: {\n        // Some providers check user-agent\n        \"User-Agent\":\n          \"Mozilla/5.0 (compatible; vite-fonts/1.0; +https://github.com/your-repo)\",\n      },\n    })\n\n    if (!response.ok) {\n      throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n    }\n\n    const arrayBuffer = await response.arrayBuffer()\n    const buffer = Buffer.from(arrayBuffer)\n\n    // Cache the downloaded font\n    await setCachedFont(url, buffer)\n\n    return buffer\n  } catch (error) {\n    throw new Error(\n      `Failed to download font from ${url}: ${error instanceof Error ? error.message : error}`\n    )\n  }\n}\n\n/**\n * Download multiple fonts in parallel\n */\nexport async function downloadFonts(\n  urls: string[]\n): Promise<Map<string, Buffer>> {\n  const results = new Map<string, Buffer>()\n\n  const downloads = urls.map(async (url) => {\n    try {\n      const buffer = await downloadFont(url)\n      results.set(url, buffer)\n    } catch (error) {\n      console.warn(`[vite-fonts] ${error}`)\n    }\n  })\n\n  await Promise.all(downloads)\n\n  return results\n}\n\n/**\n * Clear the font cache\n */\nexport async function clearCache(): Promise<void> {\n  const cache = getCache()\n  if (!cache) return\n\n  try {\n    await cache.clear()\n  } catch (error) {\n    console.warn(\"[vite-fonts] Failed to clear cache:\", error)\n  }\n}\n\n/**\n * Clean up storage instance\n */\nexport function destroyCache(): void {\n  storageInstance = null\n}\n","import type { Plugin, ResolvedConfig, ViteDevServer } from \"vite\"\nimport type { ViteFontsOptions, ResolvedOptions, PluginState } from \"./types.js\"\nimport {\n  extractFontsFromCSS,\n  shouldProcessFile,\n  extractCSSFromFile,\n} from \"./css-parser.js\"\nimport {\n  initializeUnifont,\n  resolveFonts,\n  generateFontFaceCSS,\n  generateFontFaceCSSWithLocalUrls,\n  extractFontUrls,\n  destroyUnifont,\n} from \"./font-resolver.js\"\nimport { generateFallbackCSS } from \"./fallback.js\"\nimport { initializeCache, downloadFonts, destroyCache } from \"./cache.js\"\n\nconst PLUGIN_NAME = \"vite-fonts\"\nconst VIRTUAL_MODULE_ID = \"virtual:fonts.css\"\nconst RESOLVED_VIRTUAL_MODULE_ID = `\\0${VIRTUAL_MODULE_ID}`\n\n/**\n * Resolve user options with defaults\n */\nfunction resolveOptions(options: ViteFontsOptions = {}): ResolvedOptions {\n  return {\n    defaults: {\n      weights: options.defaults?.weights ?? [400, 700],\n      styles: options.defaults?.styles ?? [\"normal\"],\n      subsets: options.defaults?.subsets ?? [\"latin\"],\n      display: options.defaults?.display ?? \"swap\",\n    },\n    families: options.families\n      ? Object.fromEntries(\n          Object.entries(options.families).map(([key, value]) => [\n            key,\n            value === true ? {} : value,\n          ])\n        )\n      : {},\n    providers: {\n      bunny: options.providers?.bunny ?? true,\n      fontsource: options.providers?.fontsource ?? true,\n      google: options.providers?.google ?? false,\n      local: options.providers?.local ?? true,\n    },\n    fallbacks: options.fallbacks ?? true,\n    cache: options.cache ?? true,\n    cacheDir: options.cacheDir ?? \"node_modules/.cache/vite-fonts\",\n    assetsDir: options.assetsDir ?? \"fonts\",\n    inject: options.inject ?? \"inline\",\n    debug: options.debug ?? false,\n  }\n}\n\n/**\n * Create the vite-fonts plugin\n */\nexport function viteFonts(userOptions: ViteFontsOptions = {}): Plugin {\n  const options = resolveOptions(userOptions)\n  let config: ResolvedConfig\n  let isProduction = false\n\n  // Plugin state\n  const state: PluginState = {\n    detectedFonts: new Map(),\n    resolvedFaces: [],\n    fontAssets: new Map(),\n    fontFaceCSS: \"\",\n    fallbackCSS: \"\",\n  }\n\n  // Track if we've initialized\n  let initialized = false\n\n  const log = (message: string, ...args: unknown[]) => {\n    if (options.debug) {\n      console.log(`[${PLUGIN_NAME}] ${message}`, ...args)\n    }\n  }\n\n  return {\n    name: PLUGIN_NAME,\n    enforce: \"pre\",\n\n    async configResolved(resolvedConfig) {\n      config = resolvedConfig\n      isProduction = config.command === \"build\"\n\n      // Initialize cache\n      const storage = initializeCache(options)\n\n      // Initialize unifont with providers\n      await initializeUnifont(options, options.cache ? storage : undefined)\n\n      initialized = true\n      log(\"Initialized with options:\", options)\n    },\n\n    resolveId(id) {\n      if (id === VIRTUAL_MODULE_ID) {\n        return RESOLVED_VIRTUAL_MODULE_ID\n      }\n    },\n\n    async load(id) {\n      if (id === RESOLVED_VIRTUAL_MODULE_ID) {\n        // Return the generated font CSS\n        // This will be populated after all CSS has been processed\n        return state.fontFaceCSS + \"\\n\" + state.fallbackCSS\n      }\n    },\n\n    async transform(code, id) {\n      if (!initialized) return null\n      if (!shouldProcessFile(id)) return null\n\n      // Extract CSS blocks from the file\n      const cssBlocks = extractCSSFromFile(code, id)\n      if (cssBlocks.length === 0) return null\n\n      let hasNewFonts = false\n\n      for (const css of cssBlocks) {\n        const detected = extractFontsFromCSS(css, id)\n\n        for (const font of detected) {\n          const key = font.family.toLowerCase()\n          if (!state.detectedFonts.has(key)) {\n            state.detectedFonts.set(key, font)\n            hasNewFonts = true\n            log(`Detected font: ${font.family} in ${id}`)\n          }\n        }\n      }\n\n      // If we detected new fonts, resolve them\n      if (hasNewFonts) {\n        await resolveFontsAndGenerateCSS()\n      }\n\n      return null // Don't modify the source, we inject CSS separately\n    },\n\n    configureServer(server: ViteDevServer) {\n      // Serve font files during development\n      server.middlewares.use(async (req, res, next) => {\n        if (!req.url?.startsWith(\"/_fonts/\")) {\n          return next()\n        }\n\n        const fontPath = req.url.replace(\"/_fonts/\", \"\")\n        const asset = state.fontAssets.get(fontPath)\n\n        if (asset) {\n          // Determine content type\n          const ext = fontPath.split(\".\").pop()\n          const contentType =\n            ext === \"woff2\"\n              ? \"font/woff2\"\n              : ext === \"woff\"\n                ? \"font/woff\"\n                : ext === \"ttf\"\n                  ? \"font/ttf\"\n                  : \"application/octet-stream\"\n\n          res.setHeader(\"Content-Type\", contentType)\n          res.setHeader(\"Cache-Control\", \"public, max-age=31536000, immutable\")\n          res.end(asset.content)\n          return\n        }\n\n        next()\n      })\n    },\n\n    transformIndexHtml: {\n      order: \"post\",\n      handler(html) {\n        if (!state.fontFaceCSS && !state.fallbackCSS) {\n          return html\n        }\n\n        const css = state.fontFaceCSS + \"\\n\" + state.fallbackCSS\n\n        if (options.inject === \"inline\") {\n          // Inject as inline <style> tag\n          const styleTag = `<style data-vite-fonts>\\n${css}\\n</style>`\n          return html.replace(\"</head>\", `${styleTag}\\n</head>`)\n        } else {\n          // Inject as link to virtual module\n          const linkTag = `<link rel=\"stylesheet\" href=\"/${VIRTUAL_MODULE_ID}\">`\n          return html.replace(\"</head>\", `${linkTag}\\n</head>`)\n        }\n      },\n    },\n\n    async generateBundle(_outputOptions, _bundle) {\n      if (!isProduction) return\n\n      // Final resolution of all fonts\n      await resolveFontsAndGenerateCSS()\n\n      // Download all font files\n      const fontUrls = extractFontUrls(state.resolvedFaces)\n      log(`Downloading ${fontUrls.length} font files...`)\n\n      const downloads = await downloadFonts(fontUrls)\n\n      // Create URL mapping for local paths\n      const urlMap = new Map<string, string>()\n\n      for (const [sourceUrl, content] of downloads) {\n        // Generate a hashed filename\n        const ext = sourceUrl.split(\".\").pop() ?? \"woff2\"\n        const hash = generateHash(content)\n        const fileName = `${options.assetsDir}/${hash}.${ext}`\n\n        urlMap.set(sourceUrl, `/${fileName}`)\n\n        // Emit the font file\n        this.emitFile({\n          type: \"asset\",\n          fileName,\n          source: content,\n        })\n\n        log(`Emitted font: ${fileName}`)\n      }\n\n      // Regenerate CSS with local URLs\n      const localCSS = generateFontFaceCSSWithLocalUrls(\n        state.resolvedFaces,\n        urlMap\n      )\n\n      // Emit the fonts CSS file if using external injection\n      if (options.inject === \"external\") {\n        const cssHash = generateHash(Buffer.from(localCSS + state.fallbackCSS))\n        const cssFileName = `${options.assetsDir}/fonts.${cssHash.slice(0, 8)}.css`\n\n        this.emitFile({\n          type: \"asset\",\n          fileName: cssFileName,\n          source: localCSS + \"\\n\" + state.fallbackCSS,\n        })\n      }\n\n      // Update state for index.html transformation\n      state.fontFaceCSS = localCSS\n    },\n\n    buildEnd() {\n      // Cleanup\n      destroyUnifont()\n      destroyCache()\n    },\n  }\n\n  /**\n   * Resolve detected fonts and generate CSS\n   */\n  async function resolveFontsAndGenerateCSS(): Promise<void> {\n    const detectedArray = Array.from(state.detectedFonts.values())\n\n    if (detectedArray.length === 0) {\n      state.fontFaceCSS = \"\"\n      state.fallbackCSS = \"\"\n      return\n    }\n\n    // Resolve fonts using unifont\n    state.resolvedFaces = await resolveFonts(detectedArray, options)\n\n    if (state.resolvedFaces.length === 0) {\n      log(\"No fonts could be resolved\")\n      return\n    }\n\n    log(`Resolved ${state.resolvedFaces.length} font faces`)\n\n    // Generate @font-face CSS\n    // In dev mode, use remote URLs; in build, we'll replace with local URLs later\n    state.fontFaceCSS = generateFontFaceCSS(state.resolvedFaces)\n\n    // Generate fallback CSS if enabled\n    if (options.fallbacks) {\n      state.fallbackCSS = await generateFallbackCSS(\n        detectedArray,\n        state.resolvedFaces\n      )\n    }\n\n    // In dev mode, download fonts for the middleware to serve\n    if (!isProduction) {\n      const fontUrls = extractFontUrls(state.resolvedFaces)\n      const downloads = await downloadFonts(fontUrls)\n\n      // Store for dev server middleware\n      const urlMap = new Map<string, string>()\n      for (const [sourceUrl, content] of downloads) {\n        const ext = sourceUrl.split(\".\").pop() ?? \"woff2\"\n        const hash = generateHash(content)\n        const localPath = `${hash}.${ext}`\n\n        urlMap.set(sourceUrl, `/_fonts/${localPath}`)\n        state.fontAssets.set(localPath, {\n          sourceUrl,\n          fileName: localPath,\n          content,\n        })\n      }\n\n      // Update CSS to use local dev URLs\n      state.fontFaceCSS = generateFontFaceCSSWithLocalUrls(\n        state.resolvedFaces,\n        urlMap\n      )\n    }\n  }\n}\n\n/**\n * Generate a short hash from content\n */\nfunction generateHash(content: Buffer): string {\n  let hash = 0\n  for (let i = 0; i < content.length; i++) {\n    const byte = content[i]!\n    hash = ((hash << 5) - hash) + byte\n    hash = hash & hash\n  }\n  return Math.abs(hash).toString(36).padStart(8, \"0\")\n}\n"],"mappings":"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"}