vitepress-linkcard 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,20 +1,49 @@
1
1
  {
2
- "author": "aSumo",
3
- "babel": {
4
- "presets": [
5
- "@babel/env",
6
- "@babel/typescript"
7
- ]
8
- },
2
+ "name": "vitepress-linkcard",
3
+ "version": "2.1.0",
4
+ "description": "A Vitepress plugin to generate a pretty linkcard with OGP.",
5
+ "keywords": [
6
+ "linkcard",
7
+ "markdown-it",
8
+ "ogp",
9
+ "thumbnail",
10
+ "vitepress",
11
+ "vitepress-plugin"
12
+ ],
9
13
  "bugs": {
10
14
  "url": "https://github.com/asumo-1xts/vitepress-linkcard"
11
15
  },
12
- "description": "A Vitepress plugin to generate a pretty linkcard with OGP.",
16
+ "license": "MIT",
17
+ "author": "aSumo",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/asumo-1xts/vitepress-linkcard.git"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "types"
25
+ ],
26
+ "type": "module",
27
+ "main": "./dist/.esm.min.js",
28
+ "module": "./dist/.esm.min.js",
29
+ "types": "./types/index.d.ts",
30
+ "publishConfig": {
31
+ "registry": "https://registry.npmjs.org/"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc && rollup -c",
35
+ "clean": "rm -rf dist types",
36
+ "dev": "rollup -c -w",
37
+ "docs": "typedoc",
38
+ "format": "oxfmt --write",
39
+ "lint": "oxlint",
40
+ "lint:github": "oxlint --format=github",
41
+ "type:dts": "tsc --emitDeclarationOnly"
42
+ },
13
43
  "devDependencies": {
14
44
  "@babel/core": "^7.28.5",
15
45
  "@babel/preset-env": "^7.28.5",
16
46
  "@babel/preset-typescript": "^7.28.5",
17
- "@eslint/js": "^9.39.2",
18
47
  "@luckrya/utility": "^0.1.1",
19
48
  "@rollup/plugin-babel": "^6.1.0",
20
49
  "@rollup/plugin-commonjs": "^29.0.0",
@@ -22,58 +51,22 @@
22
51
  "@types/babel__core": "^7",
23
52
  "@types/markdown-it": "^13.0.2",
24
53
  "@types/node": "^25.0.3",
25
- "eslint": "^9.39.2",
26
- "eslint-plugin-vue": "^10.6.2",
27
54
  "globals": "^16.5.0",
28
- "jiti": "^2.6.1",
29
55
  "markdown-it": "^13.0.2",
30
- "npm-check-updates": "^19.2.0",
31
- "prettier": "^3.7.4",
56
+ "oxfmt": "^0.26.0",
57
+ "oxlint": "^1.41.0",
32
58
  "rollup": "^2.79.2",
33
59
  "rollup-plugin-terser": "^7.0.2",
34
60
  "typedoc": "^0.28.15",
35
61
  "typedoc-theme-hierarchy": "^6.0.0",
36
62
  "typescript": "^5.9.3",
37
- "typescript-eslint": "^8.50.1",
38
- "vue-eslint-parser": "^10.2.0",
39
63
  "xmlhttprequest": "^1.8.0"
40
64
  },
41
- "files": [
42
- "dist",
43
- "types"
44
- ],
45
- "keywords": [
46
- "thumbnail",
47
- "typescript",
48
- "markdown-it",
49
- "metadata",
50
- "ogp",
51
- "linkcard",
52
- "vite",
53
- "vitepress"
54
- ],
55
- "license": "MIT",
56
- "main": "./dist/.esm.min.js",
57
- "module": "./dist/.esm.min.js",
58
- "name": "vitepress-linkcard",
59
- "packageManager": "yarn@4.9.2",
60
- "publishConfig": {
61
- "registry": "https://registry.npmjs.org/"
62
- },
63
- "repository": {
64
- "type": "git",
65
- "url": "git+https://github.com/asumo-1xts/vitepress-linkcard.git"
66
- },
67
- "scripts": {
68
- "build": "tsc && rollup -c",
69
- "clean": "rm -rf dist types",
70
- "dev": "rollup -c -w",
71
- "docs": "yarn typedoc",
72
- "format": "yarn prettier --config .vscode/.prettierrc.json --write .config/*.json .github/workflows .vscode src *.json && rm -rf node_modules",
73
- "lint": "yarn eslint --config .vscode/eslint.config.ts src/**/*",
74
- "type:dts": "tsc --emitDeclarationOnly"
65
+ "babel": {
66
+ "presets": [
67
+ "@babel/env",
68
+ "@babel/typescript"
69
+ ]
75
70
  },
76
- "type": "module",
77
- "types": "./types/index.d.ts",
78
- "version": "2.0.0"
79
- }
71
+ "packageManager": "yarn@4.9.2"
72
+ }
package/types/api.d.ts CHANGED
@@ -1,53 +1,16 @@
1
1
  import type { UrlMetadata, CardDomRenderOptions } from './types';
2
- /**
3
- * Represents a complete card response with all necessary data for rendering.
4
- * @internal
5
- */
6
2
  interface CardResponse {
7
- /**
8
- * The URL that was fetched.
9
- */
10
3
  url: string;
11
- /**
12
- * Parsed metadata from the URL.
13
- */
14
4
  data: UrlMetadata;
15
- /**
16
- * Rendering options (excluding href which is derived from url).
17
- */
18
5
  options: Omit<CardDomRenderOptions, 'href'>;
19
- /**
20
- * The generated HTML string for the card.
21
- */
22
6
  dom: string;
23
7
  }
24
8
  /**
25
9
  * Generates a link card by fetching and parsing metadata from a URL.
26
10
  *
27
- * This function performs the following operations:
28
- * 1. Fetches the HTML content from the provided URL synchronously
29
- * 2. Parses metadata (title, description, logo) from the HTML
30
- * 3. Generates an HTML card fragment with the metadata
31
- * 4. Caches the result for subsequent calls
32
- *
33
- * The function is primarily used by the link-to-card plugin during markdown processing
34
- * but can also be used standalone for programmatic card generation.
35
- *
36
11
  * @param url - The URL to fetch metadata from
37
- * @param options - Rendering options for the card (excluding href, which is set to the url parameter)
12
+ * @param options - Rendering options for the card
38
13
  * @returns A promise that resolves to a CardResponse containing the card data and HTML
39
- *
40
- * @example
41
- * ```typescript
42
- * const card = await generateCard('https://example.com', {
43
- * linkTitle: 'Example Site',
44
- * target: '_blank'
45
- * })
46
- * console.log(card.dom) // HTML string of the card
47
- * ```
48
- *
49
- * @see {@link parserMetadata} for details on metadata extraction
50
- * @see {@link generateCardDomFragment} for details on card HTML generation
51
14
  */
52
15
  export declare function generateCard(url: string, options: Omit<CardDomRenderOptions, 'href'>): Promise<CardResponse>;
53
16
  export {};
@@ -2,54 +2,8 @@ import type { CardDomRender } from '../types';
2
2
  /**
3
3
  * Generates the HTML DOM fragment for a link card display.
4
4
  *
5
- * This is the default card renderer that creates a rich preview card with:
6
- * - Card title (with 2-line ellipsis)
7
- * - Domain name (with underline)
8
- * - Description (with 2-line ellipsis)
9
- * - Logo/icon image
10
- * - Smooth border transition for hover effects
11
- *
12
- * The function includes special handling for GitHub URLs to improve the display
13
- * of repository cards by cleaning up redundant text patterns.
14
- *
15
- * @param data - The metadata extracted from the URL (title, description, logo)
16
- * @param options - Rendering options including href, target, colors, etc.
17
- * @returns An HTML string containing the complete card markup with inline styles
18
- *
19
- * @example
20
- * ```typescript
21
- * const html = generateCardDomFragment(
22
- * { title: 'Example', description: 'A site', logo: 'https://...' },
23
- * { href: 'https://example.com', linkTitle: 'Link', target: '_blank' }
24
- * )
25
- * ```
26
- *
27
- * @remarks
28
- * - HTML entities in title/description are automatically escaped
29
- * - For GitHub URLs, the title is cleaned to remove "GitHub - " prefix and redundant text
30
- * - The card uses flexbox layout for responsive design
31
- * - All styles are inlined for maximum compatibility
32
- * - Container has class `vitepress-linkcard-container` for custom styling
33
- * - Uses CSS custom properties for theming:
34
- * - `--vitepress-linkcard-border-color`: Customize border color
35
- * - `--vitepress-linkcard-bg-color`: Customize background color
36
- * - Styling options in your VitePress theme's custom CSS:
37
- * ```css
38
- * .vitepress-linkcard-container {
39
- * --vitepress-linkcard-border-color: #e0e0e0;
40
- * --vitepress-linkcard-bg-color: #f9f9f9;
41
- * }
42
- *
43
- * .vitepress-linkcard-container {
44
- * border-color: var(--vp-c-brand-2) !important;
45
- * background-color: var(--vp-c-brand-soft) !important;
46
- * }
47
- *
48
- * .vitepress-linkcard-container:hover {
49
- * border-color: var(--vp-c-brand-1) !important;
50
- * }
51
- * ```
52
- *
53
- * @see {@link STYLE} for the styling implementation
5
+ * @param data - The metadata extracted from the URL
6
+ * @param options - Rendering options including href, target, etc.
7
+ * @returns An HTML string containing the card markup
54
8
  */
55
9
  export declare const generateCardDomFragment: CardDomRender;
@@ -1,116 +1,11 @@
1
- /**
2
- * Local file-based cache implementation for persisting URL metadata.
3
- *
4
- * This module provides a simple key-value cache that persists data to a JSON file
5
- * on disk. It's used to cache fetched URL metadata to avoid redundant network requests
6
- * across different build sessions.
7
- *
8
- * @module local-file-cache
9
- */
10
1
  /**
11
2
  * A simple file-based cache for storing and retrieving structured data.
12
- *
13
- * This class provides a Map-like interface for caching data that persists to disk
14
- * in JSON format. Each cache entry is keyed by URL and stores structured metadata.
15
- *
16
- * The cache file is automatically created if it doesn't exist, and all writes are
17
- * synchronized and formatted for readability.
18
- *
19
- * @template V - The value type, must extend Record<string, unknown>
20
- *
21
- * @example
22
- * ```typescript
23
- * const cache = new LocalFileCache<UrlMetadata>()
24
- *
25
- * // Store metadata
26
- * cache.set('https://example.com', {
27
- * title: 'Example',
28
- * description: 'A site',
29
- * logo: 'https://example.com/logo.png'
30
- * })
31
- *
32
- * // Retrieve metadata
33
- * const metadata = cache.get('https://example.com')
34
- *
35
- * // Check if URL is cached
36
- * if (cache.has('https://example.com')) {
37
- * console.log('URL is cached')
38
- * }
39
- * ```
40
- *
41
- * @remarks
42
- * - Cache is stored in `.linkcard_cache.json` at project root
43
- * - All operations are synchronous
44
- * - Cache persists across process restarts
45
- * - Merges new data with existing cache entries
46
3
  */
47
4
  export default class LocalFileCache<V extends Record<string, unknown>> {
48
5
  constructor();
49
- /**
50
- * Writes data to the cache file.
51
- *
52
- * Merges the provided data with existing cache content and writes the result
53
- * to disk. The file is automatically formatted after writing.
54
- *
55
- * @param data - Object mapping URLs to cached data
56
- *
57
- * @private
58
- */
59
6
  private setFile;
60
- /**
61
- * Reads and parses the cache file.
62
- *
63
- * @returns The parsed cache data, or undefined if the file is empty or invalid
64
- *
65
- * @private
66
- */
67
7
  private readFile;
68
- /**
69
- * Checks if a URL exists in the cache.
70
- *
71
- * @param url - The URL to check
72
- * @returns true if the URL has cached data, false otherwise
73
- *
74
- * @example
75
- * ```typescript
76
- * if (cache.has('https://example.com')) {
77
- * console.log('Cache hit!')
78
- * }
79
- * ```
80
- */
81
8
  has(url: string): boolean;
82
- /**
83
- * Retrieves cached data for a URL.
84
- *
85
- * @param url - The URL to retrieve data for
86
- * @returns The cached data for the URL, or undefined if not found
87
- *
88
- * @example
89
- * ```typescript
90
- * const metadata = cache.get('https://example.com')
91
- * if (metadata) {
92
- * console.log(metadata.title)
93
- * }
94
- * ```
95
- */
96
9
  get(url: string): V | undefined;
97
- /**
98
- * Stores data in the cache for a URL.
99
- *
100
- * Adds or updates the cache entry for the specified URL. The data is merged
101
- * with existing cache content and persisted to disk.
102
- *
103
- * @param url - The URL to cache data for
104
- * @param data - The data to cache
105
- *
106
- * @example
107
- * ```typescript
108
- * cache.set('https://example.com', {
109
- * title: 'Example Domain',
110
- * description: 'Example description',
111
- * logo: 'https://example.com/logo.png'
112
- * })
113
- * ```
114
- */
115
10
  set(url: string, data: V): void;
116
11
  }
@@ -2,28 +2,7 @@ import type { UrlMetadata } from '../types';
2
2
  /**
3
3
  * Retrieves metadata for a given URL, using cache when available.
4
4
  *
5
- * This function first checks if the metadata is already cached. If not, it fetches
6
- * the HTML content from the URL, parses the metadata, and caches the result for
7
- * future use.
8
- *
9
- * The metadata includes:
10
- * - Title (from `<title>` or OGP tags)
11
- * - Description (from meta description or OGP tags)
12
- * - Logo/icon (from OGP image or favicon)
13
- *
14
5
  * @param url - The URL to fetch metadata from
15
- * @returns The parsed URL metadata, or null if the URL cannot be fetched or parsed
16
- *
17
- * @example
18
- * ```typescript
19
- * const metadata = getUrlMetadata('https://example.com')
20
- * if (metadata) {
21
- * console.log(metadata.title) // "Example Domain"
22
- * console.log(metadata.description) // "Example website description"
23
- * }
24
- * ```
25
- *
26
- * @see {@link parserMetadata} for details on metadata extraction
27
- * @see {@link LocalFileCache} for caching implementation
6
+ * @returns The parsed URL metadata, or null if unavailable
28
7
  */
29
8
  export declare function getUrlMetadata(url: string): UrlMetadata | null | undefined;
@@ -1,37 +1,9 @@
1
- /**
2
- * HTML parser module for extracting metadata from web pages.
3
- *
4
- * This module provides functions to parse HTML strings and extract metadata such as
5
- * title, description, and logo/icon URLs. It supports both standard HTML meta tags
6
- * and Open Graph Protocol (OGP) tags.
7
- *
8
- * @module parser
9
- * @todo Refactor to improve maintainability and add support for more meta tag formats
10
- */
11
1
  import type { UrlMetadata } from '../types';
12
2
  /**
13
3
  * Parses HTML string to extract structured metadata for link card generation.
14
4
  *
15
- * This is the main parsing function that extracts title, description, and logo
16
- * from an HTML page. It handles both absolute and relative URLs, converting
17
- * relative logo paths to absolute URLs when necessary.
18
- *
19
5
  * @param htmlString - The HTML content to parse
20
- * @param url - The URL of the page (used to resolve relative logo URLs)
21
- * @returns Parsed metadata object, or null if no valid metadata could be extracted
22
- *
23
- * @example
24
- * ```typescript
25
- * const html = '<title>Example</title><meta name="description" content="Test">'
26
- * const metadata = parserMetadata(html, 'https://example.com')
27
- * // Returns: { title: 'Example', description: 'Test', logo: '...' }
28
- * ```
29
- *
30
- * @remarks
31
- * - Returns null if all metadata fields (title, description, logo) are empty
32
- * - Relative logo URLs are converted to absolute URLs using the page's origin
33
- * - Falls back to a default logo if no logo can be found
34
- *
35
- * @todo Handle protocol-relative URLs like `//img.example.com/logo.png`
6
+ * @param url - The URL of the page
7
+ * @returns Parsed metadata object, or null if no valid metadata found
36
8
  */
37
9
  export declare function parserMetadata(htmlString: string, url: string): UrlMetadata | null;
@@ -1,38 +1,5 @@
1
- /**
2
- * Style generation utilities for link card rendering.
3
- *
4
- * This module provides functions to generate inline CSS styles and class names
5
- * for the link card components. The styles support customizable colors and
6
- * responsive design with text ellipsis for long content.
7
- *
8
- * @module style
9
- */
10
1
  /**
11
2
  * Generates complete inline styles for all link card components.
12
- *
13
- * Creates a set of inline style strings for each part of the link card:
14
- * - Container: main card box with border and background
15
- * - Image: logo/icon display
16
- * - Texts: wrapper for text content
17
- * - Title: card title (2-line ellipsis)
18
- * - Domain: domain name with underline
19
- * - Description: description text (2-line ellipsis)
20
- *
21
- * The styles are inspired by VitePress's VPFeature component design.
22
- *
23
- * The container uses CSS custom properties for theming:
24
- * - `--vitepress-linkcard-border-color`: Border color (default: #7d7d7dff)
25
- * - `--vitepress-linkcard-bg-color`: Background color (default: transparent)
26
- *
27
- * @returns Object containing style attribute strings for each card component
28
- *
29
- * @example
30
- * ```typescript
31
- * const styles = STYLE()
32
- * // Use in HTML: <div ${styles.container}>...</div>
33
- * ```
34
- *
35
- * @see {@link https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/components/VPFeature.vue | VPFeature component}
36
3
  */
37
4
  export declare const STYLE: () => {
38
5
  a: string;
@@ -43,29 +10,6 @@ export declare const STYLE: () => {
43
10
  domain: string;
44
11
  description: string;
45
12
  };
46
- /**
47
- * Generates CSS class names with a custom prefix.
48
- *
49
- * When using the `classPrefix` option, this function creates consistent
50
- * class names for all card components following a BEM-like naming convention.
51
- *
52
- * @param prefix - The prefix to prepend to all class names
53
- * @returns Object mapping component names to their class names
54
- *
55
- * @example
56
- * ```typescript
57
- * const classes = classNames('my-card')
58
- * // Returns: {
59
- * // container: 'my-card__container',
60
- * // title: 'my-card__texts--title',
61
- * // ...
62
- * // }
63
- * ```
64
- *
65
- * @remarks
66
- * When class names are used instead of inline styles, you must provide
67
- * your own CSS definitions for these classes.
68
- */
69
13
  export declare const classNames: (prefix?: string) => {
70
14
  container: string;
71
15
  img: string;
@@ -1,41 +1,14 @@
1
- /**
2
- * URL utility functions for parsing and manipulating URLs.
3
- *
4
- * @module url
5
- */
6
1
  /**
7
2
  * Parses a URL string and returns a URL object.
8
3
  *
9
- * This is a wrapper around the native URL constructor that provides
10
- * a consistent interface for URL parsing throughout the codebase.
11
- *
12
4
  * @param url - The URL string to parse
13
5
  * @returns A URL object containing the parsed components
14
- * @throws {TypeError} If the URL string is invalid
15
- *
16
- * @example
17
- * ```typescript
18
- * const urlObj = extractUrl('https://example.com/path')
19
- * console.log(urlObj.origin) // "https://example.com"
20
- * console.log(urlObj.pathname) // "/path"
21
- * ```
22
- *
23
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/URL | MDN - URL}
24
6
  */
25
7
  export declare function extractUrl(url: string): URL;
26
8
  /**
27
9
  * Removes duplicate consecutive slashes from a path string.
28
10
  *
29
- * This function normalizes paths by replacing multiple consecutive slashes
30
- * with a single slash. Useful for constructing clean URLs from path segments.
31
- *
32
11
  * @param path - The path string to clean
33
12
  * @returns The cleaned path with no consecutive slashes
34
- *
35
- * @example
36
- * ```typescript
37
- * cleanPath('/path//to///file') // Returns: '/path/to/file'
38
- * cleanPath('//images//logo.png') // Returns: '/images/logo.png'
39
- * ```
40
13
  */
41
14
  export declare function cleanPath(path: string): string;
@@ -1,68 +1,14 @@
1
- /**
2
- * XHR module for fetching remote URL content.
3
- *
4
- * This module provides both synchronous and asynchronous HTTP GET request functionality
5
- * with built-in caching. It works in both browser and Node.js environments by using
6
- * the appropriate XMLHttpRequest implementation.
7
- *
8
- * @module xhr
9
- * @todo Replace xmlhttprequest with a modern alternative (e.g., node-fetch or axios)
10
- */
11
1
  /**
12
2
  * Performs a synchronous HTTP GET request to fetch HTML content from a URL.
13
3
  *
14
- * This function fetches the content synchronously, which means it blocks execution
15
- * until the request completes. The response is cached to avoid redundant requests.
16
- *
17
4
  * @param url - The URL to fetch content from
18
5
  * @returns The HTML content as a string, or undefined if the request fails
19
- *
20
- * @example
21
- * ```typescript
22
- * const html = sync('https://example.com')
23
- * if (html) {
24
- * console.log('Fetched HTML content')
25
- * }
26
- * ```
27
- *
28
- * @remarks
29
- * - Returns cached content if available
30
- * - Only returns content if HTTP status is 200
31
- * - Errors are logged to console but not thrown
32
- * - Synchronous requests block the event loop - use with caution
33
- *
34
- * @see {@link async} for an asynchronous alternative
35
6
  */
36
7
  export declare function sync(url: string): string | undefined;
37
8
  /**
38
9
  * Performs an asynchronous HTTP GET request to fetch HTML content from a URL.
39
10
  *
40
- * This function fetches content asynchronously using Promises. The response is
41
- * cached to avoid redundant requests.
42
- *
43
11
  * @param url - The URL to fetch content from
44
- * @returns A Promise that resolves to the HTML content string, or undefined if the request fails
45
- *
46
- * @example
47
- * ```typescript
48
- * async function fetchPage() {
49
- * try {
50
- * const html = await async('https://example.com')
51
- * if (html) {
52
- * console.log('Fetched HTML content')
53
- * }
54
- * } catch (error) {
55
- * console.error('Failed to fetch:', error)
56
- * }
57
- * }
58
- * ```
59
- *
60
- * @remarks
61
- * - Returns cached content if available
62
- * - Only resolves with content if HTTP status is 200 and readyState is 4
63
- * - Promise is rejected if the request throws an error
64
- * - Preferred over `sync()` for non-blocking operations
65
- *
66
- * @see {@link sync} for a synchronous alternative
12
+ * @returns A Promise that resolves to the HTML content string
67
13
  */
68
14
  export declare function async(url: string): Promise<string | undefined>;
@@ -2,30 +2,7 @@ import type { LinkToCardPlugin } from './types';
2
2
  /**
3
3
  * Markdown-it plugin that converts specially-formatted links into rich link preview cards.
4
4
  *
5
- * This plugin intercepts markdown links that start with the `@:` prefix and transforms them
6
- * into interactive cards displaying metadata (title, description, logo) fetched from the target URL.
7
- *
8
- * ## Usage
9
- *
10
- * In your markdown file:
11
- * ```md
12
- * [@:https://example.com](Link Title)
13
- * ```
14
- *
15
- * Plugin configuration:
16
- * ```typescript
17
- * import MarkdownIt from 'markdown-it'
18
- * import { linkToCardPlugin } from 'vitepress-linkcard'
19
- *
20
- * const md = new MarkdownIt()
21
- * md.use(linkToCardPlugin, {
22
- * target: '_blank'
23
- * })
24
- * ```
25
- *
26
5
  * @param md - The markdown-it instance
27
6
  * @param pluginOptions - Configuration options for the plugin
28
- *
29
- * @see {@link LinkToCardPluginOptions} for available options
30
7
  */
31
8
  export declare const linkToCardPlugin: LinkToCardPlugin;