@xyd-js/plugin-docs 0.0.0-build-1760f84-20251129221538 → 0.0.0-build-11974d8-20251130234931
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/dist/index.js +96 -77
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
- package/src/presets/docs/settings.ts +271 -264
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xyd-js/plugin-docs",
|
|
3
|
-
"version": "0.0.0-build-
|
|
3
|
+
"version": "0.0.0-build-11974d8-20251130234931",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"codehike": "^1.0.3",
|
|
19
19
|
"@code-hike/lighter": "^1.0.3",
|
|
20
20
|
"dotenv": "^16.4.7",
|
|
21
|
-
"@xyd-js/openapi": "0.0.0-build-
|
|
22
|
-
"@xyd-js/gql": "0.0.0-build-
|
|
23
|
-
"@xyd-js/uniform": "0.0.0-build-
|
|
24
|
-
"@xyd-js/sources": "0.0.0-build-
|
|
21
|
+
"@xyd-js/openapi": "0.0.0-build-11974d8-20251130234931",
|
|
22
|
+
"@xyd-js/gql": "0.0.0-build-11974d8-20251130234931",
|
|
23
|
+
"@xyd-js/uniform": "0.0.0-build-11974d8-20251130234931",
|
|
24
|
+
"@xyd-js/sources": "0.0.0-build-11974d8-20251130234931",
|
|
25
25
|
"@xyd-js/cli-sdk": "0.1.0-build.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"react": "^19.1.0",
|
|
33
33
|
"react-dom": "^19.1.0",
|
|
34
34
|
"react-router": "^7.7.1",
|
|
35
|
-
"@xyd-js/framework": "0.0.0-build-
|
|
36
|
-
"@xyd-js/composer": "0.0.0-build-
|
|
37
|
-
"@xyd-js/themes": "0.0.0-build-
|
|
38
|
-
"@xyd-js/components": "0.0.0-build-
|
|
39
|
-
"@xyd-js/content": "0.0.0-build-
|
|
40
|
-
"@xyd-js/core": "0.0.0-build-
|
|
35
|
+
"@xyd-js/framework": "0.0.0-build-11974d8-20251130234931",
|
|
36
|
+
"@xyd-js/composer": "0.0.0-build-11974d8-20251130234931",
|
|
37
|
+
"@xyd-js/themes": "0.0.0-build-11974d8-20251130234931",
|
|
38
|
+
"@xyd-js/components": "0.0.0-build-11974d8-20251130234931",
|
|
39
|
+
"@xyd-js/content": "0.0.0-build-11974d8-20251130234931",
|
|
40
|
+
"@xyd-js/core": "0.0.0-build-11974d8-20251130234931"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/react-dom": "^19.1.0",
|
|
@@ -35,127 +35,127 @@ const extensions = ["tsx", "ts", "json"];
|
|
|
35
35
|
* @throws May throw errors if file reading or parsing fails
|
|
36
36
|
*/
|
|
37
37
|
export async function readSettings() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// Load environment variables from .env files first
|
|
41
|
-
await loadEnvFiles(dirPath);
|
|
42
|
-
|
|
43
|
-
const baseFileName = "docs";
|
|
44
|
-
let settingsFilePath = "";
|
|
45
|
-
let reactSettings = false;
|
|
46
|
-
|
|
47
|
-
let error: string | null = null;
|
|
48
|
-
try {
|
|
49
|
-
const files = await fs.readdir(dirPath);
|
|
50
|
-
const settingsFile = files.find((file) => {
|
|
51
|
-
const ext = path.extname(file).slice(1);
|
|
52
|
-
return file.startsWith(baseFileName) && extensions.includes(ext);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
if (settingsFile) {
|
|
56
|
-
settingsFilePath = path.join(dirPath, settingsFile);
|
|
57
|
-
reactSettings = path.extname(settingsFile) !== ".json";
|
|
58
|
-
} else {
|
|
59
|
-
error =
|
|
60
|
-
"No settings file found.\nFile must be named 'docs' with one of the following extensions: ${extensions.join(', ')}";
|
|
61
|
-
}
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.error(error);
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
38
|
+
const dirPath = process.cwd();
|
|
66
39
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (!error) {
|
|
70
|
-
if (reactSettings) {
|
|
71
|
-
const settingsPreview = await createServer({
|
|
72
|
-
optimizeDeps: {
|
|
73
|
-
include: ["react/jsx-runtime"],
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
const config = await settingsPreview.ssrLoadModule(settingsFilePath);
|
|
77
|
-
const mod = config.default as Settings;
|
|
40
|
+
// Load environment variables from .env files first
|
|
41
|
+
await loadEnvFiles(dirPath);
|
|
78
42
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
let json = JSON.parse(rawJsonSettings) as Settings;
|
|
43
|
+
const baseFileName = "docs";
|
|
44
|
+
let settingsFilePath = "";
|
|
45
|
+
let reactSettings = false;
|
|
84
46
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
47
|
+
let error: string | null = null;
|
|
48
|
+
try {
|
|
49
|
+
const files = await fs.readdir(dirPath);
|
|
50
|
+
const settingsFile = files.find((file) => {
|
|
51
|
+
const ext = path.extname(file).slice(1);
|
|
52
|
+
return file.startsWith(baseFileName) && extensions.includes(ext);
|
|
53
|
+
});
|
|
88
54
|
|
|
55
|
+
if (settingsFile) {
|
|
56
|
+
settingsFilePath = path.join(dirPath, settingsFile);
|
|
57
|
+
reactSettings = path.extname(settingsFile) !== ".json";
|
|
58
|
+
} else {
|
|
59
|
+
error =
|
|
60
|
+
"No settings file found.\nFile must be named 'docs' with one of the following extensions: ${extensions.join(', ')}";
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(error);
|
|
89
64
|
return null;
|
|
90
|
-
}
|
|
91
65
|
}
|
|
92
|
-
}
|
|
93
66
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
67
|
+
let settings: Settings | null = null;
|
|
68
|
+
|
|
69
|
+
if (!error) {
|
|
70
|
+
if (reactSettings) {
|
|
71
|
+
const settingsPreview = await createServer({
|
|
72
|
+
optimizeDeps: {
|
|
73
|
+
include: ["react/jsx-runtime"],
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
const config = await settingsPreview.ssrLoadModule(settingsFilePath);
|
|
77
|
+
const mod = config.default as Settings;
|
|
78
|
+
|
|
79
|
+
settings = postLoadSetup(mod);
|
|
80
|
+
} else {
|
|
81
|
+
const rawJsonSettings = await fs.readFile(settingsFilePath, "utf-8");
|
|
82
|
+
try {
|
|
83
|
+
let json = JSON.parse(rawJsonSettings) as Settings;
|
|
84
|
+
|
|
85
|
+
settings = postLoadSetup(json);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
console.error("⚠️ Error parsing settings file");
|
|
88
|
+
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const fastServeSettings = await fastServeSetup(settings);
|
|
95
|
+
if (fastServeSettings) {
|
|
96
|
+
return fastServeSettings;
|
|
97
|
+
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
return settings;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
// TODO: it's concept only
|
|
103
103
|
async function fastServeSetup(currentSettings: Settings | null) {
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
const args = process.argv.slice(2);
|
|
105
|
+
const [command, optionalFastServePath] = args;
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const extension = path.extname(optionalFastServePath).slice(1);
|
|
114
|
-
|
|
115
|
-
let fastServeSettings: Settings = {
|
|
116
|
-
theme: {
|
|
117
|
-
name: "gusto",
|
|
118
|
-
appearance: {
|
|
119
|
-
//@ts-ignore
|
|
120
|
-
search: false,
|
|
121
|
-
colorScheme: false,
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
if (currentSettings) {
|
|
126
|
-
fastServeSettings = deepMerge(fastServeSettings, currentSettings);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
switch (extension) {
|
|
130
|
-
case "yaml":
|
|
131
|
-
case "yml": {
|
|
132
|
-
if (await isOpenApiYaml(optionalFastServePath)) {
|
|
133
|
-
fastServeSettings.api = {
|
|
134
|
-
openapi: optionalFastServePath,
|
|
135
|
-
};
|
|
107
|
+
const fastServeMode =
|
|
108
|
+
(command === "dev" || command === "build") && optionalFastServePath;
|
|
109
|
+
if (!fastServeMode) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
136
112
|
|
|
137
|
-
|
|
138
|
-
|
|
113
|
+
const extension = path.extname(optionalFastServePath).slice(1);
|
|
114
|
+
|
|
115
|
+
let fastServeSettings: Settings = {
|
|
116
|
+
theme: {
|
|
117
|
+
name: "gusto",
|
|
118
|
+
appearance: {
|
|
119
|
+
//@ts-ignore
|
|
120
|
+
search: false,
|
|
121
|
+
colorScheme: false,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
if (currentSettings) {
|
|
126
|
+
fastServeSettings = deepMerge(fastServeSettings, currentSettings);
|
|
139
127
|
}
|
|
140
|
-
case "graphql":
|
|
141
|
-
case "graphqls": {
|
|
142
|
-
fastServeSettings.api = {
|
|
143
|
-
graphql: optionalFastServePath,
|
|
144
|
-
};
|
|
145
128
|
|
|
146
|
-
|
|
129
|
+
switch (extension) {
|
|
130
|
+
case "yaml":
|
|
131
|
+
case "yml": {
|
|
132
|
+
if (await isOpenApiYaml(optionalFastServePath)) {
|
|
133
|
+
fastServeSettings.api = {
|
|
134
|
+
openapi: optionalFastServePath,
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
return postLoadSetup(fastServeSettings);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
case "graphql":
|
|
141
|
+
case "graphqls": {
|
|
142
|
+
fastServeSettings.api = {
|
|
143
|
+
graphql: optionalFastServePath,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return postLoadSetup(fastServeSettings);
|
|
147
|
+
}
|
|
147
148
|
}
|
|
148
|
-
}
|
|
149
149
|
|
|
150
|
-
|
|
150
|
+
return null;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
function postLoadSetup(settings: Settings) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
// Replace environment variables in the settings
|
|
155
|
+
const processedSettings = replaceEnvVars(settings);
|
|
156
|
+
presets(processedSettings);
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
return processedSettings;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
// if (settings?.theme?.coder?.syntaxHighlight) {
|
|
@@ -163,106 +163,113 @@ function postLoadSetup(settings: Settings) {
|
|
|
163
163
|
// }
|
|
164
164
|
|
|
165
165
|
function presets(settings: Settings) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
166
|
+
if (
|
|
167
|
+
settings?.theme?.coder?.syntaxHighlight &&
|
|
168
|
+
typeof settings.theme.coder.syntaxHighlight === "string"
|
|
169
|
+
) {
|
|
170
|
+
handleSyntaxHighlight(settings.theme.coder.syntaxHighlight, settings);
|
|
171
|
+
}
|
|
172
|
+
ensureNavigation(settings);
|
|
173
|
+
|
|
174
|
+
if (settings?.theme && !settings?.theme?.head?.length) {
|
|
175
|
+
settings.theme.head = [];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
ensureBasename(settings);
|
|
179
|
+
|
|
180
|
+
if (typeof settings?.integrations?.diagrams === "boolean" && settings?.integrations?.diagrams) {
|
|
181
|
+
// by default, enable mermaid only
|
|
182
|
+
settings.integrations.diagrams = [
|
|
183
|
+
"mermaid",
|
|
184
|
+
]
|
|
185
|
+
}
|
|
179
186
|
}
|
|
180
187
|
|
|
181
188
|
function ensureBasename(settings: Settings) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
189
|
+
const basename = settings?.advanced?.basename;
|
|
190
|
+
if (!basename) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (typeof settings?.theme?.logo === "string") {
|
|
194
|
+
settings.theme.logo = path.join(basename, settings?.theme?.logo);
|
|
195
|
+
}
|
|
196
|
+
if (
|
|
197
|
+
typeof settings?.theme?.logo === "object" &&
|
|
198
|
+
("light" in settings?.theme?.logo ||
|
|
199
|
+
"dark" in settings?.theme?.logo ||
|
|
200
|
+
"href" in settings?.theme?.logo)
|
|
201
|
+
) {
|
|
202
|
+
settings.theme.logo = {
|
|
203
|
+
light: path.join(basename, settings?.theme?.logo?.light || ""),
|
|
204
|
+
dark: path.join(basename, settings?.theme?.logo?.dark || ""),
|
|
205
|
+
href: settings?.theme?.logo?.href,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
if (typeof settings?.theme?.favicon === "string") {
|
|
209
|
+
settings.theme.favicon = path.join(basename, settings?.theme?.favicon);
|
|
210
|
+
}
|
|
204
211
|
}
|
|
205
212
|
|
|
206
213
|
async function handleSyntaxHighlight(
|
|
207
|
-
|
|
208
|
-
|
|
214
|
+
syntaxHighlight: string,
|
|
215
|
+
settings: Settings
|
|
209
216
|
) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// Check if it's a URL
|
|
220
|
-
if (isUrl(syntaxHighlight)) {
|
|
221
|
-
// Fetch from remote URL
|
|
222
|
-
const response = await fetch(syntaxHighlight);
|
|
223
|
-
if (!response.ok) {
|
|
224
|
-
console.error(
|
|
225
|
-
`⚠️ Failed to fetch syntax highlight from URL: ${syntaxHighlight}`
|
|
226
|
-
);
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
const json = await response.json();
|
|
230
|
-
settings.theme!.coder!.syntaxHighlight = json;
|
|
231
|
-
} else {
|
|
232
|
-
// Handle local path - but first check if ita's actually a path
|
|
233
|
-
const localPath = path.resolve(process.cwd(), syntaxHighlight);
|
|
234
|
-
try {
|
|
235
|
-
// Check if the file exists before trying to read it
|
|
236
|
-
await fs.access(localPath);
|
|
237
|
-
const fileContent = await fs.readFile(localPath, "utf-8");
|
|
238
|
-
const json = JSON.parse(fileContent);
|
|
239
|
-
settings.theme!.coder!.syntaxHighlight = json;
|
|
240
|
-
} catch (error) {}
|
|
241
|
-
}
|
|
217
|
+
try {
|
|
218
|
+
// Ensure theme.coder exists
|
|
219
|
+
if (!settings.theme) {
|
|
220
|
+
settings.theme = { name: "default" } as any;
|
|
221
|
+
}
|
|
222
|
+
if (!settings.theme!.coder) {
|
|
223
|
+
settings.theme!.coder = {};
|
|
224
|
+
}
|
|
242
225
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
226
|
+
// Check if it's a URL
|
|
227
|
+
if (isUrl(syntaxHighlight)) {
|
|
228
|
+
// Fetch from remote URL
|
|
229
|
+
const response = await fetch(syntaxHighlight);
|
|
230
|
+
if (!response.ok) {
|
|
231
|
+
console.error(
|
|
232
|
+
`⚠️ Failed to fetch syntax highlight from URL: ${syntaxHighlight}`
|
|
233
|
+
);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const json = await response.json();
|
|
237
|
+
settings.theme!.coder!.syntaxHighlight = json;
|
|
238
|
+
} else {
|
|
239
|
+
// Handle local path - but first check if ita's actually a path
|
|
240
|
+
const localPath = path.resolve(process.cwd(), syntaxHighlight);
|
|
241
|
+
try {
|
|
242
|
+
// Check if the file exists before trying to read it
|
|
243
|
+
await fs.access(localPath);
|
|
244
|
+
const fileContent = await fs.readFile(localPath, "utf-8");
|
|
245
|
+
const json = JSON.parse(fileContent);
|
|
246
|
+
settings.theme!.coder!.syntaxHighlight = json;
|
|
247
|
+
} catch (error) {}
|
|
248
|
+
}
|
|
247
249
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
const syntaxHighlightTheme = settings.theme?.coder?.syntaxHighlight;
|
|
251
|
+
if (syntaxHighlightTheme) {
|
|
252
|
+
try {
|
|
253
|
+
const themeColors = await getThemeColors(syntaxHighlightTheme);
|
|
254
|
+
|
|
255
|
+
if (themeColors) {
|
|
256
|
+
globalThis.__xydUserPreferences = {
|
|
257
|
+
themeColors,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
} catch (error) {
|
|
261
|
+
console.error(
|
|
262
|
+
`⚠️ Error processing syntax highlight theme colors.`,
|
|
263
|
+
error
|
|
264
|
+
);
|
|
265
|
+
}
|
|
252
266
|
}
|
|
253
|
-
|
|
267
|
+
} catch (error) {
|
|
254
268
|
console.error(
|
|
255
|
-
|
|
256
|
-
|
|
269
|
+
`⚠️ Error processing syntax highlight: ${syntaxHighlight}`,
|
|
270
|
+
error
|
|
257
271
|
);
|
|
258
|
-
}
|
|
259
272
|
}
|
|
260
|
-
} catch (error) {
|
|
261
|
-
console.error(
|
|
262
|
-
`⚠️ Error processing syntax highlight: ${syntaxHighlight}`,
|
|
263
|
-
error
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
273
|
}
|
|
267
274
|
|
|
268
275
|
/**
|
|
@@ -270,105 +277,105 @@ async function handleSyntaxHighlight(
|
|
|
270
277
|
* @param dirPath - The directory path to search for .env files
|
|
271
278
|
*/
|
|
272
279
|
async function loadEnvFiles(dirPath: string) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
280
|
+
try {
|
|
281
|
+
// Define the order of .env files to load (later files override earlier ones)
|
|
282
|
+
const envFiles = [
|
|
283
|
+
".env",
|
|
284
|
+
".env.local",
|
|
285
|
+
".env.development",
|
|
286
|
+
".env.production",
|
|
287
|
+
];
|
|
288
|
+
|
|
289
|
+
for (const envFile of envFiles) {
|
|
290
|
+
const envPath = path.join(dirPath, envFile);
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
await fs.access(envPath);
|
|
294
|
+
const result = dotenvConfig({
|
|
295
|
+
path: envPath,
|
|
296
|
+
override: true, // Ensure variables are overridden
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
if (result.parsed && Object.keys(result.parsed).length > 0) {
|
|
300
|
+
console.debug(`📄 Loaded environment variables.`);
|
|
301
|
+
}
|
|
302
|
+
} catch (error) {
|
|
303
|
+
// File doesn't exist, which is fine - continue to next file
|
|
304
|
+
}
|
|
294
305
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
306
|
+
} catch (error) {
|
|
307
|
+
console.warn("⚠️ Error loading .env files:", error);
|
|
298
308
|
}
|
|
299
|
-
} catch (error) {
|
|
300
|
-
console.warn("⚠️ Error loading .env files:", error);
|
|
301
|
-
}
|
|
302
309
|
}
|
|
303
310
|
|
|
304
311
|
|
|
305
312
|
function isUrl(str: string): boolean {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
313
|
+
try {
|
|
314
|
+
new URL(str);
|
|
315
|
+
return true;
|
|
316
|
+
} catch {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
312
319
|
}
|
|
313
320
|
|
|
314
321
|
function ensureNavigation(json: Settings) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
322
|
+
if (!json?.webeditor) {
|
|
323
|
+
json.webeditor = {};
|
|
324
|
+
}
|
|
318
325
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
326
|
+
if (!json?.navigation) {
|
|
327
|
+
json.navigation = {
|
|
328
|
+
sidebar: [],
|
|
329
|
+
};
|
|
330
|
+
}
|
|
324
331
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
332
|
+
if (!json?.navigation?.sidebar) {
|
|
333
|
+
json.navigation.sidebar = [];
|
|
334
|
+
}
|
|
328
335
|
}
|
|
329
336
|
|
|
330
337
|
type DeepPartial<T> = {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
+
[P in keyof T]?: T[P] extends object
|
|
339
|
+
? T[P] extends Function
|
|
340
|
+
? T[P]
|
|
341
|
+
: T[P] extends Array<infer U>
|
|
342
|
+
? Array<DeepPartial<U>>
|
|
343
|
+
: DeepPartial<T[P]>
|
|
344
|
+
: T[P];
|
|
338
345
|
};
|
|
339
346
|
|
|
340
347
|
function deepMerge<T>(target: T, source: DeepPartial<T>): T {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
348
|
+
for (const key in source) {
|
|
349
|
+
const sourceVal = source[key];
|
|
350
|
+
const targetVal = target[key];
|
|
351
|
+
|
|
352
|
+
if (
|
|
353
|
+
sourceVal &&
|
|
354
|
+
typeof sourceVal === "object" &&
|
|
355
|
+
!Array.isArray(sourceVal) &&
|
|
356
|
+
typeof targetVal === "object" &&
|
|
357
|
+
targetVal !== null
|
|
358
|
+
) {
|
|
359
|
+
target[key] = deepMerge(targetVal, sourceVal);
|
|
360
|
+
} else if (sourceVal !== undefined) {
|
|
361
|
+
target[key] = sourceVal as any;
|
|
362
|
+
}
|
|
355
363
|
}
|
|
356
|
-
}
|
|
357
364
|
|
|
358
|
-
|
|
365
|
+
return target;
|
|
359
366
|
}
|
|
360
367
|
|
|
361
368
|
async function isOpenApiYaml(filePath: string): Promise<boolean> {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
369
|
+
try {
|
|
370
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
371
|
+
const parsed = yaml.load(content);
|
|
372
|
+
if (!parsed) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
368
375
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
376
|
+
return parsed && typeof parsed === "object" && "openapi" in parsed;
|
|
377
|
+
} catch (error) {
|
|
378
|
+
console.warn(`⚠️ Error reading or parsing YAML file ${filePath}:`, error);
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
374
381
|
}
|