@stainless-api/docs 0.1.0-beta.2 → 0.1.0-beta.21
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/CHANGELOG.md +153 -0
- package/components/variables.css +1 -27
- package/eslint-suppressions.json +47 -0
- package/locals.d.ts +14 -0
- package/package.json +30 -27
- package/plugin/buildAlgoliaIndex.ts +29 -4
- package/plugin/cms/server.ts +97 -54
- package/plugin/cms/sidebar-builder.ts +6 -25
- package/plugin/cms/worker.ts +2 -2
- package/plugin/components/SnippetCode.tsx +7 -4
- package/plugin/components/search/SearchAlgolia.astro +0 -7
- package/plugin/components/search/SearchIsland.tsx +30 -17
- package/plugin/generateAPIReferenceLink.ts +1 -1
- package/plugin/globalJs/ai-dropdown-options.ts +161 -0
- package/plugin/globalJs/navigation.ts +0 -23
- package/plugin/helpers/getPageLoadEvent.ts +1 -1
- package/plugin/index.ts +48 -17
- package/plugin/languages.ts +1 -1
- package/plugin/loadPluginConfig.ts +100 -13
- package/plugin/react/Routing.tsx +30 -33
- package/plugin/referencePlaceholderUtils.ts +1 -1
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +4 -0
- package/plugin/routes/Docs.astro +59 -85
- package/plugin/routes/Overview.astro +9 -15
- package/plugin/routes/markdown.ts +1 -1
- package/plugin/vendor/preview.worker.docs.js +6357 -6132
- package/resolveSrcFile.ts +10 -0
- package/shared/getSharedLogger.ts +15 -0
- package/shared/terminalUtils.ts +3 -0
- package/src/content.config.ts +9 -0
- package/stl-docs/components/AIDropdown.tsx +52 -0
- package/stl-docs/components/Head.astro +9 -0
- package/stl-docs/components/Header.astro +3 -2
- package/stl-docs/components/PageTitle.astro +64 -0
- package/stl-docs/components/TableOfContents.astro +34 -0
- package/stl-docs/components/ThemeSelect.astro +4 -2
- package/stl-docs/components/content-panel/ContentPanel.astro +9 -39
- package/stl-docs/components/headers/DefaultHeader.astro +1 -1
- package/stl-docs/components/headers/HeaderLinks.astro +1 -1
- package/stl-docs/components/headers/StackedHeader.astro +30 -25
- package/stl-docs/components/icons/chat-gpt.tsx +17 -0
- package/stl-docs/components/icons/claude.tsx +10 -0
- package/stl-docs/components/icons/markdown.tsx +10 -0
- package/stl-docs/components/index.ts +2 -0
- package/stl-docs/components/mintlify-compat/Accordion.astro +7 -38
- package/stl-docs/components/mintlify-compat/AccordionGroup.astro +9 -23
- package/stl-docs/components/mintlify-compat/Columns.astro +40 -42
- package/stl-docs/components/mintlify-compat/Frame.astro +16 -18
- package/stl-docs/components/mintlify-compat/Step.astro +30 -32
- package/stl-docs/components/mintlify-compat/Steps.astro +8 -10
- package/stl-docs/components/mintlify-compat/callouts/Callout.astro +10 -3
- package/stl-docs/components/mintlify-compat/callouts/Check.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Danger.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Info.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Note.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Tip.astro +7 -3
- package/stl-docs/components/mintlify-compat/callouts/Warning.astro +7 -3
- package/stl-docs/components/mintlify-compat/card.css +33 -35
- package/stl-docs/components/nav-tabs/NavDropdown.astro +1 -1
- package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -7
- package/stl-docs/components/nav-tabs/buildNavLinks.ts +4 -3
- package/stl-docs/components/pagination/HomeLink.astro +10 -0
- package/stl-docs/components/pagination/Pagination.astro +173 -0
- package/stl-docs/components/pagination/PaginationLinkEmphasized.astro +22 -0
- package/stl-docs/components/pagination/PaginationLinkQuiet.astro +13 -0
- package/stl-docs/components/pagination/util.ts +71 -0
- package/stl-docs/components/{Sidebar.astro → sidebars/BaseSidebar.astro} +2 -3
- package/stl-docs/components/sidebars/SDKSelectSidebar.astro +8 -0
- package/stl-docs/disableCalloutSyntax.ts +36 -0
- package/stl-docs/index.ts +77 -13
- package/stl-docs/loadStlDocsConfig.ts +25 -3
- package/stl-docs/proseMarkdown/proseMarkdownIntegration.ts +64 -0
- package/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts +34 -0
- package/stl-docs/proseMarkdown/toMarkdown.ts +158 -0
- package/stl-docs/tabsMiddleware.ts +12 -4
- package/styles/code.css +115 -127
- package/styles/fonts.css +24 -9
- package/styles/links.css +10 -49
- package/styles/overrides.css +55 -57
- package/styles/page.css +89 -59
- package/styles/sdk_select.css +6 -7
- package/styles/search.css +65 -67
- package/styles/sidebar.css +199 -128
- package/styles/toc.css +37 -33
- package/theme.css +9 -1
- package/tsconfig.json +2 -5
- package/virtual-module.d.ts +5 -1
- package/plugin/globalJs/ai-dropdown.ts +0 -57
- package/stl-docs/components/APIReferenceAIDropdown.tsx +0 -86
- package/stl-docs/components/content-panel/ProseAIDropdown.tsx +0 -64
- /package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
import HomeLink from './HomeLink.astro';
|
|
3
|
+
import PaginationLinkEmphasized from './PaginationLinkEmphasized.astro';
|
|
4
|
+
|
|
5
|
+
import { getPrevNextPage } from './util';
|
|
6
|
+
import config from 'virtual:starlight/user-config';
|
|
7
|
+
const { prev, next } = (await getPrevNextPage(Astro.locals.starlightRoute, config.pagination)) ?? {};
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
next || prev ? (
|
|
12
|
+
<div class="pagination-links print:hidden stl-ui-not-prose">
|
|
13
|
+
{/* Previous */}
|
|
14
|
+
{!prev && <HomeLink />}
|
|
15
|
+
{/* TODO: intelligently decide whether or not to emphasize the previous page - including user config option (page level?) */}
|
|
16
|
+
{/* {prev && next && (
|
|
17
|
+
<PaginationLinkQuiet href={prev.href}>
|
|
18
|
+
<ChevronLeftIcon slot="icon" />
|
|
19
|
+
Previous
|
|
20
|
+
</PaginationLinkQuiet>
|
|
21
|
+
)} */}
|
|
22
|
+
{prev && (
|
|
23
|
+
<PaginationLinkEmphasized href={prev.href} direction="prev">
|
|
24
|
+
<h2 slot="page-title">{prev.label}</h2>
|
|
25
|
+
{prev.description && <p slot="page-description">{prev.description}</p>}
|
|
26
|
+
</PaginationLinkEmphasized>
|
|
27
|
+
)}
|
|
28
|
+
|
|
29
|
+
{/* Next */}
|
|
30
|
+
{!next && <HomeLink />}
|
|
31
|
+
{next && (
|
|
32
|
+
<PaginationLinkEmphasized href={next.href} direction="next">
|
|
33
|
+
<h2 slot="page-title">{next.label}</h2>
|
|
34
|
+
{next.description && <p slot="page-description">{next.description}</p>}
|
|
35
|
+
</PaginationLinkEmphasized>
|
|
36
|
+
)}
|
|
37
|
+
</div>
|
|
38
|
+
) : null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
<style is:global>
|
|
42
|
+
@layer starlight.core {
|
|
43
|
+
.pagination-links,
|
|
44
|
+
.pagination-links a,
|
|
45
|
+
.pagination-links a:hover,
|
|
46
|
+
.pagination-links a[rel='next'],
|
|
47
|
+
.link-title {
|
|
48
|
+
all: revert-layer;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.pagination-links {
|
|
53
|
+
--stl-ui-pagination-padding: 8px;
|
|
54
|
+
--stl-ui-pagination-border-radius-inner: var(--stl-ui-layout-border-radius-sml);
|
|
55
|
+
|
|
56
|
+
padding: var(--stl-ui-pagination-padding);
|
|
57
|
+
background-color: var(--stl-ui-muted-background);
|
|
58
|
+
border: 1px solid var(--stl-ui-border);
|
|
59
|
+
border-radius: calc(var(--stl-ui-pagination-border-radius-inner) + var(--stl-ui-pagination-padding));
|
|
60
|
+
|
|
61
|
+
font-size: var(--stl-ui-type-scale-text-sm);
|
|
62
|
+
letter-spacing: normal;
|
|
63
|
+
|
|
64
|
+
display: flex;
|
|
65
|
+
gap: 8px;
|
|
66
|
+
|
|
67
|
+
margin-bottom: 2rem;
|
|
68
|
+
|
|
69
|
+
a {
|
|
70
|
+
border-radius: var(--stl-ui-pagination-border-radius-inner);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.pagination-links__link {
|
|
75
|
+
display: flex;
|
|
76
|
+
border-radius: var(--stl-ui-pagination-border-radius-inner);
|
|
77
|
+
padding: 8px 12px;
|
|
78
|
+
display: flex;
|
|
79
|
+
text-decoration: none;
|
|
80
|
+
align-items: center;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.pagination-links__link--emphasized {
|
|
84
|
+
background-color: var(--stl-ui-background);
|
|
85
|
+
border: 1px solid var(--stl-ui-border);
|
|
86
|
+
flex: 1 1 50%;
|
|
87
|
+
gap: 12px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.pagination-links__link--quiet {
|
|
91
|
+
flex: 0 1 auto;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.pagination-links__button {
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
padding: 8px 14px;
|
|
98
|
+
font-weight: 500;
|
|
99
|
+
line-height: 1;
|
|
100
|
+
|
|
101
|
+
svg {
|
|
102
|
+
width: 16px;
|
|
103
|
+
height: 16px;
|
|
104
|
+
margin-block: -4px;
|
|
105
|
+
margin-inline-start: -6px;
|
|
106
|
+
margin-inline-end: 6px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&.pagination-links__link--quiet {
|
|
110
|
+
padding-inline: 22px;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.pagination-links__link__divider {
|
|
115
|
+
border: 0;
|
|
116
|
+
border-inline-start: 1px solid var(--stl-ui-border);
|
|
117
|
+
align-self: stretch;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.pagination-links__page-description {
|
|
121
|
+
padding-block: 4px;
|
|
122
|
+
padding-inline-start: 8px;
|
|
123
|
+
padding-inline-end: 2px;
|
|
124
|
+
line-height: 1.5;
|
|
125
|
+
flex: 1 1 50%;
|
|
126
|
+
width: 0;
|
|
127
|
+
|
|
128
|
+
h2,
|
|
129
|
+
p {
|
|
130
|
+
white-space: nowrap;
|
|
131
|
+
overflow: hidden;
|
|
132
|
+
text-overflow: ellipsis;
|
|
133
|
+
}
|
|
134
|
+
h2 {
|
|
135
|
+
font-size: inherit;
|
|
136
|
+
font-weight: 500;
|
|
137
|
+
}
|
|
138
|
+
p {
|
|
139
|
+
font-size: var(--stl-ui-type-scale-text-xs);
|
|
140
|
+
color: var(--stl-ui-foreground-muted);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.pagination-links__link--quiet:hover {
|
|
145
|
+
background-color: rgb(from var(--stl-ui-foreground) r g b / 0.05);
|
|
146
|
+
}
|
|
147
|
+
.pagination-links__link--emphasized:hover {
|
|
148
|
+
border-color: var(--stl-ui-border-emphasis);
|
|
149
|
+
.pagination-links__page-description h2 {
|
|
150
|
+
text-decoration: underline;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* “next” link runs the opposite direction of the “previous” link */
|
|
155
|
+
.pagination-links__link:last-child {
|
|
156
|
+
flex-direction: row-reverse;
|
|
157
|
+
|
|
158
|
+
&.pagination-links__button,
|
|
159
|
+
.pagination-links__button {
|
|
160
|
+
flex-direction: row-reverse;
|
|
161
|
+
svg {
|
|
162
|
+
margin-inline-start: 6px;
|
|
163
|
+
margin-inline-end: -6px;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.pagination-links__page-description {
|
|
168
|
+
padding-inline-start: 2px;
|
|
169
|
+
padding-inline-end: 8px;
|
|
170
|
+
text-align: right;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
|
|
3
|
+
const { href, direction } = Astro.props;
|
|
4
|
+
export interface Props {
|
|
5
|
+
href: string;
|
|
6
|
+
direction: 'prev' | 'next';
|
|
7
|
+
}
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<a href={href} class="pagination-links__link pagination-links__link--emphasized">
|
|
11
|
+
<div class="pagination-links__button">
|
|
12
|
+
{{ prev: <ChevronLeftIcon />, next: <ChevronRightIcon /> }[direction]}
|
|
13
|
+
<span>{{ prev: 'Previous', next: 'Next' }[direction]}</span>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<hr class="pagination-links__link__divider" />
|
|
17
|
+
|
|
18
|
+
<article class="pagination-links__page-description">
|
|
19
|
+
<slot name="page-title" />
|
|
20
|
+
<slot name="page-description" />
|
|
21
|
+
</article>
|
|
22
|
+
</a>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
const { href } = Astro.props;
|
|
3
|
+
export interface Props {
|
|
4
|
+
href: string;
|
|
5
|
+
}
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<a href={href} class="pagination-links__link pagination-links__button pagination-links__link--quiet">
|
|
9
|
+
<slot name="icon" />
|
|
10
|
+
<span>
|
|
11
|
+
<slot />
|
|
12
|
+
</span>
|
|
13
|
+
</a>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { StarlightRouteData } from '@astrojs/starlight/route-data';
|
|
2
|
+
import { getCollection } from 'astro:content';
|
|
3
|
+
|
|
4
|
+
export type SidebarEntry = StarlightRouteData['sidebar'][number];
|
|
5
|
+
export type SidebarLink = Extract<SidebarEntry, { type: 'link' }>;
|
|
6
|
+
export type SidebarGroup = Extract<SidebarEntry, { type: 'group' }>;
|
|
7
|
+
|
|
8
|
+
export const flattenSidebar = (sidebar: SidebarEntry[]): SidebarLink[] =>
|
|
9
|
+
sidebar.flatMap((e) => (e.type === 'group' ? flattenSidebar(e.entries) : e));
|
|
10
|
+
|
|
11
|
+
function findParentOfSidebarEntry(sidebar: SidebarEntry[], targetEntry: SidebarEntry): SidebarGroup | null {
|
|
12
|
+
for (const entry of sidebar) {
|
|
13
|
+
if (entry.type === 'group') {
|
|
14
|
+
if (entry.entries.includes(targetEntry)) {
|
|
15
|
+
return entry;
|
|
16
|
+
}
|
|
17
|
+
const foundInChild = findParentOfSidebarEntry(entry.entries, targetEntry);
|
|
18
|
+
if (foundInChild) {
|
|
19
|
+
return foundInChild;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function getPrevNextPage(page: StarlightRouteData, paginationEnabled: boolean) {
|
|
27
|
+
// TODO: respect user `next` / `prev` config from frontmatter the way starlight does
|
|
28
|
+
|
|
29
|
+
if (!paginationEnabled) return null;
|
|
30
|
+
|
|
31
|
+
const docsContent = await getCollection('docs');
|
|
32
|
+
const findSidebarLinkInContent = (link: SidebarLink) =>
|
|
33
|
+
docsContent.find((doc) => {
|
|
34
|
+
if (doc.id === 'index' && link.href === '/') return true;
|
|
35
|
+
return doc.id === link.href.replace(/^\//, '').replace(/\/$/, '');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const currentSidebar = page.sidebar;
|
|
39
|
+
|
|
40
|
+
const paginationSequence: (SidebarLink & { description?: string })[] = flattenSidebar(currentSidebar)
|
|
41
|
+
// Remove injected stl-mobile-only-sidebar-item links - TODO: better solution for this
|
|
42
|
+
.filter((link) => !(link.attrs.class ?? '').trim().split(/\s+/).includes('stl-mobile-only-sidebar-item'))
|
|
43
|
+
// Remove data-stldocs-method links from pagination sequence
|
|
44
|
+
.filter((link) => !link.attrs['data-stldocs-method'])
|
|
45
|
+
// Map data-stldocs-overview=readme links so that their name is not just “Overview”
|
|
46
|
+
.map((link) => {
|
|
47
|
+
if (link.attrs['data-stldocs-overview'] && link.label === 'Overview') {
|
|
48
|
+
const parent = findParentOfSidebarEntry(currentSidebar, link);
|
|
49
|
+
if (parent) return { ...link, label: parent.label };
|
|
50
|
+
}
|
|
51
|
+
return link;
|
|
52
|
+
})
|
|
53
|
+
.map((link) => {
|
|
54
|
+
const contentEntry = findSidebarLinkInContent(link);
|
|
55
|
+
if (contentEntry) return { ...link, description: contentEntry.data.description };
|
|
56
|
+
return link;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const currentIndex = paginationSequence.findIndex((e) => e.isCurrent);
|
|
60
|
+
if (currentIndex === -1) return null;
|
|
61
|
+
|
|
62
|
+
const prevIndex = currentIndex > 0 ? currentIndex - 1 : null;
|
|
63
|
+
const nextIndex = currentIndex < paginationSequence.length - 1 ? currentIndex + 1 : null;
|
|
64
|
+
const prevSidebarEntry = prevIndex !== null ? (paginationSequence[prevIndex] ?? null) : null;
|
|
65
|
+
const nextSidebarEntry = nextIndex !== null ? (paginationSequence[nextIndex] ?? null) : null;
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
prev: prevSidebarEntry,
|
|
69
|
+
next: nextSidebarEntry,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Default from '@astrojs/starlight/components/Sidebar.astro';
|
|
3
|
-
import
|
|
4
|
-
import HeaderLinks from './headers/HeaderLinks.astro';
|
|
3
|
+
import HeaderLinks from '../headers/HeaderLinks.astro';
|
|
5
4
|
---
|
|
6
5
|
|
|
7
6
|
<div class="stl-sidebar-header-links">
|
|
8
7
|
<HeaderLinks />
|
|
9
8
|
</div>
|
|
10
|
-
<
|
|
9
|
+
<slot name="sdk-select" />
|
|
11
10
|
<Default><slot /></Default>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AstroIntegration } from 'astro';
|
|
2
|
+
import type { StarlightPlugin } from '@astrojs/starlight/types';
|
|
3
|
+
|
|
4
|
+
export const disableCalloutSyntaxAstroIntegration = {
|
|
5
|
+
name: 'stl-starlight-remove-callout-syntax',
|
|
6
|
+
hooks: {
|
|
7
|
+
'astro:config:setup': ({ config: astroConfig }) => {
|
|
8
|
+
// Remove starlight callout syntax in favor of our own callout component
|
|
9
|
+
// updateConfig always deeply merges arrays so we need to mutate remarkPlugins directly
|
|
10
|
+
// in order to remove plugins that starlight added
|
|
11
|
+
astroConfig.markdown.remarkPlugins = astroConfig.markdown.remarkPlugins.filter((plugin, i, arr) => {
|
|
12
|
+
if (typeof plugin !== 'function') return true;
|
|
13
|
+
// remove:
|
|
14
|
+
// 1. remarkDirective plugin
|
|
15
|
+
if (plugin.name === 'remarkDirective') return false;
|
|
16
|
+
// 2. directly followed by remarkAsides plugin (inner function named 'attacher')
|
|
17
|
+
if (plugin.name === 'attacher') {
|
|
18
|
+
const prev = arr[i - 1];
|
|
19
|
+
if (typeof prev === 'function' && prev.name === 'remarkDirective') return false;
|
|
20
|
+
}
|
|
21
|
+
// 3. remarkDirectivesRestoration plugin
|
|
22
|
+
if (plugin.name === 'remarkDirectivesRestoration') return false;
|
|
23
|
+
return true;
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
} satisfies AstroIntegration;
|
|
28
|
+
|
|
29
|
+
export const disableCalloutSyntaxStarlightPlugin = {
|
|
30
|
+
name: 'stl-starlight-remove-callout-syntax',
|
|
31
|
+
hooks: {
|
|
32
|
+
'config:setup': ({ addIntegration }) => {
|
|
33
|
+
addIntegration(disableCalloutSyntaxAstroIntegration);
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
} satisfies StarlightPlugin;
|
package/stl-docs/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import starlight from '@astrojs/starlight';
|
|
2
2
|
import react from '@astrojs/react';
|
|
3
|
+
import type { StarlightPlugin } from '@astrojs/starlight/types';
|
|
3
4
|
import { stainlessStarlight } from '../plugin';
|
|
5
|
+
import { disableCalloutSyntaxStarlightPlugin } from './disableCalloutSyntax';
|
|
4
6
|
|
|
5
7
|
import type { AstroIntegration } from 'astro';
|
|
6
8
|
|
|
@@ -16,11 +18,15 @@ import {
|
|
|
16
18
|
type StarlightSidebarConfig,
|
|
17
19
|
} from './loadStlDocsConfig';
|
|
18
20
|
import { buildVirtualModuleString } from '../shared/virtualModule';
|
|
19
|
-
|
|
21
|
+
import { resolveSrcFile } from '../resolveSrcFile';
|
|
20
22
|
import geistPath from '../plugin/assets/fonts/geist/geist-latin.woff2?url';
|
|
23
|
+
import { stainlessDocsMarkdownRenderer } from './proseMarkdown/proseMarkdownIntegration';
|
|
24
|
+
import { setSharedLogger } from '../shared/getSharedLogger';
|
|
21
25
|
|
|
22
26
|
export * from '../plugin';
|
|
23
27
|
|
|
28
|
+
const COMPONENTS_FOLDER = '/stl-docs/components';
|
|
29
|
+
|
|
24
30
|
function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig) {
|
|
25
31
|
// We transform our tabs into a Starlight sidebar
|
|
26
32
|
// This gives them all the built-in features of Starlight (eg. auto-generated entries by directory)
|
|
@@ -41,13 +47,34 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
|
|
|
41
47
|
|
|
42
48
|
type ComponentOverrides = StarlightConfigDefined['components'];
|
|
43
49
|
const componentOverrides: ComponentOverrides = {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
ThemeSelect: '
|
|
48
|
-
ContentPanel: '
|
|
50
|
+
Sidebar: resolveSrcFile(COMPONENTS_FOLDER, './sidebars/BaseSidebar.astro'),
|
|
51
|
+
Header: resolveSrcFile(COMPONENTS_FOLDER, './Header.astro'),
|
|
52
|
+
Head: resolveSrcFile(COMPONENTS_FOLDER, './Head.astro'),
|
|
53
|
+
ThemeSelect: resolveSrcFile(COMPONENTS_FOLDER, './ThemeSelect.astro'),
|
|
54
|
+
ContentPanel: resolveSrcFile(COMPONENTS_FOLDER, './content-panel/ContentPanel.astro'),
|
|
55
|
+
TableOfContents: resolveSrcFile(COMPONENTS_FOLDER, './TableOfContents.astro'),
|
|
56
|
+
PageTitle: resolveSrcFile(COMPONENTS_FOLDER, './PageTitle.astro'),
|
|
57
|
+
Pagination: resolveSrcFile(COMPONENTS_FOLDER, './pagination/Pagination.astro'),
|
|
49
58
|
};
|
|
50
59
|
|
|
60
|
+
const plugins: StarlightPlugin[] = [
|
|
61
|
+
// Disable starlight callout syntax in favor of our own component
|
|
62
|
+
disableCalloutSyntaxStarlightPlugin,
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
if (config.apiReference !== null) {
|
|
66
|
+
plugins.push(
|
|
67
|
+
stainlessStarlight({
|
|
68
|
+
...config.apiReference,
|
|
69
|
+
contextMenu: config.contextMenu,
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
componentOverrides.Sidebar = resolveSrcFile(COMPONENTS_FOLDER, './sidebars/SDKSelectSidebar.astro');
|
|
73
|
+
componentOverrides.Search = resolveSrcFile('/plugin/components/search/Search.astro');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
plugins.push(...config.starlightCompat.plugins);
|
|
77
|
+
|
|
51
78
|
// TODO: re-add once we figure out what to do with the client router
|
|
52
79
|
// if (config.enableClientRouter) {
|
|
53
80
|
// // logger.info(`Client router is enabled`);
|
|
@@ -92,20 +119,26 @@ function stainlessDocsStarlightIntegration(config: NormalizedStainlessDocsConfig
|
|
|
92
119
|
},
|
|
93
120
|
},
|
|
94
121
|
],
|
|
95
|
-
routeMiddleware: [
|
|
96
|
-
|
|
97
|
-
|
|
122
|
+
routeMiddleware: [
|
|
123
|
+
...config.starlightCompat.routeMiddleware,
|
|
124
|
+
resolveSrcFile('/stl-docs/tabsMiddleware.ts'),
|
|
125
|
+
],
|
|
126
|
+
customCss: [resolveSrcFile('/theme.css'), ...config.customCss],
|
|
127
|
+
plugins,
|
|
98
128
|
});
|
|
99
129
|
}
|
|
100
130
|
|
|
101
|
-
function stainlessDocsIntegration(
|
|
102
|
-
|
|
131
|
+
function stainlessDocsIntegration(
|
|
132
|
+
config: NormalizedStainlessDocsConfig,
|
|
133
|
+
apiReferenceBasePath: string | null,
|
|
134
|
+
): AstroIntegration {
|
|
135
|
+
const virtualId = `virtual:stl-docs-virtual-module`;
|
|
103
136
|
// The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
|
|
104
137
|
const resolvedId = `\0${virtualId}`;
|
|
105
138
|
let redirects: NormalizedRedirectConfig | null = null;
|
|
106
139
|
|
|
107
140
|
return {
|
|
108
|
-
name: 'stl-docs-
|
|
141
|
+
name: 'stl-docs-astro',
|
|
109
142
|
hooks: {
|
|
110
143
|
'astro:config:setup': ({ updateConfig, command, config: astroConfig }) => {
|
|
111
144
|
// // we only handle redirects for builds
|
|
@@ -116,6 +149,10 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
|
|
|
116
149
|
|
|
117
150
|
updateConfig({
|
|
118
151
|
vite: {
|
|
152
|
+
ssr: {
|
|
153
|
+
noExternal: ['@stainless-api/ui-primitives'],
|
|
154
|
+
},
|
|
155
|
+
optimizeDeps: { include: ['@stainless-api/ui-primitives'] },
|
|
119
156
|
plugins: [
|
|
120
157
|
{
|
|
121
158
|
name: 'stl-docs-vite',
|
|
@@ -132,6 +169,10 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
|
|
|
132
169
|
HEADER_LINKS: config.header.links,
|
|
133
170
|
HEADER_LAYOUT: config.header.layout,
|
|
134
171
|
ENABLE_CLIENT_ROUTER: config.enableClientRouter,
|
|
172
|
+
API_REFERENCE_BASE_PATH: apiReferenceBasePath,
|
|
173
|
+
ENABLE_PROSE_MARKDOWN_RENDERING: config.enableProseMarkdownRendering,
|
|
174
|
+
// TODO: do not duplicate this between both virtual modules
|
|
175
|
+
ENABLE_CONTEXT_MENU: config.contextMenu,
|
|
135
176
|
});
|
|
136
177
|
}
|
|
137
178
|
},
|
|
@@ -158,6 +199,17 @@ function stainlessDocsIntegration(config: NormalizedStainlessDocsConfig): AstroI
|
|
|
158
199
|
};
|
|
159
200
|
}
|
|
160
201
|
|
|
202
|
+
function sharedLoggerIntegration(): AstroIntegration {
|
|
203
|
+
return {
|
|
204
|
+
name: 'stainless',
|
|
205
|
+
hooks: {
|
|
206
|
+
'astro:config:setup': ({ logger }) => {
|
|
207
|
+
setSharedLogger(logger);
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
161
213
|
export function stainlessDocs(config: StainlessDocsUserConfig) {
|
|
162
214
|
const normalizedConfigResult = parseStlDocsConfig(config);
|
|
163
215
|
if (normalizedConfigResult.result === 'error') {
|
|
@@ -166,9 +218,21 @@ export function stainlessDocs(config: StainlessDocsUserConfig) {
|
|
|
166
218
|
process.exit(1);
|
|
167
219
|
}
|
|
168
220
|
const normalizedConfig = normalizedConfigResult.config;
|
|
221
|
+
|
|
222
|
+
// TODO: need to refactor this, but this allows us to get the base path for the API reference _if_ it exists
|
|
223
|
+
// if it doesn't exist, the value of basePath is null.
|
|
224
|
+
// the stl-starlight virtual module has base path, but it's not available when there's no API reference
|
|
225
|
+
const hasApiReference = normalizedConfig.apiReference !== null;
|
|
226
|
+
let apiReferenceBasePath: string | null = null;
|
|
227
|
+
if (hasApiReference) {
|
|
228
|
+
apiReferenceBasePath = normalizedConfig.apiReference?.basePath ?? '/api';
|
|
229
|
+
}
|
|
230
|
+
|
|
169
231
|
return [
|
|
232
|
+
sharedLoggerIntegration(), // this **must** be first so it can set the shared logger used by our other integrations
|
|
170
233
|
react(),
|
|
171
234
|
stainlessDocsStarlightIntegration(normalizedConfig),
|
|
172
|
-
stainlessDocsIntegration(normalizedConfig),
|
|
235
|
+
stainlessDocsIntegration(normalizedConfig, apiReferenceBasePath),
|
|
236
|
+
stainlessDocsMarkdownRenderer({ enabled: normalizedConfig.enableProseMarkdownRendering }),
|
|
173
237
|
];
|
|
174
238
|
}
|
|
@@ -45,7 +45,8 @@ type Tabs = {
|
|
|
45
45
|
sidebar?: SidebarEntry[];
|
|
46
46
|
/**
|
|
47
47
|
* Whether to hide the tab in the tab bar.
|
|
48
|
-
*
|
|
48
|
+
*
|
|
49
|
+
* Default: `false`
|
|
49
50
|
*/
|
|
50
51
|
hidden?: boolean;
|
|
51
52
|
}[];
|
|
@@ -58,7 +59,7 @@ export type HeaderLink = {
|
|
|
58
59
|
};
|
|
59
60
|
|
|
60
61
|
export type StainlessDocsUserConfig = {
|
|
61
|
-
apiReference
|
|
62
|
+
apiReference?: StainlessStarlightUserConfig;
|
|
62
63
|
tabs?: Tabs;
|
|
63
64
|
header?: {
|
|
64
65
|
layout?: HeaderLayout;
|
|
@@ -67,7 +68,19 @@ export type StainlessDocsUserConfig = {
|
|
|
67
68
|
experimental?: {
|
|
68
69
|
starlightCompat?: ExperimentalStarlightCompatibilityConfig;
|
|
69
70
|
enableClientRouter?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Disable markdown rendering for prose content. Only disable this if it is causing issues.
|
|
73
|
+
*
|
|
74
|
+
* Default: `false`
|
|
75
|
+
*/
|
|
76
|
+
disableProseMarkdownRendering?: boolean;
|
|
70
77
|
};
|
|
78
|
+
/**
|
|
79
|
+
* Whether to show the context menu with options like "Copy as Markdown" and "Open in ChatGPT".
|
|
80
|
+
*
|
|
81
|
+
* Default: `true`
|
|
82
|
+
*/
|
|
83
|
+
contextMenu?: boolean;
|
|
71
84
|
} & PassThroughStarlightConfigOptions;
|
|
72
85
|
|
|
73
86
|
type HeaderLayout = 'default' | 'stacked';
|
|
@@ -119,6 +132,12 @@ function normalizeConfig(userConfig: StainlessDocsUserConfig) {
|
|
|
119
132
|
description: userConfig.description,
|
|
120
133
|
tagline: userConfig.tagline,
|
|
121
134
|
logo: userConfig.logo,
|
|
135
|
+
favicon: userConfig.favicon,
|
|
136
|
+
disable404Route: userConfig.disable404Route,
|
|
137
|
+
editLink: userConfig.editLink,
|
|
138
|
+
locales: userConfig.locales,
|
|
139
|
+
lastUpdated: userConfig.lastUpdated,
|
|
140
|
+
pagination: userConfig.pagination,
|
|
122
141
|
},
|
|
123
142
|
starlightCompat: {
|
|
124
143
|
components: userConfig.experimental?.starlightCompat?.components ?? {},
|
|
@@ -126,8 +145,11 @@ function normalizeConfig(userConfig: StainlessDocsUserConfig) {
|
|
|
126
145
|
routeMiddleware: normalizeRouteMiddleware(userConfig),
|
|
127
146
|
},
|
|
128
147
|
enableClientRouter: userConfig.experimental?.enableClientRouter ?? false,
|
|
129
|
-
apiReference: userConfig.apiReference,
|
|
148
|
+
apiReference: userConfig.apiReference ?? null,
|
|
130
149
|
sidebar: userConfig.sidebar,
|
|
150
|
+
enableProseMarkdownRendering:
|
|
151
|
+
userConfig.experimental?.disableProseMarkdownRendering === true ? false : true,
|
|
152
|
+
contextMenu: userConfig.contextMenu ?? true,
|
|
131
153
|
};
|
|
132
154
|
|
|
133
155
|
return configWithDefaults;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { AstroIntegration } from 'astro';
|
|
2
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
3
|
+
import { toMarkdown } from './toMarkdown';
|
|
4
|
+
import { resolveSrcFile } from '../../resolveSrcFile';
|
|
5
|
+
import { getSharedLogger } from '../../shared/getSharedLogger';
|
|
6
|
+
import { bold } from '../../shared/terminalUtils';
|
|
7
|
+
|
|
8
|
+
export function stainlessDocsMarkdownRenderer({ enabled }: { enabled: boolean }): AstroIntegration {
|
|
9
|
+
return {
|
|
10
|
+
name: 'stl-docs-md',
|
|
11
|
+
hooks: {
|
|
12
|
+
'astro:config:setup': ({ addMiddleware }) => {
|
|
13
|
+
if (enabled) {
|
|
14
|
+
addMiddleware({
|
|
15
|
+
entrypoint: resolveSrcFile('/stl-docs/proseMarkdown/proseMarkdownMiddleware.ts'),
|
|
16
|
+
order: 'post',
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
'astro:build:done': async ({ assets, logger: localLogger, dir }) => {
|
|
21
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
22
|
+
if (!enabled) {
|
|
23
|
+
logger.info('Stainless Docs prose Markdown rendering is disabled, skipping...');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const starlightPagePatterns = ['/[...slug]'];
|
|
27
|
+
const pagesToRender = Array.from(assets.entries())
|
|
28
|
+
.filter(([k]) => {
|
|
29
|
+
if (starlightPagePatterns.includes(k)) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
})
|
|
34
|
+
.map(([, v]) => v)
|
|
35
|
+
.flat()
|
|
36
|
+
.map((v) => v.pathname);
|
|
37
|
+
|
|
38
|
+
logger.info(bold(`Building ${pagesToRender.length} Markdown pages for prose content`));
|
|
39
|
+
|
|
40
|
+
const outputBasePath = dir.pathname;
|
|
41
|
+
|
|
42
|
+
let completedCount = 0;
|
|
43
|
+
for (const absHtmlPath of pagesToRender) {
|
|
44
|
+
const txt = await readFile(absHtmlPath, 'utf-8');
|
|
45
|
+
const md = await toMarkdown(txt);
|
|
46
|
+
if (md) {
|
|
47
|
+
const absMdPath = absHtmlPath.replace('.html', '.md');
|
|
48
|
+
await writeFile(absMdPath, md, 'utf-8');
|
|
49
|
+
|
|
50
|
+
completedCount++;
|
|
51
|
+
|
|
52
|
+
const relHtmlPath = absHtmlPath.replace(outputBasePath, '');
|
|
53
|
+
const relMdPath = absMdPath.replace(outputBasePath, '');
|
|
54
|
+
|
|
55
|
+
logger.info(`(${completedCount}/${pagesToRender.length}) ${relHtmlPath} -> ${relMdPath}`);
|
|
56
|
+
} else {
|
|
57
|
+
logger.error(`Failed to render ${absHtmlPath} as Markdown`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { defineMiddleware } from 'astro:middleware';
|
|
2
|
+
import { toMarkdown } from './toMarkdown';
|
|
3
|
+
import { API_REFERENCE_BASE_PATH } from 'virtual:stl-docs-virtual-module';
|
|
4
|
+
|
|
5
|
+
// this is only run in `astro dev` for rendering prose content as Markdown on the fly.
|
|
6
|
+
export const onRequest = defineMiddleware(async (context, next) => {
|
|
7
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
8
|
+
if (!import.meta.env.DEV) {
|
|
9
|
+
return next();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (API_REFERENCE_BASE_PATH && context.url.pathname.startsWith(API_REFERENCE_BASE_PATH)) {
|
|
13
|
+
// handled by the API reference API route in stl-starlight plugin
|
|
14
|
+
return next();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!context.url.pathname.endsWith('/index.md')) {
|
|
18
|
+
return next();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const htmlUrl = new URL(context.url.pathname.replace('index.md', ''), context.url);
|
|
22
|
+
const resp = await fetch(htmlUrl);
|
|
23
|
+
if (!resp.ok) {
|
|
24
|
+
return new Response('Failed to fetch HTML', { status: 400 });
|
|
25
|
+
}
|
|
26
|
+
const html = await resp.text();
|
|
27
|
+
const md = await toMarkdown(html);
|
|
28
|
+
|
|
29
|
+
if (!md) {
|
|
30
|
+
return new Response('Failed to render Markdown', { status: 400 });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return new Response(md, { status: 200 });
|
|
34
|
+
});
|