{
  "version": 3,
  "sources": ["../../src/html/mergeDocumentHead.ts", "../../src/lib/getMetaAsDict.ts", "../../src/meta/builder.ts"],
  "sourcesContent": ["import { isString } from '@xylabs/typeof'\nimport { load } from 'cheerio'\n\nconst opts = {}\n// const opts = { decodeEntities: false }\n\n/**\n * Merges meta tags from the source HTML head into the destination HTML head.\n * Existing meta tags with matching property attributes are replaced; others are appended.\n * @param destination - The base HTML string to merge into.\n * @param source - The HTML string whose head meta tags will be merged.\n * @returns The merged HTML string.\n */\nexport const mergeDocumentHead = (destination: string, source: string) => {\n  const $destination = load(destination, opts)\n  const $source = load(source, opts)\n\n  // For each child node of the source head\n  $source('head')\n    .children()\n    .each((_, element) => {\n      const el = $destination(element)\n\n      // Special case for meta tags: We want to match them by the name attribute\n      if (el[0].tagName === 'meta') {\n        const property = el.attr('property')\n        if (isString(property)) {\n          const match = $destination(`head meta[property=\"${property}\"]`)\n\n          // If it exists, replace it, otherwise append it\n          if (match.length > 0) {\n            match.replaceWith(el)\n            return\n          } else {\n            $destination('head').append(el)\n          }\n        }\n        // else {\n        //   // For all other elements, just check if the same element exists in the first HTML string\n        //   const match = $destination(el[0].tagName)\n\n        //   // If it exists, replace it, otherwise append it\n        //   if (match.length > 0) {\n        //     match.replaceWith(el)\n        //   } else {\n        //     $destination('head').append(el)\n        //   }\n        // }\n      }\n    })\n\n  // Return the merged HTML\n  return $destination.html(opts)\n}\n", "import { isString } from '@xylabs/typeof'\n\n/** An object with string keys and arbitrary values, used for recursive meta flattening. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type StringIndexable = Record<string, any>\n\nconst propertyDelimiter = ':'\n\n/**\n * Recursively flattens a nested meta object into a flat dictionary with colon-delimited keys.\n * @param obj - The nested object to flatten.\n * @param parentKey - The accumulated key prefix from parent levels.\n * @returns A flat record mapping colon-delimited property names to string values.\n */\nexport const getMetaAsDict = (obj: StringIndexable, parentKey?: string): Record<string, string> => {\n  let flatRecord: StringIndexable = {}\n  for (const key in obj) {\n    if (typeof obj[key] === 'object' && obj[key] !== null) {\n      // If the value is another object, we want to iterate through its keys as well.\n      const childRecord = getMetaAsDict(obj[key] as StringIndexable, `${isString(parentKey) ? parentKey : ''}${key}${propertyDelimiter}`)\n      flatRecord = { ...flatRecord, ...childRecord }\n    } else {\n      // Concatenate the key with its parent key.\n      const newKey = isString(parentKey) ? `${parentKey}${key}` : key\n      const trimmed = newKey.endsWith(propertyDelimiter) ? newKey.slice(0, -1) : newKey\n      flatRecord[trimmed] = `${obj[key]}`\n    }\n  }\n  return flatRecord\n}\n", "import { isString } from '@xylabs/typeof'\nimport type { CheerioAPI } from 'cheerio'\nimport { load } from 'cheerio'\n\nimport { getMetaAsDict } from '../lib/index.ts'\nimport type { Meta } from '../models/index.ts'\n\n/* test change */\n\n/**\n * Adds or replaces a meta tag in the document head.\n * @param $ - The Cheerio API instance for the document.\n * @param name - The meta property name.\n * @param value - The meta content value (string, array, or nested object).\n */\nexport const addMetaToHead = ($: CheerioAPI, name: string, value: string | object) => {\n  if (typeof value === 'string') {\n    const newMeta = `<meta property=\"${name}\" content=\"${value}\" />`\n    const existingMeta = $(`head meta[property=\"${name}\"]`)\n    if ((existingMeta?.length ?? 0) > 0) {\n      existingMeta.replaceWith(newMeta)\n    } else {\n      $('head').append(newMeta)\n    }\n  } else if (Array.isArray(value)) {\n    for (const item of value) addMetaToHead($, `${name}`, item)\n  } else if (typeof value === 'object') {\n    for (const [key, v] of Object.entries(value)) {\n      if (key === 'url') {\n        addMetaToHead($, name, v)\n      } else {\n        addMetaToHead($, `${name}:${key}`, v)\n      }\n    }\n  } else {\n    throw new TypeError(`Invalid item type [${name}, ${typeof value}]`)\n  }\n}\n\n/**\n * Injects meta properties, title, and description into an HTML string.\n * @param html - The base HTML string to modify.\n * @param meta - The metadata to inject.\n * @param handler - Optional meta-handler property value to include.\n * @returns The modified HTML string with injected metadata.\n */\nexport const metaBuilder = (html: string, meta: Meta, handler?: string) => {\n  const $ = load(html)\n  // NOTE: This assumes unique meta properties (no duplicates)\n  // which is generally the case, but not always (you can have\n  // multiple og:video:tag tags, for example)\n  const metaProperties = getMetaAsDict(meta)\n  for (const [key, value] of Object.entries(metaProperties)) {\n    addMetaToHead($, key, value)\n  }\n  if (isString(meta.description)) {\n    addMetaToHead($, 'description', meta.description)\n  }\n  if (isString(meta.title)) {\n    $('title').text(meta.title)\n  }\n  if (isString(handler)) {\n    addMetaToHead($, 'meta-handler', handler)\n  }\n  return $.html()\n}\n"],
  "mappings": "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",
  "names": ["isString", "isString", "load", "load", "isString"]
}
