@mui/internal-docs-infra 0.12.1-canary.45 → 0.12.1-canary.47
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/createSitemap/index.d.mts +2 -1
- package/createSitemap/types.d.mts +27 -0
- package/package.json +22 -2
- package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.d.mts +1 -1
- package/pipeline/loadServerPageIndex/enrichPageIndex.mjs +12 -2
- package/pipeline/loadServerPageIndex/extractPrefixAndTitle.mjs +2 -1
- package/pipeline/loadServerPageIndex/loadServerPageIndex.d.mts +1 -1
- package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.d.mts +9 -2
- package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.mjs +9 -2
- package/pipeline/loaderUtils/extractNameAndSlugFromUrl.mjs +1 -31
- package/pipeline/loaderUtils/index.d.mts +2 -1
- package/pipeline/loaderUtils/index.mjs +2 -1
- package/pipeline/loaderUtils/kebabToTitleCase.d.mts +11 -0
- package/pipeline/loaderUtils/kebabToTitleCase.mjs +34 -0
- package/pipeline/loaderUtils/stripRouteGroups.d.mts +36 -0
- package/pipeline/loaderUtils/stripRouteGroups.mjs +44 -0
- package/pipeline/parseSource/index.d.mts +1 -1
- package/pipeline/parseSource/index.mjs +1 -1
- package/pipeline/parseSource/parseSource.d.mts +11 -1
- package/pipeline/parseSource/parseSource.mjs +15 -0
- package/pipeline/syncPageIndex/mergeMetadataMarkdown.d.mts +7 -0
- package/pipeline/syncPageIndex/mergeMetadataMarkdown.mjs +156 -18
- package/pipeline/syncPageIndex/metadataToMarkdown.d.mts +147 -1
- package/pipeline/syncPageIndex/metadataToMarkdown.mjs +446 -71
- package/pipeline/syncPageIndex/syncPageIndex.d.mts +14 -1
- package/pipeline/syncPageIndex/syncPageIndex.mjs +21 -19
- package/pipeline/syncTypes/syncTypes.mjs +6 -4
- package/pipeline/transformHtmlCodeInline/transformHtmlCodeInline.mjs +18 -50
- package/pipeline/transformMarkdownMetadata/transformMarkdownMetadata.mjs +19 -31
- package/pipeline/transformMarkdownMetadata/types.d.mts +1 -1
- package/pipeline/transformMarkdownRelativePaths/transformMarkdownRelativePaths.mjs +5 -2
- package/resolvePageUrl/index.d.mts +1 -0
- package/resolvePageUrl/index.mjs +1 -0
- package/resolvePageUrl/resolvePageUrl.d.mts +12 -0
- package/resolvePageUrl/resolvePageUrl.mjs +27 -0
- package/useSearch/useSearch.mjs +3 -1
- package/withDocsInfra/withDocsInfra.d.mts +2 -2
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from "./createSitemap.mjs";
|
|
1
|
+
export * from "./createSitemap.mjs";
|
|
2
|
+
export type * from "./types.mjs";
|
|
@@ -41,11 +41,30 @@ export interface SitemapPage {
|
|
|
41
41
|
skipDetailSection?: boolean;
|
|
42
42
|
audience?: Audience;
|
|
43
43
|
index?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* The title of the route-group section this page is listed under in a grouped index
|
|
46
|
+
* (e.g. `Components`), resolved from the page's route group. `null` for a page in a flat
|
|
47
|
+
* index or with no route group, so the field is always present. Useful for
|
|
48
|
+
* grouping/faceting search results.
|
|
49
|
+
*/
|
|
50
|
+
section: string | null;
|
|
44
51
|
image?: {
|
|
45
52
|
url: string;
|
|
46
53
|
alt?: string;
|
|
47
54
|
};
|
|
48
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* A route-group section heading in a grouped index (see `SitemapSectionData.sections`).
|
|
58
|
+
* Maps a Next.js route group to the human-editable heading its pages are listed under.
|
|
59
|
+
*/
|
|
60
|
+
export interface PageIndexSection {
|
|
61
|
+
/** The route group this section collects (e.g. `(components)`). */
|
|
62
|
+
group: string;
|
|
63
|
+
/** The (human-editable) heading text shown for the section. */
|
|
64
|
+
title: string;
|
|
65
|
+
/** Heading depth for the section title. Defaults to 2 (`##`). */
|
|
66
|
+
depth?: number;
|
|
67
|
+
}
|
|
49
68
|
/**
|
|
50
69
|
* Section data from sitemap
|
|
51
70
|
*/
|
|
@@ -53,6 +72,14 @@ export interface SitemapSectionData {
|
|
|
53
72
|
title: string;
|
|
54
73
|
prefix: string;
|
|
55
74
|
pages: SitemapPage[];
|
|
75
|
+
/**
|
|
76
|
+
* Ordered route-group sections when the index is grouped (its `##` subtitles), so
|
|
77
|
+
* search can recover the sections a page belongs to. An empty array for a flat index,
|
|
78
|
+
* so the field is always present.
|
|
79
|
+
*/
|
|
80
|
+
sections: PageIndexSection[];
|
|
81
|
+
/** Heading of the detail-region wrapper in a grouped index (defaults to `Details`). */
|
|
82
|
+
detailsSectionTitle?: string;
|
|
56
83
|
}
|
|
57
84
|
/**
|
|
58
85
|
* Orama schema property types
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mui/internal-docs-infra",
|
|
3
|
-
"version": "0.12.1-canary.
|
|
3
|
+
"version": "0.12.1-canary.47",
|
|
4
4
|
"author": "MUI Team",
|
|
5
5
|
"description": "MUI Infra - internal documentation creation tools.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -281,6 +281,26 @@
|
|
|
281
281
|
"default": "./createSitemap/types.mjs"
|
|
282
282
|
}
|
|
283
283
|
},
|
|
284
|
+
"./resolvePageUrl": {
|
|
285
|
+
"import": {
|
|
286
|
+
"types": "./resolvePageUrl/index.d.mts",
|
|
287
|
+
"default": "./resolvePageUrl/index.mjs"
|
|
288
|
+
},
|
|
289
|
+
"default": {
|
|
290
|
+
"types": "./resolvePageUrl/index.d.mts",
|
|
291
|
+
"default": "./resolvePageUrl/index.mjs"
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
"./routeGroups": {
|
|
295
|
+
"import": {
|
|
296
|
+
"types": "./pipeline/loaderUtils/stripRouteGroups.d.mts",
|
|
297
|
+
"default": "./pipeline/loaderUtils/stripRouteGroups.mjs"
|
|
298
|
+
},
|
|
299
|
+
"default": {
|
|
300
|
+
"types": "./pipeline/loaderUtils/stripRouteGroups.d.mts",
|
|
301
|
+
"default": "./pipeline/loaderUtils/stripRouteGroups.mjs"
|
|
302
|
+
}
|
|
303
|
+
},
|
|
284
304
|
"./useStream": {
|
|
285
305
|
"import": {
|
|
286
306
|
"types": "./useStream/index.d.mts",
|
|
@@ -795,5 +815,5 @@
|
|
|
795
815
|
"bin": {
|
|
796
816
|
"docs-infra": "./cli/index.mjs"
|
|
797
817
|
},
|
|
798
|
-
"gitSha": "
|
|
818
|
+
"gitSha": "81765a8f621d2dc77469da42ae427c0b7e680e4f"
|
|
799
819
|
}
|
|
@@ -8,7 +8,7 @@ export type LoaderOptions = {
|
|
|
8
8
|
};
|
|
9
9
|
/**
|
|
10
10
|
* Directory for the sha256-validated JSON cache of parsed page indexes. When set,
|
|
11
|
-
* unchanged indexes are read from `{cacheDir}/pages-index/{route}.json` instead of
|
|
11
|
+
* unchanged indexes are read from `{cacheDir}/pages-index-v2/{route}.json` instead of
|
|
12
12
|
* being re-parsed.
|
|
13
13
|
*/
|
|
14
14
|
cacheDir?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { extractPrefixAndTitle, stripTitleMarkdown } from "./extractPrefixAndTitle.mjs";
|
|
2
|
-
import { collapseInlineWhitespace } from "../syncPageIndex/metadataToMarkdown.mjs";
|
|
2
|
+
import { collapseInlineWhitespace, createPageSectionResolver } from "../syncPageIndex/metadataToMarkdown.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* Converts parsed page-index metadata into the `SitemapSectionData` read-model.
|
|
5
5
|
*
|
|
@@ -18,10 +18,15 @@ export function enrichPageIndex(metadata, absolutePath, rootContext) {
|
|
|
18
18
|
prefix,
|
|
19
19
|
title
|
|
20
20
|
} = extractPrefixAndTitle(absolutePath, rootContext);
|
|
21
|
+
|
|
22
|
+
// Resolve each page's section title from its route group (grouped indexes only).
|
|
23
|
+
const resolveSection = createPageSectionResolver(metadata.sections);
|
|
21
24
|
return {
|
|
22
25
|
...metadata,
|
|
23
26
|
prefix,
|
|
24
27
|
title,
|
|
28
|
+
// Always present so consumers never branch on absence: an empty array for a flat index.
|
|
29
|
+
sections: metadata.sections ?? [],
|
|
25
30
|
// Normalize the index's own (leaked) description like the parser. Spread instead of an explicit
|
|
26
31
|
// key because SitemapSectionData does not declare `description`.
|
|
27
32
|
...(metadata.description !== undefined ? {
|
|
@@ -35,6 +40,7 @@ export function enrichPageIndex(metadata, absolutePath, rootContext) {
|
|
|
35
40
|
const {
|
|
36
41
|
descriptionMarkdown,
|
|
37
42
|
sections,
|
|
43
|
+
sectionGroup,
|
|
38
44
|
...pageWithoutMarkdown
|
|
39
45
|
} = page;
|
|
40
46
|
return {
|
|
@@ -43,7 +49,11 @@ export function enrichPageIndex(metadata, absolutePath, rootContext) {
|
|
|
43
49
|
keywords: page.keywords?.map(collapseInlineWhitespace),
|
|
44
50
|
types: page.types?.map(collapseInlineWhitespace),
|
|
45
51
|
// Strip titleMarkdown from the sections hierarchy.
|
|
46
|
-
sections: sections ? stripTitleMarkdown(sections) : undefined
|
|
52
|
+
sections: sections ? stripTitleMarkdown(sections) : undefined,
|
|
53
|
+
// Resolve the route-group section title for grouped indexes (search faceting),
|
|
54
|
+
// honoring the header a human filed an otherwise-ungrouped page under. Always present
|
|
55
|
+
// (`null` when the page has no section) so consumers never branch on absence.
|
|
56
|
+
section: resolveSection(page.path, sectionGroup) ?? null
|
|
47
57
|
};
|
|
48
58
|
})
|
|
49
59
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { isRouteGroup } from "../loaderUtils/stripRouteGroups.mjs";
|
|
2
3
|
/**
|
|
3
4
|
* Converts a path segment to a title
|
|
4
5
|
* e.g., "docs-infra" -> "Docs Infra", "components" -> "Components"
|
|
@@ -58,7 +59,7 @@ export function extractPrefixAndTitle(absolutePath, rootContext) {
|
|
|
58
59
|
return false;
|
|
59
60
|
}
|
|
60
61
|
// Filter out Next.js route groups (e.g., '(public)', '(content)')
|
|
61
|
-
if (
|
|
62
|
+
if (isRouteGroup(seg)) {
|
|
62
63
|
return false;
|
|
63
64
|
}
|
|
64
65
|
// Filter out current directory markers
|
|
@@ -11,7 +11,7 @@ export interface CreateLoadServerPageIndexOptions {
|
|
|
11
11
|
/**
|
|
12
12
|
* Directory for the sha256-validated JSON cache of parsed page indexes.
|
|
13
13
|
*
|
|
14
|
-
* When set, a read first checks `{cacheDir}/pages-index/{route}.json`; on a hash
|
|
14
|
+
* When set, a read first checks `{cacheDir}/pages-index-v2/{route}.json`; on a hash
|
|
15
15
|
* match it returns the cached data and skips the markdown parse, and on a miss it
|
|
16
16
|
* parses, writes the cache, and returns. When unset, no cache is read or written.
|
|
17
17
|
*/
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Cache namespace (subdirectory) for page-index entries. The `-v2` suffix is a schema version:
|
|
3
|
+
* grouped indexes added always-present `sections` and per-page `section` fields to the cached
|
|
4
|
+
* read-model, so a pre-existing `pages-index` entry (keyed only by content hash) could otherwise
|
|
5
|
+
* survive a docs-infra upgrade and serve the old shape for an unchanged index file. Bumping the
|
|
6
|
+
* namespace forces a clean miss the first time the new code runs. Bump again on any future
|
|
7
|
+
* breaking change to the cached page-index shape.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PAGE_INDEX_CACHE_NAMESPACE = "pages-index-v2";
|
|
3
10
|
/**
|
|
4
11
|
* Derives the cache key for a page-index file from its path, reusing the same
|
|
5
12
|
* route derivation as the loaded data so a writer and reader of the same index
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { extractPrefixAndTitle } from "./extractPrefixAndTitle.mjs";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Cache namespace (subdirectory) for page-index entries. The `-v2` suffix is a schema version:
|
|
5
|
+
* grouped indexes added always-present `sections` and per-page `section` fields to the cached
|
|
6
|
+
* read-model, so a pre-existing `pages-index` entry (keyed only by content hash) could otherwise
|
|
7
|
+
* survive a docs-infra upgrade and serve the old shape for an unchanged index file. Bumping the
|
|
8
|
+
* namespace forces a clean miss the first time the new code runs. Bump again on any future
|
|
9
|
+
* breaking change to the cached page-index shape.
|
|
10
|
+
*/
|
|
11
|
+
export const PAGE_INDEX_CACHE_NAMESPACE = 'pages-index-v2';
|
|
5
12
|
|
|
6
13
|
/**
|
|
7
14
|
* Derives the cache key for a page-index file from its path, reusing the same
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fileUrlToPortablePath } from "./fileUrlToPortablePath.mjs";
|
|
2
|
+
import { kebabToTitleCase } from "./kebabToTitleCase.mjs";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Extracts and formats a name and slug from a URL path.
|
|
@@ -42,37 +43,6 @@ function camelToTitleCase(camelCase) {
|
|
|
42
43
|
.replace(/^./, str => str.toUpperCase());
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
/**
|
|
46
|
-
* Known brand names and acronyms that have a canonical capitalization.
|
|
47
|
-
* Keys are lowercase, values are the canonical form to use in titles.
|
|
48
|
-
*/
|
|
49
|
-
const BRAND_NAME_OVERRIDES = {
|
|
50
|
-
javascript: 'JavaScript',
|
|
51
|
-
typescript: 'TypeScript'
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Capitalizes a single word, applying brand-name overrides when applicable.
|
|
56
|
-
*/
|
|
57
|
-
function capitalizeWord(word) {
|
|
58
|
-
const lower = word.toLowerCase();
|
|
59
|
-
const override = BRAND_NAME_OVERRIDES[lower];
|
|
60
|
-
if (override) {
|
|
61
|
-
return override;
|
|
62
|
-
}
|
|
63
|
-
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Converts a kebab-case string to Title Case
|
|
68
|
-
* @param kebabCase - The kebab-case string to convert
|
|
69
|
-
* @returns Title case string
|
|
70
|
-
*/
|
|
71
|
-
function kebabToTitleCase(kebabCase) {
|
|
72
|
-
return kebabCase.split(/[-_]/) // Split on both hyphens and underscores
|
|
73
|
-
.map(capitalizeWord).join(' ');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
46
|
/**
|
|
77
47
|
* Detects if a string is camelCase or PascalCase
|
|
78
48
|
* @param str - The string to check
|
|
@@ -7,4 +7,5 @@ export * from "./extractNameAndSlugFromUrl.mjs";
|
|
|
7
7
|
export * from "./externalsToPackages.mjs";
|
|
8
8
|
export * from "./fileUrlToPortablePath.mjs";
|
|
9
9
|
export * from "./getLanguageFromExtension.mjs";
|
|
10
|
-
export * from "./generateFileSlug.mjs";
|
|
10
|
+
export * from "./generateFileSlug.mjs";
|
|
11
|
+
export * from "./stripRouteGroups.mjs";
|
|
@@ -7,4 +7,5 @@ export * from "./extractNameAndSlugFromUrl.mjs";
|
|
|
7
7
|
export * from "./externalsToPackages.mjs";
|
|
8
8
|
export * from "./fileUrlToPortablePath.mjs";
|
|
9
9
|
export * from "./getLanguageFromExtension.mjs";
|
|
10
|
-
export * from "./generateFileSlug.mjs";
|
|
10
|
+
export * from "./generateFileSlug.mjs";
|
|
11
|
+
export * from "./stripRouteGroups.mjs";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a kebab-case (or snake_case) string to Title Case, honoring brand-name overrides
|
|
3
|
+
* (e.g. `javascript` -> `JavaScript`). This is the single title-casing rule shared by the
|
|
4
|
+
* producers that turn a slug/folder name into a display title — directory-derived index titles,
|
|
5
|
+
* URL-segment names, and route-group section headings — so those titles never diverge.
|
|
6
|
+
*
|
|
7
|
+
* @example kebabToTitleCase('alert-dialog') -> 'Alert Dialog'
|
|
8
|
+
* @example kebabToTitleCase('getting_started') -> 'Getting Started'
|
|
9
|
+
* @example kebabToTitleCase('typescript') -> 'TypeScript'
|
|
10
|
+
*/
|
|
11
|
+
export declare function kebabToTitleCase(kebabCase: string): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Known brand names and acronyms that have a canonical capitalization.
|
|
3
|
+
* Keys are lowercase, values are the canonical form to use in titles.
|
|
4
|
+
*/
|
|
5
|
+
const BRAND_NAME_OVERRIDES = {
|
|
6
|
+
javascript: 'JavaScript',
|
|
7
|
+
typescript: 'TypeScript'
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Capitalizes a single word, applying brand-name overrides when applicable.
|
|
12
|
+
*/
|
|
13
|
+
function capitalizeWord(word) {
|
|
14
|
+
const lower = word.toLowerCase();
|
|
15
|
+
const override = BRAND_NAME_OVERRIDES[lower];
|
|
16
|
+
if (override) {
|
|
17
|
+
return override;
|
|
18
|
+
}
|
|
19
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Converts a kebab-case (or snake_case) string to Title Case, honoring brand-name overrides
|
|
24
|
+
* (e.g. `javascript` -> `JavaScript`). This is the single title-casing rule shared by the
|
|
25
|
+
* producers that turn a slug/folder name into a display title — directory-derived index titles,
|
|
26
|
+
* URL-segment names, and route-group section headings — so those titles never diverge.
|
|
27
|
+
*
|
|
28
|
+
* @example kebabToTitleCase('alert-dialog') -> 'Alert Dialog'
|
|
29
|
+
* @example kebabToTitleCase('getting_started') -> 'Getting Started'
|
|
30
|
+
* @example kebabToTitleCase('typescript') -> 'TypeScript'
|
|
31
|
+
*/
|
|
32
|
+
export function kebabToTitleCase(kebabCase) {
|
|
33
|
+
return kebabCase.split(/[-_]/).map(capitalizeWord).join(' ');
|
|
34
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a single path segment is a Next.js route group: a directory name wrapped in
|
|
3
|
+
* parentheses (e.g. `(overview)`). Route groups organize files without appearing in the public
|
|
4
|
+
* URL. This is the one shared definition used by page grouping, parent-index resolution, and
|
|
5
|
+
* path-to-URL resolution.
|
|
6
|
+
*
|
|
7
|
+
* Because it tests a whole segment, a segment that merely contains parentheses (e.g.
|
|
8
|
+
* `(draft)notes`) is not a route group and is kept.
|
|
9
|
+
*
|
|
10
|
+
* @example isRouteGroup('(overview)') -> true
|
|
11
|
+
* @example isRouteGroup('components') -> false
|
|
12
|
+
* @example isRouteGroup('(draft)notes') -> false
|
|
13
|
+
*/
|
|
14
|
+
export declare function isRouteGroup(segment: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The name inside a route-group segment (e.g. `(overview)` -> `overview`), or `undefined` when the
|
|
17
|
+
* segment is not a whole route group. Uses the same whole-segment rule as {@link isRouteGroup}, so
|
|
18
|
+
* callers get one definition of the parenthesis convention instead of re-deriving it. Useful for
|
|
19
|
+
* mapping a route group back to a section (e.g. resolving a section's default landing page).
|
|
20
|
+
*
|
|
21
|
+
* @example routeGroupName('(overview)') -> 'overview'
|
|
22
|
+
* @example routeGroupName('components') -> undefined
|
|
23
|
+
* @example routeGroupName('(draft)notes') -> undefined
|
|
24
|
+
*/
|
|
25
|
+
export declare function routeGroupName(segment: string): string | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Removes whole Next.js route-group segments (`(group)`) from a `/`-separated path or URL, since
|
|
28
|
+
* they do not appear in the public URL, keeping every other segment intact. It splits on `/` and
|
|
29
|
+
* filters whole segments with {@link isRouteGroup}, so a folder that merely contains parentheses
|
|
30
|
+
* (e.g. `(draft)notes`) stays in the path. This is the one whole-segment rule the grouped index,
|
|
31
|
+
* rendered links, and search URL resolution all share.
|
|
32
|
+
*
|
|
33
|
+
* @example stripRouteGroupSegments('/components/(inputs)/checkbox') -> '/components/checkbox'
|
|
34
|
+
* @example stripRouteGroupSegments('/(draft)notes/guide') -> '/(draft)notes/guide'
|
|
35
|
+
*/
|
|
36
|
+
export declare function stripRouteGroupSegments(pathOrUrl: string): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a single path segment is a Next.js route group: a directory name wrapped in
|
|
3
|
+
* parentheses (e.g. `(overview)`). Route groups organize files without appearing in the public
|
|
4
|
+
* URL. This is the one shared definition used by page grouping, parent-index resolution, and
|
|
5
|
+
* path-to-URL resolution.
|
|
6
|
+
*
|
|
7
|
+
* Because it tests a whole segment, a segment that merely contains parentheses (e.g.
|
|
8
|
+
* `(draft)notes`) is not a route group and is kept.
|
|
9
|
+
*
|
|
10
|
+
* @example isRouteGroup('(overview)') -> true
|
|
11
|
+
* @example isRouteGroup('components') -> false
|
|
12
|
+
* @example isRouteGroup('(draft)notes') -> false
|
|
13
|
+
*/
|
|
14
|
+
export function isRouteGroup(segment) {
|
|
15
|
+
return segment.startsWith('(') && segment.endsWith(')');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The name inside a route-group segment (e.g. `(overview)` -> `overview`), or `undefined` when the
|
|
20
|
+
* segment is not a whole route group. Uses the same whole-segment rule as {@link isRouteGroup}, so
|
|
21
|
+
* callers get one definition of the parenthesis convention instead of re-deriving it. Useful for
|
|
22
|
+
* mapping a route group back to a section (e.g. resolving a section's default landing page).
|
|
23
|
+
*
|
|
24
|
+
* @example routeGroupName('(overview)') -> 'overview'
|
|
25
|
+
* @example routeGroupName('components') -> undefined
|
|
26
|
+
* @example routeGroupName('(draft)notes') -> undefined
|
|
27
|
+
*/
|
|
28
|
+
export function routeGroupName(segment) {
|
|
29
|
+
return isRouteGroup(segment) ? segment.slice(1, -1) : undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Removes whole Next.js route-group segments (`(group)`) from a `/`-separated path or URL, since
|
|
34
|
+
* they do not appear in the public URL, keeping every other segment intact. It splits on `/` and
|
|
35
|
+
* filters whole segments with {@link isRouteGroup}, so a folder that merely contains parentheses
|
|
36
|
+
* (e.g. `(draft)notes`) stays in the path. This is the one whole-segment rule the grouped index,
|
|
37
|
+
* rendered links, and search URL resolution all share.
|
|
38
|
+
*
|
|
39
|
+
* @example stripRouteGroupSegments('/components/(inputs)/checkbox') -> '/components/checkbox'
|
|
40
|
+
* @example stripRouteGroupSegments('/(draft)notes/guide') -> '/(draft)notes/guide'
|
|
41
|
+
*/
|
|
42
|
+
export function stripRouteGroupSegments(pathOrUrl) {
|
|
43
|
+
return pathOrUrl.split('/').filter(segment => !isRouteGroup(segment)).join('/');
|
|
44
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { createParseSource, parsePlainText, parseSource, registerAllGrammars, registerGrammars, resetStarryNight } from "./parseSource.mjs";
|
|
2
2
|
export { getGrammarFromLanguage, languageToGrammarMap, extensionMap } from "./grammarMaps.mjs";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { createParseSource, parsePlainText, parseSource, registerAllGrammars, registerGrammars, resetStarryNight } from "./parseSource.mjs";
|
|
2
2
|
export { getGrammarFromLanguage, languageToGrammarMap, extensionMap } from "./grammarMaps.mjs";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { createStarryNight } from '@wooorm/starry-night';
|
|
1
2
|
import type { ParseSource } from "../../CodeHighlighter/types.mjs";
|
|
3
|
+
type StarryNight = Awaited<ReturnType<typeof createStarryNight>>;
|
|
2
4
|
/**
|
|
3
5
|
* Parses source into a line-guttered HAST **without** syntax highlighting — the
|
|
4
6
|
* raw text wrapped in the same `.line`/`.frame` structure `parseSource` produces,
|
|
@@ -51,8 +53,16 @@ export declare function registerAllGrammars(): Promise<void>;
|
|
|
51
53
|
* @returns A Promise that resolves to the initialized `parseSource` function
|
|
52
54
|
*/
|
|
53
55
|
export declare const createParseSource: (initialScopes?: string[]) => Promise<ParseSource>;
|
|
56
|
+
/**
|
|
57
|
+
* Returns the shared Starry Night instance after registering every grammar.
|
|
58
|
+
*
|
|
59
|
+
* Inline highlighting can follow code that initialized a lazy subset, so it must
|
|
60
|
+
* initialize the complete registry before using the shared instance.
|
|
61
|
+
*/
|
|
62
|
+
export declare function getStarryNightInstance(): Promise<StarryNight>;
|
|
54
63
|
/**
|
|
55
64
|
* Clears the global Starry Night singleton and registration state. Intended for
|
|
56
65
|
* tests exercising lazy registration from a known-empty registry.
|
|
57
66
|
*/
|
|
58
|
-
export declare function resetStarryNight(): void;
|
|
67
|
+
export declare function resetStarryNight(): void;
|
|
68
|
+
export {};
|
|
@@ -232,6 +232,21 @@ export const createParseSource = async initialScopes => {
|
|
|
232
232
|
return parseSource;
|
|
233
233
|
};
|
|
234
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Returns the shared Starry Night instance after registering every grammar.
|
|
237
|
+
*
|
|
238
|
+
* Inline highlighting can follow code that initialized a lazy subset, so it must
|
|
239
|
+
* initialize the complete registry before using the shared instance.
|
|
240
|
+
*/
|
|
241
|
+
export async function getStarryNightInstance() {
|
|
242
|
+
await createParseSource();
|
|
243
|
+
const instance = getInstance();
|
|
244
|
+
if (!instance) {
|
|
245
|
+
throw new Error('Starry Night failed to initialize.');
|
|
246
|
+
}
|
|
247
|
+
return instance;
|
|
248
|
+
}
|
|
249
|
+
|
|
235
250
|
/**
|
|
236
251
|
* Clears the global Starry Night singleton and registration state. Intended for
|
|
237
252
|
* tests exercising lazy registration from a known-empty registry.
|
|
@@ -59,6 +59,13 @@ export declare function mergeMetadataPages(existingMarkdown: string | undefined,
|
|
|
59
59
|
* This allows multiple pages to have the same slug (anchor) while still being treated
|
|
60
60
|
* as distinct pages.
|
|
61
61
|
*
|
|
62
|
+
* Known limitation: matching is by exact path, so a page whose stored path changes format —
|
|
63
|
+
* notably an index first regenerated after route groups became path-preserving, where an old
|
|
64
|
+
* entry `./accordion/page.mdx` no longer matches the new `./(components)/accordion/page.mdx` —
|
|
65
|
+
* is not reconciled with its old entry and can briefly duplicate. This is accepted rather than
|
|
66
|
+
* matched by route-group-stripped path (two distinct pages `./(a)/x` and `./(b)/x` share one
|
|
67
|
+
* stripped path), since grouped indexes are net-new; a stale entry clears once removed by hand.
|
|
68
|
+
*
|
|
62
69
|
* @param existingMarkdown - The existing markdown content (or undefined if none exists)
|
|
63
70
|
* @param newMetadata - The new metadata to merge in
|
|
64
71
|
* @param options - Optional configuration
|