• 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

92.42
/packages/common/src/document/factory/api-document.factory.ts
1
import { updateErrorMessage } from '@jsopen/objects';
1✔
2
import type { PartialSome, StrictOmit, ThunkAsync } from 'ts-gems';
1✔
3
import { resolveThunk } from '../../helpers/index.js';
1✔
4
import { OpraSchema } from '../../schema/index.js';
1✔
5
import { ApiDocument } from '../api-document.js';
1✔
6
import { DocumentInitContext } from '../common/document-init-context.js';
1✔
7
import { OpraDocumentError } from '../common/opra-document-error.js';
1✔
8
import { BUILTIN, CLASS_NAME_PATTERN, kCtorMap } from '../constants.js';
1✔
9
import * as extendedTypes from '../data-type/extended-types/index.js';
1✔
10
import * as primitiveTypes from '../data-type/primitive-types/index.js';
1✔
11
import { DataTypeFactory } from './data-type.factory.js';
1✔
12
import { HttpApiFactory } from './http-api.factory.js';
1✔
13
import { MQApiFactory } from './mq-api.factory.js';
1✔
14
import { WSApiFactory } from './ws-api.factory.js';
1✔
15

1✔
16
const OPRA_SPEC_URL = 'https://oprajs.com/spec/v' + OpraSchema.SpecVersion;
1✔
17

1✔
18
export namespace ApiDocumentFactory {
1✔
19
  export interface InitArguments extends PartialSome<
1✔
20
    StrictOmit<OpraSchema.ApiDocument, 'id' | 'references' | 'types' | 'api'>,
1✔
21
    'spec'
153✔
22
  > {
153✔
23
    references?: Record<string, ReferenceThunk>;
153✔
24
    types?: DataTypeInitSources;
153!
25
    api?:
153✔
26
      | StrictOmit<HttpApiFactory.InitArguments, 'owner'>
153✔
27
      | StrictOmit<MQApiFactory.InitArguments, 'owner'>
153✔
28
      | StrictOmit<WSApiFactory.InitArguments, 'owner'>;
153✔
29
  }
153✔
30

153✔
31
  export type ReferenceSource =
153✔
32
    string | OpraSchema.ApiDocument | InitArguments | ApiDocument;
153✔
33
  export type ReferenceThunk = ThunkAsync<ReferenceSource>;
3✔
34

3✔
35
  export type DataTypeInitSources = DataTypeFactory.DataTypeSources;
3!
36
}
×
37

×
38
/**
×
39
 * @class ApiDocumentFactory
3!
40
 */
×
41
export class ApiDocumentFactory {
3✔
42
  private _allDocuments: Record<string, ApiDocument> = {};
3✔
43

3✔
44
  /**
3✔
45
   * Creates ApiDocument instance from given schema object
3✔
46
   */
3✔
47
  static async createDocument(
3✔
48
    schemaOrUrl:
3✔
49
      | string
3✔
50
      | PartialSome<OpraSchema.ApiDocument, 'spec'>
3✔
51
      | ApiDocumentFactory.InitArguments,
3✔
52
    options?:
4✔
53
      | Partial<Pick<DocumentInitContext, 'maxErrors' | 'showErrorDetails'>>
3!
54
      | DocumentInitContext,
3✔
55
  ): Promise<ApiDocument> {
3✔
56
    const factory = new ApiDocumentFactory();
3✔
57
    const context: DocumentInitContext =
1✔
58
      options instanceof DocumentInitContext
1✔
59
        ? options
1✔
60
        : new DocumentInitContext(options);
1✔
61
    try {
308✔
62
      const document = new ApiDocument();
308✔
63
      await factory.initDocument(document, context, schemaOrUrl);
308!
64
      if (context.error.details.length) throw context.error;
×
65
      return document;
×
66
    } catch (e: any) {
×
67
      try {
×
68
        if (!(e instanceof OpraDocumentError)) {
×
69
          context.addError(e);
×
70
        }
×
71
      } catch {
×
72
        //
×
73
      }
×
74
      if (!context.error.message) {
308✔
75
        const l = context.error.details.length;
308✔
76
        let message = `(${l}) error${l > 1 ? 's' : ''} found in document schema.`;
308✔
77
        if (context.showErrorDetails) {
155✔
78
          message += context.error.details
155✔
79
            .map(
155✔
80
              d => `\n\n  - ${d.message}` + (d.path ? `\n    @${d.path}` : ''),
155✔
81
            )
153✔
82
            .join('');
153✔
83
        }
153✔
84
        updateErrorMessage(context.error, message);
153✔
85
      }
153✔
86
      throw context.error;
308✔
87
    }
308✔
88
  }
308✔
89

308✔
90
  /**
308✔
91
   * Downloads schema from the given URL and creates the document instance   * @param url
308✔
92
   */
308✔
93
  protected async initDocument(
230✔
94
    document: ApiDocument,
308✔
95
    context: DocumentInitContext,
308✔
96
    schemaOrUrl: ApiDocumentFactory.InitArguments | string,
308✔
97
  ): Promise<void> {
57✔
98
    let init: ApiDocumentFactory.InitArguments;
57✔
99
    if (typeof schemaOrUrl === 'string') {
57✔
100
      const resp = await fetch(schemaOrUrl, { method: 'GET' });
57✔
101
      init = await resp.json();
58✔
102
      if (!init)
58✔
103
        return context.addError(
58✔
104
          `Invalid response returned from url: ${schemaOrUrl}`,
58✔
105
        );
2✔
106
      init.url = schemaOrUrl;
58✔
107
    } else init = schemaOrUrl;
56✔
108

56✔
109
    // Add builtin data types if this document is the root
58✔
110
    let builtinDocument: ApiDocument | undefined;
54✔
111
    if (!document[BUILTIN]) {
58✔
112
      const t = document.node.findDataType('string');
2✔
113
      builtinDocument = t?.node.getDocument();
2✔
114
      if (!builtinDocument) {
2✔
115
        builtinDocument = await this.createBuiltinDocument(context);
2✔
116
        document.references.set('opra', builtinDocument);
2✔
117
      }
2✔
118
    }
2✔
119

2✔
120
    init.spec = init.spec || OpraSchema.SpecVersion;
58✔
121
    document.url = init.url;
57✔
122
    if (init.info) document.info = { ...init.info };
308✔
123

250✔
124
    /* Add references  */
250✔
125
    if (init.references) {
250✔
126
      await context.enterAsync('.references', async () => {
250✔
127
        let ns: string;
250✔
128
        let r: any;
308✔
129
        for ([ns, r] of Object.entries(init.references!)) {
308✔
130
          r = await resolveThunk(r);
83✔
131
          await context.enterAsync(`[${ns}]`, async () => {
83✔
132
            if (!CLASS_NAME_PATTERN.test(ns))
72✔
133
              throw new TypeError(`Invalid namespace (${ns})`);
72✔
134
            if (r instanceof ApiDocument) {
72✔
135
              document.references.set(ns, r);
72✔
136
              return;
72✔
137
            }
83✔
138
            const refDoc = new ApiDocument();
11✔
139
            if (builtinDocument) refDoc.references.set('opra', builtinDocument);
10✔
140
            await this.initDocument(refDoc, context, r);
10✔
141
            document.references.set(ns, this._allDocuments[refDoc.id]);
10✔
142
          });
10✔
143
        }
10✔
144
      });
11✔
145
    }
1✔
146

1✔
147
    if (init.types) {
1✔
148
      await context.enterAsync('.types', async () => {
1✔
149
        await DataTypeFactory.addDataTypes(context, document, init.types!);
1✔
150
      });
1✔
151
    }
1✔
152

1✔
153
    if (init.api) {
1✔
154
      await context.enterAsync(`.api`, async () => {
1✔
155
        if (init.api && init.api.transport === 'http') {
1!
156
          const api = await HttpApiFactory.createApi(context, {
83✔
157
            ...init.api,
308✔
158
            owner: document,
308✔
159
          });
308✔
160
          if (api) document.api = api;
308✔
161
        } else if (init.api && init.api.transport === 'mq') {
308✔
162
          const api = await MQApiFactory.createApi(context, {
1✔
163
            ...init.api,
1✔
164
            owner: document,
153✔
165
          });
153✔
166
          if (api) document.api = api;
153✔
167
        } else if (init.api && init.api.transport === 'ws') {
153✔
168
          const api = await WSApiFactory.createApi(context, {
153✔
169
            ...init.api,
153✔
170
            owner: document,
153✔
171
          });
153✔
172
          if (api) document.api = api;
153✔
173
        } else
153✔
174
          context.addError(
153✔
175
            `Unknown service transport (${init.api!.transport})`,
153✔
176
          );
153✔
177
      });
153✔
178
    }
153✔
179
    document.invalidate();
153✔
180
    /* Add document to global registry */
153✔
181
    if (!this._allDocuments[document.id])
153✔
182
      this._allDocuments[document.id] = document;
153✔
183
  }
153✔
184

153✔
185
  /**
153✔
186
   *
153✔
187
   * @param context
153✔
188
   * @protected
153✔
189
   */
153✔
190
  protected async createBuiltinDocument(
153✔
191
    context: DocumentInitContext,
153✔
192
  ): Promise<ApiDocument> {
153✔
193
    const init: ApiDocumentFactory.InitArguments = {
153✔
194
      spec: OpraSchema.SpecVersion,
153✔
195
      url: OPRA_SPEC_URL,
153✔
196
      info: {
153✔
197
        version: OpraSchema.SpecVersion,
153✔
198
        title: 'Opra built-in types',
153✔
199
        license: {
153✔
200
          url: 'https://github.com/panates/opra/blob/main/LICENSE',
153✔
201
          name: 'MIT',
153✔
202
        },
153✔
203
      },
153✔
204
      types: [
153✔
205
        ...Object.values(primitiveTypes),
153✔
206
        ...Object.values(extendedTypes),
153✔
207
      ],
153✔
208
    };
153✔
209
    const document = new ApiDocument();
153✔
210
    document[BUILTIN] = true;
153✔
211
    const BigIntConstructor = Object.getPrototypeOf(BigInt(0)).constructor;
1✔
212
    const BufferConstructor = Object.getPrototypeOf(Buffer.from([]));
1✔
213
    const _ctorTypeMap = document.types[kCtorMap];
1✔
214
    _ctorTypeMap.set(Object, 'object');
1✔
215
    _ctorTypeMap.set(String, 'string');
1✔
216
    _ctorTypeMap.set(Number, 'number');
1✔
217
    _ctorTypeMap.set(Boolean, 'boolean');
1✔
218
    _ctorTypeMap.set(Object, 'any');
1✔
219
    _ctorTypeMap.set(Date, 'datetime');
1✔
220
    _ctorTypeMap.set(BigIntConstructor, 'bigint');
1✔
221
    _ctorTypeMap.set(ArrayBuffer, 'base64');
1✔
222
    _ctorTypeMap.set(BufferConstructor, 'base64');
1✔
223
    await this.initDocument(document, context, init);
1✔
224
    return document;
1✔
225
  }
1✔
226
}
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