@stainless-api/docs 0.1.0-beta.6 → 0.1.0-beta.60
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 +476 -0
- package/README.md +1 -1
- package/eslint-suppressions.json +52 -0
- package/locals.d.ts +16 -0
- package/package.json +45 -40
- package/plugin/assets/languages/csharp.svg +1 -0
- package/plugin/buildAlgoliaIndex.ts +32 -7
- package/plugin/cms/server.ts +130 -58
- package/plugin/cms/sidebar-builder.ts +7 -26
- package/plugin/cms/worker.ts +83 -5
- package/plugin/components/MethodDescription.tsx +54 -0
- package/plugin/components/SDKSelect.astro +7 -87
- package/plugin/components/SnippetCode.tsx +53 -8
- package/plugin/components/search/SearchAlgolia.astro +14 -26
- package/plugin/components/search/SearchIsland.tsx +38 -24
- package/plugin/create-playground.shim.tsx +3 -0
- package/plugin/generateAPIReferenceLink.ts +2 -2
- package/plugin/globalJs/ai-dropdown-options.ts +235 -0
- package/plugin/globalJs/code-snippets.ts +15 -8
- package/plugin/globalJs/copy.ts +81 -16
- package/plugin/globalJs/method-descriptions.ts +33 -0
- package/plugin/globalJs/navigation.ts +7 -4
- package/plugin/index.ts +179 -35
- package/plugin/languages.ts +5 -2
- package/plugin/loadPluginConfig.ts +121 -32
- package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
- package/plugin/react/Routing.tsx +208 -104
- package/plugin/referencePlaceholderUtils.ts +1 -1
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +5 -1
- package/plugin/routes/Docs.astro +61 -83
- package/plugin/routes/Overview.astro +10 -16
- package/plugin/routes/markdown.ts +7 -7
- package/plugin/vendor/preview.worker.docs.js +19768 -17702
- package/plugin/vendor/templates/go.md +1 -1
- package/plugin/vendor/templates/python.md +1 -1
- package/resolveSrcFile.ts +10 -0
- package/scripts/vendor_deps.ts +5 -5
- 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 +63 -0
- package/stl-docs/components/AiChatIsland.tsx +10 -0
- package/stl-docs/components/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +10 -18
- package/stl-docs/components/Head.astro +16 -0
- package/stl-docs/components/Header.astro +6 -8
- package/stl-docs/components/PageFrame.astro +14 -0
- package/stl-docs/components/PageTitle.astro +82 -0
- package/stl-docs/components/TableOfContents.astro +34 -0
- package/stl-docs/components/ThemeSelect.astro +118 -136
- package/stl-docs/components/content-panel/ContentPanel.astro +16 -25
- package/stl-docs/components/headers/SplashMobileMenuToggle.astro +17 -1
- package/stl-docs/components/headers/StackedHeader.astro +29 -24
- package/stl-docs/components/icons/chat-gpt.tsx +17 -0
- package/stl-docs/components/icons/claude.tsx +10 -0
- package/stl-docs/components/icons/cursor.tsx +10 -0
- package/stl-docs/components/icons/gemini.tsx +19 -0
- package/stl-docs/components/icons/markdown.tsx +10 -0
- package/stl-docs/components/index.ts +1 -0
- package/stl-docs/components/mintlify-compat/Accordion.astro +7 -5
- package/stl-docs/components/mintlify-compat/AccordionGroup.astro +7 -3
- 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 +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Check.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Danger.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Info.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Note.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Tip.astro +1 -1
- package/stl-docs/components/mintlify-compat/callouts/Warning.astro +1 -1
- package/stl-docs/components/mintlify-compat/card.css +33 -35
- package/stl-docs/components/nav-tabs/NavDropdown.astro +31 -70
- package/stl-docs/components/nav-tabs/NavTabs.astro +78 -80
- package/stl-docs/components/nav-tabs/SecondaryNavTabs.astro +15 -8
- package/stl-docs/components/nav-tabs/buildNavLinks.ts +3 -2
- package/stl-docs/components/pagination/HomeLink.astro +10 -0
- package/stl-docs/components/pagination/Pagination.astro +175 -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/scripts.ts +1 -0
- package/stl-docs/disableCalloutSyntax.ts +36 -0
- package/stl-docs/index.ts +121 -48
- package/stl-docs/loadStlDocsConfig.ts +44 -4
- 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/proseSearchIndexing.ts +113 -0
- package/stl-docs/tabsMiddleware.ts +11 -3
- package/styles/code.css +108 -140
- package/styles/fonts.css +32 -17
- package/styles/links.css +11 -48
- package/styles/method-descriptions.css +36 -0
- package/styles/overrides.css +48 -60
- package/styles/page.css +92 -52
- package/styles/sdk_select.css +9 -7
- package/styles/search.css +58 -69
- package/styles/sidebar.css +211 -131
- package/styles/{variables.css → sl-variables.css} +3 -2
- package/styles/stldocs-variables.css +6 -0
- package/styles/toc.css +41 -34
- package/theme.css +10 -10
- package/tsconfig.json +2 -5
- package/virtual-module.d.ts +23 -3
- package/components/variables.css +0 -135
- /package/{plugin/assets → assets}/fonts/geist/OFL.txt +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-italic-latin.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin-ext.woff2 +0 -0
- /package/{plugin/assets → assets}/fonts/geist/geist-mono-latin.woff2 +0 -0
package/plugin/globalJs/copy.ts
CHANGED
|
@@ -1,30 +1,39 @@
|
|
|
1
1
|
import { EXPERIMENTAL_COLLAPSIBLE_SNIPPETS } from 'virtual:stl-starlight-virtual-module';
|
|
2
|
+
import { getPageLoadEvent } from '../helpers/getPageLoadEvent';
|
|
2
3
|
const copyIcon = `<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>`;
|
|
3
4
|
const circleAlertIcon = `<circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/>`;
|
|
4
5
|
const checkIcon = `<path d="M20 6 9 17l-5-5"/>`;
|
|
5
6
|
|
|
7
|
+
function getContent(button: HTMLElement, full: boolean) {
|
|
8
|
+
const isContentCollapsed = !!document.querySelector('.stldocs-snippet-code.stl-snippet-code-is-collapsed');
|
|
9
|
+
|
|
10
|
+
const content = button.closest('[data-stldocs-copy-parent]')!.querySelector('[data-stldocs-copy-content]')!;
|
|
11
|
+
|
|
12
|
+
const contentCopy = content.cloneNode(true) as HTMLElement;
|
|
13
|
+
|
|
14
|
+
contentCopy.querySelectorAll('.ellipsis').forEach((el) => el.remove());
|
|
15
|
+
if (EXPERIMENTAL_COLLAPSIBLE_SNIPPETS && isContentCollapsed && !full) {
|
|
16
|
+
contentCopy.querySelectorAll('.hidden').forEach((el) => el.remove());
|
|
17
|
+
contentCopy.querySelectorAll('.leading-ws').forEach((el) => el.remove());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return contentCopy.textContent!;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const preloadPlayground = async (event: Event) => {
|
|
24
|
+
const playButton = (event.target as HTMLElement).closest('[data-stldocs-snippet-play]') as HTMLElement;
|
|
25
|
+
if (playButton) {
|
|
26
|
+
loadPlayground(playButton);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
addEventListener('mouseover', preloadPlayground);
|
|
6
30
|
addEventListener('click', async (event) => {
|
|
7
31
|
const copyButton = (event.target as HTMLElement).closest('[data-stldocs-snippet-copy]') as HTMLElement;
|
|
8
32
|
if (copyButton) {
|
|
9
33
|
const iconElement = copyButton.querySelector('.stldocs-icon') as SVGElement;
|
|
10
34
|
clearTimeout(copyButton.dataset.__stldocsCopyTimeout);
|
|
11
35
|
try {
|
|
12
|
-
|
|
13
|
-
'.stldocs-snippet-code.stl-snippet-code-is-collapsed',
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
const content = copyButton
|
|
17
|
-
.closest('[data-stldocs-copy-parent]')!
|
|
18
|
-
.querySelector('[data-stldocs-copy-content]')!;
|
|
19
|
-
|
|
20
|
-
const contentCopy = content.cloneNode(true) as HTMLElement;
|
|
21
|
-
|
|
22
|
-
contentCopy.querySelectorAll('.ellipsis').forEach((el) => el.remove());
|
|
23
|
-
if (EXPERIMENTAL_COLLAPSIBLE_SNIPPETS && isContentCollapsed) {
|
|
24
|
-
contentCopy.querySelectorAll('.hidden').forEach((el) => el.remove());
|
|
25
|
-
contentCopy.querySelectorAll('.leading-ws').forEach((el) => el.remove());
|
|
26
|
-
}
|
|
27
|
-
await navigator.clipboard.writeText(contentCopy.textContent!);
|
|
36
|
+
await navigator.clipboard.writeText(getContent(copyButton, false));
|
|
28
37
|
iconElement.innerHTML = checkIcon;
|
|
29
38
|
} catch {
|
|
30
39
|
iconElement.innerHTML = circleAlertIcon;
|
|
@@ -34,4 +43,60 @@ addEventListener('click', async (event) => {
|
|
|
34
43
|
iconElement.innerHTML = copyIcon;
|
|
35
44
|
}, 1000) + '';
|
|
36
45
|
}
|
|
46
|
+
|
|
47
|
+
const playButton = (event.target as HTMLElement).closest('[data-stldocs-snippet-play]') as HTMLElement;
|
|
48
|
+
if (playButton) {
|
|
49
|
+
showPlayground(playButton);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
async function showPlayground(playButton: HTMLElement) {
|
|
54
|
+
if (playButton.getAttribute('aria-disabled') === 'true') return;
|
|
55
|
+
const iconElement = playButton.querySelector('.stldocs-icon') as SVGElement;
|
|
56
|
+
try {
|
|
57
|
+
// use aria-disabled, not disabled, to avoid losing focus
|
|
58
|
+
playButton.setAttribute('aria-disabled', 'true');
|
|
59
|
+
playButton.setAttribute('aria-label', 'Loading playground...');
|
|
60
|
+
playButton.classList.add('stl-ui-button--loading');
|
|
61
|
+
const showPlayground = loadPlayground(playButton);
|
|
62
|
+
await showPlayground();
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.error(e);
|
|
65
|
+
iconElement.innerHTML = circleAlertIcon;
|
|
66
|
+
}
|
|
67
|
+
playButton.removeAttribute('aria-disabled');
|
|
68
|
+
playButton.removeAttribute('aria-label');
|
|
69
|
+
playButton.classList.remove('stl-ui-button--loading');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function loadPlayground(playButton: HTMLElement) {
|
|
73
|
+
(playButton as any).__playgroundLoadPromise ??= (async () => {
|
|
74
|
+
const container = playButton.closest('.stldocs-snippet') as HTMLElement;
|
|
75
|
+
const language = (container.querySelector('.stl-sdk-select') as HTMLElement).dataset.currentValue;
|
|
76
|
+
const code = getContent(playButton, true);
|
|
77
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
78
|
+
if (import.meta.env.DEV) {
|
|
79
|
+
const id = '/@id/astro:scripts/before-hydration.js';
|
|
80
|
+
await import(/* @vite-ignore */ id).catch(console.warn);
|
|
81
|
+
}
|
|
82
|
+
const { createPlayground } = await import('virtual:stl-playground/create');
|
|
83
|
+
return createPlayground({
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
|
+
lang: language as any,
|
|
86
|
+
doc: (language === 'python' ? 'from rich import print\n' : '') + code.trimEnd(),
|
|
87
|
+
container,
|
|
88
|
+
});
|
|
89
|
+
})();
|
|
90
|
+
return async () => {
|
|
91
|
+
const promise = (playButton as any).__playgroundLoadPromise;
|
|
92
|
+
(playButton as any).__playgroundLoadPromise = null;
|
|
93
|
+
await ((await promise) as () => Promise<void>)();
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
document.addEventListener(getPageLoadEvent(), () => {
|
|
97
|
+
if (new URL(location.href).searchParams.has('play')) {
|
|
98
|
+
document.querySelectorAll('[data-stldocs-snippet-play]').forEach((e) => {
|
|
99
|
+
showPlayground(e as HTMLElement);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
37
102
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
2
|
+
const COLLAPSED_HEIGHT = 170;
|
|
3
|
+
|
|
4
|
+
const container = document.querySelector<HTMLElement>('[data-stldocs-property-group="method-description"]');
|
|
5
|
+
|
|
6
|
+
if (!container) return;
|
|
7
|
+
|
|
8
|
+
const toggle = document?.querySelector<HTMLButtonElement>('[data-method-description-toggle]');
|
|
9
|
+
if (!toggle) return;
|
|
10
|
+
|
|
11
|
+
// If content isn't tall enough, don't show the button
|
|
12
|
+
if (container.scrollHeight <= COLLAPSED_HEIGHT + 1) {
|
|
13
|
+
toggle.hidden = true;
|
|
14
|
+
container.dataset.collapsed = 'false';
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Only show button if content is taller than collapsed max height
|
|
19
|
+
if (container.scrollHeight > COLLAPSED_HEIGHT + 1) {
|
|
20
|
+
toggle.hidden = false;
|
|
21
|
+
} else {
|
|
22
|
+
// Not tall enough to need collapsing — show full content and hide button
|
|
23
|
+
container.dataset.collapsed = 'false';
|
|
24
|
+
toggle.hidden = true;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
toggle.addEventListener('click', function () {
|
|
29
|
+
const isCollapsed = container.dataset.collapsed !== 'false';
|
|
30
|
+
container.dataset.collapsed = isCollapsed ? 'false' : 'true';
|
|
31
|
+
toggle.textContent = isCollapsed ? 'Show less' : 'Show more';
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { parseRoute, scrollToPath } from '@stainless-api/docs-ui/
|
|
1
|
+
import { parseRoute, scrollToPath } from '@stainless-api/docs-ui/routing';
|
|
2
2
|
import { BASE_PATH } from 'virtual:stl-starlight-virtual-module';
|
|
3
3
|
import { updateSelectedLanguage } from '../languages';
|
|
4
4
|
import { navigate } from 'astro:transitions/client';
|
|
5
5
|
import { getPageLoadEvent } from '../helpers/getPageLoadEvent.ts';
|
|
6
6
|
|
|
7
|
-
import { initDropdown } from '@stainless-api/docs
|
|
7
|
+
import { initDropdown } from '@stainless-api/docs/components/scripts';
|
|
8
8
|
|
|
9
9
|
history.scrollRestoration = 'auto';
|
|
10
10
|
|
|
@@ -22,10 +22,13 @@ window.addEventListener('popstate', (ev: PopStateEvent) => {
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
document.addEventListener(getPageLoadEvent(), () => {
|
|
25
|
+
const rootElement = document.getElementById('stldocs-snippet-select');
|
|
26
|
+
if (!rootElement) return;
|
|
27
|
+
|
|
25
28
|
initDropdown({
|
|
26
|
-
|
|
29
|
+
root: rootElement,
|
|
27
30
|
onSelect: (value) => {
|
|
28
|
-
const originalLanguage =
|
|
31
|
+
const originalLanguage = rootElement?.dataset.currentValue;
|
|
29
32
|
navigate(updateSelectedLanguage(BASE_PATH, originalLanguage, value));
|
|
30
33
|
},
|
|
31
34
|
});
|
package/plugin/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import react from '@astrojs/react';
|
|
2
2
|
import type { StarlightPlugin } from '@astrojs/starlight/types';
|
|
3
|
-
import type { AstroIntegration } from 'astro';
|
|
3
|
+
import type { AstroIntegration, AstroIntegrationLogger } from 'astro';
|
|
4
|
+
import type { BundledTheme } from 'shiki';
|
|
4
5
|
import { config } from 'dotenv';
|
|
5
6
|
import getPort from 'get-port';
|
|
6
|
-
import { startDevServer } from './cms/server';
|
|
7
|
+
import { startDevServer, type SpecResp } from './cms/server';
|
|
7
8
|
import { buildAlgoliaIndex } from './buildAlgoliaIndex';
|
|
8
9
|
import {
|
|
9
10
|
getAPIReferencePlaceholderItemFromSidebarConfig,
|
|
@@ -21,13 +22,21 @@ import {
|
|
|
21
22
|
type SpecRetrieverConfig,
|
|
22
23
|
} from './loadPluginConfig';
|
|
23
24
|
import { buildVirtualModuleString } from '../shared/virtualModule';
|
|
25
|
+
import type * as StlStarlightVirtualModule from 'virtual:stl-starlight-virtual-module';
|
|
24
26
|
import path from 'path';
|
|
25
27
|
import fs from 'fs';
|
|
28
|
+
import { getSharedLogger } from '../shared/getSharedLogger';
|
|
29
|
+
import { resolveSrcFile } from '../resolveSrcFile';
|
|
30
|
+
import { mkdir } from 'fs/promises';
|
|
31
|
+
import { fileURLToPath } from 'url';
|
|
32
|
+
import prebundleWorkers from 'vite-plugin-prebundle-workers';
|
|
26
33
|
|
|
27
34
|
export { generateAPILink } from './generateAPIReferenceLink';
|
|
28
35
|
export type { ReferenceSidebarConfigItem };
|
|
29
36
|
|
|
30
|
-
config(
|
|
37
|
+
config({
|
|
38
|
+
quiet: true,
|
|
39
|
+
});
|
|
31
40
|
|
|
32
41
|
let sidebarIdCounter = 0;
|
|
33
42
|
|
|
@@ -108,20 +117,24 @@ function tmpGetCMSServerConfig(specRetrieverConfig: SpecRetrieverConfig) {
|
|
|
108
117
|
|
|
109
118
|
async function stlStarlightAstroIntegration(
|
|
110
119
|
pluginConfig: NormalizedStainlessStarlightConfig,
|
|
120
|
+
stlStarlightPluginLogger: AstroIntegrationLogger,
|
|
111
121
|
): Promise<AstroIntegration> {
|
|
112
122
|
const virtualId = `virtual:stl-starlight-virtual-module`;
|
|
113
123
|
// The '\0' prefix tells Vite “this is a virtual module” and prevents it from being resolved again.
|
|
114
124
|
const resolvedId = `\0${virtualId}`;
|
|
125
|
+
let playgroundsBase: string | undefined;
|
|
126
|
+
let buildPlaygrounds;
|
|
115
127
|
|
|
116
128
|
const CMS_PORT = await getPort();
|
|
117
129
|
|
|
118
130
|
const { apiKey, version, devPaths } = tmpGetCMSServerConfig(pluginConfig.specRetrieverConfig);
|
|
119
131
|
|
|
120
|
-
const cmsServer =
|
|
132
|
+
const cmsServer = startDevServer({
|
|
121
133
|
port: CMS_PORT,
|
|
122
|
-
apiKey,
|
|
134
|
+
apiKey: apiKey.value,
|
|
123
135
|
version,
|
|
124
136
|
devPaths,
|
|
137
|
+
logger: stlStarlightPluginLogger,
|
|
125
138
|
getGeneratedSidebarConfig: (id: number) => {
|
|
126
139
|
const config = sidebarConfigs.get(id);
|
|
127
140
|
if (!config) {
|
|
@@ -131,50 +144,98 @@ async function stlStarlightAstroIntegration(
|
|
|
131
144
|
},
|
|
132
145
|
});
|
|
133
146
|
|
|
147
|
+
let building: Promise<void> | undefined;
|
|
148
|
+
let reportError: ((message: string) => void) | null = null;
|
|
149
|
+
let collectedErrors: string[] | null = null;
|
|
150
|
+
|
|
151
|
+
function startPlaygroundsBuild(playgroundsCachePath: string) {
|
|
152
|
+
if (!pluginConfig.experimentalPlaygrounds) return;
|
|
153
|
+
if (building) return building;
|
|
154
|
+
return (building = (async () => {
|
|
155
|
+
const { data: spec, auth } = (await (
|
|
156
|
+
await fetch(`http://localhost:${CMS_PORT}/retrieve_spec`, {
|
|
157
|
+
method: 'POST',
|
|
158
|
+
body: JSON.stringify({}),
|
|
159
|
+
})
|
|
160
|
+
).json()) as SpecResp;
|
|
161
|
+
if (!spec || !auth) throw new Error('expected spec');
|
|
162
|
+
|
|
163
|
+
const langs = (spec.docs?.languages ?? ['http'])
|
|
164
|
+
.filter((lang) => lang !== 'terraform')
|
|
165
|
+
.filter((lang) => !pluginConfig.excludeLanguages?.includes(lang));
|
|
166
|
+
|
|
167
|
+
await buildPlaygrounds!({
|
|
168
|
+
spec,
|
|
169
|
+
langs,
|
|
170
|
+
auth,
|
|
171
|
+
playPath: playgroundsCachePath,
|
|
172
|
+
reportError(message: string) {
|
|
173
|
+
(reportError ?? console.error)(message);
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
})());
|
|
177
|
+
}
|
|
178
|
+
|
|
134
179
|
return {
|
|
135
180
|
name: 'stl-starlight-astro',
|
|
136
181
|
hooks: {
|
|
137
|
-
'astro:config:setup': async ({
|
|
182
|
+
'astro:config:setup': async ({
|
|
183
|
+
injectRoute,
|
|
184
|
+
updateConfig,
|
|
185
|
+
logger: localLogger,
|
|
186
|
+
command,
|
|
187
|
+
config: astroConfig,
|
|
188
|
+
}) => {
|
|
189
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
138
190
|
const projectDir = astroConfig.root.pathname;
|
|
139
191
|
|
|
192
|
+
reportError = (message: string) => logger.error(message);
|
|
193
|
+
|
|
194
|
+
if (pluginConfig.experimentalPlaygrounds) {
|
|
195
|
+
playgroundsBase = pluginConfig.experimentalPlaygrounds.playgroundsBase;
|
|
196
|
+
}
|
|
197
|
+
|
|
140
198
|
const middlewareFile = path.join(projectDir, 'middleware.stainless.ts');
|
|
141
199
|
|
|
142
200
|
let vmMiddlewareExport = 'export const MIDDLEWARE = {};';
|
|
143
201
|
if (fs.existsSync(middlewareFile)) {
|
|
144
|
-
logger.
|
|
202
|
+
logger.debug(`Loading middleware from ${middlewareFile}`);
|
|
145
203
|
vmMiddlewareExport = `export { default as MIDDLEWARE } from '${middlewareFile}';`;
|
|
146
204
|
}
|
|
147
205
|
|
|
148
206
|
injectRoute({
|
|
149
|
-
pattern: `${pluginConfig.basePath}/[...slug].md`,
|
|
150
|
-
entrypoint: '
|
|
207
|
+
pattern: `${pluginConfig.basePath}/[...slug]/index.md`,
|
|
208
|
+
entrypoint: resolveSrcFile('/plugin/routes/markdown.ts'),
|
|
151
209
|
prerender: command === 'build',
|
|
152
210
|
});
|
|
153
211
|
|
|
154
|
-
const astroFile = command === 'build' ? '
|
|
212
|
+
const astroFile = command === 'build' ? 'DocsStatic' : 'Docs';
|
|
155
213
|
injectRoute({
|
|
156
214
|
pattern: `${pluginConfig.basePath}/[...slug]`,
|
|
157
|
-
|
|
158
|
-
entrypoint: `@stainless-api/docs/${astroFile}`,
|
|
215
|
+
entrypoint: resolveSrcFile(`/plugin/routes/${astroFile}.astro`),
|
|
159
216
|
prerender: command === 'build',
|
|
160
217
|
});
|
|
161
218
|
|
|
162
219
|
injectRoute({
|
|
163
220
|
pattern: pluginConfig.basePath,
|
|
164
|
-
entrypoint: '
|
|
221
|
+
entrypoint: resolveSrcFile('/plugin/routes/Overview.astro'),
|
|
165
222
|
prerender: command === 'build',
|
|
166
223
|
});
|
|
167
224
|
|
|
168
225
|
updateConfig({
|
|
169
226
|
vite: {
|
|
170
|
-
ssr: {
|
|
171
|
-
noExternal: ['@stainless-api/ui-primitives'],
|
|
172
|
-
},
|
|
173
|
-
optimizeDeps: { include: ['@stainless-api/ui-primitives'] },
|
|
174
227
|
plugins: [
|
|
175
228
|
{
|
|
176
229
|
name: 'stl-starlight-vite',
|
|
177
|
-
|
|
230
|
+
buildStart() {
|
|
231
|
+
building = undefined;
|
|
232
|
+
},
|
|
233
|
+
async configureServer(server) {
|
|
234
|
+
if (playgroundsBase) {
|
|
235
|
+
buildPlaygrounds = (await server.ssrLoadModule(playgroundsBase + '/src/build.ts'))
|
|
236
|
+
.buildPlaygrounds;
|
|
237
|
+
}
|
|
238
|
+
|
|
178
239
|
for (const filePath of Object.values(devPaths)) {
|
|
179
240
|
if (!filePath) {
|
|
180
241
|
continue;
|
|
@@ -197,6 +258,30 @@ async function stlStarlightAstroIntegration(
|
|
|
197
258
|
if (id === virtualId) {
|
|
198
259
|
return resolvedId;
|
|
199
260
|
}
|
|
261
|
+
if (id === 'virtual:stl-playground/unstable-update-language') {
|
|
262
|
+
return resolveSrcFile('plugin/languages.ts');
|
|
263
|
+
}
|
|
264
|
+
if (id === 'virtual:stl-playground/create') {
|
|
265
|
+
return fileURLToPath(
|
|
266
|
+
new URL(
|
|
267
|
+
pluginConfig.experimentalPlaygrounds
|
|
268
|
+
? path.join(playgroundsBase!, '/src/create.tsx')
|
|
269
|
+
: './create-playground.shim.tsx',
|
|
270
|
+
import.meta.url,
|
|
271
|
+
),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
if (id.startsWith('virtual:stl-playground/')) {
|
|
275
|
+
const result = path.join(
|
|
276
|
+
this.environment.getTopLevelConfig().cacheDir,
|
|
277
|
+
'stl-playground',
|
|
278
|
+
id.slice('virtual:stl-playground/'.length),
|
|
279
|
+
);
|
|
280
|
+
const config = this.environment.getTopLevelConfig();
|
|
281
|
+
return startPlaygroundsBuild(path.join(config.cacheDir, 'stl-playground'))?.then(
|
|
282
|
+
() => result,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
200
285
|
},
|
|
201
286
|
load(id) {
|
|
202
287
|
if (id === resolvedId) {
|
|
@@ -204,21 +289,40 @@ async function stlStarlightAstroIntegration(
|
|
|
204
289
|
buildVirtualModuleString({
|
|
205
290
|
BASE_PATH: pluginConfig.basePath,
|
|
206
291
|
CMS_PORT,
|
|
207
|
-
EXCLUDE_LANGUAGES: pluginConfig.excludeLanguages,
|
|
292
|
+
EXCLUDE_LANGUAGES: ['php', ...pluginConfig.excludeLanguages],
|
|
208
293
|
DEFAULT_LANGUAGE: pluginConfig.defaultLanguage,
|
|
209
294
|
BREADCRUMB_CONFIG: pluginConfig.breadcrumbs,
|
|
210
295
|
EXPAND_RESOURCES: pluginConfig.expandResources,
|
|
211
296
|
HIGHLIGHT_THEMES: pluginConfig.highlighting.themes,
|
|
212
297
|
CONTENT_PANEL_LAYOUT: pluginConfig.contentPanel.layout,
|
|
213
298
|
EXPERIMENTAL_COLLAPSIBLE_SNIPPETS: pluginConfig.experimentalCollapsibleSnippets,
|
|
299
|
+
EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS:
|
|
300
|
+
pluginConfig.experimentalCollapsibleMethodDescriptions,
|
|
214
301
|
PROPERTY_SETTINGS: pluginConfig.propertySettings,
|
|
215
|
-
|
|
216
|
-
|
|
302
|
+
ENABLE_CONTEXT_MENU: pluginConfig.contextMenu,
|
|
303
|
+
EXPERIMENTAL_PLAYGROUNDS: !!pluginConfig.experimentalPlaygrounds,
|
|
304
|
+
STAINLESS_PROJECT: version.stainlessProject,
|
|
305
|
+
} satisfies Omit<typeof StlStarlightVirtualModule, 'MIDDLEWARE'>),
|
|
217
306
|
vmMiddlewareExport,
|
|
218
307
|
].join('\n');
|
|
219
308
|
}
|
|
220
309
|
},
|
|
221
310
|
},
|
|
311
|
+
prebundleWorkers({
|
|
312
|
+
include: [
|
|
313
|
+
'**/typescript/runner*',
|
|
314
|
+
'**/typescript/worker*',
|
|
315
|
+
'**/pyright.worker*',
|
|
316
|
+
'**/python/pyodide*',
|
|
317
|
+
],
|
|
318
|
+
configureEsBuild(_, opts) {
|
|
319
|
+
opts.external ??= [];
|
|
320
|
+
opts.external.push('url');
|
|
321
|
+
opts.loader ??= {};
|
|
322
|
+
opts.loader['.wasm'] = 'dataurl';
|
|
323
|
+
return opts;
|
|
324
|
+
},
|
|
325
|
+
}),
|
|
222
326
|
],
|
|
223
327
|
},
|
|
224
328
|
});
|
|
@@ -226,6 +330,24 @@ async function stlStarlightAstroIntegration(
|
|
|
226
330
|
'astro:server:done': async () => {
|
|
227
331
|
await cmsServer.destroy();
|
|
228
332
|
},
|
|
333
|
+
'astro:build:start'({ logger }) {
|
|
334
|
+
collectedErrors = [];
|
|
335
|
+
reportError = (message: string) => {
|
|
336
|
+
logger.error(message);
|
|
337
|
+
collectedErrors!.push(message);
|
|
338
|
+
};
|
|
339
|
+
},
|
|
340
|
+
'astro:build:done': async ({ dir, logger }) => {
|
|
341
|
+
const dist = fileURLToPath(dir);
|
|
342
|
+
const stainlessDir = path.join(dist, '_stainless');
|
|
343
|
+
await mkdir(stainlessDir, { recursive: true });
|
|
344
|
+
if (collectedErrors) {
|
|
345
|
+
for (const error of collectedErrors) {
|
|
346
|
+
logger.error(error);
|
|
347
|
+
}
|
|
348
|
+
collectedErrors = null;
|
|
349
|
+
}
|
|
350
|
+
},
|
|
229
351
|
},
|
|
230
352
|
};
|
|
231
353
|
}
|
|
@@ -241,15 +363,20 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
241
363
|
command,
|
|
242
364
|
config: starlightConfig,
|
|
243
365
|
astroConfig,
|
|
244
|
-
logger,
|
|
366
|
+
logger: localLogger,
|
|
245
367
|
}) => {
|
|
246
368
|
if (command !== 'build' && command !== 'dev') {
|
|
247
369
|
return;
|
|
248
370
|
}
|
|
249
371
|
|
|
372
|
+
const logger = getSharedLogger({ fallback: localLogger });
|
|
373
|
+
|
|
250
374
|
const configParseResult = parseStarlightPluginConfig(someUserConfig, command);
|
|
251
375
|
if (configParseResult.result === 'error') {
|
|
252
|
-
|
|
376
|
+
const errorLines = configParseResult.message.split('\n');
|
|
377
|
+
for (const line of errorLines) {
|
|
378
|
+
logger.error(line);
|
|
379
|
+
}
|
|
253
380
|
process.exit(1);
|
|
254
381
|
}
|
|
255
382
|
const config = configParseResult.config;
|
|
@@ -260,17 +387,30 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
260
387
|
addIntegration(react());
|
|
261
388
|
}
|
|
262
389
|
|
|
390
|
+
if ('apiKey' in config.specRetrieverConfig) {
|
|
391
|
+
if (!config.specRetrieverConfig.apiKey) {
|
|
392
|
+
logger.info(`Stainless credentials not loaded`);
|
|
393
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'explicit-config') {
|
|
394
|
+
logger.info(`Stainless credentials loaded from user config`);
|
|
395
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'environment-variable') {
|
|
396
|
+
logger.info('Stainless credentials loaded from `STAINLESS_API_KEY` environment variable');
|
|
397
|
+
} else if (config.specRetrieverConfig.apiKey.source === 'cli') {
|
|
398
|
+
logger.info('Stainless credentials loaded from `stl` CLI');
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
263
402
|
if (
|
|
264
403
|
command === 'build' &&
|
|
265
404
|
config.specRetrieverConfig.kind === 'local_spec_server_with_remote_files'
|
|
266
405
|
) {
|
|
267
406
|
await buildAlgoliaIndex({
|
|
268
407
|
version: config.specRetrieverConfig.version,
|
|
269
|
-
apiKey: config.specRetrieverConfig.apiKey,
|
|
408
|
+
apiKey: config.specRetrieverConfig.apiKey.value,
|
|
409
|
+
logger,
|
|
270
410
|
});
|
|
271
411
|
}
|
|
272
412
|
|
|
273
|
-
addIntegration(await stlStarlightAstroIntegration(config));
|
|
413
|
+
addIntegration(await stlStarlightAstroIntegration(config, logger));
|
|
274
414
|
|
|
275
415
|
if (starlightConfig.sidebar) {
|
|
276
416
|
// for pagination (https://starlight.astro.build/reference/configuration/#pagination) to work correctly
|
|
@@ -281,21 +421,25 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
281
421
|
}
|
|
282
422
|
}
|
|
283
423
|
|
|
284
|
-
const
|
|
424
|
+
const expressiveCodeConfig =
|
|
285
425
|
typeof starlightConfig.expressiveCode === 'object' ? starlightConfig.expressiveCode : {};
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
},
|
|
291
|
-
});
|
|
426
|
+
|
|
427
|
+
const themes = expressiveCodeConfig.themes
|
|
428
|
+
? (expressiveCodeConfig.themes as BundledTheme[])
|
|
429
|
+
: (['github-light', 'github-dark'] as BundledTheme[]);
|
|
292
430
|
|
|
293
431
|
updateConfig({
|
|
294
432
|
sidebar: starlightConfig.sidebar,
|
|
433
|
+
...(expressiveCodeConfig && {
|
|
434
|
+
expressiveCode: {
|
|
435
|
+
...expressiveCodeConfig,
|
|
436
|
+
themes,
|
|
437
|
+
},
|
|
438
|
+
}),
|
|
295
439
|
});
|
|
296
440
|
|
|
297
441
|
addRouteMiddleware({
|
|
298
|
-
entrypoint: '
|
|
442
|
+
entrypoint: resolveSrcFile('/plugin/replaceSidebarPlaceholderMiddleware.ts'),
|
|
299
443
|
order: 'post',
|
|
300
444
|
});
|
|
301
445
|
},
|
|
@@ -304,5 +448,5 @@ export function stainlessStarlight(someUserConfig: SomeStainlessStarlightUserCon
|
|
|
304
448
|
}
|
|
305
449
|
|
|
306
450
|
// Additional exports we want for Stainless <-> docs integration.
|
|
307
|
-
export { parseStainlessPath } from '@stainless-api/docs-ui/
|
|
308
|
-
export { renderMarkdown } from '@stainless-api/docs-ui/
|
|
451
|
+
export { parseStainlessPath } from '@stainless-api/docs-ui/routing';
|
|
452
|
+
export { renderMarkdown } from '@stainless-api/docs-ui/markdown';
|
package/plugin/languages.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DocsLanguage } from '@stainless-api/docs-ui/
|
|
1
|
+
import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
2
2
|
import KotlinIcon from './assets/languages/kotlin.svg';
|
|
3
3
|
import RubyIcon from './assets/languages/ruby.svg';
|
|
4
4
|
import TerraformIcon from './assets/languages/terraform.svg';
|
|
@@ -7,6 +7,7 @@ import PythonIcon from './assets/languages/python.svg';
|
|
|
7
7
|
import JavaIcon from './assets/languages/java.svg';
|
|
8
8
|
import GoIcon from './assets/languages/go.svg';
|
|
9
9
|
import CurlIcon from './assets/languages/curl.svg';
|
|
10
|
+
import CSharpIcon from './assets/languages/csharp.svg';
|
|
10
11
|
|
|
11
12
|
export const Languages: Record<
|
|
12
13
|
DocsLanguage,
|
|
@@ -29,6 +30,8 @@ export const Languages: Record<
|
|
|
29
30
|
http: { name: 'HTTP', icon: CurlIcon, alt: 'HTTP logo' },
|
|
30
31
|
terraform: { name: 'Terraform', icon: TerraformIcon, alt: 'Terraform logo' },
|
|
31
32
|
ruby: { name: 'Ruby', icon: RubyIcon, alt: 'Ruby logo' },
|
|
33
|
+
csharp: { name: 'C#', icon: CSharpIcon, alt: 'C# logo' },
|
|
34
|
+
php: { name: 'PHP', icon: CSharpIcon, alt: 'PHP logo' }, // TODO update PHP icon
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
export function generatePrefix(basePath: string, language: string) {
|
|
@@ -44,7 +47,7 @@ export function applyLanguageToLinks(basePath?: string, defaultLanguage?: string
|
|
|
44
47
|
`[data-stldocs-overview],[data-stldocs-method],a.nav-link[href^='${basePath}']`,
|
|
45
48
|
);
|
|
46
49
|
|
|
47
|
-
for (
|
|
50
|
+
for (const link of links) {
|
|
48
51
|
const href = link.getAttribute('href');
|
|
49
52
|
const prefix = generatePrefix(basePath, language);
|
|
50
53
|
if (href?.startsWith(basePath) && !href?.startsWith(prefix)) {
|