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

panates / opra / 29494915195

16 Jul 2026 11:33AM UTC coverage: 83.024% (+0.4%) from 82.653%
29494915195

push

github

erayhanoglu
1.29.1

4118 of 5238 branches covered (78.62%)

Branch coverage included in aggregate %.

34348 of 41093 relevant lines covered (83.59%)

239.47 hits per line

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

93.62
/packages/common/src/document/http/http-controller.ts
1
import nodePath from 'node:path';
1✔
2
import { omitUndefined } from '@jsopen/objects';
1✔
3
import type { Combine, ThunkAsync, Type } from 'ts-gems';
1✔
4
import { asMutable } from 'ts-gems';
1✔
5
import { ResponsiveMap } from '../../helpers/index.js';
1✔
6
import { OpraSchema } from '../../schema/index.js';
1✔
7
import type { ApiDocument } from '../api-document.js';
1✔
8
import { DataTypeMap } from '../common/data-type-map.js';
1✔
9
import { DocumentElement } from '../common/document-element.js';
1✔
10
import { CLASS_NAME_PATTERN, DECORATOR, kDataTypeMap } from '../constants.js';
1✔
11
import type { EnumType } from '../data-type/enum-type.js';
1✔
12
import { HttpControllerDecoratorFactory } from '../decorators/http-controller.decorator.js';
1✔
13
import {
352✔
14
  colorFgMagenta,
352✔
15
  colorFgYellow,
352✔
16
  colorReset,
352✔
17
  nodeInspectCustom,
43✔
18
} from '../utils/inspect.util.js';
352✔
19
import type { HttpApi } from './http-api.js';
309✔
20
import type { HttpOperation } from './http-operation.js';
309✔
21
import { HttpParameter } from './http-parameter.js';
352!
22

×
23
/**
×
24
 * @namespace HttpController
×
25
 */
×
26
export namespace HttpController {
352✔
27
  export interface Metadata extends Pick<
309✔
28
    OpraSchema.HttpController,
309✔
29
    'description' | 'path'
309✔
30
  > {
309✔
31
    name: string;
309✔
32
    controllers?: (Type | ((parent: any) => any))[];
309✔
33
    types?: ThunkAsync<Type | EnumType.EnumObject | EnumType.EnumArray>[];
309✔
34
    operations?: Record<string, HttpOperation.Metadata>;
309✔
35
    parameters?: HttpParameter.Metadata[];
352✔
36
  }
5✔
37

5✔
38
  export interface Options extends Partial<
352✔
39
    Pick<OpraSchema.HttpController, 'description' | 'path'>
352✔
40
  > {
352✔
41
    name?: string;
352✔
42
    controllers?: (Type | ((parent: any) => any))[];
1!
43
  }
1✔
44

1✔
45
  export interface InitArguments extends Combine<
1✔
46
    {
1✔
47
      instance?: object;
1✔
48
      ctor?: Type;
1✔
49
    },
1✔
50
    Pick<Metadata, 'name' | 'description' | 'path'>
1✔
51
  > {}
×
52
}
×
53

×
54
/**
×
55
 * Type definition for HttpController
1✔
56
 * @class HttpController
61✔
57
 */
61✔
58
export interface HttpControllerStatic extends HttpControllerDecoratorFactory {
61✔
59
  /**
16✔
60
   * Class constructor of HttpController
16✔
61
   * @param owner
16✔
62
   * @param args
16✔
63
   */
16✔
64
  new (
10✔
65
    owner: HttpApi | HttpController,
16✔
66
    args: HttpController.InitArguments,
6✔
67
  ): HttpController;
6✔
68

6✔
69
  prototype: HttpController;
16✔
70
}
8✔
71

8✔
72
/**
8✔
73
 * Type definition of HttpController prototype
8✔
74
 * @interface HttpController
5✔
75
 */
5✔
76
export interface HttpController extends HttpControllerClass {}
8✔
77

3✔
78
/**
3✔
79
 * HttpController
8✔
80
 */
1✔
81
export const HttpController = function (
1✔
82
  this: HttpController | void,
1✔
83
  ...args: any[]
1✔
84
) {
1✔
85
  // ClassDecorator
1✔
86
  if (!this) return HttpController[DECORATOR].apply(undefined, args);
1✔
87

1✔
88
  // Constructor
1✔
89
  const [owner, initArgs] = args as [
1✔
90
    HttpApi | HttpController,
16!
91
    HttpController.InitArguments,
×
92
  ];
×
93
  DocumentElement.call(this, owner);
61✔
94
  if (!CLASS_NAME_PATTERN.test(initArgs.name))
61✔
95
    throw new TypeError(`Invalid resource name (${initArgs.name})`);
61✔
96
  const _this = asMutable(this);
3✔
97
  _this.kind = OpraSchema.HttpController.Kind;
3✔
98
  _this.types = _this.node[kDataTypeMap] = new DataTypeMap();
6✔
99
  _this.operations = new ResponsiveMap();
61✔
100
  _this.controllers = new ResponsiveMap();
1✔
101
  _this.parameters = [];
1,975✔
102
  _this.name = initArgs.name;
1,975✔
103
  _this.description = initArgs.description;
1,975✔
104
  _this.path = initArgs.path ?? initArgs.name;
1,975✔
105
  _this.instance = initArgs.instance;
710✔
106
  _this.ctor = initArgs.ctor;
710✔
107
  (_this as any)._controllerReverseMap = new WeakMap();
360✔
108
  (_this as any)._initialize?.(initArgs);
360✔
109
} as HttpControllerStatic;
360✔
110

360✔
111
/**
360✔
112
 *
360✔
113
 * @class HttpController
360✔
114
 */
360✔
115
class HttpControllerClass extends DocumentElement {
710✔
116
  declare protected _controllerReverseMap: WeakMap<Type, HttpController | null>;
710!
117
  declare readonly kind: OpraSchema.HttpController.Kind;
1,975✔
118
  declare readonly name: string;
1,975✔
119
  declare description?: string;
551✔
120
  declare path: string;
551✔
121
  declare instance?: any;
551✔
122
  declare ctor?: Type;
1✔
123
  declare parameters: HttpParameter[];
×
124
  declare operations: ResponsiveMap<HttpOperation>;
×
125
  declare controllers: ResponsiveMap<HttpController>;
1✔
126
  declare types: DataTypeMap;
1✔
127

1✔
128
  /**
1✔
129
   * @property isRoot
1✔
130
   */
1✔
131
  get isRoot(): boolean {
1✔
132
    return !(this.owner instanceof HttpController);
330✔
133
  }
330✔
134

330✔
135
  findController(controller: Type): HttpController | undefined;
330✔
136
  findController(resourcePath: string): HttpController | undefined;
330✔
137
  findController(arg0: string | Type): HttpController | undefined {
330✔
138
    if (typeof arg0 === 'function') {
318✔
139
      /* Check for cached mapping */
809✔
140
      let controller = this._controllerReverseMap.get(arg0);
330✔
141
      if (controller != null) return controller;
330✔
142
      /* Lookup for ctor in all controllers */
58✔
143
      for (const c of this.controllers.values()) {
58✔
144
        if (c.ctor === arg0) {
68✔
145
          this._controllerReverseMap.set(arg0, c);
330✔
146
          return c;
10✔
147
        }
10✔
148
        if (c.controllers.size) {
10✔
149
          controller = c.findController(arg0);
10✔
150
          if (controller) {
10✔
151
            this._controllerReverseMap.set(arg0, controller);
330✔
152
            return controller;
99✔
153
          }
99✔
154
        }
99✔
155
      }
99✔
156
      this._controllerReverseMap.set(arg0, null);
99✔
157
      return;
119✔
158
    }
119✔
159
    if (arg0.startsWith('/')) arg0 = arg0.substring(1);
1✔
160
    if (arg0.includes('/')) {
1✔
161
      const a = arg0.split('/');
×
162
      let r: HttpController | undefined = this;
×
163
      while (r && a.length > 0) {
1✔
164
        r = r.controllers.get(a.shift()!);
1✔
165
      }
1✔
166
      return r;
1✔
167
    }
1✔
168
    return this.controllers.get(arg0);
1✔
169
  }
1✔
170

1✔
171
  findParameter(
1✔
172
    paramName: string,
1✔
173
    location?: OpraSchema.HttpParameterLocation,
1✔
174
  ): HttpParameter | undefined {
1✔
175
    const paramNameLower = paramName.toLowerCase();
1✔
176
    let prm: any;
1✔
177
    for (prm of this.parameters) {
1✔
178
      if (location && location !== prm.location) continue;
1✔
179
      if (typeof prm.name === 'string') {
1✔
180
        prm._nameLower = prm._nameLower || prm.name.toLowerCase();
1✔
181
        if (prm._nameLower === paramNameLower) return prm;
1✔
182
      }
1✔
183
      if (prm.name instanceof RegExp && prm.name.test(paramName)) return prm;
1✔
184
    }
1✔
185
    if (
1✔
186
      this.node.parent &&
1✔
187
      this.node.parent.element instanceof HttpController
1✔
188
    ) {
1✔
189
      return this.node.parent.element.findParameter(paramName, location);
1✔
190
    }
1✔
191
  }
1✔
192

1✔
193
  getFullUrl(): string {
1✔
194
    return nodePath.posix.join(
1✔
195
      this.owner instanceof HttpController ? this.owner.getFullUrl() : '/',
1✔
196
      this.path,
1✔
197
    );
1✔
198
  }
1✔
199

1✔
200
  /**
1✔
201
   *
1✔
202
   */
1✔
203
  toString(): string {
1✔
204
    return `[HttpController ${this.name}]`;
1✔
205
  }
1✔
206

1✔
207
  /**
1✔
208
   *
1✔
209
   */
1✔
210
  toJSON(options?: ApiDocument.ExportOptions): OpraSchema.HttpController {
1✔
211
    const out = omitUndefined<OpraSchema.HttpController>({
1✔
212
      kind: this.kind,
1✔
213
      description: this.description,
1✔
214
      path: this.path,
1✔
215
    });
1✔
216
    if (this.operations.size) {
1✔
217
      out.operations = {};
1✔
218
      for (const v of this.operations.values()) {
1✔
219
        out.operations[v.name] = v.toJSON(options);
1✔
220
      }
1✔
221
    }
1✔
222
    if (this.controllers.size) {
1✔
223
      out.controllers = {};
1✔
224
      for (const v of this.controllers.values()) {
1✔
225
        out.controllers[v.name] = v.toJSON(options);
1✔
226
      }
1✔
227
    }
1✔
228
    if (this.types.size) {
1✔
229
      out.types = {};
1✔
230
      for (const v of this.types.values()) {
1✔
231
        out.types[v.name!] = v.toJSON(options);
1✔
232
      }
1✔
233
    }
1✔
234
    if (this.parameters.length) {
1✔
235
      out.parameters = [];
1✔
236
      for (const prm of this.parameters) {
1✔
237
        out.parameters.push(prm.toJSON(options));
1✔
238
      }
1✔
239
    }
1✔
240
    return out;
1✔
241
  }
1✔
242

1✔
243
  /**
1✔
244
   *
1✔
245
   */
1✔
246
  protected [nodeInspectCustom](): string {
1✔
247
    return `[${colorFgYellow}HttpController${colorFgMagenta + this.name + colorReset}]`;
1✔
248
  }
1✔
249
}
1✔
250

1✔
251
HttpController.prototype = HttpControllerClass.prototype;
1✔
252
Object.assign(HttpController, HttpControllerDecoratorFactory);
1✔
253
HttpController[DECORATOR] = HttpControllerDecoratorFactory;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc