• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RobinTail / express-zod-api / 3863643685

pending completion
3863643685

Pull #766

github

GitHub
Merge 91d9f9ef5 into 03b5a9a3b
Pull Request #766: Bump @typescript-eslint/parser from 5.47.1 to 5.48.0

437 of 464 branches covered (94.18%)

1039 of 1039 relevant lines covered (100.0%)

345.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.51
/src/open-api.ts
1
import {
176✔
2
  OpenApiBuilder,
3
  OperationObject,
4
  SecuritySchemeObject,
5
  SecuritySchemeType,
6
} from "openapi3-ts";
7
import { defaultInputSources } from "./common-helpers";
176✔
8
import { CommonConfig } from "./config-type";
9
import { mapLogicalContainer } from "./logical-container";
176✔
10
import { Method } from "./method";
11
import {
176✔
12
  depictRequest,
13
  depictRequestParams,
14
  depictResponse,
15
  depictSecurity,
16
  depictSecurityRefs,
17
  depictTags,
18
  ensureShortDescription,
19
  reformatParamsInPath,
20
} from "./open-api-helpers";
21
import { Routing } from "./routing";
22
import { RoutingWalkerParams, walkRouting } from "./routing-walker";
176✔
23

24
interface GeneratorParams {
25
  title: string;
26
  version: string;
27
  serverUrl: string;
28
  routing: Routing;
29
  config: CommonConfig;
30
  /** @default Successful response */
31
  successfulResponseDescription?: string;
32
  /** @default Error response */
33
  errorResponseDescription?: string;
34
  /** @default true */
35
  hasSummaryFromDescription?: boolean;
36
}
37

38
export class OpenAPI extends OpenApiBuilder {
176✔
39
  protected lastSecuritySchemaIds: Partial<Record<SecuritySchemeType, number>> =
264✔
40
    {};
41

42
  protected ensureUniqSecuritySchemaName(subject: SecuritySchemeObject) {
43
    for (const name in this.rootDoc.components?.securitySchemes || {}) {
48!
44
      if (
48✔
45
        JSON.stringify(subject) ===
46
        JSON.stringify(this.rootDoc.components?.securitySchemes?.[name])
47
      ) {
48
        return name;
8✔
49
      }
50
    }
51
    this.lastSecuritySchemaIds[subject.type] =
40✔
52
      (this.lastSecuritySchemaIds?.[subject.type] || 0) + 1;
72✔
53
    return `${subject.type.toUpperCase()}_${
40✔
54
      this.lastSecuritySchemaIds[subject.type]
55
    }`;
56
  }
57

58
  public constructor({
59
    routing,
60
    config,
61
    title,
62
    version,
63
    serverUrl,
64
    successfulResponseDescription = "Successful response",
264✔
65
    errorResponseDescription = "Error response",
264✔
66
    hasSummaryFromDescription = true,
264✔
67
  }: GeneratorParams) {
68
    super();
264✔
69
    this.addInfo({ title, version }).addServer({ url: serverUrl });
264✔
70
    const onEndpoint: RoutingWalkerParams["onEndpoint"] = (
264✔
71
      endpoint,
72
      path,
73
      _method
74
    ) => {
75
      const method = _method as Method;
312✔
76
      const commonParams = { path, method, endpoint };
312✔
77
      const [shortDesc, longDesc] = (["short", "long"] as const).map(
312✔
78
        endpoint.getDescription.bind(endpoint)
79
      );
80
      const inputSources =
81
        config.inputSources?.[method] || defaultInputSources[method];
312✔
82
      const depictedParams = depictRequestParams({
312✔
83
        ...commonParams,
84
        inputSources,
85
      });
86
      const operation: OperationObject = {
312✔
87
        responses: {
88
          "200": depictResponse({
89
            ...commonParams,
90
            description: successfulResponseDescription,
91
            isPositive: true,
92
          }),
93
          "400": depictResponse({
94
            ...commonParams,
95
            description: errorResponseDescription,
96
            isPositive: false,
97
          }),
98
        },
99
      };
100
      if (longDesc) {
312✔
101
        operation.description = longDesc;
24✔
102
        if (hasSummaryFromDescription && shortDesc === undefined) {
24✔
103
          operation.summary = ensureShortDescription(longDesc);
16✔
104
        }
105
      }
106
      if (shortDesc) {
312✔
107
        operation.summary = ensureShortDescription(shortDesc);
24✔
108
      }
109
      if (endpoint.getTags().length > 0) {
312✔
110
        operation.tags = endpoint.getTags();
40✔
111
      }
112
      if (depictedParams.length > 0) {
312✔
113
        operation.parameters = depictedParams;
120✔
114
      }
115
      if (inputSources.includes("body")) {
312✔
116
        operation.requestBody = depictRequest(commonParams);
208✔
117
      }
118
      const securityRefs = depictSecurityRefs(
248✔
119
        mapLogicalContainer(
120
          depictSecurity(endpoint.getSecurity()),
121
          (securitySchema) => {
122
            const name = this.ensureUniqSecuritySchemaName(securitySchema);
48✔
123
            const scopes = ["oauth2", "openIdConnect"].includes(
48✔
124
              securitySchema.type
125
            )
126
              ? endpoint.getScopes()
48✔
127
              : [];
128
            this.addSecurityScheme(name, securitySchema);
48✔
129
            return { name, scopes };
48✔
130
          }
131
        )
132
      );
133
      if (securityRefs.length > 0) {
248✔
134
        operation.security = securityRefs;
24✔
135
      }
136
      const swaggerCompatiblePath = reformatParamsInPath(path);
248✔
137
      this.addPath(swaggerCompatiblePath, {
248✔
138
        [method]: operation,
139
      });
140
    };
141
    walkRouting({ routing, onEndpoint });
264✔
142
    this.rootDoc.tags = config.tags ? depictTags(config.tags) : [];
200✔
143
  }
144
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc