rehype-og-card 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +9 -6
- package/dist/types.d.ts +16 -1
- package/dist/util/cache.d.ts +13 -0
- package/dist/util/cache.js +52 -0
- package/dist/util/file.d.ts +7 -0
- package/dist/util/file.js +25 -0
- package/dist/util/hast.d.ts +37 -0
- package/dist/util/hast.js +68 -0
- package/dist/util/network.d.ts +35 -0
- package/dist/{util.js → util/network.js} +36 -46
- package/package.json +1 -1
- package/dist/openGraphUtil.d.ts +0 -31
- package/dist/openGraphUtil.js +0 -91
- package/dist/util.d.ts +0 -60
package/dist/index.js
CHANGED
|
@@ -7,8 +7,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { convertTextToAnchorElement,
|
|
11
|
-
import {
|
|
10
|
+
import { convertTextToAnchorElement, createOGCard, isAnchorElement, isTextNode } from "./util/hast.js";
|
|
11
|
+
import { downloadImage, getOGData, isValidURL } from "./util/network.js";
|
|
12
|
+
import { restoreBuildCache, saveBuildCache } from "./util/cache.js";
|
|
12
13
|
import { isElement } from "hast-util-is-element";
|
|
13
14
|
import path from "path";
|
|
14
15
|
import { visitParents } from "unist-util-visit-parents";
|
|
@@ -45,6 +46,9 @@ const rehypeOGCard = (options) => {
|
|
|
45
46
|
*/
|
|
46
47
|
// eslint-disable-next-line max-lines-per-function
|
|
47
48
|
const transform = (tree) => __awaiter(void 0, void 0, void 0, function* () {
|
|
49
|
+
if (mergedOptions.buildCache) {
|
|
50
|
+
yield restoreBuildCache(mergedOptions.buildCachePath, mergedOptions.serverCachePath);
|
|
51
|
+
}
|
|
48
52
|
const linkCardPromises = [];
|
|
49
53
|
// eslint-disable-next-line max-statements, max-lines-per-function
|
|
50
54
|
visitParents(tree, ["element", "text"], (node, ancestors) => {
|
|
@@ -88,10 +92,8 @@ const rehypeOGCard = (options) => {
|
|
|
88
92
|
return;
|
|
89
93
|
if (OGData.OGImageURL && mergedOptions.serverCache) {
|
|
90
94
|
const filename = yield downloadImage({
|
|
91
|
-
buildCacheDirectory: mergedOptions.buildCachePath,
|
|
92
95
|
directly: mergedOptions.serverCachePath,
|
|
93
96
|
url: OGData.OGImageURL,
|
|
94
|
-
useBuildCache: mergedOptions.buildCache,
|
|
95
97
|
userAgent: mergedOptions.crawlerUserAgent
|
|
96
98
|
});
|
|
97
99
|
if (filename && mergedOptions.serverCache) {
|
|
@@ -100,10 +102,8 @@ const rehypeOGCard = (options) => {
|
|
|
100
102
|
}
|
|
101
103
|
if (OGData.faviconURL && mergedOptions.serverCache) {
|
|
102
104
|
const filename = yield downloadImage({
|
|
103
|
-
buildCacheDirectory: mergedOptions.buildCachePath,
|
|
104
105
|
directly: mergedOptions.serverCachePath,
|
|
105
106
|
url: OGData.faviconURL,
|
|
106
|
-
useBuildCache: mergedOptions.buildCache,
|
|
107
107
|
userAgent: mergedOptions.crawlerUserAgent
|
|
108
108
|
});
|
|
109
109
|
if (filename && mergedOptions.serverCache) {
|
|
@@ -126,6 +126,9 @@ const rehypeOGCard = (options) => {
|
|
|
126
126
|
linkCardPromises.push(linkCardPromise());
|
|
127
127
|
});
|
|
128
128
|
yield Promise.all(linkCardPromises);
|
|
129
|
+
if (mergedOptions.buildCache) {
|
|
130
|
+
yield saveBuildCache(mergedOptions.serverCachePath, mergedOptions.buildCachePath);
|
|
131
|
+
}
|
|
129
132
|
});
|
|
130
133
|
return transform;
|
|
131
134
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -31,16 +31,20 @@ interface RehypeOGCardOptions {
|
|
|
31
31
|
serverCache?: boolean;
|
|
32
32
|
/**
|
|
33
33
|
* Path to save the server cache.
|
|
34
|
+
* Specify the directory whose contents will be copied to the root.
|
|
35
|
+
* For example, for an Astro project, specify the `public` directory.
|
|
34
36
|
* @default "./public"
|
|
35
37
|
*/
|
|
36
38
|
serverCachePath?: string;
|
|
37
39
|
/**
|
|
38
40
|
* Whether to cache the OG metadata and images for the next build.
|
|
41
|
+
* `buildCache` option requires `serverCache` option to be enabled.
|
|
39
42
|
* @default false
|
|
40
43
|
*/
|
|
41
44
|
buildCache?: boolean;
|
|
42
45
|
/**
|
|
43
46
|
* Path to save the build cache.
|
|
47
|
+
* For Astro projects, specify the `./node_modules/.astro` directory.
|
|
44
48
|
* @default "./node_modules/.cache"
|
|
45
49
|
*/
|
|
46
50
|
buildCachePath?: string;
|
|
@@ -50,4 +54,15 @@ interface RehypeOGCardOptions {
|
|
|
50
54
|
*/
|
|
51
55
|
crawlerUserAgent?: string;
|
|
52
56
|
}
|
|
53
|
-
|
|
57
|
+
interface OGCardData {
|
|
58
|
+
url: string;
|
|
59
|
+
title: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
displayURL: string;
|
|
62
|
+
faviconURL?: string;
|
|
63
|
+
OGImageURL?: string;
|
|
64
|
+
OGImageAlt?: string;
|
|
65
|
+
OGImageWidth?: number;
|
|
66
|
+
OGImageHeight?: number;
|
|
67
|
+
}
|
|
68
|
+
export { RehypeOGCardOptions, OGCardData };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Save build cache if server cache exists.
|
|
3
|
+
* @param serverCachePath Server cache path.
|
|
4
|
+
* @param buildCachePath Build cache path.
|
|
5
|
+
*/
|
|
6
|
+
declare const saveBuildCache: (serverCachePath: string, buildCachePath: string) => Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Restore build cache if it exists.
|
|
9
|
+
* @param buildCachePath Build cache path.
|
|
10
|
+
* @param serverCachePath Server cache path.
|
|
11
|
+
*/
|
|
12
|
+
declare const restoreBuildCache: (buildCachePath: string, serverCachePath: string) => Promise<void>;
|
|
13
|
+
export { saveBuildCache, restoreBuildCache };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { checkFileExists } from "./file.js";
|
|
11
|
+
import fs from "fs/promises";
|
|
12
|
+
import path from "path";
|
|
13
|
+
/**
|
|
14
|
+
* Copy directory from source to destination.
|
|
15
|
+
* @param source Source directory.
|
|
16
|
+
* @param destination Destination directory.
|
|
17
|
+
*/
|
|
18
|
+
// eslint-disable-next-line max-statements
|
|
19
|
+
const copyDirectory = (source, destination) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
const sourceExists = yield checkFileExists(source);
|
|
21
|
+
if (!sourceExists)
|
|
22
|
+
return;
|
|
23
|
+
const destinationExists = yield checkFileExists(destination);
|
|
24
|
+
if (!destinationExists) {
|
|
25
|
+
yield fs.mkdir(destination, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
const files = yield fs.readdir(source);
|
|
28
|
+
const promises = [];
|
|
29
|
+
for (const file of files) {
|
|
30
|
+
const sourceFile = path.join(source, file);
|
|
31
|
+
const destFile = path.join(destination, file);
|
|
32
|
+
promises.push(fs.copyFile(sourceFile, destFile));
|
|
33
|
+
}
|
|
34
|
+
yield Promise.all(promises);
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Save build cache if server cache exists.
|
|
38
|
+
* @param serverCachePath Server cache path.
|
|
39
|
+
* @param buildCachePath Build cache path.
|
|
40
|
+
*/
|
|
41
|
+
const saveBuildCache = (serverCachePath, buildCachePath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
|
+
yield copyDirectory(serverCachePath, buildCachePath);
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Restore build cache if it exists.
|
|
46
|
+
* @param buildCachePath Build cache path.
|
|
47
|
+
* @param serverCachePath Server cache path.
|
|
48
|
+
*/
|
|
49
|
+
const restoreBuildCache = (buildCachePath, serverCachePath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
yield copyDirectory(buildCachePath, serverCachePath);
|
|
51
|
+
});
|
|
52
|
+
export { saveBuildCache, restoreBuildCache };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import fs from "fs/promises";
|
|
11
|
+
/**
|
|
12
|
+
* Check if the file exists.
|
|
13
|
+
* @param filePath Path to check.
|
|
14
|
+
* @returns `true` if the file exists, `false` otherwise.
|
|
15
|
+
*/
|
|
16
|
+
const checkFileExists = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
try {
|
|
18
|
+
yield fs.access(filePath);
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
catch (_a) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
export { checkFileExists };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Element, ElementContent, Text } from "hast";
|
|
2
|
+
import { OGCardData, RehypeOGCardOptions } from "../types.js";
|
|
3
|
+
interface AnchorElement extends Element {
|
|
4
|
+
tagName: "a";
|
|
5
|
+
properties: {
|
|
6
|
+
href: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Check if the node is a text node.
|
|
11
|
+
* @param node Node to check.
|
|
12
|
+
* @returns `true` if the node is a text node, `false` otherwise.
|
|
13
|
+
*/
|
|
14
|
+
declare const isTextNode: (node: ElementContent) => node is Text;
|
|
15
|
+
/**
|
|
16
|
+
* Check if the node is an anchor element.
|
|
17
|
+
* @param node Node to check.
|
|
18
|
+
* @returns `true` if the node is an anchor element, `false` otherwise.
|
|
19
|
+
*/
|
|
20
|
+
declare const isAnchorElement: (node: unknown) => node is AnchorElement;
|
|
21
|
+
/**
|
|
22
|
+
* Convert text node to anchor element. **This function does not check if the text is a valid URL.**
|
|
23
|
+
* @param text Text node to convert.
|
|
24
|
+
* @returns Anchor element.
|
|
25
|
+
*/
|
|
26
|
+
declare const convertTextToAnchorElement: (text: Text) => AnchorElement;
|
|
27
|
+
/**
|
|
28
|
+
* Create OG card element from given data.
|
|
29
|
+
* @param data Data to create OG card.
|
|
30
|
+
* @param options Options to create OG card.
|
|
31
|
+
* @returns OG card element.
|
|
32
|
+
*/
|
|
33
|
+
declare const createOGCard: (data: OGCardData, options: Required<{
|
|
34
|
+
loading: RehypeOGCardOptions["loading"];
|
|
35
|
+
decoding: RehypeOGCardOptions["decoding"];
|
|
36
|
+
}>) => Element;
|
|
37
|
+
export { AnchorElement, isTextNode, isAnchorElement, convertTextToAnchorElement, createOGCard };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { h } from "hastscript";
|
|
2
|
+
import { isElement } from "hast-util-is-element";
|
|
3
|
+
/**
|
|
4
|
+
* Check if the node is a text node.
|
|
5
|
+
* @param node Node to check.
|
|
6
|
+
* @returns `true` if the node is a text node, `false` otherwise.
|
|
7
|
+
*/
|
|
8
|
+
const isTextNode = (node) => Boolean(node) && typeof node === "object" && "type" in node && node.type === "text";
|
|
9
|
+
/**
|
|
10
|
+
* Check if the node is an anchor element.
|
|
11
|
+
* @param node Node to check.
|
|
12
|
+
* @returns `true` if the node is an anchor element, `false` otherwise.
|
|
13
|
+
*/
|
|
14
|
+
const isAnchorElement = (node) => Boolean(node) && isElement(node, "a") && "href" in node.properties && typeof node.properties.href === "string";
|
|
15
|
+
/**
|
|
16
|
+
* Convert text node to anchor element. **This function does not check if the text is a valid URL.**
|
|
17
|
+
* @param text Text node to convert.
|
|
18
|
+
* @returns Anchor element.
|
|
19
|
+
*/
|
|
20
|
+
const convertTextToAnchorElement = (text) => ({
|
|
21
|
+
children: [text],
|
|
22
|
+
properties: {
|
|
23
|
+
href: text.value.trim()
|
|
24
|
+
},
|
|
25
|
+
tagName: "a",
|
|
26
|
+
type: "element"
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Create OG card element from given data.
|
|
30
|
+
* @param data Data to create OG card.
|
|
31
|
+
* @param options Options to create OG card.
|
|
32
|
+
* @returns OG card element.
|
|
33
|
+
*/
|
|
34
|
+
const createOGCard = (data, options) => {
|
|
35
|
+
const card = h("div.og-card-container", [
|
|
36
|
+
h("a", { href: data.url }, [
|
|
37
|
+
h("div.og-card-info", [
|
|
38
|
+
h("div.og-card-title", data.title),
|
|
39
|
+
data.description ? h("div.og-card-description", data.description) : null,
|
|
40
|
+
h("div.og-card-url-container", [
|
|
41
|
+
h("img.og-card-favicon", {
|
|
42
|
+
alt: "favicon",
|
|
43
|
+
decoding: options.decoding,
|
|
44
|
+
height: 16,
|
|
45
|
+
loading: options.loading,
|
|
46
|
+
src: data.faviconURL,
|
|
47
|
+
width: 16
|
|
48
|
+
}),
|
|
49
|
+
h("span.og-card-url", data.displayURL)
|
|
50
|
+
])
|
|
51
|
+
]),
|
|
52
|
+
data.OGImageURL
|
|
53
|
+
? h("div.og-card-image-container", [
|
|
54
|
+
h("img.og-card-image", {
|
|
55
|
+
alt: data.OGImageAlt || data.OGImageURL,
|
|
56
|
+
decoding: options.decoding,
|
|
57
|
+
height: data.OGImageHeight,
|
|
58
|
+
loading: options.loading,
|
|
59
|
+
src: data.OGImageURL,
|
|
60
|
+
width: data.OGImageWidth
|
|
61
|
+
})
|
|
62
|
+
])
|
|
63
|
+
: null
|
|
64
|
+
])
|
|
65
|
+
]);
|
|
66
|
+
return card;
|
|
67
|
+
};
|
|
68
|
+
export { isTextNode, isAnchorElement, convertTextToAnchorElement, createOGCard };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { OGCardData } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Check if the URL is valid.
|
|
4
|
+
* @param url URL to check.
|
|
5
|
+
* @returns `true` if the URL is valid, `false` otherwise.
|
|
6
|
+
*/
|
|
7
|
+
declare const isValidURL: (url: string) => boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Get OG card data from given URL.
|
|
10
|
+
* @param url URL to get OG card data.
|
|
11
|
+
* @param userAgent User agent to use for fetching.
|
|
12
|
+
* @returns OG card data.
|
|
13
|
+
*/
|
|
14
|
+
declare const getOGData: (url: string, userAgent: string) => Promise<OGCardData | null>;
|
|
15
|
+
interface DownloadImageOptions {
|
|
16
|
+
/**
|
|
17
|
+
* URL to download image.
|
|
18
|
+
*/
|
|
19
|
+
url: string;
|
|
20
|
+
/**
|
|
21
|
+
* Directory to save the downloaded image.
|
|
22
|
+
*/
|
|
23
|
+
directly: string;
|
|
24
|
+
/**
|
|
25
|
+
* User agent to use for fetching the image.
|
|
26
|
+
*/
|
|
27
|
+
userAgent: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Download image from given URL.
|
|
31
|
+
* @param options Options to download image.
|
|
32
|
+
* @returns Path to the downloaded image.
|
|
33
|
+
*/
|
|
34
|
+
declare const downloadImage: (options: DownloadImageOptions) => Promise<string | null>;
|
|
35
|
+
export { isValidURL, getOGData, downloadImage };
|
|
@@ -7,22 +7,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
import { checkFileExists } from "./file.js";
|
|
10
11
|
import { createHash } from "crypto";
|
|
11
12
|
import fs from "fs/promises";
|
|
12
|
-
import { isElement } from "hast-util-is-element";
|
|
13
13
|
import path from "path";
|
|
14
|
-
|
|
15
|
-
* Check if the node is a text node.
|
|
16
|
-
* @param node Node to check.
|
|
17
|
-
* @returns `true` if the node is a text node, `false` otherwise.
|
|
18
|
-
*/
|
|
19
|
-
const isTextNode = (node) => Boolean(node) && typeof node === "object" && "type" in node && node.type === "text";
|
|
20
|
-
/**
|
|
21
|
-
* Check if the node is an anchor element.
|
|
22
|
-
* @param node Node to check.
|
|
23
|
-
* @returns `true` if the node is an anchor element, `false` otherwise.
|
|
24
|
-
*/
|
|
25
|
-
const isAnchorElement = (node) => Boolean(node) && isElement(node, "a") && "href" in node.properties && typeof node.properties.href === "string";
|
|
14
|
+
import scraper from "open-graph-scraper";
|
|
26
15
|
/**
|
|
27
16
|
* Check if the URL is valid.
|
|
28
17
|
* @param url URL to check.
|
|
@@ -39,30 +28,42 @@ const isValidURL = (url) => {
|
|
|
39
28
|
}
|
|
40
29
|
};
|
|
41
30
|
/**
|
|
42
|
-
*
|
|
43
|
-
* @param
|
|
44
|
-
* @
|
|
31
|
+
* Get OG card data from given URL.
|
|
32
|
+
* @param url URL to get OG card data.
|
|
33
|
+
* @param userAgent User agent to use for fetching.
|
|
34
|
+
* @returns OG card data.
|
|
45
35
|
*/
|
|
46
|
-
const
|
|
47
|
-
children: [text],
|
|
48
|
-
properties: {
|
|
49
|
-
href: text.value.trim()
|
|
50
|
-
},
|
|
51
|
-
tagName: "a",
|
|
52
|
-
type: "element"
|
|
53
|
-
});
|
|
54
|
-
/**
|
|
55
|
-
* Check if the file exists.
|
|
56
|
-
* @param filePath Path to check.
|
|
57
|
-
* @returns `true` if the file exists, `false` otherwise.
|
|
58
|
-
*/
|
|
59
|
-
const checkFileExists = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
36
|
+
const getOGData = (url, userAgent) => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
37
|
try {
|
|
61
|
-
yield
|
|
62
|
-
|
|
38
|
+
const { result } = yield scraper({
|
|
39
|
+
fetchOptions: {
|
|
40
|
+
headers: {
|
|
41
|
+
"user-agent": userAgent
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
url
|
|
45
|
+
});
|
|
46
|
+
const OGImage = result.ogImage ? result.ogImage[0] : null;
|
|
47
|
+
const faviconURL = result.favicon
|
|
48
|
+
? `https://www.google.com/s2/favicons?domain=${new URL(url).hostname}`
|
|
49
|
+
: // eslint-disable-next-line no-undefined
|
|
50
|
+
undefined;
|
|
51
|
+
return {
|
|
52
|
+
OGImageAlt: OGImage === null || OGImage === void 0 ? void 0 : OGImage.alt,
|
|
53
|
+
OGImageHeight: OGImage === null || OGImage === void 0 ? void 0 : OGImage.height,
|
|
54
|
+
OGImageURL: OGImage === null || OGImage === void 0 ? void 0 : OGImage.url,
|
|
55
|
+
OGImageWidth: OGImage === null || OGImage === void 0 ? void 0 : OGImage.width,
|
|
56
|
+
description: result.ogDescription,
|
|
57
|
+
displayURL: url,
|
|
58
|
+
faviconURL,
|
|
59
|
+
title: result.ogTitle || url,
|
|
60
|
+
url
|
|
61
|
+
};
|
|
63
62
|
}
|
|
64
|
-
catch (
|
|
65
|
-
|
|
63
|
+
catch (error) {
|
|
64
|
+
// eslint-disable-next-line no-console
|
|
65
|
+
console.error("[rehype-og-card] Error fetching OG data:", error);
|
|
66
|
+
return null;
|
|
66
67
|
}
|
|
67
68
|
});
|
|
68
69
|
/**
|
|
@@ -81,18 +82,11 @@ const downloadImage = (options) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
81
82
|
const hash = createHash("sha256").update(options.url).digest("hex");
|
|
82
83
|
const filename = hash + path.extname(new URL(options.url).pathname);
|
|
83
84
|
const savePath = path.posix.join(options.directly, filename);
|
|
84
|
-
const buildCachePath = path.posix.join(options.buildCacheDirectory, filename);
|
|
85
85
|
// If the file already exists, return the filename.
|
|
86
86
|
const fileExists = yield checkFileExists(savePath);
|
|
87
87
|
if (fileExists) {
|
|
88
88
|
return filename;
|
|
89
89
|
}
|
|
90
|
-
const buildCacheExists = yield checkFileExists(buildCachePath);
|
|
91
|
-
if (options.useBuildCache && buildCacheExists) {
|
|
92
|
-
yield fs.mkdir(options.directly, { recursive: true });
|
|
93
|
-
yield fs.copyFile(buildCachePath, savePath);
|
|
94
|
-
return filename;
|
|
95
|
-
}
|
|
96
90
|
const response = yield fetch(options.url, {
|
|
97
91
|
headers: {
|
|
98
92
|
"user-agent": options.userAgent
|
|
@@ -102,10 +96,6 @@ const downloadImage = (options) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
102
96
|
const buffer = Buffer.from(arrayBuffer);
|
|
103
97
|
yield fs.mkdir(options.directly, { recursive: true });
|
|
104
98
|
yield fs.writeFile(savePath, buffer);
|
|
105
|
-
if (options.useBuildCache) {
|
|
106
|
-
yield fs.mkdir(options.buildCacheDirectory, { recursive: true });
|
|
107
|
-
yield fs.writeFile(buildCachePath, buffer);
|
|
108
|
-
}
|
|
109
99
|
return filename;
|
|
110
100
|
}
|
|
111
101
|
catch (error) {
|
|
@@ -114,4 +104,4 @@ const downloadImage = (options) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
114
104
|
return null;
|
|
115
105
|
}
|
|
116
106
|
});
|
|
117
|
-
export {
|
|
107
|
+
export { isValidURL, getOGData, downloadImage };
|
package/package.json
CHANGED
package/dist/openGraphUtil.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { Element } from "hast";
|
|
2
|
-
import { RehypeOGCardOptions } from "./types.js";
|
|
3
|
-
interface OGCardData {
|
|
4
|
-
url: string;
|
|
5
|
-
title: string;
|
|
6
|
-
description?: string;
|
|
7
|
-
displayURL: string;
|
|
8
|
-
faviconURL?: string;
|
|
9
|
-
OGImageURL?: string;
|
|
10
|
-
OGImageAlt?: string;
|
|
11
|
-
OGImageWidth?: number;
|
|
12
|
-
OGImageHeight?: number;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Get OG card data from given URL.
|
|
16
|
-
* @param url URL to get OG card data.
|
|
17
|
-
* @param userAgent User agent to use for fetching.
|
|
18
|
-
* @returns OG card data.
|
|
19
|
-
*/
|
|
20
|
-
declare const getOGData: (url: string, userAgent: string) => Promise<OGCardData | null>;
|
|
21
|
-
/**
|
|
22
|
-
* Create OG card element from given data.
|
|
23
|
-
* @param data Data to create OG card.
|
|
24
|
-
* @param options Options to create OG card.
|
|
25
|
-
* @returns OG card element.
|
|
26
|
-
*/
|
|
27
|
-
declare const createOGCard: (data: OGCardData, options: Required<{
|
|
28
|
-
loading: RehypeOGCardOptions["loading"];
|
|
29
|
-
decoding: RehypeOGCardOptions["decoding"];
|
|
30
|
-
}>) => Element;
|
|
31
|
-
export { OGCardData, createOGCard, getOGData };
|
package/dist/openGraphUtil.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import { h } from "hastscript";
|
|
11
|
-
import scraper from "open-graph-scraper";
|
|
12
|
-
/**
|
|
13
|
-
* Get OG card data from given URL.
|
|
14
|
-
* @param url URL to get OG card data.
|
|
15
|
-
* @param userAgent User agent to use for fetching.
|
|
16
|
-
* @returns OG card data.
|
|
17
|
-
*/
|
|
18
|
-
const getOGData = (url, userAgent) => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
-
try {
|
|
20
|
-
const { result } = yield scraper({
|
|
21
|
-
fetchOptions: {
|
|
22
|
-
headers: {
|
|
23
|
-
"user-agent": userAgent
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
url
|
|
27
|
-
});
|
|
28
|
-
const OGImage = result.ogImage ? result.ogImage[0] : null;
|
|
29
|
-
const faviconURL = result.favicon
|
|
30
|
-
? `https://www.google.com/s2/favicons?domain=${new URL(url).hostname}`
|
|
31
|
-
: // eslint-disable-next-line no-undefined
|
|
32
|
-
undefined;
|
|
33
|
-
return {
|
|
34
|
-
OGImageAlt: OGImage === null || OGImage === void 0 ? void 0 : OGImage.alt,
|
|
35
|
-
OGImageHeight: OGImage === null || OGImage === void 0 ? void 0 : OGImage.height,
|
|
36
|
-
OGImageURL: OGImage === null || OGImage === void 0 ? void 0 : OGImage.url,
|
|
37
|
-
OGImageWidth: OGImage === null || OGImage === void 0 ? void 0 : OGImage.width,
|
|
38
|
-
description: result.ogDescription,
|
|
39
|
-
displayURL: url,
|
|
40
|
-
faviconURL,
|
|
41
|
-
title: result.ogTitle || url,
|
|
42
|
-
url
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
// eslint-disable-next-line no-console
|
|
47
|
-
console.error("[rehype-og-card] Error fetching OG data:", error);
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
/**
|
|
52
|
-
* Create OG card element from given data.
|
|
53
|
-
* @param data Data to create OG card.
|
|
54
|
-
* @param options Options to create OG card.
|
|
55
|
-
* @returns OG card element.
|
|
56
|
-
*/
|
|
57
|
-
const createOGCard = (data, options) => {
|
|
58
|
-
const card = h("div.og-card-container", [
|
|
59
|
-
h("a", { href: data.url }, [
|
|
60
|
-
h("div.og-card-info", [
|
|
61
|
-
h("div.og-card-title", data.title),
|
|
62
|
-
data.description ? h("div.og-card-description", data.description) : null,
|
|
63
|
-
h("div.og-card-url-container", [
|
|
64
|
-
h("img.og-card-favicon", {
|
|
65
|
-
alt: "favicon",
|
|
66
|
-
decoding: options.decoding,
|
|
67
|
-
height: 16,
|
|
68
|
-
loading: options.loading,
|
|
69
|
-
src: data.faviconURL,
|
|
70
|
-
width: 16
|
|
71
|
-
}),
|
|
72
|
-
h("span.og-card-url", data.displayURL)
|
|
73
|
-
])
|
|
74
|
-
]),
|
|
75
|
-
data.OGImageURL
|
|
76
|
-
? h("div.og-card-image-container", [
|
|
77
|
-
h("img.og-card-image", {
|
|
78
|
-
alt: data.OGImageAlt || data.OGImageURL,
|
|
79
|
-
decoding: options.decoding,
|
|
80
|
-
height: data.OGImageHeight,
|
|
81
|
-
loading: options.loading,
|
|
82
|
-
src: data.OGImageURL,
|
|
83
|
-
width: data.OGImageWidth
|
|
84
|
-
})
|
|
85
|
-
])
|
|
86
|
-
: null
|
|
87
|
-
])
|
|
88
|
-
]);
|
|
89
|
-
return card;
|
|
90
|
-
};
|
|
91
|
-
export { createOGCard, getOGData };
|
package/dist/util.d.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import type { Element, ElementContent, Text } from "hast";
|
|
2
|
-
interface AnchorElement extends Element {
|
|
3
|
-
tagName: "a";
|
|
4
|
-
properties: {
|
|
5
|
-
href: string;
|
|
6
|
-
};
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Check if the node is a text node.
|
|
10
|
-
* @param node Node to check.
|
|
11
|
-
* @returns `true` if the node is a text node, `false` otherwise.
|
|
12
|
-
*/
|
|
13
|
-
declare const isTextNode: (node: ElementContent) => node is Text;
|
|
14
|
-
/**
|
|
15
|
-
* Check if the node is an anchor element.
|
|
16
|
-
* @param node Node to check.
|
|
17
|
-
* @returns `true` if the node is an anchor element, `false` otherwise.
|
|
18
|
-
*/
|
|
19
|
-
declare const isAnchorElement: (node: unknown) => node is AnchorElement;
|
|
20
|
-
/**
|
|
21
|
-
* Check if the URL is valid.
|
|
22
|
-
* @param url URL to check.
|
|
23
|
-
* @returns `true` if the URL is valid, `false` otherwise.
|
|
24
|
-
*/
|
|
25
|
-
declare const isValidURL: (url: string) => boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Convert text node to anchor element. **This function does not check if the text is a valid URL.**
|
|
28
|
-
* @param text Text node to convert.
|
|
29
|
-
* @returns Anchor element.
|
|
30
|
-
*/
|
|
31
|
-
declare const convertTextToAnchorElement: (text: Text) => AnchorElement;
|
|
32
|
-
interface DownloadImageOptions {
|
|
33
|
-
/**
|
|
34
|
-
* URL to download image.
|
|
35
|
-
*/
|
|
36
|
-
url: string;
|
|
37
|
-
/**
|
|
38
|
-
* Directory to save the downloaded image.
|
|
39
|
-
*/
|
|
40
|
-
directly: string;
|
|
41
|
-
/**
|
|
42
|
-
* Whether to save and restore the image cache.
|
|
43
|
-
*/
|
|
44
|
-
useBuildCache: boolean;
|
|
45
|
-
/**
|
|
46
|
-
* Directory to save the image cache.
|
|
47
|
-
*/
|
|
48
|
-
buildCacheDirectory: string;
|
|
49
|
-
/**
|
|
50
|
-
* User agent to use for fetching the image.
|
|
51
|
-
*/
|
|
52
|
-
userAgent: string;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Download image from given URL.
|
|
56
|
-
* @param options Options to download image.
|
|
57
|
-
* @returns Path to the downloaded image.
|
|
58
|
-
*/
|
|
59
|
-
declare const downloadImage: (options: DownloadImageOptions) => Promise<string | null>;
|
|
60
|
-
export { AnchorElement, isTextNode, isAnchorElement, isValidURL, convertTextToAnchorElement, downloadImage };
|