mark-deco 0.29.0 → 1.1.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.
Files changed (34) hide show
  1. package/README.md +22 -13
  2. package/dist/browser.cjs +2 -2
  3. package/dist/browser.d.ts +2 -2
  4. package/dist/browser.mjs +2 -2
  5. package/dist/card-oembed-fallback.cjs +3 -3
  6. package/dist/card-oembed-fallback.d.ts +2 -2
  7. package/dist/card-oembed-fallback.mjs +3 -3
  8. package/dist/{html-generator-DOlAM9Ff.js → html-generator-BmIuyVQU.js} +5 -5
  9. package/dist/{html-generator-DOlAM9Ff.js.map → html-generator-BmIuyVQU.js.map} +1 -1
  10. package/dist/{html-generator-BKd2MyoO.cjs → html-generator-CHbU5jbh.cjs} +4 -4
  11. package/dist/{html-generator-BKd2MyoO.cjs.map → html-generator-CHbU5jbh.cjs.map} +1 -1
  12. package/dist/{html-generator-BlVRLqE6.cjs → html-generator-DTRmTXLk.cjs} +5 -5
  13. package/dist/{html-generator-BlVRLqE6.cjs.map → html-generator-DTRmTXLk.cjs.map} +1 -1
  14. package/dist/{html-generator-CClcgkAK.js → html-generator-RU0HacgN.js} +4 -4
  15. package/dist/{html-generator-CClcgkAK.js.map → html-generator-RU0HacgN.js.map} +1 -1
  16. package/dist/index.cjs +336 -7
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.ts +39 -2
  19. package/dist/index.mjs +315 -8
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/internal.cjs +4 -4
  22. package/dist/internal.d.ts +2 -2
  23. package/dist/internal.mjs +4 -4
  24. package/dist/misc.cjs +2 -2
  25. package/dist/misc.d.ts +2 -2
  26. package/dist/misc.mjs +2 -2
  27. package/dist/node.cjs +3 -3
  28. package/dist/node.d.ts +2 -2
  29. package/dist/node.mjs +3 -3
  30. package/dist/{utils-CoXrMKLM.cjs → utils-DBRV1kXj.cjs} +22 -3
  31. package/dist/{utils-CoXrMKLM.cjs.map → utils-DBRV1kXj.cjs.map} +1 -1
  32. package/dist/{utils-B06SsBEd.js → utils-DLDazcJ8.js} +23 -4
  33. package/dist/{utils-B06SsBEd.js.map → utils-DLDazcJ8.js.map} +1 -1
  34. package/package.json +8 -7
package/README.md CHANGED
@@ -1,20 +1,20 @@
1
- # MarkDeco
1
+ # mark-deco
2
2
 
3
3
  Flexible Markdown to HTML conversion library.
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/mark-deco.svg)](https://www.npmjs.com/package/mark-deco)
5
+ [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
8
  ## What is this?
9
9
 
10
10
  Flexible Markdown to HTML conversion library written in TypeScript.
11
11
  It interprets GitHub Flavored Markdown (GFM) and outputs HTML.
12
- Supports frontmatter parsing, heading analysis, source code formatting, oEmbed/card/Mermaid graph rendering, and custom code block processing through plugin extensions.
12
+ Supports frontmatter parsing, heading analysis, source code formatting, oEmbed/card/Mermaid diagram rendering (mermaid.js or beautiful-mermaid), and custom code block processing through plugin extensions.
13
13
 
14
14
  - Can be used to render HTML from Markdown input.
15
15
  - Simple interface makes it very easy to use.
16
16
  - Highly independent with minimal runtime requirements. Works in both Node.js and browser environments.
17
- - Built-in plugins support oEmbed, cards, and Mermaid.js.
17
+ - Built-in plugins support oEmbed, cards, Mermaid.js, and Beautiful Mermaid.
18
18
 
19
19
  ## Installation
20
20
 
@@ -32,7 +32,7 @@ import { createMarkdownProcessor, createCachedFetcher } from 'mark-deco';
32
32
  // Create a memory-cached fetcher
33
33
  const fetcher = createCachedFetcher('MyApp/1.0');
34
34
 
35
- // Create MarkDeco processor
35
+ // Create mark-deco processor
36
36
  const processor = createMarkdownProcessor({
37
37
  fetcher,
38
38
  });
@@ -68,11 +68,11 @@ This will render HTML like this:
68
68
  A "fetcher" is an abstraction for external server access. It's primarily used by oEmbed and card plugins for external API calls and page scraping.
69
69
  The argument passed to the fetcher is a user agent string, which is applied to HTTP request headers when accessing external servers.
70
70
 
71
- HTML converted by the MarkDeco processor is formatted in a readable manner. Advanced options allow fine-tuning of formatting conditions.
71
+ HTML converted by the mark-deco processor is formatted in a readable manner. Advanced options allow fine-tuning of formatting conditions.
72
72
 
73
73
  ### Aborting Processor Operations
74
74
 
75
- While the MarkDeco processor engine itself doesn't access external servers, plugins may access external servers as needed (e.g., when using oEmbed APIs or performing page scraping).
75
+ While the mark-deco processor engine itself doesn't access external servers, plugins may access external servers as needed (e.g., when using oEmbed APIs or performing page scraping).
76
76
 
77
77
  To enable operation cancellation in such cases, pass an ECMAScript standard `AbortSignal` instance to notify cancellation signals:
78
78
 
@@ -93,18 +93,14 @@ For usage of `AbortController` and `AbortSignal`, refer to ECMAScript documentat
93
93
 
94
94
  ### CLI Interface
95
95
 
96
- Although MarkDeco is a library, a CLI interface is also available in the package that allows you to easily try out MarkDeco. This allows you to try out conversions without having to write code in TypeScript, or call it as an independent application from another code.
96
+ Although mark-deco is a library, a CLI interface is also available in the package that allows you to easily try out mark-deco. This allows you to try out conversions without having to write code in TypeScript, or call it as an independent application from another code.
97
97
 
98
98
  ```bash
99
99
  # Take Markdown from standard input and output HTML
100
100
  echo "# Hello World" | mark-deco-cli
101
101
  ```
102
102
 
103
- ## Documentation
104
-
105
- For detailed documentation and advanced features, please visit our [GitHub repository](https://github.com/kekyo/mark-deco).
106
-
107
- Key features include:
103
+ ## Supported Features
108
104
 
109
105
  - Frontmatter Information Extraction - Parse YAML frontmatter from Markdown files
110
106
  - Heading ID Generation and Heading Information Extraction - Automatically generate unique IDs for headings
@@ -113,6 +109,19 @@ Key features include:
113
109
  - Creating Custom Plugins - Develop custom plugins to extend Markdown processing
114
110
  - CLI Application - Command-line interface for batch processing
115
111
 
112
+ ---
113
+
114
+ ## Documentation
115
+
116
+ For detailed documentation and advanced features, please visit our [GitHub repository](https://github.com/kekyo/mark-deco/).
117
+
118
+ ## Note
119
+
120
+ This library was born when we determined during the development of [a-terra-forge](https://github.com/kekyo/a-terra-forge/) that it would be better to separate the conversion engine into a standalone component.
121
+
122
+ The project includes a demonstration page that can be run with `npm run dev`.
123
+ Additionally, using a-terra-forge allows you to verify the implementation of a site generator utilizing mark-deco.
124
+
116
125
  ## License
117
126
 
118
127
  Under MIT.
package/dist/browser.cjs CHANGED
@@ -1,11 +1,11 @@
1
1
  /*!
2
2
  * name: mark-deco
3
- * version: 0.29.0
3
+ * version: 1.1.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: 671fab29f293a6a2bb863f3b1d1d00cb1c3112d5
8
+ * git.commit.hash: 1671d139a7f806a597d37327b87576bd3e85d817
9
9
  */
10
10
 
11
11
  "use strict";
package/dist/browser.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /*!
2
2
  * name: mark-deco
3
- * version: 0.29.0
3
+ * version: 1.1.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: 671fab29f293a6a2bb863f3b1d1d00cb1c3112d5
8
+ * git.commit.hash: 1671d139a7f806a597d37327b87576bd3e85d817
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.29.0
3
+ * version: 1.1.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: 671fab29f293a6a2bb863f3b1d1d00cb1c3112d5
8
+ * git.commit.hash: 1671d139a7f806a597d37327b87576bd3e85d817
9
9
  */
10
10
 
11
11
  import { createMutex } from "async-primitives";
@@ -1,16 +1,16 @@
1
1
  /*!
2
2
  * name: mark-deco
3
- * version: 0.29.0
3
+ * version: 1.1.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: 671fab29f293a6a2bb863f3b1d1d00cb1c3112d5
8
+ * git.commit.hash: 1671d139a7f806a597d37327b87576bd3e85d817
9
9
  */
10
10
 
11
11
  "use strict";
12
12
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
13
- const htmlGenerator = require("./html-generator-BKd2MyoO.cjs");
13
+ const htmlGenerator = require("./html-generator-CHbU5jbh.cjs");
14
14
  const isProviderNotFoundError = (error) => {
15
15
  return error instanceof Error && error.message.startsWith("No oEmbed provider found for URL:");
16
16
  };
@@ -1,11 +1,11 @@
1
1
  /*!
2
2
  * name: mark-deco
3
- * version: 0.29.0
3
+ * version: 1.1.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: 671fab29f293a6a2bb863f3b1d1d00cb1c3112d5
8
+ * git.commit.hash: 1671d139a7f806a597d37327b87576bd3e85d817
9
9
  */
10
10
 
11
11
  /**
@@ -1,14 +1,14 @@
1
1
  /*!
2
2
  * name: mark-deco
3
- * version: 0.29.0
3
+ * version: 1.1.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: 671fab29f293a6a2bb863f3b1d1d00cb1c3112d5
8
+ * git.commit.hash: 1671d139a7f806a597d37327b87576bd3e85d817
9
9
  */
10
10
 
11
- import { f as fetchOEmbedData, b as generateHtml, C as CORSError } from "./html-generator-CClcgkAK.js";
11
+ import { f as fetchOEmbedData, b as generateHtml, C as CORSError } from "./html-generator-RU0HacgN.js";
12
12
  const isProviderNotFoundError = (error) => {
13
13
  return error instanceof Error && error.message.startsWith("No oEmbed provider found for URL:");
14
14
  };
@@ -1,16 +1,16 @@
1
1
  /*!
2
2
  * name: mark-deco
3
- * version: 0.29.0
3
+ * version: 1.1.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: 671fab29f293a6a2bb863f3b1d1d00cb1c3112d5
8
+ * git.commit.hash: 1671d139a7f806a597d37327b87576bd3e85d817
9
9
  */
10
10
 
11
11
  import * as cheerio from "cheerio";
12
- import { a as isCORSError, i as isBrowser } from "./utils-B06SsBEd.js";
13
- import { d as createResponsiveImageWithContainer, h as createResponsiveImageTag } from "./html-generator-CClcgkAK.js";
12
+ import { a as isCORSError, i as isBrowser } from "./utils-DLDazcJ8.js";
13
+ import { d as createResponsiveImageWithContainer, h as createResponsiveImageTag } from "./html-generator-RU0HacgN.js";
14
14
  const formatErrorInfo = (error) => {
15
15
  var _a, _b;
16
16
  if (!error) {
@@ -968,4 +968,4 @@ export {
968
968
  resolveUrl as r,
969
969
  truncateText as t
970
970
  };
971
- //# sourceMappingURL=html-generator-DOlAM9Ff.js.map
971
+ //# sourceMappingURL=html-generator-BmIuyVQU.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"html-generator-DOlAM9Ff.js","sources":["../src/plugins/shared/error-formatter.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 * 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 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":["e","resolveUrl"],"mappings":"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"}
1
+ {"version":3,"file":"html-generator-BmIuyVQU.js","sources":["../src/plugins/shared/error-formatter.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 * 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 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":["e","resolveUrl"],"mappings":"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"}
@@ -1,15 +1,15 @@
1
1
  /*!
2
2
  * name: mark-deco
3
- * version: 0.29.0
3
+ * version: 1.1.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: 671fab29f293a6a2bb863f3b1d1d00cb1c3112d5
8
+ * git.commit.hash: 1671d139a7f806a597d37327b87576bd3e85d817
9
9
  */
10
10
 
11
11
  "use strict";
12
- const utils = require("./utils-CoXrMKLM.cjs");
12
+ const utils = require("./utils-DBRV1kXj.cjs");
13
13
  const decodeHtmlEntities = (str) => {
14
14
  const entities = {
15
15
  "&amp;": "&",
@@ -640,4 +640,4 @@ exports.generateFallbackHtml = generateFallbackHtml;
640
640
  exports.generateHtml = generateHtml;
641
641
  exports.generateResponsiveImageStyles = generateResponsiveImageStyles;
642
642
  exports.isValidUrl = isValidUrl;
643
- //# sourceMappingURL=html-generator-BKd2MyoO.cjs.map
643
+ //# sourceMappingURL=html-generator-CHbU5jbh.cjs.map