@zuplo/cli 6.57.1 → 6.57.3

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.
Files changed (29) hide show
  1. package/dist/cmds/source/index.d.ts.map +1 -1
  2. package/dist/cmds/source/index.js +6 -1
  3. package/dist/cmds/source/index.js.map +1 -1
  4. package/dist/cmds/source/migrate/handler.d.ts +3 -0
  5. package/dist/cmds/source/migrate/handler.d.ts.map +1 -0
  6. package/dist/cmds/source/migrate/handler.js +648 -0
  7. package/dist/cmds/source/migrate/handler.js.map +1 -0
  8. package/dist/cmds/source/migrate/runner.d.ts +43 -0
  9. package/dist/cmds/source/migrate/runner.d.ts.map +1 -0
  10. package/dist/cmds/source/migrate/runner.js +65 -0
  11. package/dist/cmds/source/migrate/runner.js.map +1 -0
  12. package/dist/cmds/source/migrate/stringify-config.d.ts +2 -0
  13. package/dist/cmds/source/migrate/stringify-config.d.ts.map +1 -0
  14. package/dist/cmds/source/migrate/stringify-config.js +14 -0
  15. package/dist/cmds/source/migrate/stringify-config.js.map +1 -0
  16. package/dist/cmds/source/migrate/stringify-config.test.d.ts +2 -0
  17. package/dist/cmds/source/migrate/stringify-config.test.d.ts.map +1 -0
  18. package/dist/cmds/source/migrate/stringify-config.test.js +80 -0
  19. package/dist/cmds/source/migrate/stringify-config.test.js.map +1 -0
  20. package/dist/cmds/source/migrate/types.d.ts +83 -0
  21. package/dist/cmds/source/migrate/types.d.ts.map +1 -0
  22. package/dist/cmds/source/migrate/types.js +2 -0
  23. package/dist/cmds/source/migrate/types.js.map +1 -0
  24. package/dist/cmds/source/migrate.d.ts +10 -0
  25. package/dist/cmds/source/migrate.d.ts.map +1 -0
  26. package/dist/cmds/source/migrate.js +38 -0
  27. package/dist/cmds/source/migrate.js.map +1 -0
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +5 -4
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAKtC,QAAA,MAAM,QAAQ,EAAE,aAOf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAMtC,QAAA,MAAM,QAAQ,EAAE,aAWf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -1,11 +1,16 @@
1
1
  import { groupHandler } from "../../common/handler.js";
2
2
  import importOpenApi from "./import-openapi.js";
3
+ import migrate from "./migrate.js";
3
4
  import upgrade from "./upgrade.js";
4
5
  const commands = {
5
6
  describe: "Source code management commands",
6
7
  command: "source",
7
8
  builder: (yargs) => {
8
- return yargs.command(upgrade).command(importOpenApi).help();
9
+ return yargs
10
+ .command(upgrade)
11
+ .command(importOpenApi)
12
+ .command(migrate)
13
+ .help();
9
14
  },
10
15
  handler: groupHandler,
11
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cmds/source/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,MAAM,QAAQ,GAAkB;IAC9B,QAAQ,EAAE,iCAAiC;IAC3C,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QACjB,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,CAAC;IACD,OAAO,EAAE,YAAY;CACtB,CAAC;AAEF,eAAe,QAAQ,CAAC","sourcesContent":["import { CommandModule } from \"yargs\";\nimport { groupHandler } from \"../../common/handler.js\";\nimport importOpenApi from \"./import-openapi.js\";\nimport upgrade from \"./upgrade.js\";\n\nconst commands: CommandModule = {\n describe: \"Source code management commands\",\n command: \"source\",\n builder: (yargs) => {\n return yargs.command(upgrade).command(importOpenApi).help();\n },\n handler: groupHandler,\n};\n\nexport default commands;\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cmds/source/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,MAAM,QAAQ,GAAkB;IAC9B,QAAQ,EAAE,iCAAiC;IAC3C,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QACjB,OAAO,KAAK;aACT,OAAO,CAAC,OAAO,CAAC;aAChB,OAAO,CAAC,aAAa,CAAC;aACtB,OAAO,CAAC,OAAO,CAAC;aAChB,IAAI,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,EAAE,YAAY;CACtB,CAAC;AAEF,eAAe,QAAQ,CAAC","sourcesContent":["import { CommandModule } from \"yargs\";\nimport { groupHandler } from \"../../common/handler.js\";\nimport importOpenApi from \"./import-openapi.js\";\nimport migrate from \"./migrate.js\";\nimport upgrade from \"./upgrade.js\";\n\nconst commands: CommandModule = {\n describe: \"Source code management commands\",\n command: \"source\",\n builder: (yargs) => {\n return yargs\n .command(upgrade)\n .command(importOpenApi)\n .command(migrate)\n .help();\n },\n handler: groupHandler,\n};\n\nexport default commands;\n"]}
@@ -0,0 +1,3 @@
1
+ import type { Arguments } from "./types.js";
2
+ export declare const migrateDevPortal: (args: Arguments) => Promise<void>;
3
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/cmds/source/migrate/handler.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,SAAS,EAMV,MAAM,YAAY,CAAC;AAiBpB,eAAO,MAAM,gBAAgB,GAAU,MAAM,SAAS,kBAmErD,CAAC"}
@@ -0,0 +1,648 @@
1
+ import { readFile, writeFile, stat, mkdir, rename, unlink, } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { exec } from "node:child_process";
4
+ import { promisify } from "node:util";
5
+ import glob from "fast-glob";
6
+ import { format } from "prettier";
7
+ import { printDiagnosticsToConsole } from "../../../common/output.js";
8
+ import chalk from "chalk";
9
+ import { PluginResult, runPlugins } from "./runner.js";
10
+ import { stringifyConfig } from "./stringify-config.js";
11
+ const exists = (path) => stat(path)
12
+ .then(() => true)
13
+ .catch(() => false);
14
+ const deleteUndefinedValues = (obj) => {
15
+ Object.entries(obj).forEach(([key, value]) => {
16
+ if (value === undefined) {
17
+ delete obj[key];
18
+ }
19
+ });
20
+ };
21
+ const execAsync = promisify(exec);
22
+ export const migrateDevPortal = async (args) => {
23
+ const absoluteBaseDir = path.isAbsolute(args.dir)
24
+ ? args.dir
25
+ : path.join(process.cwd(), args.dir);
26
+ const tasks = [
27
+ checkGitStatus,
28
+ loadInputFiles,
29
+ validateDevPortalEnabled,
30
+ convertBasicConfig,
31
+ convertSidebar,
32
+ handleApiReferences,
33
+ handleAuthentication,
34
+ handleAdditionalFeatures,
35
+ updatePackageJsonWorkspaces,
36
+ createPackageJson,
37
+ createTsConfig,
38
+ moveMarkdownFiles,
39
+ writeConfigFile,
40
+ cleanupOldFiles,
41
+ ];
42
+ const pluginConfig = {
43
+ absoluteBaseDir,
44
+ force: args.force,
45
+ };
46
+ const { errors, warnings, notes } = await runPlugins(tasks, pluginConfig);
47
+ if (errors.length > 0) {
48
+ printDiagnosticsToConsole("❌ Migration failed with errors:");
49
+ errors.forEach((error) => printDiagnosticsToConsole(`- [${error.pluginName}] ${error.message}`));
50
+ process.exit(1);
51
+ }
52
+ printDiagnosticsToConsole(chalk.green("\n✅ Migration completed successfully! 🎉"));
53
+ if (notes.length > 0) {
54
+ printDiagnosticsToConsole("\n📝 Migration notes:");
55
+ notes.forEach((note) => printDiagnosticsToConsole(`- ${note}`));
56
+ }
57
+ if (warnings.length > 0) {
58
+ printDiagnosticsToConsole("\n⚠️ Plugin warnings:");
59
+ warnings.forEach((warning) => printDiagnosticsToConsole(`- [${warning.pluginName}] ${warning.message}`));
60
+ }
61
+ printDiagnosticsToConsole("\nNext steps:");
62
+ printDiagnosticsToConsole("1. Switch to the docs directory:");
63
+ printDiagnosticsToConsole(` ${chalk.cyan(`cd ${path.join(absoluteBaseDir, "docs")}`)}`);
64
+ printDiagnosticsToConsole("\n2. Install dependencies:");
65
+ printDiagnosticsToConsole(` ${chalk.cyan("npm install")}`);
66
+ printDiagnosticsToConsole("\n3. Start the dev portal:");
67
+ printDiagnosticsToConsole(` ${chalk.cyan("npm run dev")}`);
68
+ printDiagnosticsToConsole("");
69
+ };
70
+ const checkGitStatus = async (config) => {
71
+ if (config.force)
72
+ return new PluginResult();
73
+ try {
74
+ await execAsync("git rev-parse --git-dir", { cwd: config.absoluteBaseDir });
75
+ const status = await execAsync("git status --porcelain", {
76
+ cwd: config.absoluteBaseDir,
77
+ });
78
+ if (status.stdout.trim() !== "") {
79
+ return new PluginResult({
80
+ pluginName: "check-git-status",
81
+ message: "There are uncommitted changes in the repository.\nCommit or stash them before running the migration, or use --force to proceed anyway.",
82
+ severity: "error",
83
+ });
84
+ }
85
+ }
86
+ catch {
87
+ }
88
+ return new PluginResult();
89
+ };
90
+ const loadInputFiles = async (config, { data }) => {
91
+ const dir = config.absoluteBaseDir;
92
+ try {
93
+ const packageJson = JSON.parse(await readFile(path.join(dir, "package.json"), "utf-8"));
94
+ const inputFile = path.join(dir, "config/dev-portal.json");
95
+ const sidebarFile = path.join(dir, "docs/sidebar.json");
96
+ const devPortalConfig = JSON.parse(await readFile(inputFile, "utf-8"));
97
+ const sidebar = JSON.parse(await readFile(sidebarFile, "utf-8"));
98
+ data.packageJson = packageJson;
99
+ data.devPortalConfig = devPortalConfig;
100
+ data.sidebar = sidebar;
101
+ return new PluginResult();
102
+ }
103
+ catch (error) {
104
+ return new PluginResult({
105
+ pluginName: "load-input-files",
106
+ message: `Failed to load input files: ${error.message}`,
107
+ severity: "error",
108
+ });
109
+ }
110
+ };
111
+ const validateDevPortalEnabled = async (_, { data }) => {
112
+ if (data.devPortalConfig?.enabled === false) {
113
+ return new PluginResult({
114
+ pluginName: "validate-dev-portal-enabled",
115
+ message: "Dev portal is not enabled in the config",
116
+ severity: "error",
117
+ });
118
+ }
119
+ return new PluginResult();
120
+ };
121
+ const convertBasicConfig = async (_, { data }) => {
122
+ try {
123
+ if (!data.devPortalConfig) {
124
+ return new PluginResult({
125
+ pluginName: "convert-basic-config",
126
+ message: "Dev portal config not found",
127
+ severity: "error",
128
+ });
129
+ }
130
+ const zudokuConfig = {};
131
+ if (data.devPortalConfig.faviconUrl) {
132
+ zudokuConfig.metadata = {
133
+ ...zudokuConfig.metadata,
134
+ favicon: data.devPortalConfig.faviconUrl,
135
+ };
136
+ }
137
+ if (data.devPortalConfig.pageTitle) {
138
+ zudokuConfig.metadata = {
139
+ ...zudokuConfig.metadata,
140
+ title: data.devPortalConfig.pageTitle,
141
+ };
142
+ }
143
+ if (data.devPortalConfig.sitePathname) {
144
+ zudokuConfig.basePath = data.devPortalConfig.sitePathname;
145
+ }
146
+ data.zudokuConfig = zudokuConfig;
147
+ return new PluginResult();
148
+ }
149
+ catch (error) {
150
+ return new PluginResult({
151
+ pluginName: "convert-basic-config",
152
+ message: `Failed to convert basic config: ${error.message}`,
153
+ severity: "error",
154
+ });
155
+ }
156
+ };
157
+ const convertSidebar = async (_, { data }) => {
158
+ try {
159
+ if (!data.sidebar || !data.zudokuConfig) {
160
+ return new PluginResult({
161
+ pluginName: "convert-sidebar",
162
+ message: "Required data not found",
163
+ severity: "error",
164
+ });
165
+ }
166
+ const convertSidebarToNavigation = (oldSidebar) => {
167
+ const navigation = [];
168
+ if (!oldSidebar.docs) {
169
+ return navigation;
170
+ }
171
+ for (const item of oldSidebar.docs) {
172
+ if (typeof item === "string") {
173
+ navigation.push(item);
174
+ }
175
+ else if (item.type === "doc") {
176
+ const docItem = {
177
+ type: "doc",
178
+ file: item.id,
179
+ label: item.label,
180
+ };
181
+ if ("defaultPage" in item && item.defaultPage) {
182
+ docItem.path = "/";
183
+ }
184
+ navigation.push(docItem);
185
+ }
186
+ else if (item.type === "category") {
187
+ const category = {
188
+ type: "category",
189
+ label: item.label,
190
+ items: [],
191
+ };
192
+ if (item.link) {
193
+ if (typeof item.link === "string") {
194
+ category.link = item.link;
195
+ }
196
+ else if (item.link.type === "doc") {
197
+ category.link = { type: "doc", file: item.link.id };
198
+ }
199
+ }
200
+ if (item.items) {
201
+ category.items = [];
202
+ for (const subItem of item.items) {
203
+ if (typeof subItem === "string") {
204
+ category.items.push({
205
+ type: "doc",
206
+ file: subItem,
207
+ });
208
+ }
209
+ else if (subItem.type === "doc") {
210
+ category.items.push({
211
+ type: "doc",
212
+ file: subItem.id,
213
+ label: subItem.label,
214
+ });
215
+ }
216
+ }
217
+ }
218
+ navigation.push(category);
219
+ }
220
+ }
221
+ return navigation;
222
+ };
223
+ const navigation = convertSidebarToNavigation(data.sidebar);
224
+ data.zudokuConfig = {
225
+ ...data.zudokuConfig,
226
+ navigation,
227
+ };
228
+ const result = new PluginResult();
229
+ if (navigation.length > 0) {
230
+ result.notes.push(`Converted sidebar navigation: ${navigation.length} navigation items`);
231
+ }
232
+ return result;
233
+ }
234
+ catch (error) {
235
+ return new PluginResult({
236
+ pluginName: "convert-sidebar",
237
+ message: `Failed to convert sidebar: ${error.message}`,
238
+ severity: "error",
239
+ });
240
+ }
241
+ };
242
+ const handleApiReferences = async (_, { data }) => {
243
+ try {
244
+ if (!data.sidebar || !data.zudokuConfig) {
245
+ return new PluginResult({
246
+ pluginName: "handle-api-references",
247
+ message: "Required data not found",
248
+ severity: "error",
249
+ });
250
+ }
251
+ const apiRefItems = data.sidebar.docs?.filter((item) => typeof item !== "string" && item.type === "api-ref");
252
+ const result = new PluginResult();
253
+ if (!apiRefItems || apiRefItems.length === 0) {
254
+ return result;
255
+ }
256
+ data.zudokuConfig.apis = apiRefItems.map((apiRefItem, index) => {
257
+ const specInput = apiRefItem.defaultSpec
258
+ ? `../config/${apiRefItem.defaultSpec}.oas.json`
259
+ : "../config/routes.oas.json";
260
+ const apiPath = index === 0 ? "/api" : `/api-${index + 1}`;
261
+ result.notes.push(`Migrated API reference to ${apiPath}`);
262
+ return {
263
+ type: "file",
264
+ input: specInput,
265
+ path: apiPath,
266
+ };
267
+ });
268
+ if (apiRefItems.length > 1) {
269
+ result.warnings.push({
270
+ message: "Multiple API references found. Adding multiple links to the navigation. For advanced use cases you can use an API catalog. See: https://zuplo.com/docs/dev-portal/zudoku/configuration/api-catalog.",
271
+ pluginName: "handle-api-references",
272
+ severity: "warning",
273
+ });
274
+ }
275
+ const navigationLinks = apiRefItems.map((apiRefItem, index) => {
276
+ const apiPath = index === 0 ? "/api" : `/api-${index + 1}`;
277
+ return {
278
+ type: "link",
279
+ to: apiPath,
280
+ label: apiRefItem.label,
281
+ };
282
+ });
283
+ data.zudokuConfig.navigation = [
284
+ ...(data.zudokuConfig.navigation || []),
285
+ ...navigationLinks,
286
+ ];
287
+ return result;
288
+ }
289
+ catch (error) {
290
+ return new PluginResult({
291
+ pluginName: "handle-api-references",
292
+ message: `Failed to handle API references: ${error.message}`,
293
+ severity: "error",
294
+ });
295
+ }
296
+ };
297
+ const handleAuthentication = async (_, { data }) => {
298
+ try {
299
+ if (!data.devPortalConfig || !data.zudokuConfig) {
300
+ return new PluginResult({
301
+ pluginName: "handle-authentication",
302
+ message: "Required data not found",
303
+ severity: "error",
304
+ });
305
+ }
306
+ if (data.devPortalConfig.authentication) {
307
+ const auth = data.devPortalConfig.authentication;
308
+ let clientId;
309
+ let audience;
310
+ let issuer;
311
+ let scope;
312
+ if ("clientId" in auth) {
313
+ clientId = auth.clientId;
314
+ audience = auth.audience;
315
+ issuer = auth.issuer;
316
+ scope = auth.scope;
317
+ }
318
+ else if ("devPortalClient" in auth) {
319
+ clientId = auth.devPortalClient?.clientId;
320
+ audience = auth.devPortalClient?.audience;
321
+ issuer = auth.authority;
322
+ }
323
+ if (auth.provider === "auth0") {
324
+ data.zudokuConfig.authentication = {
325
+ type: "auth0",
326
+ clientId,
327
+ domain: issuer?.replace("https://", "").replace("/", ""),
328
+ audience,
329
+ scopes: scope?.split(" "),
330
+ };
331
+ }
332
+ else if (auth.provider === "clerk") {
333
+ const clerkPubKey = issuer?.match(/clerk\.accounts\.dev/)?.[0]
334
+ ? issuer.split("://")[1]?.split(".")[0]
335
+ : undefined;
336
+ data.zudokuConfig.authentication = {
337
+ type: "clerk",
338
+ clerkPubKey: clerkPubKey || clientId,
339
+ };
340
+ }
341
+ else {
342
+ data.zudokuConfig.authentication = {
343
+ type: "openid",
344
+ clientId,
345
+ issuer,
346
+ audience,
347
+ scopes: scope?.split(" "),
348
+ };
349
+ }
350
+ }
351
+ if (data.zudokuConfig.authentication) {
352
+ deleteUndefinedValues(data.zudokuConfig.authentication);
353
+ }
354
+ const result = new PluginResult();
355
+ if (data.zudokuConfig.authentication) {
356
+ result.notes.push(`Configured ${data.zudokuConfig.authentication.type} authentication`);
357
+ }
358
+ return result;
359
+ }
360
+ catch (error) {
361
+ return new PluginResult({
362
+ pluginName: "handle-authentication",
363
+ message: `Failed to handle authentication: ${error.message}`,
364
+ severity: "error",
365
+ });
366
+ }
367
+ };
368
+ const handleAdditionalFeatures = async (_, { data }) => {
369
+ try {
370
+ if (!data.devPortalConfig || !data.sidebar || !data.zudokuConfig) {
371
+ return new PluginResult({
372
+ pluginName: "handle-additional-features",
373
+ message: "Required data not found",
374
+ severity: "error",
375
+ });
376
+ }
377
+ const result = new PluginResult();
378
+ if (data.devPortalConfig.apiKeys) {
379
+ data.zudokuConfig.apiKeys = {
380
+ enabled: true,
381
+ };
382
+ }
383
+ const hasSpecsFiltering = data.sidebar.docs?.some((item) => {
384
+ if (typeof item === "string")
385
+ return false;
386
+ if (item.type === "doc" && "specs" in item && item.specs)
387
+ return true;
388
+ if (item.type === "category" && "specs" in item && item.specs)
389
+ return true;
390
+ if (item.type === "category" && item.items) {
391
+ return item.items.some((subItem) => typeof subItem !== "string" && "specs" in subItem && subItem.specs);
392
+ }
393
+ return false;
394
+ });
395
+ if (hasSpecsFiltering) {
396
+ result.warnings.push({
397
+ message: "The 'specs' property for filtering docs by OpenAPI specification is not supported in Zudoku",
398
+ pluginName: "handle-additional-features",
399
+ severity: "warning",
400
+ });
401
+ }
402
+ if (data.devPortalConfig.monetization) {
403
+ result.warnings.push({
404
+ message: "Monetization configuration is not supported in the new dev portal.",
405
+ pluginName: "handle-additional-features",
406
+ severity: "warning",
407
+ });
408
+ }
409
+ if (data.devPortalConfig.enableMetering) {
410
+ result.warnings.push({
411
+ message: "Metering is not supported in the new dev portal.",
412
+ pluginName: "handle-additional-features",
413
+ severity: "warning",
414
+ });
415
+ }
416
+ if (data.devPortalConfig.authorizePathname &&
417
+ data.devPortalConfig.authorizePathname !== "/oauth/authorize") {
418
+ result.warnings.push({
419
+ message: "Custom authorize pathname is not configurable in the new dev portal.",
420
+ pluginName: "handle-additional-features",
421
+ severity: "warning",
422
+ });
423
+ }
424
+ if (data.zudokuConfig.apiKeys?.enabled) {
425
+ result.notes.push("Enabled API keys support");
426
+ }
427
+ return result;
428
+ }
429
+ catch (error) {
430
+ return new PluginResult({
431
+ pluginName: "handle-additional-features",
432
+ message: `Failed to handle additional features: ${error.message}`,
433
+ severity: "error",
434
+ });
435
+ }
436
+ };
437
+ const createPackageJson = async (config) => {
438
+ try {
439
+ const packageJsonFile = path.join(config.absoluteBaseDir, "docs/package.json");
440
+ if (!config.force && (await exists(packageJsonFile))) {
441
+ return new PluginResult({
442
+ pluginName: "create-package-json",
443
+ message: "package.json already exists",
444
+ severity: "warning",
445
+ });
446
+ }
447
+ const zudokuPackageJson = await fetch("https://cdn.jsdelivr.net/npm/zudoku/package.json").then((res) => res.json());
448
+ const packageJsonContent = {
449
+ name: "docs",
450
+ version: "1.0.0",
451
+ type: "module",
452
+ private: true,
453
+ scripts: {
454
+ dev: "zudoku dev",
455
+ build: "zudoku build",
456
+ start: "zudoku start",
457
+ },
458
+ dependencies: {
459
+ zudoku: zudokuPackageJson.version || "latest",
460
+ react: zudokuPackageJson.dependencies.react || "^19.0.0",
461
+ "react-dom": zudokuPackageJson.dependencies["react-dom"] || "^19.0.0",
462
+ },
463
+ devDependencies: {
464
+ "@types/node": "^22",
465
+ "@types/react": ">=19",
466
+ "@types/react-dom": ">=19",
467
+ typescript: zudokuPackageJson.devDependencies.typescript || "^5",
468
+ },
469
+ };
470
+ await writeFile(packageJsonFile, JSON.stringify(packageJsonContent, null, 2));
471
+ const result = new PluginResult();
472
+ result.notes.push("Wrote docs/package.json");
473
+ return result;
474
+ }
475
+ catch (error) {
476
+ return new PluginResult({
477
+ pluginName: "create-package-json",
478
+ message: `Failed to create package.json: ${error.message}`,
479
+ severity: "error",
480
+ });
481
+ }
482
+ };
483
+ const createTsConfig = async (config) => {
484
+ try {
485
+ const tsConfigFile = path.join(config.absoluteBaseDir, "docs/tsconfig.json");
486
+ if (!config.force && (await exists(tsConfigFile))) {
487
+ return new PluginResult({
488
+ pluginName: "create-tsconfig",
489
+ message: "tsconfig.json already exists",
490
+ severity: "warning",
491
+ });
492
+ }
493
+ const tsConfigContent = await fetch("https://cdn.jsdelivr.net/npm/create-zudoku/dist/templates/zuplo/tsconfig.json").then((res) => res.text());
494
+ await writeFile(tsConfigFile, tsConfigContent);
495
+ const result = new PluginResult();
496
+ result.notes.push("Wrote docs/tsconfig.json");
497
+ return result;
498
+ }
499
+ catch (error) {
500
+ return new PluginResult({
501
+ pluginName: "create-tsconfig",
502
+ message: `Failed to create tsconfig.json: ${error.message}`,
503
+ severity: "error",
504
+ });
505
+ }
506
+ };
507
+ const updatePackageJsonWorkspaces = async (config) => {
508
+ try {
509
+ const packageJsonFile = path.join(config.absoluteBaseDir, "package.json");
510
+ if (!(await exists(packageJsonFile))) {
511
+ return new PluginResult({
512
+ pluginName: "update-package-json-workspaces",
513
+ message: "Root package.json not found",
514
+ severity: "warning",
515
+ });
516
+ }
517
+ const packageJsonContent = JSON.parse(await readFile(packageJsonFile, "utf-8"));
518
+ if (Array.isArray(packageJsonContent.workspaces)) {
519
+ if (!packageJsonContent.workspaces.includes("docs")) {
520
+ packageJsonContent.workspaces.push("docs");
521
+ }
522
+ }
523
+ else if (!packageJsonContent.workspaces) {
524
+ packageJsonContent.workspaces = ["docs"];
525
+ }
526
+ await writeFile(packageJsonFile, JSON.stringify(packageJsonContent, null, 2));
527
+ const result = new PluginResult();
528
+ result.notes.push("Updated package.json workspaces");
529
+ return result;
530
+ }
531
+ catch (error) {
532
+ return new PluginResult({
533
+ pluginName: "update-package-json-workspaces",
534
+ message: `Failed to update package.json workspaces: ${error.message}`,
535
+ severity: "error",
536
+ });
537
+ }
538
+ };
539
+ const moveMarkdownFiles = async (config) => {
540
+ try {
541
+ const docsDir = path.join(config.absoluteBaseDir, "docs");
542
+ const pagesDir = path.join(docsDir, "pages");
543
+ const markdownFiles = await glob(["*.md", "*.mdx"], {
544
+ cwd: docsDir,
545
+ absolute: false,
546
+ });
547
+ try {
548
+ await mkdir(pagesDir, { recursive: true });
549
+ }
550
+ catch {
551
+ }
552
+ const result = new PluginResult();
553
+ const movedFiles = [];
554
+ for (const file of markdownFiles) {
555
+ const sourcePath = path.join(docsDir, file);
556
+ const targetPath = path.join(pagesDir, file);
557
+ try {
558
+ await rename(sourcePath, targetPath);
559
+ movedFiles.push(file);
560
+ }
561
+ catch (error) {
562
+ result.warnings.push({
563
+ message: `Failed to move ${file}: ${error.message}`,
564
+ pluginName: "move-markdown-files",
565
+ severity: "warning",
566
+ });
567
+ }
568
+ }
569
+ if (movedFiles.length > 0) {
570
+ result.notes.push(`Moved ${movedFiles.length} markdown files to docs/pages/`);
571
+ }
572
+ return result;
573
+ }
574
+ catch (error) {
575
+ return new PluginResult({
576
+ pluginName: "move-markdown-files",
577
+ message: `Failed to move markdown files: ${error.message}`,
578
+ severity: "error",
579
+ });
580
+ }
581
+ };
582
+ const cleanupOldFiles = async (config) => {
583
+ try {
584
+ const filesToCleanup = [
585
+ path.join(config.absoluteBaseDir, "config/dev-portal.json"),
586
+ path.join(config.absoluteBaseDir, "docs/sidebar.json"),
587
+ ];
588
+ const result = new PluginResult();
589
+ const cleanedFiles = [];
590
+ for (const filePath of filesToCleanup) {
591
+ try {
592
+ if (await exists(filePath)) {
593
+ await unlink(filePath);
594
+ cleanedFiles.push(path.relative(config.absoluteBaseDir, filePath));
595
+ }
596
+ }
597
+ catch (error) {
598
+ result.warnings.push({
599
+ message: `Failed to remove ${path.relative(config.absoluteBaseDir, filePath)}: ${error.message}`,
600
+ pluginName: "cleanup-old-files",
601
+ severity: "warning",
602
+ });
603
+ }
604
+ }
605
+ if (cleanedFiles.length > 0) {
606
+ result.notes.push(`Cleaned up old files: ${cleanedFiles.join(", ")}`);
607
+ }
608
+ return result;
609
+ }
610
+ catch (error) {
611
+ return new PluginResult({
612
+ pluginName: "cleanup-old-files",
613
+ message: `Failed to cleanup old files: ${error.message}`,
614
+ severity: "error",
615
+ });
616
+ }
617
+ };
618
+ const writeConfigFile = async (config, { data }) => {
619
+ try {
620
+ if (!data.zudokuConfig) {
621
+ return new PluginResult({
622
+ pluginName: "write-output-file",
623
+ message: "Zudoku config not found",
624
+ severity: "error",
625
+ });
626
+ }
627
+ const outputFile = path.join(config.absoluteBaseDir, "docs/zudoku.config.tsx");
628
+ const configContent = [];
629
+ configContent.push(`// This file was generated by the Zuplo CLI migrate-dev-portal command.
630
+ // It is used to configure the Zuplo dev portal.
631
+ // You can edit this file to customize the dev portal.
632
+ // For more information, see https://zuplo.com/docs/dev-portal/zudoku/configuration/overview`);
633
+ configContent.push(`import type { ZudokuConfig } from "zudoku";\n`);
634
+ configContent.push(`export const config: ZudokuConfig = ${stringifyConfig(data.zudokuConfig)}`);
635
+ await writeFile(outputFile, await format(configContent.join("\n"), { parser: "typescript" }));
636
+ const result = new PluginResult();
637
+ result.notes.push("Wrote docs/zudoku.config.tsx");
638
+ return result;
639
+ }
640
+ catch (error) {
641
+ return new PluginResult({
642
+ pluginName: "write-output-file",
643
+ message: `Failed to write output file: ${error.message}`,
644
+ severity: "error",
645
+ });
646
+ }
647
+ };
648
+ //# sourceMappingURL=handler.js.map