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

oprajs / opra / 14419802659

12 Apr 2025 12:55PM UTC coverage: 82.088% (+4.2%) from 77.908%
14419802659

push

github

web-flow
Merge pull request #27 from oprajs/dev

Dev

3458 of 4432 branches covered (78.02%)

Branch coverage included in aggregate %.

16 of 16 new or added lines in 10 files covered. (100.0%)

1793 existing lines in 129 files now uncovered.

29424 of 35625 relevant lines covered (82.59%)

183.2 hits per line

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

93.31
/packages/common/src/document/api-document.ts
1
import { omitUndefined } from '@jsopen/objects';
1✔
2
import { md5 } from 'super-fast-md5';
1✔
3
import type { Mutable, Type } from 'ts-gems';
1✔
4
import { cloneObject, ResponsiveMap } from '../helpers/index.js';
1✔
5
import { OpraSchema } from '../schema/index.js';
1✔
6
import { DataTypeMap } from './common/data-type-map.js';
1✔
7
import { DocumentElement } from './common/document-element.js';
1✔
8
import {
1✔
9
  BUILTIN,
1✔
10
  kDataTypeMap,
1✔
11
  kTypeNSMap,
1✔
12
  NAMESPACE_PATTERN,
1✔
13
} from './constants.js';
1✔
14
import { DataType } from './data-type/data-type.js';
1✔
15
import type { EnumType } from './data-type/enum-type.js';
1✔
16
import { HttpApi } from './http/http-api.js';
1✔
17
import { RpcApi } from './rpc/rpc-api.js';
1✔
18

1✔
19
/**
1✔
20
 *
1✔
21
 * @class ApiDocument
1✔
22
 */
1✔
23
export class ApiDocument extends DocumentElement {
1✔
24
  protected [kTypeNSMap] = new WeakMap<DataType, string>();
1✔
25
  readonly id: string = '';
1✔
26
  url?: string;
1✔
27
  info: OpraSchema.DocumentInfo = {};
1✔
28
  references = new ResponsiveMap<ApiDocument>();
1✔
29
  types = new DataTypeMap();
1✔
30
  api?: HttpApi | RpcApi;
1✔
31

1✔
32
  constructor() {
1✔
33
    super(null as any);
260✔
34
    this.node[kDataTypeMap] = this.types;
260✔
35
    this.node.findDataType = this._findDataType.bind(this);
260✔
36
  }
260✔
37

1✔
38
  /**
1✔
39
   * Returns NS of datatype. Returns undefined if not found
1✔
40
   * @param nameOrCtor
1✔
41
   */
1✔
42
  getDataTypeNs(
1✔
43
    nameOrCtor:
4,149✔
44
      | string
4,149✔
45
      | Type
4,149✔
46
      | Function
4,149✔
47
      | EnumType.EnumArray
4,149✔
48
      | EnumType.EnumObject
4,149✔
49
      | DataType,
4,149✔
50
  ): string | undefined {
4,149✔
51
    const dt =
4,149✔
52
      nameOrCtor instanceof DataType
4,149✔
53
        ? this._findDataType(nameOrCtor.name || '')
4,146!
54
        : this._findDataType(nameOrCtor);
3✔
55
    if (dt) return this[kTypeNSMap].get(dt);
4,149✔
56
  }
4,149✔
57

1✔
58
  findDocument(id: string): ApiDocument | undefined {
1✔
59
    if (this.id === id) return this;
2!
60
    for (const doc of this.references.values()) {
2✔
61
      if (doc.id === id) return doc;
2✔
62
      const d = doc.findDocument(id);
1✔
63
      if (d) return d;
2!
64
    }
2✔
65
  }
1✔
66

1✔
67
  get httpApi(): HttpApi {
1✔
68
    if (!(this.api && this.api instanceof HttpApi)) {
105!
69
      throw new TypeError('The document do not contains HttpApi instance');
×
UNCOV
70
    }
×
71
    return this.api as HttpApi;
105✔
72
  }
105✔
73

1✔
74
  get rpcApi(): RpcApi {
1✔
75
    if (!(this.api && this.api instanceof RpcApi)) {
23!
76
      throw new TypeError('The document do not contains RpcApi instance');
×
UNCOV
77
    }
×
78
    return this.api as RpcApi;
23✔
79
  }
23✔
80

1✔
81
  toJSON(): OpraSchema.ApiDocument {
1✔
82
    return this.export();
×
UNCOV
83
  }
×
84

1✔
85
  /**
1✔
86
   * Export as Opra schema definition object
1✔
87
   */
1✔
88
  export(options?: ApiDocument.ExportOptions): OpraSchema.ApiDocument {
1✔
89
    const out = omitUndefined<OpraSchema.ApiDocument>({
267✔
90
      spec: OpraSchema.SpecVersion,
267✔
91
      id: this.id,
267✔
92
      url: this.url,
267✔
93
      info: cloneObject(this.info, true),
267✔
94
    });
267✔
95
    if (this.references.size) {
267✔
96
      let i = 0;
138✔
97
      const references: Record<string, OpraSchema.DocumentReference> = {};
138✔
98
      for (const [ns, doc] of this.references.entries()) {
138✔
99
        if (doc[BUILTIN]) continue;
174✔
100
        references[ns] = {
36✔
101
          id: doc.id,
36✔
102
          url: doc.url,
36✔
103
          info: cloneObject(doc.info, true),
36✔
104
        };
36✔
105
        i++;
36✔
106
      }
36✔
107
      if (i) out.references = references;
138✔
108
    }
138✔
109
    if (this.types.size) {
267✔
110
      out.types = {};
227✔
111
      for (const v of this.types.values()) {
227✔
112
        if (!v.inScope(options?.scope)) continue;
3,002✔
113
        out.types[v.name!] = v.toJSON(options);
2,992✔
114
      }
2,992✔
115
    }
227✔
116
    if (this.api) out.api = this.api.toJSON(options);
267✔
117
    return out;
267✔
118
  }
267✔
119

1✔
120
  invalidate(): void {
1✔
121
    /** Generate id */
260✔
122
    const x = this.export({});
260✔
123
    delete (x as any).id;
260✔
124
    (this as Mutable<ApiDocument>).id = md5(JSON.stringify(x));
260✔
125
    /** Clear [kTypeNSMap] */
260✔
126
    this[kTypeNSMap] = new WeakMap<DataType, string>();
260✔
127
  }
260✔
128

1✔
129
  protected _findDataType(
1✔
130
    nameOrCtor:
24,903✔
131
      | string
24,903✔
132
      | Type
24,903✔
133
      | Function
24,903✔
134
      | EnumType.EnumArray
24,903✔
135
      | EnumType.EnumObject,
24,903✔
136
    scope?: string,
24,903✔
137
    visitedRefs?: WeakMap<ApiDocument, boolean>,
24,903✔
138
  ): DataType | undefined {
24,903✔
139
    let result = this.types.get(nameOrCtor);
24,903✔
140
    if (result && result.inScope(scope)) return result;
24,903✔
141
    if (!this.references.size) return;
24,903✔
142
    // Lookup for references
10,901✔
143
    if (typeof nameOrCtor === 'string') {
24,903✔
144
      // If given string has namespace pattern (ns:type_name)
6,472✔
145
      const m = NAMESPACE_PATTERN.exec(nameOrCtor);
6,472✔
146
      if (m) {
6,472✔
147
        const ns = m[1];
17✔
148
        if (ns) {
17✔
149
          const ref = this.references.get(ns);
17✔
150
          if (!ref) return;
17!
151
          visitedRefs = visitedRefs || new WeakMap<ApiDocument, boolean>();
17✔
152
          visitedRefs.set(this, true);
17✔
153
          visitedRefs.set(ref, true);
17✔
154
          return ref._findDataType(m[2], scope, visitedRefs);
17✔
155
        }
17!
156
        nameOrCtor = m[2];
×
UNCOV
157
      }
×
158
    }
6,472✔
159

10,884✔
160
    // if not found, search in references (from last to first)
10,884✔
161
    visitedRefs = visitedRefs || new WeakMap<ApiDocument, boolean>();
24,903✔
162
    visitedRefs.set(this, true);
24,903✔
163
    const references = Array.from(this.references.keys()).reverse();
24,903✔
164
    /** First step, lookup for own types */
24,903✔
165
    for (const refNs of references) {
24,903✔
166
      const ref = this.references.get(refNs);
14,939✔
167
      result = ref?.types.get(nameOrCtor);
14,939✔
168
      if (result) {
14,939✔
169
        this[kTypeNSMap].set(result, ref?.[BUILTIN] ? '' : refNs);
6,922✔
170
        return result;
6,922✔
171
      }
6,922✔
172
    }
14,939✔
173
    /** If not found lookup for child references */
3,962✔
174
    for (const refNs of references) {
24,903✔
175
      const ref = this.references.get(refNs);
5,532✔
176
      visitedRefs.set(ref!, true);
5,532✔
177
      result = ref!._findDataType(nameOrCtor, scope, visitedRefs);
5,532✔
178
      if (result) {
5,532✔
179
        this[kTypeNSMap].set(result, ref?.[BUILTIN] ? '' : refNs);
27!
180
        return result;
27✔
181
      }
27✔
182
    }
5,532✔
183
  }
3,935✔
184
}
1✔
185

1✔
186
export namespace ApiDocument {
1✔
187
  export interface ExportOptions {
1✔
188
    scope?: string;
1✔
189
  }
1✔
190
}
1✔
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