@elysiajs/openapi 1.3.6 → 1.3.8

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.
@@ -29,31 +29,34 @@ var import_os = require("os");
29
29
  var import_path = require("path");
30
30
  var import_child_process = require("child_process");
31
31
  var matchRoute = /: Elysia<(.*)>/gs;
32
- var matchStatus = /(\d{3}):/gs;
32
+ var matchStatus = /(\d{3}):/g;
33
33
  var wrapStatusInQuote = (value) => value.replace(matchStatus, '"$1":');
34
- var exec = (command, cwd) => (0, import_child_process.spawnSync)(command, {
35
- shell: true,
36
- cwd,
37
- stdio: "inherit"
38
- });
39
34
  var fromTypes = (targetFilePath, {
40
35
  tsconfigPath = "tsconfig.json",
41
36
  instanceName,
42
37
  projectRoot = process.cwd(),
43
- overrideOutputPath
38
+ overrideOutputPath,
39
+ debug = false
44
40
  } = {}) => () => {
45
- if (!targetFilePath.endsWith(".ts") && !targetFilePath.endsWith(".tsx"))
46
- throw new Error("Only .ts files are supported");
47
41
  const tmpRoot = (0, import_path.join)((0, import_os.tmpdir)(), ".ElysiaAutoOpenAPI");
48
- if ((0, import_fs.existsSync)(tmpRoot))
49
- (0, import_fs.rmSync)(tmpRoot, { recursive: true, force: true });
50
- (0, import_fs.mkdirSync)(tmpRoot, { recursive: true });
51
- const extendsRef = (0, import_fs.existsSync)((0, import_path.join)(projectRoot, "tsconfig.json")) ? `"extends": "${(0, import_path.join)(projectRoot, "tsconfig.json")}",` : "";
52
- if (!(0, import_path.join)(projectRoot, targetFilePath))
53
- throw new Error("Target file does not exist");
54
- (0, import_fs.writeFileSync)(
55
- (0, import_path.join)(tmpRoot, tsconfigPath),
56
- `{
42
+ try {
43
+ if (!targetFilePath.endsWith(".ts") && !targetFilePath.endsWith(".tsx"))
44
+ throw new Error("Only .ts files are supported");
45
+ if (targetFilePath.startsWith("./"))
46
+ targetFilePath = targetFilePath.slice(2);
47
+ const src = targetFilePath.startsWith("/") ? targetFilePath : (0, import_path.join)(projectRoot, targetFilePath);
48
+ if (!(0, import_fs.existsSync)(src))
49
+ throw new Error(
50
+ `Couldn't find "${targetFilePath}" from ${projectRoot}`
51
+ );
52
+ if ((0, import_fs.existsSync)(tmpRoot))
53
+ (0, import_fs.rmSync)(tmpRoot, { recursive: true, force: true });
54
+ (0, import_fs.mkdirSync)(tmpRoot, { recursive: true });
55
+ const tsconfig = tsconfigPath.startsWith("/") ? tsconfigPath : (0, import_path.join)(projectRoot, tsconfigPath);
56
+ const extendsRef = (0, import_fs.existsSync)(tsconfig) ? `"extends": "${(0, import_path.join)(projectRoot, "tsconfig.json")}",` : "";
57
+ (0, import_fs.writeFileSync)(
58
+ (0, import_path.join)(tmpRoot, "tsconfig.json"),
59
+ `{
57
60
  ${extendsRef}
58
61
  "compilerOptions": {
59
62
  "lib": ["ESNext"],
@@ -66,20 +69,34 @@ var fromTypes = (targetFilePath, {
66
69
  "skipDefaultLibCheck": true,
67
70
  "outDir": "./dist"
68
71
  },
69
- "include": ["${(0, import_path.join)(projectRoot, targetFilePath)}"]
72
+ "include": ["${src}"]
70
73
  }`
71
- );
72
- exec(`tsc`, tmpRoot);
73
- try {
74
+ );
75
+ (0, import_child_process.spawnSync)(`tsc`, {
76
+ shell: true,
77
+ cwd: tmpRoot,
78
+ stdio: debug ? "inherit" : void 0
79
+ });
74
80
  const fileName = targetFilePath.replace(/.tsx$/, ".ts").replace(/.ts$/, ".d.ts");
75
- let targetFile = overrideOutputPath?.(tmpRoot) ?? (0, import_path.join)(tmpRoot, "dist", fileName);
76
- {
77
- const _targetFile = (0, import_path.join)(
78
- tmpRoot,
79
- "dist",
80
- fileName.slice(fileName.indexOf("/") + 1)
81
+ const targetFile = (overrideOutputPath ? typeof overrideOutputPath === "string" ? overrideOutputPath.startsWith("/") ? overrideOutputPath : (0, import_path.join)(tmpRoot, "dist", overrideOutputPath) : overrideOutputPath(tmpRoot) : void 0) ?? (0, import_path.join)(tmpRoot, "dist", fileName);
82
+ if (!(0, import_fs.existsSync)(targetFile)) {
83
+ (0, import_fs.rmSync)((0, import_path.join)(tmpRoot, "tsconfig.json"));
84
+ console.warn(
85
+ "[@elysiajs/openapi/gen] Failed to generate OpenAPI schema"
81
86
  );
82
- if ((0, import_fs.existsSync)(_targetFile)) targetFile = _targetFile;
87
+ console.warn("Couldn't find generated declaration file");
88
+ if ((0, import_fs.existsSync)((0, import_path.join)(tmpRoot, "dist"))) {
89
+ const tempFiles = (0, import_fs.readdirSync)((0, import_path.join)(tmpRoot, "dist"), {
90
+ recursive: true
91
+ }).filter((x) => x.toString().endsWith(".d.ts")).map((x) => `- ${x}`).join("\n");
92
+ if (tempFiles) {
93
+ console.warn(
94
+ "You can override with `overrideOutputPath` with one of the following:"
95
+ );
96
+ console.warn(tempFiles);
97
+ }
98
+ }
99
+ return;
83
100
  }
84
101
  const declaration = (0, import_fs.readFileSync)(targetFile, "utf8");
85
102
  if ((0, import_fs.existsSync)(tmpRoot))
@@ -89,18 +106,22 @@ var fromTypes = (targetFilePath, {
89
106
  )?.[0];
90
107
  if (!instance) return;
91
108
  for (let i = 0; i < 3; i++)
92
- instance = instance.slice(instance.indexOf("}, {", 3));
93
- const routesString = wrapStatusInQuote(instance).slice(
94
- 3,
95
- instance.indexOf("}, {", 3)
96
- ) + "}\n}\n";
109
+ instance = instance.slice(
110
+ instance.indexOf(
111
+ "}, {",
112
+ // remove just `}, `, leaving `{`
113
+ 3
114
+ )
115
+ );
116
+ const routesString = wrapStatusInQuote(
117
+ // Intentionally not adding "}"
118
+ // to avoid mismatched bracket in loop below
119
+ instance.slice(3, instance.indexOf("}, {", 4))
120
+ );
97
121
  const routes = {};
98
122
  for (const route of routesString.slice(1).split("} & {")) {
99
- let schema = (0, import_typemap.TypeBox)(`{${route}}}`);
100
- if (schema.type !== "object") {
101
- schema = (0, import_typemap.TypeBox)(`{${route}}`);
102
- if (schema.type !== "object") continue;
103
- }
123
+ let schema = (0, import_typemap.TypeBox)(`{${route}}`);
124
+ if (schema.type !== "object") continue;
104
125
  const paths = [];
105
126
  while (true) {
106
127
  const keys = Object.keys(schema.properties);
@@ -128,6 +149,9 @@ var fromTypes = (targetFilePath, {
128
149
  );
129
150
  console.warn(error);
130
151
  return;
152
+ } finally {
153
+ if (!debug && (0, import_fs.existsSync)(tmpRoot))
154
+ (0, import_fs.rmSync)(tmpRoot, { recursive: true, force: true });
131
155
  }
132
156
  };
133
157
  // Annotate the CommonJS export names for ESM import in node:
package/dist/cjs/index.js CHANGED
@@ -347,6 +347,7 @@ function toOpenAPISchema(app, exclude, references) {
347
347
  const hooks = route.hooks ?? {};
348
348
  if (references)
349
349
  for (const reference of references) {
350
+ if (!reference) continue;
350
351
  const refer = reference[route.path]?.[method] ?? reference[getLoosePath(route.path)]?.[method];
351
352
  if (!refer) continue;
352
353
  if (!hooks.body && isValidSchema(refer.body))
@@ -89,6 +89,7 @@ function toOpenAPISchema(app, exclude, references) {
89
89
  const hooks = route.hooks ?? {};
90
90
  if (references)
91
91
  for (const reference of references) {
92
+ if (!reference) continue;
92
93
  const refer = reference[route.path]?.[method] ?? reference[getLoosePath(route.path)]?.[method];
93
94
  if (!refer) continue;
94
95
  if (!hooks.body && isValidSchema(refer.body))
@@ -24,7 +24,13 @@ interface OpenAPIGeneratorOptions {
24
24
  * Under any circumstance, that Elysia failed to find a correct schema,
25
25
  * Put your own schema in this path
26
26
  */
27
- overrideOutputPath?(tempDir: string): string;
27
+ overrideOutputPath?: string | ((tempDir: string) => string);
28
+ /**
29
+ * don't remove temporary files
30
+ * for debugging purpose
31
+ * @default false
32
+ */
33
+ debug?: boolean;
28
34
  }
29
35
  /**
30
36
  * Auto generate OpenAPI schema from Elysia instance
@@ -39,5 +45,5 @@ export declare const fromTypes: (
39
45
  *
40
46
  * The path must export an Elysia instance
41
47
  */
42
- targetFilePath: string, { tsconfigPath, instanceName, projectRoot, overrideOutputPath }?: OpenAPIGeneratorOptions) => () => AdditionalReference | undefined;
48
+ targetFilePath: string, { tsconfigPath, instanceName, projectRoot, overrideOutputPath, debug }?: OpenAPIGeneratorOptions) => () => AdditionalReference | undefined;
43
49
  export {};
@@ -4,38 +4,42 @@ import {
4
4
  mkdirSync,
5
5
  writeFileSync,
6
6
  rmSync,
7
- existsSync
7
+ existsSync,
8
+ readdirSync
8
9
  } from "fs";
9
10
  import { TypeBox } from "@sinclair/typemap";
10
11
  import { tmpdir } from "os";
11
12
  import { join } from "path";
12
13
  import { spawnSync } from "child_process";
13
14
  var matchRoute = /: Elysia<(.*)>/gs;
14
- var matchStatus = /(\d{3}):/gs;
15
+ var matchStatus = /(\d{3}):/g;
15
16
  var wrapStatusInQuote = (value) => value.replace(matchStatus, '"$1":');
16
- var exec = (command, cwd) => spawnSync(command, {
17
- shell: true,
18
- cwd,
19
- stdio: "inherit"
20
- });
21
17
  var fromTypes = (targetFilePath, {
22
18
  tsconfigPath = "tsconfig.json",
23
19
  instanceName,
24
20
  projectRoot = process.cwd(),
25
- overrideOutputPath
21
+ overrideOutputPath,
22
+ debug = false
26
23
  } = {}) => () => {
27
- if (!targetFilePath.endsWith(".ts") && !targetFilePath.endsWith(".tsx"))
28
- throw new Error("Only .ts files are supported");
29
24
  const tmpRoot = join(tmpdir(), ".ElysiaAutoOpenAPI");
30
- if (existsSync(tmpRoot))
31
- rmSync(tmpRoot, { recursive: true, force: true });
32
- mkdirSync(tmpRoot, { recursive: true });
33
- const extendsRef = existsSync(join(projectRoot, "tsconfig.json")) ? `"extends": "${join(projectRoot, "tsconfig.json")}",` : "";
34
- if (!join(projectRoot, targetFilePath))
35
- throw new Error("Target file does not exist");
36
- writeFileSync(
37
- join(tmpRoot, tsconfigPath),
38
- `{
25
+ try {
26
+ if (!targetFilePath.endsWith(".ts") && !targetFilePath.endsWith(".tsx"))
27
+ throw new Error("Only .ts files are supported");
28
+ if (targetFilePath.startsWith("./"))
29
+ targetFilePath = targetFilePath.slice(2);
30
+ const src = targetFilePath.startsWith("/") ? targetFilePath : join(projectRoot, targetFilePath);
31
+ if (!existsSync(src))
32
+ throw new Error(
33
+ `Couldn't find "${targetFilePath}" from ${projectRoot}`
34
+ );
35
+ if (existsSync(tmpRoot))
36
+ rmSync(tmpRoot, { recursive: true, force: true });
37
+ mkdirSync(tmpRoot, { recursive: true });
38
+ const tsconfig = tsconfigPath.startsWith("/") ? tsconfigPath : join(projectRoot, tsconfigPath);
39
+ const extendsRef = existsSync(tsconfig) ? `"extends": "${join(projectRoot, "tsconfig.json")}",` : "";
40
+ writeFileSync(
41
+ join(tmpRoot, "tsconfig.json"),
42
+ `{
39
43
  ${extendsRef}
40
44
  "compilerOptions": {
41
45
  "lib": ["ESNext"],
@@ -48,20 +52,34 @@ var fromTypes = (targetFilePath, {
48
52
  "skipDefaultLibCheck": true,
49
53
  "outDir": "./dist"
50
54
  },
51
- "include": ["${join(projectRoot, targetFilePath)}"]
55
+ "include": ["${src}"]
52
56
  }`
53
- );
54
- exec(`tsc`, tmpRoot);
55
- try {
57
+ );
58
+ spawnSync(`tsc`, {
59
+ shell: true,
60
+ cwd: tmpRoot,
61
+ stdio: debug ? "inherit" : void 0
62
+ });
56
63
  const fileName = targetFilePath.replace(/.tsx$/, ".ts").replace(/.ts$/, ".d.ts");
57
- let targetFile = overrideOutputPath?.(tmpRoot) ?? join(tmpRoot, "dist", fileName);
58
- {
59
- const _targetFile = join(
60
- tmpRoot,
61
- "dist",
62
- fileName.slice(fileName.indexOf("/") + 1)
64
+ const targetFile = (overrideOutputPath ? typeof overrideOutputPath === "string" ? overrideOutputPath.startsWith("/") ? overrideOutputPath : join(tmpRoot, "dist", overrideOutputPath) : overrideOutputPath(tmpRoot) : void 0) ?? join(tmpRoot, "dist", fileName);
65
+ if (!existsSync(targetFile)) {
66
+ rmSync(join(tmpRoot, "tsconfig.json"));
67
+ console.warn(
68
+ "[@elysiajs/openapi/gen] Failed to generate OpenAPI schema"
63
69
  );
64
- if (existsSync(_targetFile)) targetFile = _targetFile;
70
+ console.warn("Couldn't find generated declaration file");
71
+ if (existsSync(join(tmpRoot, "dist"))) {
72
+ const tempFiles = readdirSync(join(tmpRoot, "dist"), {
73
+ recursive: true
74
+ }).filter((x) => x.toString().endsWith(".d.ts")).map((x) => `- ${x}`).join("\n");
75
+ if (tempFiles) {
76
+ console.warn(
77
+ "You can override with `overrideOutputPath` with one of the following:"
78
+ );
79
+ console.warn(tempFiles);
80
+ }
81
+ }
82
+ return;
65
83
  }
66
84
  const declaration = readFileSync(targetFile, "utf8");
67
85
  if (existsSync(tmpRoot))
@@ -71,18 +89,22 @@ var fromTypes = (targetFilePath, {
71
89
  )?.[0];
72
90
  if (!instance) return;
73
91
  for (let i = 0; i < 3; i++)
74
- instance = instance.slice(instance.indexOf("}, {", 3));
75
- const routesString = wrapStatusInQuote(instance).slice(
76
- 3,
77
- instance.indexOf("}, {", 3)
78
- ) + "}\n}\n";
92
+ instance = instance.slice(
93
+ instance.indexOf(
94
+ "}, {",
95
+ // remove just `}, `, leaving `{`
96
+ 3
97
+ )
98
+ );
99
+ const routesString = wrapStatusInQuote(
100
+ // Intentionally not adding "}"
101
+ // to avoid mismatched bracket in loop below
102
+ instance.slice(3, instance.indexOf("}, {", 4))
103
+ );
79
104
  const routes = {};
80
105
  for (const route of routesString.slice(1).split("} & {")) {
81
- let schema = TypeBox(`{${route}}}`);
82
- if (schema.type !== "object") {
83
- schema = TypeBox(`{${route}}`);
84
- if (schema.type !== "object") continue;
85
- }
106
+ let schema = TypeBox(`{${route}}`);
107
+ if (schema.type !== "object") continue;
86
108
  const paths = [];
87
109
  while (true) {
88
110
  const keys = Object.keys(schema.properties);
@@ -110,6 +132,9 @@ var fromTypes = (targetFilePath, {
110
132
  );
111
133
  console.warn(error);
112
134
  return;
135
+ } finally {
136
+ if (!debug && existsSync(tmpRoot))
137
+ rmSync(tmpRoot, { recursive: true, force: true });
113
138
  }
114
139
  };
115
140
  export {
package/dist/index.mjs CHANGED
@@ -320,6 +320,7 @@ function toOpenAPISchema(app, exclude, references) {
320
320
  const hooks = route.hooks ?? {};
321
321
  if (references)
322
322
  for (const reference of references) {
323
+ if (!reference) continue;
323
324
  const refer = reference[route.path]?.[method] ?? reference[getLoosePath(route.path)]?.[method];
324
325
  if (!refer) continue;
325
326
  if (!hooks.body && isValidSchema(refer.body))
package/dist/openapi.mjs CHANGED
@@ -61,6 +61,7 @@ function toOpenAPISchema(app, exclude, references) {
61
61
  const hooks = route.hooks ?? {};
62
62
  if (references)
63
63
  for (const reference of references) {
64
+ if (!reference) continue;
64
65
  const refer = reference[route.path]?.[method] ?? reference[getLoosePath(route.path)]?.[method];
65
66
  if (!refer) continue;
66
67
  if (!hooks.body && isValidSchema(refer.body))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elysiajs/openapi",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "Plugin for Elysia to auto-generate API documentation",
5
5
  "author": {
6
6
  "name": "saltyAom",