@opra/common 1.4.4 → 1.5.0

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 (120) hide show
  1. package/browser/index.cjs +5 -5
  2. package/browser/index.mjs +5 -5
  3. package/cjs/document/api-document.js +13 -8
  4. package/cjs/document/common/api-base.js +2 -1
  5. package/cjs/document/common/document-init-context.js +5 -0
  6. package/cjs/document/common/document-node.js +25 -29
  7. package/cjs/document/common/value.js +6 -2
  8. package/cjs/document/constants.js +1 -2
  9. package/cjs/document/data-type/api-field.js +16 -3
  10. package/cjs/document/data-type/complex-type-base.js +12 -3
  11. package/cjs/document/data-type/complex-type.js +12 -5
  12. package/cjs/document/data-type/data-type.js +16 -1
  13. package/cjs/document/data-type/enum-type.js +9 -2
  14. package/cjs/document/data-type/extended-types/base64.type.js +1 -0
  15. package/cjs/document/data-type/extended-types/date-string.type.js +1 -0
  16. package/cjs/document/data-type/extended-types/date-time-string.type.js +1 -0
  17. package/cjs/document/data-type/extended-types/date-time.type.js +1 -0
  18. package/cjs/document/data-type/extended-types/date.type.js +1 -0
  19. package/cjs/document/data-type/extended-types/email.type.js +1 -0
  20. package/cjs/document/data-type/extended-types/field-path.type.js +6 -2
  21. package/cjs/document/data-type/extended-types/filter.type.js +11 -4
  22. package/cjs/document/data-type/extended-types/object-id.type.js +1 -0
  23. package/cjs/document/data-type/extended-types/operation-result.type.js +1 -0
  24. package/cjs/document/data-type/extended-types/time.type.js +1 -0
  25. package/cjs/document/data-type/extended-types/url.type.js +1 -0
  26. package/cjs/document/data-type/extended-types/uuid.type.js +1 -0
  27. package/cjs/document/data-type/mapped-type.js +6 -3
  28. package/cjs/document/data-type/mixin-type.js +7 -4
  29. package/cjs/document/data-type/primitive-types/any.type.js +1 -0
  30. package/cjs/document/data-type/primitive-types/bigint.type.js +1 -0
  31. package/cjs/document/data-type/primitive-types/boolean.type.js +1 -0
  32. package/cjs/document/data-type/primitive-types/integer.type.js +1 -0
  33. package/cjs/document/data-type/primitive-types/null.type.js +1 -0
  34. package/cjs/document/data-type/primitive-types/number.type.js +1 -0
  35. package/cjs/document/data-type/primitive-types/string.type.js +1 -0
  36. package/cjs/document/data-type/simple-type.js +10 -3
  37. package/cjs/document/decorators/complex-type.decorator.js +1 -1
  38. package/cjs/document/decorators/simple-type.decorator.js +1 -1
  39. package/cjs/document/factory/api-document.factory.js +1 -0
  40. package/cjs/document/http/http-api.js +2 -2
  41. package/cjs/document/http/http-controller.js +5 -5
  42. package/cjs/document/http/http-media-type.js +3 -3
  43. package/cjs/document/http/http-multipart-field.js +2 -2
  44. package/cjs/document/http/http-operation-response.js +3 -3
  45. package/cjs/document/http/http-operation.js +5 -5
  46. package/cjs/document/http/http-parameter.js +2 -2
  47. package/cjs/document/http/http-request-body.js +4 -2
  48. package/cjs/filter/filter-rules.js +5 -4
  49. package/esm/document/api-document.js +13 -8
  50. package/esm/document/common/api-base.js +2 -1
  51. package/esm/document/common/document-init-context.js +5 -0
  52. package/esm/document/common/document-node.js +25 -29
  53. package/esm/document/common/value.js +6 -2
  54. package/esm/document/constants.js +0 -1
  55. package/esm/document/data-type/api-field.js +16 -3
  56. package/esm/document/data-type/complex-type-base.js +12 -3
  57. package/esm/document/data-type/complex-type.js +12 -5
  58. package/esm/document/data-type/data-type.js +16 -1
  59. package/esm/document/data-type/enum-type.js +9 -2
  60. package/esm/document/data-type/extended-types/base64.type.js +1 -0
  61. package/esm/document/data-type/extended-types/date-string.type.js +1 -0
  62. package/esm/document/data-type/extended-types/date-time-string.type.js +1 -0
  63. package/esm/document/data-type/extended-types/date-time.type.js +1 -0
  64. package/esm/document/data-type/extended-types/date.type.js +1 -0
  65. package/esm/document/data-type/extended-types/email.type.js +1 -0
  66. package/esm/document/data-type/extended-types/field-path.type.js +6 -2
  67. package/esm/document/data-type/extended-types/filter.type.js +11 -4
  68. package/esm/document/data-type/extended-types/object-id.type.js +1 -0
  69. package/esm/document/data-type/extended-types/operation-result.type.js +1 -0
  70. package/esm/document/data-type/extended-types/time.type.js +1 -0
  71. package/esm/document/data-type/extended-types/url.type.js +1 -0
  72. package/esm/document/data-type/extended-types/uuid.type.js +1 -0
  73. package/esm/document/data-type/mapped-type.js +6 -3
  74. package/esm/document/data-type/mixin-type.js +7 -4
  75. package/esm/document/data-type/primitive-types/any.type.js +1 -0
  76. package/esm/document/data-type/primitive-types/bigint.type.js +1 -0
  77. package/esm/document/data-type/primitive-types/boolean.type.js +1 -0
  78. package/esm/document/data-type/primitive-types/integer.type.js +1 -0
  79. package/esm/document/data-type/primitive-types/null.type.js +1 -0
  80. package/esm/document/data-type/primitive-types/number.type.js +1 -0
  81. package/esm/document/data-type/primitive-types/string.type.js +1 -0
  82. package/esm/document/data-type/simple-type.js +10 -3
  83. package/esm/document/decorators/complex-type.decorator.js +2 -2
  84. package/esm/document/decorators/simple-type.decorator.js +2 -2
  85. package/esm/document/factory/api-document.factory.js +1 -0
  86. package/esm/document/http/http-api.js +2 -2
  87. package/esm/document/http/http-controller.js +5 -5
  88. package/esm/document/http/http-media-type.js +3 -3
  89. package/esm/document/http/http-multipart-field.js +2 -2
  90. package/esm/document/http/http-operation-response.js +3 -3
  91. package/esm/document/http/http-operation.js +5 -5
  92. package/esm/document/http/http-parameter.js +2 -2
  93. package/esm/document/http/http-request-body.js +4 -2
  94. package/esm/filter/filter-rules.js +5 -4
  95. package/package.json +1 -1
  96. package/types/document/api-document.d.ts +8 -2
  97. package/types/document/common/api-base.d.ts +1 -1
  98. package/types/document/common/document-init-context.d.ts +2 -0
  99. package/types/document/common/document-node.d.ts +8 -14
  100. package/types/document/common/value.d.ts +2 -1
  101. package/types/document/constants.d.ts +0 -1
  102. package/types/document/data-type/api-field.d.ts +6 -11
  103. package/types/document/data-type/complex-type.d.ts +2 -1
  104. package/types/document/data-type/data-type.d.ts +7 -2
  105. package/types/document/data-type/enum-type.d.ts +2 -1
  106. package/types/document/data-type/extended-types/field-path.type.d.ts +2 -1
  107. package/types/document/data-type/extended-types/filter.type.d.ts +2 -1
  108. package/types/document/data-type/mapped-type.d.ts +2 -1
  109. package/types/document/data-type/mixin-type.d.ts +2 -1
  110. package/types/document/data-type/simple-type.d.ts +2 -1
  111. package/types/document/factory/api-document.factory.d.ts +2 -1
  112. package/types/document/http/http-api.d.ts +1 -1
  113. package/types/document/http/http-controller.d.ts +2 -1
  114. package/types/document/http/http-media-type.d.ts +2 -1
  115. package/types/document/http/http-multipart-field.d.ts +2 -1
  116. package/types/document/http/http-operation-response.d.ts +2 -1
  117. package/types/document/http/http-operation.d.ts +2 -1
  118. package/types/document/http/http-parameter.d.ts +2 -1
  119. package/types/document/http/http-request-body.d.ts +2 -1
  120. package/types/filter/filter-rules.d.ts +3 -3
@@ -20,6 +20,7 @@ let BooleanType = class BooleanType {
20
20
  exports.BooleanType = BooleanType;
21
21
  exports.BooleanType = BooleanType = tslib_1.__decorate([
22
22
  (0, simple_type_js_1.SimpleType)({
23
+ name: 'boolean',
23
24
  description: 'Simple true/false value',
24
25
  nameMappings: {
25
26
  js: 'boolean',
@@ -27,6 +27,7 @@ let IntegerType = class IntegerType extends number_type_js_1.NumberType {
27
27
  exports.IntegerType = IntegerType;
28
28
  exports.IntegerType = IntegerType = tslib_1.__decorate([
29
29
  (0, simple_type_js_1.SimpleType)({
30
+ name: 'integer',
30
31
  description: 'An integer number',
31
32
  nameMappings: {
32
33
  js: 'number',
@@ -20,6 +20,7 @@ let NullType = class NullType {
20
20
  exports.NullType = NullType;
21
21
  exports.NullType = NullType = tslib_1.__decorate([
22
22
  (0, simple_type_js_1.SimpleType)({
23
+ name: 'null',
23
24
  description: 'A Null value',
24
25
  nameMappings: {
25
26
  js: 'null',
@@ -39,6 +39,7 @@ tslib_1.__decorate([
39
39
  ], NumberType.prototype, "maxValue", void 0);
40
40
  exports.NumberType = NumberType = tslib_1.__decorate([
41
41
  (0, simple_type_js_1.SimpleType)({
42
+ name: 'number',
42
43
  description: 'Both Integer as well as Floating-Point numbers',
43
44
  nameMappings: {
44
45
  js: 'number',
@@ -59,6 +59,7 @@ tslib_1.__decorate([
59
59
  ], StringType.prototype, "maxLength", void 0);
60
60
  exports.StringType = StringType = tslib_1.__decorate([
61
61
  (0, simple_type_js_1.SimpleType)({
62
+ name: 'string',
62
63
  description: 'A sequence of characters',
63
64
  nameMappings: {
64
65
  js: 'string',
@@ -83,20 +83,27 @@ class SimpleTypeClass extends data_type_js_1.DataType {
83
83
  }
84
84
  return valgen_1.isAny;
85
85
  }
86
- toJSON() {
86
+ toJSON(options) {
87
87
  const attributes = (0, objects_1.omitUndefined)(this.ownAttributes);
88
88
  let properties;
89
89
  if (this.properties && typeof this.properties.toJSON === 'function') {
90
- properties = this.properties.toJSON(this.properties, this.owner);
90
+ properties = this.properties.toJSON(this.properties, this.owner, options);
91
91
  }
92
92
  else
93
93
  properties = this.properties ? (0, index_js_1.cloneObject)(this.properties) : {};
94
94
  const baseName = this.base
95
95
  ? this.node.getDataTypeNameWithNs(this.base)
96
96
  : undefined;
97
+ if (options?.scopes && !this.base?.inScope(options?.scopes))
98
+ throw new TypeError(`Base type ${baseName ? '(' + baseName + ')' : ''} of ${this.name ? +this.name : 'embedded'} type ` +
99
+ `is not in required scope(s) [${options.scopes}`);
97
100
  const out = (0, objects_1.omitUndefined)({
98
101
  ...data_type_js_1.DataType.prototype.toJSON.apply(this),
99
- base: this.base ? (baseName ? baseName : this.base.toJSON()) : undefined,
102
+ base: this.base
103
+ ? baseName
104
+ ? baseName
105
+ : this.base.toJSON(options)
106
+ : undefined,
100
107
  attributes: attributes && Object.keys(attributes).length ? attributes : undefined,
101
108
  properties: Object.keys(properties).length ? properties : undefined,
102
109
  });
@@ -14,7 +14,7 @@ function ComplexTypeDecorator(options) {
14
14
  name = options.name;
15
15
  }
16
16
  else {
17
- name = target.name.match(constants_js_1.EXTRACT_TYPENAME_PATTERN)?.[1] || target.name;
17
+ name = target.name;
18
18
  }
19
19
  }
20
20
  let metadata = Reflect.getOwnMetadata(constants_js_1.DATATYPE_METADATA, target);
@@ -18,7 +18,7 @@ function SimpleTypeDecoratorFactory(options) {
18
18
  name = options.name;
19
19
  }
20
20
  else {
21
- name = target.name.match(constants_js_1.EXTRACT_TYPENAME_PATTERN)?.[1] || target.name;
21
+ name = target.name;
22
22
  name = name.toLowerCase();
23
23
  }
24
24
  }
@@ -30,6 +30,7 @@ class ApiDocumentFactory {
30
30
  : new document_init_context_js_1.DocumentInitContext(options);
31
31
  try {
32
32
  const document = new api_document_js_1.ApiDocument();
33
+ document.scopes = context.scopes;
33
34
  await factory.initDocument(document, context, schemaOrUrl);
34
35
  if (context.error.details.length)
35
36
  throw context.error;
@@ -23,7 +23,7 @@ class HttpApi extends api_base_js_1.ApiBase {
23
23
  const controller = this.findController(arg0);
24
24
  return controller?.operations.get(operationName);
25
25
  }
26
- toJSON() {
26
+ toJSON(options) {
27
27
  const schema = super.toJSON();
28
28
  const out = {
29
29
  ...schema,
@@ -32,7 +32,7 @@ class HttpApi extends api_base_js_1.ApiBase {
32
32
  controllers: {},
33
33
  };
34
34
  for (const v of this.controllers.values()) {
35
- out.controllers[v.name] = v.toJSON();
35
+ out.controllers[v.name] = v.toJSON(options);
36
36
  }
37
37
  return out;
38
38
  }
@@ -115,7 +115,7 @@ class HttpControllerClass extends document_element_js_1.DocumentElement {
115
115
  /**
116
116
  *
117
117
  */
118
- toJSON() {
118
+ toJSON(options) {
119
119
  const out = (0, objects_1.omitUndefined)({
120
120
  kind: this.kind,
121
121
  description: this.description,
@@ -124,25 +124,25 @@ class HttpControllerClass extends document_element_js_1.DocumentElement {
124
124
  if (this.operations.size) {
125
125
  out.operations = {};
126
126
  for (const v of this.operations.values()) {
127
- out.operations[v.name] = v.toJSON();
127
+ out.operations[v.name] = v.toJSON(options);
128
128
  }
129
129
  }
130
130
  if (this.controllers.size) {
131
131
  out.controllers = {};
132
132
  for (const v of this.controllers.values()) {
133
- out.controllers[v.name] = v.toJSON();
133
+ out.controllers[v.name] = v.toJSON(options);
134
134
  }
135
135
  }
136
136
  if (this.types.size) {
137
137
  out.types = {};
138
138
  for (const v of this.types.values()) {
139
- out.types[v.name] = v.toJSON();
139
+ out.types[v.name] = v.toJSON(options);
140
140
  }
141
141
  }
142
142
  if (this.parameters.length) {
143
143
  out.parameters = [];
144
144
  for (const prm of this.parameters) {
145
- out.parameters.push(prm.toJSON());
145
+ out.parameters.push(prm.toJSON(options));
146
146
  }
147
147
  }
148
148
  return out;
@@ -52,7 +52,7 @@ class HttpMediaTypeClass extends document_element_js_1.DocumentElement {
52
52
  }
53
53
  }
54
54
  }
55
- toJSON() {
55
+ toJSON(options) {
56
56
  const typeName = this.type
57
57
  ? this.node.getDataTypeNameWithNs(this.type)
58
58
  : undefined;
@@ -60,7 +60,7 @@ class HttpMediaTypeClass extends document_element_js_1.DocumentElement {
60
60
  description: this.description,
61
61
  contentType: this.contentType,
62
62
  contentEncoding: this.contentEncoding,
63
- type: typeName ? typeName : this.type?.toJSON(),
63
+ type: typeName ? typeName : this.type?.toJSON(options),
64
64
  isArray: this.isArray,
65
65
  example: this.example,
66
66
  examples: this.examples,
@@ -71,7 +71,7 @@ class HttpMediaTypeClass extends document_element_js_1.DocumentElement {
71
71
  maxTotalFileSize: this.maxTotalFileSize,
72
72
  });
73
73
  if (this.multipartFields?.length) {
74
- out.multipartFields = this.multipartFields.map(x => x.toJSON());
74
+ out.multipartFields = this.multipartFields.map(x => x.toJSON(options));
75
75
  }
76
76
  return out;
77
77
  }
@@ -20,12 +20,12 @@ class HttpMultipartField extends http_media_type_js_1.HttpMediaType {
20
20
  this.fieldType = initArgs.fieldType;
21
21
  this.required = initArgs.required;
22
22
  }
23
- toJSON() {
23
+ toJSON(options) {
24
24
  return (0, objects_1.omitUndefined)({
25
25
  fieldName: this.fieldName,
26
26
  fieldType: this.fieldType,
27
27
  required: this.required,
28
- ...super.toJSON(),
28
+ ...super.toJSON(options),
29
29
  });
30
30
  }
31
31
  }
@@ -26,10 +26,10 @@ class HttpOperationResponse extends http_media_type_js_1.HttpMediaType {
26
26
  }
27
27
  }
28
28
  }
29
- toJSON() {
29
+ toJSON(options) {
30
30
  const statusCode = this.statusCode.map(x => x.toJSON());
31
31
  const out = (0, objects_1.omitUndefined)({
32
- ...super.toJSON(),
32
+ ...super.toJSON(options),
33
33
  statusCode: statusCode.length === 1 && typeof statusCode[0] === 'number'
34
34
  ? statusCode[0]
35
35
  : statusCode,
@@ -38,7 +38,7 @@ class HttpOperationResponse extends http_media_type_js_1.HttpMediaType {
38
38
  if (this.parameters.length) {
39
39
  out.parameters = [];
40
40
  for (const prm of this.parameters) {
41
- out.parameters.push(prm.toJSON());
41
+ out.parameters.push(prm.toJSON(options));
42
42
  }
43
43
  }
44
44
  return out;
@@ -71,7 +71,7 @@ class HttpOperationClass extends document_element_js_1.DocumentElement {
71
71
  }
72
72
  return this.path || '/';
73
73
  }
74
- toJSON() {
74
+ toJSON(options) {
75
75
  const out = (0, objects_1.omitUndefined)({
76
76
  kind: index_js_2.OpraSchema.HttpOperation.Kind,
77
77
  description: this.description,
@@ -79,22 +79,22 @@ class HttpOperationClass extends document_element_js_1.DocumentElement {
79
79
  path: this.path,
80
80
  mergePath: this.mergePath,
81
81
  composition: this.composition,
82
- requestBody: this.requestBody?.toJSON(),
82
+ requestBody: this.requestBody?.toJSON(options),
83
83
  });
84
84
  if (this.types.size) {
85
85
  out.types = {};
86
86
  for (const v of this.types.values()) {
87
- out.types[v.name] = v.toJSON();
87
+ out.types[v.name] = v.toJSON(options);
88
88
  }
89
89
  }
90
90
  if (this.parameters.length) {
91
91
  out.parameters = [];
92
92
  for (const prm of this.parameters) {
93
- out.parameters.push(prm.toJSON());
93
+ out.parameters.push(prm.toJSON(options));
94
94
  }
95
95
  }
96
96
  if (this.responses.length)
97
- out.responses = this.responses.map(r => r.toJSON());
97
+ out.responses = this.responses.map(r => r.toJSON(options));
98
98
  return out;
99
99
  }
100
100
  }
@@ -33,9 +33,9 @@ exports.HttpParameter = function (owner, initArgs) {
33
33
  * @class HttpParameter
34
34
  */
35
35
  class HttpParameterClass extends value_js_1.Value {
36
- toJSON() {
36
+ toJSON(options) {
37
37
  return (0, objects_1.omitUndefined)({
38
- ...super.toJSON(),
38
+ ...super.toJSON(options),
39
39
  name: this.name,
40
40
  location: this.location,
41
41
  arraySeparator: this.arraySeparator,
@@ -11,12 +11,14 @@ class HttpRequestBody extends document_element_js_1.DocumentElement {
11
11
  super(owner);
12
12
  this.content = [];
13
13
  }
14
- toJSON() {
14
+ toJSON(options) {
15
15
  return (0, objects_1.omitUndefined)({
16
16
  description: this.description,
17
17
  required: this.required,
18
18
  maxContentSize: this.maxContentSize,
19
- content: this.content.length ? this.content.map(x => x.toJSON()) : [],
19
+ content: this.content.length
20
+ ? this.content.map(x => x.toJSON(options))
21
+ : [],
20
22
  partial: this.partial,
21
23
  allowPatchOperators: this.allowPatchOperators,
22
24
  });
@@ -32,11 +32,12 @@ class FilterRules {
32
32
  operators,
33
33
  }));
34
34
  }
35
- normalizeFilter(filter, currentType) {
35
+ normalizeFilter(filter, currentType, element) {
36
36
  const ast = typeof filter === 'string' ? (0, parse_js_1.parse)(filter) : filter;
37
- return this.normalizeFilterAst(ast, [], currentType);
37
+ const doc = element?.node.getDocument();
38
+ return this.normalizeFilterAst(ast, [], currentType, doc?.scopes);
38
39
  }
39
- normalizeFilterAst(ast, stack, currentType) {
40
+ normalizeFilterAst(ast, stack, currentType, scopes) {
40
41
  if (ast instanceof index_js_4.ComparisonExpression) {
41
42
  stack.push(ast);
42
43
  this.normalizeFilterAst(ast.left, stack, currentType);
@@ -128,9 +129,9 @@ class FilterRules {
128
129
  decoder = this._decoderCache.get(comp.left.field);
129
130
  if (!decoder) {
130
131
  decoder = comp.left.field.type.generateCodec('decode', {
132
+ scope: scopes,
131
133
  projection: '*',
132
134
  ignoreWriteonlyFields: true,
133
- ignoreHiddenFields: true,
134
135
  coerce: true,
135
136
  });
136
137
  this._decoderCache.set(comp.left.field, decoder);
@@ -64,13 +64,14 @@ export class ApiDocument extends DocumentElement {
64
64
  /**
65
65
  * Export as Opra schema definition object
66
66
  */
67
- export() {
67
+ export(options) {
68
68
  const out = omitUndefined({
69
69
  spec: OpraSchema.SpecVersion,
70
70
  id: this.id,
71
71
  url: this.url,
72
72
  info: cloneObject(this.info, true),
73
73
  });
74
+ options = options || { scopes: this.scopes };
74
75
  if (this.references.size) {
75
76
  let i = 0;
76
77
  const references = {};
@@ -90,25 +91,29 @@ export class ApiDocument extends DocumentElement {
90
91
  if (this.types.size) {
91
92
  out.types = {};
92
93
  for (const v of this.types.values()) {
93
- out.types[v.name] = v.toJSON();
94
+ if (!v.inScope(options.scopes))
95
+ continue;
96
+ out.types[v.name] = v.toJSON(options);
94
97
  }
95
98
  }
96
99
  if (this.api)
97
- out.api = this.api.toJSON();
100
+ out.api = this.api.toJSON(options);
98
101
  return out;
99
102
  }
100
103
  invalidate() {
101
104
  /** Generate id */
102
- const x = this.export();
105
+ const x = this.export({});
103
106
  delete x.id;
104
107
  this.id = md5(JSON.stringify(x));
105
108
  /** Clear [kTypeNSMap] */
106
109
  this[kTypeNSMap] = new WeakMap();
107
110
  }
108
- _findDataType(nameOrCtor, visitedRefs) {
111
+ _findDataType(nameOrCtor, scope, visitedRefs) {
109
112
  let result = this.types.get(nameOrCtor);
110
- if (result || !this.references.size)
113
+ if (result && result.inScope(scope))
111
114
  return result;
115
+ if (!this.references.size)
116
+ return;
112
117
  // Lookup for references
113
118
  if (typeof nameOrCtor === 'string') {
114
119
  // If given string has namespace pattern (ns:type_name)
@@ -122,7 +127,7 @@ export class ApiDocument extends DocumentElement {
122
127
  visitedRefs = visitedRefs || new WeakMap();
123
128
  visitedRefs.set(this, true);
124
129
  visitedRefs.set(ref, true);
125
- return ref._findDataType(m[2], visitedRefs);
130
+ return ref._findDataType(m[2], scope, visitedRefs);
126
131
  }
127
132
  nameOrCtor = m[2];
128
133
  }
@@ -144,7 +149,7 @@ export class ApiDocument extends DocumentElement {
144
149
  for (const refNs of references) {
145
150
  const ref = this.references.get(refNs);
146
151
  visitedRefs.set(ref, true);
147
- result = ref._findDataType(nameOrCtor, visitedRefs);
152
+ result = ref._findDataType(nameOrCtor, scope, visitedRefs);
148
153
  if (result) {
149
154
  this[kTypeNSMap].set(result, ref?.[BUILTIN] ? '' : refNs);
150
155
  return result;
@@ -8,7 +8,8 @@ export class ApiBase extends DocumentElement {
8
8
  this.name = init.name;
9
9
  this.description = init.description;
10
10
  }
11
- toJSON() {
11
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
12
+ toJSON(options) {
12
13
  return omitUndefined({
13
14
  transport: this.transport,
14
15
  name: this.name,
@@ -6,6 +6,11 @@ export class DocumentInitContext {
6
6
  this.showErrorDetails = true;
7
7
  this.maxErrors = options?.maxErrors || 0;
8
8
  this.error.message = '';
9
+ this.scopes = options?.scopes
10
+ ? Array.isArray(options.scopes)
11
+ ? options?.scopes
12
+ : [options?.scopes]
13
+ : undefined;
9
14
  }
10
15
  addError(error) {
11
16
  if (!this.error.details.length) {
@@ -18,25 +18,24 @@ export class DocumentNode {
18
18
  // istanbul ignore next
19
19
  throw new Error('ApiDocument not found in document tree');
20
20
  }
21
- hasDataType(nameOrCtor) {
22
- const result = this[kDataTypeMap]?.has(nameOrCtor);
23
- if (result)
24
- return result;
25
- return this.parent ? this.parent.hasDataType(nameOrCtor) : false;
21
+ hasDataType(nameOrCtor, scope) {
22
+ return !!this.findDataType(nameOrCtor, scope);
26
23
  }
27
- findDataType(nameOrCtor) {
28
- const result = this[kDataTypeMap]?.get(nameOrCtor);
29
- if (result)
30
- return result;
31
- return this.parent ? this.parent.findDataType(nameOrCtor) : undefined;
24
+ findDataType(nameOrCtor, scope) {
25
+ scope = scope || this.getDocument().scopes;
26
+ const dt = this[kDataTypeMap]?.get(nameOrCtor);
27
+ if (dt && dt.inScope(scope))
28
+ return dt;
29
+ return this.parent
30
+ ? this.parent.findDataType(nameOrCtor, scope)
31
+ : undefined;
32
32
  }
33
33
  /**
34
34
  * Returns DataType instance by name or Constructor. Returns undefined if not found
35
- * @param nameOrCtor
36
35
  */
37
- getDataType(nameOrCtor) {
36
+ getDataType(nameOrCtor, scope) {
38
37
  const dt = this.findDataType(nameOrCtor);
39
- if (dt)
38
+ if (dt && dt.inScope(scope))
40
39
  return dt;
41
40
  let name = '';
42
41
  if (typeof nameOrCtor === 'function') {
@@ -53,7 +52,9 @@ export class DocumentNode {
53
52
  else if (typeof nameOrCtor === 'function')
54
53
  name = nameOrCtor.name;
55
54
  }
56
- throw new TypeError(`Unknown data type` + (name ? ' (' + name + ')' : ''));
55
+ if (dt)
56
+ throw new TypeError(`Data type${name ? ' (' + name + ')' : ''} is not in requested scope (${scope})`);
57
+ throw new TypeError(`Unknown data type${name ? ' (' + name + ')' : ''}`);
57
58
  }
58
59
  getDataTypeNameWithNs(dataType) {
59
60
  if (!dataType.name)
@@ -65,10 +66,9 @@ export class DocumentNode {
65
66
  * Returns ComplexType instance by name or Constructor.
66
67
  * Returns undefined if not found
67
68
  * Throws error if data type is not a ComplexType
68
- * @param nameOrCtor
69
69
  */
70
- getComplexType(nameOrCtor) {
71
- const t = this.getDataType(nameOrCtor);
70
+ getComplexType(nameOrCtor, scope) {
71
+ const t = this.getDataType(nameOrCtor, scope);
72
72
  if (t.kind === OpraSchema.ComplexType.Kind)
73
73
  return t;
74
74
  throw new TypeError(`Data type "${t.name}" is not a ComplexType`);
@@ -77,10 +77,9 @@ export class DocumentNode {
77
77
  * Returns SimpleType instance by name or Constructor.
78
78
  * Returns undefined if not found
79
79
  * Throws error if data type is not a SimpleType
80
- * @param nameOrCtor
81
80
  */
82
- getSimpleType(nameOrCtor) {
83
- const t = this.getDataType(nameOrCtor);
81
+ getSimpleType(nameOrCtor, scope) {
82
+ const t = this.getDataType(nameOrCtor, scope);
84
83
  if (t.kind === OpraSchema.SimpleType.Kind)
85
84
  return t;
86
85
  throw new TypeError(`Data type "${t.name || t}" is not a SimpleType`);
@@ -89,10 +88,9 @@ export class DocumentNode {
89
88
  * Returns EnumType instance by name or Constructor.
90
89
  * Returns undefined if not found
91
90
  * Throws error if data type is not a EnumType
92
- * @param nameOrCtor
93
91
  */
94
- getEnumType(nameOrCtor) {
95
- const t = this.getDataType(nameOrCtor);
92
+ getEnumType(nameOrCtor, scope) {
93
+ const t = this.getDataType(nameOrCtor, scope);
96
94
  if (t.kind === OpraSchema.EnumType.Kind)
97
95
  return t;
98
96
  throw new TypeError(`Data type "${t.name || t}" is not a EnumType`);
@@ -101,10 +99,9 @@ export class DocumentNode {
101
99
  * Returns EnumType instance by name or Constructor.
102
100
  * Returns undefined if not found
103
101
  * Throws error if data type is not a MappedType
104
- * @param nameOrCtor
105
102
  */
106
- getMappedType(nameOrCtor) {
107
- const t = this.getDataType(nameOrCtor);
103
+ getMappedType(nameOrCtor, scope) {
104
+ const t = this.getDataType(nameOrCtor, scope);
108
105
  if (t.kind === OpraSchema.MappedType.Kind)
109
106
  return t;
110
107
  throw new TypeError(`Data type "${t.name || t}" is not a MappedType`);
@@ -113,10 +110,9 @@ export class DocumentNode {
113
110
  * Returns EnumType instance by name or Constructor.
114
111
  * Returns undefined if not found
115
112
  * Throws error if data type is not a MixinType
116
- * @param nameOrCtor
117
113
  */
118
- getMixinType(nameOrCtor) {
119
- const t = this.getDataType(nameOrCtor);
114
+ getMixinType(nameOrCtor, scope) {
115
+ const t = this.getDataType(nameOrCtor, scope);
120
116
  if (t.kind === OpraSchema.MixinType.Kind)
121
117
  return t;
122
118
  throw new TypeError(`Data type "${t.name || t}" is not a MixinType`);
@@ -17,12 +17,16 @@ export const Value = function (owner, initArgs) {
17
17
  * @class Value
18
18
  */
19
19
  class ValueClass extends DocumentElement {
20
- toJSON() {
20
+ toJSON(options) {
21
21
  const typeName = this.type
22
22
  ? this.node.getDataTypeNameWithNs(this.type)
23
23
  : undefined;
24
24
  return omitUndefined({
25
- type: this.type ? (typeName ? typeName : this.type.toJSON()) : 'any',
25
+ type: this.type
26
+ ? typeName
27
+ ? typeName
28
+ : this.type.toJSON(options)
29
+ : 'any',
26
30
  description: this.description,
27
31
  isArray: this.isArray,
28
32
  examples: this.examples,
@@ -7,7 +7,6 @@ export const DECORATOR = Symbol.for('DECORATOR');
7
7
  export const BUILTIN = Symbol.for('BUILTIN');
8
8
  export const NAMESPACE_PATTERN = /([a-z$_]\w+):(.+)/i;
9
9
  export const CLASS_NAME_PATTERN = /^[a-z][\w_]*$/i;
10
- export const EXTRACT_TYPENAME_PATTERN = /^(.*)Type(\d*)$/;
11
10
  export const kDataTypeMap = Symbol.for('kDataTypeMap');
12
11
  export const kCtorMap = Symbol.for('kCtorMap');
13
12
  export const kTypeNSMap = Symbol.for('kTypeNSMap');
@@ -25,6 +25,7 @@ export const ApiField = function (...args) {
25
25
  throw new Error('Field origin should be one of ComplexType, MappedType or MixinType');
26
26
  }
27
27
  _this.origin = origin;
28
+ _this.scopes = initArgs.scopes;
28
29
  _this.type = initArgs.type || owner.node.getDataType('any');
29
30
  _this.description = initArgs.description;
30
31
  _this.isArray = initArgs.isArray;
@@ -38,19 +39,31 @@ export const ApiField = function (...args) {
38
39
  _this.readonly = initArgs.readonly;
39
40
  _this.writeonly = initArgs.writeonly;
40
41
  _this.examples = initArgs.examples;
41
- _this.hidden = initArgs.hidden;
42
42
  };
43
43
  /**
44
44
  *
45
45
  * @class ApiField
46
46
  */
47
47
  class ApiFieldClass extends DocumentElement {
48
- toJSON() {
48
+ inScope(scopes) {
49
+ if (!this.scopes?.length || !scopes)
50
+ return true;
51
+ /** this.scope should match all required scopes */
52
+ scopes = Array.isArray(scopes) ? scopes : [scopes];
53
+ for (const scope of scopes) {
54
+ if (!this.scopes.some(s => {
55
+ return typeof s === 'string' ? scope === s : s.test(scope);
56
+ }))
57
+ return false;
58
+ }
59
+ return true;
60
+ }
61
+ toJSON(options) {
49
62
  const typeName = this.type
50
63
  ? this.node.getDataTypeNameWithNs(this.type)
51
64
  : undefined;
52
65
  return omitUndefined({
53
- type: typeName ? typeName : this.type?.toJSON(),
66
+ type: typeName ? typeName : this.type?.toJSON(options),
54
67
  description: this.description,
55
68
  isArray: this.isArray || undefined,
56
69
  default: this.default,
@@ -146,12 +146,21 @@ class ComplexTypeBaseClass extends DataType {
146
146
  const schema = {};
147
147
  const { currentPath, projection } = context;
148
148
  const pickList = !!(projection && Object.values(projection).find(p => !p.sign));
149
+ const scope = context.scope
150
+ ? Array.isArray(context.scope)
151
+ ? context.scope
152
+ : [context.scope]
153
+ : undefined;
149
154
  // Process fields
150
155
  let fieldName;
151
156
  for (const field of this.fields.values()) {
152
- if ((context.ignoreReadonlyFields && field.readonly) ||
153
- (context.ignoreWriteonlyFields && field.writeonly) ||
154
- (context.ignoreHiddenFields && field.hidden)) {
157
+ if (
158
+ /** Ignore field if required scope(s) do not match field scopes */
159
+ (scope && !field.inScope(scope)) ||
160
+ /** Ignore field if readonly and ignoreReadonlyFields option true */
161
+ (context.ignoreReadonlyFields && field.readonly) ||
162
+ /** Ignore field if writeonly and ignoreWriteonlyFields option true */
163
+ (context.ignoreWriteonlyFields && field.writeonly)) {
155
164
  schema[field.name] = vg.isUndefined({ coerce: true });
156
165
  continue;
157
166
  }