@e22m4u/js-openapi 0.0.5 → 0.0.7

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.
Files changed (70) hide show
  1. package/README.md +226 -146
  2. package/dist/cjs/index.cjs +2025 -2092
  3. package/package.json +10 -8
  4. package/schema/openapi-3-1/dialect/base.js +21 -0
  5. package/schema/openapi-3-1/meta/base.js +76 -0
  6. package/schema/openapi-3-1/schema-base.js +32 -0
  7. package/schema/openapi-3-1/schema.js +1403 -0
  8. package/src/ajv.js +32 -0
  9. package/src/errors/index.d.ts +1 -1
  10. package/src/errors/index.js +1 -1
  11. package/src/errors/oa-document-object-validation-error.d.ts +6 -0
  12. package/src/errors/oa-document-object-validation-error.js +6 -0
  13. package/src/errors/oa-document-object-validation-error.spec.js +10 -0
  14. package/src/index.d.ts +1 -3
  15. package/src/index.js +1 -3
  16. package/src/json-pointer/resolve-json-pointer.js +1 -1
  17. package/src/json-pointer/unescape-json-pointer.d.ts +1 -2
  18. package/src/oa-document-builder.d.ts +302 -111
  19. package/src/oa-document-builder.js +208 -142
  20. package/src/oa-document-builder.spec.js +1411 -0
  21. package/src/oa-document-object/index.d.ts +1 -1
  22. package/src/oa-document-object/index.js +1 -1
  23. package/src/oa-document-object/validate-oa-document-object.d.ts +18 -0
  24. package/src/oa-document-object/validate-oa-document-object.js +53 -0
  25. package/src/oa-document-object/validate-oa-document-object.spec.js +122 -0
  26. package/src/{oa-document-scope.d.ts → oa-operation-group.d.ts} +7 -7
  27. package/src/{oa-document-scope.js → oa-operation-group.js} +101 -46
  28. package/src/oa-operation-group.spec.js +544 -0
  29. package/src/oa-reference-object/is-oa-reference-object.js +1 -1
  30. package/src/oa-reference-object/is-oa-reference-object.spec.js +1 -1
  31. package/src/oa-reference-object/oa-ref.js +7 -0
  32. package/src/oa-reference-object/resolve-oa-reference-object.js +1 -11
  33. package/src/oa-reference-object/resolve-oa-reference-object.spec.js +0 -10
  34. package/src/oa-specification.d.ts +55 -66
  35. package/src/oa-specification.js +11 -22
  36. package/src/data-type/index.d.ts +0 -1
  37. package/src/data-type/index.js +0 -1
  38. package/src/data-type/infer-openapi-data-type.d.ts +0 -30
  39. package/src/data-type/infer-openapi-data-type.js +0 -38
  40. package/src/data-validation/data-format-validator-map.d.ts +0 -13
  41. package/src/data-validation/data-format-validator-map.js +0 -36
  42. package/src/data-validation/data-format-validator-map.spec.js +0 -39
  43. package/src/data-validation/data-format-validators.d.ts +0 -84
  44. package/src/data-validation/data-format-validators.js +0 -217
  45. package/src/data-validation/index.d.ts +0 -3
  46. package/src/data-validation/index.js +0 -3
  47. package/src/data-validation/validate-data-with-openapi-schema.d.ts +0 -46
  48. package/src/data-validation/validate-data-with-openapi-schema.js +0 -1913
  49. package/src/data-validation/validate-data-with-openapi-schema.spec.js +0 -6953
  50. package/src/errors/oa-data-validation-error.d.ts +0 -6
  51. package/src/errors/oa-data-validation-error.js +0 -6
  52. package/src/errors/oa-data-validation-error.spec.js +0 -17
  53. package/src/oa-document-object/validate-shallow-oa-document.d.ts +0 -10
  54. package/src/oa-document-object/validate-shallow-oa-document.js +0 -209
  55. package/src/oa-document-object/validate-shallow-oa-document.spec.js +0 -362
  56. package/src/utils/count-unicode.d.ts +0 -11
  57. package/src/utils/count-unicode.js +0 -15
  58. package/src/utils/index.d.ts +0 -5
  59. package/src/utils/index.js +0 -5
  60. package/src/utils/join-path.d.ts +0 -6
  61. package/src/utils/join-path.js +0 -36
  62. package/src/utils/join-path.spec.js +0 -104
  63. package/src/utils/normalize-path.d.ts +0 -12
  64. package/src/utils/normalize-path.js +0 -22
  65. package/src/utils/normalize-path.spec.js +0 -56
  66. package/src/utils/to-pascal-case.d.ts +0 -6
  67. package/src/utils/to-pascal-case.js +0 -26
  68. package/src/utils/to-pascal-case.spec.js +0 -15
  69. package/src/utils/to-spaced-json.d.ts +0 -17
  70. package/src/utils/to-spaced-json.js +0 -27
@@ -1,8 +1,8 @@
1
- import {OADocumentScope} from './oa-document-scope.js';
2
1
  import {InvalidArgumentError} from '@e22m4u/js-format';
3
- import {normalizePath} from './utils/normalize-path.js';
2
+ import {OAOperationGroup} from './oa-operation-group.js';
4
3
  import {isServiceContainer, Service} from '@e22m4u/js-service';
5
- import {validateShallowOADocument} from './oa-document-object/index.js';
4
+ import {validateOADocumentObject} from './oa-document-object/index.js';
5
+ import {escapeJsonPointer} from './json-pointer/escape-json-pointer.js';
6
6
  import {OPENAPI_VERSION, OAOperationMethod} from './oa-specification.js';
7
7
 
8
8
  /**
@@ -26,6 +26,11 @@ export const OAComponentType = {
26
26
  */
27
27
  export const OA_COMPONENT_TYPES = Object.values(OAComponentType);
28
28
 
29
+ /**
30
+ * Component name RegExp.
31
+ */
32
+ export const OA_COMPONENT_NAME_REGEX = /^[a-zA-Z0-9.\-_]+$/;
33
+
29
34
  /**
30
35
  * Component type to components key map.
31
36
  */
@@ -42,6 +47,23 @@ export const OA_COMPONENT_TYPE_TO_COMPONENTS_KEY_MAP = {
42
47
  [OAComponentType.PATH_ITEM]: 'pathItems',
43
48
  };
44
49
 
50
+ /**
51
+ * Component type to definition name map.
52
+ * "#/$defs/${name}"
53
+ */
54
+ export const OA_COMPONENT_TYPE_TO_DEFINITION_NAME_MAP = {
55
+ [OAComponentType.SCHEMA]: 'schema',
56
+ [OAComponentType.RESPONSE]: 'response-or-reference',
57
+ [OAComponentType.PARAMETER]: 'parameter-or-reference',
58
+ [OAComponentType.EXAMPLE]: 'example-or-reference',
59
+ [OAComponentType.REQUEST_BODY]: 'request-body-or-reference',
60
+ [OAComponentType.HEADER]: 'header-or-reference',
61
+ [OAComponentType.SECURITY_SCHEME]: 'security-scheme-or-reference',
62
+ [OAComponentType.LINK]: 'link-or-reference',
63
+ [OAComponentType.CALLBACK]: 'callbacks-or-reference',
64
+ [OAComponentType.PATH_ITEM]: 'path-item',
65
+ };
66
+
45
67
  /**
46
68
  * OpenAPI Document builder.
47
69
  */
@@ -58,84 +80,73 @@ export class OADocumentBuilder extends Service {
58
80
  title: 'API Documentation',
59
81
  version: '0.0.1',
60
82
  },
83
+ paths: {},
61
84
  };
62
85
 
63
86
  /**
64
87
  * Constructor.
65
88
  *
66
- * @param {object} [containerOrDocument]
67
- * @param {object} [document]
89
+ * @param {import('@e22m4u/js-service').ServiceContainer|import('./oa-document-builder.js').OADocumentInput} containerOrDocument
90
+ * @param {import('./oa-document-builder.js').OADocumentInput} document
68
91
  */
69
92
  constructor(containerOrDocument, document) {
70
93
  if (isServiceContainer(containerOrDocument)) {
71
94
  super(containerOrDocument);
72
95
  } else {
73
96
  super();
74
- document = containerOrDocument;
97
+ // containerOrDocument
98
+ if (containerOrDocument !== undefined) {
99
+ if (
100
+ !containerOrDocument ||
101
+ typeof containerOrDocument !== 'object' ||
102
+ Array.isArray(containerOrDocument)
103
+ ) {
104
+ throw new InvalidArgumentError(
105
+ 'Parameter "containerOrDocument" must be an Object, ' +
106
+ 'but %v was given.',
107
+ containerOrDocument,
108
+ );
109
+ }
110
+ }
111
+ document = document === undefined ? containerOrDocument : document;
75
112
  }
113
+ // document
76
114
  if (document !== undefined) {
77
- // если схема документа не является
78
- // объектом, то выбрасывается ошибка
79
115
  if (
80
116
  !document ||
81
117
  typeof document !== 'object' ||
82
118
  Array.isArray(document)
83
119
  ) {
84
120
  throw new InvalidArgumentError(
85
- 'OpenAPI Document Object must be an Object, but %v was given.',
121
+ 'Parameter "document" must be an Object, but %v was given.',
86
122
  document,
87
123
  );
88
124
  }
89
- // чтобы избежать мутации аргумента,
90
- // выполняется копирование документа
91
125
  document = structuredClone(document);
92
- // если версия OpenAPI не определена,
93
- // то устанавливается версия по умолчанию
94
- if (!document.openapi) {
95
- document.openapi = this._document.openapi;
96
- }
97
- // если Info Object не определен,
98
- // то устанавливается значение по умолчанию
99
- if (!document.info) {
100
- document.info = this._document.info;
101
- }
102
- // если свойство "info" не является
103
- // объектом, то выбрасывается ошибка
104
- if (
105
- !document.info ||
106
- typeof document.info !== 'object' ||
107
- Array.isArray(document.info)
108
- ) {
109
- throw new InvalidArgumentError(
110
- 'Property "info" must be an Object, but %v was given.',
111
- document.info,
112
- );
113
- }
114
- // если свойство "info.title" не определено,
115
- // то устанавливается значение по умолчанию
116
- if (!document.info.title) {
117
- document.info.title = this._document.info.title;
118
- }
119
- // если свойство "info.version" не определено,
120
- // то устанавливается значение по умолчанию
121
- if (!document.info.version) {
122
- document.info.version = this._document.info.version;
123
- }
124
- // поверхностная проверка свойств документа
125
- // выполняется после установки значений по умолчанию
126
- validateShallowOADocument(document);
127
- this._document = document;
126
+ this._document = {...this._document, ...document};
128
127
  }
128
+ // validate
129
+ validateOADocumentObject(this._document);
130
+ }
131
+
132
+ /**
133
+ * Get document object reference.
134
+ *
135
+ * @returns {import('./oa-specification.js').OADocumentObject}
136
+ */
137
+ getDocumentObjectRef() {
138
+ return this._document;
129
139
  }
130
140
 
131
141
  /**
132
142
  * Define component.
133
143
  *
134
144
  * @param {string} type
135
- * @param {object} definition
145
+ * @param {object} name
146
+ * @param {object} component
136
147
  * @returns {this}
137
148
  */
138
- defineComponent(type, definition) {
149
+ defineComponent(type, name, component) {
139
150
  // type
140
151
  if (!OA_COMPONENT_TYPES.includes(type)) {
141
152
  throw new InvalidArgumentError(
@@ -143,49 +154,56 @@ export class OADocumentBuilder extends Service {
143
154
  type,
144
155
  );
145
156
  }
146
- // definition
147
- if (
148
- !definition ||
149
- typeof definition !== 'object' ||
150
- Array.isArray(definition)
151
- ) {
157
+ // name
158
+ if (!name || typeof name !== 'string') {
152
159
  throw new InvalidArgumentError(
153
- 'Component definition must be an Object, but %v was given.',
154
- definition,
160
+ 'Component name must be a non-empty String, but %v was given.',
161
+ name,
155
162
  );
156
163
  }
157
- // definition.name
158
- if (!definition.name || typeof definition.name !== 'string') {
164
+ if (!OA_COMPONENT_NAME_REGEX.test(name)) {
159
165
  throw new InvalidArgumentError(
160
- 'Property "name" must be a non-empty String, but %v was given.',
161
- definition.name,
166
+ 'Component name %v contains invalid characters.',
167
+ name,
162
168
  );
163
169
  }
164
- // definition[type]
165
- const component = definition[type];
170
+ // component
166
171
  if (
167
172
  !component ||
168
173
  typeof component !== 'object' ||
169
174
  Array.isArray(component)
170
175
  ) {
171
176
  throw new InvalidArgumentError(
172
- 'Property %v must be an Object, but %v was given.',
173
- type,
177
+ 'Component %v must be an Object, but %v was given.',
178
+ name,
174
179
  component,
175
180
  );
176
181
  }
177
182
  // components key
178
- const key = OA_COMPONENT_TYPE_TO_COMPONENTS_KEY_MAP[type];
179
- if (!key) {
183
+ const componentsKey = OA_COMPONENT_TYPE_TO_COMPONENTS_KEY_MAP[type];
184
+ if (!componentsKey) {
180
185
  throw new InvalidArgumentError(
181
186
  'Component type %v does not have a reference to the components key.',
182
- type,
187
+ componentsKey,
183
188
  );
184
189
  }
190
+ // definition name
191
+ const definitionName = OA_COMPONENT_TYPE_TO_DEFINITION_NAME_MAP[type];
192
+ if (!definitionName) {
193
+ throw new InvalidArgumentError(
194
+ 'Component type %v does not have a reference to the definition name.',
195
+ definitionName,
196
+ );
197
+ }
198
+ // validation
199
+ validateOADocumentObject(component, {
200
+ schemaUri: `#/$defs/${definitionName}`,
201
+ dataSourceUri: `#/components/${componentsKey}/${escapeJsonPointer(name)}`,
202
+ });
185
203
  this._document.components = this._document.components || {};
186
- this._document.components[key] = this._document.components[key] || {};
187
- this._document.components[key][definition.name] =
188
- structuredClone(component);
204
+ this._document.components[componentsKey] =
205
+ this._document.components[componentsKey] || {};
206
+ this._document.components[componentsKey][name] = structuredClone(component);
189
207
  return this;
190
208
  }
191
209
 
@@ -197,25 +215,38 @@ export class OADocumentBuilder extends Service {
197
215
  * @returns {boolean}
198
216
  */
199
217
  hasComponent(type, name) {
218
+ // type
219
+ if (!OA_COMPONENT_TYPES.includes(type)) {
220
+ throw new InvalidArgumentError(
221
+ 'Components type %v is not supported.',
222
+ type,
223
+ );
224
+ }
200
225
  // name
201
226
  if (!name || typeof name !== 'string') {
202
227
  throw new InvalidArgumentError(
203
- 'Parameter "name" must be a non-empty String, but %v was given.',
228
+ 'Component name must be a non-empty String, but %v was given.',
229
+ name,
230
+ );
231
+ }
232
+ if (!OA_COMPONENT_NAME_REGEX.test(name)) {
233
+ throw new InvalidArgumentError(
234
+ 'Component name %v contains invalid characters.',
204
235
  name,
205
236
  );
206
237
  }
207
238
  // components key
208
- const key = OA_COMPONENT_TYPE_TO_COMPONENTS_KEY_MAP[type];
209
- if (!key) {
239
+ const componentsKey = OA_COMPONENT_TYPE_TO_COMPONENTS_KEY_MAP[type];
240
+ if (!componentsKey) {
210
241
  throw new InvalidArgumentError(
211
242
  'Component type %v does not have a reference to the components key.',
212
- type,
243
+ componentsKey,
213
244
  );
214
245
  }
215
246
  return Boolean(
216
247
  this._document.components &&
217
- this._document.components[key] &&
218
- this._document.components[key][name],
248
+ this._document.components[componentsKey] &&
249
+ this._document.components[componentsKey][name],
219
250
  );
220
251
  }
221
252
 
@@ -227,16 +258,29 @@ export class OADocumentBuilder extends Service {
227
258
  * @returns {object}
228
259
  */
229
260
  getComponent(type, name) {
261
+ // type
262
+ if (!OA_COMPONENT_TYPES.includes(type)) {
263
+ throw new InvalidArgumentError(
264
+ 'Components type %v is not supported.',
265
+ type,
266
+ );
267
+ }
230
268
  // name
231
269
  if (!name || typeof name !== 'string') {
232
270
  throw new InvalidArgumentError(
233
- 'Parameter "name" must be a non-empty String, but %v was given.',
271
+ 'Component name must be a non-empty String, but %v was given.',
272
+ name,
273
+ );
274
+ }
275
+ if (!OA_COMPONENT_NAME_REGEX.test(name)) {
276
+ throw new InvalidArgumentError(
277
+ 'Component name %v contains invalid characters.',
234
278
  name,
235
279
  );
236
280
  }
237
281
  // components key
238
- const key = OA_COMPONENT_TYPE_TO_COMPONENTS_KEY_MAP[type];
239
- if (!key) {
282
+ const componentsKey = OA_COMPONENT_TYPE_TO_COMPONENTS_KEY_MAP[type];
283
+ if (!componentsKey) {
240
284
  throw new InvalidArgumentError(
241
285
  'Component type %v does not have a reference to the components key.',
242
286
  type,
@@ -245,12 +289,12 @@ export class OADocumentBuilder extends Service {
245
289
  const component =
246
290
  this._document &&
247
291
  this._document.components &&
248
- this._document.components[key] &&
249
- this._document.components[key][name];
292
+ this._document.components[componentsKey] &&
293
+ this._document.components[componentsKey][name];
250
294
  if (!component) {
251
295
  throw new InvalidArgumentError(
252
296
  'Component "#/components/%s/%s" does not exist.',
253
- key,
297
+ componentsKey,
254
298
  name,
255
299
  );
256
300
  }
@@ -260,110 +304,122 @@ export class OADocumentBuilder extends Service {
260
304
  /**
261
305
  * Define schema component.
262
306
  *
263
- * @param {object} schemaDef
307
+ * @param {string} name
308
+ * @param {object} component
264
309
  * @returns {this}
265
310
  */
266
- defineSchemaComponent(schemaDef) {
267
- return this.defineComponent(OAComponentType.SCHEMA, schemaDef);
311
+ defineSchemaComponent(name, component) {
312
+ return this.defineComponent(OAComponentType.SCHEMA, name, component);
268
313
  }
269
314
 
270
315
  /**
271
316
  * Define response component.
272
317
  *
273
- * @param {object} responseDef
318
+ * @param {string} name
319
+ * @param {object} component
274
320
  * @returns {this}
275
321
  */
276
- defineResponseComponent(responseDef) {
277
- return this.defineComponent(OAComponentType.RESPONSE, responseDef);
322
+ defineResponseComponent(name, component) {
323
+ return this.defineComponent(OAComponentType.RESPONSE, name, component);
278
324
  }
279
325
 
280
326
  /**
281
327
  * Define parameter component.
282
328
  *
283
- * @param {object} parameterDef
329
+ * @param {string} name
330
+ * @param {object} component
284
331
  * @returns {this}
285
332
  */
286
- defineParameterComponent(parameterDef) {
287
- return this.defineComponent(OAComponentType.PARAMETER, parameterDef);
333
+ defineParameterComponent(name, component) {
334
+ return this.defineComponent(OAComponentType.PARAMETER, name, component);
288
335
  }
289
336
 
290
337
  /**
291
338
  * Define example component.
292
339
  *
293
- * @param {object} exampleDef
340
+ * @param {string} name
341
+ * @param {object} component
294
342
  * @returns {this}
295
343
  */
296
- defineExampleComponent(exampleDef) {
297
- return this.defineComponent(OAComponentType.EXAMPLE, exampleDef);
344
+ defineExampleComponent(name, component) {
345
+ return this.defineComponent(OAComponentType.EXAMPLE, name, component);
298
346
  }
299
347
 
300
348
  /**
301
349
  * Define request body component.
302
350
  *
303
- * @param {object} requestBodyDef
351
+ * @param {string} name
352
+ * @param {object} component
304
353
  * @returns {this}
305
354
  */
306
- defineRequestBodyComponent(requestBodyDef) {
307
- return this.defineComponent(OAComponentType.REQUEST_BODY, requestBodyDef);
355
+ defineRequestBodyComponent(name, component) {
356
+ return this.defineComponent(OAComponentType.REQUEST_BODY, name, component);
308
357
  }
309
358
 
310
359
  /**
311
360
  * Define header component.
312
361
  *
313
- * @param {object} headerDef
362
+ * @param {string} name
363
+ * @param {object} component
314
364
  * @returns {this}
315
365
  */
316
- defineHeaderComponent(headerDef) {
317
- return this.defineComponent(OAComponentType.HEADER, headerDef);
366
+ defineHeaderComponent(name, component) {
367
+ return this.defineComponent(OAComponentType.HEADER, name, component);
318
368
  }
319
369
 
320
370
  /**
321
371
  * Define security scheme component.
322
372
  *
323
- * @param {object} securitySchemeDef
373
+ * @param {string} name
374
+ * @param {object} component
324
375
  * @returns {this}
325
376
  */
326
- defineSecuritySchemeComponent(securitySchemeDef) {
377
+ defineSecuritySchemeComponent(name, component) {
327
378
  return this.defineComponent(
328
379
  OAComponentType.SECURITY_SCHEME,
329
- securitySchemeDef,
380
+ name,
381
+ component,
330
382
  );
331
383
  }
332
384
 
333
385
  /**
334
386
  * Define link component.
335
387
  *
336
- * @param {object} linkDef
388
+ * @param {string} name
389
+ * @param {object} component
337
390
  * @returns {this}
338
391
  */
339
- defineLinkComponent(linkDef) {
340
- return this.defineComponent(OAComponentType.LINK, linkDef);
392
+ defineLinkComponent(name, component) {
393
+ return this.defineComponent(OAComponentType.LINK, name, component);
341
394
  }
342
395
 
343
396
  /**
344
397
  * Define callback component.
345
398
  *
346
- * @param {object} callbackDef
399
+ * @param {string} name
400
+ * @param {object} component
347
401
  * @returns {this}
348
402
  */
349
- defineCallbackComponent(callbackDef) {
350
- return this.defineComponent(OAComponentType.CALLBACK, callbackDef);
403
+ defineCallbackComponent(name, component) {
404
+ return this.defineComponent(OAComponentType.CALLBACK, name, component);
351
405
  }
352
406
 
353
407
  /**
354
408
  * Define path item component.
355
409
  *
356
- * @param {object} pathItemDef
410
+ * @param {string} name
411
+ * @param {object} component
357
412
  * @returns {this}
358
413
  */
359
- definePathItemComponent(pathItemDef) {
360
- return this.defineComponent(OAComponentType.PATH_ITEM, pathItemDef);
414
+ definePathItemComponent(name, component) {
415
+ return this.defineComponent(OAComponentType.PATH_ITEM, name, component);
361
416
  }
362
417
 
363
418
  /**
364
419
  * Define operation.
365
420
  *
366
- * @param {object} operationDef
421
+ * @param {import('./oa-document-builder.js').OAOperationDefinition} operationDef
422
+ * @returns {this}
367
423
  */
368
424
  defineOperation(operationDef) {
369
425
  if (
@@ -377,56 +433,66 @@ export class OADocumentBuilder extends Service {
377
433
  );
378
434
  }
379
435
  // path
380
- if (!operationDef.path || typeof operationDef.path !== 'string') {
436
+ if (typeof operationDef.path !== 'string') {
381
437
  throw new InvalidArgumentError(
382
- 'Property "path" must be a non-empty String, but %v was given.',
438
+ 'Keyword "path" must be a String, but %v was given.',
383
439
  operationDef.path,
384
440
  );
385
441
  }
386
- // method
387
- if (!operationDef.method || typeof operationDef.method !== 'string') {
442
+ if (!operationDef.path.startsWith('/')) {
388
443
  throw new InvalidArgumentError(
389
- 'Property "method" must be a non-empty String, but %v was given.',
390
- operationDef.method,
444
+ 'Keyword "path" must start with "/", but %v was given.',
445
+ operationDef.path,
391
446
  );
392
447
  }
448
+ // method
393
449
  if (!Object.values(OAOperationMethod).includes(operationDef.method)) {
394
450
  throw new InvalidArgumentError(
395
- 'Property "method" must be one of values: %l, but %v was given.',
396
- Object.values(OAOperationMethod),
451
+ 'Keyword "method" must be one of the allowed values, but %v was given.',
452
+ operationDef.method,
397
453
  );
398
454
  }
399
455
  // operation
400
- if (
401
- !operationDef.operation ||
402
- typeof operationDef.operation !== 'object' ||
403
- Array.isArray(operationDef.operation)
404
- ) {
405
- throw new InvalidArgumentError(
406
- 'Property "operation" must be an Object, but %v was given.',
407
- operationDef.operation,
408
- );
456
+ if (operationDef.operation !== undefined) {
457
+ if (
458
+ !operationDef.operation ||
459
+ typeof operationDef.operation !== 'object' ||
460
+ Array.isArray(operationDef.operation)
461
+ ) {
462
+ throw new InvalidArgumentError(
463
+ 'Keyword "operation" must be an Object, but %v was given.',
464
+ operationDef.operation,
465
+ );
466
+ }
467
+ // validation
468
+ validateOADocumentObject(operationDef.operation, {
469
+ schemaUri: '#/$defs/operation',
470
+ dataSourceUri: `#/paths/${escapeJsonPointer(operationDef.path)}/${escapeJsonPointer(operationDef.method)}`,
471
+ });
409
472
  }
410
- const normalizedPath = normalizePath(operationDef.path);
473
+ // создание поверхностной копии определения
474
+ // операции для избежания мутации аргумента
475
+ const operation = operationDef.operation
476
+ ? structuredClone(operationDef.operation)
477
+ : {};
411
478
  if (!this._document.paths) {
412
479
  this._document.paths = {};
413
480
  }
414
- if (!this._document.paths[normalizedPath]) {
415
- this._document.paths[normalizedPath] = {};
481
+ if (!this._document.paths[operationDef.path]) {
482
+ this._document.paths[operationDef.path] = {};
416
483
  }
417
- this._document.paths[normalizedPath][operationDef.method] = structuredClone(
418
- operationDef.operation,
419
- );
484
+ this._document.paths[operationDef.path][operationDef.method] = operation;
485
+ return this;
420
486
  }
421
487
 
422
488
  /**
423
- * Create scope.
489
+ * Create operation group.
424
490
  *
425
- * @param {object} [options]
426
- * @returns {OADocumentScope}
491
+ * @param {import('./oa-operation-group.js').OAOperationGroupOptions} [options]
492
+ * @returns {OAOperationGroup}
427
493
  */
428
- createScope(options) {
429
- return new OADocumentScope(this, options);
494
+ createOperationGroup(options) {
495
+ return new OAOperationGroup(this, options);
430
496
  }
431
497
 
432
498
  /**