vitepress-linkcard 1.3.0 → 2.0.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 +36 -22
- package/dist/.cjs.min.js +5 -5
- package/dist/.esm.min.js +5 -5
- package/dist/api.js +31 -3
- package/dist/assemble/html.js +61 -8
- package/dist/assemble/local-file-cache.js +119 -8
- package/dist/assemble/metadata.js +30 -2
- package/dist/assemble/parser.js +133 -19
- package/dist/assemble/style.js +117 -18
- package/dist/assemble/url.js +35 -4
- package/dist/assemble/xhr.js +71 -5
- package/dist/link-to-card-plugin.js +104 -24
- package/package.json +2 -2
- package/types/api.d.ts +42 -3
- package/types/assemble/html.d.ts +51 -3
- package/types/assemble/local-file-cache.d.ts +98 -8
- package/types/assemble/metadata.d.ts +25 -2
- package/types/assemble/parser.d.ts +31 -4
- package/types/assemble/style.d.ts +56 -7
- package/types/assemble/url.d.ts +35 -4
- package/types/assemble/xhr.d.ts +62 -4
- package/types/link-to-card-plugin.d.ts +27 -2
- package/types/types.d.ts +103 -4
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ vitepress-linkcard
|
|
|
6
6
|
|
|
7
7
|
**A VitePress plugin to generate a pretty linkcard with OGP.**
|
|
8
8
|
|
|
9
|
-
A blog generated with this plugin
|
|
9
|
+
You can see: [A blog generated with this plugin](https://asumoranda.com/posts/10-vitepress-linkcard.html) | [Docs by TypeDoc](https://asumo-1xts.github.io/vitepress-linkcard/)
|
|
10
10
|
|
|
11
11
|
[](https://www.npmjs.com/package/vitepress-linkcard)
|
|
12
12
|
[](https://www.npmjs.com/package/vitepress-linkcard)
|
|
13
|
+
[](https://vuejs.github.io/vitepress/v1/)
|
|
13
14
|
[](/LICENSE)
|
|
14
15
|
|
|
15
|
-
[](https://vuejs.github.io/vitepress/v1/)
|
|
16
16
|
[](https://yarnpkg.com/)
|
|
17
17
|
[](https://github.com/asumo-1xts/vitepress-linkcard/actions/workflows/eslint.yml)
|
|
18
18
|
[](https://github.com/asumo-1xts/vitepress-linkcard/actions/workflows/prettier.yml)
|
|
@@ -47,10 +47,7 @@ export default defineConfig({
|
|
|
47
47
|
markdown: {
|
|
48
48
|
config: (md) => {
|
|
49
49
|
md.use<LinkToCardPluginOptions>(linkToCardPlugin, {
|
|
50
|
-
// //
|
|
51
|
-
// target: "_self",
|
|
52
|
-
// borderColor: "#039393",
|
|
53
|
-
// bgColor: "#CB3837"
|
|
50
|
+
// target: "_self" // if needed
|
|
54
51
|
});
|
|
55
52
|
},
|
|
56
53
|
}
|
|
@@ -68,30 +65,47 @@ Generates a linkcard when `@:` appended.
|
|
|
68
65
|
|
|
69
66
|
## Supported options
|
|
70
67
|
|
|
71
|
-
###
|
|
68
|
+
### Target
|
|
72
69
|
|
|
73
|
-
|
|
70
|
+
As shown in [Usage](#usage), you can specify the target window in which to open a link.
|
|
74
71
|
|
|
75
|
-
-
|
|
76
|
-
- `
|
|
77
|
-
-
|
|
72
|
+
- `_blank` **(default)**
|
|
73
|
+
- `_self`
|
|
74
|
+
- `_top`
|
|
75
|
+
- `_parent`
|
|
78
76
|
|
|
79
|
-
###
|
|
77
|
+
### Color theme
|
|
80
78
|
|
|
81
|
-
|
|
79
|
+
You can customize:
|
|
82
80
|
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
81
|
+
- Border color
|
|
82
|
+
- Background color
|
|
83
|
+
- Border color when hovered
|
|
84
|
+
- Background color when hovered
|
|
86
85
|
|
|
87
|
-
|
|
86
|
+
**By default, all colors are set to `var(--vp-c-bg-soft)`.**
|
|
88
87
|
|
|
89
|
-
|
|
88
|
+
#### `docs/.vitepress/theme/custom.css`
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
-
|
|
90
|
+
```css
|
|
91
|
+
/* For example: like Features in VitePress */
|
|
92
|
+
|
|
93
|
+
.vitepress-linkcard-container {
|
|
94
|
+
border-color: #00000000 !important;
|
|
95
|
+
background-color: var(--vp-c-bg-soft) !important;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.vitepress-linkcard-container:hover {
|
|
99
|
+
border-color: var(--vp-c-brand-1) !important;
|
|
100
|
+
background-color: var(--vp-c-bg-soft) !important;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### `docs/.vitepress/theme/index.ts`
|
|
105
|
+
|
|
106
|
+
``` ts
|
|
107
|
+
import './style.css'
|
|
108
|
+
```
|
|
95
109
|
|
|
96
110
|
## Other specifications
|
|
97
111
|
|
package/dist/.cjs.min.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* vitepress-linkcard
|
|
3
|
-
* (c) 2022 -
|
|
2
|
+
* vitepress-linkcard v2.0.0
|
|
3
|
+
* (c) 2022 - 2026 luckrya
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
Object.defineProperty(exports,"__esModule",{value:!0});var e=require("url"),t=require("child_process"),r=require("fs"),n=require("http"),o=require("https"),i=require("node:fs");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var s,c,l=a(e),u=a(t),
|
|
6
|
+
Object.defineProperty(exports,"__esModule",{value:!0});var e=require("url"),t=require("child_process"),r=require("fs"),n=require("http"),o=require("https"),i=require("node:fs");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var s,c,l=a(e),u=a(t),f=a(r),d=a(n),p=a(o),h=a(i);function v(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=Array(t);r<t;r++)n[r]=e[r];return n}function g(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,m(n.key),n)}}function y(e,t,r){return(t=m(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function b(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,n)}return r}function E(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?b(Object(r),!0).forEach(function(t){y(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):b(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}function w(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,o,i,a,s=[],c=!0,l=!1;try{if(i=(r=r.call(e)).next,0===t){if(Object(r)!==r)return;c=!1}else for(;!(c=(n=i.call(r)).done)&&(s.push(n.value),s.length!==t);c=!0);}catch(e){l=!0,o=e}finally{try{if(!c&&null!=r.return&&(a=r.return(),Object(a)!==a))return}finally{if(l)throw o}}return s}}(e,t)||function(e,t){if(e){if("string"==typeof e)return v(e,t);var r={}.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?v(e,t):void 0}}
|
|
7
7
|
/*!
|
|
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,
|
|
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(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/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={};
|
|
12
12
|
/**
|
|
13
13
|
* Wrapper for built-in http.js to emulate the browser XMLHttpRequest object.
|
|
14
14
|
*
|
|
@@ -20,4 +20,4 @@ Object.defineProperty(exports,"__esModule",{value:!0});var e=require("url"),t=re
|
|
|
20
20
|
* @author Dan DeFelippi <dan@driverdan.com>
|
|
21
21
|
* @contributor David Ellis <d.f.ellis@ieee.org>
|
|
22
22
|
* @license MIT
|
|
23
|
-
*/var z=function(){if(J)return G;J=1;var e=l.default,t=u.default.spawn,r=
|
|
23
|
+
*/var z=function(){if(J)return G;J=1;var e=l.default,t=u.default.spawn,r=f.default;return G.XMLHttpRequest=function(){var n,o,i=this,a=d.default,s=p.default,c={},l=!1,u={"User-Agent":"node-XMLHttpRequest",Accept:"*/*"},f={},h={},v=["accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","content-transfer-encoding","cookie","cookie2","date","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","via"],g=["TRACE","TRACK","CONNECT"],y=!1,b=!1,E={};this.UNSENT=0,this.OPENED=1,this.HEADERS_RECEIVED=2,this.LOADING=3,this.DONE=4,this.readyState=this.UNSENT,this.onreadystatechange=null,this.responseText="",this.responseXML="",this.status=null,this.statusText=null,this.withCredentials=!1;this.open=function(e,t,r,n,o){if(this.abort(),b=!1,!function(e){return e&&-1===g.indexOf(e)}(e))throw new Error("SecurityError: Request method not allowed");c={method:e,url:t.toString(),async:"boolean"!=typeof r||r,user:n||null,password:o||null},w(this.OPENED)},this.setDisableHeaderCheck=function(e){l=e},this.setRequestHeader=function(e,t){if(this.readyState!==this.OPENED)throw new Error("INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN");if(function(e){return l||e&&-1===v.indexOf(e.toLowerCase())}(e)){if(y)throw new Error("INVALID_STATE_ERR: send flag is true");e=h[e.toLowerCase()]||e,h[e.toLowerCase()]=e,f[e]=f[e]?f[e]+", "+t:t}else console.warn('Refused to set unsafe header "'+e+'"')},this.getResponseHeader=function(e){return"string"==typeof e&&this.readyState>this.OPENED&&o&&o.headers&&o.headers[e.toLowerCase()]&&!b?o.headers[e.toLowerCase()]:null},this.getAllResponseHeaders=function(){if(this.readyState<this.HEADERS_RECEIVED||b)return"";var e="";for(var t in o.headers)"set-cookie"!==t&&"set-cookie2"!==t&&(e+=t+": "+o.headers[t]+"\r\n");return e.substr(0,e.length-2)},this.getRequestHeader=function(e){return"string"==typeof e&&h[e.toLowerCase()]?f[h[e.toLowerCase()]]:""},this.send=function(l){if(this.readyState!==this.OPENED)throw new Error("INVALID_STATE_ERR: connection must be opened before send() is called");if(y)throw new Error("INVALID_STATE_ERR: send has already been called");var d,p=!1,v=!1,g=e.parse(c.url);switch(g.protocol){case"https:":p=!0;case"http:":d=g.hostname;break;case"file:":v=!0;break;case void 0:case null:case"":d="localhost";break;default:throw new Error("Protocol not supported.")}if(v){if("GET"!==c.method)throw new Error("XMLHttpRequest: Only GET method is supported");if(c.async)r.readFile(g.pathname,"utf8",function(e,t){e?i.handleError(e):(i.status=200,i.responseText=t,w(i.DONE))});else try{this.responseText=r.readFileSync(g.pathname,"utf8"),this.status=200,w(i.DONE)}catch(e){this.handleError(e)}}else{var E=g.port||(p?443:80),m=g.pathname+(g.search?g.search:"");for(var x in u)h[x.toLowerCase()]||(f[x]=u[x]);if(f.Host=d,p&&443===E||80===E||(f.Host+=":"+g.port),c.user){void 0===c.password&&(c.password="");var S=new Buffer(c.user+":"+c.password);f.Authorization="Basic "+S.toString("base64")}"GET"===c.method||"HEAD"===c.method?l=null:l?(f["Content-Length"]=Buffer.isBuffer(l)?l.length:Buffer.byteLength(l),f["Content-Type"]||(f["Content-Type"]="text/plain;charset=UTF-8")):"POST"===c.method&&(f["Content-Length"]=0);var O={host:d,port:E,path:m,method:c.method,headers:f,agent:!1,withCredentials:i.withCredentials};if(b=!1,c.async){var k=p?s.request:a.request;y=!0,i.dispatchEvent("readystatechange");var N=function(e){i.handleError(e)};n=k(O,function t(r){if(301!==(o=r).statusCode&&302!==o.statusCode&&303!==o.statusCode&&307!==o.statusCode)o.setEncoding("utf8"),w(i.HEADERS_RECEIVED),i.status=o.statusCode,o.on("data",function(e){e&&(i.responseText+=e),y&&w(i.LOADING)}),o.on("end",function(){y&&(w(i.DONE),y=!1)}),o.on("error",function(e){i.handleError(e)});else{c.url=o.headers.location;var a=e.parse(c.url);d=a.hostname;var s={hostname:a.hostname,port:a.port,path:a.path,method:303===o.statusCode?"GET":c.method,headers:f,withCredentials:i.withCredentials};(n=k(s,t).on("error",N)).end()}}).on("error",N),l&&n.write(l),n.end(),i.dispatchEvent("loadstart")}else{var T=".node-xmlhttprequest-content-"+process.pid,j=".node-xmlhttprequest-sync-"+process.pid;r.writeFileSync(j,"","utf8");for(var C="var http = require('http'), https = require('https'), fs = require('fs');var doRequest = http"+(p?"s":"")+".request;var options = "+JSON.stringify(O)+";var responseText = '';var req = doRequest(options, function(response) {response.setEncoding('utf8');response.on('data', function(chunk) { responseText += chunk;});response.on('end', function() {fs.writeFileSync('"+T+"', JSON.stringify({err: null, data: {statusCode: response.statusCode, headers: response.headers, text: responseText}}), 'utf8');fs.unlinkSync('"+j+"');});response.on('error', function(error) {fs.writeFileSync('"+T+"', JSON.stringify({err: error}), 'utf8');fs.unlinkSync('"+j+"');});}).on('error', function(error) {fs.writeFileSync('"+T+"', JSON.stringify({err: error}), 'utf8');fs.unlinkSync('"+j+"');});"+(l?"req.write('"+JSON.stringify(l).slice(1,-1).replace(/'/g,"\\'")+"');":"")+"req.end();",R=t(process.argv[0],["-e",C]);r.existsSync(j););var D=JSON.parse(r.readFileSync(T,"utf8"));R.stdin.end(),r.unlinkSync(T),D.err?i.handleError(D.err):(o=D.data,i.status=D.data.statusCode,i.responseText=D.data.text,w(i.DONE))}}},this.handleError=function(e){this.status=0,this.statusText=e,this.responseText=e.stack,b=!0,w(this.DONE),this.dispatchEvent("error")},this.abort=function(){n&&(n.abort(),n=null),f=u,this.status=0,this.responseText="",this.responseXML="",b=!0,this.readyState===this.UNSENT||this.readyState===this.OPENED&&!y||this.readyState===this.DONE||(y=!1,w(this.DONE)),this.readyState=this.UNSENT,this.dispatchEvent("abort")},this.addEventListener=function(e,t){e in E||(E[e]=[]),E[e].push(t)},this.removeEventListener=function(e,t){e in E&&(E[e]=E[e].filter(function(e){return e!==t}))},this.dispatchEvent=function(e){if("function"==typeof i["on"+e]&&i["on"+e](),e in E)for(var t=0,r=E[e].length;t<r;t++)E[e][t].call(i)};var w=function(e){e!=i.LOADING&&i.readyState===e||(i.readyState=e,(c.async||i.readyState<i.OPENED||i.readyState===i.DONE)&&i.dispatchEvent("readystatechange"),i.readyState!==i.DONE||b||(i.dispatchEvent("load"),i.dispatchEvent("loadend")))}},G}(),X=B(z),V=new Map,W=O?window.XMLHttpRequest:X.XMLHttpRequest;function Z(e){if(V.has(e))return V.get(e);var t;try{var r=new W;r.open("GET",e,!1),r.setRequestHeader("Content-Type","text/html"),r.send(),200===r.status&&r.responseText&&(t=r.responseText,V.set(e,r.responseText))}catch(e){console.error("【XHR Error】:".concat(e instanceof Error?e.message:"get remote URL resource exception!"))}return t}var $=new Map;exports.generateCard=function(e,t){return new Promise(function(r){var n=Z(e);if(n){var o=M(n,e);if(o){var i={linkTitle:t.linkTitle,target:t.target||"_blank",classPrefix:t.classPrefix},a=R(o,E(E({},i),{},{href:e})),s={url:e,data:o,options:i,dom:a};$.set(e,s),r(s)}}})},exports.linkToCardPlugin=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};function r(e){var r,n=function(e){if(T.has(e))return T.get(e);var t=null,r=Z(e);return r&&(t=M(r,e))&&T.set(e,t),t}(e.url);if(n){!function(e,t){e.forEach(function(e,r){r!==t&&(e.hidden=!0)})}(e.tokens,e.i);var o={href:e.url,linkTitle:(r=e.tokens,r.map(function(e){var t=e.hidden,r=e.content;return t?r:""}).filter(Boolean).join("")),target:t.target||"_blank",classPrefix:t.classPrefix};return S(t.render)?t.render(n,o):R(n,o)}}e.renderer.renderInline=function(t,r,n){for(var o="",i=0;i<t.length;i++){var a=t[i],s=e.renderer.rules[a.type];a.hidden?o+="":S(s)?o+=s(t,i,r,n,e.renderer):o+=e.renderer.renderToken(t,i,r)}return o},e.renderer.rules.link_open=function(e,t,n,o,i){var a,s=e[t],c="a"===s.tag&&"link_open"===s.type,l=function(e){var t=new RegExp("^(".concat("@",":)([a-zA-Z0-9]+.*)")),r=null==e?void 0:e.match(t);return{isCardLink:!!r,url:null==r?void 0:r[2]}}(null===(a=s.attrs)||void 0===a||null===(a=a.filter(function(e){return e.includes("href")})[0])||void 0===a?void 0:a[1]),u=l.url,f=l.isCardLink;if(c&&f&&u){var d=r({url:u,tokens:e,i:t});if(d)return d}return i.renderToken(e,t,n)}};
|
package/dist/.esm.min.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* vitepress-linkcard
|
|
3
|
-
* (c) 2022 -
|
|
2
|
+
* vitepress-linkcard v2.0.0
|
|
3
|
+
* (c) 2022 - 2026 luckrya
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
import e from"url";import t from"child_process";import r from"fs";import n from"http";import o from"https";import i from"node:fs";function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=Array(t);r<t;r++)n[r]=e[r];return n}function s(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,
|
|
6
|
+
import e from"url";import t from"child_process";import r from"fs";import n from"http";import o from"https";import i from"node:fs";function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=Array(t);r<t;r++)n[r]=e[r];return n}function s(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,p(n.key),n)}}function c(e,t,r){return(t=p(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,n)}return r}function u(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?l(Object(r),!0).forEach(function(t){c(e,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):l(Object(r)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})}return e}function f(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,o,i,a,s=[],c=!0,l=!1;try{if(i=(r=r.call(e)).next,0===t){if(Object(r)!==r)return;c=!1}else for(;!(c=(n=i.call(r)).done)&&(s.push(n.value),s.length!==t);c=!0);}catch(e){l=!0,o=e}finally{try{if(!c&&null!=r.return&&(a=r.return(),Object(a)!==a))return}finally{if(l)throw o}}return s}}(e,t)||function(e,t){if(e){if("string"==typeof e)return a(e,t);var r={}.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?a(e,t):void 0}}
|
|
7
7
|
/*!
|
|
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
|
|
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(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/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={};
|
|
12
12
|
/**
|
|
13
13
|
* Wrapper for built-in http.js to emulate the browser XMLHttpRequest object.
|
|
14
14
|
*
|
|
@@ -20,4 +20,4 @@ import e from"url";import t from"child_process";import r from"fs";import n from"
|
|
|
20
20
|
* @author Dan DeFelippi <dan@driverdan.com>
|
|
21
21
|
* @contributor David Ellis <d.f.ellis@ieee.org>
|
|
22
22
|
* @license MIT
|
|
23
|
-
*/var _=function(){if(H)return F;H=1;var i=e,a=t.spawn,s=r;return F.XMLHttpRequest=function(){var e,t,r=this,c=n,l=o,u={},f=!1,
|
|
23
|
+
*/var _=function(){if(H)return F;H=1;var i=e,a=t.spawn,s=r;return F.XMLHttpRequest=function(){var e,t,r=this,c=n,l=o,u={},f=!1,p={"User-Agent":"node-XMLHttpRequest",Accept:"*/*"},d={},h={},v=["accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","content-transfer-encoding","cookie","cookie2","date","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","via"],g=["TRACE","TRACK","CONNECT"],y=!1,b=!1,m={};this.UNSENT=0,this.OPENED=1,this.HEADERS_RECEIVED=2,this.LOADING=3,this.DONE=4,this.readyState=this.UNSENT,this.onreadystatechange=null,this.responseText="",this.responseXML="",this.status=null,this.statusText=null,this.withCredentials=!1;this.open=function(e,t,r,n,o){if(this.abort(),b=!1,!function(e){return e&&-1===g.indexOf(e)}(e))throw new Error("SecurityError: Request method not allowed");u={method:e,url:t.toString(),async:"boolean"!=typeof r||r,user:n||null,password:o||null},E(this.OPENED)},this.setDisableHeaderCheck=function(e){f=e},this.setRequestHeader=function(e,t){if(this.readyState!==this.OPENED)throw new Error("INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN");if(function(e){return f||e&&-1===v.indexOf(e.toLowerCase())}(e)){if(y)throw new Error("INVALID_STATE_ERR: send flag is true");e=h[e.toLowerCase()]||e,h[e.toLowerCase()]=e,d[e]=d[e]?d[e]+", "+t:t}else console.warn('Refused to set unsafe header "'+e+'"')},this.getResponseHeader=function(e){return"string"==typeof e&&this.readyState>this.OPENED&&t&&t.headers&&t.headers[e.toLowerCase()]&&!b?t.headers[e.toLowerCase()]:null},this.getAllResponseHeaders=function(){if(this.readyState<this.HEADERS_RECEIVED||b)return"";var e="";for(var r in t.headers)"set-cookie"!==r&&"set-cookie2"!==r&&(e+=r+": "+t.headers[r]+"\r\n");return e.substr(0,e.length-2)},this.getRequestHeader=function(e){return"string"==typeof e&&h[e.toLowerCase()]?d[h[e.toLowerCase()]]:""},this.send=function(n){if(this.readyState!==this.OPENED)throw new Error("INVALID_STATE_ERR: connection must be opened before send() is called");if(y)throw new Error("INVALID_STATE_ERR: send has already been called");var o,f=!1,v=!1,g=i.parse(u.url);switch(g.protocol){case"https:":f=!0;case"http:":o=g.hostname;break;case"file:":v=!0;break;case void 0:case null:case"":o="localhost";break;default:throw new Error("Protocol not supported.")}if(v){if("GET"!==u.method)throw new Error("XMLHttpRequest: Only GET method is supported");if(u.async)s.readFile(g.pathname,"utf8",function(e,t){e?r.handleError(e):(r.status=200,r.responseText=t,E(r.DONE))});else try{this.responseText=s.readFileSync(g.pathname,"utf8"),this.status=200,E(r.DONE)}catch(e){this.handleError(e)}}else{var m=g.port||(f?443:80),w=g.pathname+(g.search?g.search:"");for(var x in p)h[x.toLowerCase()]||(d[x]=p[x]);if(d.Host=o,f&&443===m||80===m||(d.Host+=":"+g.port),u.user){void 0===u.password&&(u.password="");var S=new Buffer(u.user+":"+u.password);d.Authorization="Basic "+S.toString("base64")}"GET"===u.method||"HEAD"===u.method?n=null:n?(d["Content-Length"]=Buffer.isBuffer(n)?n.length:Buffer.byteLength(n),d["Content-Type"]||(d["Content-Type"]="text/plain;charset=UTF-8")):"POST"===u.method&&(d["Content-Length"]=0);var O={host:o,port:m,path:w,method:u.method,headers:d,agent:!1,withCredentials:r.withCredentials};if(b=!1,u.async){var k=f?l.request:c.request;y=!0,r.dispatchEvent("readystatechange");var N=function(e){r.handleError(e)};e=k(O,function n(a){if(301!==(t=a).statusCode&&302!==t.statusCode&&303!==t.statusCode&&307!==t.statusCode)t.setEncoding("utf8"),E(r.HEADERS_RECEIVED),r.status=t.statusCode,t.on("data",function(e){e&&(r.responseText+=e),y&&E(r.LOADING)}),t.on("end",function(){y&&(E(r.DONE),y=!1)}),t.on("error",function(e){r.handleError(e)});else{u.url=t.headers.location;var s=i.parse(u.url);o=s.hostname;var c={hostname:s.hostname,port:s.port,path:s.path,method:303===t.statusCode?"GET":u.method,headers:d,withCredentials:r.withCredentials};(e=k(c,n).on("error",N)).end()}}).on("error",N),n&&e.write(n),e.end(),r.dispatchEvent("loadstart")}else{var T=".node-xmlhttprequest-content-"+process.pid,j=".node-xmlhttprequest-sync-"+process.pid;s.writeFileSync(j,"","utf8");for(var C="var http = require('http'), https = require('https'), fs = require('fs');var doRequest = http"+(f?"s":"")+".request;var options = "+JSON.stringify(O)+";var responseText = '';var req = doRequest(options, function(response) {response.setEncoding('utf8');response.on('data', function(chunk) { responseText += chunk;});response.on('end', function() {fs.writeFileSync('"+T+"', JSON.stringify({err: null, data: {statusCode: response.statusCode, headers: response.headers, text: responseText}}), 'utf8');fs.unlinkSync('"+j+"');});response.on('error', function(error) {fs.writeFileSync('"+T+"', JSON.stringify({err: error}), 'utf8');fs.unlinkSync('"+j+"');});}).on('error', function(error) {fs.writeFileSync('"+T+"', JSON.stringify({err: error}), 'utf8');fs.unlinkSync('"+j+"');});"+(n?"req.write('"+JSON.stringify(n).slice(1,-1).replace(/'/g,"\\'")+"');":"")+"req.end();",R=a(process.argv[0],["-e",C]);s.existsSync(j););var D=JSON.parse(s.readFileSync(T,"utf8"));R.stdin.end(),s.unlinkSync(T),D.err?r.handleError(D.err):(t=D.data,r.status=D.data.statusCode,r.responseText=D.data.text,E(r.DONE))}}},this.handleError=function(e){this.status=0,this.statusText=e,this.responseText=e.stack,b=!0,E(this.DONE),this.dispatchEvent("error")},this.abort=function(){e&&(e.abort(),e=null),d=p,this.status=0,this.responseText="",this.responseXML="",b=!0,this.readyState===this.UNSENT||this.readyState===this.OPENED&&!y||this.readyState===this.DONE||(y=!1,E(this.DONE)),this.readyState=this.UNSENT,this.dispatchEvent("abort")},this.addEventListener=function(e,t){e in m||(m[e]=[]),m[e].push(t)},this.removeEventListener=function(e,t){e in m&&(m[e]=m[e].filter(function(e){return e!==t}))},this.dispatchEvent=function(e){if("function"==typeof r["on"+e]&&r["on"+e](),e in m)for(var t=0,n=m[e].length;t<n;t++)m[e][t].call(r)};var E=function(e){e!=r.LOADING&&r.readyState===e||(r.readyState=e,(u.async||r.readyState<r.OPENED||r.readyState===r.DONE)&&r.dispatchEvent("readystatechange"),r.readyState!==r.DONE||b||(r.dispatchEvent("load"),r.dispatchEvent("loadend")))}},F}(),I=q(_),U=new Map,B=y?window.XMLHttpRequest:I.XMLHttpRequest;function J(e){if(U.has(e))return U.get(e);var t;try{var r=new B;r.open("GET",e,!1),r.setRequestHeader("Content-Type","text/html"),r.send(),200===r.status&&r.responseText&&(t=r.responseText,U.set(e,r.responseText))}catch(e){console.error("【XHR Error】:".concat(e instanceof Error?e.message:"get remote URL resource exception!"))}return t}var M=new Map;function G(e,t){return new Promise(function(r){var n=J(e);if(n){var o=P(n,e);if(o){var i={linkTitle:t.linkTitle,target:t.target||"_blank",classPrefix:t.classPrefix},a=S(o,u(u({},i),{},{href:e})),s={url:e,data:o,options:i,dom:a};M.set(e,s),r(s)}}})}var z=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};function r(e){var r,n=function(e){if(E.has(e))return E.get(e);var t=null,r=J(e);return r&&(t=P(r,e))&&E.set(e,t),t}(e.url);if(n){!function(e,t){e.forEach(function(e,r){r!==t&&(e.hidden=!0)})}(e.tokens,e.i);var o={href:e.url,linkTitle:(r=e.tokens,r.map(function(e){var t=e.hidden,r=e.content;return t?r:""}).filter(Boolean).join("")),target:t.target||"_blank",classPrefix:t.classPrefix};return g(t.render)?t.render(n,o):S(n,o)}}e.renderer.renderInline=function(t,r,n){for(var o="",i=0;i<t.length;i++){var a=t[i],s=e.renderer.rules[a.type];a.hidden?o+="":g(s)?o+=s(t,i,r,n,e.renderer):o+=e.renderer.renderToken(t,i,r)}return o},e.renderer.rules.link_open=function(e,t,n,o,i){var a,s=e[t],c="a"===s.tag&&"link_open"===s.type,l=function(e){var t=new RegExp("^(".concat("@",":)([a-zA-Z0-9]+.*)")),r=null==e?void 0:e.match(t);return{isCardLink:!!r,url:null==r?void 0:r[2]}}(null===(a=s.attrs)||void 0===a||null===(a=a.filter(function(e){return e.includes("href")})[0])||void 0===a?void 0:a[1]),u=l.url,f=l.isCardLink;if(c&&f&&u){var p=r({url:u,tokens:e,i:t});if(p)return p}return i.renderToken(e,t,n)}};export{G as generateCard,z as linkToCardPlugin};
|
package/dist/api.js
CHANGED
|
@@ -1,9 +1,37 @@
|
|
|
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
|
+
*/
|
|
2
7
|
const cache = new Map();
|
|
3
8
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
9
|
+
* Generates a link card by fetching and parsing metadata from a URL.
|
|
10
|
+
*
|
|
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
|
+
* @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)
|
|
22
|
+
* @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
|
|
7
35
|
*/
|
|
8
36
|
export function generateCard(url, options) {
|
|
9
37
|
return new Promise((resolve) => {
|
package/dist/assemble/html.js
CHANGED
|
@@ -1,28 +1,81 @@
|
|
|
1
1
|
import { STYLE } from './style';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Generates the HTML DOM fragment for a link card display.
|
|
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
|
|
6
54
|
*/
|
|
7
55
|
export const generateCardDomFragment = (data, options) => {
|
|
8
56
|
const aa = {
|
|
9
57
|
rel: `rel="noopener noreferrer"`,
|
|
10
58
|
target: `target="${options.target}"`,
|
|
11
59
|
href: `href="${options.href}"`,
|
|
12
|
-
title: `title="${options.linkTitle}"
|
|
13
|
-
borderColor: `borderColor="${options.borderColor}"`,
|
|
14
|
-
bgColor: `bgColor="${options.bgColor}"`
|
|
60
|
+
title: `title="${options.linkTitle}"`
|
|
15
61
|
};
|
|
16
62
|
const inject = (s) => {
|
|
17
63
|
return s;
|
|
18
64
|
};
|
|
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
|
+
*/
|
|
19
72
|
const escapeHTML = (str) => str
|
|
20
73
|
.replace(/&/g, '&')
|
|
21
74
|
.replace(/</g, '<')
|
|
22
75
|
.replace(/>/g, '>')
|
|
23
76
|
.replace(/"/g, '"')
|
|
24
77
|
.replace(/'/g, "'");
|
|
25
|
-
const style = STYLE(
|
|
78
|
+
const style = STYLE();
|
|
26
79
|
const url = options.href || '';
|
|
27
80
|
const domain = new URL(url).origin.replace(/^https?:\/\//, '').replace(/^www\./, '') ||
|
|
28
81
|
'Unknown domain';
|
|
@@ -41,7 +94,7 @@ export const generateCardDomFragment = (data, options) => {
|
|
|
41
94
|
}
|
|
42
95
|
return `<span style="display:block;">
|
|
43
96
|
<a ${aa.rel} ${aa.target} ${aa.href} ${aa.title} ${style.a}>
|
|
44
|
-
<span ${inject(style.container)}>
|
|
97
|
+
<span class="vitepress-linkcard-container" ${inject(style.container)}>
|
|
45
98
|
<span ${inject(style.texts)}>
|
|
46
99
|
<span ${inject(style.title)}>
|
|
47
100
|
${escapeHTML(title)}
|
|
@@ -1,5 +1,27 @@
|
|
|
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
|
+
*/
|
|
1
10
|
import { isPureObject } from '@luckrya/utility';
|
|
2
11
|
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
|
+
*/
|
|
3
25
|
const CONFIG_FILE = () => {
|
|
4
26
|
let filePath;
|
|
5
27
|
const defaultPath = `${process.cwd()}/.linkcard_cache.json`;
|
|
@@ -23,6 +45,14 @@ const CONFIG_FILE = () => {
|
|
|
23
45
|
}
|
|
24
46
|
return filePath;
|
|
25
47
|
};
|
|
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
|
+
*/
|
|
26
56
|
const format = () => {
|
|
27
57
|
const filePath = CONFIG_FILE();
|
|
28
58
|
const content = fs.readFileSync(filePath, 'utf-8').trim();
|
|
@@ -32,10 +62,54 @@ const format = () => {
|
|
|
32
62
|
const formatted = JSON.stringify(parsed, null, 2) + '\n';
|
|
33
63
|
fs.writeFileSync(filePath, formatted);
|
|
34
64
|
};
|
|
65
|
+
/**
|
|
66
|
+
* 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
|
+
*/
|
|
35
102
|
export default class LocalFileCache {
|
|
36
103
|
constructor() { }
|
|
37
104
|
/**
|
|
38
|
-
*
|
|
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
|
|
39
113
|
*/
|
|
40
114
|
setFile(data) {
|
|
41
115
|
let content = data;
|
|
@@ -47,7 +121,11 @@ export default class LocalFileCache {
|
|
|
47
121
|
format();
|
|
48
122
|
}
|
|
49
123
|
/**
|
|
50
|
-
*
|
|
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
|
|
51
129
|
*/
|
|
52
130
|
readFile() {
|
|
53
131
|
const content = fs.readFileSync(CONFIG_FILE(), 'utf-8');
|
|
@@ -57,23 +135,56 @@ export default class LocalFileCache {
|
|
|
57
135
|
return undefined;
|
|
58
136
|
}
|
|
59
137
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
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
|
+
* ```
|
|
62
149
|
*/
|
|
63
150
|
has(url) {
|
|
64
151
|
return !!this.get(url);
|
|
65
152
|
}
|
|
66
153
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
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
|
+
* ```
|
|
69
166
|
*/
|
|
70
167
|
get(url) {
|
|
71
168
|
const cache = this.readFile();
|
|
72
169
|
return cache?.[url];
|
|
73
170
|
}
|
|
74
171
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
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
|
+
* ```
|
|
77
188
|
*/
|
|
78
189
|
set(url, data) {
|
|
79
190
|
this.setFile({ [url]: data });
|