Skip to content

Commit fd658dd

Browse files
authored
Merge pull request #1095 from samchon/feat/editor-module
`NestiaEditorModule` for NestJS backend server's editor.
2 parents 807474a + fd1a189 commit fd658dd

File tree

9 files changed

+272
-20
lines changed

9 files changed

+272
-20
lines changed

packages/editor/package.json

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
22
"name": "@nestia/editor",
3-
"version": "0.6.2",
3+
"version": "0.7.1",
44
"typings": "lib/index.d.ts",
55
"main": "lib/index.js",
66
"module": "lib/index.mjs",
77
"scripts": {
8-
"build:lib": "tsc --project tsconfig.lib.json && rollup -c",
9-
"build:static": "tsc -b && vite build",
8+
"build": "npm run build:static && npm run build:lib",
9+
"build:static": "rimraf dist && tsc -b && vite build",
10+
"build:lib": "rimraf lib && tsc --project tsconfig.lib.json && rollup -c",
1011
"dev": "vite",
1112
"lint": "eslint .",
1213
"preview": "vite preview"
@@ -42,9 +43,14 @@
4243
},
4344
"devDependencies": {
4445
"@eslint/js": "^9.13.0",
46+
"@nestjs/common": "^10.4.6",
47+
"@nestjs/core": "^10.4.6",
48+
"@nestjs/platform-express": "^10.4.6",
49+
"@nestjs/platform-fastify": "^10.4.6",
4550
"@rollup/plugin-terser": "^0.4.4",
4651
"@rollup/plugin-typescript": "^12.1.1",
4752
"@types/js-yaml": "^4.0.9",
53+
"@types/node": "^22.8.6",
4854
"@types/react": "^18.3.11",
4955
"@types/react-dom": "^18.3.1",
5056
"@vitejs/plugin-react": "^4.3.3",
@@ -55,6 +61,7 @@
5561
"react": "^18.3.1",
5662
"react-dom": "^18.3.1",
5763
"rollup": "^4.24.2",
64+
"ts-node": "^10.9.2",
5865
"typescript": "^5.6.2",
5966
"typescript-eslint": "^8.10.0",
6067
"vite": "^5.4.9"
@@ -63,6 +70,7 @@
6370
"README.md",
6471
"LICENSE",
6572
"package.json",
73+
"dist",
6674
"lib",
6775
"src"
6876
]
+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import type { OpenApiV3, OpenApiV3_1, SwaggerV2 } from "@samchon/openapi";
2+
import * as fs from "fs";
3+
4+
export namespace NestiaEditorModule {
5+
export const setup = async (props: {
6+
path: string;
7+
application: INestApplication;
8+
swagger:
9+
| string
10+
| SwaggerV2.IDocument
11+
| OpenApiV3.IDocument
12+
| OpenApiV3_1.IDocument;
13+
package?: string;
14+
simulate?: boolean;
15+
e2e?: boolean;
16+
}): Promise<void> => {
17+
const prefix: string =
18+
"/" +
19+
[getGlobalPrefix(props.application), props.path]
20+
.join("/")
21+
.split("/")
22+
.filter((str) => str.length !== 0)
23+
.join("/");
24+
const adaptor: INestHttpAdaptor = props.application.getHttpAdapter();
25+
const staticFiles: IStaticFile[] = [
26+
{
27+
path: "/index.html",
28+
type: "text/html",
29+
content: await getIndex(props),
30+
},
31+
{
32+
path: "/swagger.json",
33+
type: "application/json",
34+
content: JSON.stringify(
35+
typeof props.swagger === "string"
36+
? await getSwagger(props.swagger)
37+
: props.swagger,
38+
null,
39+
2,
40+
),
41+
},
42+
await getJavaScript(),
43+
];
44+
for (const f of staticFiles) {
45+
adaptor.get(prefix + f.path, (_: any, res: any) => {
46+
res.type(f.type);
47+
return res.send(f.content);
48+
});
49+
}
50+
for (const p of ["", "/"])
51+
adaptor.get(prefix + p, (_: any, res: any) => {
52+
return res.redirect(prefix + "/index.html");
53+
});
54+
};
55+
56+
const getGlobalPrefix = (app: INestApplication): string =>
57+
typeof (app as any).config?.globalPrefix === "string"
58+
? (app as any).config.globalPrefix
59+
: "";
60+
}
61+
62+
interface INestApplication {
63+
use(...args: any[]): this;
64+
getUrl(): Promise<string>;
65+
getHttpAdapter(): INestHttpAdaptor;
66+
setGlobalPrefix(prefix: string, options?: any): this;
67+
}
68+
interface INestHttpAdaptor {
69+
getType(): string;
70+
close(): any;
71+
init?(): Promise<void>;
72+
get: Function;
73+
post: Function;
74+
put: Function;
75+
patch: Function;
76+
delete: Function;
77+
head: Function;
78+
all: Function;
79+
}
80+
interface IStaticFile {
81+
path: string;
82+
type: string;
83+
content: string;
84+
}
85+
86+
const getIndex = async (props: {
87+
package?: string;
88+
simulate?: boolean;
89+
e2e?: boolean;
90+
}): Promise<string> => {
91+
const content: string = await fs.promises.readFile(
92+
`${__dirname}/../dist/index.html`,
93+
"utf8",
94+
);
95+
return content
96+
.replace(
97+
`"@ORGANIZATION/PROJECT"`,
98+
JSON.stringify(props.package ?? "@ORGANIZATION/PROJECT"),
99+
)
100+
.replace("window.simulate = false", `window.simulate = ${!!props.simulate}`)
101+
.replace("window.e2e = false", `window.e2e = ${!!props.e2e}`);
102+
};
103+
104+
const getJavaScript = async (): Promise<IStaticFile> => {
105+
const directory: string[] = await fs.promises.readdir(
106+
`${__dirname}/../dist/assets`,
107+
);
108+
const path: string | undefined = directory[0];
109+
if (path === undefined)
110+
throw new Error("Unreachable code, no JS file exists.");
111+
return {
112+
path: `/assets/${path}`,
113+
type: "application/javascript",
114+
content: await fs.promises.readFile(
115+
`${__dirname}/../dist/assets/${path}`,
116+
"utf8",
117+
),
118+
};
119+
};
120+
121+
const getSwagger = async (
122+
url: string,
123+
): Promise<
124+
SwaggerV2.IDocument | OpenApiV3.IDocument | OpenApiV3_1.IDocument
125+
> => {
126+
const response: Response = await fetch(url);
127+
if (response.status !== 200)
128+
throw new Error(`Failed to fetch Swagger document from ${url}`);
129+
return response.json();
130+
};

packages/editor/test/express.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Module } from "@nestjs/common";
2+
import { NestFactory } from "@nestjs/core";
3+
4+
import { NestiaEditorModule } from "../src/NestiaEditorModule";
5+
6+
@Module({})
7+
class MyModule {}
8+
9+
const main = async (): Promise<void> => {
10+
const app = await NestFactory.create(MyModule, { logger: false });
11+
await NestiaEditorModule.setup({
12+
path: "editor",
13+
application: app,
14+
swagger:
15+
"https://raw.githubusercontent.com/samchon/openapi/refs/heads/master/examples/v3.1/shopping.json",
16+
});
17+
await app.listen(3_001);
18+
};
19+
main().catch((exp) => {
20+
console.error(exp);
21+
process.exit(-1);
22+
});

packages/editor/test/fastify.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Module } from "@nestjs/common";
2+
import { NestFactory } from "@nestjs/core";
3+
import { FastifyAdapter } from "@nestjs/platform-fastify";
4+
5+
import { NestiaEditorModule } from "../src/NestiaEditorModule";
6+
7+
@Module({})
8+
class MyModule {}
9+
10+
const main = async (): Promise<void> => {
11+
const app = await NestFactory.create(MyModule, new FastifyAdapter(), {
12+
logger: false,
13+
});
14+
await NestiaEditorModule.setup({
15+
path: "editor",
16+
application: app,
17+
swagger:
18+
"https://raw.githubusercontent.com/samchon/openapi/refs/heads/master/examples/v3.1/shopping.json",
19+
});
20+
await app.listen(3_001);
21+
};
22+
main().catch((exp) => {
23+
console.error(exp);
24+
process.exit(-1);
25+
});
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"root":["./src/nestiaeditorapplication.tsx","./src/nestiaeditoriframe.tsx","./src/nestiaeditoruploader.tsx","./src/index.ts","./src/main.tsx","./src/vite-env.d.ts","./src/internal/nestiaeditorcomposer.ts","./src/internal/nestiaeditorfileuploader.tsx"],"errors":true,"version":"5.6.3"}
1+
{"root":["./src/nestiaeditorapplication.tsx","./src/nestiaeditoriframe.tsx","./src/nestiaeditormodule.ts","./src/nestiaeditoruploader.tsx","./src/index.ts","./src/main.tsx","./src/vite-env.d.ts","./src/internal/nestiaeditorcomposer.ts","./src/internal/nestiaeditorfileuploader.tsx"],"version":"5.6.3"}

packages/editor/tsconfig.test.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "./tsconfig.lib.json",
3+
"compilerOptions": {
4+
"target": "ES2015",
5+
"module": "CommonJS",
6+
"outDir": "bin",
7+
"noEmit": true,
8+
},
9+
"include": ["src", "test"]
10+
}

website/package-lock.json

+21-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

website/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"@mui/icons-material": "5.15.6",
2424
"@mui/material": "5.15.6",
2525
"@mui/system": "5.15.6",
26-
"@nestia/editor": "^0.6.2",
26+
"@nestia/editor": "^0.7.1",
2727
"next": "14.2.13",
2828
"nextra": "^2.13.4",
2929
"nextra-theme-docs": "^2.13.4",

0 commit comments

Comments
 (0)