vitepress-linkcard 2.0.0 → 2.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.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  <h1 align="center">
2
- vitepress-linkcard
2
+
3
+ vitepress-linkcard [![NPM License](https://img.shields.io/npm/l/vitepress-linkcard)](/LICENSE)
4
+
3
5
  </h1>
4
6
 
5
7
  <div align="center">
@@ -10,14 +12,12 @@ You can see: [A blog generated with this plugin](https://asumoranda.com/posts/10
10
12
 
11
13
  [![NPM Version](https://img.shields.io/npm/v/vitepress-linkcard?style=flat&logo=npm&logoColor=white&label=npmjs&color=%23CB3837)](https://www.npmjs.com/package/vitepress-linkcard)
12
14
  [![NPM bundle size](https://img.shields.io/bundlephobia/min/vitepress-linkcard)](https://www.npmjs.com/package/vitepress-linkcard)
13
- [![VitePress](https://img.shields.io/badge/For_VitePress-v1-%235C73E7?logo=vitepress&logoColor=white)](https://vuejs.github.io/vitepress/v1/)
14
- [![NPM License](https://img.shields.io/npm/l/vitepress-linkcard)](/LICENSE)
15
+ [![VitePress](https://img.shields.io/badge/For_VitePress-v1_|_v2-%235C73E7?logo=vitepress&logoColor=white)](https://vuejs.github.io/vitepress/v1]/)
15
16
 
16
17
  [![Yarn](https://img.shields.io/badge/Built_with_Yarn-v4.9.2-%232C8EBB?logo=yarn&logoColor=white)](https://yarnpkg.com/)
17
- [![ESLint](https://img.shields.io/badge/Lint_with-ESLint-%234B32C3?style=flat&logo=eslint&logoColor=white&labelColor=gray)](https://github.com/asumo-1xts/vitepress-linkcard/actions/workflows/eslint.yml)
18
- [![Prettier](https://img.shields.io/badge/Format_with-Prettier-%23F7B93E?style=flat&logo=prettier&logoColor=white&labelColor=gray)](https://github.com/asumo-1xts/vitepress-linkcard/actions/workflows/prettier.yml)
18
+ [![Oxc](https://img.shields.io/badge/Oxc-%2300F7F1?logo=oxc&logoColor=white&label=Lint%20and%20Format%20with&labelColor=gray)](https://oxc.rs/)
19
19
 
20
- <img src="https://github.com/asumo-1xts/vitepress-linkcard/blob/main/.github/screen.webp?raw=true" width=90% alt="How it shows" />
20
+ <img src="https://github.com/asumo-1xts/vitepress-linkcard/blob/main/.github/screen.gif?raw=true" width=90% alt="How it shows" />
21
21
 
22
22
  This plugin was forked from [markdown-it-link-to-card](https://github.com/luckrya/markdown-it-link-to-card).
23
23
 
@@ -38,9 +38,9 @@ pnpm add -D vitepress-linkcard # pnpm
38
38
  #### `docs/.vitepress/config.ts`
39
39
 
40
40
  ```ts
41
- import { defineConfig } from "vitepress";
42
- import { linkToCardPlugin } from "vitepress-linkcard";
43
- import type { LinkToCardPluginOptions } from "vitepress-linkcard";
41
+ import { defineConfig } from 'vitepress'
42
+ import { linkToCardPlugin } from 'vitepress-linkcard'
43
+ import type { LinkToCardPluginOptions } from 'vitepress-linkcard'
44
44
 
45
45
  export default defineConfig({
46
46
  // ...
@@ -48,11 +48,11 @@ export default defineConfig({
48
48
  config: (md) => {
49
49
  md.use<LinkToCardPluginOptions>(linkToCardPlugin, {
50
50
  // target: "_self" // if needed
51
- });
52
- },
51
+ })
52
+ }
53
53
  }
54
54
  // ...
55
- });
55
+ })
56
56
  ```
57
57
 
58
58
  #### `*.md`
@@ -88,7 +88,7 @@ You can customize:
88
88
  #### `docs/.vitepress/theme/custom.css`
89
89
 
90
90
  ```css
91
- /* For example: like Features in VitePress */
91
+ /* For example: like "Features" in VitePress */
92
92
 
93
93
  .vitepress-linkcard-container {
94
94
  border-color: #00000000 !important;
@@ -103,8 +103,18 @@ You can customize:
103
103
 
104
104
  #### `docs/.vitepress/theme/index.ts`
105
105
 
106
- ``` ts
107
- import './style.css'
106
+ ```ts
107
+ import DefaultTheme from 'vitepress/theme-without-fonts'
108
+ import type { Theme as ThemeConfig } from 'vitepress'
109
+ import './custom.css'
110
+
111
+ const Theme: ThemeConfig = {
112
+ extends: DefaultTheme
113
+ }
114
+
115
+ export default {
116
+ ...Theme
117
+ }
108
118
  ```
109
119
 
110
120
  ## Other specifications
@@ -119,7 +129,7 @@ You can move it to `.config` directory or edit it if needed.
119
129
 
120
130
  When the domain is `github.com`, trimming is performed as shown in the following example to avoid duplication of the title and description.
121
131
 
122
- | | Title | Description |
123
- | - | - | - |
132
+ | | Title | Description |
133
+ | ------ | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
124
134
  | Before | GitHub - asumo-1xts/vitepress-linkcard: A VitePress plugin to generate a pretty linkcard. | A VitePress plugin to generate a pretty linkcard. Contribute to asumo-1xts/vitepress-linkcard development by creating an account on GitHub. |
125
- | After | asumo-1xts/vitepress-linkcard | A VitePress plugin to generate a pretty linkcard. |
135
+ | After | asumo-1xts/vitepress-linkcard | A VitePress plugin to generate a pretty linkcard. |
package/dist/.cjs.min.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * vitepress-linkcard v2.0.0
2
+ * vitepress-linkcard v2.0.1
3
3
  * (c) 2022 - 2026 luckrya
4
4
  * Released under the MIT License.
5
5
  */
@@ -8,7 +8,7 @@ Object.defineProperty(exports,"__esModule",{value:!0});var e=require("url"),t=re
8
8
  * @luckrya/utility v0.1.0
9
9
  * (c) 2022 - 2022 Y.R
10
10
  * Released under the MIT License.
11
- */(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function m(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}(c=s||(s={})).Array="[object Array]",c.Object="[object Object]",c.Function="[object Function]",c.Number="[object Number]",c.String="[object String]",c.Boolean="[object Boolean]",c.Undefined="[object Undefined]",c.Null="[object Null]",c.Error="[object Error]";var x=function(e){return Object.prototype.toString.call(e)===s.String},S=function(e){return Object.prototype.toString.call(e)===s.Function},O="undefined"!=typeof window,k=function(){var e,t="".concat(process.cwd(),"/.linkcard_cache.json"),r="".concat(process.cwd(),"/.config/.linkcard_cache.json");if(h.default.existsSync(t))e=t;else if(h.default.existsSync(r))e=r;else{e=t;h.default.writeFileSync(e,JSON.stringify({"https://example.com/":{description:"Example Website",logo:"https://example.com/example.png",title:"Example Title"}},null,2))}return e},N=function(){return function(e,t,r){return t&&g(e.prototype,t),r&&g(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}(function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e)},[{key:"setFile",value:function(e){var t=e,r=this.readFile();r&&(t=Object.assign(r,t)),h.default.writeFileSync(k(),JSON.stringify(t)),function(){var e=k(),t=h.default.readFileSync(e,"utf-8").trim();if(t){var r=JSON.parse(t),n=JSON.stringify(r,null,2)+"\n";h.default.writeFileSync(e,n)}}()}},{key:"readFile",value:function(){var e=h.default.readFileSync(k(),"utf-8"),t=JSON.parse(e);if(function(e){return Object.prototype.toString.call(e)===s.Object}(t))return t}},{key:"has",value:function(e){return!!this.get(e)}},{key:"get",value:function(e){var t=this.readFile();return null==t?void 0:t[e]}},{key:"set",value:function(e,t){this.setFile(y({},e,t))}}])}(),T=new N;function j(e){return'style="'.concat(function(e){return Object.entries(e).map(function(e){var t,r=w(e,2),n=r[0],o=r[1];if(n&&o)return"".concat((t=n,t.replace(/\B([A-Z])/g,"-$1").toLowerCase()),": ").concat(o,";")}).filter(Boolean).join(" ")}(e),'"')}var C=function(e){return{"-webkit-box-orient":"vertical","-webkit-line-clamp":e,display:"-webkit-box",hyphens:"auto",lineClamp:e,overflow:"hidden",overflowWrap:"anywhere",textOverflow:"ellipsis",wordBreak:"break-word"}},R=function(e,t){var r,n,o={rel:'rel="noopener noreferrer"',target:'target="'.concat(t.target,'"'),href:'href="'.concat(t.href,'"'),title:'title="'.concat(t.linkTitle,'"')},i=function(e){return e.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#039;/g,"'")},a={a:j({color:"unset !important",display:"block",width:"100%",textDecoration:"none"}),container:j({display:"flex",alignItems:"center",flexWrap:"wrap",gap:"10px",borderRadius:"12px",border:"1px solid var(--vp-c-bg-soft)",backgroundColor:"var(--vp-c-bg-soft)",boxSizing:"border-box",width:"100%",height:"130px",transition:"border-color 0.25s, background-color 0.25s"}),img:j({borderRadius:"0px 12px 12px 0px",maxWidth:"40%",height:"128px",flexShrink:0,objectFit:"contain",overflow:"hidden"}),texts:j({flex:"1 1 0%",minWidth:"0"}),title:j(E(E({},C(2)),{},{opacity:1,fontSize:"16px",lineHeight:"22px",margin:"0 16px 8px 16px",fontWeight:"bold"})),domain:j(E(E({},C(1)),{},{opacity:1,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 8px 16px",textDecoration:"underline"})),description:j(E(E({},C(2)),{},{opacity:.8,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 0px 16px"}))},s=t.href||"",c=new URL(s).origin.replace(/^https?:\/\//,"").replace(/^www\./,"")||"Unknown domain",l=e.title,u=e.description;"github.com"==c?(l=(null===(r=e.title)||void 0===r?void 0:r.split(":")[0].replace("GitHub - ",""))||"No title",u=(null===(n=u)||void 0===n?void 0:n.replace(" - ".concat(l),"").replace("Contribute to ".concat(l," development by creating an account on GitHub."),""))||""):(l=e.title||"No title",u=e.description||"");return'<span style="display:block;">\n <a '.concat(o.rel," ").concat(o.target," ").concat(o.href," ").concat(o.title," ").concat(a.a,'>\n <span class="vitepress-linkcard-container" ').concat(a.container,">\n <span ").concat(a.texts,">\n <span ").concat(a.title,">\n ").concat(i(l),"\n </span>\n <span ").concat(a.domain,">\n ").concat(i(c),"\n </span>\n <span ").concat(a.description,">\n ").concat(i(u),'\n </span>\n </span>\n <img src="').concat(null==e?void 0:e.logo,'" ').concat(a.img,"/>\n </span>\n </a>\n</span>")};function D(e){return new URL(e)}var A="https://resources.whatwg.org/logo-url.svg",L=/(<[A-Za-z]+\s*[^>]*>(.*)<\/[A-Za-z]+>)/,q=/content=["|']([^>]*)["|']/,P=/href=["|']([^>]*)["|']/,H=/(<title\s*[^>]*>(.*)<\/title>)/g,F=function(e){return new RegExp("<".concat(arguments.length>1&&void 0!==arguments[1]?arguments[1]:"meta","\\s[^>]*\\w+=['|\"]([a-zA-Z]|:|\\s)*").concat(e,"['|\"][^>]*\\/?>"))};function _(e){var t,r=e.match(F("title"));if(null!=r&&r.length){var n=r[0].match(q);n&&x(n[1])&&(t=n[1])}else{var o=e.match(H);if(null!=o&&o.length){var i=o[0].match(L);i&&x(i[2])&&(t=i[2])}}return t}function I(e){var t,r=e.match(F("description"));if(null!=r&&r.length){var n=r[0].match(q);n&&x(n[1])&&(t=n[1])}return t}function U(e){var t,r=e.match(F("image"));if(null!=r&&r.length){var n=r[0].match(q);n&&x(n[1])&&(t=n[1])}else{var o=e.match(F("icon","link"));if(null!=o&&o.length){var i=o[0].match(P);i&&x(i[1])&&(t=i[1])}}return t}function M(e,t){var r,n,o,i={title:_(e),description:I(e),logo:(r=U(e),r?D(r)?r:"".concat(null===(n=D(t))||void 0===n?void 0:n.origin).concat("/".concat(r).replace(/\/\//g,"/")):A)};return o=i,Object.values(o).filter(function(e){return x(e)}).length?i:null}function B(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var J,G={};
11
+ */(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function m(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}(c=s||(s={})).Array="[object Array]",c.Object="[object Object]",c.Function="[object Function]",c.Number="[object Number]",c.String="[object String]",c.Boolean="[object Boolean]",c.Undefined="[object Undefined]",c.Null="[object Null]",c.Error="[object Error]";var x=function(e){return Object.prototype.toString.call(e)===s.String},S=function(e){return Object.prototype.toString.call(e)===s.Function},O="undefined"!=typeof window,k=function(){var e,t="".concat(process.cwd(),"/.linkcard_cache.json"),r="".concat(process.cwd(),"/.config/.linkcard_cache.json");if(h.default.existsSync(t))e=t;else if(h.default.existsSync(r))e=r;else{e=t;h.default.writeFileSync(e,JSON.stringify({"https://example.com/":{description:"Example Website",logo:"https://example.com/example.png",title:"Example Title"}},null,2))}return e},N=function(){return function(e,t,r){return t&&g(e.prototype,t),r&&g(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}(function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e)},[{key:"setFile",value:function(e){var t=e,r=this.readFile();r&&(t=Object.assign(r,t)),h.default.writeFileSync(k(),JSON.stringify(t)),function(){var e=k(),t=h.default.readFileSync(e,"utf-8").trim();if(t){var r=JSON.parse(t),n=JSON.stringify(r,null,2)+"\n";h.default.writeFileSync(e,n)}}()}},{key:"readFile",value:function(){var e=h.default.readFileSync(k(),"utf-8"),t=JSON.parse(e);if(function(e){return Object.prototype.toString.call(e)===s.Object}(t))return t}},{key:"has",value:function(e){return!!this.get(e)}},{key:"get",value:function(e){var t=this.readFile();return null==t?void 0:t[e]}},{key:"set",value:function(e,t){this.setFile(y({},e,t))}}])}(),T=new N;function j(e){return'style="'.concat(function(e){return Object.entries(e).map(function(e){var t,r=w(e,2),n=r[0],o=r[1];if(n&&o)return"".concat((t=n,t.replace(/\B([A-Z])/g,"-$1").toLowerCase()),": ").concat(o,";")}).filter(Boolean).join(" ")}(e),'"')}var C=function(e){return{"-webkit-box-orient":"vertical","-webkit-line-clamp":e,display:"-webkit-box",hyphens:"auto",lineClamp:e,overflow:"hidden",overflowWrap:"anywhere",textOverflow:"ellipsis",wordBreak:"break-word"}},R=function(e,t){var r,n,o={rel:'rel="noopener noreferrer"',target:'target="'.concat(t.target,'"'),href:'href="'.concat(t.href,'"'),title:'title="'.concat(t.linkTitle,'"')},i=function(e){return e.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#039;/g,"'")},a={a:j({color:"unset !important",display:"block",width:"100%",textDecoration:"none"}),container:j({display:"flex",alignItems:"center",flexWrap:"wrap",gap:"10px",borderRadius:"12px",border:"1px solid var(--vp-c-bg-soft)",backgroundColor:"var(--vp-c-bg-soft)",boxSizing:"border-box",width:"100%",height:"130px",transition:"border-color 0.25s, background-color 0.25s"}),img:j({borderRadius:"0px 12px 12px 0px",maxWidth:"40%",height:"129px",flexShrink:0,objectFit:"contain",overflow:"hidden"}),texts:j({flex:"1 1 0%",minWidth:"0"}),title:j(E(E({},C(2)),{},{opacity:1,fontSize:"16px",lineHeight:"22px",margin:"0 16px 8px 16px",fontWeight:"bold"})),domain:j(E(E({},C(1)),{},{opacity:1,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 8px 16px",textDecoration:"underline"})),description:j(E(E({},C(2)),{},{opacity:.8,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 0px 16px"}))},s=t.href||"",c=new URL(s).origin.replace(/^https?:\/\//,"").replace(/^www\./,"")||"Unknown domain",l=e.title,u=e.description;"github.com"==c?(l=(null===(r=e.title)||void 0===r?void 0:r.split(":")[0].replace("GitHub - ",""))||"No title",u=(null===(n=u)||void 0===n?void 0:n.replace(" - ".concat(l),"").replace("Contribute to ".concat(l," development by creating an account on GitHub."),""))||""):(l=e.title||"No title",u=e.description||"");return'<span style="display:block;">\n <a '.concat(o.rel," ").concat(o.target," ").concat(o.href," ").concat(o.title," ").concat(a.a,'>\n <span class="vitepress-linkcard-container" ').concat(a.container,">\n <span ").concat(a.texts,">\n <span ").concat(a.title,">\n ").concat(i(l),"\n </span>\n <span ").concat(a.domain,">\n ").concat(i(c),"\n </span>\n <span ").concat(a.description,">\n ").concat(i(u),'\n </span>\n </span>\n <img src="').concat(null==e?void 0:e.logo,'" ').concat(a.img,"/>\n </span>\n </a>\n</span>")};function D(e){return new URL(e)}var A="https://resources.whatwg.org/logo-url.svg",L=/(<[A-Za-z]+\s*[^>]*>(.*)<\/[A-Za-z]+>)/,q=/content=["|']([^>]*)["|']/,P=/href=["|']([^>]*)["|']/,H=/(<title\s*[^>]*>(.*)<\/title>)/g,F=function(e){return new RegExp("<".concat(arguments.length>1&&void 0!==arguments[1]?arguments[1]:"meta","\\s[^>]*\\w+=['|\"]([a-zA-Z]|:|\\s)*").concat(e,"['|\"][^>]*\\/?>"))};function _(e){var t,r=e.match(F("title"));if(null!=r&&r.length){var n=r[0].match(q);n&&x(n[1])&&(t=n[1])}else{var o=e.match(H);if(null!=o&&o.length){var i=o[0].match(L);i&&x(i[2])&&(t=i[2])}}return t}function I(e){var t,r=e.match(F("description"));if(null!=r&&r.length){var n=r[0].match(q);n&&x(n[1])&&(t=n[1])}return t}function U(e){var t,r=e.match(F("image"));if(null!=r&&r.length){var n=r[0].match(q);n&&x(n[1])&&(t=n[1])}else{var o=e.match(F("icon","link"));if(null!=o&&o.length){var i=o[0].match(P);i&&x(i[1])&&(t=i[1])}}return t}function M(e,t){var r,n,o,i={title:_(e),description:I(e),logo:(r=U(e),r?D(r)?r:"".concat(null===(n=D(t))||void 0===n?void 0:n.origin).concat("/".concat(r).replace(/\/\//g,"/")):A)};return o=i,Object.values(o).filter(function(e){return x(e)}).length?i:null}function B(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var J,G={};
12
12
  /**
13
13
  * Wrapper for built-in http.js to emulate the browser XMLHttpRequest object.
14
14
  *
package/dist/.esm.min.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * vitepress-linkcard v2.0.0
2
+ * vitepress-linkcard v2.0.1
3
3
  * (c) 2022 - 2026 luckrya
4
4
  * Released under the MIT License.
5
5
  */
@@ -8,7 +8,7 @@ import e from"url";import t from"child_process";import r from"fs";import n from"
8
8
  * @luckrya/utility v0.1.0
9
9
  * (c) 2022 - 2022 Y.R
10
10
  * Released under the MIT License.
11
- */(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function p(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}var d,h;(h=d||(d={})).Array="[object Array]",h.Object="[object Object]",h.Function="[object Function]",h.Number="[object Number]",h.String="[object String]",h.Boolean="[object Boolean]",h.Undefined="[object Undefined]",h.Null="[object Null]",h.Error="[object Error]";var v=function(e){return Object.prototype.toString.call(e)===d.String},g=function(e){return Object.prototype.toString.call(e)===d.Function},y="undefined"!=typeof window,b=function(){var e,t="".concat(process.cwd(),"/.linkcard_cache.json"),r="".concat(process.cwd(),"/.config/.linkcard_cache.json");if(i.existsSync(t))e=t;else if(i.existsSync(r))e=r;else{e=t;i.writeFileSync(e,JSON.stringify({"https://example.com/":{description:"Example Website",logo:"https://example.com/example.png",title:"Example Title"}},null,2))}return e},m=function(){return function(e,t,r){return t&&s(e.prototype,t),r&&s(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}(function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e)},[{key:"setFile",value:function(e){var t=e,r=this.readFile();r&&(t=Object.assign(r,t)),i.writeFileSync(b(),JSON.stringify(t)),function(){var e=b(),t=i.readFileSync(e,"utf-8").trim();if(t){var r=JSON.parse(t),n=JSON.stringify(r,null,2)+"\n";i.writeFileSync(e,n)}}()}},{key:"readFile",value:function(){var e=i.readFileSync(b(),"utf-8"),t=JSON.parse(e);if(function(e){return Object.prototype.toString.call(e)===d.Object}(t))return t}},{key:"has",value:function(e){return!!this.get(e)}},{key:"get",value:function(e){var t=this.readFile();return null==t?void 0:t[e]}},{key:"set",value:function(e,t){this.setFile(c({},e,t))}}])}(),E=new m;function w(e){return'style="'.concat(function(e){return Object.entries(e).map(function(e){var t,r=f(e,2),n=r[0],o=r[1];if(n&&o)return"".concat((t=n,t.replace(/\B([A-Z])/g,"-$1").toLowerCase()),": ").concat(o,";")}).filter(Boolean).join(" ")}(e),'"')}var x=function(e){return{"-webkit-box-orient":"vertical","-webkit-line-clamp":e,display:"-webkit-box",hyphens:"auto",lineClamp:e,overflow:"hidden",overflowWrap:"anywhere",textOverflow:"ellipsis",wordBreak:"break-word"}},S=function(e,t){var r,n,o={rel:'rel="noopener noreferrer"',target:'target="'.concat(t.target,'"'),href:'href="'.concat(t.href,'"'),title:'title="'.concat(t.linkTitle,'"')},i=function(e){return e.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#039;/g,"'")},a={a:w({color:"unset !important",display:"block",width:"100%",textDecoration:"none"}),container:w({display:"flex",alignItems:"center",flexWrap:"wrap",gap:"10px",borderRadius:"12px",border:"1px solid var(--vp-c-bg-soft)",backgroundColor:"var(--vp-c-bg-soft)",boxSizing:"border-box",width:"100%",height:"130px",transition:"border-color 0.25s, background-color 0.25s"}),img:w({borderRadius:"0px 12px 12px 0px",maxWidth:"40%",height:"128px",flexShrink:0,objectFit:"contain",overflow:"hidden"}),texts:w({flex:"1 1 0%",minWidth:"0"}),title:w(u(u({},x(2)),{},{opacity:1,fontSize:"16px",lineHeight:"22px",margin:"0 16px 8px 16px",fontWeight:"bold"})),domain:w(u(u({},x(1)),{},{opacity:1,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 8px 16px",textDecoration:"underline"})),description:w(u(u({},x(2)),{},{opacity:.8,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 0px 16px"}))},s=t.href||"",c=new URL(s).origin.replace(/^https?:\/\//,"").replace(/^www\./,"")||"Unknown domain",l=e.title,f=e.description;"github.com"==c?(l=(null===(r=e.title)||void 0===r?void 0:r.split(":")[0].replace("GitHub - ",""))||"No title",f=(null===(n=f)||void 0===n?void 0:n.replace(" - ".concat(l),"").replace("Contribute to ".concat(l," development by creating an account on GitHub."),""))||""):(l=e.title||"No title",f=e.description||"");return'<span style="display:block;">\n <a '.concat(o.rel," ").concat(o.target," ").concat(o.href," ").concat(o.title," ").concat(a.a,'>\n <span class="vitepress-linkcard-container" ').concat(a.container,">\n <span ").concat(a.texts,">\n <span ").concat(a.title,">\n ").concat(i(l),"\n </span>\n <span ").concat(a.domain,">\n ").concat(i(c),"\n </span>\n <span ").concat(a.description,">\n ").concat(i(f),'\n </span>\n </span>\n <img src="').concat(null==e?void 0:e.logo,'" ').concat(a.img,"/>\n </span>\n </a>\n</span>")};function O(e){return new URL(e)}var k="https://resources.whatwg.org/logo-url.svg",N=/(<[A-Za-z]+\s*[^>]*>(.*)<\/[A-Za-z]+>)/,T=/content=["|']([^>]*)["|']/,j=/href=["|']([^>]*)["|']/,C=/(<title\s*[^>]*>(.*)<\/title>)/g,R=function(e){return new RegExp("<".concat(arguments.length>1&&void 0!==arguments[1]?arguments[1]:"meta","\\s[^>]*\\w+=['|\"]([a-zA-Z]|:|\\s)*").concat(e,"['|\"][^>]*\\/?>"))};function D(e){var t,r=e.match(R("title"));if(null!=r&&r.length){var n=r[0].match(T);n&&v(n[1])&&(t=n[1])}else{var o=e.match(C);if(null!=o&&o.length){var i=o[0].match(N);i&&v(i[2])&&(t=i[2])}}return t}function A(e){var t,r=e.match(R("description"));if(null!=r&&r.length){var n=r[0].match(T);n&&v(n[1])&&(t=n[1])}return t}function L(e){var t,r=e.match(R("image"));if(null!=r&&r.length){var n=r[0].match(T);n&&v(n[1])&&(t=n[1])}else{var o=e.match(R("icon","link"));if(null!=o&&o.length){var i=o[0].match(j);i&&v(i[1])&&(t=i[1])}}return t}function P(e,t){var r,n,o,i={title:D(e),description:A(e),logo:(r=L(e),r?O(r)?r:"".concat(null===(n=O(t))||void 0===n?void 0:n.origin).concat("/".concat(r).replace(/\/\//g,"/")):k)};return o=i,Object.values(o).filter(function(e){return v(e)}).length?i:null}function q(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var H,F={};
11
+ */(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function p(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}var d,h;(h=d||(d={})).Array="[object Array]",h.Object="[object Object]",h.Function="[object Function]",h.Number="[object Number]",h.String="[object String]",h.Boolean="[object Boolean]",h.Undefined="[object Undefined]",h.Null="[object Null]",h.Error="[object Error]";var v=function(e){return Object.prototype.toString.call(e)===d.String},g=function(e){return Object.prototype.toString.call(e)===d.Function},y="undefined"!=typeof window,b=function(){var e,t="".concat(process.cwd(),"/.linkcard_cache.json"),r="".concat(process.cwd(),"/.config/.linkcard_cache.json");if(i.existsSync(t))e=t;else if(i.existsSync(r))e=r;else{e=t;i.writeFileSync(e,JSON.stringify({"https://example.com/":{description:"Example Website",logo:"https://example.com/example.png",title:"Example Title"}},null,2))}return e},m=function(){return function(e,t,r){return t&&s(e.prototype,t),r&&s(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}(function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e)},[{key:"setFile",value:function(e){var t=e,r=this.readFile();r&&(t=Object.assign(r,t)),i.writeFileSync(b(),JSON.stringify(t)),function(){var e=b(),t=i.readFileSync(e,"utf-8").trim();if(t){var r=JSON.parse(t),n=JSON.stringify(r,null,2)+"\n";i.writeFileSync(e,n)}}()}},{key:"readFile",value:function(){var e=i.readFileSync(b(),"utf-8"),t=JSON.parse(e);if(function(e){return Object.prototype.toString.call(e)===d.Object}(t))return t}},{key:"has",value:function(e){return!!this.get(e)}},{key:"get",value:function(e){var t=this.readFile();return null==t?void 0:t[e]}},{key:"set",value:function(e,t){this.setFile(c({},e,t))}}])}(),E=new m;function w(e){return'style="'.concat(function(e){return Object.entries(e).map(function(e){var t,r=f(e,2),n=r[0],o=r[1];if(n&&o)return"".concat((t=n,t.replace(/\B([A-Z])/g,"-$1").toLowerCase()),": ").concat(o,";")}).filter(Boolean).join(" ")}(e),'"')}var x=function(e){return{"-webkit-box-orient":"vertical","-webkit-line-clamp":e,display:"-webkit-box",hyphens:"auto",lineClamp:e,overflow:"hidden",overflowWrap:"anywhere",textOverflow:"ellipsis",wordBreak:"break-word"}},S=function(e,t){var r,n,o={rel:'rel="noopener noreferrer"',target:'target="'.concat(t.target,'"'),href:'href="'.concat(t.href,'"'),title:'title="'.concat(t.linkTitle,'"')},i=function(e){return e.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#039;/g,"'")},a={a:w({color:"unset !important",display:"block",width:"100%",textDecoration:"none"}),container:w({display:"flex",alignItems:"center",flexWrap:"wrap",gap:"10px",borderRadius:"12px",border:"1px solid var(--vp-c-bg-soft)",backgroundColor:"var(--vp-c-bg-soft)",boxSizing:"border-box",width:"100%",height:"130px",transition:"border-color 0.25s, background-color 0.25s"}),img:w({borderRadius:"0px 12px 12px 0px",maxWidth:"40%",height:"129px",flexShrink:0,objectFit:"contain",overflow:"hidden"}),texts:w({flex:"1 1 0%",minWidth:"0"}),title:w(u(u({},x(2)),{},{opacity:1,fontSize:"16px",lineHeight:"22px",margin:"0 16px 8px 16px",fontWeight:"bold"})),domain:w(u(u({},x(1)),{},{opacity:1,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 8px 16px",textDecoration:"underline"})),description:w(u(u({},x(2)),{},{opacity:.8,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 0px 16px"}))},s=t.href||"",c=new URL(s).origin.replace(/^https?:\/\//,"").replace(/^www\./,"")||"Unknown domain",l=e.title,f=e.description;"github.com"==c?(l=(null===(r=e.title)||void 0===r?void 0:r.split(":")[0].replace("GitHub - ",""))||"No title",f=(null===(n=f)||void 0===n?void 0:n.replace(" - ".concat(l),"").replace("Contribute to ".concat(l," development by creating an account on GitHub."),""))||""):(l=e.title||"No title",f=e.description||"");return'<span style="display:block;">\n <a '.concat(o.rel," ").concat(o.target," ").concat(o.href," ").concat(o.title," ").concat(a.a,'>\n <span class="vitepress-linkcard-container" ').concat(a.container,">\n <span ").concat(a.texts,">\n <span ").concat(a.title,">\n ").concat(i(l),"\n </span>\n <span ").concat(a.domain,">\n ").concat(i(c),"\n </span>\n <span ").concat(a.description,">\n ").concat(i(f),'\n </span>\n </span>\n <img src="').concat(null==e?void 0:e.logo,'" ').concat(a.img,"/>\n </span>\n </a>\n</span>")};function O(e){return new URL(e)}var k="https://resources.whatwg.org/logo-url.svg",N=/(<[A-Za-z]+\s*[^>]*>(.*)<\/[A-Za-z]+>)/,T=/content=["|']([^>]*)["|']/,j=/href=["|']([^>]*)["|']/,C=/(<title\s*[^>]*>(.*)<\/title>)/g,R=function(e){return new RegExp("<".concat(arguments.length>1&&void 0!==arguments[1]?arguments[1]:"meta","\\s[^>]*\\w+=['|\"]([a-zA-Z]|:|\\s)*").concat(e,"['|\"][^>]*\\/?>"))};function D(e){var t,r=e.match(R("title"));if(null!=r&&r.length){var n=r[0].match(T);n&&v(n[1])&&(t=n[1])}else{var o=e.match(C);if(null!=o&&o.length){var i=o[0].match(N);i&&v(i[2])&&(t=i[2])}}return t}function A(e){var t,r=e.match(R("description"));if(null!=r&&r.length){var n=r[0].match(T);n&&v(n[1])&&(t=n[1])}return t}function L(e){var t,r=e.match(R("image"));if(null!=r&&r.length){var n=r[0].match(T);n&&v(n[1])&&(t=n[1])}else{var o=e.match(R("icon","link"));if(null!=o&&o.length){var i=o[0].match(j);i&&v(i[1])&&(t=i[1])}}return t}function P(e,t){var r,n,o,i={title:D(e),description:A(e),logo:(r=L(e),r?O(r)?r:"".concat(null===(n=O(t))||void 0===n?void 0:n.origin).concat("/".concat(r).replace(/\/\//g,"/")):k)};return o=i,Object.values(o).filter(function(e){return v(e)}).length?i:null}function q(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var H,F={};
12
12
  /**
13
13
  * Wrapper for built-in http.js to emulate the browser XMLHttpRequest object.
14
14
  *
package/dist/api.js CHANGED
@@ -1,37 +1,11 @@
1
1
  import { xhr, generateCardDomFragment, parserMetadata } from './assemble';
2
- /**
3
- * Internal cache storing generated card responses by URL.
4
- * This prevents redundant network requests and parsing operations for the same URLs.
5
- * @internal
6
- */
7
2
  const cache = new Map();
8
3
  /**
9
4
  * Generates a link card by fetching and parsing metadata from a URL.
10
5
  *
11
- * This function performs the following operations:
12
- * 1. Fetches the HTML content from the provided URL synchronously
13
- * 2. Parses metadata (title, description, logo) from the HTML
14
- * 3. Generates an HTML card fragment with the metadata
15
- * 4. Caches the result for subsequent calls
16
- *
17
- * The function is primarily used by the link-to-card plugin during markdown processing
18
- * but can also be used standalone for programmatic card generation.
19
- *
20
6
  * @param url - The URL to fetch metadata from
21
- * @param options - Rendering options for the card (excluding href, which is set to the url parameter)
7
+ * @param options - Rendering options for the card
22
8
  * @returns A promise that resolves to a CardResponse containing the card data and HTML
23
- *
24
- * @example
25
- * ```typescript
26
- * const card = await generateCard('https://example.com', {
27
- * linkTitle: 'Example Site',
28
- * target: '_blank'
29
- * })
30
- * console.log(card.dom) // HTML string of the card
31
- * ```
32
- *
33
- * @see {@link parserMetadata} for details on metadata extraction
34
- * @see {@link generateCardDomFragment} for details on card HTML generation
35
9
  */
36
10
  export function generateCard(url, options) {
37
11
  return new Promise((resolve) => {
@@ -2,55 +2,9 @@ import { STYLE } from './style';
2
2
  /**
3
3
  * Generates the HTML DOM fragment for a link card display.
4
4
  *
5
- * This is the default card renderer that creates a rich preview card with:
6
- * - Card title (with 2-line ellipsis)
7
- * - Domain name (with underline)
8
- * - Description (with 2-line ellipsis)
9
- * - Logo/icon image
10
- * - Smooth border transition for hover effects
11
- *
12
- * The function includes special handling for GitHub URLs to improve the display
13
- * of repository cards by cleaning up redundant text patterns.
14
- *
15
- * @param data - The metadata extracted from the URL (title, description, logo)
16
- * @param options - Rendering options including href, target, colors, etc.
17
- * @returns An HTML string containing the complete card markup with inline styles
18
- *
19
- * @example
20
- * ```typescript
21
- * const html = generateCardDomFragment(
22
- * { title: 'Example', description: 'A site', logo: 'https://...' },
23
- * { href: 'https://example.com', linkTitle: 'Link', target: '_blank' }
24
- * )
25
- * ```
26
- *
27
- * @remarks
28
- * - HTML entities in title/description are automatically escaped
29
- * - For GitHub URLs, the title is cleaned to remove "GitHub - " prefix and redundant text
30
- * - The card uses flexbox layout for responsive design
31
- * - All styles are inlined for maximum compatibility
32
- * - Container has class `vitepress-linkcard-container` for custom styling
33
- * - Uses CSS custom properties for theming:
34
- * - `--vitepress-linkcard-border-color`: Customize border color
35
- * - `--vitepress-linkcard-bg-color`: Customize background color
36
- * - Styling options in your VitePress theme's custom CSS:
37
- * ```css
38
- * .vitepress-linkcard-container {
39
- * --vitepress-linkcard-border-color: #e0e0e0;
40
- * --vitepress-linkcard-bg-color: #f9f9f9;
41
- * }
42
- *
43
- * .vitepress-linkcard-container {
44
- * border-color: var(--vp-c-brand-2) !important;
45
- * background-color: var(--vp-c-brand-soft) !important;
46
- * }
47
- *
48
- * .vitepress-linkcard-container:hover {
49
- * border-color: var(--vp-c-brand-1) !important;
50
- * }
51
- * ```
52
- *
53
- * @see {@link STYLE} for the styling implementation
5
+ * @param data - The metadata extracted from the URL
6
+ * @param options - Rendering options including href, target, etc.
7
+ * @returns An HTML string containing the card markup
54
8
  */
55
9
  export const generateCardDomFragment = (data, options) => {
56
10
  const aa = {
@@ -62,13 +16,6 @@ export const generateCardDomFragment = (data, options) => {
62
16
  const inject = (s) => {
63
17
  return s;
64
18
  };
65
- /**
66
- * Escapes HTML entities in a string to prevent XSS and display issues.
67
- *
68
- * @param str - The string to escape
69
- * @returns The escaped string safe for HTML insertion
70
- * @internal
71
- */
72
19
  const escapeHTML = (str) => str
73
20
  .replace(/&amp;/g, '&')
74
21
  .replace(/&lt;/g, '<')
@@ -81,12 +28,12 @@ export const generateCardDomFragment = (data, options) => {
81
28
  'Unknown domain';
82
29
  let title = data.title;
83
30
  let description = data.description;
84
- // Special handling for gitub.com
85
31
  if (domain == 'github.com') {
86
32
  title = data.title?.split(':')[0].replace('GitHub - ', '') || 'No title';
87
33
  description =
88
- description?.replace(` - ${title}`, '').replace(`Contribute to ${title} development by creating an account on GitHub.`, // 定型句
89
- '') || '';
34
+ description
35
+ ?.replace(` - ${title}`, '')
36
+ .replace(`Contribute to ${title} development by creating an account on GitHub.`, '') || '';
90
37
  }
91
38
  else {
92
39
  title = data.title || 'No title';
@@ -1,27 +1,5 @@
1
- /**
2
- * Local file-based cache implementation for persisting URL metadata.
3
- *
4
- * This module provides a simple key-value cache that persists data to a JSON file
5
- * on disk. It's used to cache fetched URL metadata to avoid redundant network requests
6
- * across different build sessions.
7
- *
8
- * @module local-file-cache
9
- */
10
1
  import { isPureObject } from '@luckrya/utility';
11
2
  import fs from 'node:fs';
12
- /**
13
- * Determines the path to the cache file.
14
- *
15
- * Checks for cache file existence in two locations:
16
- * 1. `.linkcard_cache.json` in the project root (preferred)
17
- * 2. `.config/.linkcard_cache.json` as fallback
18
- *
19
- * If neither exists, creates a new cache file with example data.
20
- *
21
- * @returns The absolute path to the cache file
22
- *
23
- * @internal
24
- */
25
3
  const CONFIG_FILE = () => {
26
4
  let filePath;
27
5
  const defaultPath = `${process.cwd()}/.linkcard_cache.json`;
@@ -45,14 +23,6 @@ const CONFIG_FILE = () => {
45
23
  }
46
24
  return filePath;
47
25
  };
48
- /**
49
- * Formats the cache file with consistent indentation.
50
- *
51
- * Reads the cache file, parses it, and rewrites it with proper JSON formatting
52
- * (2-space indentation) and a trailing newline.
53
- *
54
- * @internal
55
- */
56
26
  const format = () => {
57
27
  const filePath = CONFIG_FILE();
58
28
  const content = fs.readFileSync(filePath, 'utf-8').trim();
@@ -64,53 +34,9 @@ const format = () => {
64
34
  };
65
35
  /**
66
36
  * A simple file-based cache for storing and retrieving structured data.
67
- *
68
- * This class provides a Map-like interface for caching data that persists to disk
69
- * in JSON format. Each cache entry is keyed by URL and stores structured metadata.
70
- *
71
- * The cache file is automatically created if it doesn't exist, and all writes are
72
- * synchronized and formatted for readability.
73
- *
74
- * @template V - The value type, must extend Record<string, unknown>
75
- *
76
- * @example
77
- * ```typescript
78
- * const cache = new LocalFileCache<UrlMetadata>()
79
- *
80
- * // Store metadata
81
- * cache.set('https://example.com', {
82
- * title: 'Example',
83
- * description: 'A site',
84
- * logo: 'https://example.com/logo.png'
85
- * })
86
- *
87
- * // Retrieve metadata
88
- * const metadata = cache.get('https://example.com')
89
- *
90
- * // Check if URL is cached
91
- * if (cache.has('https://example.com')) {
92
- * console.log('URL is cached')
93
- * }
94
- * ```
95
- *
96
- * @remarks
97
- * - Cache is stored in `.linkcard_cache.json` at project root
98
- * - All operations are synchronous
99
- * - Cache persists across process restarts
100
- * - Merges new data with existing cache entries
101
37
  */
102
38
  export default class LocalFileCache {
103
39
  constructor() { }
104
- /**
105
- * Writes data to the cache file.
106
- *
107
- * Merges the provided data with existing cache content and writes the result
108
- * to disk. The file is automatically formatted after writing.
109
- *
110
- * @param data - Object mapping URLs to cached data
111
- *
112
- * @private
113
- */
114
40
  setFile(data) {
115
41
  let content = data;
116
42
  const _content = this.readFile();
@@ -120,13 +46,6 @@ export default class LocalFileCache {
120
46
  fs.writeFileSync(CONFIG_FILE(), JSON.stringify(content));
121
47
  format();
122
48
  }
123
- /**
124
- * Reads and parses the cache file.
125
- *
126
- * @returns The parsed cache data, or undefined if the file is empty or invalid
127
- *
128
- * @private
129
- */
130
49
  readFile() {
131
50
  const content = fs.readFileSync(CONFIG_FILE(), 'utf-8');
132
51
  const data = JSON.parse(content);
@@ -134,58 +53,13 @@ export default class LocalFileCache {
134
53
  return data;
135
54
  return undefined;
136
55
  }
137
- /**
138
- * Checks if a URL exists in the cache.
139
- *
140
- * @param url - The URL to check
141
- * @returns true if the URL has cached data, false otherwise
142
- *
143
- * @example
144
- * ```typescript
145
- * if (cache.has('https://example.com')) {
146
- * console.log('Cache hit!')
147
- * }
148
- * ```
149
- */
150
56
  has(url) {
151
57
  return !!this.get(url);
152
58
  }
153
- /**
154
- * Retrieves cached data for a URL.
155
- *
156
- * @param url - The URL to retrieve data for
157
- * @returns The cached data for the URL, or undefined if not found
158
- *
159
- * @example
160
- * ```typescript
161
- * const metadata = cache.get('https://example.com')
162
- * if (metadata) {
163
- * console.log(metadata.title)
164
- * }
165
- * ```
166
- */
167
59
  get(url) {
168
60
  const cache = this.readFile();
169
61
  return cache?.[url];
170
62
  }
171
- /**
172
- * Stores data in the cache for a URL.
173
- *
174
- * Adds or updates the cache entry for the specified URL. The data is merged
175
- * with existing cache content and persisted to disk.
176
- *
177
- * @param url - The URL to cache data for
178
- * @param data - The data to cache
179
- *
180
- * @example
181
- * ```typescript
182
- * cache.set('https://example.com', {
183
- * title: 'Example Domain',
184
- * description: 'Example description',
185
- * logo: 'https://example.com/logo.png'
186
- * })
187
- * ```
188
- */
189
63
  set(url, data) {
190
64
  this.setFile({ [url]: data });
191
65
  }
@@ -1,37 +1,11 @@
1
1
  import { parserMetadata, xhr } from '.';
2
2
  import LocalFileCache from './local-file-cache';
3
- /**
4
- * Local file cache instance for storing fetched URL metadata.
5
- * This cache persists metadata to disk to avoid repeated network requests.
6
- * @internal
7
- */
8
3
  const cache = new LocalFileCache();
9
4
  /**
10
5
  * Retrieves metadata for a given URL, using cache when available.
11
6
  *
12
- * This function first checks if the metadata is already cached. If not, it fetches
13
- * the HTML content from the URL, parses the metadata, and caches the result for
14
- * future use.
15
- *
16
- * The metadata includes:
17
- * - Title (from `<title>` or OGP tags)
18
- * - Description (from meta description or OGP tags)
19
- * - Logo/icon (from OGP image or favicon)
20
- *
21
7
  * @param url - The URL to fetch metadata from
22
- * @returns The parsed URL metadata, or null if the URL cannot be fetched or parsed
23
- *
24
- * @example
25
- * ```typescript
26
- * const metadata = getUrlMetadata('https://example.com')
27
- * if (metadata) {
28
- * console.log(metadata.title) // "Example Domain"
29
- * console.log(metadata.description) // "Example website description"
30
- * }
31
- * ```
32
- *
33
- * @see {@link parserMetadata} for details on metadata extraction
34
- * @see {@link LocalFileCache} for caching implementation
8
+ * @returns The parsed URL metadata, or null if unavailable
35
9
  */
36
10
  export function getUrlMetadata(url) {
37
11
  if (cache.has(url))