mark-deco 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/browser.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  /*!
3
3
  * name: mark-deco
4
- * version: 0.17.0
4
+ * version: 0.19.0
5
5
  * description: Flexible Markdown to HTML conversion library
6
6
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
7
7
  * license: MIT
8
8
  * repository.url: https://github.com/kekyo/mark-deco
9
- * git.commit.hash: 50ed26c3accc15bee0957672d131f1a905d82351
9
+ * git.commit.hash: 0383f6b5dacf8b3d9c8d54b9ffad5180b3f58bea
10
10
  */
11
11
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
12
12
  const asyncPrimitives = require("async-primitives");
package/dist/browser.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /*!
2
2
  * name: mark-deco
3
- * version: 0.17.0
3
+ * version: 0.19.0
4
4
  * description: Flexible Markdown to HTML conversion library
5
5
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
6
6
  * license: MIT
7
7
  * repository.url: https://github.com/kekyo/mark-deco
8
- * git.commit.hash: 50ed26c3accc15bee0957672d131f1a905d82351
8
+ * git.commit.hash: 0383f6b5dacf8b3d9c8d54b9ffad5180b3f58bea
9
9
  */
10
10
 
11
11
  /**
package/dist/browser.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  /*!
2
2
  * name: mark-deco
3
- * version: 0.17.0
3
+ * version: 0.19.0
4
4
  * description: Flexible Markdown to HTML conversion library
5
5
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
6
6
  * license: MIT
7
7
  * repository.url: https://github.com/kekyo/mark-deco
8
- * git.commit.hash: 50ed26c3accc15bee0957672d131f1a905d82351
8
+ * git.commit.hash: 0383f6b5dacf8b3d9c8d54b9ffad5180b3f58bea
9
9
  */
10
10
  import { createMutex } from "async-primitives";
11
11
  const createLocalCacheStorage = (keyPrefix = "cache:") => {
@@ -1,14 +1,14 @@
1
1
  "use strict";
2
2
  /*!
3
3
  * name: mark-deco
4
- * version: 0.17.0
4
+ * version: 0.19.0
5
5
  * description: Flexible Markdown to HTML conversion library
6
6
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
7
7
  * license: MIT
8
8
  * repository.url: https://github.com/kekyo/mark-deco
9
- * git.commit.hash: 50ed26c3accc15bee0957672d131f1a905d82351
9
+ * git.commit.hash: 0383f6b5dacf8b3d9c8d54b9ffad5180b3f58bea
10
10
  */
11
- const utils = require("./utils-DFcJBcGu.cjs");
11
+ const utils = require("./utils-Tvge9ukB.cjs");
12
12
  const cheerio = require("cheerio");
13
13
  function _interopNamespaceDefault(e) {
14
14
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -682,7 +682,7 @@ const wrapWithResponsiveContainer = (html, aspectRatio) => {
682
682
  const ogpRules = [
683
683
  {
684
684
  // Match any URL as fallback
685
- pattern: "^https?://",
685
+ patterns: ["^https?://"],
686
686
  locale: "auto",
687
687
  siteName: "Generic Site",
688
688
  fields: {
@@ -902,6 +902,16 @@ const extractLocaleFromHTML = ($) => {
902
902
  if (languageMeta) return languageMeta;
903
903
  return void 0;
904
904
  };
905
+ const normalizePatternList = (value) => {
906
+ if (!value) return [];
907
+ return value.map((pattern) => pattern.trim()).filter(Boolean);
908
+ };
909
+ const getRulePatterns = (rule) => {
910
+ return normalizePatternList(rule.patterns);
911
+ };
912
+ const getRulePostFilters = (rule) => {
913
+ return normalizePatternList(rule.postFilters);
914
+ };
905
915
  const executeProcessorRule = (rule, values, _context) => {
906
916
  const params = rule.params || {};
907
917
  switch (rule.type) {
@@ -1079,8 +1089,11 @@ const extractFieldWithRules = (rules, $, context, fieldName, logger) => {
1079
1089
  return void 0;
1080
1090
  };
1081
1091
  const applyScrapingRule = (rule, $, url, logger) => {
1092
+ const patterns = getRulePatterns(rule);
1093
+ const postFilters = getRulePostFilters(rule);
1082
1094
  logger == null ? void 0 : logger.debug("applyScrapingRule: Starting metadata extraction", {
1083
- pattern: rule.pattern,
1095
+ patterns,
1096
+ postFilters: postFilters.length > 0 ? postFilters : void 0,
1084
1097
  siteName: rule.siteName,
1085
1098
  fieldsCount: Object.keys(rule.fields).length
1086
1099
  });
@@ -1139,33 +1152,62 @@ const applyScrapingRule = (rule, $, url, logger) => {
1139
1152
  });
1140
1153
  return extractedData;
1141
1154
  };
1142
- const findMatchingRule = (rules, url, logger) => {
1143
- logger == null ? void 0 : logger.debug("findMatchingRule: Testing rules against URL", {
1155
+ function findMatchingRule(rules, url, postFilterUrlOrLogger, logger) {
1156
+ const hasPostFilterUrl = typeof postFilterUrlOrLogger === "string";
1157
+ const postFilterUrl = hasPostFilterUrl ? postFilterUrlOrLogger : void 0;
1158
+ const resolvedLogger = hasPostFilterUrl ? logger : postFilterUrlOrLogger != null ? postFilterUrlOrLogger : logger;
1159
+ resolvedLogger == null ? void 0 : resolvedLogger.debug("findMatchingRule: Testing rules against URL", {
1144
1160
  url,
1161
+ postFilterUrl,
1145
1162
  rulesCount: rules.length
1146
1163
  });
1147
1164
  for (let i = 0; i < rules.length; i++) {
1148
1165
  const rule = rules[i];
1149
1166
  if (!rule) continue;
1150
- const regex = new RegExp(rule.pattern);
1151
- const matches = regex.test(url);
1152
- logger == null ? void 0 : logger.debug(`findMatchingRule: Rule ${i + 1}/${rules.length}`, {
1153
- pattern: rule.pattern,
1167
+ const patterns = getRulePatterns(rule);
1168
+ if (patterns.length === 0) {
1169
+ resolvedLogger == null ? void 0 : resolvedLogger.debug(`findMatchingRule: Rule ${i + 1}/${rules.length}`, {
1170
+ patterns,
1171
+ matches: false
1172
+ });
1173
+ continue;
1174
+ }
1175
+ const matchesPattern = patterns.some(
1176
+ (pattern) => new RegExp(pattern).test(url)
1177
+ );
1178
+ const postFilters = getRulePostFilters(rule);
1179
+ let matchesPostFilter = true;
1180
+ if (postFilters.length > 0) {
1181
+ if (!postFilterUrl) {
1182
+ matchesPostFilter = false;
1183
+ } else {
1184
+ matchesPostFilter = postFilters.some(
1185
+ (pattern) => new RegExp(pattern).test(postFilterUrl)
1186
+ );
1187
+ }
1188
+ }
1189
+ const matches = matchesPattern && matchesPostFilter;
1190
+ resolvedLogger == null ? void 0 : resolvedLogger.debug(`findMatchingRule: Rule ${i + 1}/${rules.length}`, {
1191
+ patterns,
1192
+ postFilters: postFilters.length > 0 ? postFilters : void 0,
1154
1193
  siteName: rule.siteName,
1155
- matches
1194
+ matches,
1195
+ matchesPattern,
1196
+ matchesPostFilter
1156
1197
  });
1157
1198
  if (matches) {
1158
- logger == null ? void 0 : logger.debug("findMatchingRule: Found matching rule", {
1199
+ resolvedLogger == null ? void 0 : resolvedLogger.debug("findMatchingRule: Found matching rule", {
1159
1200
  ruleIndex: i + 1,
1160
- pattern: rule.pattern,
1201
+ patterns,
1202
+ postFilters: postFilters.length > 0 ? postFilters : void 0,
1161
1203
  siteName: rule.siteName
1162
1204
  });
1163
1205
  return rule;
1164
1206
  }
1165
1207
  }
1166
- logger == null ? void 0 : logger.debug("findMatchingRule: No matching rule found");
1208
+ resolvedLogger == null ? void 0 : resolvedLogger.debug("findMatchingRule: No matching rule found");
1167
1209
  return void 0;
1168
- };
1210
+ }
1169
1211
  const isValidUrl = (url) => {
1170
1212
  try {
1171
1213
  new URL(url);
@@ -1220,22 +1262,31 @@ const buildRuleSet = (customRules = []) => [
1220
1262
  ...ogpRules
1221
1263
  // OGP rules as fallback
1222
1264
  ];
1223
- const extractEnhancedData = ($, sourceUrl, customRules, logger) => {
1265
+ const extractEnhancedData = ($, sourceUrl, customRules, logger, postFilterUrl) => {
1224
1266
  const rules = buildRuleSet(customRules);
1225
1267
  logger == null ? void 0 : logger.debug("extractEnhancedData: Starting rule matching process", {
1226
1268
  url: sourceUrl,
1269
+ postFilterUrl,
1227
1270
  totalRules: rules.length,
1228
1271
  customRulesCount: (customRules == null ? void 0 : customRules.length) || 0,
1229
1272
  ogpRulesCount: ogpRules.length
1230
1273
  });
1231
- const matchingRule = findMatchingRule(rules, sourceUrl, logger);
1274
+ const matchingRule = findMatchingRule(
1275
+ rules,
1276
+ sourceUrl,
1277
+ postFilterUrl,
1278
+ logger
1279
+ );
1232
1280
  if (matchingRule) {
1233
1281
  logger == null ? void 0 : logger.debug("extractEnhancedData: Found matching rule", {
1234
- pattern: matchingRule.pattern,
1282
+ patterns: matchingRule.patterns,
1283
+ postFilters: matchingRule.postFilters,
1235
1284
  siteName: matchingRule.siteName,
1236
1285
  fieldsToExtract: Object.keys(matchingRule.fields)
1237
1286
  });
1238
- const result = applyScrapingRule(matchingRule, $, sourceUrl, logger);
1287
+ const hasPostFilters = Array.isArray(matchingRule.postFilters) && matchingRule.postFilters.length > 0;
1288
+ const contextUrl = hasPostFilters && postFilterUrl ? postFilterUrl : sourceUrl;
1289
+ const result = applyScrapingRule(matchingRule, $, contextUrl, logger);
1239
1290
  logger == null ? void 0 : logger.debug("extractEnhancedData: Rule application completed", {
1240
1291
  extractedFields: Object.keys(result),
1241
1292
  successfulFieldsCount: Object.keys(result).length
@@ -1252,16 +1303,18 @@ const fetchMetadata = async (url, options, context) => {
1252
1303
  const { logger, signal, fetcher } = context;
1253
1304
  logger.info("fetchMetadata: Starting metadata extraction for URL:", url);
1254
1305
  try {
1255
- const htmlContent = await utils.fetchText(
1256
- fetcher,
1257
- url,
1258
- "text/html",
1259
- signal,
1260
- logger
1261
- );
1306
+ const response = await fetcher.rawFetcher(url, "text/html", signal, logger);
1307
+ const htmlContent = await response.text();
1262
1308
  logger.info("fetchMetadata: Successfully fetched HTML content");
1263
1309
  const $ = cheerio__namespace.load(htmlContent);
1264
- const metadata = extractEnhancedData($, url, options.scrapingRules, logger);
1310
+ const postFilterUrl = resolvePostFilterUrl($, url, response.url);
1311
+ const metadata = extractEnhancedData(
1312
+ $,
1313
+ url,
1314
+ options.scrapingRules,
1315
+ logger,
1316
+ postFilterUrl
1317
+ );
1265
1318
  if (metadata === null || Object.keys(metadata).length === 0) {
1266
1319
  const domain = new URL(url).hostname.replace(/^www\./, "");
1267
1320
  logger.debug(
@@ -1302,6 +1355,21 @@ const fetchMetadata = async (url, options, context) => {
1302
1355
  throw error;
1303
1356
  }
1304
1357
  };
1358
+ const resolvePostFilterUrl = ($, originalUrl, responseUrl) => {
1359
+ var _a, _b, _c;
1360
+ const trimmedResponseUrl = responseUrl == null ? void 0 : responseUrl.trim();
1361
+ if (trimmedResponseUrl) {
1362
+ return trimmedResponseUrl;
1363
+ }
1364
+ const ogUrl = (_a = $('meta[property="og:url"]').attr("content")) == null ? void 0 : _a.trim();
1365
+ const canonicalUrl = (_b = $('link[rel="canonical"]').attr("href")) == null ? void 0 : _b.trim();
1366
+ const twitterUrl = (_c = $('meta[name="twitter:url"]').attr("content")) == null ? void 0 : _c.trim();
1367
+ const candidate = ogUrl || canonicalUrl || twitterUrl;
1368
+ if (!candidate) {
1369
+ return void 0;
1370
+ }
1371
+ return resolveUrl(candidate, originalUrl);
1372
+ };
1305
1373
  const generateFallbackHtml = (url, errorInfo) => {
1306
1374
  const domain = extractDomain(url);
1307
1375
  let errorMessage = "Content not accessible";
@@ -1541,4 +1609,4 @@ exports.isValidUrl = isValidUrl$1;
1541
1609
  exports.isValidUrl$1 = isValidUrl;
1542
1610
  exports.resolveUrl = resolveUrl;
1543
1611
  exports.truncateText = truncateText;
1544
- //# sourceMappingURL=html-generator-1BkRM5Oq.cjs.map
1612
+ //# sourceMappingURL=html-generator-B9rrVTtd.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-generator-B9rrVTtd.cjs","sources":["../src/plugins/oembed/utils.ts","../src/utils/responsive-image.ts","../src/plugins/shared/error-formatter.ts","../src/plugins/oembed/providers.ts","../src/plugins/oembed/redirect-resolver.ts","../src/plugins/oembed/fetcher.ts","../src/plugins/oembed/html-generator.ts","../src/plugins/card/ogp-rules.ts","../src/plugins/card/rule-engine.ts","../src/plugins/card/utils.ts","../src/plugins/card/fetcher.ts","../src/plugins/card/html-generator.ts"],"sourcesContent":["// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\n/**\n * Validate URL format\n */\nexport const isValidUrl = (url: string): boolean => {\n try {\n new URL(url);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Escape HTML characters\n */\nexport const escapeHtml = (text: string): string => {\n const map: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#039;',\n };\n return text.replace(/[&<>\"']/g, (m) => map[m] || m);\n};\n\n/**\n * Calculate aspect ratio from width and height\n */\nexport const calculateAspectRatio = (\n width?: number,\n height?: number\n): number | null => {\n // When both are valid numbers\n if (width && height && width > 0 && height > 0) {\n const ratio = (height / width) * 100;\n // Limit extreme aspect ratios (range from 1:10 to 10:1)\n if (ratio >= 10 && ratio <= 1000) {\n return ratio;\n }\n }\n\n // When only one is provided, complement with 16:9\n if (width && width > 0 && (!height || height <= 0)) {\n // Width only: calculate height with 16:9\n const calculatedHeight = (width * 9) / 16;\n return (calculatedHeight / width) * 100; // = 56.25\n }\n\n if (height && height > 0 && (!width || width <= 0)) {\n // Height only: calculate width with 16:9\n const calculatedWidth = (height * 16) / 9;\n return (height / calculatedWidth) * 100; // = 56.25\n }\n\n return null;\n};\n\n/**\n * Extract aspect ratio from HTML iframe attributes\n */\nexport const extractAspectRatioFromHtml = (html: string): number | null => {\n // Target only the first iframe tag found\n const iframeMatch = html.match(/<iframe[^>]*>/i);\n if (!iframeMatch) return null;\n\n const firstIframe = iframeMatch[0];\n\n // Extract width attribute (numbers only)\n const widthMatch = firstIframe.match(/width=['\"]?(\\d+)['\"]?/i);\n // Extract height attribute (numbers only)\n const heightMatch = firstIframe.match(/height=['\"]?(\\d+)['\"]?/i);\n\n const width = widthMatch && widthMatch[1] ? parseInt(widthMatch[1], 10) : 0;\n const height =\n heightMatch && heightMatch[1] ? parseInt(heightMatch[1], 10) : 0;\n\n // Calculate using calculateAspectRatio (including 16:9 complement)\n // 0 is treated as undefined\n return calculateAspectRatio(width || undefined, height || undefined);\n};\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\n/**\n * Generate responsive image HTML with inline styles for aspect ratio preservation\n */\n\n/**\n * Generate inline styles for responsive images\n * These styles ensure images scale responsively while maintaining aspect ratio\n * and fit within their container using object-fit: contain (inscribed scaling)\n * Uses width: 100% to enable both scaling up and down to fit the container\n */\nexport const generateResponsiveImageStyles = (): string => {\n return 'width: 100%; height: auto; display: block; object-fit: contain; object-position: center;';\n};\n\n/**\n * Generate a responsive image tag with inline styles\n * @param src - Image source URL\n * @param alt - Alt text for accessibility\n * @param title - Optional title attribute\n * @param additionalAttrs - Additional HTML attributes as string\n * @returns Complete img tag with responsive styles\n */\nexport const createResponsiveImageTag = (\n src: string,\n alt: string,\n title?: string,\n additionalAttrs?: string\n): string => {\n const styles = generateResponsiveImageStyles();\n const titleAttr = title ? ` title=\"${title}\"` : '';\n const extraAttrs = additionalAttrs ? ` ${additionalAttrs}` : '';\n\n return `<img src=\"${src}\" alt=\"${alt}\"${titleAttr} style=\"${styles}\"${extraAttrs} />`;\n};\n\n/**\n * Generate responsive image HTML wrapped in a container with aspect ratio preservation\n * @param src - Image source URL\n * @param alt - Alt text for accessibility\n * @param containerClass - CSS class for the container\n * @param title - Optional title attribute\n * @param additionalAttrs - Additional HTML attributes as string\n * @returns Complete responsive image HTML with container\n */\nexport const createResponsiveImageWithContainer = (\n src: string,\n alt: string,\n containerClass: string,\n title?: string,\n additionalAttrs?: string\n): string => {\n const imageTag = createResponsiveImageTag(src, alt, title, additionalAttrs);\n\n return `<div class=\"${containerClass}\">\n ${imageTag}\n </div>`;\n};\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\n/**\n * Format error information in a consistent way across browsers\n * Attempts to use error constructor name and message, falls back to toString()\n */\nexport const formatErrorInfo = (error: unknown): string | undefined => {\n if (!error) {\n return undefined;\n }\n\n try {\n // Try to extract constructor name and message\n if (error instanceof Error) {\n const typeName = error.constructor?.name || 'Error';\n const message = error.message || '';\n\n if (message) {\n // Format as: TypeName[message]\n return `${typeName}[${message}]`;\n } else {\n // Format as: TypeName (no message available)\n return typeName;\n }\n }\n\n // For non-Error objects, try to get constructor name\n if (typeof error === 'object' && error !== null) {\n const typeName = (error as { constructor?: { name?: string } })\n .constructor?.name;\n if (typeName && typeName !== 'Object') {\n const message = (error as { message?: string }).message;\n if (message) {\n return `${typeName}[${message}]`;\n } else {\n return typeName;\n }\n }\n }\n\n // Fall back to toString() if we can't get structured information\n return String(error);\n } catch {\n // If all else fails, use toString() as ultimate fallback\n try {\n return String(error);\n } catch {\n // If even toString() fails, return a safe default\n return 'Unknown error';\n }\n }\n};\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\nimport { fetchText, isCORSError } from '../../utils';\nimport downloadedProvidersJson from './providers.json' with { type: 'json' };\nimport type { OEmbedProvider } from './types';\nimport type { MarkdownProcessorPluginContext } from '../../types';\n\n/**\n * Default providers from downloaded providers.json\n * Downloaded from https://oembed.com/providers.json\n *\n * Export this if you want to use the built-in provider list,\n * or provide your own custom providers to buildProvidersCache.\n */\nexport const defaultProviderList: OEmbedProvider[] =\n downloadedProvidersJson as OEmbedProvider[];\n\n/**\n * Decode HTML entities in a string\n * @param str - String containing HTML entities\n * @returns Decoded string with entities replaced\n */\nconst decodeHtmlEntities = (str: string): string => {\n const entities: Record<string, string> = {\n '&amp;': '&',\n '&lt;': '<',\n '&gt;': '>',\n '&quot;': '\"',\n '&#x27;': \"'\",\n '&#x3D;': '=',\n '&#x2F;': '/',\n '&#x60;': '`',\n };\n\n return str.replace(\n /&(?:amp|lt|gt|quot|#x27|#x3D|#x2F|#x60);/g,\n (match) => entities[match] || match\n );\n};\n\n/**\n * Check if URL matches a scheme pattern\n * @param url - URL to check\n * @param scheme - Scheme pattern to match against\n * @returns True if URL matches the scheme pattern\n */\nconst matchesScheme = (url: string, scheme: string): boolean => {\n // Convert scheme to regex pattern\n const regexPattern = scheme\n .replace(/\\./g, '\\\\.') // Escape dots\n .replace(/\\*/g, '.*') // * matches anything including slash\n .replace(/\\?\\*$/, '.*'); // Handle query parameters\n\n const regex = new RegExp(`^${regexPattern}$`, 'i');\n return regex.test(url);\n};\n\n/**\n * Build a cache mapping schemes to oEmbed endpoints\n * @param param0 - Plugin context containing logger\n * @param providers - List of oEmbed providers\n * @returns Promise resolving to a Map of schemes to endpoint URLs\n */\nexport const buildProvidersCache = async (\n { logger }: MarkdownProcessorPluginContext,\n providers: OEmbedProvider[]\n): Promise<Map<string, string>> => {\n const cache = new Map<string, string>();\n\n logger.info(\n 'buildProvidersCache: Using providers, length=' + providers.length\n );\n\n for (const provider of providers) {\n for (const endpoint of provider.endpoints) {\n if (endpoint.schemes) {\n for (const scheme of endpoint.schemes) {\n const cacheKey = scheme.toLowerCase();\n cache.set(cacheKey, endpoint.url);\n }\n }\n }\n }\n\n logger.info('buildProvidersCache: Built cache with', cache.size, 'entries');\n return cache;\n};\n\n/**\n * Find oEmbed endpoint URL for a given content URL\n * @param url - Content URL to find oEmbed endpoint for\n * @param providersCache - Cache of provider schemes to endpoints\n * @param param2 - Plugin context containing logger, signal, and fetcher\n * @returns Promise resolving to the oEmbed endpoint URL\n */\nexport const getOEmbedUrl = async (\n url: string,\n providersCache: Map<string, string>,\n { logger, signal, fetcher }: MarkdownProcessorPluginContext\n): Promise<string> => {\n const urlObj = new URL(url);\n const hostname = urlObj.hostname.toLowerCase();\n\n // Try to find matching provider endpoint by checking schemes\n for (const [scheme, endpointUrl] of providersCache.entries()) {\n if (matchesScheme(url, scheme)) {\n const oembedUrl = new URL(endpointUrl);\n oembedUrl.searchParams.set('url', url);\n oembedUrl.searchParams.set('format', 'json');\n\n logger.info(\n 'getOEmbedUrl: Found matching endpoint for',\n hostname,\n ':',\n endpointUrl\n );\n return oembedUrl.toString();\n }\n }\n\n // If no provider found, try oEmbed discovery\n logger.info(\n 'getOEmbedUrl: No provider found for',\n hostname,\n ', attempting discovery'\n );\n\n try {\n const html = await fetchText(fetcher, url, 'text/html', signal, logger);\n\n // Look for oEmbed discovery links\n const oembedLinkMatch = html.match(\n /<link[^>]*type=['\"]application\\/json\\+oembed['\"][^>]*>/i\n );\n if (oembedLinkMatch) {\n const hrefMatch = oembedLinkMatch[0].match(/href=['\"]([^'\"]+)['\"]/i);\n if (hrefMatch && hrefMatch[1]) {\n const rawUrl = hrefMatch[1];\n // Decode HTML entities in the discovered URL\n const decodedUrl = decodeHtmlEntities(rawUrl);\n const discoveredUrl = new URL(decodedUrl, url).toString();\n logger.info('getOEmbedUrl: Discovered oEmbed endpoint:', discoveredUrl);\n return discoveredUrl;\n }\n }\n } catch (error) {\n if (isCORSError(error)) {\n logger.debug(\n 'getOEmbedUrl: Discovery blocked by CORS restrictions for',\n url\n );\n } else {\n logger.warn('getOEmbedUrl: Discovery failed for', url, ':', error);\n }\n }\n\n throw new Error(`No oEmbed provider found for URL: ${url}`);\n};\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\nimport {\n combineAbortSignals,\n createTimeoutSignal,\n isCORSError,\n} from '../../utils';\nimport type { Logger } from '../../types';\n// Removed unused import\n\n/**\n * Resolve URL redirects to get the final URL\n */\nexport const resolveRedirects = async (\n url: string,\n maxRedirects: number,\n timeoutEachRedirect: number,\n userAgent: string | undefined,\n logger: Logger,\n signal: AbortSignal | undefined\n): Promise<string> => {\n // Default implementation using fetch with manual redirect.\n // Here fetchData (FetcherType) is not used.\n let currentUrl = url;\n let redirectCount = 0;\n\n while (redirectCount < maxRedirects) {\n try {\n const headers: HeadersInit = {};\n if (userAgent) {\n headers['User-Agent'] = userAgent;\n }\n const options: RequestInit = {\n method: 'HEAD',\n redirect: 'manual', // Will cause CORS error in browser environment\n headers,\n };\n const timeoutSignal = createTimeoutSignal(timeoutEachRedirect);\n options.signal = signal\n ? combineAbortSignals(signal, timeoutSignal)\n : timeoutSignal;\n\n const response = await fetch(currentUrl, options);\n\n // Check if it's a redirect response\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n if (location) {\n // Handle relative URLs\n currentUrl = new URL(location, currentUrl).toString();\n redirectCount++;\n continue;\n }\n }\n\n // No more redirects, return current URL\n break;\n } catch (error) {\n if (isCORSError(error)) {\n logger.debug(\n 'resolveRedirects: Browser CORS restrictions prevent redirect resolution for URL:',\n currentUrl\n );\n } else {\n logger.warn(\n 'resolveRedirects: Failed to resolve redirect for URL:',\n currentUrl,\n error\n );\n }\n return currentUrl;\n }\n }\n\n if (redirectCount >= maxRedirects) {\n logger.warn('resolveRedirects: Maximum redirects reached for URL:', url);\n }\n\n return currentUrl;\n};\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\nimport { fetchJson, isBrowser, isCORSError } from '../../utils';\nimport { getOEmbedUrl, buildProvidersCache } from './providers';\nimport { resolveRedirects } from './redirect-resolver';\nimport type { OEmbedResponse, OEmbedProvider } from './types';\nimport type { MarkdownProcessorPluginContext } from '../../types';\n\n/**\n * Custom error class to indicate CORS failure\n */\nexport class CORSError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CORSError';\n }\n}\n\n/**\n * Fetch oEmbed data from provider\n */\nexport const fetchOEmbedData = async (\n url: string,\n maxRedirects: number,\n timeoutEachRedirect: number,\n context: MarkdownProcessorPluginContext,\n providers: OEmbedProvider[]\n): Promise<OEmbedResponse> => {\n const { logger, signal, fetcher } = context;\n\n logger.info('fetchOEmbedData: Starting for URL:', url);\n\n try {\n // Resolve redirects to get the final URL\n const finalUrl = await resolveRedirects(\n url,\n maxRedirects,\n timeoutEachRedirect,\n fetcher.userAgent,\n logger,\n signal\n );\n logger.info(\n 'fetchOEmbedData: Final URL after redirect resolution:',\n finalUrl\n );\n\n // Build providers cache\n const providersCache = await buildProvidersCache(context, providers);\n\n const oembedUrl = await getOEmbedUrl(finalUrl, providersCache, context);\n logger.info('fetchOEmbedData: oEmbed API URL:', oembedUrl);\n\n const data = await fetchJson<OEmbedResponse>(\n fetcher,\n oembedUrl,\n signal,\n logger\n );\n logger.info('fetchOEmbedData: Parsed JSON data:', data);\n\n // Add web_page if not provided\n if (!data.web_page) {\n data.web_page = finalUrl;\n }\n\n return data;\n } catch (error: unknown) {\n // Check if this is a CORS error and wrap it appropriately\n if (isCORSError(error)) {\n if (isBrowser()) {\n logger.debug(\n 'fetchOEmbedData: Browser CORS restrictions block oEmbed API access for URL:',\n url\n );\n } else {\n logger.warn(\n 'fetchOEmbedData: CORS error detected for URL:',\n url,\n error\n );\n }\n throw new CORSError(\n `CORS restrictions prevent accessing oEmbed data for ${url}`\n );\n }\n\n // Re-throw other errors as-is\n throw error;\n }\n};\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\nimport {\n createResponsiveImageWithContainer,\n createResponsiveImageTag,\n} from '../../utils/responsive-image';\nimport {\n escapeHtml,\n calculateAspectRatio,\n extractAspectRatioFromHtml,\n} from './utils';\nimport type { OEmbedResponse, OEmbedPluginOptions } from './types';\n\n/**\n * Generate fallback HTML for unsupported providers\n */\nexport const generateFallbackHtml = (\n url: string,\n errorInfo?: string\n): string => {\n const urlObj = new URL(url);\n const domain = urlObj.hostname.replace(/^www\\./, '');\n\n const errorIndicator = errorInfo ? ` (Failed by ${errorInfo})` : '';\n\n return `<div class=\"oembed-container oembed-fallback\">\n <div class=\"oembed-header\">\n <div class=\"oembed-title\">External Content</div>\n <div class=\"oembed-provider\">${escapeHtml(domain)}${errorIndicator}</div>\n </div>\n <div class=\"oembed-content\">\n <a href=\"${escapeHtml(url)}\" target=\"_blank\" rel=\"noopener noreferrer\">\n View content on ${escapeHtml(domain)}\n </a>\n </div>\n</div>`;\n};\n\n/**\n * Generate HTML from oEmbed response data\n */\nexport const generateHtml = (\n data: OEmbedResponse,\n originalUrl: string,\n options: OEmbedPluginOptions = {}\n): string => {\n // Default display fields with default order when displayFields is undefined\n const defaultDisplayFields = {\n title: 1,\n author: 2,\n provider: 3,\n description: 4,\n thumbnail: 5,\n embeddedContent: 6,\n externalLink: 7,\n };\n\n // If displayFields is undefined, use default display fields, otherwise use provided displayFields\n const displayFields =\n options.displayFields === undefined\n ? defaultDisplayFields\n : options.displayFields;\n\n const urlObj = new URL(originalUrl);\n const domain = urlObj.hostname.replace(/^www\\./, '');\n\n switch (data.type) {\n case 'photo':\n return generatePhotoHtml(\n data,\n originalUrl,\n domain,\n displayFields,\n options\n );\n case 'video':\n case 'rich':\n return generateVideoRichHtml(\n data,\n originalUrl,\n domain,\n displayFields,\n options\n );\n case 'link':\n return generateLinkHtml(\n data,\n originalUrl,\n domain,\n displayFields,\n options\n );\n default:\n return generateFallbackHtml(originalUrl, undefined);\n }\n};\n\n/**\n * Generate HTML for photo type oEmbed response\n */\nconst generatePhotoHtml = (\n data: OEmbedResponse,\n originalUrl: string,\n domain: string,\n displayFields: NonNullable<OEmbedPluginOptions['displayFields']>,\n options: OEmbedPluginOptions\n): string => {\n const title = data.title || 'Untitled';\n const authorName = data.author_name || 'Unknown';\n const imageUrl = data.url || '';\n const width = data.width || 0;\n const height = data.height || 0;\n\n let sizeAttrs = '';\n if (width > 0 && height > 0) {\n sizeAttrs = ` width=\"${width}\" height=\"${height}\"`;\n }\n\n // Prepare all field items for sorting by display order\n interface DisplayItem {\n order: number;\n html: string;\n }\n\n const allItems: DisplayItem[] = [];\n\n // Add all fields based on display order\n if (displayFields.title !== undefined) {\n allItems.push({\n order: displayFields.title,\n html: `<div class=\"oembed-title\">${escapeHtml(title)}</div>`,\n });\n }\n if (displayFields.author !== undefined) {\n allItems.push({\n order: displayFields.author,\n html: `<div class=\"oembed-author\">by ${escapeHtml(authorName)}</div>`,\n });\n }\n if (displayFields.provider !== undefined) {\n allItems.push({\n order: displayFields.provider,\n html: `<div class=\"oembed-provider\">${escapeHtml(domain)}</div>`,\n });\n }\n if (displayFields.description !== undefined && data.author_name) {\n allItems.push({\n order: displayFields.description,\n html: `<div class=\"oembed-description\">${escapeHtml(data.author_name)}</div>`,\n });\n }\n if (displayFields.thumbnail !== undefined && data.thumbnail_url) {\n allItems.push({\n order: displayFields.thumbnail,\n html: createResponsiveImageWithContainer(\n escapeHtml(data.thumbnail_url),\n escapeHtml(title),\n 'oembed-thumbnail'\n ),\n });\n }\n if (displayFields.embeddedContent !== undefined && imageUrl) {\n const additionalAttrs = sizeAttrs ? sizeAttrs.trim() : '';\n allItems.push({\n order: displayFields.embeddedContent,\n html: createResponsiveImageTag(\n escapeHtml(imageUrl),\n escapeHtml(title),\n undefined,\n additionalAttrs\n ),\n });\n }\n if (displayFields.externalLink !== undefined) {\n const linkUrl = options.useMetadataUrlLink\n ? data.web_page || originalUrl\n : originalUrl;\n allItems.push({\n order: displayFields.externalLink,\n html: `<div class=\"oembed-external-link\">\n <a href=\"${escapeHtml(linkUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">\n Visit ${escapeHtml(domain)}\n </a>\n </div>`,\n });\n }\n\n // Sort by display order and generate unified HTML\n const sortedItems = allItems.sort((a, b) => a.order - b.order);\n\n // Group items into header and content sections based on their type\n const headerItems: string[] = [];\n const contentItems: string[] = [];\n\n sortedItems.forEach((item) => {\n // Determine if this is a header or content item based on CSS class\n if (\n item.html.includes('oembed-title') ||\n item.html.includes('oembed-author') ||\n item.html.includes('oembed-provider') ||\n item.html.includes('oembed-description')\n ) {\n headerItems.push(item.html);\n } else {\n contentItems.push(item.html);\n }\n });\n\n let headerHtml = '';\n if (headerItems.length > 0) {\n headerHtml = `<div class=\"oembed-header\">${headerItems.join('')}</div>`;\n }\n\n let contentHtml = '';\n if (contentItems.length > 0) {\n contentHtml = `<div class=\"oembed-content\">\n ${contentItems.join('')}\n </div>`;\n }\n\n return `<div class=\"oembed-container oembed-photo\">\n ${headerHtml}\n ${contentHtml}\n</div>`;\n};\n\n/**\n * Generate HTML for video/rich type oEmbed response\n */\nconst generateVideoRichHtml = (\n data: OEmbedResponse,\n originalUrl: string,\n domain: string,\n displayFields: NonNullable<OEmbedPluginOptions['displayFields']>,\n options: OEmbedPluginOptions\n): string => {\n const title = data.title || 'Untitled';\n const authorName = data.author_name || 'Unknown';\n const html = data.html || '';\n\n // Make content responsive if HTML contains iframe\n const processedHtml = shouldMakeResponsive(html)\n ? makeContentResponsive(html, data)\n : html;\n\n // Prepare all field items for sorting by display order\n interface DisplayItem {\n order: number;\n html: string;\n }\n\n const allItems: DisplayItem[] = [];\n\n // Add all fields based on display order\n if (displayFields.title !== undefined) {\n allItems.push({\n order: displayFields.title,\n html: `<div class=\"oembed-title\">${escapeHtml(title)}</div>`,\n });\n }\n if (displayFields.author !== undefined) {\n allItems.push({\n order: displayFields.author,\n html: `<div class=\"oembed-author\">by ${escapeHtml(authorName)}</div>`,\n });\n }\n if (displayFields.provider !== undefined) {\n allItems.push({\n order: displayFields.provider,\n html: `<div class=\"oembed-provider\">${escapeHtml(domain)}</div>`,\n });\n }\n if (displayFields.description !== undefined && data.author_name) {\n allItems.push({\n order: displayFields.description,\n html: `<div class=\"oembed-description\">${escapeHtml(data.author_name)}</div>`,\n });\n }\n if (displayFields.thumbnail !== undefined && data.thumbnail_url) {\n allItems.push({\n order: displayFields.thumbnail,\n html: createResponsiveImageWithContainer(\n escapeHtml(data.thumbnail_url),\n escapeHtml(title),\n 'oembed-thumbnail'\n ),\n });\n }\n if (displayFields.embeddedContent !== undefined && processedHtml) {\n allItems.push({\n order: displayFields.embeddedContent,\n html: processedHtml,\n });\n }\n if (displayFields.externalLink !== undefined) {\n const linkUrl = options.useMetadataUrlLink\n ? data.web_page || originalUrl\n : originalUrl;\n allItems.push({\n order: displayFields.externalLink,\n html: `<div class=\"oembed-external-link\">\n <a href=\"${escapeHtml(linkUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">\n Visit ${escapeHtml(domain)}\n </a>\n </div>`,\n });\n }\n\n // Sort by display order and generate unified HTML\n const sortedItems = allItems.sort((a, b) => a.order - b.order);\n\n // Group items into header and content sections based on their type\n const headerItems: string[] = [];\n const contentItems: string[] = [];\n\n sortedItems.forEach((item) => {\n // Determine if this is a header or content item based on CSS class\n if (\n item.html.includes('oembed-title') ||\n item.html.includes('oembed-author') ||\n item.html.includes('oembed-provider') ||\n item.html.includes('oembed-description')\n ) {\n headerItems.push(item.html);\n } else {\n contentItems.push(item.html);\n }\n });\n\n let headerHtml = '';\n if (headerItems.length > 0) {\n headerHtml = `<div class=\"oembed-header\">${headerItems.join('')}</div>`;\n }\n\n let contentHtml = '';\n if (contentItems.length > 0) {\n contentHtml = `<div class=\"oembed-content\">\n ${contentItems.join('')}\n </div>`;\n }\n\n return `<div class=\"oembed-container oembed-video\">\n ${headerHtml}\n ${contentHtml}\n</div>`;\n};\n\n/**\n * Generate HTML for link type oEmbed response\n */\nconst generateLinkHtml = (\n data: OEmbedResponse,\n originalUrl: string,\n domain: string,\n displayFields: NonNullable<OEmbedPluginOptions['displayFields']>,\n options: OEmbedPluginOptions\n): string => {\n const title = data.title || 'Link';\n const description = data.author_name || '';\n const thumbnailUrl = data.thumbnail_url || '';\n\n // Prepare all field items for sorting by display order\n interface DisplayItem {\n order: number;\n html: string;\n }\n\n const allItems: DisplayItem[] = [];\n\n // Add all fields based on display order\n if (displayFields.title !== undefined) {\n allItems.push({\n order: displayFields.title,\n html: `<div class=\"oembed-title\">${escapeHtml(title)}</div>`,\n });\n }\n if (displayFields.author !== undefined) {\n allItems.push({\n order: displayFields.author,\n html: `<div class=\"oembed-author\">by ${escapeHtml(data.author_name || 'Unknown')}</div>`,\n });\n }\n if (displayFields.provider !== undefined) {\n allItems.push({\n order: displayFields.provider,\n html: `<div class=\"oembed-provider\">${escapeHtml(domain)}</div>`,\n });\n }\n if (displayFields.description !== undefined && description) {\n allItems.push({\n order: displayFields.description,\n html: `<div class=\"oembed-description\">${escapeHtml(description)}</div>`,\n });\n }\n if (displayFields.thumbnail !== undefined && thumbnailUrl) {\n allItems.push({\n order: displayFields.thumbnail,\n html: createResponsiveImageWithContainer(\n escapeHtml(thumbnailUrl),\n escapeHtml(title),\n 'oembed-thumbnail'\n ),\n });\n }\n if (displayFields.embeddedContent !== undefined && data.html) {\n allItems.push({\n order: displayFields.embeddedContent,\n html: data.html,\n });\n }\n if (displayFields.externalLink !== undefined) {\n const linkUrl = options.useMetadataUrlLink\n ? data.web_page || originalUrl\n : originalUrl;\n allItems.push({\n order: displayFields.externalLink,\n html: `<a href=\"${escapeHtml(linkUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">\n Visit ${escapeHtml(domain)}\n </a>`,\n });\n }\n\n // Sort by display order and generate unified HTML\n const sortedItems = allItems.sort((a, b) => a.order - b.order);\n\n // Group items into header and content sections based on their type\n const headerItems: string[] = [];\n const contentItems: string[] = [];\n\n sortedItems.forEach((item) => {\n // Determine if this is a header or content item based on CSS class\n if (\n item.html.includes('oembed-title') ||\n item.html.includes('oembed-author') ||\n item.html.includes('oembed-provider') ||\n item.html.includes('oembed-description')\n ) {\n headerItems.push(item.html);\n } else {\n contentItems.push(item.html);\n }\n });\n\n let headerHtml = '';\n if (headerItems.length > 0) {\n headerHtml = `<div class=\"oembed-header\">${headerItems.join('')}</div>`;\n }\n\n let contentHtml = '';\n if (contentItems.length > 0) {\n contentHtml = `<div class=\"oembed-content\">${contentItems.join('')}</div>`;\n }\n\n return `<div class=\"oembed-container oembed-link\">\n ${headerHtml}\n ${contentHtml}\n</div>`;\n};\n\n/**\n * Make content responsive\n */\nconst makeContentResponsive = (\n html: string,\n oembedData?: OEmbedResponse\n): string => {\n if (!html) return html;\n\n // Determine aspect ratio (in priority order)\n let aspectRatio: number | null = null;\n\n // 1. Calculate from oEmbed data width/height\n if (oembedData) {\n aspectRatio = calculateAspectRatio(oembedData.width, oembedData.height);\n }\n\n // 2. Extract from HTML iframe attributes\n if (!aspectRatio) {\n aspectRatio = extractAspectRatioFromHtml(html);\n }\n\n // 3. Final fallback (16:9)\n if (!aspectRatio) {\n aspectRatio = 56.25; // 16:9\n }\n\n return wrapWithResponsiveContainer(html, aspectRatio);\n};\n\n/**\n * Check if content should be made responsive\n */\nconst shouldMakeResponsive = (html: string): boolean => {\n return !!html && /<iframe/i.test(html);\n};\n\n/**\n * Generate responsive iframe CSS styles\n */\nconst generateResponsiveIframeStyles = (): string => {\n return `\n <style>\n .oembed-responsive-wrapper {\n position: relative;\n width: 100%;\n height: 0;\n overflow: hidden;\n }\n .oembed-iframe-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n .oembed-iframe-container iframe {\n width: 100% !important;\n height: 100% !important;\n border: none !important;\n }\n </style>\n `;\n};\n\n/**\n * Wrap content with responsive container\n */\nconst wrapWithResponsiveContainer = (\n html: string,\n aspectRatio: number\n): string => {\n const hasIframe = /<iframe/i.test(html);\n\n if (hasIframe) {\n // Complete responsive container with CSS styles\n const styles = generateResponsiveIframeStyles();\n const wrapperStyle = `padding-bottom: ${aspectRatio}%;`;\n\n return `${styles}<div class=\"oembed-responsive-wrapper\" style=\"${wrapperStyle}\"><div class=\"oembed-iframe-container\">${html}</div></div>`;\n } else {\n // Basic responsive container for non-iframe content\n return `<div class=\"oembed-responsive-content\">${html}</div>`;\n }\n};\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\nimport type { ScrapingRule } from './types';\n\n/**\n * OGP (Open Graph Protocol) scraping rules for general fallback\n * These rules are applied to any site as a last resort fallback\n *\n * IMPORTANT: Twitter Card metadata is included in this fallback strategy because:\n *\n * 1. WIDESPREAD ADOPTION: Twitter Card meta tags are used by 53.7% of websites (W3Techs)\n * including major sites like Google, Microsoft, Apple, YouTube, LinkedIn, Amazon, GitHub\n *\n * 2. OFFICIAL RECOMMENDATION: Twitter/X officially recommends using Twitter Card metadata\n * alongside OGP, with Twitter's parser falling back to OGP when Twitter-specific\n * properties are not present\n *\n * 3. CROSS-PLATFORM USAGE: Twitter Card metadata is not Twitter-exclusive - it's\n * referenced by LinkedIn, Facebook, Pinterest, SEO tools, and CMS platforms\n *\n * 4. DE FACTO STANDARD: Twitter Card has become a web standard for rich social sharing,\n * making it appropriate for general OGP fallback rules rather than site-specific rules\n *\n * 5. OPTIMAL FALLBACK CHAIN: OGP → Twitter Card → HTML elements provides comprehensive\n * coverage for social media sharing across all platforms\n */\nexport const ogpRules: ScrapingRule[] = [\n {\n // Match any URL as fallback\n patterns: ['^https?://'],\n locale: 'auto',\n siteName: 'Generic Site',\n fields: {\n title: {\n required: true,\n rules: [\n // Try OGP title first\n {\n selector: 'meta[property=\"og:title\"]',\n method: 'attr',\n attr: 'content',\n },\n // Then Twitter Card title\n {\n selector: 'meta[name=\"twitter:title\"]',\n method: 'attr',\n attr: 'content',\n },\n // Finally HTML title element\n {\n selector: 'title',\n method: 'text',\n },\n ],\n },\n\n description: {\n rules: [\n // Try OGP description first\n {\n selector: 'meta[property=\"og:description\"]',\n method: 'attr',\n attr: 'content',\n },\n // Then Twitter Card description\n {\n selector: 'meta[name=\"twitter:description\"]',\n method: 'attr',\n attr: 'content',\n },\n // Finally standard meta description\n {\n selector: 'meta[name=\"description\"]',\n method: 'attr',\n attr: 'content',\n },\n ],\n },\n\n image: {\n rules: [\n // Try OGP image first\n {\n selector: 'meta[property=\"og:image\"]',\n method: 'attr',\n attr: 'content',\n processor: (values, context) => {\n return values.length > 0 && values[0]\n ? resolveUrl(values[0], context.url)\n : undefined;\n },\n },\n // Then Twitter Card image\n {\n selector: 'meta[name=\"twitter:image\"]',\n method: 'attr',\n attr: 'content',\n processor: (values, context) => {\n return values.length > 0 && values[0]\n ? resolveUrl(values[0], context.url)\n : undefined;\n },\n },\n // Then various favicon links\n {\n selector: 'link[rel=\"icon\"]',\n method: 'attr',\n attr: 'href',\n processor: (values, context) => {\n return values.length > 0 && values[0]\n ? resolveUrl(values[0], context.url)\n : undefined;\n },\n },\n {\n selector: 'link[rel=\"apple-touch-icon\"]',\n method: 'attr',\n attr: 'href',\n processor: (values, context) => {\n return values.length > 0 && values[0]\n ? resolveUrl(values[0], context.url)\n : undefined;\n },\n },\n {\n selector: 'link[rel=\"shortcut icon\"]',\n method: 'attr',\n attr: 'href',\n processor: (values, context) => {\n return values.length > 0 && values[0]\n ? resolveUrl(values[0], context.url)\n : undefined;\n },\n },\n ],\n },\n\n siteName: {\n rules: [\n // Try OGP site name first\n {\n selector: 'meta[property=\"og:site_name\"]',\n method: 'attr',\n attr: 'content',\n },\n // Then Twitter site\n {\n selector: 'meta[name=\"twitter:site\"]',\n method: 'attr',\n attr: 'content',\n processor: (values) => {\n // Remove @ symbol from Twitter handle if present\n return values.length > 0 && values[0]\n ? values[0].replace(/^@/, '')\n : undefined;\n },\n },\n // Finally extract domain from URL\n {\n selector: 'html',\n method: 'text',\n processor: (_values, context) => {\n try {\n const url = new URL(context.url);\n return url.hostname.replace(/^www\\./, '');\n } catch {\n return 'Unknown Site';\n }\n },\n },\n ],\n },\n\n url: {\n rules: [\n // Try OGP URL first\n {\n selector: 'meta[property=\"og:url\"]',\n method: 'attr',\n attr: 'content',\n },\n // Fallback to current URL\n {\n selector: 'html',\n method: 'text',\n processor: (_values, context) => {\n return context.url;\n },\n },\n ],\n },\n\n type: {\n rules: [\n {\n selector: 'meta[property=\"og:type\"]',\n method: 'attr',\n attr: 'content',\n },\n ],\n },\n\n locale: {\n rules: [\n {\n selector: 'meta[property=\"og:locale\"]',\n method: 'attr',\n attr: 'content',\n },\n ],\n },\n\n favicon: {\n rules: [\n // Try standard favicon first\n {\n selector: 'link[rel=\"icon\"]',\n method: 'attr',\n attr: 'href',\n processor: (values, context) => {\n return values.length > 0 && values[0]\n ? resolveUrl(values[0], context.url)\n : undefined;\n },\n },\n // Then Apple touch icon\n {\n selector: 'link[rel=\"apple-touch-icon\"]',\n method: 'attr',\n attr: 'href',\n processor: (values, context) => {\n return values.length > 0 && values[0]\n ? resolveUrl(values[0], context.url)\n : undefined;\n },\n },\n // Finally shortcut icon\n {\n selector: 'link[rel=\"shortcut icon\"]',\n method: 'attr',\n attr: 'href',\n processor: (values, context) => {\n return values.length > 0 && values[0]\n ? resolveUrl(values[0], context.url)\n : undefined;\n },\n },\n ],\n },\n },\n },\n];\n\n/**\n * Resolve relative URLs to absolute URLs\n */\nfunction resolveUrl(url: string, baseUrl: string): string {\n try {\n // If it's already an absolute URL, return as is\n if (url.startsWith('http://') || url.startsWith('https://')) {\n return url;\n }\n\n // If it starts with //, add protocol\n if (url.startsWith('//')) {\n const baseUrlObj = new URL(baseUrl);\n return `${baseUrlObj.protocol}${url}`;\n }\n\n // Resolve relative URL\n return new URL(url, baseUrl).toString();\n } catch {\n return url; // Return original if resolution fails\n }\n}\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\nimport * as cheerio from 'cheerio';\nimport type {\n ScrapingRule,\n FieldRule,\n Processor,\n ProcessorRule,\n ProcessorFunction,\n ProcessorContext,\n ExtractedMetadata,\n} from './types';\nimport type { Logger } from '../../types';\n\n/**\n * Extract locale from HTML meta tags\n */\nconst extractLocaleFromHTML = (\n $: ReturnType<typeof import('cheerio').load>\n): string | undefined => {\n // <html lang=\"ja\">\n const htmlLang = $('html').attr('lang');\n if (htmlLang) return htmlLang;\n\n // <meta http-equiv=\"content-language\" content=\"ja-JP\">\n const metaLang = $('meta[http-equiv=\"content-language\"]').attr('content');\n if (metaLang) return metaLang;\n\n // <meta name=\"language\" content=\"ja\">\n const languageMeta = $('meta[name=\"language\"]').attr('content');\n if (languageMeta) return languageMeta;\n\n return undefined;\n};\n\nconst normalizePatternList = (value?: string[]): string[] => {\n if (!value) return [];\n return value.map((pattern) => pattern.trim()).filter(Boolean);\n};\n\nconst getRulePatterns = (rule: ScrapingRule): string[] => {\n return normalizePatternList(rule.patterns);\n};\n\nconst getRulePostFilters = (rule: ScrapingRule): string[] => {\n return normalizePatternList(rule.postFilters);\n};\n\n/**\n * Built-in processor rules\n */\nconst executeProcessorRule = (\n rule: ProcessorRule,\n values: string[],\n _context: ProcessorContext\n): string | string[] | undefined => {\n const params = rule.params || {};\n\n switch (rule.type) {\n case 'regex': {\n const replace = params.replace as any;\n const match = params.match as any;\n if (replace) {\n return values\n .map((value) => {\n let result = value;\n for (const r of Array.isArray(replace) ? replace : [replace]) {\n result = result.replace(\n new RegExp(r.pattern, r.flags || 'g'),\n r.replacement || ''\n );\n }\n return result.trim();\n })\n .filter(Boolean);\n }\n if (match) {\n const regex = new RegExp(match.pattern, match.flags || '');\n return values\n .map((value) => {\n const matches = value.match(regex);\n return matches?.[match.group || 0] || '';\n })\n .filter(Boolean);\n }\n return values;\n }\n\n case 'filter': {\n const contains = params.contains as string;\n const excludeContains = params.excludeContains as string | string[];\n const minLength = params.minLength as number;\n const maxLength = params.maxLength as number;\n return values.filter((value) => {\n if (minLength && value.length < minLength) return false;\n if (maxLength && value.length > maxLength) return false;\n if (contains && !value.includes(contains)) return false;\n if (excludeContains) {\n for (const exclude of Array.isArray(excludeContains)\n ? excludeContains\n : [excludeContains]) {\n if (value.includes(exclude)) return false;\n }\n }\n return true;\n });\n }\n\n case 'slice': {\n const start = (params.start as number) || 0;\n const end = params.end as number;\n return values.slice(start, end);\n }\n\n case 'first': {\n return values.length > 0 ? values[0] : undefined;\n }\n\n case 'currency': {\n const symbol = (params.symbol as string) || '$';\n const locale = (params.locale as string) || 'en-US';\n return values\n .map((value) => {\n const numbers = value.match(/[\\d,\\.]+/g);\n if (numbers && numbers.length > 0) {\n const cleanPrice = numbers[0].replace(/,/g, '');\n if (/^\\d+(\\.\\d+)?$/.test(cleanPrice)) {\n const amount = parseFloat(cleanPrice);\n // Use simple formatting for consistent test results\n if (locale === 'de-DE') {\n return `${symbol}${amount.toLocaleString('de-DE')}`;\n } else {\n return `${symbol}${amount.toLocaleString('en-US')}`;\n }\n }\n }\n return value;\n })\n .filter(Boolean);\n }\n\n default:\n return values;\n }\n};\n\n/**\n * Execute a processor (rule or function)\n */\nconst executeProcessor = (\n processor: Processor,\n values: string[],\n context: ProcessorContext\n): string | string[] | undefined => {\n if (typeof processor === 'function') {\n return (processor as ProcessorFunction)(values, context);\n } else {\n return executeProcessorRule(processor as ProcessorRule, values, context);\n }\n};\n\n/**\n * Extract field data based on field rule\n */\nconst extractField = (\n rule: FieldRule,\n $: ReturnType<typeof cheerio.load>,\n context: ProcessorContext,\n logger?: Logger\n): string | string[] | undefined => {\n const selectors = Array.isArray(rule.selector)\n ? rule.selector\n : [rule.selector];\n const method = rule.method || 'text';\n let values: string[] = [];\n\n logger?.debug('extractField: Attempting field extraction', {\n selectors,\n method,\n attr: rule.attr,\n multiple: rule.multiple,\n });\n\n // Extract values using selectors\n for (const selector of selectors) {\n const elements = $(selector);\n logger?.debug(\n `extractField: Found ${elements.length} elements for selector \"${selector}\"`\n );\n\n elements.each((_, elem) => {\n let value: string;\n switch (method) {\n case 'attr':\n value = $(elem).attr(rule.attr || 'href') || '';\n break;\n case 'html':\n value = $(elem).html() || '';\n break;\n case 'text':\n default:\n value = $(elem).text().trim();\n break;\n }\n if (value) {\n values.push(value);\n }\n });\n\n // If not extracting multiple and we have values, break early\n if (!rule.multiple && values.length > 0) {\n break;\n }\n }\n\n logger?.debug('extractField: Raw extraction results', {\n valuesCount: values.length,\n hasProcessor: !!rule.processor,\n });\n\n // Apply processor if specified\n if (rule.processor && values.length > 0) {\n logger?.debug('extractField: Applying processor to extracted values');\n const processed = executeProcessor(rule.processor, values, context);\n if (processed !== undefined) {\n // If processor returns a single value and we're not in multiple mode, use it directly\n if (!rule.multiple && !Array.isArray(processed)) {\n logger?.debug('extractField: Processor returned single value');\n return processed;\n }\n values = Array.isArray(processed) ? processed : [processed];\n logger?.debug('extractField: Processor applied successfully', {\n processedValuesCount: values.length,\n });\n }\n }\n\n // Return result based on multiple flag\n if (rule.multiple) {\n const result = values.length > 0 ? values : undefined;\n logger?.debug('extractField: Multiple mode result', {\n resultCount: result?.length || 0,\n });\n return result;\n } else {\n const result = values.length > 0 ? values[0] : undefined;\n logger?.debug('extractField: Single mode result', { hasResult: !!result });\n return result;\n }\n};\n\n/**\n * Extract field data using multiple rules (try in order until one succeeds)\n */\nconst extractFieldWithRules = (\n rules: FieldRule[],\n $: ReturnType<typeof cheerio.load>,\n context: ProcessorContext,\n fieldName: string,\n logger?: Logger\n): string | string[] | undefined => {\n logger?.debug(\n `extractFieldWithRules: Trying ${rules.length} rules for field \"${fieldName}\"`\n );\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n if (!rule) continue;\n\n logger?.debug(\n `extractFieldWithRules: Attempting rule ${i + 1}/${rules.length} for field \"${fieldName}\"`\n );\n\n const value = extractField(rule, $, context, logger);\n if (value !== undefined) {\n logger?.debug(\n `extractFieldWithRules: Successfully extracted field \"${fieldName}\" using rule ${i + 1}`\n );\n return value;\n } else {\n logger?.debug(\n `extractFieldWithRules: Rule ${i + 1} failed for field \"${fieldName}\"`\n );\n }\n }\n\n logger?.debug(\n `extractFieldWithRules: All rules failed for field \"${fieldName}\"`\n );\n return undefined;\n};\n\n/**\n * Apply scraping rule to extract metadata\n */\nexport const applyScrapingRule = (\n rule: ScrapingRule,\n $: ReturnType<typeof cheerio.load>,\n url: string,\n logger?: Logger\n): ExtractedMetadata => {\n const patterns = getRulePatterns(rule);\n const postFilters = getRulePostFilters(rule);\n\n logger?.debug('applyScrapingRule: Starting metadata extraction', {\n patterns,\n postFilters: postFilters.length > 0 ? postFilters : undefined,\n siteName: rule.siteName,\n fieldsCount: Object.keys(rule.fields).length,\n });\n\n // Determine locale: rule locale takes precedence, otherwise extract from HTML\n const locale = rule.locale || extractLocaleFromHTML($);\n logger?.debug('applyScrapingRule: Determined locale', { locale });\n\n // Create head-specific cheerio instance\n const $head = cheerio.load($('head').html() || '');\n\n const context: ProcessorContext = {\n $,\n $head,\n url,\n ...(locale && { locale }),\n };\n\n const extractedData: ExtractedMetadata = {};\n\n // Automatically add siteName if specified in rule\n if (rule.siteName) {\n extractedData.siteName = rule.siteName;\n logger?.debug('applyScrapingRule: Added siteName from rule', {\n siteName: rule.siteName,\n });\n }\n\n // Extract fields using the new FieldConfig structure\n for (const [fieldName, fieldConfig] of Object.entries(rule.fields)) {\n logger?.debug(`applyScrapingRule: Processing field \"${fieldName}\"`, {\n isRequired: fieldConfig.required,\n rulesCount: fieldConfig.rules.length,\n });\n\n const value = extractFieldWithRules(\n fieldConfig.rules,\n $,\n context,\n fieldName,\n logger\n );\n\n // Check if required field is missing\n if (fieldConfig.required && value === undefined) {\n logger?.debug(\n `applyScrapingRule: Required field \"${fieldName}\" is missing`\n );\n // For required fields, we could optionally fail the entire rule\n // For now, we continue but note the missing required field\n continue;\n }\n\n // Only add non-undefined values to metadata\n if (value !== undefined) {\n extractedData[fieldName] = value;\n logger?.debug(\n `applyScrapingRule: Successfully extracted field \"${fieldName}\"`,\n {\n valueType: Array.isArray(value) ? 'array' : 'string',\n valueLength: Array.isArray(value) ? value.length : value.length,\n }\n );\n } else {\n logger?.debug(\n `applyScrapingRule: Field \"${fieldName}\" extraction failed`\n );\n }\n }\n\n logger?.debug('applyScrapingRule: Metadata extraction completed', {\n extractedFieldsCount: Object.keys(extractedData).length,\n extractedFields: Object.keys(extractedData),\n });\n\n return extractedData;\n};\n\n/**\n * Find matching scraping rule for URL\n */\nexport function findMatchingRule(\n rules: ScrapingRule[],\n url: string,\n logger?: Logger\n): ScrapingRule | undefined;\nexport function findMatchingRule(\n rules: ScrapingRule[],\n url: string,\n postFilterUrl: string | undefined,\n logger?: Logger\n): ScrapingRule | undefined;\nexport function findMatchingRule(\n rules: ScrapingRule[],\n url: string,\n postFilterUrlOrLogger?: string | Logger,\n logger?: Logger\n): ScrapingRule | undefined {\n const hasPostFilterUrl = typeof postFilterUrlOrLogger === 'string';\n const postFilterUrl = hasPostFilterUrl ? postFilterUrlOrLogger : undefined;\n const resolvedLogger = hasPostFilterUrl\n ? logger\n : (postFilterUrlOrLogger ?? logger);\n\n resolvedLogger?.debug('findMatchingRule: Testing rules against URL', {\n url,\n postFilterUrl,\n rulesCount: rules.length,\n });\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n if (!rule) continue;\n\n const patterns = getRulePatterns(rule);\n if (patterns.length === 0) {\n resolvedLogger?.debug(`findMatchingRule: Rule ${i + 1}/${rules.length}`, {\n patterns,\n matches: false,\n });\n continue;\n }\n\n const matchesPattern = patterns.some((pattern) =>\n new RegExp(pattern).test(url)\n );\n const postFilters = getRulePostFilters(rule);\n let matchesPostFilter = true;\n if (postFilters.length > 0) {\n if (!postFilterUrl) {\n matchesPostFilter = false;\n } else {\n matchesPostFilter = postFilters.some((pattern) =>\n new RegExp(pattern).test(postFilterUrl)\n );\n }\n }\n const matches = matchesPattern && matchesPostFilter;\n\n resolvedLogger?.debug(`findMatchingRule: Rule ${i + 1}/${rules.length}`, {\n patterns,\n postFilters: postFilters.length > 0 ? postFilters : undefined,\n siteName: rule.siteName,\n matches,\n matchesPattern,\n matchesPostFilter,\n });\n\n if (matches) {\n resolvedLogger?.debug('findMatchingRule: Found matching rule', {\n ruleIndex: i + 1,\n patterns,\n postFilters: postFilters.length > 0 ? postFilters : undefined,\n siteName: rule.siteName,\n });\n return rule;\n }\n }\n\n resolvedLogger?.debug('findMatchingRule: No matching rule found');\n return undefined;\n}\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\nimport * as cheerio from 'cheerio';\nimport { ogpRules } from './ogp-rules';\nimport { findMatchingRule, applyScrapingRule } from './rule-engine';\nimport type { ExtractedMetadata, ScrapingRule } from './types';\nimport type { Logger } from '../../types';\n\n/**\n * Validate URL format\n */\nexport const isValidUrl = (url: string): boolean => {\n try {\n new URL(url);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Escape HTML characters\n */\nexport const escapeHtml = (text: string): string => {\n const map: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#039;',\n };\n return text.replace(/[&<>\"']/g, (m) => map[m] || m);\n};\n\n/**\n * Extract domain from URL\n */\nexport const extractDomain = (url: string): string => {\n try {\n const urlObj = new URL(url);\n return urlObj.hostname.replace(/^www\\./, '');\n } catch {\n return 'unknown';\n }\n};\n\n/**\n * Resolve relative URLs to absolute URLs\n */\nexport const resolveUrl = (url: string, baseUrl: string): string => {\n try {\n // If it's already an absolute URL, return as is\n if (url.startsWith('http://') || url.startsWith('https://')) {\n return url;\n }\n\n // If it starts with //, add protocol\n if (url.startsWith('//')) {\n const baseUrlObj = new URL(baseUrl);\n return `${baseUrlObj.protocol}${url}`;\n }\n\n // Resolve relative URL\n return new URL(url, baseUrl).toString();\n } catch {\n return url; // Return original if resolution fails\n }\n};\n\n/**\n * Truncate text to specified length with ellipsis\n */\nexport const truncateText = (text: string, maxLength: number): string => {\n if (text.length <= maxLength) {\n return text;\n }\n return text.substring(0, maxLength - 3) + '...';\n};\n\n/**\n * Clean and normalize text content\n */\nexport const cleanText = (text: string): string => {\n return text\n .replace(/\\s+/g, ' ') // Normalize whitespace\n .trim()\n .replace(/[\\r\\n]/g, ' '); // Remove line breaks\n};\n\n/**\n * Build rule set from custom rules and OGP fallback\n * OGP rules are always appended as fallback\n */\nconst buildRuleSet = (customRules: ScrapingRule[] = []): ScrapingRule[] => [\n ...customRules,\n ...ogpRules, // OGP rules as fallback\n];\n\n/**\n * Extract enhanced scraping data for supported sites using rule engine\n */\nexport const extractEnhancedData = (\n $: ReturnType<typeof cheerio.load>,\n sourceUrl: string,\n customRules?: ScrapingRule[],\n logger?: Logger,\n postFilterUrl?: string\n): ExtractedMetadata | null => {\n const rules = buildRuleSet(customRules);\n\n logger?.debug('extractEnhancedData: Starting rule matching process', {\n url: sourceUrl,\n postFilterUrl,\n totalRules: rules.length,\n customRulesCount: customRules?.length || 0,\n ogpRulesCount: ogpRules.length,\n });\n\n const matchingRule = findMatchingRule(\n rules,\n sourceUrl,\n postFilterUrl,\n logger\n );\n\n if (matchingRule) {\n logger?.debug('extractEnhancedData: Found matching rule', {\n patterns: matchingRule.patterns,\n postFilters: matchingRule.postFilters,\n siteName: matchingRule.siteName,\n fieldsToExtract: Object.keys(matchingRule.fields),\n });\n\n const hasPostFilters =\n Array.isArray(matchingRule.postFilters) &&\n matchingRule.postFilters.length > 0;\n const contextUrl =\n hasPostFilters && postFilterUrl ? postFilterUrl : sourceUrl;\n const result = applyScrapingRule(matchingRule, $, contextUrl, logger);\n\n logger?.debug('extractEnhancedData: Rule application completed', {\n extractedFields: Object.keys(result),\n successfulFieldsCount: Object.keys(result).length,\n });\n\n return result;\n }\n\n logger?.debug(\n 'extractEnhancedData: No matching rule found for URL:',\n sourceUrl\n );\n return null;\n};\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\nimport * as cheerio from 'cheerio';\nimport { isBrowser, isCORSError } from '../../utils';\nimport { extractEnhancedData, resolveUrl } from './utils';\nimport type { CardPluginOptions, ExtractedMetadata } from './types';\nimport type { MarkdownProcessorPluginContext } from '../../types';\n\n/**\n * Fetch HTML content and extract metadata using rule-based system\n */\nexport const fetchMetadata = async (\n url: string,\n options: CardPluginOptions,\n context: MarkdownProcessorPluginContext\n): Promise<ExtractedMetadata> => {\n const { logger, signal, fetcher } = context;\n\n logger.info('fetchMetadata: Starting metadata extraction for URL:', url);\n\n try {\n const response = await fetcher.rawFetcher(url, 'text/html', signal, logger);\n const htmlContent = await response.text();\n\n logger.info('fetchMetadata: Successfully fetched HTML content');\n\n // Parse metadata from HTML using rule-based system\n const $ = cheerio.load(htmlContent);\n const postFilterUrl = resolvePostFilterUrl($, url, response.url);\n const metadata = extractEnhancedData(\n $,\n url,\n options.scrapingRules,\n logger,\n postFilterUrl\n );\n\n if (metadata === null || Object.keys(metadata).length === 0) {\n // Return minimal metadata if no rules matched\n const domain = new URL(url).hostname.replace(/^www\\./, '');\n logger.debug(\n 'fetchMetadata: No metadata extracted, returning minimal fallback metadata'\n );\n return {\n siteName: domain,\n url: url,\n };\n }\n\n logger.debug('fetchMetadata: Successfully extracted metadata:', {\n url,\n extractedFields: Object.keys(metadata),\n fieldCount: Object.keys(metadata).length,\n });\n\n return metadata;\n } catch (error: unknown) {\n if (isCORSError(error)) {\n if (isBrowser()) {\n logger.debug(\n 'fetchMetadata: Browser CORS restrictions prevent fetching metadata for URL:',\n url\n );\n } else {\n logger.warn(\n 'fetchMetadata: CORS error fetching metadata for URL:',\n url,\n error\n );\n }\n } else {\n logger.warn(\n 'fetchMetadata: Error fetching or parsing metadata for URL:',\n url,\n error\n );\n }\n\n // Re-throw the original error\n throw error;\n }\n};\n\nconst resolvePostFilterUrl = (\n $: ReturnType<typeof cheerio.load>,\n originalUrl: string,\n responseUrl?: string\n): string | undefined => {\n const trimmedResponseUrl = responseUrl?.trim();\n if (trimmedResponseUrl) {\n return trimmedResponseUrl;\n }\n\n const ogUrl = $('meta[property=\"og:url\"]').attr('content')?.trim();\n const canonicalUrl = $('link[rel=\"canonical\"]').attr('href')?.trim();\n const twitterUrl = $('meta[name=\"twitter:url\"]').attr('content')?.trim();\n const candidate = ogUrl || canonicalUrl || twitterUrl;\n if (!candidate) {\n return undefined;\n }\n return resolveUrl(candidate, originalUrl);\n};\n","// mark-deco - Flexible Markdown to HTML conversion library\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/mark-deco\n\nimport {\n createResponsiveImageWithContainer,\n createResponsiveImageTag,\n} from '../../utils/responsive-image';\nimport { escapeHtml, truncateText, cleanText, extractDomain } from './utils';\nimport type { ExtractedMetadata, CardPluginOptions } from './types';\n\n/**\n * Generate fallback HTML for when OGP data cannot be fetched\n */\nexport const generateFallbackHtml = (\n url: string,\n errorInfo?: string\n): string => {\n const domain = extractDomain(url);\n\n // Determine error message based on error type\n let errorMessage = 'Content not accessible';\n let hint = '';\n\n if (errorInfo) {\n if (\n errorInfo.includes('CORS') ||\n errorInfo.includes('NetworkError') ||\n errorInfo.includes('TypeError')\n ) {\n errorMessage = 'CORS restriction';\n hint = 'This site blocks cross-origin requests in browsers';\n } else if (errorInfo.includes('Timeout')) {\n errorMessage = 'Request timeout';\n hint = 'The site took too long to respond';\n } else {\n errorMessage = 'Access failed';\n hint = errorInfo;\n }\n }\n\n return `<div class=\"card-container card-fallback\">\n <div class=\"card-body\">\n <div class=\"card-header\">\n <div class=\"card-title\">📄 External Content</div>\n <div class=\"card-provider\">${escapeHtml(domain)}</div>\n </div>\n <div class=\"card-description\">\n ${errorMessage}${hint ? ` - ${hint}` : ''}\n </div>\n <div class=\"card-content\">\n <a href=\"${escapeHtml(url)}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"card-external-link\">\n → Open ${escapeHtml(domain)} in new tab\n </a>\n </div>\n </div>\n</div>`;\n};\n\n/**\n * Generate HTML card from extracted metadata\n */\nexport const generateCardHtml = (\n data: ExtractedMetadata,\n originalUrl: string,\n options: CardPluginOptions = {}\n): string => {\n // Default display fields with default order when displayFields is undefined\n const defaultDisplayFields: Record<string, number> = {\n title: 1,\n image: 2,\n description: 3,\n siteName: 4,\n favicon: 5,\n url: 6,\n // Enhanced fields for common scenarios\n price: 10,\n rating: 11,\n brand: 12,\n features: 13,\n };\n\n // Use provided displayFields or defaults\n const displayFields = options.displayFields || defaultDisplayFields;\n\n // Helper function to safely get string value from metadata\n const getString = (key: string): string | undefined => {\n const value = data[key];\n return typeof value === 'string' ? value : undefined;\n };\n\n // Extract basic metadata\n const title = cleanText(getString('title') || 'Untitled');\n const description = getString('description') || '';\n const imageUrl = getString('image') || '';\n const faviconUrl = getString('favicon');\n\n // Determine which URL to use based on useMetadataUrlLink option\n const url = options.useMetadataUrlLink\n ? getString('url') || originalUrl\n : originalUrl;\n const siteName = getString('siteName') || extractDomain(url);\n\n // Truncate text for better display\n const truncatedTitle = truncateText(title, 80);\n const truncatedDescription = truncateText(cleanText(description), 160);\n\n // Prepare field items for sorting by display order\n interface DisplayItem {\n order: number;\n html: string;\n isHeader?: boolean;\n section: 'image' | 'header' | 'body' | 'enhanced';\n }\n\n const allItems: DisplayItem[] = [];\n\n // Generate image section\n if (imageUrl && displayFields.image !== undefined) {\n allItems.push({\n order: displayFields.image,\n section: 'image',\n html: createResponsiveImageWithContainer(\n escapeHtml(imageUrl),\n escapeHtml(truncatedTitle),\n 'card-image',\n undefined,\n 'loading=\"lazy\"'\n ),\n });\n }\n\n // Generate favicon if available\n let faviconHtml = '';\n if (faviconUrl && displayFields.favicon !== undefined) {\n faviconHtml = createResponsiveImageTag(\n escapeHtml(faviconUrl),\n '',\n undefined,\n 'class=\"card-favicon\"'\n );\n }\n\n // Generate header items\n const headerItems: DisplayItem[] = [];\n\n if (displayFields.title !== undefined) {\n headerItems.push({\n order: displayFields.title,\n section: 'header',\n isHeader: true,\n html: `<div class=\"card-title\">${escapeHtml(truncatedTitle)}</div>`,\n });\n }\n\n if (displayFields.siteName !== undefined) {\n headerItems.push({\n order: displayFields.siteName,\n section: 'header',\n isHeader: true,\n html: `<div class=\"card-provider\">\n ${displayFields.favicon !== undefined ? faviconHtml : ''}\n <span>${escapeHtml(siteName)}</span>\n </div>`,\n });\n }\n\n // Generate body items\n if (truncatedDescription && displayFields.description !== undefined) {\n allItems.push({\n order: displayFields.description,\n section: 'body',\n html: `<div class=\"card-description\">${escapeHtml(truncatedDescription)}</div>`,\n });\n }\n\n // Generate enhanced fields from metadata\n for (const [fieldName, value] of Object.entries(data)) {\n // Skip basic fields that are handled separately\n if (\n [\n 'title',\n 'description',\n 'image',\n 'url',\n 'siteName',\n 'type',\n 'locale',\n 'favicon',\n ].includes(fieldName)\n ) {\n continue;\n }\n\n const order = displayFields[fieldName];\n if (order !== undefined) {\n let fieldHtml = '';\n\n if (Array.isArray(value)) {\n // Handle array values (e.g., features)\n const items = value\n .slice(0, 3)\n .map((item) => `<li>${escapeHtml(String(item))}</li>`)\n .join('');\n fieldHtml = `<div class=\"card-field card-${fieldName}\">\n <div class=\"field-label\">${escapeHtml(fieldName)}:</div>\n <ul class=\"field-list\">${items}</ul>\n </div>`;\n } else {\n // Handle single values\n fieldHtml = `<div class=\"card-field card-${fieldName}\">\n <span class=\"field-label\">${escapeHtml(fieldName)}:</span>\n <span class=\"field-value\">${escapeHtml(String(value))}</span>\n </div>`;\n }\n\n allItems.push({\n order,\n section: 'enhanced',\n html: fieldHtml,\n });\n }\n }\n\n // Also add any undefined fields at the end\n const undefinedFields: string[] = [];\n for (const fieldName of Object.keys(data)) {\n // Skip basic fields and already processed fields\n if (\n [\n 'title',\n 'description',\n 'image',\n 'url',\n 'siteName',\n 'type',\n 'locale',\n 'favicon',\n ].includes(fieldName)\n ) {\n continue;\n }\n\n if (displayFields[fieldName] === undefined) {\n undefinedFields.push(fieldName);\n }\n }\n\n // Add undefined fields with high order values\n let undefinedOrder = 1000;\n for (const fieldName of undefinedFields) {\n const value = data[fieldName];\n let fieldHtml = '';\n\n if (Array.isArray(value)) {\n const items = value\n .slice(0, 3)\n .map((item) => `<li>${escapeHtml(String(item))}</li>`)\n .join('');\n fieldHtml = `<div class=\"card-field card-${fieldName}\">\n <div class=\"field-label\">${escapeHtml(fieldName)}:</div>\n <ul class=\"field-list\">${items}</ul>\n </div>`;\n } else {\n fieldHtml = `<div class=\"card-field card-${fieldName}\">\n <span class=\"field-label\">${escapeHtml(fieldName)}:</span>\n <span class=\"field-value\">${escapeHtml(String(value))}</span>\n </div>`;\n }\n\n allItems.push({\n order: undefinedOrder++,\n section: 'enhanced',\n html: fieldHtml,\n });\n }\n\n // Sort header items by order\n const sortedHeaderItems = headerItems.sort((a, b) => a.order - b.order);\n\n // Generate header HTML\n let headerHtml = '';\n if (sortedHeaderItems.length > 0) {\n headerHtml = `<div class=\"card-header\">\n ${sortedHeaderItems.map((item) => item.html).join('')}\n </div>`;\n }\n\n // Sort non-header items by order\n const sortedBodyItems = allItems\n .filter((item) => !item.isHeader)\n .sort((a, b) => a.order - b.order);\n\n // Group items by section for proper HTML structure\n const imageItems = sortedBodyItems.filter((item) => item.section === 'image');\n const bodyItems = sortedBodyItems.filter(\n (item) => item.section === 'body' || item.section === 'enhanced'\n );\n\n // Generate image section HTML\n const imageHtml = imageItems.map((item) => item.html).join('');\n\n // Generate body content HTML\n let bodyContentHtml = '';\n if (bodyItems.length > 0) {\n bodyContentHtml = bodyItems.map((item) => item.html).join('');\n }\n\n // Combine header and body content\n const bodyHtml =\n headerHtml || bodyContentHtml\n ? `<div class=\"card-body\">\n ${headerHtml}\n ${bodyContentHtml}\n </div>`\n : '';\n\n // Add class modifier for Amazon products\n const isAmazon = getString('siteName')?.toLowerCase().includes('amazon');\n const containerClass = isAmazon\n ? 'card-container card-amazon'\n : 'card-container';\n\n // Generate the card HTML conditionally\n const cardContent =\n displayFields.url !== undefined\n ? `<a href=\"${escapeHtml(url)}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"card-link\">\n ${imageHtml}\n ${bodyHtml}\n </a>`\n : `${imageHtml}\n ${bodyHtml}`;\n\n return `<div class=\"${containerClass}\">\n ${cardContent}\n</div>`;\n};\n"],"names":["isValidUrl","escapeHtml","e","fetchText","isCORSError","createTimeoutSignal","combineAbortSignals","fetchJson","isBrowser","generateFallbackHtml","resolveUrl","cheerio"],"mappings":"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"}