@stainless-api/docs 1.0.0-beta.142 → 1.0.0-beta.143
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 +7 -0
- package/package.json +1 -1
- package/plugin/index.ts +1 -1
- package/plugin/loadPluginConfig.ts +2 -2
- package/plugin/react/Routing.tsx +0 -1
- package/plugin/specs/defaultSDKJSONLoader.ts +27 -18
- package/plugin/specs/fileSystemSDKJSONLoader.ts +126 -0
- package/plugin/specs/utils.ts +15 -1
- package/plugin/specs/makeFileSystemSDKJSONFilesLoader.ts +0 -63
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
package/plugin/index.ts
CHANGED
|
@@ -39,7 +39,7 @@ import { buildAlgoliaIndex } from './buildAlgoliaIndex';
|
|
|
39
39
|
import { flatSpecsList, loadAllSpecs, LoadedSpecs } from './specs/utils';
|
|
40
40
|
|
|
41
41
|
export { generateAPILink } from './generateAPIReferenceLink';
|
|
42
|
-
export {
|
|
42
|
+
export { fileSystemSDKJSONLoader } from './specs/fileSystemSDKJSONLoader';
|
|
43
43
|
export type { ReferenceSidebarConfigItem };
|
|
44
44
|
|
|
45
45
|
config({
|
|
@@ -6,7 +6,7 @@ import type { CreateShikiHighlighterOptions } from '@astrojs/markdown-remark';
|
|
|
6
6
|
import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
7
7
|
import type { PropertySettingsType } from '@stainless-api/docs-ui/contexts';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { defaultSDKJSONLoader } from './specs/defaultSDKJSONLoader';
|
|
10
10
|
import { SDKJSONFilesLoaderFn as SDKJSONFilesLoaderFn } from './specs/utils';
|
|
11
11
|
|
|
12
12
|
type ApiKeySource = 'explicit-config' | 'environment-variable' | 'cli';
|
|
@@ -286,7 +286,7 @@ function normalizeConfig(partial: SomeStainlessStarlightUserConfig, astroOptions
|
|
|
286
286
|
detailThreshold: partial.llmsTxt?.detailThreshold ?? 2000,
|
|
287
287
|
},
|
|
288
288
|
apiKey: loadApiKey(partial.apiKey),
|
|
289
|
-
loadSDKJSONFiles: partial.loadSDKJSONFiles ??
|
|
289
|
+
loadSDKJSONFiles: partial.loadSDKJSONFiles ?? defaultSDKJSONLoader,
|
|
290
290
|
branch: partial.versions?.[0]?.branch ?? 'main',
|
|
291
291
|
};
|
|
292
292
|
|
package/plugin/react/Routing.tsx
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import type { SDKJSONFilesLoaderFn, SDKJSONFilesLoaderParams } from './utils';
|
|
3
|
+
import { sdkJSONCacheReaderWriter } from './utils';
|
|
3
4
|
import Stainless, { APIError } from '@stainless-api/sdk';
|
|
4
|
-
import { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
5
|
+
import { DocsLanguage, isSupportedLanguage } from '@stainless-api/docs-ui/routing';
|
|
5
6
|
import { bold } from '../../shared/terminalUtils';
|
|
6
|
-
import { mkdir, readdir, readFile, rm
|
|
7
|
+
import { mkdir, readdir, readFile, rm } from 'fs/promises';
|
|
7
8
|
import { generateSpecFromStrings, previewWorkerCode } from '@stainless/sdk-json/spec';
|
|
8
|
-
import { Spec
|
|
9
|
+
import { Spec } from '@stainless/sdk-json';
|
|
9
10
|
import crypto from 'crypto';
|
|
10
11
|
|
|
11
12
|
function resolvePath(inputPath: string) {
|
|
@@ -115,13 +116,11 @@ async function loadInputs({ apiKey, logger, stainlessProject, branch }: SDKJSONF
|
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return JSON.parse(fileContents) as T;
|
|
122
|
-
} catch {
|
|
123
|
-
return null;
|
|
119
|
+
function getLanguagesFromSDKJSON(spec: Spec) {
|
|
120
|
+
if (spec.docs?.languages) {
|
|
121
|
+
return spec.docs.languages;
|
|
124
122
|
}
|
|
123
|
+
return Object.keys(spec.decls).filter(isSupportedLanguage);
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
async function cleanupDirectory(directory: string, filesToKeep: string[]) {
|
|
@@ -133,12 +132,12 @@ async function cleanupDirectory(directory: string, filesToKeep: string[]) {
|
|
|
133
132
|
};
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
export const
|
|
135
|
+
export const defaultSDKJSONLoader: SDKJSONFilesLoaderFn = async (params) => {
|
|
137
136
|
const { createCodegenDir } = params;
|
|
138
137
|
|
|
139
138
|
const inputs = await loadInputs(params);
|
|
140
139
|
|
|
141
|
-
const specsDirectory = path.join(createCodegenDir().pathname, '
|
|
140
|
+
const specsDirectory = path.join(createCodegenDir().pathname, 'sdk_json_cache');
|
|
142
141
|
await mkdir(specsDirectory, { recursive: true });
|
|
143
142
|
|
|
144
143
|
const fileName =
|
|
@@ -150,20 +149,28 @@ export const defaultSpecLoader: SDKJSONFilesLoaderFn = async (params) => {
|
|
|
150
149
|
|
|
151
150
|
const filePath = path.join(specsDirectory, fileName);
|
|
152
151
|
|
|
153
|
-
const cachedSpec = await
|
|
152
|
+
const cachedSpec = await (async () => {
|
|
153
|
+
try {
|
|
154
|
+
return await sdkJSONCacheReaderWriter.readFile(filePath);
|
|
155
|
+
} catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
})();
|
|
159
|
+
|
|
154
160
|
// skip generation since we already have a cached spec
|
|
155
161
|
if (cachedSpec) {
|
|
162
|
+
const languages = getLanguagesFromSDKJSON(cachedSpec);
|
|
156
163
|
params.logger.info(`Loaded cached spec: ${fileName}`);
|
|
157
164
|
return [
|
|
158
165
|
{
|
|
159
166
|
filePath,
|
|
160
|
-
languages
|
|
161
|
-
sdkJson: cachedSpec
|
|
167
|
+
languages,
|
|
168
|
+
sdkJson: cachedSpec,
|
|
162
169
|
},
|
|
163
170
|
];
|
|
164
171
|
}
|
|
165
172
|
|
|
166
|
-
const { sdkJson
|
|
173
|
+
const { sdkJson } = await generateSpecFromStrings({
|
|
167
174
|
oasStr: inputs.oasStr,
|
|
168
175
|
configStr: inputs.configStr,
|
|
169
176
|
languageOverrides: {
|
|
@@ -174,9 +181,11 @@ export const defaultSpecLoader: SDKJSONFilesLoaderFn = async (params) => {
|
|
|
174
181
|
stainlessProject: params.stainlessProject,
|
|
175
182
|
});
|
|
176
183
|
|
|
177
|
-
|
|
178
|
-
params.logger.info(`Generated: ${fileName}`);
|
|
184
|
+
const languages = getLanguagesFromSDKJSON(sdkJson);
|
|
179
185
|
|
|
186
|
+
await sdkJSONCacheReaderWriter.writeFile(filePath, sdkJson);
|
|
187
|
+
|
|
188
|
+
params.logger.info(`Generated: ${fileName}`);
|
|
180
189
|
const { deletedCount } = await cleanupDirectory(specsDirectory, [fileName]);
|
|
181
190
|
if (deletedCount > 0) {
|
|
182
191
|
params.logger.info(`Cleaned up ${deletedCount} unused spec file(s)`);
|
|
@@ -185,7 +194,7 @@ export const defaultSpecLoader: SDKJSONFilesLoaderFn = async (params) => {
|
|
|
185
194
|
return [
|
|
186
195
|
{
|
|
187
196
|
filePath,
|
|
188
|
-
languages
|
|
197
|
+
languages,
|
|
189
198
|
sdkJson,
|
|
190
199
|
},
|
|
191
200
|
];
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Spec, SpecLanguage } from '@stainless/sdk-json';
|
|
2
|
+
import { SDKJSONFilesLoaderFn, SDKJSONFilesLoaderParams, sdkJSONCacheReaderWriter } from './utils';
|
|
3
|
+
import { mkdir, readFile } from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { generateSpecFromStrings } from '@stainless/sdk-json/spec';
|
|
6
|
+
|
|
7
|
+
interface GenerateSDKJSONOptions {
|
|
8
|
+
/** Raw OpenAPI spec contents (JSON or YAML). */
|
|
9
|
+
spec: string;
|
|
10
|
+
/** Raw Stainless config contents (YAML). */
|
|
11
|
+
config: string;
|
|
12
|
+
/** Language to build the SDK JSON spec for. */
|
|
13
|
+
language: SpecLanguage;
|
|
14
|
+
/** The name of the project. */
|
|
15
|
+
stainlessProject: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type GenerateSDKJSONFn<T> = (options: GenerateSDKJSONOptions) => Promise<{ spec: T }>;
|
|
19
|
+
|
|
20
|
+
type NonHttpSpecLanguage = Exclude<SpecLanguage, 'http'>;
|
|
21
|
+
|
|
22
|
+
type LibraryInformationOverride = Partial<{
|
|
23
|
+
[key in NonHttpSpecLanguage]: {
|
|
24
|
+
repo_url?: string;
|
|
25
|
+
code_url?: string;
|
|
26
|
+
version?: string;
|
|
27
|
+
install?: string;
|
|
28
|
+
};
|
|
29
|
+
}>;
|
|
30
|
+
|
|
31
|
+
type FileSystemSpecLoaderParams<T> = {
|
|
32
|
+
/**
|
|
33
|
+
* The path to the OpenAPI spec file.
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
specPath: string;
|
|
37
|
+
/**
|
|
38
|
+
* The path to your Stainless config file.
|
|
39
|
+
*/
|
|
40
|
+
configFilePath: string;
|
|
41
|
+
/**
|
|
42
|
+
* The function used to generate your SDKJSON.
|
|
43
|
+
*/
|
|
44
|
+
generateSDKJSON?: GenerateSDKJSONFn<T>;
|
|
45
|
+
/**
|
|
46
|
+
* The languages for which you want to render documentation.
|
|
47
|
+
*/
|
|
48
|
+
languages: SpecLanguage[];
|
|
49
|
+
/**
|
|
50
|
+
* A key:value map of languages to overrides. Used to manually set things like the install command or SDK version.
|
|
51
|
+
*/
|
|
52
|
+
override?: LibraryInformationOverride;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const defaultGenerateSDKJSON: GenerateSDKJSONFn<Spec> = async ({
|
|
56
|
+
config,
|
|
57
|
+
spec,
|
|
58
|
+
language,
|
|
59
|
+
stainlessProject,
|
|
60
|
+
}) => {
|
|
61
|
+
const { sdkJson } = await generateSpecFromStrings({
|
|
62
|
+
oasStr: spec,
|
|
63
|
+
configStr: config,
|
|
64
|
+
languageOverrides: {
|
|
65
|
+
mode: 'only',
|
|
66
|
+
list: [language],
|
|
67
|
+
},
|
|
68
|
+
versionInfo: null,
|
|
69
|
+
stainlessProject,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return { spec: sdkJson };
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export function fileSystemSDKJSONLoader<T>({
|
|
76
|
+
specPath,
|
|
77
|
+
configFilePath,
|
|
78
|
+
generateSDKJSON,
|
|
79
|
+
languages,
|
|
80
|
+
override,
|
|
81
|
+
}: FileSystemSpecLoaderParams<T>): SDKJSONFilesLoaderFn {
|
|
82
|
+
const generateFn = generateSDKJSON ?? defaultGenerateSDKJSON;
|
|
83
|
+
return async function fileSystemSpecLoader(opts: SDKJSONFilesLoaderParams) {
|
|
84
|
+
const { createCodegenDir, logger } = opts;
|
|
85
|
+
const [spec, config] = await Promise.all([readFile(specPath, 'utf8'), readFile(configFilePath, 'utf8')]);
|
|
86
|
+
|
|
87
|
+
const specsDirectory = path.join(createCodegenDir().pathname, 'fs_spec_loader_specs');
|
|
88
|
+
await mkdir(specsDirectory, { recursive: true });
|
|
89
|
+
|
|
90
|
+
const r = languages.map(async (language) => {
|
|
91
|
+
const generateResult = await generateFn({
|
|
92
|
+
spec,
|
|
93
|
+
config,
|
|
94
|
+
language,
|
|
95
|
+
stainlessProject: opts.stainlessProject,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// type casting here is a little weird
|
|
99
|
+
// it prevents type errors from slightly incompatible SDKJSON types (since generateSDKJSON comes from the user)
|
|
100
|
+
const sdkJson = generateResult.spec as unknown as Spec;
|
|
101
|
+
|
|
102
|
+
if (override && language !== 'http' && override[language]) {
|
|
103
|
+
sdkJson.metadata[language] = {
|
|
104
|
+
...sdkJson.metadata[language],
|
|
105
|
+
...override[language],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const filePath = path.join(specsDirectory, `${language}.json`);
|
|
110
|
+
|
|
111
|
+
await sdkJSONCacheReaderWriter.writeFile(filePath, sdkJson);
|
|
112
|
+
|
|
113
|
+
logger.info(`Loaded SDKJSON for ${language} to ${filePath}`);
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
filePath: filePath,
|
|
117
|
+
languages: [language],
|
|
118
|
+
sdkJson,
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const results = await Promise.all(r);
|
|
123
|
+
|
|
124
|
+
return results;
|
|
125
|
+
};
|
|
126
|
+
}
|
package/plugin/specs/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Spec } from '@stainless/sdk-json';
|
|
2
|
-
import { readFile } from 'fs/promises';
|
|
2
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
3
3
|
import { DocsLanguage } from '@stainless-api/docs-ui/routing';
|
|
4
4
|
import { AstroIntegrationLogger } from 'astro';
|
|
5
5
|
|
|
@@ -84,3 +84,17 @@ export function flatSpecsList(specs: LoadedSpecs) {
|
|
|
84
84
|
)
|
|
85
85
|
.flat();
|
|
86
86
|
}
|
|
87
|
+
|
|
88
|
+
function typedReaderWriter<T>() {
|
|
89
|
+
return {
|
|
90
|
+
async readFile(filePath: string) {
|
|
91
|
+
const fileContents = await readFile(filePath, 'utf8');
|
|
92
|
+
return JSON.parse(fileContents) as T;
|
|
93
|
+
},
|
|
94
|
+
async writeFile(filePath: string, data: T) {
|
|
95
|
+
await writeFile(filePath, JSON.stringify(data), 'utf8');
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const sdkJSONCacheReaderWriter = typedReaderWriter<Spec>();
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { Spec, SpecLanguage } from '@stainless/sdk-json';
|
|
2
|
-
import { SDKJSONFilesLoaderFn, SDKJSONFilesLoaderParams } from './utils';
|
|
3
|
-
import { mkdir, readFile, writeFile } from 'fs/promises';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
|
|
6
|
-
interface GenerateSDKJSONOptions {
|
|
7
|
-
/** Raw OpenAPI spec contents (JSON or YAML). */
|
|
8
|
-
spec: string;
|
|
9
|
-
/** Raw Stainless config contents (YAML). */
|
|
10
|
-
config: string;
|
|
11
|
-
/** Language to build the SDK JSON spec for. */
|
|
12
|
-
language: SpecLanguage;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type GenerateSDKJSONFn<T> = (options: GenerateSDKJSONOptions) => Promise<T>;
|
|
16
|
-
|
|
17
|
-
type FileSystemSpecLoaderParams<T> = {
|
|
18
|
-
specPath: string;
|
|
19
|
-
configFilePath: string;
|
|
20
|
-
generateSDKJSON: GenerateSDKJSONFn<T>;
|
|
21
|
-
languages: SpecLanguage[];
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export function makeFileSystemSDKJSONFilesLoader<T>({
|
|
25
|
-
specPath,
|
|
26
|
-
configFilePath,
|
|
27
|
-
generateSDKJSON,
|
|
28
|
-
languages,
|
|
29
|
-
}: FileSystemSpecLoaderParams<T>): SDKJSONFilesLoaderFn {
|
|
30
|
-
return async function fileSystemSpecLoader(opts: SDKJSONFilesLoaderParams) {
|
|
31
|
-
const { createCodegenDir, logger } = opts;
|
|
32
|
-
const [spec, config] = await Promise.all([readFile(specPath, 'utf8'), readFile(configFilePath, 'utf8')]);
|
|
33
|
-
|
|
34
|
-
const specsDirectory = path.join(createCodegenDir().pathname, 'fsSpecLoaderSpecs');
|
|
35
|
-
await mkdir(specsDirectory, { recursive: true });
|
|
36
|
-
|
|
37
|
-
const r = languages.map(async (language) => {
|
|
38
|
-
// type casting here is a little weird
|
|
39
|
-
// it prevents type errors from slightly incompatible SDKJSON types (since generateSDKJSON comes from the user)
|
|
40
|
-
const sdkJson = (await generateSDKJSON({
|
|
41
|
-
spec,
|
|
42
|
-
config,
|
|
43
|
-
language,
|
|
44
|
-
})) as unknown as Spec;
|
|
45
|
-
|
|
46
|
-
const filePath = path.join(specsDirectory, `${language}.json`);
|
|
47
|
-
|
|
48
|
-
await writeFile(filePath, JSON.stringify(sdkJson));
|
|
49
|
-
|
|
50
|
-
logger.info(`Loaded SDKJSON for ${language} to ${filePath}`);
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
filePath: filePath,
|
|
54
|
-
languages: [language],
|
|
55
|
-
sdkJson,
|
|
56
|
-
};
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
const results = await Promise.all(r);
|
|
60
|
-
|
|
61
|
-
return results;
|
|
62
|
-
};
|
|
63
|
-
}
|