@grove-dev/astro 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -5
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -33
- package/dist/index.js.map +1 -1
- package/dist/lib/display.d.ts +1 -1
- package/dist/lib/display.js +1 -1
- package/dist/lib/format.d.ts +1 -1
- package/dist/lib/format.js +1 -1
- package/dist/lib/icon-kinds.d.ts +1 -1
- package/dist/lib/icon-kinds.js +43 -43
- package/dist/lib/icon-registry.d.ts +2 -2
- package/dist/lib/icon-registry.js +23 -23
- package/dist/lib/index.d.ts +9 -9
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +9 -9
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/lenses.d.ts +1 -1
- package/dist/lib/lenses.js +1 -1
- package/dist/lib/packaged-icons.d.ts +1 -1
- package/dist/lib/packaged-icons.js +4 -4
- package/dist/lib/repo.d.ts +1 -1
- package/dist/lib/repo.js +1 -1
- package/dist/lib/search.d.ts +1 -1
- package/dist/lib/search.js +1 -1
- package/dist/lib/taxonomy-counts.d.ts +1 -1
- package/dist/lib/taxonomy-counts.js +1 -1
- package/package.json +7 -17
- package/src/index.ts +23 -38
- package/src/lib/display.ts +1 -1
- package/src/lib/format.ts +1 -1
- package/src/lib/icon-kinds.ts +44 -44
- package/src/lib/icon-registry.ts +25 -25
- package/src/lib/index.ts +9 -9
- package/src/lib/lenses.ts +1 -1
- package/src/lib/packaged-icons.ts +8 -8
- package/src/lib/repo.ts +1 -1
- package/src/lib/search.ts +1 -1
- package/src/lib/taxonomy-counts.ts +1 -1
- package/src/server/collections.ts +53 -42
- package/src/server/contrast.ts +14 -9
- package/src/server/directory.ts +22 -17
- package/src/server/index.ts +3 -2
- package/src/server/models.ts +404 -213
- package/src/server/seo.ts +34 -31
- package/src/styles.css +235 -91
- package/dist/layouts/index.d.ts +0 -25
- package/dist/layouts/index.d.ts.map +0 -1
- package/dist/layouts/index.js +0 -25
- package/dist/layouts/index.js.map +0 -1
- package/dist/ui/button.d.ts +0 -53
- package/dist/ui/button.d.ts.map +0 -1
- package/dist/ui/button.js +0 -90
- package/dist/ui/button.js.map +0 -1
- package/src/components/CardGrid.astro +0 -41
- package/src/components/CardIcon.astro +0 -67
- package/src/components/CategoryGrid.astro +0 -114
- package/src/components/CollectionCard.astro +0 -56
- package/src/components/CollectionIndex.astro +0 -102
- package/src/components/CollectionPage.astro +0 -128
- package/src/components/CollectionRow.astro +0 -81
- package/src/components/CollectionTeaser.astro +0 -47
- package/src/components/ContributorsGrid.astro +0 -143
- package/src/components/DirectoryIndexClient.astro +0 -510
- package/src/components/EditorialSummary.astro +0 -58
- package/src/components/FilterGroupMenu.astro +0 -69
- package/src/components/FilterOptions.astro +0 -49
- package/src/components/FinalCta.astro +0 -43
- package/src/components/Hero.astro +0 -243
- package/src/components/Icon.astro +0 -191
- package/src/components/IndexRow.astro +0 -37
- package/src/components/LanguageBreakdown.astro +0 -67
- package/src/components/MarkdownBody.astro +0 -37
- package/src/components/OriginalCollection.astro +0 -117
- package/src/components/Pagination.astro +0 -50
- package/src/components/PoweredBy.astro +0 -60
- package/src/components/ProjectCard.astro +0 -321
- package/src/components/RecordHeader.astro +0 -221
- package/src/components/RecordSection.astro +0 -128
- package/src/components/RecordSidebar.astro +0 -387
- package/src/components/RefinePanel.astro +0 -168
- package/src/components/SmartLensTabs.astro +0 -81
- package/src/components/StackGrid.astro +0 -151
- package/src/components/StackPlatformChips.astro +0 -73
- package/src/components/SubmissionClient.astro +0 -254
- package/src/components/TableOfContents.astro +0 -140
- package/src/components/WhyThisExists.astro +0 -116
- package/src/layouts/BaseLayout.astro +0 -415
- package/src/layouts/Container.astro +0 -18
- package/src/layouts/Footer.astro +0 -231
- package/src/layouts/Header.astro +0 -214
- package/src/layouts/SectionHeader.astro +0 -43
- package/src/layouts/Seo.astro +0 -171
- package/src/layouts/ThemeToggle.astro +0 -118
- package/src/layouts/astro-shim.d.ts +0 -29
- package/src/layouts/index.ts +0 -24
- package/src/server/collections.test.ts +0 -212
- package/src/server/contrast.test.ts +0 -82
- package/src/server/directory.test.ts +0 -177
- package/src/server/github-repo.test.ts +0 -88
- package/src/server/models-home.test.ts +0 -101
- package/src/server/models.test.ts +0 -135
- package/src/server/seo.test.ts +0 -123
- package/src/ui/Badge.astro +0 -38
- package/src/ui/Button.astro +0 -42
- package/src/ui/EmptyState.astro +0 -38
- package/src/ui/FilterDrawer.astro +0 -124
- package/src/ui/PageHeader.astro +0 -39
- package/src/ui/SearchField.astro +0 -106
- package/src/ui/button.test.ts +0 -54
- package/src/ui/button.ts +0 -107
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { Collection, CollectionEntry } from
|
|
2
|
-
import { collectionSchema, findRelated, runCollection } from
|
|
3
|
-
import { absoluteUrl, ogPath, type PageSeo, seoDescription, seoTitle } from
|
|
1
|
+
import type { Collection, CollectionEntry } from '@grove-dev/core';
|
|
2
|
+
import { collectionSchema, findRelated, runCollection } from '@grove-dev/core';
|
|
3
|
+
import { absoluteUrl, ogPath, type PageSeo, seoDescription, seoTitle } from './seo.js';
|
|
4
4
|
|
|
5
5
|
// Collection YAML loading lives in @grove-dev/core (it also feeds the
|
|
6
6
|
// sitemap and OG-image pipelines there); re-exported for page code.
|
|
7
|
-
export { loadCollections } from
|
|
7
|
+
export { loadCollections } from '@grove-dev/core';
|
|
8
8
|
|
|
9
9
|
interface RouteHint {
|
|
10
10
|
routeSlug?: string;
|
|
@@ -65,19 +65,18 @@ export function recordsToCollectionEntries(
|
|
|
65
65
|
records: RawRecord[],
|
|
66
66
|
site: RouteHint,
|
|
67
67
|
): CollectionEntry[] {
|
|
68
|
-
const routeSlug = site.routeSlug ?? site.blueprintConfig?.routeSlug ??
|
|
68
|
+
const routeSlug = site.routeSlug ?? site.blueprintConfig?.routeSlug ?? 'projects';
|
|
69
69
|
const out: CollectionEntry[] = [];
|
|
70
70
|
for (const r of records) {
|
|
71
|
-
if (r.visibility ===
|
|
71
|
+
if (r.visibility === 'hide') continue;
|
|
72
72
|
if (!r.slug) continue;
|
|
73
|
-
const categories = [
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
].filter((value, index, self) => self.indexOf(value) === index);
|
|
73
|
+
const categories = [...(r.category ? [r.category] : []), ...(r.tags ?? [])].filter(
|
|
74
|
+
(value, index, self) => self.indexOf(value) === index,
|
|
75
|
+
);
|
|
77
76
|
out.push({
|
|
78
77
|
slug: r.slug,
|
|
79
78
|
title: r.name ?? r.title ?? r.slug,
|
|
80
|
-
description: r.description ??
|
|
79
|
+
description: r.description ?? '',
|
|
81
80
|
url: `/${routeSlug}/${r.slug}/`,
|
|
82
81
|
repoHref: r.repoUrl ?? r.links?.github,
|
|
83
82
|
homepageHref: r.links?.website,
|
|
@@ -89,11 +88,7 @@ export function recordsToCollectionEntries(
|
|
|
89
88
|
// If only `license` (singular, GitHub-synced) is present, mirror
|
|
90
89
|
// it into the array so the filter still matches it.
|
|
91
90
|
licenses:
|
|
92
|
-
r.licenses && r.licenses.length > 0
|
|
93
|
-
? r.licenses
|
|
94
|
-
: r.license
|
|
95
|
-
? [r.license]
|
|
96
|
-
: undefined,
|
|
91
|
+
r.licenses && r.licenses.length > 0 ? r.licenses : r.license ? [r.license] : undefined,
|
|
97
92
|
status: r.visibility,
|
|
98
93
|
stars: r.stars ?? r.github?.repository?.stargazers_count,
|
|
99
94
|
forks: r.forks ?? r.github?.repository?.forks_count,
|
|
@@ -118,7 +113,7 @@ export interface CollectionPageModel {
|
|
|
118
113
|
slug: string;
|
|
119
114
|
title: string;
|
|
120
115
|
description: string;
|
|
121
|
-
kind:
|
|
116
|
+
kind: 'curated' | 'generated';
|
|
122
117
|
selectionNote?: string;
|
|
123
118
|
introduction?: string;
|
|
124
119
|
};
|
|
@@ -140,7 +135,7 @@ export interface CollectionIndexModel {
|
|
|
140
135
|
slug: string;
|
|
141
136
|
title: string;
|
|
142
137
|
description: string;
|
|
143
|
-
kind:
|
|
138
|
+
kind: 'curated' | 'generated';
|
|
144
139
|
count: number;
|
|
145
140
|
url: string;
|
|
146
141
|
}>;
|
|
@@ -151,14 +146,19 @@ export interface CollectionIndexModel {
|
|
|
151
146
|
|
|
152
147
|
export interface CollectionTeaserModel {
|
|
153
148
|
total: number;
|
|
154
|
-
collections: CollectionIndexModel[
|
|
149
|
+
collections: CollectionIndexModel['collections'];
|
|
155
150
|
}
|
|
156
151
|
|
|
157
152
|
export function getCollectionPageModel(
|
|
158
153
|
collection: Collection,
|
|
159
154
|
entries: CollectionEntry[],
|
|
160
155
|
allCollections: Collection[],
|
|
161
|
-
site?: {
|
|
156
|
+
site?: {
|
|
157
|
+
name?: string;
|
|
158
|
+
url?: string;
|
|
159
|
+
siteUrl?: string;
|
|
160
|
+
blueprintConfig?: { labelPlural?: string };
|
|
161
|
+
},
|
|
162
162
|
): CollectionPageModel {
|
|
163
163
|
const result = runCollection(collection, entries);
|
|
164
164
|
const related = findRelated(collection, allCollections, 4).map((c) => ({
|
|
@@ -166,9 +166,9 @@ export function getCollectionPageModel(
|
|
|
166
166
|
title: c.title,
|
|
167
167
|
url: `/collections/${c.slug}/`,
|
|
168
168
|
}));
|
|
169
|
-
const siteUrl = (site?.siteUrl ?? site?.url ??
|
|
170
|
-
const siteName = site?.name ??
|
|
171
|
-
const plural = site?.blueprintConfig?.labelPlural ??
|
|
169
|
+
const siteUrl = (site?.siteUrl ?? site?.url ?? 'https://example.com').replace(/\/$/, '');
|
|
170
|
+
const siteName = site?.name ?? '';
|
|
171
|
+
const plural = site?.blueprintConfig?.labelPlural ?? 'items';
|
|
172
172
|
const pageUrl = absoluteUrl(siteUrl, `collections/${collection.slug}/`);
|
|
173
173
|
// CollectionPage + ItemList + BreadcrumbList. The ItemList is capped
|
|
174
174
|
// at 50 entries to keep the payload bounded; search engines don't
|
|
@@ -178,13 +178,13 @@ export function getCollectionPageModel(
|
|
|
178
178
|
name: collection.seo?.title ?? collection.title,
|
|
179
179
|
description: collection.seo?.description ?? collection.description,
|
|
180
180
|
items: result.entries.slice(0, 50).map((entry) => ({
|
|
181
|
-
url: entry.url.startsWith(
|
|
181
|
+
url: entry.url.startsWith('http') ? entry.url : absoluteUrl(siteUrl, entry.url),
|
|
182
182
|
name: entry.title,
|
|
183
183
|
...(entry.description ? { description: entry.description } : {}),
|
|
184
184
|
})),
|
|
185
185
|
crumbs: [
|
|
186
|
-
{ url: `${siteUrl}/`, name:
|
|
187
|
-
{ url: absoluteUrl(siteUrl,
|
|
186
|
+
{ url: `${siteUrl}/`, name: 'Home' },
|
|
187
|
+
{ url: absoluteUrl(siteUrl, 'collections/'), name: 'Collections' },
|
|
188
188
|
{ url: pageUrl, name: collection.title },
|
|
189
189
|
],
|
|
190
190
|
});
|
|
@@ -195,11 +195,8 @@ export function getCollectionPageModel(
|
|
|
195
195
|
title:
|
|
196
196
|
collection.seo?.title ??
|
|
197
197
|
seoTitle(`${collection.title} — ${result.entries.length} ${plural}`, siteName),
|
|
198
|
-
description: seoDescription(
|
|
199
|
-
|
|
200
|
-
collection.description,
|
|
201
|
-
),
|
|
202
|
-
image: ogPath("collection", collection.slug),
|
|
198
|
+
description: seoDescription(collection.seo?.description, collection.description),
|
|
199
|
+
image: ogPath('collection', collection.slug),
|
|
203
200
|
...(siteName ? { imageAlt: `${collection.title} — ${siteName}` } : {}),
|
|
204
201
|
jsonLd: jsonLd as unknown as Record<string, unknown>[],
|
|
205
202
|
noindex: collection.seo?.index === false,
|
|
@@ -225,7 +222,12 @@ export function getCollectionPageModel(
|
|
|
225
222
|
export function getCollectionIndexModel(
|
|
226
223
|
collections: Collection[],
|
|
227
224
|
entries: CollectionEntry[],
|
|
228
|
-
site?: {
|
|
225
|
+
site?: {
|
|
226
|
+
name?: string;
|
|
227
|
+
url?: string;
|
|
228
|
+
siteUrl?: string;
|
|
229
|
+
blueprintConfig?: { labelPlural?: string };
|
|
230
|
+
},
|
|
229
231
|
): CollectionIndexModel {
|
|
230
232
|
const rows = collections.map((c) => {
|
|
231
233
|
const result = runCollection(c, entries);
|
|
@@ -240,20 +242,20 @@ export function getCollectionIndexModel(
|
|
|
240
242
|
});
|
|
241
243
|
let seo: PageSeo | undefined;
|
|
242
244
|
if (site) {
|
|
243
|
-
const siteUrl = (site.siteUrl ?? site.url ??
|
|
244
|
-
const siteName = site.name ??
|
|
245
|
-
const plural = site.blueprintConfig?.labelPlural ??
|
|
246
|
-
const title = seoTitle(
|
|
245
|
+
const siteUrl = (site.siteUrl ?? site.url ?? 'https://example.com').replace(/\/$/, '');
|
|
246
|
+
const siteName = site.name ?? '';
|
|
247
|
+
const plural = site.blueprintConfig?.labelPlural ?? 'items';
|
|
248
|
+
const title = seoTitle('Collections', siteName);
|
|
247
249
|
const description = seoDescription(
|
|
248
250
|
undefined,
|
|
249
|
-
`${rows.length} curated and generated collections of ${plural} on ${siteName ||
|
|
251
|
+
`${rows.length} curated and generated collections of ${plural} on ${siteName || 'this site'} — hand-picked lists kept in sync with the source files.`,
|
|
250
252
|
);
|
|
251
253
|
seo = {
|
|
252
254
|
title,
|
|
253
255
|
description,
|
|
254
|
-
image: ogPath(
|
|
256
|
+
image: ogPath('default'),
|
|
255
257
|
jsonLd: collectionSchema({
|
|
256
|
-
url: absoluteUrl(siteUrl,
|
|
258
|
+
url: absoluteUrl(siteUrl, 'collections/'),
|
|
257
259
|
name: title,
|
|
258
260
|
description,
|
|
259
261
|
items: rows.map((row) => ({
|
|
@@ -262,8 +264,8 @@ export function getCollectionIndexModel(
|
|
|
262
264
|
...(row.description ? { description: row.description } : {}),
|
|
263
265
|
})),
|
|
264
266
|
crumbs: [
|
|
265
|
-
{ url: `${siteUrl}/`, name:
|
|
266
|
-
{ url: absoluteUrl(siteUrl,
|
|
267
|
+
{ url: `${siteUrl}/`, name: 'Home' },
|
|
268
|
+
{ url: absoluteUrl(siteUrl, 'collections/'), name: 'Collections' },
|
|
267
269
|
],
|
|
268
270
|
}) as unknown as Record<string, unknown>[],
|
|
269
271
|
};
|
|
@@ -300,7 +302,16 @@ export function getCollectionTeaserModel(
|
|
|
300
302
|
* label without re-loading the collection YAML.
|
|
301
303
|
*/
|
|
302
304
|
export function findCollectionsFor(
|
|
303
|
-
target: {
|
|
305
|
+
target: {
|
|
306
|
+
slug?: string;
|
|
307
|
+
stack?: string;
|
|
308
|
+
stacks?: string[];
|
|
309
|
+
platforms?: string[];
|
|
310
|
+
licenses?: string[];
|
|
311
|
+
category?: string;
|
|
312
|
+
visibility?: string;
|
|
313
|
+
status?: string;
|
|
314
|
+
},
|
|
304
315
|
collections: Collection[],
|
|
305
316
|
entries: CollectionEntry[],
|
|
306
317
|
): { slug: string; title: string; url: string }[] {
|
package/src/server/contrast.ts
CHANGED
|
@@ -9,16 +9,22 @@
|
|
|
9
9
|
* values are plain hex.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
const INK_950 =
|
|
13
|
-
const WHITE =
|
|
12
|
+
const INK_950 = '#0a0a0a';
|
|
13
|
+
const WHITE = '#ffffff';
|
|
14
14
|
const AA_NORMAL = 4.5;
|
|
15
15
|
|
|
16
16
|
export type Rgb = [number, number, number];
|
|
17
17
|
|
|
18
18
|
/** Parse #rgb / #rrggbb (also tolerates #rrggbbaa, alpha ignored). */
|
|
19
19
|
export function hexToRgb(hex: string): Rgb | null {
|
|
20
|
-
const raw = hex.replace(
|
|
21
|
-
const full =
|
|
20
|
+
const raw = hex.replace('#', '');
|
|
21
|
+
const full =
|
|
22
|
+
raw.length === 3
|
|
23
|
+
? raw
|
|
24
|
+
.split('')
|
|
25
|
+
.map((c) => c + c)
|
|
26
|
+
.join('')
|
|
27
|
+
: raw;
|
|
22
28
|
if (!/^[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/.test(full)) return null;
|
|
23
29
|
const int = Number.parseInt(full.slice(0, 6), 16);
|
|
24
30
|
return [(int >> 16) & 255, (int >> 8) & 255, int & 255];
|
|
@@ -26,7 +32,7 @@ export function hexToRgb(hex: string): Rgb | null {
|
|
|
26
32
|
|
|
27
33
|
export function rgbToHex([r, g, b]: Rgb): string {
|
|
28
34
|
const clamp = (v: number) => Math.max(0, Math.min(255, Math.round(v)));
|
|
29
|
-
return `#${[r, g, b].map((v) => clamp(v).toString(16).padStart(2,
|
|
35
|
+
return `#${[r, g, b].map((v) => clamp(v).toString(16).padStart(2, '0')).join('')}`;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
/** WCAG relative luminance (sRGB linearization, not the quick luma). */
|
|
@@ -104,14 +110,13 @@ export function derivePrimaryPalette(hex: string): PrimaryPalette | null {
|
|
|
104
110
|
} else if (contrastRatio(hex, INK_950) >= AA_NORMAL) {
|
|
105
111
|
solidForeground = INK_950;
|
|
106
112
|
} else {
|
|
107
|
-
solid = adjustUntilAA(hex,
|
|
113
|
+
solid = adjustUntilAA(hex, '#000000', WHITE);
|
|
108
114
|
solidForeground = WHITE;
|
|
109
115
|
}
|
|
110
116
|
|
|
111
117
|
const lifted = rgbToHex(mix(rgb, hexToRgb(WHITE) as Rgb, 0.28));
|
|
112
|
-
const dark =
|
|
113
|
-
? lifted
|
|
114
|
-
: adjustUntilAA(lifted, WHITE, INK_950);
|
|
118
|
+
const dark =
|
|
119
|
+
contrastRatio(lifted, INK_950) >= AA_NORMAL ? lifted : adjustUntilAA(lifted, WHITE, INK_950);
|
|
115
120
|
|
|
116
121
|
return { solid, solidForeground, dark, darkForeground: INK_950 };
|
|
117
122
|
}
|
package/src/server/directory.ts
CHANGED
|
@@ -30,27 +30,28 @@
|
|
|
30
30
|
* resolution error, which is the correct signal — a build that
|
|
31
31
|
* silently renders an empty directory hides real config mistakes.
|
|
32
32
|
*/
|
|
33
|
+
|
|
34
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
35
|
+
import { dirname, resolve } from 'node:path';
|
|
36
|
+
import { fileURLToPath } from 'node:url';
|
|
33
37
|
import fullPayload from '@grove/generated/records.full.json';
|
|
34
38
|
import indexPayload from '@grove/generated/records.index.json';
|
|
35
39
|
import siteConfigPayload from '@grove/generated/site-config.json';
|
|
36
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
37
|
-
import { fileURLToPath } from 'node:url';
|
|
38
|
-
import { dirname, resolve } from 'node:path';
|
|
39
|
-
import { marked } from 'marked';
|
|
40
|
-
import sanitizeHtml from 'sanitize-html';
|
|
41
|
-
import { getSingletonHighlighter } from 'shiki';
|
|
42
|
-
import { prettySlug } from '../lib/display.js';
|
|
43
|
-
import { headingSlug, readContentFile, stripFrontmatter, uniqueSlug } from '@grove-dev/core';
|
|
44
40
|
import type {
|
|
45
|
-
ProjectRecord,
|
|
46
|
-
ResourceRecord,
|
|
47
41
|
EntityRecord,
|
|
48
|
-
|
|
49
|
-
IndexRecord,
|
|
42
|
+
IndexEntityRecord,
|
|
50
43
|
IndexProjectRecord,
|
|
44
|
+
IndexRecord,
|
|
51
45
|
IndexResourceRecord,
|
|
52
|
-
|
|
46
|
+
ProjectRecord,
|
|
47
|
+
Resource,
|
|
48
|
+
ResourceRecord,
|
|
53
49
|
} from '@grove-dev/core';
|
|
50
|
+
import { headingSlug, readContentFile, stripFrontmatter, uniqueSlug } from '@grove-dev/core';
|
|
51
|
+
import { marked } from 'marked';
|
|
52
|
+
import sanitizeHtml from 'sanitize-html';
|
|
53
|
+
import { getSingletonHighlighter } from 'shiki';
|
|
54
|
+
import { prettySlug } from '../lib/display.js';
|
|
54
55
|
|
|
55
56
|
interface FullPayload {
|
|
56
57
|
schemaVersion?: number;
|
|
@@ -676,10 +677,14 @@ const SUPPORTED_LANGS = [
|
|
|
676
677
|
'properties',
|
|
677
678
|
];
|
|
678
679
|
const globalAny = globalThis as GlobalWithShiki;
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
680
|
+
const pendingHighlighter =
|
|
681
|
+
globalAny[SHIKI_HIGHLIGHTER] ??
|
|
682
|
+
getSingletonHighlighter({
|
|
683
|
+
themes: ['github-light', 'github-dark-default'],
|
|
684
|
+
langs: SUPPORTED_LANGS,
|
|
685
|
+
});
|
|
686
|
+
globalAny[SHIKI_HIGHLIGHTER] = pendingHighlighter;
|
|
687
|
+
const highlighter = await pendingHighlighter;
|
|
683
688
|
|
|
684
689
|
// Release the previous engine's WASM heap on HMR. Without this the
|
|
685
690
|
// old engine is unreachable but not disposed, which is the leak
|
package/src/server/index.ts
CHANGED