zudoku 0.1.1-dev.17 → 0.1.1-dev.19
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/lib/plugins/openapi/worker/createSharedWorkerClient.js +2 -3
- package/dist/lib/plugins/openapi/worker/createSharedWorkerClient.js.map +1 -1
- package/dist/lib/plugins/openapi/worker/shared-worker.d.ts +1 -0
- package/dist/lib/plugins/openapi/worker/shared-worker.js +6 -0
- package/dist/lib/plugins/openapi/worker/shared-worker.js.map +1 -0
- package/dist/vite/config.d.ts +1 -1
- package/dist/vite/config.js +13 -13
- package/dist/vite/config.js.map +1 -1
- package/dist/vite/dev-server.js +1 -1
- package/dist/vite/dev-server.js.map +1 -1
- package/lib/DevPortal-DqcnbwLT.js +12967 -0
- package/lib/assets/index-BPdJm2ty.js +4764 -0
- package/lib/assets/worker-CnXQsqxH.js +14511 -0
- package/lib/prism-bash.min-DadFsM4Z.js +6 -0
- package/lib/prism-java.min-d5iT_mOd.js +6 -0
- package/lib/prism-json.min-B1GJqK1k.js +1 -0
- package/lib/prism-markup-templating-DZrrEs0A.js +61 -0
- package/lib/prism-php.min-o7FpoMP_.js +10 -0
- package/lib/prism-ruby.min-C7LwcKyz.js +9 -0
- package/lib/zudoku.auth.js +19712 -0
- package/lib/zudoku.components.js +6 -0
- package/lib/zudoku.openapi-worker.js +12 -0
- package/lib/zudoku.plugins.js +17382 -0
- package/package.json +6 -2
- package/src/cli/build/handler.ts +14 -0
- package/src/cli/cli.ts +77 -0
- package/src/cli/cmds/build.ts +24 -0
- package/src/cli/cmds/dev.ts +29 -0
- package/src/cli/common/analytics/lib.ts +89 -0
- package/src/cli/common/constants.ts +10 -0
- package/src/cli/common/logger.ts +5 -0
- package/src/cli/common/machine-id/lib.ts +85 -0
- package/src/cli/common/outdated.ts +102 -0
- package/src/cli/common/output.ts +86 -0
- package/src/cli/common/utils/box.license.txt +202 -0
- package/src/cli/common/utils/box.ts +116 -0
- package/src/cli/common/utils/ports.ts +21 -0
- package/src/cli/common/validators/lib.ts +43 -0
- package/src/cli/common/xdg/lib.ts +36 -0
- package/src/cli/dev/handler.ts +42 -0
- package/src/config/config.ts +56 -0
- package/src/index.ts +8 -0
- package/src/lib/DevPortal.tsx +93 -0
- package/src/lib/Heading.tsx +60 -0
- package/src/lib/Router.tsx +28 -0
- package/src/lib/auth.ts +1 -0
- package/src/lib/authentication/authentication.ts +18 -0
- package/src/lib/authentication/clerk.ts +45 -0
- package/src/lib/authentication/openid.ts +192 -0
- package/src/lib/components/AnchorLink.tsx +19 -0
- package/src/lib/components/CategoryHeading.tsx +16 -0
- package/src/lib/components/Dialog.tsx +119 -0
- package/src/lib/components/DynamicIcon.tsx +60 -0
- package/src/lib/components/Header.tsx +69 -0
- package/src/lib/components/Input.tsx +24 -0
- package/src/lib/components/Layout.tsx +56 -0
- package/src/lib/components/Markdown.tsx +37 -0
- package/src/lib/components/SyntaxHighlight.tsx +94 -0
- package/src/lib/components/TopNavigation.tsx +32 -0
- package/src/lib/components/context/ComponentsContext.tsx +24 -0
- package/src/lib/components/context/DevPortalProvider.ts +54 -0
- package/src/lib/components/context/PluginSystem.ts +0 -0
- package/src/lib/components/context/ThemeContext.tsx +46 -0
- package/src/lib/components/context/ViewportAnchorContext.tsx +139 -0
- package/src/lib/components/navigation/SideNavigation.tsx +18 -0
- package/src/lib/components/navigation/SideNavigationCategory.tsx +74 -0
- package/src/lib/components/navigation/SideNavigationItem.tsx +143 -0
- package/src/lib/components/navigation/SideNavigationWrapper.tsx +15 -0
- package/src/lib/components/navigation/useNavigationCollapsibleState.ts +27 -0
- package/src/lib/components/navigation/util.ts +38 -0
- package/src/lib/components.ts +3 -0
- package/src/lib/core/DevPortalContext.ts +164 -0
- package/src/lib/core/helmet.ts +5 -0
- package/src/lib/core/icons.tsx +1 -0
- package/src/lib/core/plugins.ts +43 -0
- package/src/lib/core/router.tsx +1 -0
- package/src/lib/core/types/combine.ts +16 -0
- package/src/lib/oas/graphql/index.ts +422 -0
- package/src/lib/oas/graphql/server.ts +10 -0
- package/src/lib/oas/parser/dereference/index.ts +59 -0
- package/src/lib/oas/parser/dereference/resolveRef.ts +32 -0
- package/src/lib/oas/parser/index.ts +94 -0
- package/src/lib/oas/parser/schemas/v3.0.json +1489 -0
- package/src/lib/oas/parser/schemas/v3.1.json +1298 -0
- package/src/lib/oas/parser/upgrade/index.ts +108 -0
- package/src/lib/plugins/api-key/SettingsApiKeys.tsx +22 -0
- package/src/lib/plugins/api-key/index.tsx +123 -0
- package/src/lib/plugins/markdown/MdxPage.tsx +128 -0
- package/src/lib/plugins/markdown/Toc.tsx +122 -0
- package/src/lib/plugins/markdown/generateRoutes.tsx +72 -0
- package/src/lib/plugins/markdown/index.tsx +31 -0
- package/src/lib/plugins/openapi/ColorizedParam.tsx +82 -0
- package/src/lib/plugins/openapi/MakeRequest.tsx +49 -0
- package/src/lib/plugins/openapi/MethodBadge.tsx +36 -0
- package/src/lib/plugins/openapi/OperationList.tsx +117 -0
- package/src/lib/plugins/openapi/OperationListItem.tsx +55 -0
- package/src/lib/plugins/openapi/ParameterList.tsx +32 -0
- package/src/lib/plugins/openapi/ParameterListItem.tsx +60 -0
- package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +51 -0
- package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +60 -0
- package/src/lib/plugins/openapi/Select.tsx +35 -0
- package/src/lib/plugins/openapi/Sidecar.tsx +160 -0
- package/src/lib/plugins/openapi/SidecarBox.tsx +36 -0
- package/src/lib/plugins/openapi/graphql/fragment-masking.ts +111 -0
- package/src/lib/plugins/openapi/graphql/gql.ts +70 -0
- package/src/lib/plugins/openapi/graphql/graphql.ts +795 -0
- package/src/lib/plugins/openapi/graphql/index.ts +2 -0
- package/src/lib/plugins/openapi/index.tsx +142 -0
- package/src/lib/plugins/openapi/playground/Playground.tsx +309 -0
- package/src/lib/plugins/openapi/queries.graphql +6 -0
- package/src/lib/plugins/openapi/util/generateSchemaExample.ts +59 -0
- package/src/lib/plugins/openapi/util/urql.ts +8 -0
- package/src/lib/plugins/openapi/worker/createSharedWorkerClient.ts +60 -0
- package/src/lib/plugins/openapi/worker/shared-worker.ts +5 -0
- package/src/lib/plugins/openapi/worker/worker.ts +30 -0
- package/src/lib/plugins/redirect/index.tsx +20 -0
- package/src/lib/plugins.ts +5 -0
- package/src/lib/ui/Button.tsx +56 -0
- package/src/lib/ui/Callout.tsx +87 -0
- package/src/lib/ui/Card.tsx +82 -0
- package/src/lib/ui/Note.tsx +58 -0
- package/src/lib/ui/Tabs.tsx +52 -0
- package/src/lib/util/MdxComponents.tsx +70 -0
- package/src/lib/util/cn.ts +6 -0
- package/src/lib/util/createVariantComponent.tsx +30 -0
- package/src/lib/util/createWaitForNotify.ts +18 -0
- package/src/lib/util/groupBy.ts +24 -0
- package/src/lib/util/joinPath.tsx +10 -0
- package/src/lib/util/pastellize.ts +25 -0
- package/src/lib/util/slugify.ts +3 -0
- package/src/lib/util/traverseNavigation.ts +55 -0
- package/src/lib/util/useScrollToAnchor.ts +38 -0
- package/src/lib/util/useScrollToTop.ts +13 -0
- package/src/ts.ts +94 -0
- package/src/types.d.ts +24 -0
- package/src/vite/build.ts +33 -0
- package/src/vite/config.test.ts +10 -0
- package/src/vite/config.ts +183 -0
- package/src/vite/dev-server.ts +64 -0
- package/src/vite/html.ts +37 -0
- package/src/vite/plugin-api.ts +57 -0
- package/src/vite/plugin-auth.ts +32 -0
- package/src/vite/plugin-component.ts +26 -0
- package/src/vite/plugin-config.ts +31 -0
- package/src/vite/plugin-docs.test.ts +32 -0
- package/src/vite/plugin-docs.ts +52 -0
- package/src/vite/plugin-html.ts +50 -0
- package/src/vite/plugin-mdx.ts +74 -0
- package/src/vite/plugin-metadata.ts +30 -0
- package/src/vite/plugin.ts +23 -0
package/src/ts.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Function to check if a TypeScript string is valid
|
|
6
|
+
* Used for tests
|
|
7
|
+
*/
|
|
8
|
+
export async function checkTypescriptString(code: string) {
|
|
9
|
+
const rootDir = process.cwd();
|
|
10
|
+
const inMemoryFileName = path.join(rootDir, "/src/temp.ts");
|
|
11
|
+
const configPath = ts.findConfigFile(
|
|
12
|
+
rootDir,
|
|
13
|
+
ts.sys.fileExists,
|
|
14
|
+
"tsconfig.json",
|
|
15
|
+
);
|
|
16
|
+
if (!configPath) {
|
|
17
|
+
throw new Error("Could not find a valid tsconfig.json");
|
|
18
|
+
}
|
|
19
|
+
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
20
|
+
const parsedCommandLine = ts.parseJsonConfigFileContent(
|
|
21
|
+
configFile.config,
|
|
22
|
+
ts.sys,
|
|
23
|
+
path.dirname(configPath),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
// Custom compiler host to handle in-memory file and delegate to default host for others
|
|
27
|
+
const compilerHost: ts.CompilerHost = {
|
|
28
|
+
...ts.createCompilerHost(parsedCommandLine.options),
|
|
29
|
+
getSourceFile: (
|
|
30
|
+
fileName,
|
|
31
|
+
languageVersion,
|
|
32
|
+
onError,
|
|
33
|
+
shouldCreateNewSourceFile,
|
|
34
|
+
) => {
|
|
35
|
+
if (fileName === inMemoryFileName) {
|
|
36
|
+
return ts.createSourceFile(fileName, code, languageVersion, true);
|
|
37
|
+
}
|
|
38
|
+
return ts
|
|
39
|
+
.createCompilerHost(parsedCommandLine.options)
|
|
40
|
+
.getSourceFile(
|
|
41
|
+
fileName,
|
|
42
|
+
languageVersion,
|
|
43
|
+
onError,
|
|
44
|
+
shouldCreateNewSourceFile,
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
fileExists: (fileName) => {
|
|
48
|
+
if (fileName === inMemoryFileName) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return ts.sys.fileExists(fileName);
|
|
52
|
+
},
|
|
53
|
+
readFile: (fileName) => {
|
|
54
|
+
if (fileName === inMemoryFileName) {
|
|
55
|
+
return code;
|
|
56
|
+
}
|
|
57
|
+
return ts.sys.readFile(fileName);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Create a source file in memory
|
|
62
|
+
const sourceFile = ts.createSourceFile("tempFile.ts", code, 99, true);
|
|
63
|
+
|
|
64
|
+
// Create a program using the in-memory source file
|
|
65
|
+
const program = ts.createProgram({
|
|
66
|
+
rootNames: parsedCommandLine.fileNames.concat(inMemoryFileName),
|
|
67
|
+
options: parsedCommandLine.options,
|
|
68
|
+
host: compilerHost,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Get all diagnostics for the program, which includes syntax and semantic errors
|
|
72
|
+
const diagnostics = ts.getPreEmitDiagnostics(program);
|
|
73
|
+
|
|
74
|
+
diagnostics.forEach((diagnostic) => {
|
|
75
|
+
if (diagnostic.file) {
|
|
76
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(
|
|
77
|
+
diagnostic.start!,
|
|
78
|
+
);
|
|
79
|
+
const message = ts.flattenDiagnosticMessageText(
|
|
80
|
+
diagnostic.messageText,
|
|
81
|
+
"\n",
|
|
82
|
+
);
|
|
83
|
+
console.log(
|
|
84
|
+
`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`,
|
|
85
|
+
);
|
|
86
|
+
} else {
|
|
87
|
+
console.log(
|
|
88
|
+
ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return diagnostics;
|
|
94
|
+
}
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare module "slugify" {
|
|
2
|
+
declare function slugify(
|
|
3
|
+
string: string,
|
|
4
|
+
options?:
|
|
5
|
+
| {
|
|
6
|
+
replacement?: string;
|
|
7
|
+
remove?: RegExp;
|
|
8
|
+
lower?: boolean;
|
|
9
|
+
strict?: boolean;
|
|
10
|
+
locale?: string;
|
|
11
|
+
trim?: boolean;
|
|
12
|
+
}
|
|
13
|
+
| string,
|
|
14
|
+
): string;
|
|
15
|
+
|
|
16
|
+
export default slugify;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module "virtual:zudoku-docs-plugins";
|
|
20
|
+
declare module "virtual:zudoku-api-plugins";
|
|
21
|
+
declare module "virtual:zudoku-config";
|
|
22
|
+
declare module "virtual:zudoku-auth";
|
|
23
|
+
declare module "virtual:zudoku-component";
|
|
24
|
+
declare module "zudoku/open-api-worker";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { writeFile } from "fs/promises";
|
|
2
|
+
import { build as viteBuild } from "vite";
|
|
3
|
+
import { getViteConfig } from "./config.js";
|
|
4
|
+
import { getBuildHtml } from "./html.js";
|
|
5
|
+
|
|
6
|
+
export async function runBuild(options: { dir: string }) {
|
|
7
|
+
const viteConfig = await getViteConfig({ dir: options.dir, mode: "build" });
|
|
8
|
+
|
|
9
|
+
const result = await viteBuild(viteConfig);
|
|
10
|
+
|
|
11
|
+
if (Array.isArray(result)) {
|
|
12
|
+
throw new Error("Build failed");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if ("output" in result) {
|
|
16
|
+
const jsEntry = result.output.find(
|
|
17
|
+
(o) => "isEntry" in o && o.isEntry,
|
|
18
|
+
)?.fileName;
|
|
19
|
+
const cssEntry = result.output.find((o) =>
|
|
20
|
+
o.fileName.endsWith(".css"),
|
|
21
|
+
)?.fileName;
|
|
22
|
+
|
|
23
|
+
const html = getBuildHtml({
|
|
24
|
+
jsEntry: `/${jsEntry}`,
|
|
25
|
+
cssEntry: `/${cssEntry}`,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
await writeFile(`${options.dir}/dist/index.html`, html, "utf-8");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw new Error("Build failed");
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import { loadConfig } from "./config.js";
|
|
5
|
+
|
|
6
|
+
test("Should correctly load zudoku.config.ts file", async (t) => {
|
|
7
|
+
const rootPath = path.resolve("../../samples/with-config/");
|
|
8
|
+
const config = await loadConfig(rootPath, "zudoku.config.ts");
|
|
9
|
+
assert.equal(config.default.ui.headerTitle, "My Portal");
|
|
10
|
+
});
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import autoprefixer from "autoprefixer";
|
|
2
|
+
import esbuild from "esbuild";
|
|
3
|
+
import { stat } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import tailwindcss from "tailwindcss";
|
|
6
|
+
import { InlineConfig, LogLevel } from "vite";
|
|
7
|
+
import tailwindConfig from "../app/tailwind.js";
|
|
8
|
+
import { logger } from "../cli/common/logger.js";
|
|
9
|
+
import { isPortAvailable } from "../cli/common/utils/ports.js";
|
|
10
|
+
import { ZudokuConfig } from "../config/config.js";
|
|
11
|
+
import viteComponentPlugin from "./plugin-component.js";
|
|
12
|
+
import vitePlugin from "./plugin.js";
|
|
13
|
+
|
|
14
|
+
const extensions = ["js", "jsx", "ts", "tsx", "mjs"];
|
|
15
|
+
|
|
16
|
+
export interface ZudokuViteConfig extends InlineConfig {
|
|
17
|
+
root: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const fileExists = (path: string) =>
|
|
21
|
+
stat(path)
|
|
22
|
+
.then(() => true)
|
|
23
|
+
.catch(() => false);
|
|
24
|
+
|
|
25
|
+
export async function loadZuploConfig(rootDir: string): Promise<ZudokuConfig> {
|
|
26
|
+
for (const ext of extensions) {
|
|
27
|
+
const fileName = `zudoku.config.${ext}`;
|
|
28
|
+
const configPath = path.join(rootDir, fileName);
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
if (await fileExists(configPath)) {
|
|
32
|
+
logger.info(`Loading zudoku.config file: ${configPath}`);
|
|
33
|
+
const config = await loadConfig(rootDir, fileName);
|
|
34
|
+
return config.default as ZudokuConfig;
|
|
35
|
+
}
|
|
36
|
+
} catch (e) {
|
|
37
|
+
logger.error(e);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Default config
|
|
42
|
+
logger.warn("No zudoku.config file found");
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getModuleDir() {
|
|
47
|
+
// NOTE: This is relative to the /dist folder because the dev server
|
|
48
|
+
// runs the compiled JS files, but vite uses the raw TS files
|
|
49
|
+
return new URL("../../", import.meta.url).pathname;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getAppMainTsxPath() {
|
|
53
|
+
const modDir = getModuleDir();
|
|
54
|
+
return path.join(modDir, "src", "app", "main.tsx");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function getViteConfig({
|
|
58
|
+
dir,
|
|
59
|
+
mode,
|
|
60
|
+
}: {
|
|
61
|
+
dir: string;
|
|
62
|
+
mode: "dev" | "build";
|
|
63
|
+
}): Promise<ZudokuViteConfig> {
|
|
64
|
+
const rootDir = path.resolve(process.cwd(), dir);
|
|
65
|
+
const moduleDir = getModuleDir();
|
|
66
|
+
const config = await loadZuploConfig(rootDir);
|
|
67
|
+
|
|
68
|
+
let websocketPort = 9800;
|
|
69
|
+
while (
|
|
70
|
+
!(await isPortAvailable("localhost", websocketPort)) &&
|
|
71
|
+
websocketPort < 9999
|
|
72
|
+
) {
|
|
73
|
+
websocketPort++;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const viteConfig: ZudokuViteConfig = {
|
|
77
|
+
root: rootDir,
|
|
78
|
+
appType: "custom",
|
|
79
|
+
configFile: false,
|
|
80
|
+
clearScreen: false,
|
|
81
|
+
logLevel: (process.env.LOG_LEVEL || "info") as LogLevel,
|
|
82
|
+
customLogger: logger,
|
|
83
|
+
envPrefix: "PUBLIC_",
|
|
84
|
+
worker: {
|
|
85
|
+
format: "es",
|
|
86
|
+
},
|
|
87
|
+
server: {
|
|
88
|
+
middlewareMode: true,
|
|
89
|
+
open: true,
|
|
90
|
+
hmr: {
|
|
91
|
+
port: websocketPort,
|
|
92
|
+
},
|
|
93
|
+
watch: {
|
|
94
|
+
ignored: [
|
|
95
|
+
`${rootDir}/dist`,
|
|
96
|
+
`${rootDir}/lib`,
|
|
97
|
+
`${rootDir}/.git`,
|
|
98
|
+
`${rootDir}/node_modules`,
|
|
99
|
+
`${rootDir}/zuplo.config.ts`,
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
// sourcemapIgnoreList: (sourcePath) => {
|
|
103
|
+
// return (
|
|
104
|
+
// sourcePath.includes("node_modules/openapi-types/") ||
|
|
105
|
+
// sourcePath.includes("node_modules/value-or-promise/")
|
|
106
|
+
// );
|
|
107
|
+
// },
|
|
108
|
+
},
|
|
109
|
+
build: {
|
|
110
|
+
outDir: path.resolve(rootDir, "dist"),
|
|
111
|
+
rollupOptions: {
|
|
112
|
+
// external: ["@mdx-js/react"],
|
|
113
|
+
input: mode === "build" ? "zudoku/app/main.tsx" : undefined,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
optimizeDeps: {
|
|
117
|
+
entries: [getAppMainTsxPath()],
|
|
118
|
+
exclude: ["zudoku/open-api-worker"],
|
|
119
|
+
include: [
|
|
120
|
+
"hast-util-to-jsx-runtime > style-to-object",
|
|
121
|
+
"debug",
|
|
122
|
+
"extend",
|
|
123
|
+
"stringify-object",
|
|
124
|
+
"url",
|
|
125
|
+
"@zudoku/httpsnippet > qs",
|
|
126
|
+
"react-fast-compare",
|
|
127
|
+
"invariant",
|
|
128
|
+
"shallowequal",
|
|
129
|
+
"slugify",
|
|
130
|
+
"zustand",
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
plugins: [vitePlugin({ ...config, rootDir }), viteComponentPlugin()],
|
|
134
|
+
css: {
|
|
135
|
+
postcss: {
|
|
136
|
+
plugins: [
|
|
137
|
+
tailwindcss({
|
|
138
|
+
...tailwindConfig,
|
|
139
|
+
content: [
|
|
140
|
+
`${moduleDir}/src/**/*.{js,ts,jsx,tsx,md,mdx}`,
|
|
141
|
+
// Tailwind seems to crash if it tries to parse compiled .js files
|
|
142
|
+
// as a workaround, we will just ship the source file and use those
|
|
143
|
+
// `${moduleDir}/lib/**/*.{js,ts,jsx,tsx,md,mdx}`,
|
|
144
|
+
`${rootDir}/src/**/*.{js,ts,jsx,tsx,md,mdx}`,
|
|
145
|
+
],
|
|
146
|
+
}),
|
|
147
|
+
autoprefixer,
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
return viteConfig;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function loadConfig(rootPath: string, fileName: string) {
|
|
157
|
+
const compiledFilepath = path.join(
|
|
158
|
+
rootPath,
|
|
159
|
+
"node_modules",
|
|
160
|
+
".zudoku",
|
|
161
|
+
"zudoku.config.mjs",
|
|
162
|
+
);
|
|
163
|
+
const filepath = path.join(rootPath, fileName);
|
|
164
|
+
try {
|
|
165
|
+
await esbuild.build({
|
|
166
|
+
entryPoints: [filepath],
|
|
167
|
+
bundle: true,
|
|
168
|
+
keepNames: true,
|
|
169
|
+
treeShaking: true,
|
|
170
|
+
minifyIdentifiers: false,
|
|
171
|
+
minifySyntax: false,
|
|
172
|
+
minifyWhitespace: false,
|
|
173
|
+
platform: "node",
|
|
174
|
+
target: "es2022",
|
|
175
|
+
format: "esm",
|
|
176
|
+
outfile: compiledFilepath,
|
|
177
|
+
});
|
|
178
|
+
} catch (error) {
|
|
179
|
+
error.message = `TypeScript Error in ${filepath}:\n${error.message}`;
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
return await import(compiledFilepath);
|
|
183
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { Server } from "node:http";
|
|
3
|
+
import { createServer as createViteServer } from "vite";
|
|
4
|
+
|
|
5
|
+
import { createGraphQLServer } from "../lib/oas/graphql/index.js";
|
|
6
|
+
import { getAppMainTsxPath, getViteConfig } from "./config.js";
|
|
7
|
+
import { getDevHtml } from "./html.js";
|
|
8
|
+
|
|
9
|
+
export class DevServer {
|
|
10
|
+
private server: Server | undefined;
|
|
11
|
+
|
|
12
|
+
constructor(private options: { port: number; dir: string }) {}
|
|
13
|
+
|
|
14
|
+
async start() {
|
|
15
|
+
const app = express();
|
|
16
|
+
|
|
17
|
+
const viteConfig = await getViteConfig({
|
|
18
|
+
dir: this.options.dir,
|
|
19
|
+
mode: "dev",
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const vite = await createViteServer(viteConfig);
|
|
23
|
+
|
|
24
|
+
const graphql = createGraphQLServer({
|
|
25
|
+
graphqlEndpoint: "/__z/graphql",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
app.use(graphql.graphqlEndpoint, graphql);
|
|
29
|
+
app.use(vite.middlewares);
|
|
30
|
+
|
|
31
|
+
app.use("*", async (req, res) => {
|
|
32
|
+
try {
|
|
33
|
+
const entryJs = getAppMainTsxPath();
|
|
34
|
+
const rawHtml = getDevHtml(entryJs);
|
|
35
|
+
const indexHtml = await vite.transformIndexHtml(req.url, rawHtml);
|
|
36
|
+
|
|
37
|
+
// Send the transformed index.html back to the client
|
|
38
|
+
res.status(200).set({ "Content-Type": "text/html" }).end(indexHtml);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
vite.ssrFixStacktrace(e);
|
|
41
|
+
console.error(e);
|
|
42
|
+
res.status(500).end(e.message);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return new Promise<void>((resolve) => {
|
|
47
|
+
this.server = app.listen(this.options.port, resolve);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async stop() {
|
|
52
|
+
if (this.server) {
|
|
53
|
+
return new Promise<void>((resolve, reject) => {
|
|
54
|
+
this.server!.close((err) => {
|
|
55
|
+
if (err) {
|
|
56
|
+
reject(err);
|
|
57
|
+
} else {
|
|
58
|
+
resolve();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/vite/html.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function getDevHtml(jsEntry: string) {
|
|
2
|
+
return `<!doctype html>
|
|
3
|
+
<html lang="en" class="dark">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="${jsEntry}"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
13
|
+
`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getBuildHtml({
|
|
17
|
+
jsEntry,
|
|
18
|
+
cssEntry,
|
|
19
|
+
}: {
|
|
20
|
+
jsEntry: string;
|
|
21
|
+
cssEntry: string;
|
|
22
|
+
}) {
|
|
23
|
+
return `<!doctype html>
|
|
24
|
+
<html lang="en">
|
|
25
|
+
<head>
|
|
26
|
+
<meta charset="UTF-8" />
|
|
27
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
28
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
29
|
+
<title>Vite + React + TS</title>
|
|
30
|
+
<script type="module" crossorigin src="${jsEntry}"></script>
|
|
31
|
+
<link rel="stylesheet" crossorigin href="${cssEntry}">
|
|
32
|
+
</head>
|
|
33
|
+
<body>
|
|
34
|
+
<div id="root"></div>
|
|
35
|
+
</body>
|
|
36
|
+
</html>`;
|
|
37
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
import { ZudokuPluginOptions } from "../config/config.js";
|
|
3
|
+
import { getConfigExportCode } from "./plugin-config.js";
|
|
4
|
+
|
|
5
|
+
const viteApiPlugin = (config: ZudokuPluginOptions): Plugin => {
|
|
6
|
+
const virtualModuleId = "virtual:zudoku-api-plugins";
|
|
7
|
+
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
name: "vite-zudoku-api-plugins",
|
|
11
|
+
resolveId(id) {
|
|
12
|
+
if (id === virtualModuleId) {
|
|
13
|
+
return resolvedVirtualModuleId;
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
load(id) {
|
|
17
|
+
if (id === resolvedVirtualModuleId) {
|
|
18
|
+
const code: string[] = [
|
|
19
|
+
// IMPORTANT! This path here is important, we MUST resolve
|
|
20
|
+
// files here as Typescript from the appDir
|
|
21
|
+
getConfigExportCode(config.rootDir),
|
|
22
|
+
`import { openApiPlugin } from "zudoku/plugins";`,
|
|
23
|
+
`const configuredApiPlugins = [];`,
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
if (config?.apis) {
|
|
27
|
+
if (Array.isArray(config.apis)) {
|
|
28
|
+
config.apis.forEach((c, i) => {
|
|
29
|
+
code.push(
|
|
30
|
+
...[
|
|
31
|
+
`// @ts-ignore`, // To make tests pass
|
|
32
|
+
`configuredApiPlugins.push(openApiPlugin(config.apis?[${i}]));`,
|
|
33
|
+
],
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
} else {
|
|
37
|
+
code.push(
|
|
38
|
+
...[
|
|
39
|
+
`// @ts-ignore`, // To make tests pass
|
|
40
|
+
`configuredApiPlugins.push(openApiPlugin(config.apis));`,
|
|
41
|
+
],
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
code.push(`export { configuredApiPlugins };`);
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
code: code.join("\n"),
|
|
50
|
+
map: null,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default viteApiPlugin;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PluginOption } from "vite";
|
|
2
|
+
import { ZudokuPluginOptions } from "../config/config.js";
|
|
3
|
+
import { getConfigExportCode } from "./plugin-config.js";
|
|
4
|
+
|
|
5
|
+
const viteAuthPlugin = (config: ZudokuPluginOptions): PluginOption => {
|
|
6
|
+
const virtualModuleId = "virtual:zudoku-auth";
|
|
7
|
+
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
name: "zudoku-auth-plugin", // required, will show up in warnings and errors
|
|
11
|
+
resolveId(id) {
|
|
12
|
+
if (id === virtualModuleId) {
|
|
13
|
+
return resolvedVirtualModuleId;
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
load(id) {
|
|
17
|
+
if (id === resolvedVirtualModuleId) {
|
|
18
|
+
if (!config.authentication) {
|
|
19
|
+
return `export const configuredAuthProvider = undefined;`;
|
|
20
|
+
}
|
|
21
|
+
// TODO: Validate that the authConfig.type is a valid authentication provider
|
|
22
|
+
return [
|
|
23
|
+
getConfigExportCode(config.rootDir),
|
|
24
|
+
`import { clerkAuth } from "zudoku/auth";`,
|
|
25
|
+
`export const configuredAuthProvider = clerkAuth(config.authentication);`,
|
|
26
|
+
].join("\n");
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default viteAuthPlugin;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PluginOption } from "vite";
|
|
2
|
+
|
|
3
|
+
const viteComponentPlugin = (): PluginOption => {
|
|
4
|
+
const virtualModuleId = "virtual:zudoku-component";
|
|
5
|
+
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
name: "zudoku-component-plugin",
|
|
9
|
+
resolveId(id) {
|
|
10
|
+
if (id === virtualModuleId) {
|
|
11
|
+
return resolvedVirtualModuleId;
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
load(id) {
|
|
15
|
+
if (id === resolvedVirtualModuleId) {
|
|
16
|
+
const code: string[] = [
|
|
17
|
+
`export { DevPortal } from "zudoku/components";`,
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
return code.join("\n");
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default viteComponentPlugin;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { PluginOption } from "vite";
|
|
3
|
+
|
|
4
|
+
export function getConfigExportCode(rootDir: string) {
|
|
5
|
+
const configPath = path.join(
|
|
6
|
+
rootDir,
|
|
7
|
+
`/node_modules/.zudoku/zudoku.config.mjs`,
|
|
8
|
+
);
|
|
9
|
+
return `import config from "${configPath}"; export default config;`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const viteConfigPlugin = ({ rootDir }: { rootDir: string }): PluginOption => {
|
|
13
|
+
const virtualModuleId = "virtual:zudoku-config";
|
|
14
|
+
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
name: "zudoku-config-plugin",
|
|
18
|
+
resolveId(id) {
|
|
19
|
+
if (id === virtualModuleId) {
|
|
20
|
+
return resolvedVirtualModuleId;
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
load(id) {
|
|
24
|
+
if (id === resolvedVirtualModuleId) {
|
|
25
|
+
return getConfigExportCode(rootDir);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default viteConfigPlugin;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import { checkTypescriptString } from "../ts.js";
|
|
5
|
+
import viteDocsPlugin from "./plugin-docs.js";
|
|
6
|
+
|
|
7
|
+
test.only("Builds code", async (t) => {
|
|
8
|
+
const plugin = viteDocsPlugin({
|
|
9
|
+
docs: { files: "docs/**/*.md" },
|
|
10
|
+
} as any);
|
|
11
|
+
if (!plugin.load) {
|
|
12
|
+
throw new Error("Plugin does not have a load function");
|
|
13
|
+
}
|
|
14
|
+
if (typeof plugin.load !== "function") {
|
|
15
|
+
throw new Error("Plugin.load is not a function");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const result = await plugin.load.call(
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
{} as any,
|
|
21
|
+
"\0virtual:markdown-plugins",
|
|
22
|
+
);
|
|
23
|
+
if (result && typeof result === "object" && "code" in result) {
|
|
24
|
+
const diagnostics = await checkTypescriptString(result.code);
|
|
25
|
+
if (diagnostics.length > 0) {
|
|
26
|
+
console.error(diagnostics);
|
|
27
|
+
}
|
|
28
|
+
assert.equal(diagnostics.length, 0);
|
|
29
|
+
} else {
|
|
30
|
+
assert.fail("Invalid return value from plugin.load");
|
|
31
|
+
}
|
|
32
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
import { DocsConfig, ZudokuPluginOptions } from "../config/config.js";
|
|
3
|
+
|
|
4
|
+
const viteDocsPlugin = (config: ZudokuPluginOptions): Plugin => {
|
|
5
|
+
const virtualModuleId = "virtual:zudoku-docs-plugins";
|
|
6
|
+
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
name: "vite-zudoku-docs-plugin",
|
|
10
|
+
resolveId(id) {
|
|
11
|
+
if (id === virtualModuleId) {
|
|
12
|
+
return resolvedVirtualModuleId;
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
load(id) {
|
|
16
|
+
if (id === resolvedVirtualModuleId) {
|
|
17
|
+
const code: string[] = [
|
|
18
|
+
// IMPORTANT! This path here is important, we MUST resolve
|
|
19
|
+
// files here as Typescript from the appDir
|
|
20
|
+
`import { markdownPlugin } from "zudoku/plugins";`,
|
|
21
|
+
`const configuredDocsPlugins = [];`,
|
|
22
|
+
];
|
|
23
|
+
const docsConfigs: DocsConfig[] = config?.docs
|
|
24
|
+
? Array.isArray(config.docs)
|
|
25
|
+
? config.docs
|
|
26
|
+
: [config.docs]
|
|
27
|
+
: [];
|
|
28
|
+
|
|
29
|
+
docsConfigs.forEach((docsConfig) => {
|
|
30
|
+
code.push(
|
|
31
|
+
...[
|
|
32
|
+
`// @ts-ignore`, // To make tests pass
|
|
33
|
+
`const markdownFiles = import.meta.glob(${JSON.stringify(docsConfig.files)}, {`,
|
|
34
|
+
` eager: false,`,
|
|
35
|
+
`});`,
|
|
36
|
+
`configuredDocsPlugins.push(markdownPlugin({ markdownFiles }));`,
|
|
37
|
+
],
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
code.push(`export { configuredDocsPlugins };`);
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
code: code.join("\n"),
|
|
45
|
+
map: null,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default viteDocsPlugin;
|