@stainless-api/docs 0.1.0-beta.53 → 0.1.0-beta.55
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 +27 -3
- package/eslint-suppressions.json +6 -1
- package/package.json +8 -7
- package/plugin/assets/languages/csharp.svg +1 -0
- package/plugin/buildAlgoliaIndex.ts +1 -1
- package/plugin/cms/server.ts +34 -4
- package/plugin/cms/worker.ts +80 -2
- package/plugin/components/SnippetCode.tsx +42 -1
- package/plugin/create-playground.shim.tsx +3 -0
- package/plugin/globalJs/code-snippets.ts +15 -8
- package/plugin/globalJs/copy.ts +81 -16
- package/plugin/index.ts +112 -3
- package/plugin/languages.ts +3 -0
- package/plugin/loadPluginConfig.ts +9 -0
- package/plugin/react/Routing.tsx +21 -22
- package/plugin/vendor/preview.worker.docs.js +8222 -7568
- package/scripts/vendor_deps.ts +4 -4
- package/stl-docs/index.ts +1 -1
- package/virtual-module.d.ts +5 -0
- package/tsconfig.tsbuildinfo +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
# @stainless-api/docs
|
|
2
2
|
|
|
3
|
-
## 0.1.0-beta.
|
|
3
|
+
## 0.1.0-beta.55
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- ae56b3c: ensure changeset release commit doesn’t include [skip ci]
|
|
8
|
+
- Updated dependencies [ae56b3c]
|
|
9
|
+
- @stainless-api/docs-ui@0.1.0-beta.46
|
|
10
|
+
- @stainless-api/ui-primitives@0.1.0-beta.35
|
|
11
|
+
|
|
12
|
+
## 0.1.0-beta.54
|
|
4
13
|
|
|
5
14
|
### Minor Changes
|
|
6
15
|
|
|
7
|
-
-
|
|
16
|
+
- a70f60c: Adds the title property
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- 2ebf696: enable trusted publishing
|
|
21
|
+
- Updated dependencies [2ebf696]
|
|
22
|
+
- Updated dependencies [a70f60c]
|
|
23
|
+
- @stainless-api/docs-ui@0.1.0-beta.45
|
|
24
|
+
- @stainless-api/ui-primitives@0.1.0-beta.34
|
|
25
|
+
|
|
26
|
+
## 0.1.0-beta.53
|
|
8
27
|
|
|
9
28
|
### Patch Changes
|
|
10
29
|
|
|
11
|
-
- Updated
|
|
30
|
+
- 2e1639a: Updated preview worker and added experimental playgrounds feature.
|
|
31
|
+
- Updated dependencies [239e28c]
|
|
32
|
+
- Updated dependencies [ddc4593]
|
|
33
|
+
- Updated dependencies [2e1639a]
|
|
34
|
+
- Updated dependencies [2e1639a]
|
|
12
35
|
- @stainless-api/docs-ui@0.1.0-beta.44
|
|
36
|
+
- @stainless-api/ui-primitives@0.1.0-beta.33
|
|
13
37
|
|
|
14
38
|
## 0.1.0-beta.52
|
|
15
39
|
|
package/eslint-suppressions.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"plugin/cms/worker.ts": {
|
|
23
23
|
"@typescript-eslint/no-explicit-any": {
|
|
24
|
-
"count":
|
|
24
|
+
"count": 3
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"plugin/components/SnippetCode.tsx": {
|
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
"count": 1
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
|
+
"plugin/globalJs/copy.ts": {
|
|
33
|
+
"@typescript-eslint/no-explicit-any": {
|
|
34
|
+
"count": 3
|
|
35
|
+
}
|
|
36
|
+
},
|
|
32
37
|
"plugin/index.ts": {
|
|
33
38
|
"@typescript-eslint/no-explicit-any": {
|
|
34
39
|
"count": 1
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stainless-api/docs",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.55",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"./plugin": "./plugin/index.ts",
|
|
12
12
|
"./plugin/middleware": "./plugin/middlewareBuilder/stlStarlightMiddleware.ts",
|
|
13
13
|
"./plugin/MiddlewareTypes": "./plugin/middlewareBuilder/stainlessMiddleware.d.ts",
|
|
14
|
+
"./plugin/languages": "./plugin/languages.ts",
|
|
14
15
|
"./stainless-docs/mintlify-compat": "./stl-docs/components/mintlify-compat/index.ts",
|
|
15
16
|
"./mintlify-compat.css": "./styles/mintlify-compat.css",
|
|
16
17
|
"./font-imports": "./styles/fonts.css",
|
|
@@ -34,7 +35,6 @@
|
|
|
34
35
|
"@astrojs/markdown-remark": "^6.3.9",
|
|
35
36
|
"@astrojs/react": "^4.4.2",
|
|
36
37
|
"@stainless-api/sdk": "0.1.0-alpha.16",
|
|
37
|
-
"astro-expressive-code": "^0.41.3",
|
|
38
38
|
"cheerio": "^1.1.2",
|
|
39
39
|
"clsx": "^2.1.1",
|
|
40
40
|
"dotenv": "17.2.3",
|
|
@@ -49,16 +49,17 @@
|
|
|
49
49
|
"remark-stringify": "^11.0.0",
|
|
50
50
|
"shiki": "^3.19.0",
|
|
51
51
|
"unified": "^11.0.5",
|
|
52
|
+
"vite-plugin-prebundle-workers": "^0.2.0",
|
|
52
53
|
"web-worker": "^1.5.0",
|
|
53
54
|
"yaml": "^2.8.2",
|
|
54
|
-
"@stainless-api/ui
|
|
55
|
-
"@stainless-api/
|
|
55
|
+
"@stainless-api/docs-ui": "0.1.0-beta.46",
|
|
56
|
+
"@stainless-api/ui-primitives": "0.1.0-beta.35"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"@astrojs/check": "^0.9.6",
|
|
59
60
|
"@markdoc/markdoc": "^0.5.4",
|
|
60
61
|
"@types/node": "24.10.1",
|
|
61
|
-
"@types/react": "
|
|
62
|
+
"@types/react": "19.2.7",
|
|
62
63
|
"@types/react-dom": "^19.2.3",
|
|
63
64
|
"react": "^19.2.1",
|
|
64
65
|
"react-dom": "^19.2.1",
|
|
@@ -66,8 +67,8 @@
|
|
|
66
67
|
"typescript": "5.9.3",
|
|
67
68
|
"vite": "^6.4.1",
|
|
68
69
|
"zod": "^4.1.13",
|
|
69
|
-
"@stainless/
|
|
70
|
-
"@stainless/
|
|
70
|
+
"@stainless/eslint-config": "0.1.0-beta.0",
|
|
71
|
+
"@stainless/sdk-json": "^0.1.0-beta.1"
|
|
71
72
|
},
|
|
72
73
|
"scripts": {
|
|
73
74
|
"vendor-deps": "tsx scripts/vendor_deps.ts",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none"><defs><linearGradient id="a-_r_1_" x1="46.77" x2="69.91" y1="86.46" y2="126.73" gradientTransform="matrix(8.78996,0,0,8.78996,-233.98,-518.97)" gradientUnits="userSpaceOnUse"><stop stop-color="#927be5"></stop><stop offset="1" stop-color="#512bd4"></stop></linearGradient><filter id="b-_r_1_" width="42.84" height="39.14" x="44.63" y="91.89" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset></feOffset><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix><feBlend in2="BackgroundImageFix" result="effect1_dropShadow_2037_2800"></feBlend><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset dy="1"></feOffset><feGaussianBlur stdDeviation="2.5"></feGaussianBlur><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix><feBlend in2="effect1_dropShadow_2037_2800" result="effect2_dropShadow_2037_2800"></feBlend><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset dy="4"></feOffset><feGaussianBlur stdDeviation="2"></feGaussianBlur><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.09 0"></feColorMatrix><feBlend in2="effect2_dropShadow_2037_2800" result="effect3_dropShadow_2037_2800"></feBlend><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset dy="9"></feOffset><feGaussianBlur stdDeviation="2.5"></feGaussianBlur><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"></feColorMatrix><feBlend in2="effect3_dropShadow_2037_2800" result="effect4_dropShadow_2037_2800"></feBlend><feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"></feColorMatrix><feOffset dy="15"></feOffset><feGaussianBlur stdDeviation="3"></feGaussianBlur><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.01 0"></feColorMatrix><feBlend in2="effect4_dropShadow_2037_2800" result="effect5_dropShadow_2037_2800"></feBlend><feBlend in="SourceGraphic" in2="effect5_dropShadow_2037_2800" result="shape"></feBlend></filter></defs><path fill="url(#a-_r_1_)" d="M135.73 285.85v173.93a60.2 60.2 0 0 0 30.13 52.17l150.62 86.97a60.2 60.2 0 0 0 60.25 0l150.62-86.97a60.2 60.2 0 0 0 30.13-52.17V285.85a60.2 60.2 0 0 0-30.13-52.18l-150.62-86.95a60.2 60.2 0 0 0-60.25 0l-150.62 86.95a60.3 60.3 0 0 0-30.13 52.18" transform="scale(0.44288615) matrix(0.1,0,0,0.1,-7.57,-10.19)"></path><path fill="#fff" d="M54.06 98.03v6.86a1.7 1.7 0 0 0 1.71 1.7 1.7 1.7 0 0 0 1.71-1.7 1.71 1.71 0 1 1 3.43 0 5.14 5.14 0 1 1-10.28 0v-6.86a5.14 5.14 0 1 1 10.28 0 1.71 1.71 0 1 1-3.43 0 1.71 1.71 0 1 0-3.42 0zm27.41 6.86a1.7 1.7 0 0 1-1.71 1.7h-1.71v1.72c0 .46-.18.9-.5 1.21a1.7 1.7 0 0 1-2.43 0 1.7 1.7 0 0 1-.5-1.2v-1.72h-3.43v1.71a1.7 1.7 0 0 1-1.71 1.72 1.7 1.7 0 0 1-1.72-1.72v-1.71h-1.71a1.71 1.71 0 1 1 0-3.43h1.71v-3.43h-1.71a1.71 1.71 0 1 1 0-3.42h1.71V94.6a1.71 1.71 0 1 1 3.43 0v1.72h3.43V94.6a1.71 1.71 0 1 1 3.43 0v1.72h1.7c.46 0 .9.18 1.22.5a1.7 1.7 0 0 1 0 2.42 1.7 1.7 0 0 1-1.21.5h-1.71v3.43h1.7a1.7 1.7 0 0 1 1.72 1.71m-6.85-5.14h-3.43v3.42h3.43z" filter="url(#b-_r_1_)" style="mix-blend-mode: screen;" transform="scale(0.44288615) matrix(0.879,0,0,0.879,-30.96,-62.09)"></path></svg>
|
|
@@ -67,7 +67,6 @@ export async function buildAlgoliaIndex({
|
|
|
67
67
|
const languages =
|
|
68
68
|
config.docs?.languages ??
|
|
69
69
|
(Object.entries(config.targets)
|
|
70
|
-
// @ts-expect-error we don't have the actual Stainless config type here
|
|
71
70
|
.filter(([name, target]) => Languages.includes(name) && !target.skip)
|
|
72
71
|
.map(([name]) => name) as SDKJSON.SpecLanguage[]);
|
|
73
72
|
|
|
@@ -75,6 +74,7 @@ export async function buildAlgoliaIndex({
|
|
|
75
74
|
oas: transformedOAS,
|
|
76
75
|
config,
|
|
77
76
|
languages,
|
|
77
|
+
version,
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
const {
|
package/plugin/cms/server.ts
CHANGED
|
@@ -35,6 +35,30 @@ function redactApiKey(apiKey: string) {
|
|
|
35
35
|
.join('');
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export type Auth = Array<{
|
|
39
|
+
type: 'http_bearer' | 'query' | 'header' | 'oauth2' | 'http_basic' | 'http_digest';
|
|
40
|
+
description?: string;
|
|
41
|
+
name: string;
|
|
42
|
+
title: string;
|
|
43
|
+
header: string | undefined;
|
|
44
|
+
example: string | undefined;
|
|
45
|
+
opts: {
|
|
46
|
+
type: 'string' | 'number' | 'boolean' | 'null' | 'integer';
|
|
47
|
+
nullable: boolean;
|
|
48
|
+
description?: string | undefined;
|
|
49
|
+
example?: unknown;
|
|
50
|
+
default?: unknown;
|
|
51
|
+
read_env?: string | undefined;
|
|
52
|
+
auth?:
|
|
53
|
+
| {
|
|
54
|
+
security_scheme: string;
|
|
55
|
+
role?: 'value' | 'password' | 'username' | 'client_id' | 'client_secret' | undefined;
|
|
56
|
+
}
|
|
57
|
+
| undefined;
|
|
58
|
+
name: string;
|
|
59
|
+
}[];
|
|
60
|
+
}>;
|
|
61
|
+
|
|
38
62
|
async function loadSpec({
|
|
39
63
|
apiKey,
|
|
40
64
|
devPaths,
|
|
@@ -45,8 +69,8 @@ async function loadSpec({
|
|
|
45
69
|
devPaths: InputFilePaths;
|
|
46
70
|
version: VersionUserConfig;
|
|
47
71
|
logger: AstroIntegrationLogger;
|
|
48
|
-
}) {
|
|
49
|
-
async function unsafeLoad() {
|
|
72
|
+
}): Promise<{ data: SDKJSON.Spec; auth: Auth; id: string }> {
|
|
73
|
+
async function unsafeLoad(): Promise<{ data: SDKJSON.Spec; auth: Auth; id: string }> {
|
|
50
74
|
let oasStr: string;
|
|
51
75
|
let configStr: string;
|
|
52
76
|
let versions: Record<DocsLanguage, string> | undefined;
|
|
@@ -82,7 +106,6 @@ async function loadSpec({
|
|
|
82
106
|
const languages =
|
|
83
107
|
config.docs?.languages ??
|
|
84
108
|
(Object.entries(config.targets)
|
|
85
|
-
// @ts-expect-error we don't have the actual Stainless config type here
|
|
86
109
|
.filter(([name, target]) => Languages.includes(name) && !target.skip)
|
|
87
110
|
.map(([name]) => name) as SDKJSON.SpecLanguage[]);
|
|
88
111
|
|
|
@@ -90,6 +113,7 @@ async function loadSpec({
|
|
|
90
113
|
oas: transformedOAS,
|
|
91
114
|
config,
|
|
92
115
|
languages,
|
|
116
|
+
version,
|
|
93
117
|
});
|
|
94
118
|
|
|
95
119
|
if (versions) {
|
|
@@ -100,9 +124,14 @@ async function loadSpec({
|
|
|
100
124
|
}
|
|
101
125
|
|
|
102
126
|
const id = crypto.randomUUID();
|
|
127
|
+
const opts = Object.entries(config.client_settings.opts).map(([k, v]) => ({ name: k, ...v }));
|
|
103
128
|
|
|
104
129
|
return {
|
|
105
130
|
data: sdkJson,
|
|
131
|
+
auth: sdkJson.security_schemes.map((scheme) => ({
|
|
132
|
+
...scheme,
|
|
133
|
+
opts: opts.filter((opt) => opt.auth?.security_scheme === scheme.name),
|
|
134
|
+
})),
|
|
106
135
|
id,
|
|
107
136
|
};
|
|
108
137
|
}
|
|
@@ -127,7 +156,7 @@ async function loadSpec({
|
|
|
127
156
|
}
|
|
128
157
|
|
|
129
158
|
class Spec {
|
|
130
|
-
private specPromise: Promise<{ id: string; data: SDKJSON.Spec }>;
|
|
159
|
+
private specPromise: Promise<{ id: string; data: SDKJSON.Spec; auth: Auth }>;
|
|
131
160
|
private devPaths: InputFilePaths;
|
|
132
161
|
private apiKey: string;
|
|
133
162
|
private version: VersionUserConfig;
|
|
@@ -153,6 +182,7 @@ class Spec {
|
|
|
153
182
|
return {
|
|
154
183
|
id: spec.id,
|
|
155
184
|
data: null,
|
|
185
|
+
auth: null,
|
|
156
186
|
};
|
|
157
187
|
}
|
|
158
188
|
|
package/plugin/cms/worker.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
import { dirname, resolve } from 'node:path';
|
|
6
6
|
import fs from 'fs/promises';
|
|
7
7
|
import pathutils from 'path';
|
|
8
|
+
import type { VersionUserConfig } from '../loadPluginConfig';
|
|
8
9
|
|
|
9
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
11
|
const __dirname = dirname(__filename);
|
|
@@ -12,7 +13,81 @@ const __dirname = dirname(__filename);
|
|
|
12
13
|
const workerPath = resolve(__dirname, '..', 'vendor', 'preview.worker.docs.js');
|
|
13
14
|
|
|
14
15
|
type OpenAPIDocument = Record<string, any>;
|
|
15
|
-
type ParsedConfig =
|
|
16
|
+
export type ParsedConfig = {
|
|
17
|
+
docs:
|
|
18
|
+
| {
|
|
19
|
+
title?: string | undefined;
|
|
20
|
+
favicon?: string | undefined;
|
|
21
|
+
logo_icon?: string | undefined;
|
|
22
|
+
search?:
|
|
23
|
+
| {
|
|
24
|
+
algolia?:
|
|
25
|
+
| {
|
|
26
|
+
app_id: string;
|
|
27
|
+
index_name: string;
|
|
28
|
+
search_key: string;
|
|
29
|
+
}
|
|
30
|
+
| undefined;
|
|
31
|
+
}
|
|
32
|
+
| undefined;
|
|
33
|
+
description?: string | undefined;
|
|
34
|
+
languages?:
|
|
35
|
+
| ('node' | 'typescript' | 'python' | 'java' | 'kotlin' | 'go' | 'ruby' | 'terraform' | 'http')[]
|
|
36
|
+
| undefined;
|
|
37
|
+
snippets?:
|
|
38
|
+
| {
|
|
39
|
+
exclude_languages?: string[] | undefined;
|
|
40
|
+
}
|
|
41
|
+
| undefined;
|
|
42
|
+
show_security?: boolean | undefined;
|
|
43
|
+
show_readme?: boolean | undefined;
|
|
44
|
+
base_path?: string | undefined;
|
|
45
|
+
navigation?:
|
|
46
|
+
| {
|
|
47
|
+
menubar?:
|
|
48
|
+
| {
|
|
49
|
+
title: string;
|
|
50
|
+
icon?: string;
|
|
51
|
+
variant?: string;
|
|
52
|
+
href?: string | undefined;
|
|
53
|
+
page?: string | undefined;
|
|
54
|
+
}[]
|
|
55
|
+
| undefined;
|
|
56
|
+
sidebar?:
|
|
57
|
+
| {
|
|
58
|
+
title: string;
|
|
59
|
+
icon?: string;
|
|
60
|
+
variant?: string;
|
|
61
|
+
href?: string | undefined;
|
|
62
|
+
page?: string | undefined;
|
|
63
|
+
}[]
|
|
64
|
+
| undefined;
|
|
65
|
+
}
|
|
66
|
+
| undefined;
|
|
67
|
+
pages?: unknown;
|
|
68
|
+
resources?: unknown[] | undefined;
|
|
69
|
+
}
|
|
70
|
+
| undefined;
|
|
71
|
+
targets: Record<string, { skip?: boolean }>;
|
|
72
|
+
client_settings: {
|
|
73
|
+
opts: {
|
|
74
|
+
[x: string]: {
|
|
75
|
+
type: 'string' | 'number' | 'boolean' | 'null' | 'integer';
|
|
76
|
+
nullable: boolean;
|
|
77
|
+
description?: string | undefined;
|
|
78
|
+
example?: unknown;
|
|
79
|
+
default?: unknown;
|
|
80
|
+
read_env?: string | undefined;
|
|
81
|
+
auth?:
|
|
82
|
+
| {
|
|
83
|
+
security_scheme: string;
|
|
84
|
+
role?: 'value' | 'password' | 'username' | 'client_id' | 'client_secret' | undefined;
|
|
85
|
+
}
|
|
86
|
+
| undefined;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
};
|
|
16
91
|
|
|
17
92
|
function runJob({ type, signal, data }: { type: string; signal?: AbortSignal; data: any }) {
|
|
18
93
|
const stainlessWorker = new Worker(workerPath, {
|
|
@@ -22,6 +97,7 @@ function runJob({ type, signal, data }: { type: string; signal?: AbortSignal; da
|
|
|
22
97
|
|
|
23
98
|
return new Promise<any>((resolve, reject) => {
|
|
24
99
|
stainlessWorker.addEventListener('error', (e) => {
|
|
100
|
+
e.preventDefault();
|
|
25
101
|
reject(e);
|
|
26
102
|
});
|
|
27
103
|
|
|
@@ -85,10 +161,12 @@ export async function createSDKJSON({
|
|
|
85
161
|
oas,
|
|
86
162
|
config,
|
|
87
163
|
languages,
|
|
164
|
+
version,
|
|
88
165
|
}: {
|
|
89
166
|
oas: OpenAPIDocument;
|
|
90
167
|
config: ParsedConfig;
|
|
91
168
|
languages: DocsLanguage[];
|
|
169
|
+
version: VersionUserConfig;
|
|
92
170
|
}) {
|
|
93
171
|
const templatePath = resolve(__dirname, '../vendor/templates');
|
|
94
172
|
const readmeLoader = await Promise.all(
|
|
@@ -113,7 +191,7 @@ export async function createSDKJSON({
|
|
|
113
191
|
config,
|
|
114
192
|
languages,
|
|
115
193
|
transform: false,
|
|
116
|
-
projectName:
|
|
194
|
+
projectName: version.stainlessProject,
|
|
117
195
|
readmeTemplates,
|
|
118
196
|
},
|
|
119
197
|
});
|
|
@@ -6,9 +6,33 @@ import type {
|
|
|
6
6
|
import { useHighlight, useLanguage } from '@stainless-api/docs-ui/contexts';
|
|
7
7
|
import style from '@stainless-api/docs-ui/style';
|
|
8
8
|
import * as cheerio from 'cheerio/slim';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
EXPERIMENTAL_COLLAPSIBLE_SNIPPETS,
|
|
11
|
+
EXPERIMENTAL_PLAYGROUNDS,
|
|
12
|
+
} from 'virtual:stl-starlight-virtual-module';
|
|
10
13
|
import clsx from 'clsx';
|
|
11
14
|
import { Button } from '@stainless-api/ui-primitives';
|
|
15
|
+
import { CopyIcon } from 'lucide-react';
|
|
16
|
+
|
|
17
|
+
function PlaygroundIcon() {
|
|
18
|
+
return (
|
|
19
|
+
<svg
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
width={16}
|
|
22
|
+
height={16}
|
|
23
|
+
viewBox="0 0 24 24"
|
|
24
|
+
fill="none"
|
|
25
|
+
stroke="currentColor"
|
|
26
|
+
strokeWidth={2}
|
|
27
|
+
strokeLinecap="round"
|
|
28
|
+
strokeLinejoin="round"
|
|
29
|
+
className={'lucide ' + style.Icon}
|
|
30
|
+
aria-hidden="true"
|
|
31
|
+
>
|
|
32
|
+
<path d="m 1,2 h 1 a 4,4 0 0 1 4,4 v 1 m 5,15 H 10 A 4,4 0 0 1 6,18 V 6 a 4,4 0 0 1 4,-4 h 1 M 1,22 H 2 A 4,4 0 0 0 6,18 V 17 M 14.029059,8.147837 A 1.2853426,1.2853426 0 0 1 15.978924,7.0437277 L 22.40178,10.8959 a 1.2853426,1.2853426 0 0 1 0,2.208219 l -6.422856,3.852172 a 1.2853426,1.2853426 0 0 1 -1.949865,-1.105395 z" />
|
|
33
|
+
</svg>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
12
36
|
|
|
13
37
|
/*
|
|
14
38
|
* This may be replaced by additional data from the sdk.
|
|
@@ -185,6 +209,23 @@ export function CondensibleSnippetCode({
|
|
|
185
209
|
);
|
|
186
210
|
}
|
|
187
211
|
|
|
212
|
+
export function SnippetButtons({ content }: { content: string }) {
|
|
213
|
+
void content;
|
|
214
|
+
const language = useLanguage();
|
|
215
|
+
return (
|
|
216
|
+
<>
|
|
217
|
+
<Button variant="outline" data-stldocs-snippet-copy>
|
|
218
|
+
<CopyIcon size={16} className={style.Icon} />
|
|
219
|
+
</Button>
|
|
220
|
+
{EXPERIMENTAL_PLAYGROUNDS &&
|
|
221
|
+
(language === 'python' || language === 'typescript' || language === 'http') && (
|
|
222
|
+
<Button data-stldocs-snippet-play variant="muted" border title="Play">
|
|
223
|
+
<PlaygroundIcon />
|
|
224
|
+
</Button>
|
|
225
|
+
)}
|
|
226
|
+
</>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
188
229
|
export function SnippetCode({ content, signature, language: forcedLanguage }: SnippetCodeProps) {
|
|
189
230
|
const lang = useLanguage();
|
|
190
231
|
const language = forcedLanguage || lang;
|
|
@@ -43,24 +43,31 @@ document.addEventListener(getPageLoadEvent(), () => {
|
|
|
43
43
|
// This is a bit funky, but it animates pretty smooth.
|
|
44
44
|
// 1. Toggle to new state so we can measure the target height
|
|
45
45
|
// 2. Reset to starting height to trigger transition
|
|
46
|
-
|
|
46
|
+
el.style.height = '';
|
|
47
|
+
el.style.overflowY = '';
|
|
48
|
+
const startHeight = el.getBoundingClientRect().height;
|
|
47
49
|
el.classList.toggle('stl-snippet-code-is-expanded', expand);
|
|
48
50
|
el.classList.toggle('stl-snippet-code-is-collapsed', !expand);
|
|
49
51
|
|
|
50
|
-
const endHeight = el.
|
|
51
|
-
|
|
52
|
-
el.style.height = `${startHeight}px`;
|
|
53
|
-
|
|
54
|
-
requestAnimationFrame(() => {
|
|
55
|
-
el.style.height = `${endHeight}px`;
|
|
56
|
-
});
|
|
52
|
+
const endHeight = el.getBoundingClientRect().height;
|
|
57
53
|
|
|
58
54
|
const onEnd = (e: TransitionEvent) => {
|
|
59
55
|
if (e.propertyName !== 'height') return;
|
|
60
56
|
el.style.height = '';
|
|
57
|
+
el.style.overflowY = '';
|
|
61
58
|
el.removeEventListener('transitionend', onEnd);
|
|
62
59
|
};
|
|
63
60
|
el.addEventListener('transitionend', onEnd);
|
|
61
|
+
|
|
62
|
+
// Set initial height
|
|
63
|
+
el.style.height = `${startHeight}px`;
|
|
64
|
+
el.style.overflowY = 'hidden';
|
|
65
|
+
|
|
66
|
+
// Force layout recalculation
|
|
67
|
+
el.getBoundingClientRect();
|
|
68
|
+
|
|
69
|
+
// Start transition to end state
|
|
70
|
+
el.style.height = `${endHeight}px`;
|
|
64
71
|
};
|
|
65
72
|
|
|
66
73
|
if (collapsedDiv) {
|
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
|
});
|