vitepress-linkcard 0.9.9 → 1.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 +2 -3
- package/dist/.cjs.min.js +23 -0
- package/dist/.esm.min.js +23 -0
- package/dist/api.js +34 -0
- package/dist/assemble/html.js +60 -0
- package/dist/assemble/index.js +4 -0
- package/dist/assemble/local-file-cache.js +49 -0
- package/dist/assemble/metadata.js +19 -0
- package/dist/assemble/parser.js +107 -0
- package/dist/assemble/style.js +115 -0
- package/dist/assemble/url.js +14 -0
- package/dist/assemble/xhr.js +59 -0
- package/dist/index.js +3 -0
- package/dist/link-to-card-plugin.js +107 -0
- package/dist/types.js +1 -0
- package/package.json +3 -3
- package/types/api.d.ts +14 -0
- package/types/assemble/html.d.ts +7 -0
- package/types/assemble/index.d.ts +4 -0
- package/types/assemble/local-file-cache.d.ts +26 -0
- package/types/assemble/metadata.d.ts +6 -0
- package/types/assemble/parser.d.ts +10 -0
- package/types/assemble/style.d.ts +27 -0
- package/types/assemble/url.d.ts +10 -0
- package/types/assemble/xhr.d.ts +10 -0
- package/types/index.d.ts +3 -0
- package/types/link-to-card-plugin.d.ts +6 -0
- package/types/types.d.ts +25 -0
package/README.md
CHANGED
|
@@ -5,9 +5,8 @@ vitepress-linkcard
|
|
|
5
5
|
<div align="center">
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/vitepress-linkcard)
|
|
8
|
-

|
|
10
|
-
](/LICENSE)
|
|
8
|
+
[](https://www.npmjs.com/package/vitepress-linkcard)
|
|
9
|
+
[](/LICENSE)
|
|
11
10
|
|
|
12
11
|
[](https://vuejs.github.io/vitepress/v1/)
|
|
13
12
|
[](https://yarnpkg.com/)
|
package/dist/.cjs.min.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* vitepress-linkcard v1.0.0
|
|
3
|
+
* (c) 2022 - 2025 luckrya
|
|
4
|
+
* Released under the MIT License.
|
|
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),d=a(r),f=a(n),p=a(o),h=a(i);function g(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 v(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 g(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)?g(e,t):void 0}}
|
|
7
|
+
/*!
|
|
8
|
+
* @luckrya/utility v0.1.0
|
|
9
|
+
* (c) 2022 - 2022 Y.R
|
|
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},O=function(e){return Object.prototype.toString.call(e)===s.Function},S="undefined"!=typeof window,C=function(){return"".concat(process.cwd(),"/.linkcardrc")},k=function(){return function(e,t,r){return t&&v(e.prototype,t),r&&v(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(C(),JSON.stringify(t))}},{key:"readFile",value:function(){var e=h.default.readFileSync(C(),"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))}}])}(),N=new k;function T(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 j=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,i,a={rel:'rel="noopener noreferrer"',target:'target="'.concat(t.target,'"'),href:'href="'.concat(t.href,'"'),title:'title="'.concat(t.linkTitle,'"'),borderColor:'borderColor="'.concat(t.borderColor,'"'),bgColor:'bgColor="'.concat(t.bgColor,'"')},s=function(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'")},c=(r=t.borderColor||"#7d7d7dff",n=t.bgColor||"#7d7d7d00",{a:T({color:"unset !important",display:"block",width:"100%",textDecoration:"none"}),container:T({display:"flex",alignItems:"center",flexWrap:"wrap",gap:"10px",borderRadius:"12px",border:"1px solid ".concat(r),backgroundColor:n,boxSizing:"border-box",width:"100%",height:"130px"}),img:T({borderRadius:"0px 12px 12px 0px",maxWidth:"40%",height:"128px",flexShrink:0,objectFit:"contain",overflow:"hidden"}),texts:T({flex:"1 1 0%",minWidth:"0"}),title:T(E(E({},j(2)),{},{opacity:1,fontSize:"16px",lineHeight:"22px",margin:"0 16px 8px 16px",fontWeight:"bold"})),domain:T(E(E({},j(1)),{},{opacity:1,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 8px 16px",textDecoration:"underline"})),description:T(E(E({},j(2)),{},{opacity:.8,fontSize:"12px",lineHeight:"16px",margin:"8px 16px 0px 16px"}))}),l=t.href||"",u=new URL(l).origin.replace(/^https?:\/\//,"").replace(/^www\./,"")||"Unknown domain",d=e.title,f=e.description;"github.com"==u?(d=(null===(o=e.title)||void 0===o?void 0:o.split(":")[0].replace("GitHub - ",""))||"No title",f=(null===(i=f)||void 0===i?void 0:i.replace(" - ".concat(d),"").replace("Contribute to ".concat(d," development by creating an account on GitHub."),""))||""):(d=e.title||"No title",f=e.description||"");return'<span style="display:block;">\n <a '.concat(a.rel," ").concat(a.target," ").concat(a.href," ").concat(a.title," ").concat(c.a,">\n <span ").concat(c.container,">\n <span ").concat(c.texts,">\n <span ").concat(c.title,">\n ").concat(s(d),"\n </span>\n <span ").concat(c.domain,">\n ").concat(s(u),"\n </span>\n <span ").concat(c.description,">\n ").concat(s(f),'\n </span>\n </span>\n <img src="').concat(null==e?void 0:e.logo,'" ').concat(c.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,_=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 F(e){var t,r=e.match(_("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(_("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(_("image"));if(null!=r&&r.length){var n=r[0].match(q);n&&x(n[1])&&(t=n[1])}else{var o=e.match(_("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:F(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 G,z={};
|
|
12
|
+
/**
|
|
13
|
+
* Wrapper for built-in http.js to emulate the browser XMLHttpRequest object.
|
|
14
|
+
*
|
|
15
|
+
* This can be used with JS designed for browsers to improve reuse of code and
|
|
16
|
+
* allow the use of existing libraries.
|
|
17
|
+
*
|
|
18
|
+
* Usage: include("XMLHttpRequest.js") and use XMLHttpRequest per W3C specs.
|
|
19
|
+
*
|
|
20
|
+
* @author Dan DeFelippi <dan@driverdan.com>
|
|
21
|
+
* @contributor David Ellis <d.f.ellis@ieee.org>
|
|
22
|
+
* @license MIT
|
|
23
|
+
*/var J=function(){if(G)return z;G=1;var e=l.default,t=u.default.spawn,r=d.default;return z.XMLHttpRequest=function(){var n,o,i=this,a=f.default,s=p.default,c={},l=!1,u={"User-Agent":"node-XMLHttpRequest",Accept:"*/*"},d={},h={},g=["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"],v=["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===v.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===g.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&&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()]?d[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 f,p=!1,g=!1,v=e.parse(c.url);switch(v.protocol){case"https:":p=!0;case"http:":f=v.hostname;break;case"file:":g=!0;break;case void 0:case null:case"":f="localhost";break;default:throw new Error("Protocol not supported.")}if(g){if("GET"!==c.method)throw new Error("XMLHttpRequest: Only GET method is supported");if(c.async)r.readFile(v.pathname,"utf8",function(e,t){e?i.handleError(e):(i.status=200,i.responseText=t,w(i.DONE))});else try{this.responseText=r.readFileSync(v.pathname,"utf8"),this.status=200,w(i.DONE)}catch(e){this.handleError(e)}}else{var E=v.port||(p?443:80),m=v.pathname+(v.search?v.search:"");for(var x in u)h[x.toLowerCase()]||(d[x]=u[x]);if(d.Host=f,p&&443===E||80===E||(d.Host+=":"+v.port),c.user){void 0===c.password&&(c.password="");var O=new Buffer(c.user+":"+c.password);d.Authorization="Basic "+O.toString("base64")}"GET"===c.method||"HEAD"===c.method?l=null:l?(d["Content-Length"]=Buffer.isBuffer(l)?l.length:Buffer.byteLength(l),d["Content-Type"]||(d["Content-Type"]="text/plain;charset=UTF-8")):"POST"===c.method&&(d["Content-Length"]=0);var S={host:f,port:E,path:m,method:c.method,headers:d,agent:!1,withCredentials:i.withCredentials};if(b=!1,c.async){var C=p?s.request:a.request;y=!0,i.dispatchEvent("readystatechange");var k=function(e){i.handleError(e)};n=C(S,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);f=a.hostname;var s={hostname:a.hostname,port:a.port,path:a.path,method:303===o.statusCode?"GET":c.method,headers:d,withCredentials:i.withCredentials};(n=C(s,t).on("error",k)).end()}}).on("error",k),l&&n.write(l),n.end(),i.dispatchEvent("loadstart")}else{var N=".node-xmlhttprequest-content-"+process.pid,T=".node-xmlhttprequest-sync-"+process.pid;r.writeFileSync(T,"","utf8");for(var j="var http = require('http'), https = require('https'), fs = require('fs');var doRequest = http"+(p?"s":"")+".request;var options = "+JSON.stringify(S)+";var responseText = '';var req = doRequest(options, function(response) {response.setEncoding('utf8');response.on('data', function(chunk) { responseText += chunk;});response.on('end', function() {fs.writeFileSync('"+N+"', JSON.stringify({err: null, data: {statusCode: response.statusCode, headers: response.headers, text: responseText}}), 'utf8');fs.unlinkSync('"+T+"');});response.on('error', function(error) {fs.writeFileSync('"+N+"', JSON.stringify({err: error}), 'utf8');fs.unlinkSync('"+T+"');});}).on('error', function(error) {fs.writeFileSync('"+N+"', JSON.stringify({err: error}), 'utf8');fs.unlinkSync('"+T+"');});"+(l?"req.write('"+JSON.stringify(l).slice(1,-1).replace(/'/g,"\\'")+"');":"")+"req.end();",R=t(process.argv[0],["-e",j]);r.existsSync(T););var D=JSON.parse(r.readFileSync(N,"utf8"));R.stdin.end(),r.unlinkSync(N),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),d=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")))}},z}(),X=B(J),V=new Map,W=S?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(N.has(e))return N.get(e);var t=null,r=Z(e);return r&&(t=M(r,e))&&N.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,borderColor:t.borderColor,bgColor:t.bgColor};return O(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+="":O(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,d=l.isCardLink;if(c&&d&&u){var f=r({url:u,tokens:e,i:t});if(f)return f}return i.renderToken(e,t,n)}};
|
package/dist/.esm.min.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* vitepress-linkcard v1.0.0
|
|
3
|
+
* (c) 2022 - 2025 luckrya
|
|
4
|
+
* Released under the MIT License.
|
|
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,d(n.key),n)}}function c(e,t,r){return(t=d(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
|
+
/*!
|
|
8
|
+
* @luckrya/utility v0.1.0
|
|
9
|
+
* (c) 2022 - 2022 Y.R
|
|
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 d(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 p,h;(h=p||(p={})).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)===p.String},g=function(e){return Object.prototype.toString.call(e)===p.Function},y="undefined"!=typeof window,b=function(){return"".concat(process.cwd(),"/.linkcardrc")},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))}},{key:"readFile",value:function(){var e=i.readFileSync(b(),"utf-8"),t=JSON.parse(e);if(function(e){return Object.prototype.toString.call(e)===p.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,i,a={rel:'rel="noopener noreferrer"',target:'target="'.concat(t.target,'"'),href:'href="'.concat(t.href,'"'),title:'title="'.concat(t.linkTitle,'"'),borderColor:'borderColor="'.concat(t.borderColor,'"'),bgColor:'bgColor="'.concat(t.bgColor,'"')},s=function(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'")},c=(r=t.borderColor||"#7d7d7dff",n=t.bgColor||"#7d7d7d00",{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 ".concat(r),backgroundColor:n,boxSizing:"border-box",width:"100%",height:"130px"}),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"}))}),l=t.href||"",f=new URL(l).origin.replace(/^https?:\/\//,"").replace(/^www\./,"")||"Unknown domain",d=e.title,p=e.description;"github.com"==f?(d=(null===(o=e.title)||void 0===o?void 0:o.split(":")[0].replace("GitHub - ",""))||"No title",p=(null===(i=p)||void 0===i?void 0:i.replace(" - ".concat(d),"").replace("Contribute to ".concat(d," development by creating an account on GitHub."),""))||""):(d=e.title||"No title",p=e.description||"");return'<span style="display:block;">\n <a '.concat(a.rel," ").concat(a.target," ").concat(a.href," ").concat(a.title," ").concat(c.a,">\n <span ").concat(c.container,">\n <span ").concat(c.texts,">\n <span ").concat(c.title,">\n ").concat(s(d),"\n </span>\n <span ").concat(c.domain,">\n ").concat(s(f),"\n </span>\n <span ").concat(c.description,">\n ").concat(s(p),'\n </span>\n </span>\n <img src="').concat(null==e?void 0:e.logo,'" ').concat(c.img,"/>\n </span>\n </a>\n</span>")};function O(e){return new URL(e)}var C="https://resources.whatwg.org/logo-url.svg",k=/(<[A-Za-z]+\s*[^>]*>(.*)<\/[A-Za-z]+>)/,N=/content=["|']([^>]*)["|']/,T=/href=["|']([^>]*)["|']/,j=/(<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(N);n&&v(n[1])&&(t=n[1])}else{var o=e.match(j);if(null!=o&&o.length){var i=o[0].match(k);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(N);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(N);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(T);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,"/")):C)};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
|
+
/**
|
|
13
|
+
* Wrapper for built-in http.js to emulate the browser XMLHttpRequest object.
|
|
14
|
+
*
|
|
15
|
+
* This can be used with JS designed for browsers to improve reuse of code and
|
|
16
|
+
* allow the use of existing libraries.
|
|
17
|
+
*
|
|
18
|
+
* Usage: include("XMLHttpRequest.js") and use XMLHttpRequest per W3C specs.
|
|
19
|
+
*
|
|
20
|
+
* @author Dan DeFelippi <dan@driverdan.com>
|
|
21
|
+
* @contributor David Ellis <d.f.ellis@ieee.org>
|
|
22
|
+
* @license MIT
|
|
23
|
+
*/var I=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,d={"User-Agent":"node-XMLHttpRequest",Accept:"*/*"},p={},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,p[e]=p[e]?p[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()]?p[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 d)h[x.toLowerCase()]||(p[x]=d[x]);if(p.Host=o,f&&443===m||80===m||(p.Host+=":"+g.port),u.user){void 0===u.password&&(u.password="");var S=new Buffer(u.user+":"+u.password);p.Authorization="Basic "+S.toString("base64")}"GET"===u.method||"HEAD"===u.method?n=null:n?(p["Content-Length"]=Buffer.isBuffer(n)?n.length:Buffer.byteLength(n),p["Content-Type"]||(p["Content-Type"]="text/plain;charset=UTF-8")):"POST"===u.method&&(p["Content-Length"]=0);var O={host:o,port:m,path:w,method:u.method,headers:p,agent:!1,withCredentials:r.withCredentials};if(b=!1,u.async){var C=f?l.request:c.request;y=!0,r.dispatchEvent("readystatechange");var k=function(e){r.handleError(e)};e=C(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:p,withCredentials:r.withCredentials};(e=C(c,n).on("error",k)).end()}}).on("error",k),n&&e.write(n),e.end(),r.dispatchEvent("loadstart")}else{var N=".node-xmlhttprequest-content-"+process.pid,T=".node-xmlhttprequest-sync-"+process.pid;s.writeFileSync(T,"","utf8");for(var j="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('"+N+"', JSON.stringify({err: null, data: {statusCode: response.statusCode, headers: response.headers, text: responseText}}), 'utf8');fs.unlinkSync('"+T+"');});response.on('error', function(error) {fs.writeFileSync('"+N+"', JSON.stringify({err: error}), 'utf8');fs.unlinkSync('"+T+"');});}).on('error', function(error) {fs.writeFileSync('"+N+"', JSON.stringify({err: error}), 'utf8');fs.unlinkSync('"+T+"');});"+(n?"req.write('"+JSON.stringify(n).slice(1,-1).replace(/'/g,"\\'")+"');":"")+"req.end();",R=a(process.argv[0],["-e",j]);s.existsSync(T););var D=JSON.parse(s.readFileSync(N,"utf8"));R.stdin.end(),s.unlinkSync(N),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),p=d,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}(),_=q(I),U=new Map,B=y?window.XMLHttpRequest:_.XMLHttpRequest;function M(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 G=new Map;function z(e,t){return new Promise(function(r){var n=M(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};G.set(e,s),r(s)}}})}var J=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=M(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,borderColor:t.borderColor,bgColor:t.bgColor};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 d=r({url:u,tokens:e,i:t});if(d)return d}return i.renderToken(e,t,n)}};export{z as generateCard,J as linkToCardPlugin};
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { xhr, generateCardDomFragment, parserMetadata } from "./assemble";
|
|
2
|
+
const cache = new Map();
|
|
3
|
+
/**
|
|
4
|
+
* @param url
|
|
5
|
+
* @param options
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export function generateCard(url, options) {
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
const htmlString = xhr.sync(url);
|
|
11
|
+
if (htmlString) {
|
|
12
|
+
const urlMetadata = parserMetadata(htmlString, url);
|
|
13
|
+
if (urlMetadata) {
|
|
14
|
+
const _options = {
|
|
15
|
+
linkTitle: options.linkTitle,
|
|
16
|
+
target: options.target || "_blank",
|
|
17
|
+
classPrefix: options.classPrefix,
|
|
18
|
+
};
|
|
19
|
+
const card = generateCardDomFragment(urlMetadata, {
|
|
20
|
+
..._options,
|
|
21
|
+
href: url,
|
|
22
|
+
});
|
|
23
|
+
const response = {
|
|
24
|
+
url,
|
|
25
|
+
data: urlMetadata,
|
|
26
|
+
options: _options,
|
|
27
|
+
dom: card,
|
|
28
|
+
};
|
|
29
|
+
cache.set(url, response);
|
|
30
|
+
resolve(response);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { STYLE } from "./style";
|
|
2
|
+
/**
|
|
3
|
+
* @param data
|
|
4
|
+
* @param options
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
export const generateCardDomFragment = (data, options) => {
|
|
8
|
+
const aa = {
|
|
9
|
+
rel: `rel="noopener noreferrer"`,
|
|
10
|
+
target: `target="${options.target}"`,
|
|
11
|
+
href: `href="${options.href}"`,
|
|
12
|
+
title: `title="${options.linkTitle}"`,
|
|
13
|
+
borderColor: `borderColor="${options.borderColor}"`,
|
|
14
|
+
bgColor: `bgColor="${options.bgColor}"`,
|
|
15
|
+
};
|
|
16
|
+
const inject = (s) => {
|
|
17
|
+
return s;
|
|
18
|
+
};
|
|
19
|
+
const escapeHTML = (str) => str
|
|
20
|
+
.replace(/&/g, "&")
|
|
21
|
+
.replace(/</g, "<")
|
|
22
|
+
.replace(/>/g, ">")
|
|
23
|
+
.replace(/"/g, '"')
|
|
24
|
+
.replace(/'/g, "'");
|
|
25
|
+
const style = STYLE(options.borderColor || "#7d7d7dff", options.bgColor || "#7d7d7d00");
|
|
26
|
+
const url = options.href || "";
|
|
27
|
+
const domain = new URL(url).origin.replace(/^https?:\/\//, "").replace(/^www\./, "") ||
|
|
28
|
+
"Unknown domain";
|
|
29
|
+
let title = data.title;
|
|
30
|
+
let description = data.description;
|
|
31
|
+
// Special handling for gitub.com
|
|
32
|
+
if (domain == "github.com") {
|
|
33
|
+
title = data.title?.split(":")[0].replace("GitHub - ", "") || "No title";
|
|
34
|
+
description =
|
|
35
|
+
description?.replace(` - ${title}`, "").replace(`Contribute to ${title} development by creating an account on GitHub.`, // 定型句
|
|
36
|
+
"") || "";
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
title = data.title || "No title";
|
|
40
|
+
description = data.description || "";
|
|
41
|
+
}
|
|
42
|
+
return `<span style="display:block;">
|
|
43
|
+
<a ${aa.rel} ${aa.target} ${aa.href} ${aa.title} ${style.a}>
|
|
44
|
+
<span ${inject(style.container)}>
|
|
45
|
+
<span ${inject(style.texts)}>
|
|
46
|
+
<span ${inject(style.title)}>
|
|
47
|
+
${escapeHTML(title)}
|
|
48
|
+
</span>
|
|
49
|
+
<span ${inject(style.domain)}>
|
|
50
|
+
${escapeHTML(domain)}
|
|
51
|
+
</span>
|
|
52
|
+
<span ${inject(style.description)}>
|
|
53
|
+
${escapeHTML(description)}
|
|
54
|
+
</span>
|
|
55
|
+
</span>
|
|
56
|
+
<img src="${data?.logo}" ${inject(style.img)}/>
|
|
57
|
+
</span>
|
|
58
|
+
</a>
|
|
59
|
+
</span>`;
|
|
60
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { isPureObject } from "@luckrya/utility";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
const CONFIG_FILE = () => `${process.cwd()}/.linkcardrc`;
|
|
4
|
+
export default class LocalFileCache {
|
|
5
|
+
constructor() { }
|
|
6
|
+
/**
|
|
7
|
+
* @param data
|
|
8
|
+
*/
|
|
9
|
+
setFile(data) {
|
|
10
|
+
let content = data;
|
|
11
|
+
const _content = this.readFile();
|
|
12
|
+
if (_content) {
|
|
13
|
+
content = Object.assign(_content, content);
|
|
14
|
+
}
|
|
15
|
+
fs.writeFileSync(CONFIG_FILE(), JSON.stringify(content));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
readFile() {
|
|
21
|
+
const content = fs.readFileSync(CONFIG_FILE(), "utf-8");
|
|
22
|
+
const data = JSON.parse(content);
|
|
23
|
+
if (isPureObject(data))
|
|
24
|
+
return data;
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* @param url
|
|
29
|
+
* @returns
|
|
30
|
+
*/
|
|
31
|
+
has(url) {
|
|
32
|
+
return !!this.get(url);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @param url
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
get(url) {
|
|
39
|
+
const cache = this.readFile();
|
|
40
|
+
return cache?.[url];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* @param url
|
|
44
|
+
* @param data
|
|
45
|
+
*/
|
|
46
|
+
set(url, data) {
|
|
47
|
+
this.setFile({ [url]: data });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { parserMetadata, xhr } from ".";
|
|
2
|
+
import LocalFileCache from "./local-file-cache";
|
|
3
|
+
const cache = new LocalFileCache();
|
|
4
|
+
/**
|
|
5
|
+
* @param url
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export function getUrlMetadata(url) {
|
|
9
|
+
if (cache.has(url))
|
|
10
|
+
return cache.get(url);
|
|
11
|
+
let metadata = null;
|
|
12
|
+
const htmlString = xhr.sync(url);
|
|
13
|
+
if (htmlString) {
|
|
14
|
+
metadata = parserMetadata(htmlString, url);
|
|
15
|
+
if (metadata)
|
|
16
|
+
cache.set(url, metadata);
|
|
17
|
+
}
|
|
18
|
+
return metadata;
|
|
19
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TODO: Refactor
|
|
3
|
+
*/
|
|
4
|
+
import { isString } from "@luckrya/utility";
|
|
5
|
+
import { cleanPath, extractUrl } from "./url";
|
|
6
|
+
const DEFAULT_LOGO = "https://resources.whatwg.org/logo-url.svg";
|
|
7
|
+
const HtmlTagContentReg = /(<[A-Za-z]+\s*[^>]*>(.*)<\/[A-Za-z]+>)/;
|
|
8
|
+
const ContentAttrValueHtmlMetaTagReg = /content=["|']([^>]*)["|']/;
|
|
9
|
+
const HrefAttrValueHtmlLinkTagReg = /href=["|']([^>]*)["|']/;
|
|
10
|
+
const HtmlTitleTagReg = /(<title\s*[^>]*>(.*)<\/title>)/g;
|
|
11
|
+
// const HtmlMetaTagReg = /<meta\s[^>]*\/?>/g;
|
|
12
|
+
// const HtmlLinkTagReg = /<link\s[^>]*\/?>/g;
|
|
13
|
+
const containArrSelfLosingHtmlTagReg = (attr, tag = "meta") => new RegExp(`<${tag}\\s[^>]*\\w+=['|"]([a-zA-Z]|:|\\s)*${attr}['|"][^>]*\\/?>`);
|
|
14
|
+
/**
|
|
15
|
+
* @param htmlString
|
|
16
|
+
* @returns
|
|
17
|
+
* <title>$value</title>
|
|
18
|
+
* <meta property="og:title" content="$value" />
|
|
19
|
+
* <link data-react-helmet="true" href="https://s.xml" rel="search" title="$value" type="applon+xml">
|
|
20
|
+
*/
|
|
21
|
+
function matchTitleByMetaTag(htmlString) {
|
|
22
|
+
let title;
|
|
23
|
+
const metas = htmlString.match(containArrSelfLosingHtmlTagReg("title"));
|
|
24
|
+
if (metas?.length) {
|
|
25
|
+
const content = metas[0].match(ContentAttrValueHtmlMetaTagReg);
|
|
26
|
+
if (content && isString(content[1]))
|
|
27
|
+
title = content[1];
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const titleHtmlTag = htmlString.match(HtmlTitleTagReg);
|
|
31
|
+
if (titleHtmlTag?.length) {
|
|
32
|
+
const content = titleHtmlTag[0].match(HtmlTagContentReg);
|
|
33
|
+
if (content && isString(content[2]))
|
|
34
|
+
title = content[2];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return title;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* @returns
|
|
41
|
+
* <meta name="description" content="$value" />
|
|
42
|
+
* <meta property="og:description" content="$value" />
|
|
43
|
+
*/
|
|
44
|
+
function matchDescriptionByMetaTag(htmlString) {
|
|
45
|
+
let description;
|
|
46
|
+
const metas = htmlString.match(containArrSelfLosingHtmlTagReg("description"));
|
|
47
|
+
if (metas?.length) {
|
|
48
|
+
const content = metas[0].match(ContentAttrValueHtmlMetaTagReg);
|
|
49
|
+
if (content && isString(content[1]))
|
|
50
|
+
description = content[1];
|
|
51
|
+
}
|
|
52
|
+
return description;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* @returns
|
|
56
|
+
* <meta property="og:image" content="$value" />
|
|
57
|
+
* <link rel="icon" href="$value">
|
|
58
|
+
*/
|
|
59
|
+
function matchLogoByLinkOrMetaTag(htmlString) {
|
|
60
|
+
let logo;
|
|
61
|
+
const metas = htmlString.match(containArrSelfLosingHtmlTagReg("image"));
|
|
62
|
+
if (metas?.length) {
|
|
63
|
+
const content = metas[0].match(ContentAttrValueHtmlMetaTagReg);
|
|
64
|
+
if (content && isString(content[1]))
|
|
65
|
+
logo = content[1];
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const linkHtmlTags = htmlString.match(containArrSelfLosingHtmlTagReg("icon", "link"));
|
|
69
|
+
if (linkHtmlTags?.length) {
|
|
70
|
+
const content = linkHtmlTags[0].match(HrefAttrValueHtmlLinkTagReg);
|
|
71
|
+
// logo 判断是否是完整地址
|
|
72
|
+
if (content && isString(content[1]))
|
|
73
|
+
logo = content[1];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return logo;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* @param htmlString
|
|
80
|
+
* @param url
|
|
81
|
+
* @returns
|
|
82
|
+
*/
|
|
83
|
+
export function parserMetadata(htmlString, url) {
|
|
84
|
+
function absolute(logo) {
|
|
85
|
+
if (!logo)
|
|
86
|
+
return DEFAULT_LOGO;
|
|
87
|
+
return extractUrl(logo)
|
|
88
|
+
? logo
|
|
89
|
+
: `${extractUrl(url)?.origin}${cleanPath(`/${logo}`)}`; // TODO: no match "content='//img.xx.com/a.png'"
|
|
90
|
+
}
|
|
91
|
+
const metadata = {
|
|
92
|
+
title: matchTitleByMetaTag(htmlString),
|
|
93
|
+
description: matchDescriptionByMetaTag(htmlString),
|
|
94
|
+
logo: absolute(matchLogoByLinkOrMetaTag(htmlString)),
|
|
95
|
+
};
|
|
96
|
+
if (isEmptyStringObject(metadata))
|
|
97
|
+
return null;
|
|
98
|
+
else
|
|
99
|
+
return metadata;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* @param obj
|
|
103
|
+
* @returns
|
|
104
|
+
*/
|
|
105
|
+
function isEmptyStringObject(obj) {
|
|
106
|
+
return !Object.values(obj).filter((v) => isString(v)).length;
|
|
107
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param str
|
|
3
|
+
* @returns
|
|
4
|
+
*/
|
|
5
|
+
function hyphenate(str) {
|
|
6
|
+
return str.replace(/\B([A-Z])/g, "-$1").toLowerCase();
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* @param style
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
function join(style) {
|
|
13
|
+
return Object.entries(style)
|
|
14
|
+
.map(([k, v]) => {
|
|
15
|
+
if (k && v)
|
|
16
|
+
return `${hyphenate(k)}: ${v};`;
|
|
17
|
+
})
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
.join(" ");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* @param style
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
function inlineStyle(style) {
|
|
26
|
+
return `style="${join(style)}"`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* @param line
|
|
30
|
+
* @returns
|
|
31
|
+
*/
|
|
32
|
+
const ellipsisStyle = (line) => ({
|
|
33
|
+
"-webkit-box-orient": "vertical",
|
|
34
|
+
"-webkit-line-clamp": line,
|
|
35
|
+
display: "-webkit-box",
|
|
36
|
+
hyphens: "auto",
|
|
37
|
+
lineClamp: line,
|
|
38
|
+
overflow: "hidden",
|
|
39
|
+
overflowWrap: "anywhere",
|
|
40
|
+
textOverflow: "ellipsis",
|
|
41
|
+
wordBreak: "break-word",
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
See: * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/components/VPFeature.vue
|
|
45
|
+
* @param borderColor
|
|
46
|
+
* @param bgColor
|
|
47
|
+
* @returns
|
|
48
|
+
*/
|
|
49
|
+
export const STYLE = (borderColor, bgColor) => ({
|
|
50
|
+
a: inlineStyle({
|
|
51
|
+
color: "unset !important",
|
|
52
|
+
display: "block",
|
|
53
|
+
width: "100%",
|
|
54
|
+
textDecoration: "none",
|
|
55
|
+
}),
|
|
56
|
+
container: inlineStyle({
|
|
57
|
+
display: "flex",
|
|
58
|
+
alignItems: "center",
|
|
59
|
+
flexWrap: "wrap",
|
|
60
|
+
gap: "10px",
|
|
61
|
+
borderRadius: "12px",
|
|
62
|
+
border: `1px solid ${borderColor}`,
|
|
63
|
+
backgroundColor: bgColor,
|
|
64
|
+
boxSizing: "border-box",
|
|
65
|
+
width: "100%",
|
|
66
|
+
height: "130px",
|
|
67
|
+
}),
|
|
68
|
+
img: inlineStyle({
|
|
69
|
+
borderRadius: "0px 12px 12px 0px",
|
|
70
|
+
maxWidth: "40%",
|
|
71
|
+
height: "128px", // container.height - 2px
|
|
72
|
+
flexShrink: 0,
|
|
73
|
+
objectFit: "contain",
|
|
74
|
+
overflow: "hidden",
|
|
75
|
+
}),
|
|
76
|
+
texts: inlineStyle({
|
|
77
|
+
flex: "1 1 0%",
|
|
78
|
+
minWidth: "0", // ellipsisを有効にするために必要
|
|
79
|
+
}),
|
|
80
|
+
title: inlineStyle({
|
|
81
|
+
...ellipsisStyle(2),
|
|
82
|
+
opacity: 1,
|
|
83
|
+
fontSize: "16px",
|
|
84
|
+
lineHeight: "22px",
|
|
85
|
+
margin: "0 16px 8px 16px",
|
|
86
|
+
fontWeight: "bold",
|
|
87
|
+
}),
|
|
88
|
+
domain: inlineStyle({
|
|
89
|
+
...ellipsisStyle(1),
|
|
90
|
+
opacity: 1,
|
|
91
|
+
fontSize: "12px",
|
|
92
|
+
lineHeight: "16px",
|
|
93
|
+
margin: "8px 16px 8px 16px",
|
|
94
|
+
textDecoration: "underline",
|
|
95
|
+
}),
|
|
96
|
+
description: inlineStyle({
|
|
97
|
+
...ellipsisStyle(2),
|
|
98
|
+
opacity: 0.8,
|
|
99
|
+
fontSize: "12px",
|
|
100
|
+
lineHeight: "16px",
|
|
101
|
+
margin: "8px 16px 0px 16px",
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
104
|
+
/**
|
|
105
|
+
* @param prefix
|
|
106
|
+
* @returns
|
|
107
|
+
*/
|
|
108
|
+
export const classNames = (prefix) => ({
|
|
109
|
+
container: `${prefix}__container`,
|
|
110
|
+
img: `${prefix}__img`,
|
|
111
|
+
texts: `${prefix}__texts`,
|
|
112
|
+
title: `${prefix}__texts--title`,
|
|
113
|
+
domain: `${prefix}__texts--domain`,
|
|
114
|
+
description: `${prefix}__texts--desc`,
|
|
115
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Refactor: xmlhttprequest will be replaced later
|
|
2
|
+
// @ts-expect-error: xmlhttprequest has no types
|
|
3
|
+
import xhrForNode from "xmlhttprequest";
|
|
4
|
+
import { inBrowser, isString } from "@luckrya/utility";
|
|
5
|
+
// TODO: Local File Cache
|
|
6
|
+
const cache = new Map();
|
|
7
|
+
const XHR = inBrowser ? window.XMLHttpRequest : xhrForNode.XMLHttpRequest;
|
|
8
|
+
/**
|
|
9
|
+
* @param url
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export function sync(url) {
|
|
13
|
+
if (cache.has(url))
|
|
14
|
+
return cache.get(url);
|
|
15
|
+
let result;
|
|
16
|
+
try {
|
|
17
|
+
const xhr = new XHR();
|
|
18
|
+
xhr.open("GET", url, false);
|
|
19
|
+
xhr.setRequestHeader("Content-Type", "text/html");
|
|
20
|
+
xhr.send();
|
|
21
|
+
if (xhr.status === 200 && !!xhr.responseText) {
|
|
22
|
+
result = xhr.responseText;
|
|
23
|
+
cache.set(url, xhr.responseText);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
console.error(`【XHR Error】:${err instanceof Error
|
|
28
|
+
? err.message
|
|
29
|
+
: "get remote URL resource exception!"}`);
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* @param url
|
|
35
|
+
* @returns
|
|
36
|
+
*/
|
|
37
|
+
export function async(url) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
try {
|
|
40
|
+
if (cache.has(url))
|
|
41
|
+
return resolve(cache.get(url));
|
|
42
|
+
const xhr = new XHR();
|
|
43
|
+
xhr.open("GET", url, false);
|
|
44
|
+
xhr.setRequestHeader("Content-Type", "text/html");
|
|
45
|
+
xhr.onreadystatechange = function () {
|
|
46
|
+
if (xhr.readyState === 4 &&
|
|
47
|
+
xhr.status === 200 &&
|
|
48
|
+
isString(xhr.responseText)) {
|
|
49
|
+
cache.set(url, xhr.responseText);
|
|
50
|
+
resolve(xhr.responseText);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
xhr.send();
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
reject(err);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { isFunction } from "@luckrya/utility";
|
|
2
|
+
import { getUrlMetadata, generateCardDomFragment } from "./assemble";
|
|
3
|
+
/**
|
|
4
|
+
* @param md
|
|
5
|
+
* @param pluginOptions
|
|
6
|
+
*/
|
|
7
|
+
export const linkToCardPlugin = (md, pluginOptions = {}) => {
|
|
8
|
+
function parseCardLinkHref(href) {
|
|
9
|
+
const tagRegexp = new RegExp(`^(${"@"}:)([a-zA-Z0-9]+.*)`);
|
|
10
|
+
const match = href?.match(tagRegexp);
|
|
11
|
+
return {
|
|
12
|
+
isCardLink: !!match,
|
|
13
|
+
url: match?.[2],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* @param options
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
function assembleCardTpl(options) {
|
|
21
|
+
const urlMetadata = getUrlMetadata(options.url);
|
|
22
|
+
if (urlMetadata) {
|
|
23
|
+
ignoreRestToken(options.tokens, options.i); // linkTitle 依赖 ignoreRestToken 的处理结果
|
|
24
|
+
const cardDomOptions = {
|
|
25
|
+
href: options.url,
|
|
26
|
+
linkTitle: joinLinkTitle(options.tokens),
|
|
27
|
+
target: pluginOptions.target || "_blank",
|
|
28
|
+
classPrefix: pluginOptions.classPrefix,
|
|
29
|
+
borderColor: pluginOptions.borderColor,
|
|
30
|
+
bgColor: pluginOptions.bgColor,
|
|
31
|
+
};
|
|
32
|
+
return isFunction(pluginOptions.render)
|
|
33
|
+
? pluginOptions.render(urlMetadata, cardDomOptions)
|
|
34
|
+
: generateCardDomFragment(urlMetadata, cardDomOptions);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* https://markdown-it.github.io/markdown-it/#MarkdownIt.renderInline
|
|
39
|
+
* @param tokens
|
|
40
|
+
* @param rootOptions
|
|
41
|
+
* @param env
|
|
42
|
+
* @returns
|
|
43
|
+
*/
|
|
44
|
+
md.renderer.renderInline = (tokens, rootOptions, env) => {
|
|
45
|
+
let result = "";
|
|
46
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
47
|
+
const currentToken = tokens[i];
|
|
48
|
+
const ruleFunction = md.renderer.rules[currentToken.type];
|
|
49
|
+
if (currentToken.hidden) {
|
|
50
|
+
result += "";
|
|
51
|
+
}
|
|
52
|
+
else if (isFunction(ruleFunction)) {
|
|
53
|
+
result += ruleFunction(tokens, i, rootOptions, env, md.renderer);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
result += md.renderer.renderToken(tokens, i, rootOptions);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* envは呼ばれなくても消さないこと
|
|
63
|
+
* @param tokens
|
|
64
|
+
* @param i
|
|
65
|
+
* @param rootOptions
|
|
66
|
+
* @param env
|
|
67
|
+
* @param self
|
|
68
|
+
* @returns
|
|
69
|
+
*/
|
|
70
|
+
md.renderer.rules.link_open = (tokens, i, rootOptions, env, self) => {
|
|
71
|
+
const token = tokens[i];
|
|
72
|
+
const isLinkOpenToken = token.tag === "a" && token.type === "link_open";
|
|
73
|
+
const href = token.attrs?.filter((attr) => attr.includes("href"))[0]?.[1];
|
|
74
|
+
const { url, isCardLink } = parseCardLinkHref(href);
|
|
75
|
+
if (isLinkOpenToken && isCardLink && url) {
|
|
76
|
+
const card = assembleCardTpl({ url, tokens, i });
|
|
77
|
+
if (card)
|
|
78
|
+
return card;
|
|
79
|
+
}
|
|
80
|
+
return self.renderToken(tokens, i, rootOptions);
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* TODO: handle softbreak https://markdown-it.github.io/
|
|
85
|
+
* @param tokens
|
|
86
|
+
* @param i
|
|
87
|
+
*/
|
|
88
|
+
function ignoreRestToken(tokens, i) {
|
|
89
|
+
tokens.forEach((token, index) => {
|
|
90
|
+
if (index !== i)
|
|
91
|
+
token.hidden = true;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* @param tokens
|
|
96
|
+
* @returns
|
|
97
|
+
*/
|
|
98
|
+
function joinLinkTitle(tokens) {
|
|
99
|
+
return tokens
|
|
100
|
+
.map(({ hidden, content }) => {
|
|
101
|
+
if (hidden)
|
|
102
|
+
return content;
|
|
103
|
+
return "";
|
|
104
|
+
})
|
|
105
|
+
.filter(Boolean)
|
|
106
|
+
.join("");
|
|
107
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"bugs": {
|
|
10
10
|
"url": "https://github.com/asumo-1xts/vitepress-linkcard"
|
|
11
11
|
},
|
|
12
|
-
"description": "A
|
|
12
|
+
"description": "A Vitepress plugin to generate a pretty linkcard with OGP.",
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@babel/core": "^7.28.5",
|
|
15
15
|
"@babel/preset-env": "^7.28.5",
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
},
|
|
76
76
|
"type": "module",
|
|
77
77
|
"types": "./types/index.d.ts",
|
|
78
|
-
"version": "0.
|
|
79
|
-
}
|
|
78
|
+
"version": "1.0.0"
|
|
79
|
+
}
|
package/types/api.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { UrlMetadata, CardDomRenderOptions } from "./types";
|
|
2
|
+
interface CardResponse {
|
|
3
|
+
url: string;
|
|
4
|
+
data: UrlMetadata;
|
|
5
|
+
options: Omit<CardDomRenderOptions, "href">;
|
|
6
|
+
dom: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* @param url
|
|
10
|
+
* @param options
|
|
11
|
+
* @returns
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateCard(url: string, options: Omit<CardDomRenderOptions, "href">): Promise<CardResponse>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default class LocalFileCache<V extends Record<string, unknown>> {
|
|
2
|
+
constructor();
|
|
3
|
+
/**
|
|
4
|
+
* @param data
|
|
5
|
+
*/
|
|
6
|
+
private setFile;
|
|
7
|
+
/**
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
private readFile;
|
|
11
|
+
/**
|
|
12
|
+
* @param url
|
|
13
|
+
* @returns
|
|
14
|
+
*/
|
|
15
|
+
has(url: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* @param url
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
get(url: string): V | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* @param url
|
|
23
|
+
* @param data
|
|
24
|
+
*/
|
|
25
|
+
set(url: string, data: V): void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
See: * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/components/VPFeature.vue
|
|
3
|
+
* @param borderColor
|
|
4
|
+
* @param bgColor
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
export declare const STYLE: (borderColor: string, bgColor: string) => {
|
|
8
|
+
a: string;
|
|
9
|
+
container: string;
|
|
10
|
+
img: string;
|
|
11
|
+
texts: string;
|
|
12
|
+
title: string;
|
|
13
|
+
domain: string;
|
|
14
|
+
description: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* @param prefix
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export declare const classNames: (prefix?: string) => {
|
|
21
|
+
container: string;
|
|
22
|
+
img: string;
|
|
23
|
+
texts: string;
|
|
24
|
+
title: string;
|
|
25
|
+
domain: string;
|
|
26
|
+
description: string;
|
|
27
|
+
};
|
package/types/index.d.ts
ADDED
package/types/types.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type MarkdownIt from "markdown-it";
|
|
2
|
+
export type LinkToCardPlugin = MarkdownIt.PluginWithOptions<LinkToCardPluginOptions>;
|
|
3
|
+
export interface LinkToCardPluginOptions {
|
|
4
|
+
target?: ATarget;
|
|
5
|
+
classPrefix?: string;
|
|
6
|
+
render?: CardDomRender;
|
|
7
|
+
borderColor?: string;
|
|
8
|
+
bgColor?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface UrlMetadata {
|
|
11
|
+
title?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
logo?: string;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export type ATarget = "_self" | "_blank" | "_top" | "_parent";
|
|
17
|
+
export interface CardDomRenderOptions {
|
|
18
|
+
href: string;
|
|
19
|
+
linkTitle: string;
|
|
20
|
+
target: ATarget;
|
|
21
|
+
classPrefix?: string;
|
|
22
|
+
borderColor?: string;
|
|
23
|
+
bgColor?: string;
|
|
24
|
+
}
|
|
25
|
+
export type CardDomRender = (data: UrlMetadata, options: CardDomRenderOptions) => string;
|