vitepress-linkcard 1.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,47 @@
1
1
  import { isFunction } from '@luckrya/utility';
2
2
  import { getUrlMetadata, generateCardDomFragment } from './assemble';
3
3
  /**
4
- * @param md
5
- * @param pluginOptions
4
+ * Markdown-it plugin that converts specially-formatted links into rich link preview cards.
5
+ *
6
+ * This plugin intercepts markdown links that start with the `@:` prefix and transforms them
7
+ * into interactive cards displaying metadata (title, description, logo) fetched from the target URL.
8
+ *
9
+ * ## Usage
10
+ *
11
+ * In your markdown file:
12
+ * ```md
13
+ * [@:https://example.com](Link Title)
14
+ * ```
15
+ *
16
+ * Plugin configuration:
17
+ * ```typescript
18
+ * import MarkdownIt from 'markdown-it'
19
+ * import { linkToCardPlugin } from 'vitepress-linkcard'
20
+ *
21
+ * const md = new MarkdownIt()
22
+ * md.use(linkToCardPlugin, {
23
+ * target: '_blank'
24
+ * })
25
+ * ```
26
+ *
27
+ * @param md - The markdown-it instance
28
+ * @param pluginOptions - Configuration options for the plugin
29
+ *
30
+ * @see {@link LinkToCardPluginOptions} for available options
6
31
  */
7
32
  export const linkToCardPlugin = (md, pluginOptions = {}) => {
33
+ /**
34
+ * Parses a link href to determine if it's a card link and extracts the URL.
35
+ *
36
+ * Card links are identified by the `@:` prefix (e.g., `@:https://example.com`).
37
+ *
38
+ * @param href - The href attribute from a markdown link token
39
+ * @returns An object containing:
40
+ * - `isCardLink`: true if the href matches the card link pattern
41
+ * - `url`: the extracted URL (without the `@:` prefix)
42
+ *
43
+ * @internal
44
+ */
8
45
  function parseCardLinkHref(href) {
9
46
  const tagRegexp = new RegExp(`^(${'@'}:)([a-zA-Z0-9]+.*)`);
10
47
  const match = href?.match(tagRegexp);
@@ -14,8 +51,21 @@ export const linkToCardPlugin = (md, pluginOptions = {}) => {
14
51
  };
15
52
  }
16
53
  /**
17
- * @param options
18
- * @returns
54
+ * Assembles the HTML template for a link card by fetching metadata and rendering.
55
+ *
56
+ * This function:
57
+ * 1. Fetches URL metadata (title, description, logo)
58
+ * 2. Hides remaining tokens in the link to prevent duplicate content
59
+ * 3. Extracts the link title from tokens
60
+ * 4. Renders the card using either a custom renderer or the default one
61
+ *
62
+ * @param options - Contains the URL and token information
63
+ * @param options.url - The URL to create a card for
64
+ * @param options.tokens - Array of markdown-it tokens
65
+ * @param options.i - Current token index
66
+ * @returns HTML string of the rendered card, or undefined if metadata cannot be fetched
67
+ *
68
+ * @internal
19
69
  */
20
70
  function assembleCardTpl(options) {
21
71
  const urlMetadata = getUrlMetadata(options.url);
@@ -25,9 +75,7 @@ export const linkToCardPlugin = (md, pluginOptions = {}) => {
25
75
  href: options.url,
26
76
  linkTitle: joinLinkTitle(options.tokens),
27
77
  target: pluginOptions.target || '_blank',
28
- classPrefix: pluginOptions.classPrefix,
29
- borderColor: pluginOptions.borderColor,
30
- bgColor: pluginOptions.bgColor
78
+ classPrefix: pluginOptions.classPrefix
31
79
  };
32
80
  return isFunction(pluginOptions.render)
33
81
  ? pluginOptions.render(urlMetadata, cardDomOptions)
@@ -35,11 +83,17 @@ export const linkToCardPlugin = (md, pluginOptions = {}) => {
35
83
  }
36
84
  }
37
85
  /**
38
- * https://markdown-it.github.io/markdown-it/#MarkdownIt.renderInline
39
- * @param tokens
40
- * @param rootOptions
41
- * @param env
42
- * @returns
86
+ * Custom inline renderer that preserves hidden token handling.
87
+ *
88
+ * This overrides the default markdown-it inline renderer to properly handle
89
+ * tokens marked as hidden, which is necessary for the card link processing.
90
+ *
91
+ * @param tokens - Array of tokens to render
92
+ * @param rootOptions - Markdown-it rendering options
93
+ * @param env - Markdown-it environment variables
94
+ * @returns The rendered HTML string
95
+ *
96
+ * @see {@link https://markdown-it.github.io/markdown-it/#MarkdownIt.renderInline | MarkdownIt.renderInline}
43
97
  */
44
98
  md.renderer.renderInline = (tokens, rootOptions, env) => {
45
99
  let result = '';
@@ -59,13 +113,22 @@ export const linkToCardPlugin = (md, pluginOptions = {}) => {
59
113
  return result;
60
114
  };
61
115
  /**
62
- * envは呼ばれなくても消さないこと
63
- * @param tokens
64
- * @param i
65
- * @param rootOptions
66
- * @param env
67
- * @param self
68
- * @returns
116
+ * Custom renderer for link_open tokens that intercepts card links.
117
+ *
118
+ * This function checks if a link is a card link (prefixed with `@:`) and if so,
119
+ * generates and returns the card HTML. Regular links are passed through to the
120
+ * default renderer.
121
+ *
122
+ * @param tokens - Array of tokens being rendered
123
+ * @param i - Current token index
124
+ * @param rootOptions - Markdown-it rendering options
125
+ * @param env - Markdown-it environment (must be present even if unused to maintain signature)
126
+ * @param self - The renderer instance
127
+ * @returns HTML string for the link (either a card or a regular link)
128
+ *
129
+ * @remarks
130
+ * The `env` parameter must not be removed even if unused, as it's part of the
131
+ * markdown-it renderer signature.
69
132
  */
70
133
  md.renderer.rules.link_open = (tokens, i, rootOptions, env, self) => {
71
134
  const token = tokens[i];
@@ -81,9 +144,18 @@ export const linkToCardPlugin = (md, pluginOptions = {}) => {
81
144
  };
82
145
  };
83
146
  /**
84
- * TODO: handle softbreak https://markdown-it.github.io/
85
- * @param tokens
86
- * @param i
147
+ * Marks all tokens except the one at index `i` as hidden.
148
+ *
149
+ * This is used to prevent the link text and closing tag from being rendered
150
+ * when a card link is detected, as the card HTML replaces the entire link element.
151
+ *
152
+ * @param tokens - Array of tokens to modify
153
+ * @param i - Index of the token to keep visible
154
+ *
155
+ * @todo Handle softbreak tokens properly
156
+ * @see {@link https://markdown-it.github.io/ | markdown-it documentation}
157
+ *
158
+ * @internal
87
159
  */
88
160
  function ignoreRestToken(tokens, i) {
89
161
  tokens.forEach((token, index) => {
@@ -92,8 +164,16 @@ function ignoreRestToken(tokens, i) {
92
164
  });
93
165
  }
94
166
  /**
95
- * @param tokens
96
- * @returns
167
+ * Extracts and joins the content from hidden tokens to form the link title.
168
+ *
169
+ * When processing a card link, the link text tokens are marked as hidden.
170
+ * This function collects the content from those hidden tokens to use as the
171
+ * card's title attribute.
172
+ *
173
+ * @param tokens - Array of tokens to extract content from
174
+ * @returns The concatenated content from all hidden tokens
175
+ *
176
+ * @internal
97
177
  */
98
178
  function joinLinkTitle(tokens) {
99
179
  return tokens
package/package.json CHANGED
@@ -22,7 +22,7 @@
22
22
  "@types/babel__core": "^7",
23
23
  "@types/markdown-it": "^13.0.2",
24
24
  "@types/node": "^25.0.3",
25
- "eslint": "npm:9.39.2",
25
+ "eslint": "^9.39.2",
26
26
  "eslint-plugin-vue": "^10.6.2",
27
27
  "globals": "^16.5.0",
28
28
  "jiti": "^2.6.1",
@@ -75,5 +75,5 @@
75
75
  },
76
76
  "type": "module",
77
77
  "types": "./types/index.d.ts",
78
- "version": "1.3.0"
78
+ "version": "2.0.0"
79
79
  }
package/types/api.d.ts CHANGED
@@ -1,14 +1,53 @@
1
1
  import type { UrlMetadata, CardDomRenderOptions } from './types';
2
+ /**
3
+ * Represents a complete card response with all necessary data for rendering.
4
+ * @internal
5
+ */
2
6
  interface CardResponse {
7
+ /**
8
+ * The URL that was fetched.
9
+ */
3
10
  url: string;
11
+ /**
12
+ * Parsed metadata from the URL.
13
+ */
4
14
  data: UrlMetadata;
15
+ /**
16
+ * Rendering options (excluding href which is derived from url).
17
+ */
5
18
  options: Omit<CardDomRenderOptions, 'href'>;
19
+ /**
20
+ * The generated HTML string for the card.
21
+ */
6
22
  dom: string;
7
23
  }
8
24
  /**
9
- * @param url
10
- * @param options
11
- * @returns
25
+ * Generates a link card by fetching and parsing metadata from a URL.
26
+ *
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
+ * @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)
38
+ * @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
12
51
  */
13
52
  export declare function generateCard(url: string, options: Omit<CardDomRenderOptions, 'href'>): Promise<CardResponse>;
14
53
  export {};
@@ -1,7 +1,55 @@
1
1
  import type { CardDomRender } from '../types';
2
2
  /**
3
- * @param data
4
- * @param options
5
- * @returns
3
+ * Generates the HTML DOM fragment for a link card display.
4
+ *
5
+ * This is the default card renderer that creates a rich preview card with:
6
+ * - Card title (with 2-line ellipsis)
7
+ * - Domain name (with underline)
8
+ * - Description (with 2-line ellipsis)
9
+ * - Logo/icon image
10
+ * - Smooth border transition for hover effects
11
+ *
12
+ * The function includes special handling for GitHub URLs to improve the display
13
+ * of repository cards by cleaning up redundant text patterns.
14
+ *
15
+ * @param data - The metadata extracted from the URL (title, description, logo)
16
+ * @param options - Rendering options including href, target, colors, etc.
17
+ * @returns An HTML string containing the complete card markup with inline styles
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const html = generateCardDomFragment(
22
+ * { title: 'Example', description: 'A site', logo: 'https://...' },
23
+ * { href: 'https://example.com', linkTitle: 'Link', target: '_blank' }
24
+ * )
25
+ * ```
26
+ *
27
+ * @remarks
28
+ * - HTML entities in title/description are automatically escaped
29
+ * - For GitHub URLs, the title is cleaned to remove "GitHub - " prefix and redundant text
30
+ * - The card uses flexbox layout for responsive design
31
+ * - All styles are inlined for maximum compatibility
32
+ * - Container has class `vitepress-linkcard-container` for custom styling
33
+ * - Uses CSS custom properties for theming:
34
+ * - `--vitepress-linkcard-border-color`: Customize border color
35
+ * - `--vitepress-linkcard-bg-color`: Customize background color
36
+ * - Styling options in your VitePress theme's custom CSS:
37
+ * ```css
38
+ * .vitepress-linkcard-container {
39
+ * --vitepress-linkcard-border-color: #e0e0e0;
40
+ * --vitepress-linkcard-bg-color: #f9f9f9;
41
+ * }
42
+ *
43
+ * .vitepress-linkcard-container {
44
+ * border-color: var(--vp-c-brand-2) !important;
45
+ * background-color: var(--vp-c-brand-soft) !important;
46
+ * }
47
+ *
48
+ * .vitepress-linkcard-container:hover {
49
+ * border-color: var(--vp-c-brand-1) !important;
50
+ * }
51
+ * ```
52
+ *
53
+ * @see {@link STYLE} for the styling implementation
6
54
  */
7
55
  export declare const generateCardDomFragment: CardDomRender;
@@ -1,26 +1,116 @@
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
+ /**
11
+ * 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
+ */
1
47
  export default class LocalFileCache<V extends Record<string, unknown>> {
2
48
  constructor();
3
49
  /**
4
- * @param data
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
5
58
  */
6
59
  private setFile;
7
60
  /**
8
- * @returns
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
9
66
  */
10
67
  private readFile;
11
68
  /**
12
- * @param url
13
- * @returns
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
+ * ```
14
80
  */
15
81
  has(url: string): boolean;
16
82
  /**
17
- * @param url
18
- * @returns
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
+ * ```
19
95
  */
20
96
  get(url: string): V | undefined;
21
97
  /**
22
- * @param url
23
- * @param data
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
+ * ```
24
114
  */
25
115
  set(url: string, data: V): void;
26
116
  }
@@ -1,6 +1,29 @@
1
1
  import type { UrlMetadata } from '../types';
2
2
  /**
3
- * @param url
4
- * @returns
3
+ * Retrieves metadata for a given URL, using cache when available.
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
+ * @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
5
28
  */
6
29
  export declare function getUrlMetadata(url: string): UrlMetadata | null | undefined;
@@ -1,10 +1,37 @@
1
1
  /**
2
- * TODO: Refactor
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
3
10
  */
4
11
  import type { UrlMetadata } from '../types';
5
12
  /**
6
- * @param htmlString
7
- * @param url
8
- * @returns
13
+ * Parses HTML string to extract structured metadata for link card generation.
14
+ *
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
+ * @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`
9
36
  */
10
37
  export declare function parserMetadata(htmlString: string, url: string): UrlMetadata | null;
@@ -1,10 +1,40 @@
1
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
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
6
9
  */
7
- export declare const STYLE: (borderColor: string, bgColor: string) => {
10
+ /**
11
+ * 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
+ */
37
+ export declare const STYLE: () => {
8
38
  a: string;
9
39
  container: string;
10
40
  img: string;
@@ -14,8 +44,27 @@ export declare const STYLE: (borderColor: string, bgColor: string) => {
14
44
  description: string;
15
45
  };
16
46
  /**
17
- * @param prefix
18
- * @returns
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.
19
68
  */
20
69
  export declare const classNames: (prefix?: string) => {
21
70
  container: string;
@@ -1,10 +1,41 @@
1
1
  /**
2
- * @param url
3
- * @returns
2
+ * URL utility functions for parsing and manipulating URLs.
3
+ *
4
+ * @module url
5
+ */
6
+ /**
7
+ * Parses a URL string and returns a URL object.
8
+ *
9
+ * This is a wrapper around the native URL constructor that provides
10
+ * a consistent interface for URL parsing throughout the codebase.
11
+ *
12
+ * @param url - The URL string to parse
13
+ * @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}
4
24
  */
5
25
  export declare function extractUrl(url: string): URL;
6
26
  /**
7
- * @param path
8
- * @returns
27
+ * Removes duplicate consecutive slashes from a path string.
28
+ *
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
+ * @param path - The path string to clean
33
+ * @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
+ * ```
9
40
  */
10
41
  export declare function cleanPath(path: string): string;