@tsed/schema 8.35.0 → 8.36.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.
@@ -3,6 +3,7 @@ import { DecoratorTypes, getValue, isClass, isPlainObject, nameOf } from "@tsed/
3
3
  import { JsonSchema, SpecTypes } from "../domain/index.js";
4
4
  import { execMapper } from "../registries/JsonSchemaMapperContainer.js";
5
5
  import { getJsonEntityStore } from "../registries/JsonEntitiesContainer.js";
6
+ import { inlineRefs } from "../utils/inlineRefs.js";
6
7
  /**
7
8
  * @ignore
8
9
  */
@@ -26,25 +27,27 @@ function get(model, options) {
26
27
  CACHES.set(model, cache);
27
28
  const key = getKey(options);
28
29
  if (!cache.has(key)) {
30
+ let schema;
29
31
  if (model instanceof JsonSchema) {
30
- cache.set(key, model.toJSON(options));
31
- return cache.get(key);
32
+ schema = model.toJSON(options);
32
33
  }
33
- const entity = getJsonEntityStore(model);
34
- let mapper = "schema";
35
- if (entity.is(DecoratorTypes.PARAM)) {
36
- options = {
37
- ...options,
38
- root: true,
39
- groups: entity.schema.getGroups()
40
- };
41
- mapper = "item";
34
+ else {
35
+ const entity = getJsonEntityStore(model);
36
+ let mapper = "schema";
37
+ if (entity.is(DecoratorTypes.PARAM)) {
38
+ options = {
39
+ ...options,
40
+ root: true,
41
+ groups: entity.schema.getGroups()
42
+ };
43
+ mapper = "item";
44
+ }
45
+ schema = execMapper(mapper, [entity.schema], options);
42
46
  }
43
- const schema = execMapper(mapper, [entity.schema], options);
44
47
  if (Object.keys(getValue(options, "components.schemas", {})).length) {
45
48
  schema.definitions = options.components.schemas;
46
49
  }
47
- cache.set(key, schema);
50
+ cache.set(key, options.inlineRefs ? inlineRefs(schema) : schema);
48
51
  }
49
52
  return cache.get(key);
50
53
  }
package/lib/esm/index.js CHANGED
@@ -199,6 +199,7 @@ export * from "./utils/getJsonType.js";
199
199
  export * from "./utils/getOperationsRoutes.js";
200
200
  export * from "./utils/getOperationsStores.js";
201
201
  export * from "./utils/getPropertiesStores.js";
202
+ export * from "./utils/inlineRefs.js";
202
203
  export * from "./utils/isSuccessStatus.js";
203
204
  export * from "./utils/mapHeaders.js";
204
205
  export * from "./utils/mapOperationOptions.js";
@@ -0,0 +1,64 @@
1
+ import { isPlainObject } from "@tsed/core";
2
+ import { mergeSchema } from "./mergeSchema.js";
3
+ function getLocalReference(schema, $ref) {
4
+ if (!$ref.startsWith("#/")) {
5
+ return;
6
+ }
7
+ return $ref
8
+ .slice(2)
9
+ .split("/")
10
+ .map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~"))
11
+ .reduce((value, segment) => value?.[segment], schema);
12
+ }
13
+ function inline(value, root, resolving) {
14
+ if (Array.isArray(value)) {
15
+ return value.map((item) => inline(item, root, resolving));
16
+ }
17
+ if (!isPlainObject(value)) {
18
+ return value;
19
+ }
20
+ const { $ref, ...siblings } = value;
21
+ const target = typeof $ref === "string" && !resolving.has($ref) ? getLocalReference(root, $ref) : undefined;
22
+ if (target) {
23
+ const nextResolving = new Set(resolving).add($ref);
24
+ return {
25
+ ...inline(target, root, nextResolving),
26
+ ...inline(siblings, root, resolving)
27
+ };
28
+ }
29
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, inline(item, root, resolving)]));
30
+ }
31
+ function flattenAllOf(value) {
32
+ if (Array.isArray(value)) {
33
+ return value.map(flattenAllOf);
34
+ }
35
+ if (!isPlainObject(value)) {
36
+ return value;
37
+ }
38
+ const schema = Object.fromEntries(Object.entries(value).map(([key, item]) => [key, flattenAllOf(item)]));
39
+ if (!Array.isArray(schema.allOf)) {
40
+ return schema;
41
+ }
42
+ const { allOf, ...rest } = schema;
43
+ return allOf.reduce((merged, item) => mergeSchema(merged, item), rest);
44
+ }
45
+ function hasLocalRefs(value) {
46
+ if (Array.isArray(value)) {
47
+ return value.some(hasLocalRefs);
48
+ }
49
+ if (!isPlainObject(value)) {
50
+ return false;
51
+ }
52
+ return (typeof value.$ref === "string" && value.$ref.startsWith("#/")) || Object.values(value).some(hasLocalRefs);
53
+ }
54
+ /**
55
+ * Returns a copy of a JSON Schema with resolvable local references inlined.
56
+ * Circular and external references are preserved.
57
+ *
58
+ * @ignore
59
+ */
60
+ export function inlineRefs(schema) {
61
+ const inlined = flattenAllOf(inline(schema, schema, new Set()));
62
+ const { definitions, ...result } = inlined;
63
+ return hasLocalRefs(result) ? inlined : result;
64
+ }
@@ -60,6 +60,12 @@ export interface JsonSchemaOptions {
60
60
  * Inline enums when enum instead of using $ref.
61
61
  */
62
62
  inlineEnums?: boolean;
63
+ /**
64
+ * Inline resolvable local JSON Schema references in the compiled output.
65
+ *
66
+ * External references and circular local references are preserved.
67
+ */
68
+ inlineRefs?: boolean;
63
69
  /**
64
70
  * Explicit generic bindings used during schema compilation.
65
71
  *
@@ -12,7 +12,7 @@ import { JsonSchemaOptions } from "../domain/JsonSchemaOptions.js";
12
12
  * @param options JSON schema generation options.
13
13
  * @returns Compiled JSON schema object.
14
14
  */
15
- export declare function compile(model: Type<any> | JsonParameterStore | JsonSchema, options?: JsonSchemaOptions): any;
15
+ export declare function compile(model: Type<any> | JsonParameterStore | JsonSchema<any>, options?: JsonSchemaOptions): any;
16
16
  /**
17
17
  * @deprecated Use s.compile() instead
18
18
  * @param model
@@ -199,6 +199,7 @@ export * from "./utils/getJsonType.js";
199
199
  export * from "./utils/getOperationsRoutes.js";
200
200
  export * from "./utils/getOperationsStores.js";
201
201
  export * from "./utils/getPropertiesStores.js";
202
+ export * from "./utils/inlineRefs.js";
202
203
  export * from "./utils/isSuccessStatus.js";
203
204
  export * from "./utils/mapHeaders.js";
204
205
  export * from "./utils/mapOperationOptions.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Returns a copy of a JSON Schema with resolvable local references inlined.
3
+ * Circular and external references are preserved.
4
+ *
5
+ * @ignore
6
+ */
7
+ export declare function inlineRefs(schema: Record<string, any>): any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsed/schema",
3
- "version": "8.35.0",
3
+ "version": "8.36.0",
4
4
  "description": "JsonSchema module for Ts.ED Framework",
5
5
  "keywords": [
6
6
  "JsonSchema",
@@ -34,7 +34,7 @@
34
34
  "test:ci": "vitest run --coverage.thresholds.autoUpdate=true"
35
35
  },
36
36
  "dependencies": {
37
- "@tsed/openspec": "8.35.0",
37
+ "@tsed/openspec": "8.36.0",
38
38
  "change-case": "^5.4.4",
39
39
  "json-schema": "0.4.0",
40
40
  "picomatch": "4.0.4",
@@ -43,11 +43,11 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@apidevtools/swagger-parser": "10.1.0",
46
- "@tsed/barrels": "8.35.0",
47
- "@tsed/core": "8.35.0",
48
- "@tsed/hooks": "8.35.0",
49
- "@tsed/openspec": "8.35.0",
50
- "@tsed/typescript": "8.35.0",
46
+ "@tsed/barrels": "8.36.0",
47
+ "@tsed/core": "8.36.0",
48
+ "@tsed/hooks": "8.36.0",
49
+ "@tsed/openspec": "8.36.0",
50
+ "@tsed/typescript": "8.36.0",
51
51
  "@types/fs-extra": "11.0.4",
52
52
  "@types/json-schema": "7.0.15",
53
53
  "@types/picomatch": "3.0.2",