@stainless-api/docs 0.1.0-beta.5 → 0.1.0-beta.50
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 +381 -0
- package/eslint-suppressions.json +47 -0
- package/locals.d.ts +14 -0
- package/package.json +42 -38
- package/plugin/buildAlgoliaIndex.ts +31 -6
- package/plugin/cms/server.ts +98 -56
- package/plugin/cms/sidebar-builder.ts +7 -26
- package/plugin/cms/worker.ts +3 -3
- package/plugin/components/MethodDescription.tsx +54 -0
- package/plugin/components/SDKSelect.astro +7 -87
- package/plugin/components/SnippetCode.tsx +11 -7
- package/plugin/components/search/SearchAlgolia.astro +5 -33
- package/plugin/components/search/SearchIsland.tsx +37 -23
- package/plugin/generateAPIReferenceLink.ts +2 -2
- package/plugin/globalJs/ai-dropdown-options.ts +235 -0
- package/plugin/globalJs/method-descriptions.ts +33 -0
- package/plugin/globalJs/navigation.ts +7 -27
- package/plugin/helpers/getPageLoadEvent.ts +1 -1
- package/plugin/index.ts +54 -34
- package/plugin/languages.ts +2 -2
- package/plugin/loadPluginConfig.ts +112 -32
- package/plugin/middlewareBuilder/stainlessMiddleware.d.ts +1 -1
- package/plugin/react/Routing.tsx +176 -80
- package/plugin/referencePlaceholderUtils.ts +1 -1
- package/plugin/replaceSidebarPlaceholderMiddleware.ts +5 -1
- package/plugin/routes/Docs.astro +60 -85
- package/plugin/routes/Overview.astro +10 -16
- package/plugin/routes/markdown.ts +7 -7
- package/plugin/vendor/preview.worker.docs.js +17973 -16561
- 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 +1 -1
- 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/{content-panel/ContentBreadcrumbs.tsx → ContentBreadcrumbs.tsx} +2 -2
- package/stl-docs/components/Head.astro +16 -0
- package/stl-docs/components/Header.astro +6 -8
- package/stl-docs/components/PageTitle.astro +82 -0
- package/stl-docs/components/TableOfContents.astro +34 -0
- package/stl-docs/components/ThemeSelect.astro +118 -141
- package/stl-docs/components/content-panel/ContentPanel.astro +16 -46
- package/stl-docs/components/headers/DefaultHeader.astro +1 -1
- package/stl-docs/components/headers/HeaderLinks.astro +1 -1
- 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 -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 +31 -75
- 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 +4 -3
- package/stl-docs/components/pagination/HomeLink.astro +10 -0
- package/stl-docs/components/pagination/Pagination.astro +174 -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/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 +98 -26
- package/stl-docs/loadStlDocsConfig.ts +37 -5
- 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 +104 -141
- package/styles/fonts.css +32 -17
- package/styles/links.css +11 -48
- package/styles/method-descriptions.css +36 -0
- package/styles/overrides.css +49 -57
- package/styles/page.css +90 -59
- 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 +12 -2
- package/tsconfig.json +2 -5
- package/virtual-module.d.ts +8 -4
- package/components/variables.css +0 -139
- 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/{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/cms/server.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import type { AstroIntegrationLogger } from 'astro';
|
|
1
2
|
import { createServer, IncomingMessage } from 'http';
|
|
2
3
|
import { readFile } from 'fs/promises';
|
|
3
4
|
|
|
4
|
-
import type * as SDKJSON from '
|
|
5
|
+
import type * as SDKJSON from '@stainless/sdk-json';
|
|
5
6
|
import { createSDKJSON, parseInputs, transformOAS } from './worker';
|
|
6
|
-
import { Languages, parseRoute, type DocsLanguage } from '@stainless-api/docs-ui/
|
|
7
|
-
import Stainless from '@stainless-api/sdk';
|
|
7
|
+
import { Languages, parseRoute, type DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
8
|
+
import Stainless, { APIError } from '@stainless-api/sdk';
|
|
8
9
|
|
|
9
10
|
import {
|
|
10
11
|
toStarlightSidebar,
|
|
@@ -12,88 +13,117 @@ import {
|
|
|
12
13
|
SidebarConfigItemsBuilder,
|
|
13
14
|
} from './sidebar-builder';
|
|
14
15
|
import type { VersionUserConfig } from '../loadPluginConfig';
|
|
15
|
-
|
|
16
|
+
import { bold } from '../../shared/terminalUtils';
|
|
16
17
|
export type InputFilePaths = {
|
|
17
18
|
oasPath?: string;
|
|
18
19
|
configPath?: string;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
|
-
async function versionInfo(project: string, apiKey: string) {
|
|
22
|
+
async function versionInfo(project: string, apiKey: string): Promise<Record<DocsLanguage, string>> {
|
|
22
23
|
const data = await fetch(`https://api.stainless.com/api/projects/${project}/package-versions`, {
|
|
23
24
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
const content = await data.text();
|
|
27
|
-
return JSON.parse(content)
|
|
28
|
+
return JSON.parse(content) as Record<DocsLanguage, string>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function redactApiKey(apiKey: string) {
|
|
32
|
+
return apiKey
|
|
33
|
+
.split('')
|
|
34
|
+
.map((char, index) => (index < 10 ? char : '*'))
|
|
35
|
+
.join('');
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
async function loadSpec({
|
|
31
39
|
apiKey,
|
|
32
40
|
devPaths,
|
|
33
41
|
version,
|
|
42
|
+
logger,
|
|
34
43
|
}: {
|
|
35
44
|
apiKey: string;
|
|
36
45
|
devPaths: InputFilePaths;
|
|
37
46
|
version: VersionUserConfig;
|
|
47
|
+
logger: AstroIntegrationLogger;
|
|
38
48
|
}) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
async function unsafeLoad() {
|
|
50
|
+
let oasStr: string;
|
|
51
|
+
let configStr: string;
|
|
52
|
+
let versions: Record<DocsLanguage, string> | undefined;
|
|
53
|
+
|
|
54
|
+
if (devPaths.oasPath && devPaths.configPath) {
|
|
55
|
+
[oasStr, configStr] = await Promise.all([
|
|
56
|
+
readFile(devPaths.oasPath, 'utf-8'),
|
|
57
|
+
readFile(devPaths.configPath, 'utf-8'),
|
|
58
|
+
]);
|
|
59
|
+
} else {
|
|
60
|
+
const client = new Stainless({ apiKey });
|
|
61
|
+
const configs = await client.projects.configs.retrieve({
|
|
62
|
+
project: version.stainlessProject,
|
|
63
|
+
branch: version.branch,
|
|
64
|
+
include: 'openapi',
|
|
65
|
+
});
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
versions = await versionInfo(version.stainlessProject, apiKey);
|
|
57
68
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
const configYML = Object.values(configs)[0] as { content: any };
|
|
70
|
+
const oasJson = Object.values(configs)[1] as { content: any };
|
|
71
|
+
oasStr = oasJson['content'];
|
|
72
|
+
configStr = configYML['content'];
|
|
73
|
+
}
|
|
63
74
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
75
|
+
const { oas, config } = await parseInputs({
|
|
76
|
+
oas: oasStr,
|
|
77
|
+
config: configStr,
|
|
78
|
+
});
|
|
68
79
|
|
|
69
|
-
|
|
80
|
+
const transformedOAS = await transformOAS({ oas, config });
|
|
70
81
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
const languages =
|
|
83
|
+
config.docs?.languages ??
|
|
84
|
+
(Object.entries(config.targets)
|
|
85
|
+
// @ts-expect-error we don't have the actual Stainless config type here
|
|
86
|
+
.filter(([name, target]) => Languages.includes(name) && !target.skip)
|
|
87
|
+
.map(([name]) => name) as SDKJSON.SpecLanguage[]);
|
|
77
88
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
const sdkJson = await createSDKJSON({
|
|
90
|
+
oas: transformedOAS,
|
|
91
|
+
config,
|
|
92
|
+
languages,
|
|
93
|
+
});
|
|
83
94
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
if (versions) {
|
|
96
|
+
for (const [lang, version] of Object.entries(versions)) {
|
|
97
|
+
const meta = sdkJson.metadata[lang as DocsLanguage];
|
|
98
|
+
if (meta?.version) meta.version = version;
|
|
99
|
+
}
|
|
88
100
|
}
|
|
101
|
+
|
|
102
|
+
const id = crypto.randomUUID();
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
data: sdkJson,
|
|
106
|
+
id,
|
|
107
|
+
};
|
|
89
108
|
}
|
|
90
109
|
|
|
91
|
-
|
|
110
|
+
try {
|
|
111
|
+
const result = await unsafeLoad();
|
|
112
|
+
return result;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
logger.error(bold('Failed to fetch API reference information from Stainless:'));
|
|
115
|
+
if (error instanceof APIError && error.status >= 400 && error.status < 500) {
|
|
116
|
+
logger.error(`Requested project slug: "${version.stainlessProject}"`);
|
|
117
|
+
logger.error(`API key: "${redactApiKey(apiKey)}"`);
|
|
118
|
+
logger.error(
|
|
119
|
+
`This error can usually be corrected by re-authenticating with the Stainless. Use the CLI (stl auth login) or verify that the Stainless API key you're using can access the project mentioned above.`,
|
|
120
|
+
);
|
|
121
|
+
} else {
|
|
122
|
+
logger.error(error instanceof Error ? error.message : 'Unknown error');
|
|
123
|
+
}
|
|
92
124
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
id,
|
|
96
|
-
};
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
97
127
|
}
|
|
98
128
|
|
|
99
129
|
class Spec {
|
|
@@ -107,6 +137,7 @@ class Spec {
|
|
|
107
137
|
apiKey: this.apiKey,
|
|
108
138
|
devPaths: this.devPaths,
|
|
109
139
|
version: this.version,
|
|
140
|
+
logger: this.logger,
|
|
110
141
|
});
|
|
111
142
|
}
|
|
112
143
|
|
|
@@ -128,15 +159,22 @@ class Spec {
|
|
|
128
159
|
return spec;
|
|
129
160
|
}
|
|
130
161
|
|
|
131
|
-
constructor(
|
|
162
|
+
constructor(
|
|
163
|
+
apiKey: string,
|
|
164
|
+
version: VersionUserConfig,
|
|
165
|
+
devPaths: InputFilePaths,
|
|
166
|
+
private logger: AstroIntegrationLogger,
|
|
167
|
+
) {
|
|
132
168
|
this.specPromise = loadSpec({
|
|
133
169
|
apiKey,
|
|
134
170
|
devPaths,
|
|
135
171
|
version,
|
|
172
|
+
logger,
|
|
136
173
|
});
|
|
137
174
|
this.devPaths = devPaths;
|
|
138
175
|
this.apiKey = apiKey;
|
|
139
176
|
this.version = version;
|
|
177
|
+
this.logger = logger;
|
|
140
178
|
}
|
|
141
179
|
}
|
|
142
180
|
|
|
@@ -166,14 +204,16 @@ export function startDevServer({
|
|
|
166
204
|
devPaths,
|
|
167
205
|
apiKey,
|
|
168
206
|
getGeneratedSidebarConfig,
|
|
207
|
+
logger,
|
|
169
208
|
}: {
|
|
170
209
|
port: number;
|
|
171
210
|
version: VersionUserConfig;
|
|
172
211
|
devPaths: InputFilePaths;
|
|
173
212
|
apiKey: string;
|
|
174
213
|
getGeneratedSidebarConfig: (id: number) => GeneratedSidebarConfig | null;
|
|
214
|
+
logger: AstroIntegrationLogger;
|
|
175
215
|
}) {
|
|
176
|
-
const spec = new Spec(apiKey, version, devPaths);
|
|
216
|
+
const spec = new Spec(apiKey, version, devPaths, logger);
|
|
177
217
|
|
|
178
218
|
const server = createServer(async (req, res) => {
|
|
179
219
|
// Add CORS headers
|
|
@@ -250,7 +290,7 @@ export function startDevServer({
|
|
|
250
290
|
});
|
|
251
291
|
|
|
252
292
|
server.listen(port, () => {
|
|
253
|
-
|
|
293
|
+
logger.debug(`Stainless spec server is running on port: ${port}`);
|
|
254
294
|
});
|
|
255
295
|
|
|
256
296
|
return {
|
|
@@ -266,3 +306,5 @@ export function startDevServer({
|
|
|
266
306
|
},
|
|
267
307
|
};
|
|
268
308
|
}
|
|
309
|
+
|
|
310
|
+
export type DevSpecServer = Awaited<ReturnType<typeof startDevServer>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type * as SDKJSON from '
|
|
2
|
-
import { generateRoute, walkTree, type DocsLanguage } from '@stainless-api/docs-ui/
|
|
1
|
+
import type * as SDKJSON from '@stainless/sdk-json';
|
|
2
|
+
import { generateRoute, walkTree, type DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
3
3
|
import type { StarlightRouteData } from '@astrojs/starlight/route-data';
|
|
4
4
|
|
|
5
5
|
function isResourceNonEmpty(resource: SDKJSON.Resource) {
|
|
@@ -120,22 +120,12 @@ export type GeneratedSidebarConfig = {
|
|
|
120
120
|
};
|
|
121
121
|
|
|
122
122
|
function countKeys(obj?: Record<string, any>) {
|
|
123
|
-
|
|
123
|
+
const o = obj ?? {};
|
|
124
124
|
return Object.keys(o).length;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const decl = decls[entry.stainlessPath];
|
|
130
|
-
if (decl !== undefined) {
|
|
131
|
-
if ('ident' in decl) {
|
|
132
|
-
return decl;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
type MethodDecl = Exclude<ReturnType<typeof getMethodDeclForLanguage>, null>;
|
|
127
|
+
type HasIdent<T> = T extends { ident: unknown } ? T : never;
|
|
128
|
+
type MethodDecl = HasIdent<SDKJSON.LanguageDeclNodes[SDKJSON.SpecLanguage]>;
|
|
139
129
|
|
|
140
130
|
function makeAPIOverviewPage(): UserSidebarAPIOverviewPage {
|
|
141
131
|
return {
|
|
@@ -166,7 +156,7 @@ function pullOutSharedModelsResource(resources: SDKJSON.Resource[]): {
|
|
|
166
156
|
}
|
|
167
157
|
|
|
168
158
|
export class SidebarConfigItemsBuilder {
|
|
169
|
-
private getMethodDeclForLanguage(entry: SDKJSON.Method) {
|
|
159
|
+
private getMethodDeclForLanguage(entry: SDKJSON.Method): MethodDecl | null {
|
|
170
160
|
const decls = this.spec.decls[this.language] ?? {};
|
|
171
161
|
const decl = decls[entry.stainlessPath];
|
|
172
162
|
if (decl !== undefined) {
|
|
@@ -208,13 +198,6 @@ export class SidebarConfigItemsBuilder {
|
|
|
208
198
|
};
|
|
209
199
|
}
|
|
210
200
|
|
|
211
|
-
private sortByLabel<T extends UserSidebarConfigItem>(items: T[]) {
|
|
212
|
-
// sorts in place
|
|
213
|
-
items.sort((a, b) => {
|
|
214
|
-
return a.label.localeCompare(b.label);
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
201
|
private generateResourceGroup(resource: SDKJSON.Resource, collapsed: boolean): ReferenceSidebarGroup {
|
|
219
202
|
const entries: ReferenceSidebarConfigItem[] = [];
|
|
220
203
|
if (!this.options?.excludeResourceOverviewPages) {
|
|
@@ -228,7 +211,6 @@ export class SidebarConfigItemsBuilder {
|
|
|
228
211
|
methodPages.push(this.toMethodPage(m, langDecl));
|
|
229
212
|
}
|
|
230
213
|
}
|
|
231
|
-
this.sortByLabel(methodPages);
|
|
232
214
|
entries.push(...methodPages);
|
|
233
215
|
|
|
234
216
|
const subresources = Object.values(resource.subresources ?? {});
|
|
@@ -238,7 +220,6 @@ export class SidebarConfigItemsBuilder {
|
|
|
238
220
|
subresourceGroups.push(this.generateResourceGroup(sub, true));
|
|
239
221
|
}
|
|
240
222
|
}
|
|
241
|
-
this.sortByLabel(subresourceGroups);
|
|
242
223
|
entries.push(...subresourceGroups);
|
|
243
224
|
|
|
244
225
|
return {
|
|
@@ -253,7 +234,7 @@ export class SidebarConfigItemsBuilder {
|
|
|
253
234
|
|
|
254
235
|
public generateItems(): ReferenceSidebarConfigItem[] {
|
|
255
236
|
const resourceMap = this.spec.resources;
|
|
256
|
-
|
|
237
|
+
const { resources, sharedModelsResource } = pullOutSharedModelsResource(Object.values(resourceMap ?? {}));
|
|
257
238
|
|
|
258
239
|
const entries: ReferenceSidebarConfigItem[] = resources.filter(isResourceNonEmpty).map((r) => {
|
|
259
240
|
return this.generateResourceGroup(r, false);
|
package/plugin/cms/worker.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Worker from 'web-worker';
|
|
2
|
-
import { Languages, type DocsLanguage } from '@stainless-api/docs-ui/
|
|
3
|
-
import type * as SDKJSON from '
|
|
2
|
+
import { Languages, type DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
3
|
+
import type * as SDKJSON from '@stainless/sdk-json';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { dirname, resolve } from 'node:path';
|
|
6
6
|
import fs from 'fs/promises';
|
|
@@ -98,7 +98,7 @@ export async function createSDKJSON({
|
|
|
98
98
|
try {
|
|
99
99
|
const content = await fs.readFile(mdfile);
|
|
100
100
|
return [language, content.toString()];
|
|
101
|
-
} catch
|
|
101
|
+
} catch {
|
|
102
102
|
return [language, null];
|
|
103
103
|
}
|
|
104
104
|
}),
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { MethodDescriptionProps } from '@stainless-api/docs-ui/components';
|
|
2
|
+
import { useComponents } from '@stainless-api/docs-ui/contexts/use-components';
|
|
3
|
+
import style from '@stainless-api/docs-ui/style';
|
|
4
|
+
import { Button } from '@stainless-api/ui-primitives';
|
|
5
|
+
|
|
6
|
+
function shouldCollapseDescription(description: string) {
|
|
7
|
+
const MIN_CHARS = 400;
|
|
8
|
+
const MIN_LINES = 6;
|
|
9
|
+
|
|
10
|
+
const lineCount = description.split('\n').length;
|
|
11
|
+
|
|
12
|
+
if (description.length >= MIN_CHARS) return true;
|
|
13
|
+
if (lineCount >= MIN_LINES) return true;
|
|
14
|
+
|
|
15
|
+
// Markdown structure often means longer content
|
|
16
|
+
if (/#\s/.test(description)) return true; // has headings
|
|
17
|
+
if (/```/.test(description)) return true; // has code blocks
|
|
18
|
+
if (/^\s*[-*]\s+/m.test(description)) return true; // has lists
|
|
19
|
+
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function MethodDescription({ description }: MethodDescriptionProps) {
|
|
24
|
+
const { Markdown } = useComponents();
|
|
25
|
+
|
|
26
|
+
if (description) {
|
|
27
|
+
// Attempt to determine if we should make the description collapsible initially
|
|
28
|
+
// or not. If we get this right, there will be no FOUC.
|
|
29
|
+
const collapsible = shouldCollapseDescription(description);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div className="stl-method-description">
|
|
33
|
+
<div
|
|
34
|
+
className={style.MethodDescription}
|
|
35
|
+
data-stldocs-property-group="method-description"
|
|
36
|
+
data-collapsed={collapsible ? 'true' : 'false'}
|
|
37
|
+
>
|
|
38
|
+
<Markdown content={description} />
|
|
39
|
+
</div>
|
|
40
|
+
<div className="stl-method-description-overflow-wrapper">
|
|
41
|
+
<Button
|
|
42
|
+
type="button"
|
|
43
|
+
data-method-description-toggle
|
|
44
|
+
size="sm"
|
|
45
|
+
variant="ghost"
|
|
46
|
+
hidden={!collapsible}
|
|
47
|
+
>
|
|
48
|
+
Show more
|
|
49
|
+
</Button>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { DocsLanguage } from '@stainless-api/docs-ui/
|
|
3
|
-
import { parseRoute } from '@stainless-api/docs-ui/
|
|
2
|
+
import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
3
|
+
import { parseRoute } from '@stainless-api/docs-ui/routing';
|
|
4
4
|
import { cmsClient } from '../cms/client';
|
|
5
5
|
import { BASE_PATH, DEFAULT_LANGUAGE, EXCLUDE_LANGUAGES } from 'virtual:stl-starlight-virtual-module';
|
|
6
6
|
import { Languages } from '../languages';
|
|
@@ -53,100 +53,20 @@ const readmeSlug = language === 'http' ? BASE_PATH : `${BASE_PATH}/${language}`;
|
|
|
53
53
|
)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
<style>
|
|
57
|
-
@layer starlight.core {
|
|
58
|
-
label {
|
|
59
|
-
--sl-label-icon-size: 16px;
|
|
60
|
-
--sl-caret-size: 1.25rem;
|
|
61
|
-
--sl-inline-padding: 0.5rem;
|
|
62
|
-
position: relative;
|
|
63
|
-
display: flex;
|
|
64
|
-
align-items: center;
|
|
65
|
-
gap: 0.25rem;
|
|
66
|
-
color: var(--sl-color-gray-1);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
label:hover {
|
|
70
|
-
color: var(--sl-color-gray-2);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.icon {
|
|
74
|
-
position: absolute;
|
|
75
|
-
top: 50%;
|
|
76
|
-
transform: translateY(-50%);
|
|
77
|
-
pointer-events: none;
|
|
78
|
-
width: 16px;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
select {
|
|
82
|
-
padding-block: 0.3rem;
|
|
83
|
-
padding-inline: calc(var(--sl-label-icon-size) + var(--sl-inline-padding) + 0.5rem)
|
|
84
|
-
calc(var(--sl-caret-size) + var(--sl-inline-padding) + 0.25rem);
|
|
85
|
-
margin-inline: calc(var(--sl-inline-padding) * -1);
|
|
86
|
-
width: calc(var(--sl-select-width) + var(--sl-inline-padding) * 2);
|
|
87
|
-
text-overflow: ellipsis;
|
|
88
|
-
color: inherit;
|
|
89
|
-
cursor: pointer;
|
|
90
|
-
appearance: none;
|
|
91
|
-
font-weight: 600;
|
|
92
|
-
text-transform: capitalize;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
select:active {
|
|
96
|
-
font-weight: inherit;
|
|
97
|
-
/* font-family: sans-serif;
|
|
98
|
-
font-weight: 400; */
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
option {
|
|
102
|
-
background-color: var(--sl-color-bg-nav);
|
|
103
|
-
color: var(--sl-color-gray-1);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
@media (min-width: 50rem) {
|
|
107
|
-
select {
|
|
108
|
-
font-size: var(--sl-text-sm);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
@layer starlight.components {
|
|
114
|
-
.label-icon {
|
|
115
|
-
font-size: var(--sl-label-icon-size);
|
|
116
|
-
inset-inline-start: 0;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.caret {
|
|
120
|
-
font-size: var(--sl-caret-size);
|
|
121
|
-
inset-inline-end: 0;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.custom-select-wrapper {
|
|
126
|
-
--sl-inline-padding: 0.5rem;
|
|
127
|
-
position: relative;
|
|
128
|
-
display: inline-block;
|
|
129
|
-
/* These match the padding on the sidebar menu */
|
|
130
|
-
padding-left: var(--sl-inline-padding);
|
|
131
|
-
padding-right: var(--sl-inline-padding);
|
|
132
|
-
|
|
133
|
-
.icon.http path {
|
|
134
|
-
fill: var(--sl-color-text);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
</style>
|
|
138
56
|
<script>
|
|
139
57
|
import { navigate } from 'astro:transitions/client';
|
|
140
58
|
import { updateSelectedLanguage } from '../languages';
|
|
141
|
-
import { initDropdown } from '@stainless-api/docs
|
|
59
|
+
import { initDropdown } from '@stainless-api/docs/components/scripts';
|
|
142
60
|
import { BASE_PATH } from 'virtual:stl-starlight-virtual-module';
|
|
143
61
|
import { getPageLoadEvent } from '../helpers/getPageLoadEvent';
|
|
144
62
|
|
|
145
63
|
document.addEventListener(getPageLoadEvent(), () => {
|
|
64
|
+
const sdkSelect = document.getElementById('sidebar-sdk-select');
|
|
65
|
+
if (!sdkSelect) return;
|
|
146
66
|
initDropdown({
|
|
147
|
-
|
|
67
|
+
root: sdkSelect,
|
|
148
68
|
onSelect: (value) => {
|
|
149
|
-
const originalLanguage =
|
|
69
|
+
const originalLanguage = sdkSelect.dataset.currentValue;
|
|
150
70
|
navigate(updateSelectedLanguage(BASE_PATH, originalLanguage, value));
|
|
151
71
|
},
|
|
152
72
|
});
|
|
@@ -2,12 +2,14 @@ import type {
|
|
|
2
2
|
SnippetCodeProps,
|
|
3
3
|
SnippetContainerProps,
|
|
4
4
|
SnippetRequestContainerProps,
|
|
5
|
-
} from '@stainless-api/docs-ui/
|
|
6
|
-
import { useHighlight, useLanguage } from '@stainless-api/docs-ui/
|
|
7
|
-
import style from '@stainless-api/docs-ui/
|
|
5
|
+
} from '@stainless-api/docs-ui/components';
|
|
6
|
+
import { useHighlight, useLanguage } from '@stainless-api/docs-ui/contexts';
|
|
7
|
+
import style from '@stainless-api/docs-ui/style';
|
|
8
8
|
import * as cheerio from 'cheerio/slim';
|
|
9
9
|
import { EXPERIMENTAL_COLLAPSIBLE_SNIPPETS } from 'virtual:stl-starlight-virtual-module';
|
|
10
10
|
import clsx from 'clsx';
|
|
11
|
+
import { Button } from '@stainless-api/ui-primitives';
|
|
12
|
+
|
|
11
13
|
/*
|
|
12
14
|
* This may be replaced by additional data from the sdk.
|
|
13
15
|
* Without information from the sdk, we use simple heuristics per language.
|
|
@@ -53,7 +55,7 @@ function wrapFirstNSpaces($line: cheerio.Cheerio<any>, n: number) {
|
|
|
53
55
|
const m = inner.match(new RegExp(`^( {1,${n}})`));
|
|
54
56
|
if (!m) return;
|
|
55
57
|
|
|
56
|
-
const lead = m[1]
|
|
58
|
+
const lead = m[1]!;
|
|
57
59
|
$firstSpan.html(`<span class="leading-ws">${lead}</span>${inner.slice(lead.length)}`);
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -130,12 +132,14 @@ export function SnippetRequestContainer({ children, signature }: SnippetRequestC
|
|
|
130
132
|
<div className="stl-snippet-request-container">
|
|
131
133
|
{children}
|
|
132
134
|
{signature && isCollapsible && (
|
|
133
|
-
<
|
|
134
|
-
className={
|
|
135
|
+
<Button
|
|
136
|
+
className={'stl-snippet-expand-button'}
|
|
135
137
|
id="stl-snippet-expand-button"
|
|
138
|
+
size="sm"
|
|
139
|
+
variant="outline"
|
|
136
140
|
>
|
|
137
141
|
Show more
|
|
138
|
-
</
|
|
142
|
+
</Button>
|
|
139
143
|
)}
|
|
140
144
|
</div>
|
|
141
145
|
);
|
|
@@ -1,30 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { Icon } from '@astrojs/starlight/components';
|
|
3
3
|
import { DocsSearch } from './SearchIsland';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import '@stainless-api/docs-ui/src/styles/resets.css';
|
|
7
|
-
import '@stainless-api/docs-ui/src/styles/primitives.css';
|
|
8
|
-
import '@stainless-api/docs-ui/src/styles/main.css';
|
|
9
|
-
import '@stainless-api/docs-ui/src/styles/snippets.css';
|
|
10
|
-
import '@stainless-api/docs-ui/src/styles/search.css';
|
|
11
|
-
import '../../../components/variables.css';
|
|
4
|
+
import { Button } from '@stainless-api/ui-primitives';
|
|
12
5
|
---
|
|
13
6
|
|
|
14
7
|
<site-search>
|
|
15
|
-
<
|
|
16
|
-
|
|
8
|
+
<Button
|
|
9
|
+
popoverTarget="stldocs-search"
|
|
17
10
|
data-open-modal
|
|
18
11
|
aria-label={Astro.locals.t('search.label')}
|
|
19
12
|
aria-keyshortcuts="Control+K"
|
|
20
|
-
|
|
13
|
+
variant="outline"
|
|
21
14
|
>
|
|
22
15
|
<Icon name="magnifier" />
|
|
23
16
|
<span class="sl-hidden md:sl-block" aria-hidden="true">{Astro.locals.t('search.label')}</span>
|
|
24
17
|
<kbd class="sl-hidden md:sl-flex" style="display: none;">
|
|
25
18
|
<kbd>{Astro.locals.t('search.ctrlKey')}</kbd><kbd>K</kbd>
|
|
26
19
|
</kbd>
|
|
27
|
-
</
|
|
20
|
+
</Button>
|
|
28
21
|
|
|
29
22
|
<DocsSearch
|
|
30
23
|
client:only="react"
|
|
@@ -38,27 +31,6 @@ import '../../../components/variables.css';
|
|
|
38
31
|
/>
|
|
39
32
|
</site-search>
|
|
40
33
|
|
|
41
|
-
{
|
|
42
|
-
SEARCH?.enableAISearch === true && (
|
|
43
|
-
<button id="chat-button" popovertarget="stldocs-chat" data-open-modal>
|
|
44
|
-
<Icon name="comment" />
|
|
45
|
-
</button>
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
<style>
|
|
50
|
-
#chat-button {
|
|
51
|
-
background: var(--sl-color-bg-ui);
|
|
52
|
-
border: 1px solid var(--sl-color-hairline);
|
|
53
|
-
height: 2.25rem;
|
|
54
|
-
width: 2.25rem;
|
|
55
|
-
|
|
56
|
-
&:hover {
|
|
57
|
-
border: 1px solid rgb(64, 64, 64);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
</style>
|
|
61
|
-
|
|
62
34
|
<script is:inline>
|
|
63
35
|
function setupShortcut() {
|
|
64
36
|
const openBtn = document.querySelector('button[data-open-modal]');
|