nestjs-openapi 0.1.3 → 0.2.0

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.mjs CHANGED
@@ -1,18 +1,19 @@
1
- export { c as categorizeBrokenRefs, d as defineConfig, f as findConfigFile, e as formatValidationResult, g as generate, b as loadAndResolveConfig, a as loadConfig, l as loadConfigFromFile, r as resolveConfig, v as validateSpec } from './shared/nestjs-openapi.D2c4bMP5.mjs';
1
+ import { S as SpecFileNotFoundError, a as SpecFileReadError, b as SpecFileParseError } from './shared/nestjs-openapi.P9V98nna.mjs';
2
+ export { c as ConfigLoadError, C as ConfigNotFoundError, ae as ConfigService, e as ConfigValidationError, D as DtoGlobResolutionError, E as EntryNotFoundError, I as InvalidMethodError, B as MethodExtractionService, M as MissingGenericSchemaTempFileCleanupError, f as MissingGenericSchemaTempFileWriteError, n as ModuleTraversalService, ad as OutputService, P as ProjectInitError, i as ProjectService, j as ProjectServiceLive, h as PublicApiError, a0 as SchemaGenerationError, a1 as SchemaService, ac as ValidationService, a9 as applyConstraintsToSchema, av as categorizeBrokenRefs, d as defineConfig, a7 as extractClassConstraints, a5 as extractClassValidationInfo, a6 as extractClassValidationInfoEffect, a2 as extractPropertyConstraints, a4 as extractPropertyValidationInfo, V as filterInternalSchemas, W as filterInternalSchemasEffect, Q as filterSchemas, R as filterSchemasEffect, af as findConfigFile, aw as formatValidationResult, g as generate, _ as generateSchemas, $ as generateSchemasFromFiles, ak as generatorServicesLayer, l as getAllControllers, am as getArrayInitializer, z as getControllerMethodInfos, A as getControllerMethodInfosEffect, p as getControllerName, o as getControllerPrefix, t as getControllerTags, s as getDecoratorName, u as getHttpDecorator, r as getHttpMethods, x as getMethodInfo, y as getMethodInfoEffect, aq as getModuleDecoratorArg, at as getModuleMetadata, k as getModules, a8 as getRequiredProperties, an as getStringLiteralValue, ao as getSymbolFromIdentifier, v as isHttpDecorator, q as isHttpMethod, ap as isModuleClass, a3 as isPropertyOptional, aj as loadAndResolveConfig, ah as loadConfig, ag as loadConfigFromFile, m as makeProjectContext, N as mergeGeneratedSchemas, O as mergeGeneratedSchemasEffect, K as mergeSchemas, L as mergeSchemasEffect, aa as mergeValidationConstraints, ab as mergeValidationConstraintsEffect, w as normalizePath, T as normalizeSchemas, U as normalizeSchemasEffect, X as normalizeStructureRefs, Y as normalizeStructureRefsEffect, as as resolveArrayOfClasses, ar as resolveClassFromExpression, al as resolveClassFromSymbol, ai as resolveConfig, Z as toPascalCase, F as transformMethod, G as transformMethodEffect, H as transformMethods, J as transformMethodsEffect, au as validateSpec } from './shared/nestjs-openapi.P9V98nna.mjs';
2
3
  import { readFileSync } from 'node:fs';
4
+ import { fail } from 'node:assert';
3
5
  import { resolve } from 'node:path';
4
6
  import { Module } from '@nestjs/common';
5
- export { generateAsync, generate as generateEffect } from './internal.mjs';
6
- import { P as ProjectInitError, E as EntryNotFoundError } from './shared/nestjs-openapi.DRcy130f.mjs';
7
- export { a as ConfigLoadError, C as ConfigNotFoundError, b as ConfigValidationError, I as InvalidMethodError, c as getAllControllers, q as getArrayInitializer, o as getControllerMethodInfos, e as getControllerName, d as getControllerPrefix, j as getControllerTags, h as getDecoratorName, k as getHttpDecorator, f as getHttpMethods, m as getMethodInfo, w as getModuleDecoratorArg, z as getModuleMetadata, g as getModules, s as getStringLiteralValue, u as getSymbolFromIdentifier, l as isHttpDecorator, i as isHttpMethod, v as isModuleClass, n as normalizePath, y as resolveArrayOfClasses, x as resolveClassFromExpression, r as resolveClassFromSymbol, t as transformMethod, p as transformMethods } from './shared/nestjs-openapi.DRcy130f.mjs';
8
- import { Context, Effect, Layer } from 'effect';
9
- import { Project } from 'ts-morph';
7
+ import { Effect, Exit, Cause, Option } from 'effect';
8
+ export { generateAsync, generate as generateEffect, generateFromConfigAsync, generateFromConfigEffect, generatePathsAsync, generatePathsEffect } from './internal.mjs';
10
9
  import 'node:crypto';
10
+ import 'ts-morph';
11
11
  import 'glob';
12
- import 'js-yaml';
13
- import 'ts-json-schema-generator';
14
12
  import 'node:url';
13
+ import 'node:module';
15
14
  import 'child_process';
15
+ import 'js-yaml';
16
+ import 'ts-json-schema-generator';
16
17
 
17
18
  var __create = Object.create;
18
19
  var __defProp = Object.defineProperty;
@@ -93,22 +94,29 @@ function generateSwaggerUiHtml(title, jsonPath) {
93
94
  </body>
94
95
  </html>`;
95
96
  }
96
- function loadSpecFile(filePath) {
97
- try {
97
+ const loadSpecFileEffect = Effect.fn("OpenApiModule.loadSpecFile")(
98
+ function* (filePath) {
98
99
  const resolvedPath = resolve(process.cwd(), filePath);
99
- const content = readFileSync(resolvedPath, "utf-8");
100
- return JSON.parse(content);
101
- } catch (error) {
102
- if (error instanceof Error) {
103
- if ("code" in error && error.code === "ENOENT") {
104
- throw new Error(
105
- `OpenAPI spec file not found: ${filePath}. Make sure to run 'nestjs-openapi generate' first.`
106
- );
107
- }
108
- throw new Error(`Failed to load OpenAPI spec: ${error.message}`);
109
- }
110
- throw error;
100
+ const content = yield* Effect.try({
101
+ try: () => readFileSync(resolvedPath, "utf-8"),
102
+ catch: (cause) => cause && typeof cause === "object" && "code" in cause && cause.code === "ENOENT" ? SpecFileNotFoundError.create(filePath) : SpecFileReadError.create(filePath, cause)
103
+ });
104
+ return yield* Effect.try({
105
+ try: () => JSON.parse(content),
106
+ catch: (cause) => SpecFileParseError.create(filePath, cause)
107
+ });
108
+ }
109
+ );
110
+ function loadSpecFile(filePath) {
111
+ const exit = Effect.runSyncExit(loadSpecFileEffect(filePath));
112
+ if (Exit.isSuccess(exit)) {
113
+ return exit.value;
114
+ }
115
+ const failure = Cause.failureOption(exit.cause);
116
+ if (Option.isSome(failure)) {
117
+ fail(failure.value);
111
118
  }
119
+ fail(Cause.pretty(exit.cause));
112
120
  }
113
121
  function resolveOptions(options) {
114
122
  let swaggerEnabled = false;
@@ -232,66 +240,4 @@ function createOpenApiControllers(options, spec) {
232
240
  return controllers;
233
241
  }
234
242
 
235
- class ProjectService extends Context.Tag("ProjectService")() {
236
- }
237
- const initProject = Effect.fn("ProjectService.initProject")(function* (options) {
238
- return yield* Effect.try({
239
- try: () => new Project({
240
- tsConfigFilePath: options.tsconfig,
241
- skipAddingFilesFromTsConfig: true
242
- }),
243
- catch: (error) => ProjectInitError.create(options.tsconfig, error)
244
- });
245
- });
246
- const addSourceFiles = Effect.fn("ProjectService.addSourceFiles")(function* (project, entry) {
247
- return yield* Effect.try({
248
- try: () => {
249
- project.addSourceFilesAtPaths(entry);
250
- project.resolveSourceFileDependencies();
251
- },
252
- catch: (error) => new ProjectInitError({
253
- tsconfig: "",
254
- message: `Failed to add source files: ${entry}`,
255
- cause: error
256
- })
257
- });
258
- });
259
- const getEntrySourceFile = Effect.fn("ProjectService.getEntrySourceFile")(
260
- function* (project, entry) {
261
- const sourceFile = project.getSourceFile(entry);
262
- if (!sourceFile) {
263
- return yield* EntryNotFoundError.fileNotFound(entry);
264
- }
265
- return sourceFile;
266
- }
267
- );
268
- const getEntryClass = Effect.fn("ProjectService.getEntryClass")(function* (sourceFile, entry, className = "AppModule") {
269
- const entryClass = sourceFile.getClass(className);
270
- if (!entryClass) {
271
- return yield* EntryNotFoundError.classNotFound(entry, className);
272
- }
273
- return entryClass;
274
- });
275
- const makeProjectContext = Effect.fn(
276
- "ProjectService.makeProjectContext"
277
- )(function* (options) {
278
- yield* Effect.logDebug("Initializing project").pipe(
279
- Effect.annotateLogs({ entry: options.entry })
280
- );
281
- const project = yield* initProject(options);
282
- yield* addSourceFiles(project, options.entry);
283
- const entrySourceFile = yield* getEntrySourceFile(project, options.entry);
284
- const entryClass = yield* getEntryClass(entrySourceFile, options.entry);
285
- yield* Effect.logDebug("Project initialized successfully");
286
- return {
287
- project,
288
- entrySourceFile,
289
- entryClass
290
- };
291
- });
292
- const ProjectServiceLive = (options) => Layer.effect(
293
- ProjectService,
294
- makeProjectContext(options).pipe(Effect.map((context) => ({ context })))
295
- );
296
-
297
- export { EntryNotFoundError, OPENAPI_MODULE_OPTIONS, OPENAPI_SPEC, OpenApiModule, ProjectInitError, ProjectService, ProjectServiceLive, generateSwaggerUiHtml, loadSpecFile, makeProjectContext, resolveOptions };
243
+ export { OPENAPI_MODULE_OPTIONS, OPENAPI_SPEC, OpenApiModule, SpecFileNotFoundError, SpecFileParseError, SpecFileReadError, generateSwaggerUiHtml, loadSpecFile, loadSpecFileEffect, resolveOptions };
@@ -1,2 +1,3 @@
1
+ export { E as GenerateOptions, x as generate, y as generateAsync, D as generateFromConfigAsync, B as generateFromConfigEffect, A as generatePathsAsync, z as generatePathsEffect } from './shared/nestjs-openapi.D0Osp4GW.mjs';
1
2
  import 'effect';
2
- export { G as GenerateOptions, g as generate, d as generateAsync } from './shared/nestjs-openapi.t3iwzrrT.mjs';
3
+ import 'ts-morph';
@@ -1,2 +1,3 @@
1
+ export { E as GenerateOptions, x as generate, y as generateAsync, D as generateFromConfigAsync, B as generateFromConfigEffect, A as generatePathsAsync, z as generatePathsEffect } from './shared/nestjs-openapi.D0Osp4GW.js';
1
2
  import 'effect';
2
- export { G as GenerateOptions, g as generate, d as generateAsync } from './shared/nestjs-openapi.t3iwzrrT.js';
3
+ import 'ts-morph';
package/dist/internal.mjs CHANGED
@@ -1,53 +1,60 @@
1
1
  import { Effect } from 'effect';
2
- import { Project } from 'ts-morph';
3
- import { E as EntryNotFoundError, g as getModules, o as getControllerMethodInfos, p as transformMethods } from './shared/nestjs-openapi.DRcy130f.mjs';
2
+ import { i as ProjectService, n as ModuleTraversalService, B as MethodExtractionService, J as transformMethodsEffect, ax as generateEffect, ay as runProjectApiPromise, ak as generatorServicesLayer, az as runtimeLayerFor, aA as runGeneratorApiPromise } from './shared/nestjs-openapi.P9V98nna.mjs';
3
+ import 'node:fs';
4
+ import 'node:path';
5
+ import 'node:crypto';
6
+ import 'ts-morph';
7
+ import 'glob';
8
+ import 'node:url';
9
+ import 'node:module';
10
+ import 'child_process';
11
+ import 'js-yaml';
12
+ import 'ts-json-schema-generator';
4
13
 
5
- const generate = (options) => Effect.gen(function* () {
6
- yield* Effect.logInfo("Starting OpenAPI generation").pipe(
7
- Effect.annotateLogs({ entry: options.entry })
8
- );
9
- const project = new Project({
10
- tsConfigFilePath: options.tsconfig,
11
- skipAddingFilesFromTsConfig: true
12
- });
13
- project.addSourceFilesAtPaths(options.entry);
14
- project.resolveSourceFileDependencies();
15
- const entrySourceFile = project.getSourceFile(options.entry);
16
- if (!entrySourceFile) {
17
- return yield* EntryNotFoundError.fileNotFound(options.entry);
18
- }
19
- const entryClass = entrySourceFile.getClass("AppModule");
20
- if (!entryClass) {
21
- return yield* EntryNotFoundError.classNotFound(
22
- options.entry,
23
- "AppModule"
14
+ const generatePathsEffect = Effect.fn("Internal.generatePathsEffect")(
15
+ function* (options) {
16
+ yield* Effect.logInfo("Starting OpenAPI generation").pipe(
17
+ Effect.annotateLogs({ entry: options.entry })
18
+ );
19
+ const { entryClass } = yield* ProjectService.makeProjectContext(options);
20
+ const modules = yield* ModuleTraversalService.getModules(entryClass);
21
+ const methodInfos = yield* Effect.forEach(
22
+ modules.flatMap((mod) => mod.controllers),
23
+ (controller) => MethodExtractionService.getControllerMethodInfos(controller),
24
+ { concurrency: "unbounded" }
25
+ );
26
+ const flatMethodInfos = methodInfos.flat();
27
+ yield* Effect.logInfo("Collected method infos").pipe(
28
+ Effect.annotateLogs({
29
+ modules: modules.length,
30
+ methods: flatMethodInfos.length
31
+ })
32
+ );
33
+ const paths = yield* transformMethodsEffect(flatMethodInfos);
34
+ yield* Effect.logInfo("OpenAPI generation complete").pipe(
35
+ Effect.annotateLogs({ paths: Object.keys(paths).length })
24
36
  );
37
+ return paths;
25
38
  }
26
- const modules = yield* getModules(entryClass);
27
- const methodInfos = modules.flatMap(
28
- (mod) => mod.controllers.flatMap(
29
- (controller) => getControllerMethodInfos(controller)
39
+ );
40
+ const generateFromConfigEffect = generateEffect;
41
+ const generatePathsAsync = async (options) => {
42
+ const program = generatePathsEffect(options);
43
+ return runProjectApiPromise(program.pipe(Effect.provide(generatorServicesLayer)));
44
+ };
45
+ const generateFromConfigAsync = async (configPath, overrides) => {
46
+ const program = generateFromConfigEffect(configPath, overrides).pipe(
47
+ Effect.provide(generatorServicesLayer),
48
+ Effect.provide(
49
+ runtimeLayerFor(
50
+ overrides?.debug ?? false,
51
+ overrides?.telemetry
52
+ )
30
53
  )
31
54
  );
32
- yield* Effect.logInfo("Collected method infos").pipe(
33
- Effect.annotateLogs({
34
- modules: modules.length,
35
- methods: methodInfos.length
36
- })
37
- );
38
- const paths = transformMethods(methodInfos);
39
- yield* Effect.logInfo("OpenAPI generation complete").pipe(
40
- Effect.annotateLogs({
41
- paths: Object.keys(paths).length
42
- })
43
- );
44
- return paths;
45
- });
46
- const generateAsync = async (options) => {
47
- const program = generate(options).pipe(
48
- Effect.mapError((error) => new Error(error.message))
49
- );
50
- return Effect.runPromise(program);
55
+ return runGeneratorApiPromise(program);
51
56
  };
57
+ const generate = generatePathsEffect;
58
+ const generateAsync = generatePathsAsync;
52
59
 
53
- export { generate, generateAsync };
60
+ export { generate, generateAsync, generateFromConfigAsync, generateFromConfigEffect, generatePathsAsync, generatePathsEffect };