@mnaoumov/typescript-dev-toolkit 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/docs-site/components/ConstructorBlock.astro +16 -0
- package/assets/docs-site/components/ImportStatement.astro +12 -0
- package/assets/docs-site/components/MemberDetail.astro +101 -0
- package/assets/docs-site/components/MethodTable.astro +45 -0
- package/assets/docs-site/components/PropertyTable.astro +45 -0
- package/assets/docs-site/components/SiteTitle.astro +43 -0
- package/assets/docs-site/components/TypeSignature.astro +20 -0
- package/assets/docs-site/fonts/inter-latin-400-normal.ttf +0 -0
- package/assets/docs-site/fonts/inter-latin-700-normal.ttf +0 -0
- package/assets/docs-site/styles/global.css +221 -0
- package/dist/lib/cjs/build.cjs +1 -1
- package/dist/lib/cjs/build.d.cts +1 -1
- package/dist/lib/cjs/commitlint-forbidden-patterns.cjs +2 -2
- package/dist/lib/cjs/commitlint-forbidden-patterns.d.cts +1 -1
- package/dist/lib/cjs/commitlint-spellcheck-header.cjs +2 -2
- package/dist/lib/cjs/commitlint-spellcheck-header.d.cts +1 -1
- package/dist/lib/cjs/docs-site/api-doc-constants.cjs +171 -0
- package/dist/lib/cjs/docs-site/api-doc-constants.d.cts +18 -0
- package/dist/lib/cjs/docs-site/api-doc-jsdoc.cjs +414 -0
- package/dist/lib/cjs/docs-site/api-doc-jsdoc.d.cts +149 -0
- package/dist/lib/cjs/docs-site/api-doc-link-rendering.cjs +377 -0
- package/dist/lib/cjs/docs-site/api-doc-link-rendering.d.cts +185 -0
- package/dist/lib/cjs/docs-site/api-doc-package-sites.cjs +118 -0
- package/dist/lib/cjs/docs-site/api-doc-package-sites.d.cts +36 -0
- package/dist/lib/cjs/docs-site/api-doc-page-generation.cjs +561 -0
- package/dist/lib/cjs/docs-site/api-doc-page-generation.d.cts +159 -0
- package/dist/lib/cjs/docs-site/api-doc-route-segments.cjs +42 -0
- package/dist/lib/cjs/docs-site/api-doc-route-segments.d.cts +25 -0
- package/dist/lib/cjs/docs-site/api-doc-settings.cjs +47 -0
- package/dist/lib/cjs/docs-site/api-doc-settings.d.cts +53 -0
- package/dist/lib/cjs/docs-site/api-doc-source-processing.cjs +288 -0
- package/dist/lib/cjs/docs-site/api-doc-source-processing.d.cts +75 -0
- package/dist/lib/cjs/docs-site/api-doc-text-utils.cjs +281 -0
- package/dist/lib/cjs/docs-site/api-doc-text-utils.d.cts +178 -0
- package/dist/lib/cjs/docs-site/api-doc-type-merging.cjs +157 -0
- package/dist/lib/cjs/docs-site/api-doc-type-merging.d.cts +51 -0
- package/dist/lib/cjs/docs-site/api-doc-types.cjs +22 -0
- package/dist/lib/cjs/docs-site/api-doc-types.d.cts +157 -0
- package/dist/lib/cjs/docs-site/api-docs.cjs +143 -0
- package/dist/lib/cjs/docs-site/api-docs.d.cts +34 -0
- package/dist/lib/cjs/docs-site/astro-config.cjs +169 -0
- package/dist/lib/cjs/docs-site/astro-config.d.cts +23 -0
- package/dist/lib/cjs/docs-site/docs-links.cjs +123 -0
- package/dist/lib/cjs/docs-site/docs-links.d.cts +32 -0
- package/dist/lib/cjs/docs-site/docs-site-assets.cjs +64 -0
- package/dist/lib/cjs/docs-site/docs-site-assets.d.cts +23 -0
- package/dist/lib/cjs/docs-site/docs-site-commands.cjs +72 -0
- package/dist/lib/cjs/docs-site/docs-site-commands.d.cts +29 -0
- package/dist/lib/cjs/docs-site/docs-site-config.cjs +122 -0
- package/dist/lib/cjs/docs-site/docs-site-config.d.cts +162 -0
- package/dist/lib/cjs/docs-site/index.cjs +116 -0
- package/dist/lib/cjs/docs-site/index.d.cts +26 -0
- package/dist/lib/cjs/docs-site/link-check.cjs +197 -0
- package/dist/lib/cjs/docs-site/link-check.d.cts +163 -0
- package/dist/lib/cjs/docs-site/og-image-page.cjs +45 -0
- package/dist/lib/cjs/docs-site/og-image-page.d.cts +15 -0
- package/dist/lib/cjs/docs-site/og-image.cjs +326 -0
- package/dist/lib/cjs/docs-site/og-image.d.cts +70 -0
- package/dist/lib/cjs/docs-site/og-images.cjs +170 -0
- package/dist/lib/cjs/docs-site/og-images.d.cts +41 -0
- package/dist/lib/cjs/docs-site/route-data.cjs +47 -0
- package/dist/lib/cjs/docs-site/route-data.d.cts +14 -0
- package/dist/lib/cjs/docs-site/satteri-github-alerts.cjs +97 -0
- package/dist/lib/cjs/docs-site/satteri-github-alerts.d.cts +31 -0
- package/dist/lib/cjs/docs-site/satteri-relative-links.cjs +87 -0
- package/dist/lib/cjs/docs-site/satteri-relative-links.d.cts +29 -0
- package/dist/lib/cjs/docs-site/unrendered-alerts.cjs +51 -0
- package/dist/lib/cjs/docs-site/unrendered-alerts.d.cts +38 -0
- package/dist/lib/cjs/index.cjs +4 -1
- package/dist/lib/cjs/index.d.cts +1 -0
- package/dist/lib/cjs/library-build.cjs +1 -1
- package/dist/lib/cjs/library-build.d.cts +2 -2
- package/dist/lib/cjs/linters/eslint-config.cjs +17 -17
- package/dist/lib/cjs/linters/eslint-config.d.cts +1 -7
- package/dist/lib/cjs/linters/eslint-rules/in-house-plugin.cjs +2 -2
- package/dist/lib/cjs/linters/eslint-rules/in-house-plugin.d.cts +5 -8
- package/dist/lib/cjs/linters/markdownlint.cjs +4 -1
- package/dist/lib/cjs/package-manager.cjs +2 -2
- package/dist/lib/esm/build.d.mts +1 -1
- package/dist/lib/esm/build.mjs +1 -1
- package/dist/lib/esm/commitlint-forbidden-patterns.d.mts +1 -1
- package/dist/lib/esm/commitlint-forbidden-patterns.mjs +2 -2
- package/dist/lib/esm/commitlint-spellcheck-header.d.mts +1 -1
- package/dist/lib/esm/commitlint-spellcheck-header.mjs +2 -2
- package/dist/lib/esm/docs-site/api-doc-constants.d.mts +18 -0
- package/dist/lib/esm/docs-site/api-doc-constants.mjs +143 -0
- package/dist/lib/esm/docs-site/api-doc-jsdoc.d.mts +149 -0
- package/dist/lib/esm/docs-site/api-doc-jsdoc.mjs +377 -0
- package/dist/lib/esm/docs-site/api-doc-link-rendering.d.mts +185 -0
- package/dist/lib/esm/docs-site/api-doc-link-rendering.mjs +356 -0
- package/dist/lib/esm/docs-site/api-doc-package-sites.d.mts +36 -0
- package/dist/lib/esm/docs-site/api-doc-package-sites.mjs +91 -0
- package/dist/lib/esm/docs-site/api-doc-page-generation.d.mts +159 -0
- package/dist/lib/esm/docs-site/api-doc-page-generation.mjs +548 -0
- package/dist/lib/esm/docs-site/api-doc-route-segments.d.mts +25 -0
- package/dist/lib/esm/docs-site/api-doc-route-segments.mjs +17 -0
- package/dist/lib/esm/docs-site/api-doc-settings.d.mts +53 -0
- package/dist/lib/esm/docs-site/api-doc-settings.mjs +22 -0
- package/dist/lib/esm/docs-site/api-doc-source-processing.d.mts +75 -0
- package/dist/lib/esm/docs-site/api-doc-source-processing.mjs +274 -0
- package/dist/lib/esm/docs-site/api-doc-text-utils.d.mts +178 -0
- package/dist/lib/esm/docs-site/api-doc-text-utils.mjs +239 -0
- package/dist/lib/esm/docs-site/api-doc-type-merging.d.mts +51 -0
- package/dist/lib/esm/docs-site/api-doc-type-merging.mjs +129 -0
- package/dist/lib/esm/docs-site/api-doc-types.d.mts +157 -0
- package/dist/lib/esm/docs-site/api-doc-types.mjs +6 -0
- package/dist/lib/esm/docs-site/api-docs.d.mts +34 -0
- package/dist/lib/esm/docs-site/api-docs.mjs +139 -0
- package/dist/lib/esm/docs-site/astro-config.d.mts +23 -0
- package/dist/lib/esm/docs-site/astro-config.mjs +135 -0
- package/dist/lib/esm/docs-site/docs-links.d.mts +32 -0
- package/dist/lib/esm/docs-site/docs-links.mjs +113 -0
- package/dist/lib/esm/docs-site/docs-site-assets.d.mts +23 -0
- package/dist/lib/esm/docs-site/docs-site-assets.mjs +32 -0
- package/dist/lib/esm/docs-site/docs-site-commands.d.mts +29 -0
- package/dist/lib/esm/docs-site/docs-site-commands.mjs +46 -0
- package/dist/lib/esm/docs-site/docs-site-config.d.mts +162 -0
- package/dist/lib/esm/docs-site/docs-site-config.mjs +98 -0
- package/dist/lib/esm/docs-site/index.d.mts +26 -0
- package/dist/lib/esm/docs-site/index.mjs +58 -0
- package/dist/lib/esm/docs-site/link-check.d.mts +163 -0
- package/dist/lib/esm/docs-site/link-check.mjs +166 -0
- package/dist/lib/esm/docs-site/og-image-page.d.mts +15 -0
- package/dist/lib/esm/docs-site/og-image-page.mjs +21 -0
- package/dist/lib/esm/docs-site/og-image.d.mts +70 -0
- package/dist/lib/esm/docs-site/og-image.mjs +292 -0
- package/dist/lib/esm/docs-site/og-images.d.mts +41 -0
- package/dist/lib/esm/docs-site/og-images.mjs +156 -0
- package/dist/lib/esm/docs-site/route-data.d.mts +14 -0
- package/dist/lib/esm/docs-site/route-data.mjs +23 -0
- package/dist/lib/esm/docs-site/satteri-github-alerts.d.mts +31 -0
- package/dist/lib/esm/docs-site/satteri-github-alerts.mjs +72 -0
- package/dist/lib/esm/docs-site/satteri-relative-links.d.mts +29 -0
- package/dist/lib/esm/docs-site/satteri-relative-links.mjs +63 -0
- package/dist/lib/esm/docs-site/unrendered-alerts.d.mts +38 -0
- package/dist/lib/esm/docs-site/unrendered-alerts.mjs +26 -0
- package/dist/lib/esm/index.d.mts +1 -0
- package/dist/lib/esm/index.mjs +3 -1
- package/dist/lib/esm/library-build.d.mts +2 -2
- package/dist/lib/esm/library-build.mjs +1 -1
- package/dist/lib/esm/linters/eslint-config.d.mts +1 -7
- package/dist/lib/esm/linters/eslint-config.mjs +17 -17
- package/dist/lib/esm/linters/eslint-rules/in-house-plugin.d.mts +5 -8
- package/dist/lib/esm/linters/eslint-rules/in-house-plugin.mjs +2 -2
- package/dist/lib/esm/linters/markdownlint.mjs +4 -1
- package/dist/lib/esm/package-manager.mjs +2 -2
- package/docs-site/api-doc-constants/package.json +6 -0
- package/docs-site/api-doc-jsdoc/package.json +6 -0
- package/docs-site/api-doc-link-rendering/package.json +6 -0
- package/docs-site/api-doc-package-sites/package.json +6 -0
- package/docs-site/api-doc-page-generation/package.json +6 -0
- package/docs-site/api-doc-route-segments/package.json +6 -0
- package/docs-site/api-doc-settings/package.json +6 -0
- package/docs-site/api-doc-source-processing/package.json +6 -0
- package/docs-site/api-doc-text-utils/package.json +6 -0
- package/docs-site/api-doc-type-merging/package.json +6 -0
- package/docs-site/api-doc-types/package.json +6 -0
- package/docs-site/api-docs/package.json +6 -0
- package/docs-site/astro-config/package.json +6 -0
- package/docs-site/docs-links/package.json +6 -0
- package/docs-site/docs-site-assets/package.json +6 -0
- package/docs-site/docs-site-commands/package.json +6 -0
- package/docs-site/docs-site-config/package.json +6 -0
- package/docs-site/index/package.json +6 -0
- package/docs-site/link-check/package.json +6 -0
- package/docs-site/og-image/package.json +6 -0
- package/docs-site/og-image-page/package.json +6 -0
- package/docs-site/og-images/package.json +6 -0
- package/docs-site/package.json +6 -0
- package/docs-site/route-data/package.json +6 -0
- package/docs-site/satteri-github-alerts/package.json +6 -0
- package/docs-site/satteri-relative-links/package.json +6 -0
- package/docs-site/unrendered-alerts/package.json +6 -0
- package/package.json +74 -4
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/// <reference path="../library-references.d.mts" />
|
|
2
|
+
/// <reference lib="dom" />
|
|
3
|
+
/**
|
|
4
|
+
* @file
|
|
5
|
+
*
|
|
6
|
+
* Validation of the links emitted by the built documentation HTML.
|
|
7
|
+
*
|
|
8
|
+
* Internal (same-site) links are validated offline: every `href`/`src` must resolve to a real
|
|
9
|
+
* file in the build output, and every `#fragment` must resolve to a real element id on the
|
|
10
|
+
* target page.
|
|
11
|
+
*
|
|
12
|
+
* External links can only be validated over the network, so those requests are heavily
|
|
13
|
+
* deduplicated — each unique external URL is fetched at most once regardless of how many of the
|
|
14
|
+
* thousands of generated pages reference it — and run through a bounded concurrency pool.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* The {@link BrokenLink.httpStatus} sentinel for a network-level failure (timeout, DNS,
|
|
18
|
+
* connection refused) where no HTTP response was received.
|
|
19
|
+
*/
|
|
20
|
+
export declare const NETWORK_FAILURE_STATUS = 0;
|
|
21
|
+
/**
|
|
22
|
+
* A single link that does not resolve.
|
|
23
|
+
*/
|
|
24
|
+
export interface BrokenLink {
|
|
25
|
+
/**
|
|
26
|
+
* The HTTP status returned by an external link, when {@link BrokenLink.reason} is
|
|
27
|
+
* `external-error`. `0` denotes a network-level failure (timeout, DNS, connection refused).
|
|
28
|
+
*/
|
|
29
|
+
httpStatus?: number;
|
|
30
|
+
/**
|
|
31
|
+
* The absolute URL of the page that contains the broken link.
|
|
32
|
+
*/
|
|
33
|
+
pageUrl: string;
|
|
34
|
+
/**
|
|
35
|
+
* Why the link is considered broken.
|
|
36
|
+
*/
|
|
37
|
+
reason: 'external-error' | 'missing-fragment' | 'missing-page';
|
|
38
|
+
/**
|
|
39
|
+
* The resolved absolute URL the link points at.
|
|
40
|
+
*/
|
|
41
|
+
targetUrl: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A single built documentation page to validate.
|
|
45
|
+
*/
|
|
46
|
+
export interface DocumentationPage {
|
|
47
|
+
/**
|
|
48
|
+
* The page's rendered HTML.
|
|
49
|
+
*/
|
|
50
|
+
html: string;
|
|
51
|
+
/**
|
|
52
|
+
* The page's path relative to the build-output root, e.g. `api/foo/index.html`.
|
|
53
|
+
*/
|
|
54
|
+
relativePath: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Filesystem access the link checker needs, injected so the pure decision logic can be tested
|
|
58
|
+
* against an in-memory stub instead of a real build output.
|
|
59
|
+
*/
|
|
60
|
+
export interface LinkCheckFileSystem {
|
|
61
|
+
/**
|
|
62
|
+
* Reads the element ids present on an already-resolved page.
|
|
63
|
+
*
|
|
64
|
+
* @param pageKey - The key returned by {@link LinkCheckFileSystem.resolveExistingPage}.
|
|
65
|
+
* @returns The set of element ids on that page.
|
|
66
|
+
*/
|
|
67
|
+
readIds: (pageKey: string) => Set<string>;
|
|
68
|
+
/**
|
|
69
|
+
* Resolves an output-relative path to an existing page.
|
|
70
|
+
*
|
|
71
|
+
* @param outputRelativePath - The decoded path relative to the build-output root.
|
|
72
|
+
* @returns A stable key (e.g. the resolved absolute file path) for the existing page, or
|
|
73
|
+
* `null` when nothing exists at that path or the path escapes the build-output root.
|
|
74
|
+
*/
|
|
75
|
+
resolveExistingPage: (outputRelativePath: string) => null | string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validates the deduplicated external URLs over the network through a bounded concurrency pool.
|
|
79
|
+
*
|
|
80
|
+
* @param targets - The unique external URL → referencing page map from {@link collectExternalTargets}.
|
|
81
|
+
* @param fetchUrlStatus - Injected probe returning the HTTP status for a URL (`0` for a network failure).
|
|
82
|
+
* @param concurrency - The maximum number of in-flight probes.
|
|
83
|
+
* @returns Every external URL that did not return HTTP `200`, in the map's iteration order.
|
|
84
|
+
*/
|
|
85
|
+
export declare function collectBrokenExternalLinks(targets: Map<string, string>, fetchUrlStatus: (url: string) => Promise<number>, concurrency: number): Promise<BrokenLink[]>;
|
|
86
|
+
/**
|
|
87
|
+
* Finds every internal link across the built documentation pages that does not resolve.
|
|
88
|
+
*
|
|
89
|
+
* External and non-HTTP links are ignored. Each internal link must resolve to an existing page,
|
|
90
|
+
* and each `#fragment` must resolve to an existing element id on the target page.
|
|
91
|
+
*
|
|
92
|
+
* @param pages - The built documentation pages to validate.
|
|
93
|
+
* @param fileSystem - Injected access to the build output.
|
|
94
|
+
* @param siteBaseUrl - The absolute base URL the site is served from (with a trailing slash).
|
|
95
|
+
* @returns Every broken internal link, in page-then-document order.
|
|
96
|
+
*/
|
|
97
|
+
export declare function collectBrokenLinks(pages: DocumentationPage[], fileSystem: LinkCheckFileSystem, siteBaseUrl: string): BrokenLink[];
|
|
98
|
+
/**
|
|
99
|
+
* Collects every unique external URL referenced across the built pages, deduplicated.
|
|
100
|
+
*
|
|
101
|
+
* Only HTTP(S) links that are not {@link isInternalDocUrl} are returned. Each unique URL maps to
|
|
102
|
+
* the first page that referenced it, so a later failure can be reported with a concrete example
|
|
103
|
+
* page even though the URL is fetched only once.
|
|
104
|
+
*
|
|
105
|
+
* @param pages - The built documentation pages to scan.
|
|
106
|
+
* @param siteBaseUrl - The absolute base URL the site is served from (with a trailing slash).
|
|
107
|
+
* @returns A map from each unique external URL to one referencing page URL.
|
|
108
|
+
*/
|
|
109
|
+
export declare function collectExternalTargets(pages: DocumentationPage[], siteBaseUrl: string): Map<string, string>;
|
|
110
|
+
/**
|
|
111
|
+
* Extracts the values of every `id` attribute in a chunk of HTML.
|
|
112
|
+
*
|
|
113
|
+
* @param html - The HTML to scan.
|
|
114
|
+
* @returns The set of element ids.
|
|
115
|
+
*/
|
|
116
|
+
export declare function extractIds(html: string): Set<string>;
|
|
117
|
+
/**
|
|
118
|
+
* Extracts the values of every `href`/`src` attribute in a chunk of HTML.
|
|
119
|
+
*
|
|
120
|
+
* @param html - The HTML to scan.
|
|
121
|
+
* @returns The raw link values, in document order (duplicates preserved).
|
|
122
|
+
*/
|
|
123
|
+
export declare function extractLinks(html: string): string[];
|
|
124
|
+
/**
|
|
125
|
+
* Formats broken links into a human-readable multi-line report.
|
|
126
|
+
*
|
|
127
|
+
* @param brokenLinks - The broken links to describe.
|
|
128
|
+
* @returns One line per broken link.
|
|
129
|
+
*/
|
|
130
|
+
export declare function formatBrokenLinks(brokenLinks: BrokenLink[]): string;
|
|
131
|
+
/**
|
|
132
|
+
* Computes the build-output-relative path for an internal documentation URL.
|
|
133
|
+
*
|
|
134
|
+
* @param targetUrl - The resolved absolute link URL (must be {@link isInternalDocUrl}).
|
|
135
|
+
* @param siteBaseUrl - The absolute base URL the site is served from (with a trailing slash).
|
|
136
|
+
* @returns The decoded path relative to the build-output root.
|
|
137
|
+
*/
|
|
138
|
+
export declare function getOutputRelativePath(targetUrl: URL, siteBaseUrl: string): string;
|
|
139
|
+
/**
|
|
140
|
+
* Computes the absolute URL a built page is served at.
|
|
141
|
+
*
|
|
142
|
+
* @param relativePath - The page's path relative to the build-output root.
|
|
143
|
+
* @param siteBaseUrl - The absolute base URL the site is served from (with a trailing slash).
|
|
144
|
+
* @returns The page's absolute URL.
|
|
145
|
+
*/
|
|
146
|
+
export declare function getPageUrl(relativePath: string, siteBaseUrl: string): string;
|
|
147
|
+
/**
|
|
148
|
+
* Determines whether a resolved link points at a page hosted by this documentation site.
|
|
149
|
+
*
|
|
150
|
+
* @param targetUrl - The resolved absolute link URL.
|
|
151
|
+
* @param siteBaseUrl - The absolute base URL the site is served from (with a trailing slash).
|
|
152
|
+
* @returns `true` when the link is same-origin and under the site base path.
|
|
153
|
+
*/
|
|
154
|
+
export declare function isInternalDocUrl(targetUrl: URL, siteBaseUrl: string): boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Resolves an output-relative path to an absolute path inside the build-output root, rejecting
|
|
157
|
+
* paths that escape it via `..` segments.
|
|
158
|
+
*
|
|
159
|
+
* @param outputRootPath - The absolute build-output root path.
|
|
160
|
+
* @param outputRelativePath - The decoded output-relative path.
|
|
161
|
+
* @returns The joined path when it stays within the root, otherwise `null`.
|
|
162
|
+
*/
|
|
163
|
+
export declare function resolveWithinRoot(outputRootPath: string, outputRelativePath: string): null | string;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/*
|
|
2
|
+
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
3
|
+
if you want to view the source, please visit the github repository of this plugin
|
|
4
|
+
*/
|
|
5
|
+
(function () {
|
|
6
|
+
function ensureBrowserProcess() {
|
|
7
|
+
const browserProcess = {
|
|
8
|
+
browser: true,
|
|
9
|
+
cwd() {
|
|
10
|
+
return '/';
|
|
11
|
+
},
|
|
12
|
+
env: {},
|
|
13
|
+
platform: 'android'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const existingProcess = globalThis.process;
|
|
17
|
+
|
|
18
|
+
if (!existingProcess) {
|
|
19
|
+
globalThis.process = browserProcess;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (existingProcess.versions?.node) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const existingProcessRecord = existingProcess;
|
|
28
|
+
|
|
29
|
+
for (const [key, value] of Object.entries(browserProcess)) {
|
|
30
|
+
existingProcessRecord[key] ??= value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
existingProcessRecord['browser'] = true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
ensureBrowserProcess();
|
|
37
|
+
})();
|
|
38
|
+
|
|
39
|
+
import { getMandatoryNamedGroup } from "@mnaoumov/typescript-lib/reg-exp";
|
|
40
|
+
import {
|
|
41
|
+
assertNever,
|
|
42
|
+
ensureNonNullable
|
|
43
|
+
} from "@mnaoumov/typescript-lib/type-guards";
|
|
44
|
+
import { normalize } from "node:path/posix";
|
|
45
|
+
const LINK_ATTRIBUTE_REGEX = /\b(?:href|src)=(?<quote>['"])(?<value>.*?)\k<quote>/giu;
|
|
46
|
+
const ID_ATTRIBUTE_REGEX = /\bid=(?<quote>['"])(?<value>.*?)\k<quote>/giu;
|
|
47
|
+
const HTTP_OK_STATUS = 200;
|
|
48
|
+
const NETWORK_FAILURE_STATUS = 0;
|
|
49
|
+
async function collectBrokenExternalLinks(targets, fetchUrlStatus, concurrency) {
|
|
50
|
+
const entries = [...targets];
|
|
51
|
+
const results = Array.from({ length: entries.length }, () => null);
|
|
52
|
+
let nextIndex = 0;
|
|
53
|
+
async function runWorker() {
|
|
54
|
+
for (let index = nextIndex++; index < entries.length; index = nextIndex++) {
|
|
55
|
+
const [externalUrl, pageUrl] = ensureNonNullable(entries[index]);
|
|
56
|
+
const httpStatus = await fetchUrlStatus(externalUrl);
|
|
57
|
+
if (httpStatus !== HTTP_OK_STATUS) {
|
|
58
|
+
results[index] = { httpStatus, pageUrl, reason: "external-error", targetUrl: externalUrl };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const workerCount = Math.max(1, Math.min(concurrency, entries.length));
|
|
63
|
+
await Promise.all(Array.from({ length: workerCount }, () => runWorker()));
|
|
64
|
+
return results.filter((brokenLink) => brokenLink !== null);
|
|
65
|
+
}
|
|
66
|
+
function collectBrokenLinks(pages, fileSystem, siteBaseUrl) {
|
|
67
|
+
const brokenLinks = [];
|
|
68
|
+
for (const page of pages) {
|
|
69
|
+
const pageUrl = getPageUrl(page.relativePath, siteBaseUrl);
|
|
70
|
+
for (const rawLink of extractLinks(page.html)) {
|
|
71
|
+
const targetUrl = new URL(rawLink, pageUrl);
|
|
72
|
+
if (!isInternalDocUrl(targetUrl, siteBaseUrl)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const pageKey = fileSystem.resolveExistingPage(getOutputRelativePath(targetUrl, siteBaseUrl));
|
|
76
|
+
if (pageKey === null) {
|
|
77
|
+
brokenLinks.push({ pageUrl, reason: "missing-page", targetUrl: targetUrl.href });
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const fragment = targetUrl.hash.slice(1);
|
|
81
|
+
if (fragment.length > 0 && !fileSystem.readIds(pageKey).has(fragment)) {
|
|
82
|
+
brokenLinks.push({ pageUrl, reason: "missing-fragment", targetUrl: targetUrl.href });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return brokenLinks;
|
|
87
|
+
}
|
|
88
|
+
function collectExternalTargets(pages, siteBaseUrl) {
|
|
89
|
+
const targets = /* @__PURE__ */ new Map();
|
|
90
|
+
for (const page of pages) {
|
|
91
|
+
const pageUrl = getPageUrl(page.relativePath, siteBaseUrl);
|
|
92
|
+
for (const rawLink of extractLinks(page.html)) {
|
|
93
|
+
const targetUrl = new URL(rawLink, pageUrl);
|
|
94
|
+
if (targetUrl.protocol !== "http:" && targetUrl.protocol !== "https:" || isInternalDocUrl(targetUrl, siteBaseUrl)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const externalUrl = `${targetUrl.origin}${targetUrl.pathname}${targetUrl.search}`;
|
|
98
|
+
if (!targets.has(externalUrl)) {
|
|
99
|
+
targets.set(externalUrl, pageUrl);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return targets;
|
|
104
|
+
}
|
|
105
|
+
function extractIds(html) {
|
|
106
|
+
return new Set([...html.matchAll(ID_ATTRIBUTE_REGEX)].map((match) => getMandatoryNamedGroup(match, "value")));
|
|
107
|
+
}
|
|
108
|
+
function extractLinks(html) {
|
|
109
|
+
return [...html.matchAll(LINK_ATTRIBUTE_REGEX)].map((match) => getMandatoryNamedGroup(match, "value"));
|
|
110
|
+
}
|
|
111
|
+
function formatBrokenLinks(brokenLinks) {
|
|
112
|
+
return brokenLinks.map((brokenLink) => {
|
|
113
|
+
switch (brokenLink.reason) {
|
|
114
|
+
case "external-error": {
|
|
115
|
+
return `${brokenLink.pageUrl} links to external URL ${brokenLink.targetUrl} that returned ${describeHttpStatus(brokenLink.httpStatus)}.`;
|
|
116
|
+
}
|
|
117
|
+
case "missing-fragment": {
|
|
118
|
+
return `${brokenLink.pageUrl} links to missing fragment ${brokenLink.targetUrl}.`;
|
|
119
|
+
}
|
|
120
|
+
case "missing-page": {
|
|
121
|
+
return `${brokenLink.pageUrl} links to missing page ${brokenLink.targetUrl}.`;
|
|
122
|
+
}
|
|
123
|
+
default: {
|
|
124
|
+
return assertNever(brokenLink.reason);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}).join("\n");
|
|
128
|
+
}
|
|
129
|
+
function getOutputRelativePath(targetUrl, siteBaseUrl) {
|
|
130
|
+
const base = new URL(siteBaseUrl);
|
|
131
|
+
return decodeURIComponent(targetUrl.pathname.slice(base.pathname.length));
|
|
132
|
+
}
|
|
133
|
+
function getPageUrl(relativePath, siteBaseUrl) {
|
|
134
|
+
const normalized = relativePath.replaceAll("\\", "/");
|
|
135
|
+
const urlPath = normalized === "index.html" ? "" : normalized.replace(/index\.html$/u, "");
|
|
136
|
+
return new URL(urlPath, siteBaseUrl).href;
|
|
137
|
+
}
|
|
138
|
+
function isInternalDocUrl(targetUrl, siteBaseUrl) {
|
|
139
|
+
const base = new URL(siteBaseUrl);
|
|
140
|
+
return targetUrl.origin === base.origin && targetUrl.pathname.startsWith(base.pathname);
|
|
141
|
+
}
|
|
142
|
+
function resolveWithinRoot(outputRootPath, outputRelativePath) {
|
|
143
|
+
const root = normalize(outputRootPath.replaceAll("\\", "/")).replace(/\/$/u, "");
|
|
144
|
+
let joined = normalize(`${root}/${outputRelativePath.replaceAll("\\", "/")}`);
|
|
145
|
+
if (joined.length > 1) {
|
|
146
|
+
joined = joined.replace(/\/$/u, "");
|
|
147
|
+
}
|
|
148
|
+
return joined !== root && !joined.startsWith(`${root}/`) ? null : joined;
|
|
149
|
+
}
|
|
150
|
+
function describeHttpStatus(httpStatus) {
|
|
151
|
+
return httpStatus === void 0 || httpStatus === NETWORK_FAILURE_STATUS ? "a network failure" : `HTTP ${String(httpStatus)}`;
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
NETWORK_FAILURE_STATUS,
|
|
155
|
+
collectBrokenExternalLinks,
|
|
156
|
+
collectBrokenLinks,
|
|
157
|
+
collectExternalTargets,
|
|
158
|
+
extractIds,
|
|
159
|
+
extractLinks,
|
|
160
|
+
formatBrokenLinks,
|
|
161
|
+
getOutputRelativePath,
|
|
162
|
+
getPageUrl,
|
|
163
|
+
isInternalDocUrl,
|
|
164
|
+
resolveWithinRoot
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9kb2NzLXNpdGUvbGluay1jaGVjay50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBmaWxlXG4gKlxuICogVmFsaWRhdGlvbiBvZiB0aGUgbGlua3MgZW1pdHRlZCBieSB0aGUgYnVpbHQgZG9jdW1lbnRhdGlvbiBIVE1MLlxuICpcbiAqIEludGVybmFsIChzYW1lLXNpdGUpIGxpbmtzIGFyZSB2YWxpZGF0ZWQgb2ZmbGluZTogZXZlcnkgYGhyZWZgL2BzcmNgIG11c3QgcmVzb2x2ZSB0byBhIHJlYWxcbiAqIGZpbGUgaW4gdGhlIGJ1aWxkIG91dHB1dCwgYW5kIGV2ZXJ5IGAjZnJhZ21lbnRgIG11c3QgcmVzb2x2ZSB0byBhIHJlYWwgZWxlbWVudCBpZCBvbiB0aGVcbiAqIHRhcmdldCBwYWdlLlxuICpcbiAqIEV4dGVybmFsIGxpbmtzIGNhbiBvbmx5IGJlIHZhbGlkYXRlZCBvdmVyIHRoZSBuZXR3b3JrLCBzbyB0aG9zZSByZXF1ZXN0cyBhcmUgaGVhdmlseVxuICogZGVkdXBsaWNhdGVkIOKAlCBlYWNoIHVuaXF1ZSBleHRlcm5hbCBVUkwgaXMgZmV0Y2hlZCBhdCBtb3N0IG9uY2UgcmVnYXJkbGVzcyBvZiBob3cgbWFueSBvZiB0aGVcbiAqIHRob3VzYW5kcyBvZiBnZW5lcmF0ZWQgcGFnZXMgcmVmZXJlbmNlIGl0IOKAlCBhbmQgcnVuIHRocm91Z2ggYSBib3VuZGVkIGNvbmN1cnJlbmN5IHBvb2wuXG4gKi9cblxuaW1wb3J0IHsgZ2V0TWFuZGF0b3J5TmFtZWRHcm91cCB9IGZyb20gJ0BtbmFvdW1vdi90eXBlc2NyaXB0LWxpYi9yZWctZXhwJztcbmltcG9ydCB7XG4gIGFzc2VydE5ldmVyLFxuICBlbnN1cmVOb25OdWxsYWJsZVxufSBmcm9tICdAbW5hb3Vtb3YvdHlwZXNjcmlwdC1saWIvdHlwZS1ndWFyZHMnO1xuaW1wb3J0IHsgbm9ybWFsaXplIH0gZnJvbSAnbm9kZTpwYXRoL3Bvc2l4JztcblxuY29uc3QgTElOS19BVFRSSUJVVEVfUkVHRVggPSAvXFxiKD86aHJlZnxzcmMpPSg/PHF1b3RlPlsnXCJdKSg/PHZhbHVlPi4qPylcXGs8cXVvdGU+L2dpdTtcbmNvbnN0IElEX0FUVFJJQlVURV9SRUdFWCA9IC9cXGJpZD0oPzxxdW90ZT5bJ1wiXSkoPzx2YWx1ZT4uKj8pXFxrPHF1b3RlPi9naXU7XG5jb25zdCBIVFRQX09LX1NUQVRVUyA9IDIwMDtcblxuLyoqXG4gKiBUaGUge0BsaW5rIEJyb2tlbkxpbmsuaHR0cFN0YXR1c30gc2VudGluZWwgZm9yIGEgbmV0d29yay1sZXZlbCBmYWlsdXJlICh0aW1lb3V0LCBETlMsXG4gKiBjb25uZWN0aW9uIHJlZnVzZWQpIHdoZXJlIG5vIEhUVFAgcmVzcG9uc2Ugd2FzIHJlY2VpdmVkLlxuICovXG5leHBvcnQgY29uc3QgTkVUV09SS19GQUlMVVJFX1NUQVRVUyA9IDA7XG5cbi8qKlxuICogQSBzaW5nbGUgbGluayB0aGF0IGRvZXMgbm90IHJlc29sdmUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQnJva2VuTGluayB7XG4gIC8qKlxuICAgKiBUaGUgSFRUUCBzdGF0dXMgcmV0dXJuZWQgYnkgYW4gZXh0ZXJuYWwgbGluaywgd2hlbiB7QGxpbmsgQnJva2VuTGluay5yZWFzb259IGlzXG4gICAqIGBleHRlcm5hbC1lcnJvcmAuIGAwYCBkZW5vdGVzIGEgbmV0d29yay1sZXZlbCBmYWlsdXJlICh0aW1lb3V0LCBETlMsIGNvbm5lY3Rpb24gcmVmdXNlZCkuXG4gICAqL1xuICBodHRwU3RhdHVzPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgYWJzb2x1dGUgVVJMIG9mIHRoZSBwYWdlIHRoYXQgY29udGFpbnMgdGhlIGJyb2tlbiBsaW5rLlxuICAgKi9cbiAgcGFnZVVybDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaHkgdGhlIGxpbmsgaXMgY29uc2lkZXJlZCBicm9rZW4uXG4gICAqL1xuICByZWFzb246ICdleHRlcm5hbC1lcnJvcicgfCAnbWlzc2luZy1mcmFnbWVudCcgfCAnbWlzc2luZy1wYWdlJztcblxuICAvKipcbiAgICogVGhlIHJlc29sdmVkIGFic29sdXRlIFVSTCB0aGUgbGluayBwb2ludHMgYXQuXG4gICAqL1xuICB0YXJnZXRVcmw6IHN0cmluZztcbn1cblxuLyoqXG4gKiBBIHNpbmdsZSBidWlsdCBkb2N1bWVudGF0aW9uIHBhZ2UgdG8gdmFsaWRhdGUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRG9jdW1lbnRhdGlvblBhZ2Uge1xuICAvKipcbiAgICogVGhlIHBhZ2UncyByZW5kZXJlZCBIVE1MLlxuICAgKi9cbiAgaHRtbDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgcGFnZSdzIHBhdGggcmVsYXRpdmUgdG8gdGhlIGJ1aWxkLW91dHB1dCByb290LCBlLmcuIGBhcGkvZm9vL2luZGV4Lmh0bWxgLlxuICAgKi9cbiAgcmVsYXRpdmVQYXRoOiBzdHJpbmc7XG59XG5cbi8qKlxuICogRmlsZXN5c3RlbSBhY2Nlc3MgdGhlIGxpbmsgY2hlY2tlciBuZWVkcywgaW5qZWN0ZWQgc28gdGhlIHB1cmUgZGVjaXNpb24gbG9naWMgY2FuIGJlIHRlc3RlZFxuICogYWdhaW5zdCBhbiBpbi1tZW1vcnkgc3R1YiBpbnN0ZWFkIG9mIGEgcmVhbCBidWlsZCBvdXRwdXQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGlua0NoZWNrRmlsZVN5c3RlbSB7XG4gIC8qKlxuICAgKiBSZWFkcyB0aGUgZWxlbWVudCBpZHMgcHJlc2VudCBvbiBhbiBhbHJlYWR5LXJlc29sdmVkIHBhZ2UuXG4gICAqXG4gICAqIEBwYXJhbSBwYWdlS2V5IC0gVGhlIGtleSByZXR1cm5lZCBieSB7QGxpbmsgTGlua0NoZWNrRmlsZVN5c3RlbS5yZXNvbHZlRXhpc3RpbmdQYWdlfS5cbiAgICogQHJldHVybnMgVGhlIHNldCBvZiBlbGVtZW50IGlkcyBvbiB0aGF0IHBhZ2UuXG4gICAqL1xuICByZWFkSWRzOiAocGFnZUtleTogc3RyaW5nKSA9PiBTZXQ8c3RyaW5nPjtcblxuICAvKipcbiAgICogUmVzb2x2ZXMgYW4gb3V0cHV0LXJlbGF0aXZlIHBhdGggdG8gYW4gZXhpc3RpbmcgcGFnZS5cbiAgICpcbiAgICogQHBhcmFtIG91dHB1dFJlbGF0aXZlUGF0aCAtIFRoZSBkZWNvZGVkIHBhdGggcmVsYXRpdmUgdG8gdGhlIGJ1aWxkLW91dHB1dCByb290LlxuICAgKiBAcmV0dXJucyBBIHN0YWJsZSBrZXkgKGUuZy4gdGhlIHJlc29sdmVkIGFic29sdXRlIGZpbGUgcGF0aCkgZm9yIHRoZSBleGlzdGluZyBwYWdlLCBvclxuICAgKiAgIGBudWxsYCB3aGVuIG5vdGhpbmcgZXhpc3RzIGF0IHRoYXQgcGF0aCBvciB0aGUgcGF0aCBlc2NhcGVzIHRoZSBidWlsZC1vdXRwdXQgcm9vdC5cbiAgICovXG4gIHJlc29sdmVFeGlzdGluZ1BhZ2U6IChvdXRwdXRSZWxhdGl2ZVBhdGg6IHN0cmluZykgPT4gbnVsbCB8IHN0cmluZztcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgdGhlIGRlZHVwbGljYXRlZCBleHRlcm5hbCBVUkxzIG92ZXIgdGhlIG5ldHdvcmsgdGhyb3VnaCBhIGJvdW5kZWQgY29uY3VycmVuY3kgcG9vbC5cbiAqXG4gKiBAcGFyYW0gdGFyZ2V0cyAtIFRoZSB1bmlxdWUgZXh0ZXJuYWwgVVJMIOKGkiByZWZlcmVuY2luZyBwYWdlIG1hcCBmcm9tIHtAbGluayBjb2xsZWN0RXh0ZXJuYWxUYXJnZXRzfS5cbiAqIEBwYXJhbSBmZXRjaFVybFN0YXR1cyAtIEluamVjdGVkIHByb2JlIHJldHVybmluZyB0aGUgSFRUUCBzdGF0dXMgZm9yIGEgVVJMIChgMGAgZm9yIGEgbmV0d29yayBmYWlsdXJlKS5cbiAqIEBwYXJhbSBjb25jdXJyZW5jeSAtIFRoZSBtYXhpbXVtIG51bWJlciBvZiBpbi1mbGlnaHQgcHJvYmVzLlxuICogQHJldHVybnMgRXZlcnkgZXh0ZXJuYWwgVVJMIHRoYXQgZGlkIG5vdCByZXR1cm4gSFRUUCBgMjAwYCwgaW4gdGhlIG1hcCdzIGl0ZXJhdGlvbiBvcmRlci5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvbGxlY3RCcm9rZW5FeHRlcm5hbExpbmtzKFxuICB0YXJnZXRzOiBNYXA8c3RyaW5nLCBzdHJpbmc+LFxuICBmZXRjaFVybFN0YXR1czogKHVybDogc3RyaW5nKSA9PiBQcm9taXNlPG51bWJlcj4sXG4gIGNvbmN1cnJlbmN5OiBudW1iZXJcbik6IFByb21pc2U8QnJva2VuTGlua1tdPiB7XG4gIGNvbnN0IGVudHJpZXMgPSBbLi4udGFyZ2V0c107XG4gIGNvbnN0IHJlc3VsdHM6IChCcm9rZW5MaW5rIHwgbnVsbClbXSA9IEFycmF5LmZyb20oeyBsZW5ndGg6IGVudHJpZXMubGVuZ3RoIH0sICgpID0+IG51bGwpO1xuICBsZXQgbmV4dEluZGV4ID0gMDtcblxuICBhc3luYyBmdW5jdGlvbiBydW5Xb3JrZXIoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChsZXQgaW5kZXggPSBuZXh0SW5kZXgrKzsgaW5kZXggPCBlbnRyaWVzLmxlbmd0aDsgaW5kZXggPSBuZXh0SW5kZXgrKykge1xuICAgICAgY29uc3QgW2V4dGVybmFsVXJsLCBwYWdlVXJsXSA9IGVuc3VyZU5vbk51bGxhYmxlKGVudHJpZXNbaW5kZXhdKTtcbiAgICAgIGNvbnN0IGh0dHBTdGF0dXMgPSBhd2FpdCBmZXRjaFVybFN0YXR1cyhleHRlcm5hbFVybCk7XG4gICAgICBpZiAoaHR0cFN0YXR1cyAhPT0gSFRUUF9PS19TVEFUVVMpIHtcbiAgICAgICAgcmVzdWx0c1tpbmRleF0gPSB7IGh0dHBTdGF0dXMsIHBhZ2VVcmwsIHJlYXNvbjogJ2V4dGVybmFsLWVycm9yJywgdGFyZ2V0VXJsOiBleHRlcm5hbFVybCB9O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHdvcmtlckNvdW50ID0gTWF0aC5tYXgoMSwgTWF0aC5taW4oY29uY3VycmVuY3ksIGVudHJpZXMubGVuZ3RoKSk7XG4gIGF3YWl0IFByb21pc2UuYWxsKEFycmF5LmZyb20oeyBsZW5ndGg6IHdvcmtlckNvdW50IH0sICgpID0+IHJ1bldvcmtlcigpKSk7XG5cbiAgLy8gSW5kZXhlZCBhc3NpZ25tZW50IGFib3ZlIGtlZXBzIGZhaWx1cmVzIGluIHRoZSBtYXAncyBpdGVyYXRpb24gb3JkZXI7IGRyb3AgdGhlIHN1Y2Nlc3NmdWwgZ2Fwcy5cbiAgcmV0dXJuIHJlc3VsdHMuZmlsdGVyKChicm9rZW5MaW5rKTogYnJva2VuTGluayBpcyBCcm9rZW5MaW5rID0+IGJyb2tlbkxpbmsgIT09IG51bGwpO1xufVxuXG4vKipcbiAqIEZpbmRzIGV2ZXJ5IGludGVybmFsIGxpbmsgYWNyb3NzIHRoZSBidWlsdCBkb2N1bWVudGF0aW9uIHBhZ2VzIHRoYXQgZG9lcyBub3QgcmVzb2x2ZS5cbiAqXG4gKiBFeHRlcm5hbCBhbmQgbm9uLUhUVFAgbGlua3MgYXJlIGlnbm9yZWQuIEVhY2ggaW50ZXJuYWwgbGluayBtdXN0IHJlc29sdmUgdG8gYW4gZXhpc3RpbmcgcGFnZSxcbiAqIGFuZCBlYWNoIGAjZnJhZ21lbnRgIG11c3QgcmVzb2x2ZSB0byBhbiBleGlzdGluZyBlbGVtZW50IGlkIG9uIHRoZSB0YXJnZXQgcGFnZS5cbiAqXG4gKiBAcGFyYW0gcGFnZXMgLSBUaGUgYnVpbHQgZG9jdW1lbnRhdGlvbiBwYWdlcyB0byB2YWxpZGF0ZS5cbiAqIEBwYXJhbSBmaWxlU3lzdGVtIC0gSW5qZWN0ZWQgYWNjZXNzIHRvIHRoZSBidWlsZCBvdXRwdXQuXG4gKiBAcGFyYW0gc2l0ZUJhc2VVcmwgLSBUaGUgYWJzb2x1dGUgYmFzZSBVUkwgdGhlIHNpdGUgaXMgc2VydmVkIGZyb20gKHdpdGggYSB0cmFpbGluZyBzbGFzaCkuXG4gKiBAcmV0dXJucyBFdmVyeSBicm9rZW4gaW50ZXJuYWwgbGluaywgaW4gcGFnZS10aGVuLWRvY3VtZW50IG9yZGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29sbGVjdEJyb2tlbkxpbmtzKHBhZ2VzOiBEb2N1bWVudGF0aW9uUGFnZVtdLCBmaWxlU3lzdGVtOiBMaW5rQ2hlY2tGaWxlU3lzdGVtLCBzaXRlQmFzZVVybDogc3RyaW5nKTogQnJva2VuTGlua1tdIHtcbiAgY29uc3QgYnJva2VuTGlua3M6IEJyb2tlbkxpbmtbXSA9IFtdO1xuXG4gIGZvciAoY29uc3QgcGFnZSBvZiBwYWdlcykge1xuICAgIGNvbnN0IHBhZ2VVcmwgPSBnZXRQYWdlVXJsKHBhZ2UucmVsYXRpdmVQYXRoLCBzaXRlQmFzZVVybCk7XG4gICAgZm9yIChjb25zdCByYXdMaW5rIG9mIGV4dHJhY3RMaW5rcyhwYWdlLmh0bWwpKSB7XG4gICAgICBjb25zdCB0YXJnZXRVcmwgPSBuZXcgVVJMKHJhd0xpbmssIHBhZ2VVcmwpO1xuICAgICAgaWYgKCFpc0ludGVybmFsRG9jVXJsKHRhcmdldFVybCwgc2l0ZUJhc2VVcmwpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBwYWdlS2V5ID0gZmlsZVN5c3RlbS5yZXNvbHZlRXhpc3RpbmdQYWdlKGdldE91dHB1dFJlbGF0aXZlUGF0aCh0YXJnZXRVcmwsIHNpdGVCYXNlVXJsKSk7XG4gICAgICBpZiAocGFnZUtleSA9PT0gbnVsbCkge1xuICAgICAgICBicm9rZW5MaW5rcy5wdXNoKHsgcGFnZVVybCwgcmVhc29uOiAnbWlzc2luZy1wYWdlJywgdGFyZ2V0VXJsOiB0YXJnZXRVcmwuaHJlZiB9KTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZyYWdtZW50ID0gdGFyZ2V0VXJsLmhhc2guc2xpY2UoMSk7XG4gICAgICBpZiAoZnJhZ21lbnQubGVuZ3RoID4gMCAmJiAhZmlsZVN5c3RlbS5yZWFkSWRzKHBhZ2VLZXkpLmhhcyhmcmFnbWVudCkpIHtcbiAgICAgICAgYnJva2VuTGlua3MucHVzaCh7IHBhZ2VVcmwsIHJlYXNvbjogJ21pc3NpbmctZnJhZ21lbnQnLCB0YXJnZXRVcmw6IHRhcmdldFVybC5ocmVmIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBicm9rZW5MaW5rcztcbn1cblxuLyoqXG4gKiBDb2xsZWN0cyBldmVyeSB1bmlxdWUgZXh0ZXJuYWwgVVJMIHJlZmVyZW5jZWQgYWNyb3NzIHRoZSBidWlsdCBwYWdlcywgZGVkdXBsaWNhdGVkLlxuICpcbiAqIE9ubHkgSFRUUChTKSBsaW5rcyB0aGF0IGFyZSBub3Qge0BsaW5rIGlzSW50ZXJuYWxEb2NVcmx9IGFyZSByZXR1cm5lZC4gRWFjaCB1bmlxdWUgVVJMIG1hcHMgdG9cbiAqIHRoZSBmaXJzdCBwYWdlIHRoYXQgcmVmZXJlbmNlZCBpdCwgc28gYSBsYXRlciBmYWlsdXJlIGNhbiBiZSByZXBvcnRlZCB3aXRoIGEgY29uY3JldGUgZXhhbXBsZVxuICogcGFnZSBldmVuIHRob3VnaCB0aGUgVVJMIGlzIGZldGNoZWQgb25seSBvbmNlLlxuICpcbiAqIEBwYXJhbSBwYWdlcyAtIFRoZSBidWlsdCBkb2N1bWVudGF0aW9uIHBhZ2VzIHRvIHNjYW4uXG4gKiBAcGFyYW0gc2l0ZUJhc2VVcmwgLSBUaGUgYWJzb2x1dGUgYmFzZSBVUkwgdGhlIHNpdGUgaXMgc2VydmVkIGZyb20gKHdpdGggYSB0cmFpbGluZyBzbGFzaCkuXG4gKiBAcmV0dXJucyBBIG1hcCBmcm9tIGVhY2ggdW5pcXVlIGV4dGVybmFsIFVSTCB0byBvbmUgcmVmZXJlbmNpbmcgcGFnZSBVUkwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb2xsZWN0RXh0ZXJuYWxUYXJnZXRzKHBhZ2VzOiBEb2N1bWVudGF0aW9uUGFnZVtdLCBzaXRlQmFzZVVybDogc3RyaW5nKTogTWFwPHN0cmluZywgc3RyaW5nPiB7XG4gIGNvbnN0IHRhcmdldHMgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuXG4gIGZvciAoY29uc3QgcGFnZSBvZiBwYWdlcykge1xuICAgIGNvbnN0IHBhZ2VVcmwgPSBnZXRQYWdlVXJsKHBhZ2UucmVsYXRpdmVQYXRoLCBzaXRlQmFzZVVybCk7XG4gICAgZm9yIChjb25zdCByYXdMaW5rIG9mIGV4dHJhY3RMaW5rcyhwYWdlLmh0bWwpKSB7XG4gICAgICBjb25zdCB0YXJnZXRVcmwgPSBuZXcgVVJMKHJhd0xpbmssIHBhZ2VVcmwpO1xuICAgICAgaWYgKCh0YXJnZXRVcmwucHJvdG9jb2wgIT09ICdodHRwOicgJiYgdGFyZ2V0VXJsLnByb3RvY29sICE9PSAnaHR0cHM6JykgfHwgaXNJbnRlcm5hbERvY1VybCh0YXJnZXRVcmwsIHNpdGVCYXNlVXJsKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZXh0ZXJuYWxVcmwgPSBgJHt0YXJnZXRVcmwub3JpZ2lufSR7dGFyZ2V0VXJsLnBhdGhuYW1lfSR7dGFyZ2V0VXJsLnNlYXJjaH1gO1xuICAgICAgaWYgKCF0YXJnZXRzLmhhcyhleHRlcm5hbFVybCkpIHtcbiAgICAgICAgdGFyZ2V0cy5zZXQoZXh0ZXJuYWxVcmwsIHBhZ2VVcmwpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0YXJnZXRzO1xufVxuXG4vKipcbiAqIEV4dHJhY3RzIHRoZSB2YWx1ZXMgb2YgZXZlcnkgYGlkYCBhdHRyaWJ1dGUgaW4gYSBjaHVuayBvZiBIVE1MLlxuICpcbiAqIEBwYXJhbSBodG1sIC0gVGhlIEhUTUwgdG8gc2Nhbi5cbiAqIEByZXR1cm5zIFRoZSBzZXQgb2YgZWxlbWVudCBpZHMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0SWRzKGh0bWw6IHN0cmluZyk6IFNldDxzdHJpbmc+IHtcbiAgcmV0dXJuIG5ldyBTZXQoWy4uLmh0bWwubWF0Y2hBbGwoSURfQVRUUklCVVRFX1JFR0VYKV0ubWFwKChtYXRjaCkgPT4gZ2V0TWFuZGF0b3J5TmFtZWRHcm91cChtYXRjaCwgJ3ZhbHVlJykpKTtcbn1cblxuLyoqXG4gKiBFeHRyYWN0cyB0aGUgdmFsdWVzIG9mIGV2ZXJ5IGBocmVmYC9gc3JjYCBhdHRyaWJ1dGUgaW4gYSBjaHVuayBvZiBIVE1MLlxuICpcbiAqIEBwYXJhbSBodG1sIC0gVGhlIEhUTUwgdG8gc2Nhbi5cbiAqIEByZXR1cm5zIFRoZSByYXcgbGluayB2YWx1ZXMsIGluIGRvY3VtZW50IG9yZGVyIChkdXBsaWNhdGVzIHByZXNlcnZlZCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0TGlua3MoaHRtbDogc3RyaW5nKTogc3RyaW5nW10ge1xuICByZXR1cm4gWy4uLmh0bWwubWF0Y2hBbGwoTElOS19BVFRSSUJVVEVfUkVHRVgpXS5tYXAoKG1hdGNoKSA9PiBnZXRNYW5kYXRvcnlOYW1lZEdyb3VwKG1hdGNoLCAndmFsdWUnKSk7XG59XG5cbi8qKlxuICogRm9ybWF0cyBicm9rZW4gbGlua3MgaW50byBhIGh1bWFuLXJlYWRhYmxlIG11bHRpLWxpbmUgcmVwb3J0LlxuICpcbiAqIEBwYXJhbSBicm9rZW5MaW5rcyAtIFRoZSBicm9rZW4gbGlua3MgdG8gZGVzY3JpYmUuXG4gKiBAcmV0dXJucyBPbmUgbGluZSBwZXIgYnJva2VuIGxpbmsuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRCcm9rZW5MaW5rcyhicm9rZW5MaW5rczogQnJva2VuTGlua1tdKTogc3RyaW5nIHtcbiAgcmV0dXJuIGJyb2tlbkxpbmtzXG4gICAgLm1hcCgoYnJva2VuTGluaykgPT4ge1xuICAgICAgc3dpdGNoIChicm9rZW5MaW5rLnJlYXNvbikge1xuICAgICAgICBjYXNlICdleHRlcm5hbC1lcnJvcic6IHtcbiAgICAgICAgICByZXR1cm4gYCR7YnJva2VuTGluay5wYWdlVXJsfSBsaW5rcyB0byBleHRlcm5hbCBVUkwgJHticm9rZW5MaW5rLnRhcmdldFVybH0gdGhhdCByZXR1cm5lZCAke2Rlc2NyaWJlSHR0cFN0YXR1cyhicm9rZW5MaW5rLmh0dHBTdGF0dXMpfS5gO1xuICAgICAgICB9XG4gICAgICAgIGNhc2UgJ21pc3NpbmctZnJhZ21lbnQnOiB7XG4gICAgICAgICAgcmV0dXJuIGAke2Jyb2tlbkxpbmsucGFnZVVybH0gbGlua3MgdG8gbWlzc2luZyBmcmFnbWVudCAke2Jyb2tlbkxpbmsudGFyZ2V0VXJsfS5gO1xuICAgICAgICB9XG4gICAgICAgIGNhc2UgJ21pc3NpbmctcGFnZSc6IHtcbiAgICAgICAgICByZXR1cm4gYCR7YnJva2VuTGluay5wYWdlVXJsfSBsaW5rcyB0byBtaXNzaW5nIHBhZ2UgJHticm9rZW5MaW5rLnRhcmdldFVybH0uYDtcbiAgICAgICAgfVxuICAgICAgICBkZWZhdWx0OiB7XG4gICAgICAgICAgcmV0dXJuIGFzc2VydE5ldmVyKGJyb2tlbkxpbmsucmVhc29uKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pXG4gICAgLmpvaW4oJ1xcbicpO1xufVxuXG4vKipcbiAqIENvbXB1dGVzIHRoZSBidWlsZC1vdXRwdXQtcmVsYXRpdmUgcGF0aCBmb3IgYW4gaW50ZXJuYWwgZG9jdW1lbnRhdGlvbiBVUkwuXG4gKlxuICogQHBhcmFtIHRhcmdldFVybCAtIFRoZSByZXNvbHZlZCBhYnNvbHV0ZSBsaW5rIFVSTCAobXVzdCBiZSB7QGxpbmsgaXNJbnRlcm5hbERvY1VybH0pLlxuICogQHBhcmFtIHNpdGVCYXNlVXJsIC0gVGhlIGFic29sdXRlIGJhc2UgVVJMIHRoZSBzaXRlIGlzIHNlcnZlZCBmcm9tICh3aXRoIGEgdHJhaWxpbmcgc2xhc2gpLlxuICogQHJldHVybnMgVGhlIGRlY29kZWQgcGF0aCByZWxhdGl2ZSB0byB0aGUgYnVpbGQtb3V0cHV0IHJvb3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRPdXRwdXRSZWxhdGl2ZVBhdGgodGFyZ2V0VXJsOiBVUkwsIHNpdGVCYXNlVXJsOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBiYXNlID0gbmV3IFVSTChzaXRlQmFzZVVybCk7XG4gIHJldHVybiBkZWNvZGVVUklDb21wb25lbnQodGFyZ2V0VXJsLnBhdGhuYW1lLnNsaWNlKGJhc2UucGF0aG5hbWUubGVuZ3RoKSk7XG59XG5cbi8qKlxuICogQ29tcHV0ZXMgdGhlIGFic29sdXRlIFVSTCBhIGJ1aWx0IHBhZ2UgaXMgc2VydmVkIGF0LlxuICpcbiAqIEBwYXJhbSByZWxhdGl2ZVBhdGggLSBUaGUgcGFnZSdzIHBhdGggcmVsYXRpdmUgdG8gdGhlIGJ1aWxkLW91dHB1dCByb290LlxuICogQHBhcmFtIHNpdGVCYXNlVXJsIC0gVGhlIGFic29sdXRlIGJhc2UgVVJMIHRoZSBzaXRlIGlzIHNlcnZlZCBmcm9tICh3aXRoIGEgdHJhaWxpbmcgc2xhc2gpLlxuICogQHJldHVybnMgVGhlIHBhZ2UncyBhYnNvbHV0ZSBVUkwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRQYWdlVXJsKHJlbGF0aXZlUGF0aDogc3RyaW5nLCBzaXRlQmFzZVVybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IHJlbGF0aXZlUGF0aC5yZXBsYWNlQWxsKCdcXFxcJywgJy8nKTtcbiAgY29uc3QgdXJsUGF0aCA9IG5vcm1hbGl6ZWQgPT09ICdpbmRleC5odG1sJyA/ICcnIDogbm9ybWFsaXplZC5yZXBsYWNlKC9pbmRleFxcLmh0bWwkL3UsICcnKTtcbiAgcmV0dXJuIG5ldyBVUkwodXJsUGF0aCwgc2l0ZUJhc2VVcmwpLmhyZWY7XG59XG5cbi8qKlxuICogRGV0ZXJtaW5lcyB3aGV0aGVyIGEgcmVzb2x2ZWQgbGluayBwb2ludHMgYXQgYSBwYWdlIGhvc3RlZCBieSB0aGlzIGRvY3VtZW50YXRpb24gc2l0ZS5cbiAqXG4gKiBAcGFyYW0gdGFyZ2V0VXJsIC0gVGhlIHJlc29sdmVkIGFic29sdXRlIGxpbmsgVVJMLlxuICogQHBhcmFtIHNpdGVCYXNlVXJsIC0gVGhlIGFic29sdXRlIGJhc2UgVVJMIHRoZSBzaXRlIGlzIHNlcnZlZCBmcm9tICh3aXRoIGEgdHJhaWxpbmcgc2xhc2gpLlxuICogQHJldHVybnMgYHRydWVgIHdoZW4gdGhlIGxpbmsgaXMgc2FtZS1vcmlnaW4gYW5kIHVuZGVyIHRoZSBzaXRlIGJhc2UgcGF0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzSW50ZXJuYWxEb2NVcmwodGFyZ2V0VXJsOiBVUkwsIHNpdGVCYXNlVXJsOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgY29uc3QgYmFzZSA9IG5ldyBVUkwoc2l0ZUJhc2VVcmwpO1xuICByZXR1cm4gdGFyZ2V0VXJsLm9yaWdpbiA9PT0gYmFzZS5vcmlnaW4gJiYgdGFyZ2V0VXJsLnBhdGhuYW1lLnN0YXJ0c1dpdGgoYmFzZS5wYXRobmFtZSk7XG59XG5cbi8qKlxuICogUmVzb2x2ZXMgYW4gb3V0cHV0LXJlbGF0aXZlIHBhdGggdG8gYW4gYWJzb2x1dGUgcGF0aCBpbnNpZGUgdGhlIGJ1aWxkLW91dHB1dCByb290LCByZWplY3RpbmdcbiAqIHBhdGhzIHRoYXQgZXNjYXBlIGl0IHZpYSBgLi5gIHNlZ21lbnRzLlxuICpcbiAqIEBwYXJhbSBvdXRwdXRSb290UGF0aCAtIFRoZSBhYnNvbHV0ZSBidWlsZC1vdXRwdXQgcm9vdCBwYXRoLlxuICogQHBhcmFtIG91dHB1dFJlbGF0aXZlUGF0aCAtIFRoZSBkZWNvZGVkIG91dHB1dC1yZWxhdGl2ZSBwYXRoLlxuICogQHJldHVybnMgVGhlIGpvaW5lZCBwYXRoIHdoZW4gaXQgc3RheXMgd2l0aGluIHRoZSByb290LCBvdGhlcndpc2UgYG51bGxgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVdpdGhpblJvb3Qob3V0cHV0Um9vdFBhdGg6IHN0cmluZywgb3V0cHV0UmVsYXRpdmVQYXRoOiBzdHJpbmcpOiBudWxsIHwgc3RyaW5nIHtcbiAgY29uc3Qgcm9vdCA9IG5vcm1hbGl6ZShvdXRwdXRSb290UGF0aC5yZXBsYWNlQWxsKCdcXFxcJywgJy8nKSkucmVwbGFjZSgvXFwvJC91LCAnJyk7XG4gIGxldCBqb2luZWQgPSBub3JtYWxpemUoYCR7cm9vdH0vJHtvdXRwdXRSZWxhdGl2ZVBhdGgucmVwbGFjZUFsbCgnXFxcXCcsICcvJyl9YCk7XG4gIGlmIChqb2luZWQubGVuZ3RoID4gMSkge1xuICAgIGpvaW5lZCA9IGpvaW5lZC5yZXBsYWNlKC9cXC8kL3UsICcnKTtcbiAgfVxuXG4gIHJldHVybiBqb2luZWQgIT09IHJvb3QgJiYgIWpvaW5lZC5zdGFydHNXaXRoKGAke3Jvb3R9L2ApID8gbnVsbCA6IGpvaW5lZDtcbn1cblxuZnVuY3Rpb24gZGVzY3JpYmVIdHRwU3RhdHVzKGh0dHBTdGF0dXM6IG51bWJlciB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gIHJldHVybiBodHRwU3RhdHVzID09PSB1bmRlZmluZWQgfHwgaHR0cFN0YXR1cyA9PT0gTkVUV09SS19GQUlMVVJFX1NUQVRVUyA/ICdhIG5ldHdvcmsgZmFpbHVyZScgOiBgSFRUUCAke1N0cmluZyhodHRwU3RhdHVzKX1gO1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQWNBLFNBQVMsOEJBQThCO0FBQ3ZDO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyxpQkFBaUI7QUFFMUIsTUFBTSx1QkFBdUI7QUFDN0IsTUFBTSxxQkFBcUI7QUFDM0IsTUFBTSxpQkFBaUI7QUFNaEIsTUFBTSx5QkFBeUI7QUEwRXRDLGVBQXNCLDJCQUNwQixTQUNBLGdCQUNBLGFBQ3VCO0FBQ3ZCLFFBQU0sVUFBVSxDQUFDLEdBQUcsT0FBTztBQUMzQixRQUFNLFVBQWlDLE1BQU0sS0FBSyxFQUFFLFFBQVEsUUFBUSxPQUFPLEdBQUcsTUFBTSxJQUFJO0FBQ3hGLE1BQUksWUFBWTtBQUVoQixpQkFBZSxZQUEyQjtBQUN4QyxhQUFTLFFBQVEsYUFBYSxRQUFRLFFBQVEsUUFBUSxRQUFRLGFBQWE7QUFDekUsWUFBTSxDQUFDLGFBQWEsT0FBTyxJQUFJLGtCQUFrQixRQUFRLEtBQUssQ0FBQztBQUMvRCxZQUFNLGFBQWEsTUFBTSxlQUFlLFdBQVc7QUFDbkQsVUFBSSxlQUFlLGdCQUFnQjtBQUNqQyxnQkFBUSxLQUFLLElBQUksRUFBRSxZQUFZLFNBQVMsUUFBUSxrQkFBa0IsV0FBVyxZQUFZO0FBQUEsTUFDM0Y7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUVBLFFBQU0sY0FBYyxLQUFLLElBQUksR0FBRyxLQUFLLElBQUksYUFBYSxRQUFRLE1BQU0sQ0FBQztBQUNy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
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/// <reference path="../library-references.d.mts" />
|
|
2
|
+
/**
|
|
3
|
+
* @file
|
|
4
|
+
*
|
|
5
|
+
* Resolves generated Open Graph image paths from documentation page metadata.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Resolves the public Open Graph image slug for a documentation page.
|
|
9
|
+
*
|
|
10
|
+
* @param frontmatter - The page's parsed frontmatter.
|
|
11
|
+
* @param filePath - The page's source-file path.
|
|
12
|
+
* @param contentDocsDirectory - The documentation content root.
|
|
13
|
+
* @returns The case-preserved explicit slug, or a slug derived from the file path.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getOgImagePageSlug(frontmatter: Record<string, unknown>, filePath: string, contentDocsDirectory: string): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
3
|
+
if you want to view the source, please visit the github repository of this plugin
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { relative } from "node:path/posix";
|
|
7
|
+
function getOgImagePageSlug(frontmatter, filePath, contentDocsDirectory) {
|
|
8
|
+
const slug = frontmatter["slug"];
|
|
9
|
+
if (typeof slug === "string") {
|
|
10
|
+
return slug;
|
|
11
|
+
}
|
|
12
|
+
let filePathSlug = relative(contentDocsDirectory, filePath);
|
|
13
|
+
filePathSlug = filePathSlug.replaceAll("\\", "/");
|
|
14
|
+
filePathSlug = filePathSlug.replace(/\.\w+$/, "");
|
|
15
|
+
filePathSlug = filePathSlug.replace(/(?:^|\/)index$/, "");
|
|
16
|
+
return filePathSlug || "index";
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
getOgImagePageSlug
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL2RvY3Mtc2l0ZS9vZy1pbWFnZS1wYWdlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogUmVzb2x2ZXMgZ2VuZXJhdGVkIE9wZW4gR3JhcGggaW1hZ2UgcGF0aHMgZnJvbSBkb2N1bWVudGF0aW9uIHBhZ2UgbWV0YWRhdGEuXG4gKi9cblxuaW1wb3J0IHsgcmVsYXRpdmUgfSBmcm9tICdub2RlOnBhdGgvcG9zaXgnO1xuXG4vKipcbiAqIFJlc29sdmVzIHRoZSBwdWJsaWMgT3BlbiBHcmFwaCBpbWFnZSBzbHVnIGZvciBhIGRvY3VtZW50YXRpb24gcGFnZS5cbiAqXG4gKiBAcGFyYW0gZnJvbnRtYXR0ZXIgLSBUaGUgcGFnZSdzIHBhcnNlZCBmcm9udG1hdHRlci5cbiAqIEBwYXJhbSBmaWxlUGF0aCAtIFRoZSBwYWdlJ3Mgc291cmNlLWZpbGUgcGF0aC5cbiAqIEBwYXJhbSBjb250ZW50RG9jc0RpcmVjdG9yeSAtIFRoZSBkb2N1bWVudGF0aW9uIGNvbnRlbnQgcm9vdC5cbiAqIEByZXR1cm5zIFRoZSBjYXNlLXByZXNlcnZlZCBleHBsaWNpdCBzbHVnLCBvciBhIHNsdWcgZGVyaXZlZCBmcm9tIHRoZSBmaWxlIHBhdGguXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRPZ0ltYWdlUGFnZVNsdWcoZnJvbnRtYXR0ZXI6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBmaWxlUGF0aDogc3RyaW5nLCBjb250ZW50RG9jc0RpcmVjdG9yeTogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qgc2x1ZyA9IGZyb250bWF0dGVyWydzbHVnJ107XG4gIGlmICh0eXBlb2Ygc2x1ZyA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gc2x1ZztcbiAgfVxuXG4gIGxldCBmaWxlUGF0aFNsdWcgPSByZWxhdGl2ZShjb250ZW50RG9jc0RpcmVjdG9yeSwgZmlsZVBhdGgpO1xuICBmaWxlUGF0aFNsdWcgPSBmaWxlUGF0aFNsdWcucmVwbGFjZUFsbCgnXFxcXCcsICcvJyk7XG4gIGZpbGVQYXRoU2x1ZyA9IGZpbGVQYXRoU2x1Zy5yZXBsYWNlKC9cXC5cXHcrJC8sICcnKTtcbiAgZmlsZVBhdGhTbHVnID0gZmlsZVBhdGhTbHVnLnJlcGxhY2UoLyg/Ol58XFwvKWluZGV4JC8sICcnKTtcbiAgcmV0dXJuIGZpbGVQYXRoU2x1ZyB8fCAnaW5kZXgnO1xufVxuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7QUFNQSxTQUFTLGdCQUFnQjtBQVVsQixTQUFTLG1CQUFtQixhQUFzQyxVQUFrQixzQkFBc0M7QUFDL0gsUUFBTSxPQUFPLFlBQVksTUFBTTtBQUMvQixNQUFJLE9BQU8sU0FBUyxVQUFVO0FBQzVCLFdBQU87QUFBQSxFQUNUO0FBRUEsTUFBSSxlQUFlLFNBQVMsc0JBQXNCLFFBQVE7QUFDMUQsaUJBQWUsYUFBYSxXQUFXLE1BQU0sR0FBRztBQUNoRCxpQkFBZSxhQUFhLFFBQVEsVUFBVSxFQUFFO0FBQ2hELGlCQUFlLGFBQWEsUUFBUSxrQkFBa0IsRUFBRTtBQUN4RCxTQUFPLGdCQUFnQjtBQUN6QjsiLAogICJuYW1lcyI6IFtdCn0K
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/// <reference path="../library-references.d.mts" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/**
|
|
4
|
+
* @file
|
|
5
|
+
*
|
|
6
|
+
* Renders a page's Open Graph card: satori lays it out as SVG, resvg rasterizes it to PNG.
|
|
7
|
+
*/
|
|
8
|
+
import type { Font } from 'satori';
|
|
9
|
+
/**
|
|
10
|
+
* What one Open Graph card shows: a title, and optionally a description, a code signature and a badge.
|
|
11
|
+
*/
|
|
12
|
+
export interface OgCardContent {
|
|
13
|
+
readonly badge?: string | undefined;
|
|
14
|
+
readonly description?: string | undefined;
|
|
15
|
+
readonly signature?: string | undefined;
|
|
16
|
+
readonly title: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The per-site part of every card: the fonts, the logo and the brand text in the footer.
|
|
20
|
+
*/
|
|
21
|
+
export interface RenderOgImageOptions {
|
|
22
|
+
/**
|
|
23
|
+
* The text the footer carries, normally the package's name.
|
|
24
|
+
*/
|
|
25
|
+
readonly brandText: string;
|
|
26
|
+
/**
|
|
27
|
+
* The fonts satori renders the text with.
|
|
28
|
+
*/
|
|
29
|
+
readonly fonts: Font[];
|
|
30
|
+
/**
|
|
31
|
+
* The site logo as a PNG data URI, or `null` to render the card without one.
|
|
32
|
+
*/
|
|
33
|
+
readonly logoDataUri: null | string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Hashes a card's content, so an unchanged card is not rendered again.
|
|
37
|
+
*
|
|
38
|
+
* @param params - The card's content.
|
|
39
|
+
* @returns A 16-character hex digest.
|
|
40
|
+
*/
|
|
41
|
+
export declare function computeOgHash(params: OgCardContent): string;
|
|
42
|
+
/**
|
|
43
|
+
* Loads the fonts satori needs to render text.
|
|
44
|
+
*
|
|
45
|
+
* This package ships `inter-latin-400-normal.ttf` / `inter-latin-700-normal.ttf` under
|
|
46
|
+
* `assets/docs-site/fonts`; this falls back to any other `.ttf`/`.otf` in `fontsDirectory` and
|
|
47
|
+
* returns `null` when the directory holds none, so the caller can skip OG generation instead of
|
|
48
|
+
* crashing the build.
|
|
49
|
+
*
|
|
50
|
+
* @param fontsDirectory - The folder holding the fonts.
|
|
51
|
+
* @returns The fonts, or `null` when the folder holds none.
|
|
52
|
+
*/
|
|
53
|
+
export declare function loadFonts(fontsDirectory: string): Promise<Font[] | null>;
|
|
54
|
+
/**
|
|
55
|
+
* Rasterize an SVG favicon to a PNG data URI via resvg for embedding in the satori layout (satori's
|
|
56
|
+
* `<img>` needs a raster/data-URI source). Returns `null` when the file is missing so the caller can
|
|
57
|
+
* render the card without a logo. Call this ONCE and reuse the result across all cards.
|
|
58
|
+
*
|
|
59
|
+
* @param faviconPath - The SVG favicon's path.
|
|
60
|
+
* @returns The PNG data URI, or `null` when the favicon is missing.
|
|
61
|
+
*/
|
|
62
|
+
export declare function loadLogoDataUri(faviconPath: string): Promise<null | string>;
|
|
63
|
+
/**
|
|
64
|
+
* Renders a page's card to a PNG.
|
|
65
|
+
*
|
|
66
|
+
* @param params - The card's content.
|
|
67
|
+
* @param options - The fonts, logo and brand text every card shares.
|
|
68
|
+
* @returns The PNG.
|
|
69
|
+
*/
|
|
70
|
+
export declare function renderOgImage(params: OgCardContent, options: RenderOgImageOptions): Promise<Buffer>;
|