@rvoh/psychic 0.36.0-beta.2 → 0.37.0-beta.4

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 (79) hide show
  1. package/dist/cjs/src/bin/index.js +2 -2
  2. package/dist/cjs/src/controller/helpers/isPaginatedResult.js +5 -2
  3. package/dist/cjs/src/controller/index.js +14 -6
  4. package/dist/cjs/src/error/openapi/AttemptedToDeriveDescendentSerializersFromNonSerializer.js +16 -0
  5. package/dist/cjs/src/error/openapi/ExpectedSerializerForRendersOneOrManyOption.js +36 -0
  6. package/dist/cjs/src/error/openapi/NoSerializerFoundForRendersOneAndMany.js +16 -0
  7. package/dist/cjs/src/error/openapi/NonSerializerPassedToSerializerOpenapiRenderer.js +16 -0
  8. package/dist/cjs/src/error/openapi/NonSerializerSerializerOverrideProvided.js +23 -0
  9. package/dist/cjs/src/error/openapi/ObjectSerializerRendersOneAndManyRequireClassType.js +19 -0
  10. package/dist/cjs/src/helpers/isObject.js +12 -0
  11. package/dist/cjs/src/helpers/pathifyNestedObject.js +5 -2
  12. package/dist/cjs/src/openapi-renderer/SerializerOpenapiRenderer.js +362 -0
  13. package/dist/cjs/src/openapi-renderer/app.js +16 -15
  14. package/dist/cjs/src/openapi-renderer/body-segment.js +8 -9
  15. package/dist/cjs/src/openapi-renderer/endpoint.js +57 -103
  16. package/dist/cjs/src/openapi-renderer/helpers/allSerializersFromHandWrittenOpenapi.js +34 -0
  17. package/dist/cjs/src/openapi-renderer/helpers/allSerializersToRefsInOpenapi.js +52 -0
  18. package/dist/cjs/src/openapi-renderer/helpers/dreamAttributeOpenapiShape.js +145 -0
  19. package/dist/cjs/src/openapi-renderer/helpers/isOpenapiShorthand.js +16 -0
  20. package/dist/cjs/src/openapi-renderer/helpers/maybeNullOpenapiShorthandToOpenapiShorthand.js +17 -0
  21. package/dist/cjs/src/openapi-renderer/helpers/openapiShorthandToOpenapi.js +111 -0
  22. package/dist/cjs/src/openapi-renderer/helpers/primitiveOpenapiStatementToOpenapi.js +5 -2
  23. package/dist/cjs/src/openapi-renderer/helpers/{suppressResponseEnums.js → suppressResponseEnumsConfig.js} +2 -2
  24. package/dist/cjs/src/psychic-app/index.js +0 -1
  25. package/dist/cjs/src/server/index.js +1 -35
  26. package/dist/cjs/src/server/params.js +4 -4
  27. package/dist/esm/src/bin/index.js +1 -1
  28. package/dist/esm/src/controller/helpers/isPaginatedResult.js +1 -1
  29. package/dist/esm/src/controller/index.js +15 -7
  30. package/dist/esm/src/error/openapi/AttemptedToDeriveDescendentSerializersFromNonSerializer.js +13 -0
  31. package/dist/esm/src/error/openapi/ExpectedSerializerForRendersOneOrManyOption.js +33 -0
  32. package/dist/esm/src/error/openapi/NoSerializerFoundForRendersOneAndMany.js +13 -0
  33. package/dist/esm/src/error/openapi/NonSerializerPassedToSerializerOpenapiRenderer.js +13 -0
  34. package/dist/esm/src/error/openapi/NonSerializerSerializerOverrideProvided.js +20 -0
  35. package/dist/esm/src/error/openapi/ObjectSerializerRendersOneAndManyRequireClassType.js +16 -0
  36. package/dist/esm/src/helpers/isObject.js +9 -0
  37. package/dist/esm/src/helpers/pathifyNestedObject.js +1 -1
  38. package/dist/esm/src/openapi-renderer/SerializerOpenapiRenderer.js +356 -0
  39. package/dist/esm/src/openapi-renderer/app.js +17 -16
  40. package/dist/esm/src/openapi-renderer/body-segment.js +6 -7
  41. package/dist/esm/src/openapi-renderer/endpoint.js +58 -104
  42. package/dist/esm/src/openapi-renderer/helpers/allSerializersFromHandWrittenOpenapi.js +28 -0
  43. package/dist/esm/src/openapi-renderer/helpers/allSerializersToRefsInOpenapi.js +46 -0
  44. package/dist/esm/src/openapi-renderer/helpers/dreamAttributeOpenapiShape.js +136 -0
  45. package/dist/esm/src/openapi-renderer/helpers/isOpenapiShorthand.js +10 -0
  46. package/dist/esm/src/openapi-renderer/helpers/maybeNullOpenapiShorthandToOpenapiShorthand.js +14 -0
  47. package/dist/esm/src/openapi-renderer/helpers/openapiShorthandToOpenapi.js +102 -0
  48. package/dist/esm/src/openapi-renderer/helpers/primitiveOpenapiStatementToOpenapi.js +1 -1
  49. package/dist/esm/src/openapi-renderer/helpers/{suppressResponseEnums.js → suppressResponseEnumsConfig.js} +1 -1
  50. package/dist/esm/src/psychic-app/index.js +0 -1
  51. package/dist/esm/src/server/index.js +1 -35
  52. package/dist/esm/src/server/params.js +3 -3
  53. package/dist/types/src/controller/index.d.ts +3 -1
  54. package/dist/types/src/error/openapi/AttemptedToDeriveDescendentSerializersFromNonSerializer.d.ts +5 -0
  55. package/dist/types/src/error/openapi/ExpectedSerializerForRendersOneOrManyOption.d.ts +8 -0
  56. package/dist/types/src/error/openapi/NoSerializerFoundForRendersOneAndMany.d.ts +5 -0
  57. package/dist/types/src/error/openapi/NonSerializerPassedToSerializerOpenapiRenderer.d.ts +5 -0
  58. package/dist/types/src/error/openapi/NonSerializerSerializerOverrideProvided.d.ts +6 -0
  59. package/dist/types/src/error/openapi/ObjectSerializerRendersOneAndManyRequireClassType.d.ts +5 -0
  60. package/dist/types/src/helpers/isObject.d.ts +1 -0
  61. package/dist/types/src/openapi-renderer/SerializerOpenapiRenderer.d.ts +25 -0
  62. package/dist/types/src/openapi-renderer/body-segment.d.ts +4 -7
  63. package/dist/types/src/openapi-renderer/endpoint.d.ts +17 -21
  64. package/dist/types/src/openapi-renderer/helpers/allSerializersFromHandWrittenOpenapi.d.ts +2 -0
  65. package/dist/types/src/openapi-renderer/helpers/allSerializersToRefsInOpenapi.d.ts +2 -0
  66. package/dist/types/src/openapi-renderer/helpers/dreamAttributeOpenapiShape.d.ts +780 -0
  67. package/dist/types/src/openapi-renderer/helpers/isOpenapiShorthand.d.ts +1 -0
  68. package/dist/types/src/openapi-renderer/helpers/maybeNullOpenapiShorthandToOpenapiShorthand.d.ts +2 -0
  69. package/dist/types/src/openapi-renderer/helpers/openapiShorthandToOpenapi.d.ts +16 -0
  70. package/dist/types/src/openapi-renderer/helpers/{schemaDelimiter.d.ts → suppressResponseEnumsConfig.d.ts} +1 -1
  71. package/dist/types/src/psychic-app/index.d.ts +0 -53
  72. package/dist/types/src/server/index.d.ts +0 -1
  73. package/package.json +2 -5
  74. package/dist/cjs/src/helpers/typechecks.js +0 -20
  75. package/dist/cjs/src/openapi-renderer/helpers/schemaDelimiter.js +0 -13
  76. package/dist/esm/src/helpers/typechecks.js +0 -16
  77. package/dist/esm/src/openapi-renderer/helpers/schemaDelimiter.js +0 -7
  78. package/dist/types/src/helpers/typechecks.d.ts +0 -2
  79. package/dist/types/src/openapi-renderer/helpers/suppressResponseEnums.d.ts +0 -4
@@ -32,7 +32,7 @@ const path = __importStar(require("node:path"));
32
32
  const TypesBuilder_js_1 = __importDefault(require("../cli/helpers/TypesBuilder.js"));
33
33
  const controller_js_1 = __importDefault(require("../generate/controller.js"));
34
34
  const resource_js_1 = __importDefault(require("../generate/resource.js"));
35
- const typechecks_js_1 = require("../helpers/typechecks.js");
35
+ const isObject_js_1 = __importDefault(require("../helpers/isObject.js"));
36
36
  const app_js_1 = __importDefault(require("../openapi-renderer/app.js"));
37
37
  const index_js_1 = __importDefault(require("../psychic-app/index.js"));
38
38
  const index_js_2 = __importDefault(require("../server/index.js"));
@@ -75,7 +75,7 @@ class PsychicBin {
75
75
  for (const hook of psychicApp.specialHooks.cliSync) {
76
76
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
77
77
  const res = await hook();
78
- if ((0, typechecks_js_1.isObject)(res)) {
78
+ if ((0, isObject_js_1.default)(res)) {
79
79
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
80
80
  output = { ...output, ...res };
81
81
  }
@@ -1,10 +1,13 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.default = isPaginatedResult;
4
- const typechecks_js_1 = require("../../helpers/typechecks.js");
7
+ const isObject_js_1 = __importDefault(require("../../helpers/isObject.js"));
5
8
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
9
  function isPaginatedResult(result) {
7
- if (!(0, typechecks_js_1.isObject)(result))
10
+ if (!(0, isObject_js_1.default)(result))
8
11
  return false;
9
12
  const paginatedFields = ['currentPage', 'pageCount', 'recordCount', 'results'];
10
13
  const keys = Object.keys(result);
@@ -193,12 +193,20 @@ class PsychicController {
193
193
  session;
194
194
  config;
195
195
  action;
196
+ renderOpts;
196
197
  constructor(req, res, { config, action, }) {
197
198
  this.req = req;
198
199
  this.res = res;
199
200
  this.config = config;
200
201
  this.session = new index_js_1.default(req, res);
201
202
  this.action = action;
203
+ // TODO: read casing from Dream app config
204
+ this.renderOpts = {
205
+ casing: 'camel',
206
+ };
207
+ }
208
+ get headers() {
209
+ return this.req.headers;
202
210
  }
203
211
  get params() {
204
212
  const params = {
@@ -262,6 +270,10 @@ class PsychicController {
262
270
  return data;
263
271
  const dreamApp = dream_1.DreamApp.getOrFail();
264
272
  const psychicControllerClass = this.constructor;
273
+ // if we already have a serializer, let's just render it
274
+ if (data instanceof dream_1.DreamSerializerBuilder || data instanceof dream_1.ObjectSerializerBuilder) {
275
+ return data.render(this.defaultSerializerPassthrough, this.renderOpts);
276
+ }
265
277
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
266
278
  const lookup = exports.controllerSerializerIndex.lookupModel(this.constructor, data.constructor);
267
279
  if (lookup?.length) {
@@ -276,9 +288,7 @@ class PsychicController {
276
288
  // does not pass it into the call to DreamSerializer/ObjectSerializer,
277
289
  // then it would be lost to serializers rendered via rendersOne/Many, and SerializerRenderer
278
290
  // handles passing its passthrough data into those
279
- this.defaultSerializerPassthrough, {
280
- casing: 'camel',
281
- });
291
+ this.defaultSerializerPassthrough, this.renderOpts);
282
292
  }
283
293
  }
284
294
  else {
@@ -299,9 +309,7 @@ class PsychicController {
299
309
  // does not pass it into the call to DreamSerializer/ObjectSerializer,
300
310
  // then it would be lost to serializers rendered via rendersOne/Many, and SerializerRenderer
301
311
  // handles passing its passthrough data into those
302
- this.defaultSerializerPassthrough, {
303
- casing: 'camel',
304
- });
312
+ this.defaultSerializerPassthrough, this.renderOpts);
305
313
  }
306
314
  else {
307
315
  throw new Error(`
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_util_1 = require("node:util");
4
+ class AttemptedToDeriveDescendentSerializersFromNonSerializer extends Error {
5
+ serializer;
6
+ constructor(serializer) {
7
+ super();
8
+ this.serializer = serializer;
9
+ }
10
+ get message() {
11
+ return `
12
+ Attempted to derive descendant serializers from non serializer:
13
+ ${(0, node_util_1.inspect)(this.serializer)}`;
14
+ }
15
+ }
16
+ exports.default = AttemptedToDeriveDescendentSerializersFromNonSerializer;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class ExpectedSerializerForRendersOneOrManyOption extends Error {
4
+ rendersOneOrMany;
5
+ referencingSerializerName;
6
+ attribute;
7
+ constructor(rendersOneOrMany, referencingSerializerName, attribute) {
8
+ super();
9
+ this.rendersOneOrMany = rendersOneOrMany;
10
+ this.referencingSerializerName = referencingSerializerName;
11
+ this.attribute = attribute;
12
+ }
13
+ get message() {
14
+ const baseString = `
15
+ The \`serializer\` option on the \`${this.attribute.name}\` \`${this.rendersOneOrMany}\`
16
+ on serializer \`${this.referencingSerializerName}\``;
17
+ if (this.attribute.options?.serializer) {
18
+ return `${baseString}
19
+ specifies something other than a serializer.
20
+ It should look something like the following:
21
+
22
+ \`\`\`
23
+ .${this.rendersOneOrMany}('${this.attribute.name}', {
24
+ serializer: MySerializer
25
+ })
26
+ \`\`\`
27
+ `;
28
+ }
29
+ else {
30
+ return `${baseString}
31
+ is throwing an error.
32
+ `;
33
+ }
34
+ }
35
+ }
36
+ exports.default = ExpectedSerializerForRendersOneOrManyOption;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class NoSerializerFoundForRendersOneAndMany extends Error {
4
+ associationName;
5
+ constructor(associationName) {
6
+ super();
7
+ this.associationName = associationName;
8
+ }
9
+ get message() {
10
+ return `
11
+ Attempted to render \`rendersOne\` / \`rendersMany\`
12
+ \`${this.associationName}\`, but could not locate a
13
+ serializer.`;
14
+ }
15
+ }
16
+ exports.default = NoSerializerFoundForRendersOneAndMany;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_util_1 = require("node:util");
4
+ class NonSerializerPassedToSerializerOpenapiRenderer extends Error {
5
+ serializer;
6
+ constructor(serializer) {
7
+ super();
8
+ this.serializer = serializer;
9
+ }
10
+ get message() {
11
+ return `
12
+ Non-serializer passed to SerializerOpenapiRenderer:
13
+ ${(0, node_util_1.inspect)(this.serializer)}`;
14
+ }
15
+ }
16
+ exports.default = NonSerializerPassedToSerializerOpenapiRenderer;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_util_1 = require("node:util");
4
+ class NonSerializerSerializerOverrideProvided extends Error {
5
+ rendersAssociation;
6
+ serializer;
7
+ constructor(rendersAssociation, serializer) {
8
+ super();
9
+ this.rendersAssociation = rendersAssociation;
10
+ this.serializer = serializer;
11
+ }
12
+ get message() {
13
+ return `
14
+ Non-serializer passed to \`serializerOverride\` of a rendersOne/Many declaration:
15
+
16
+ rendersOne/Many declaration:
17
+ ${(0, node_util_1.inspect)(this.rendersAssociation)}
18
+
19
+ non-serializer passed to serializerOverride:
20
+ ${(0, node_util_1.inspect)(this.serializer)}`;
21
+ }
22
+ }
23
+ exports.default = NonSerializerSerializerOverrideProvided;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class ObjectSerializerRendersOneAndManyRequireClassType extends Error {
4
+ associationName;
5
+ constructor(associationName) {
6
+ super();
7
+ this.associationName = associationName;
8
+ }
9
+ get message() {
10
+ return `
11
+ ObjectSerializer \`rendersOne\` and \`rendersMany\`
12
+ options must include \`dreamClass\`, \`viewModelClass\`, or
13
+ \`serializer\`.
14
+
15
+ rendersOne/Many name: ${this.associationName}
16
+ `;
17
+ }
18
+ }
19
+ exports.default = ObjectSerializerRendersOneAndManyRequireClassType;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = isObject;
4
+ // also in Dream
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ function isObject(x) {
7
+ if (x === null)
8
+ return false;
9
+ if (Array.isArray(x))
10
+ return false;
11
+ return typeof x === 'object';
12
+ }
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.default = pathifyNestedObject;
4
- const typechecks_js_1 = require("./typechecks.js");
7
+ const isObject_js_1 = __importDefault(require("./isObject.js"));
5
8
  function pathifyNestedObject(obj, prefix = '') {
6
9
  return Object.keys(obj).reduce((acc, k) => {
7
10
  const pre = prefix.length ? prefix + '/' : '';
8
- if ((0, typechecks_js_1.isObject)(obj[k]))
11
+ if ((0, isObject_js_1.default)(obj[k]))
9
12
  Object.assign(acc, pathifyNestedObject(obj[k], pre + k));
10
13
  else
11
14
  acc[pre + k] = obj[k];
@@ -0,0 +1,362 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
7
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
8
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
9
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
10
+ /* eslint-disable @typescript-eslint/no-explicit-any */
11
+ const dream_1 = require("@rvoh/dream");
12
+ const node_util_1 = require("node:util");
13
+ const AttemptedToDeriveDescendentSerializersFromNonSerializer_js_1 = __importDefault(require("../error/openapi/AttemptedToDeriveDescendentSerializersFromNonSerializer.js"));
14
+ const ExpectedSerializerForRendersOneOrManyOption_js_1 = __importDefault(require("../error/openapi/ExpectedSerializerForRendersOneOrManyOption.js"));
15
+ const NonSerializerPassedToSerializerOpenapiRenderer_js_1 = __importDefault(require("../error/openapi/NonSerializerPassedToSerializerOpenapiRenderer.js"));
16
+ const NonSerializerSerializerOverrideProvided_js_1 = __importDefault(require("../error/openapi/NonSerializerSerializerOverrideProvided.js"));
17
+ const NoSerializerFoundForRendersOneAndMany_js_1 = __importDefault(require("../error/openapi/NoSerializerFoundForRendersOneAndMany.js"));
18
+ const ObjectSerializerRendersOneAndManyRequireClassType_js_1 = __importDefault(require("../error/openapi/ObjectSerializerRendersOneAndManyRequireClassType.js"));
19
+ const allSerializersFromHandWrittenOpenapi_js_1 = __importDefault(require("./helpers/allSerializersFromHandWrittenOpenapi.js"));
20
+ const allSerializersToRefsInOpenapi_js_1 = __importDefault(require("./helpers/allSerializersToRefsInOpenapi.js"));
21
+ const dreamAttributeOpenapiShape_js_1 = require("./helpers/dreamAttributeOpenapiShape.js");
22
+ const openapiShorthandToOpenapi_js_1 = __importDefault(require("./helpers/openapiShorthandToOpenapi.js"));
23
+ const NULL_OBJECT_OPENAPI = { type: 'null' };
24
+ class SerializerOpenapiRenderer {
25
+ serializer;
26
+ casing;
27
+ suppressResponseEnums;
28
+ allOfSiblings = [];
29
+ constructor(serializer, { casing = 'camel', suppressResponseEnums = false, } = {}) {
30
+ this.serializer = serializer;
31
+ if (!(0, dream_1.isDreamSerializer)(this.serializer))
32
+ throw new NonSerializerPassedToSerializerOpenapiRenderer_js_1.default(this.serializer);
33
+ this.casing = casing;
34
+ this.suppressResponseEnums = suppressResponseEnums;
35
+ }
36
+ get globalName() {
37
+ return this.serializer.globalName ?? '--unnamed--';
38
+ }
39
+ get openapiName() {
40
+ return this.serializer.openapiName ?? '--unnamed--';
41
+ }
42
+ get serializerRef() {
43
+ return {
44
+ $ref: `#/components/schemas/${this.openapiName}`,
45
+ };
46
+ }
47
+ _serializerBuilder;
48
+ get serializerBuilder() {
49
+ if (this._serializerBuilder)
50
+ return this._serializerBuilder;
51
+ this._serializerBuilder = this.serializer(undefined, undefined);
52
+ return this._serializerBuilder;
53
+ }
54
+ renderedOpenapi(alreadyExtractedDescendantSerializers = {}) {
55
+ alreadyExtractedDescendantSerializers[this.serializer.globalName] = true;
56
+ const referencedSerializersAndOpenapiSchemaBodyShorthand = this._renderedOpenapi(alreadyExtractedDescendantSerializers);
57
+ if (this.allOfSiblings.length) {
58
+ const openapi = referencedSerializersAndOpenapiSchemaBodyShorthand.openapi;
59
+ return {
60
+ ...referencedSerializersAndOpenapiSchemaBodyShorthand,
61
+ openapi: {
62
+ allOf: [openapi, ...this.allOfSiblings],
63
+ },
64
+ };
65
+ }
66
+ else {
67
+ return referencedSerializersAndOpenapiSchemaBodyShorthand;
68
+ }
69
+ }
70
+ _renderedOpenapi(alreadyExtractedDescendantSerializers) {
71
+ const referencedSerializersAndAttributes = this.renderedOpenapiAttributes(alreadyExtractedDescendantSerializers);
72
+ const requiredProperties = (0, dream_1.compact)(this.serializerBuilder['attributes'].map(attribute => {
73
+ const attributeType = attribute.type;
74
+ switch (attributeType) {
75
+ case 'attribute': {
76
+ return attribute.options?.as ?? attribute.name;
77
+ }
78
+ case 'delegatedAttribute': {
79
+ return attribute.options?.as ?? attribute.name;
80
+ }
81
+ case 'customAttribute': {
82
+ return attribute.options.flatten ? null : attribute.name;
83
+ }
84
+ case 'rendersOne': {
85
+ return attribute.options.flatten ? null : (attribute.options?.as ?? attribute.name);
86
+ }
87
+ case 'rendersMany': {
88
+ return attribute.options?.as ?? attribute.name;
89
+ }
90
+ default: {
91
+ // protection so that if a new ValidationType is ever added, this will throw a type error at build time
92
+ const _never = attributeType;
93
+ throw new Error(`Unhandled serializer attribute type: ${_never}`);
94
+ }
95
+ }
96
+ }));
97
+ return {
98
+ referencedSerializers: referencedSerializersAndAttributes.referencedSerializers,
99
+ openapi: {
100
+ type: 'object',
101
+ required: (0, dream_1.sort)((0, dream_1.uniq)(requiredProperties.map(property => this.setCase(property)))),
102
+ properties: (0, dream_1.sortObjectByKey)(referencedSerializersAndAttributes.attributes),
103
+ },
104
+ };
105
+ }
106
+ renderedOpenapiAttributes(alreadyExtractedDescendantSerializers = {}) {
107
+ const $typeForOpenapi = this.serializerBuilder['$typeForOpenapi'];
108
+ const DataTypeForOpenapi = $typeForOpenapi;
109
+ let referencedSerializers = [];
110
+ let renderedOpenapi = {};
111
+ const openapiRenderingOpts = {
112
+ casing: this.casing,
113
+ suppressResponseEnums: this.suppressResponseEnums,
114
+ };
115
+ renderedOpenapi = this.serializerBuilder['attributes'].reduce((accumulator, attribute) => {
116
+ const attributeType = attribute.type;
117
+ let newlyReferencedSerializers = [];
118
+ accumulator = (() => {
119
+ switch (attributeType) {
120
+ ////////////////
121
+ // attributes //
122
+ ////////////////
123
+ case 'attribute': {
124
+ const outputAttributeName = this.setCase(attribute.options?.as ?? attribute.name);
125
+ const openapi = attribute.options.openapi;
126
+ newlyReferencedSerializers = (0, allSerializersFromHandWrittenOpenapi_js_1.default)(openapi);
127
+ accumulator[outputAttributeName] = DataTypeForOpenapi?.isDream
128
+ ? (0, dreamAttributeOpenapiShape_js_1.dreamColumnOpenapiShape)(DataTypeForOpenapi, attribute.name, openapi, {
129
+ suppressResponseEnums: this.suppressResponseEnums,
130
+ })
131
+ : (0, allSerializersToRefsInOpenapi_js_1.default)((0, openapiShorthandToOpenapi_js_1.default)(openapi));
132
+ return accumulator;
133
+ }
134
+ /////////////////////
135
+ // end: attributes //
136
+ /////////////////////
137
+ ///////////////////////
138
+ // custom attributes //
139
+ ///////////////////////
140
+ case 'customAttribute': {
141
+ const outputAttributeName = this.setCase(attribute.name);
142
+ const openapi = attribute.options.openapi;
143
+ newlyReferencedSerializers = (0, allSerializersFromHandWrittenOpenapi_js_1.default)(openapi);
144
+ if (attribute.options.flatten) {
145
+ this.allOfSiblings.push((0, allSerializersToRefsInOpenapi_js_1.default)((0, openapiShorthandToOpenapi_js_1.default)(openapi)));
146
+ }
147
+ else {
148
+ accumulator[outputAttributeName] = (0, allSerializersToRefsInOpenapi_js_1.default)((0, openapiShorthandToOpenapi_js_1.default)(openapi));
149
+ }
150
+ return accumulator;
151
+ }
152
+ ////////////////////////////
153
+ // end: custom attributes //
154
+ ////////////////////////////
155
+ //////////////////////////
156
+ // delegated attributes //
157
+ //////////////////////////
158
+ case 'delegatedAttribute': {
159
+ const outputAttributeName = this.setCase(attribute.options?.as ?? attribute.name);
160
+ const openapi = attribute.options.openapi;
161
+ newlyReferencedSerializers = (0, allSerializersFromHandWrittenOpenapi_js_1.default)(openapi);
162
+ accumulator[outputAttributeName] = (0, allSerializersToRefsInOpenapi_js_1.default)((0, openapiShorthandToOpenapi_js_1.default)(openapi));
163
+ return accumulator;
164
+ }
165
+ ///////////////////////////////
166
+ // end: delegated attributes //
167
+ ///////////////////////////////
168
+ //////////////////
169
+ // rendersOnes //
170
+ //////////////////
171
+ case 'rendersOne': {
172
+ try {
173
+ const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
174
+ const referencedSerializersAndOpenapiSchemaBodyShorthand = associationOpenapi(attribute, DataTypeForOpenapi, alreadyExtractedDescendantSerializers, openapiRenderingOpts);
175
+ newlyReferencedSerializers =
176
+ referencedSerializersAndOpenapiSchemaBodyShorthand.referencedSerializers;
177
+ if (attribute.options.flatten && attribute.options.optional) {
178
+ this.allOfSiblings.push({
179
+ anyOf: [referencedSerializersAndOpenapiSchemaBodyShorthand.openapi, NULL_OBJECT_OPENAPI],
180
+ });
181
+ //
182
+ }
183
+ else if (attribute.options.flatten) {
184
+ this.allOfSiblings.push(referencedSerializersAndOpenapiSchemaBodyShorthand.openapi);
185
+ //
186
+ }
187
+ else if (attribute.options.optional) {
188
+ accumulator[outputAttributeName] = {
189
+ anyOf: [referencedSerializersAndOpenapiSchemaBodyShorthand.openapi, NULL_OBJECT_OPENAPI],
190
+ };
191
+ }
192
+ else {
193
+ accumulator[outputAttributeName] = referencedSerializersAndOpenapiSchemaBodyShorthand.openapi;
194
+ }
195
+ return accumulator;
196
+ }
197
+ catch (error) {
198
+ if (error instanceof CallingSerializersThrewError)
199
+ return accumulator;
200
+ if (error instanceof AttemptedToDeriveDescendentSerializersFromNonSerializer_js_1.default)
201
+ throw new ExpectedSerializerForRendersOneOrManyOption_js_1.default('rendersOne', this.globalName, attribute);
202
+ throw error;
203
+ }
204
+ }
205
+ ///////////////////////
206
+ // end: rendersOnes //
207
+ ///////////////////////
208
+ ///////////////////
209
+ // rendersManys //
210
+ ///////////////////
211
+ case 'rendersMany': {
212
+ try {
213
+ const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
214
+ const referencedSerializersAndOpenapiSchemaBodyShorthand = associationOpenapi(attribute, DataTypeForOpenapi, alreadyExtractedDescendantSerializers, openapiRenderingOpts);
215
+ newlyReferencedSerializers =
216
+ referencedSerializersAndOpenapiSchemaBodyShorthand.referencedSerializers;
217
+ accumulator[outputAttributeName] = {
218
+ type: 'array',
219
+ items: referencedSerializersAndOpenapiSchemaBodyShorthand.openapi,
220
+ };
221
+ return accumulator;
222
+ }
223
+ catch (error) {
224
+ if (error instanceof CallingSerializersThrewError)
225
+ return accumulator;
226
+ if (error instanceof AttemptedToDeriveDescendentSerializersFromNonSerializer_js_1.default)
227
+ throw new ExpectedSerializerForRendersOneOrManyOption_js_1.default('rendersMany', this.globalName, attribute);
228
+ throw error;
229
+ }
230
+ }
231
+ ////////////////////////
232
+ // end: rendersManys //
233
+ ////////////////////////
234
+ default: {
235
+ // protection so that if a new ValidationType is ever added, this will throw a type error at build time
236
+ const _never = attributeType;
237
+ throw new Error(`Unhandled serializer attribute type: ${_never}`);
238
+ }
239
+ }
240
+ })();
241
+ const recursiveNewlyReferencedSerializers = newlyReferencedSerializers.flatMap(serializer => descendantSerializers(serializer, alreadyExtractedDescendantSerializers, openapiRenderingOpts));
242
+ referencedSerializers = [
243
+ ...referencedSerializers,
244
+ ...newlyReferencedSerializers,
245
+ ...recursiveNewlyReferencedSerializers,
246
+ ];
247
+ return accumulator;
248
+ }, renderedOpenapi);
249
+ return {
250
+ referencedSerializers: (0, dream_1.uniq)(referencedSerializers, serializer => serializer.globalName),
251
+ attributes: renderedOpenapi,
252
+ };
253
+ }
254
+ setCase(attr) {
255
+ switch (this.casing) {
256
+ case 'camel':
257
+ return attr;
258
+ case 'snake':
259
+ return (0, dream_1.snakeify)(attr);
260
+ default: {
261
+ // protection so that if a new Casing is ever added, this will throw a type error at build time
262
+ const _never = this.casing;
263
+ throw new Error(`Unhandled Casing: ${_never}`);
264
+ }
265
+ }
266
+ }
267
+ }
268
+ exports.default = SerializerOpenapiRenderer;
269
+ function associationOpenapi(attribute, DataTypeForOpenapi, alreadyExtractedDescendantSerializers, opts) {
270
+ const serializerOverride = attribute.options.serializer;
271
+ if (serializerOverride) {
272
+ try {
273
+ return {
274
+ referencedSerializers: [
275
+ serializerOverride,
276
+ ...descendantSerializers(serializerOverride, alreadyExtractedDescendantSerializers, opts),
277
+ ],
278
+ openapi: new SerializerOpenapiRenderer(serializerOverride, opts).serializerRef,
279
+ };
280
+ }
281
+ catch (error) {
282
+ if (error instanceof NonSerializerPassedToSerializerOpenapiRenderer_js_1.default)
283
+ throw new NonSerializerSerializerOverrideProvided_js_1.default(attribute, serializerOverride);
284
+ throw error;
285
+ }
286
+ }
287
+ let associatedClasses;
288
+ const association = DataTypeForOpenapi?.isDream &&
289
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
290
+ DataTypeForOpenapi['getAssociationMetadata'](attribute.name);
291
+ if (association) {
292
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
293
+ associatedClasses = (0, dream_1.expandStiClasses)(association.modelCB());
294
+ //
295
+ }
296
+ else {
297
+ const associatedClass = attribute.options.dreamClass ?? attribute.options.viewModelClass;
298
+ if (associatedClass === undefined) {
299
+ let serializerCheck;
300
+ try {
301
+ ;
302
+ DataTypeForOpenapi?.prototype?.serializers;
303
+ }
304
+ catch {
305
+ throw new CallingSerializersThrewError();
306
+ }
307
+ if (serializerCheck)
308
+ throw new ObjectSerializerRendersOneAndManyRequireClassType_js_1.default(attribute.name);
309
+ throw new ObjectSerializerRendersOneAndManyRequireClassType_js_1.default(attribute.name);
310
+ }
311
+ if (associatedClass?.isDream) {
312
+ associatedClasses = (0, dream_1.expandStiClasses)(associatedClass);
313
+ }
314
+ else {
315
+ associatedClasses = [associatedClass];
316
+ }
317
+ }
318
+ const serializersOpenapi = associatedClasses.flatMap(associatedClass => (0, dream_1.inferSerializersFromDreamClassOrViewModelClass)(associatedClass, attribute.options.serializerKey));
319
+ if (serializersOpenapi.length === 0)
320
+ throw new NoSerializerFoundForRendersOneAndMany_js_1.default(attribute.name);
321
+ if (serializersOpenapi.length === 1) {
322
+ const serializer = serializersOpenapi[0];
323
+ return {
324
+ referencedSerializers: [
325
+ serializer,
326
+ ...descendantSerializers(serializer, alreadyExtractedDescendantSerializers, opts),
327
+ ],
328
+ openapi: new SerializerOpenapiRenderer(serializer, opts).serializerRef,
329
+ };
330
+ }
331
+ return {
332
+ referencedSerializers: [
333
+ ...serializersOpenapi,
334
+ ...serializersOpenapi.flatMap(serializer => descendantSerializers(serializer, alreadyExtractedDescendantSerializers, opts)),
335
+ ],
336
+ openapi: {
337
+ anyOf: (0, dream_1.sortBy)((0, dream_1.uniq)(serializersOpenapi.map(serializer => new SerializerOpenapiRenderer(serializer, opts).serializerRef), ref => ref['$ref']), ref => (ref['$ref'] ? ref['$ref'] : (0, node_util_1.inspect)(ref, { depth: 2 }))),
338
+ },
339
+ };
340
+ }
341
+ function descendantSerializers(serializer, alreadyExtractedDescendantSerializers, opts) {
342
+ // alreadyExtractedDescendantSerializers is used not only to avoid duplicate
343
+ // work (and thereby speed up OpenAPI spec generation), but also to avoid
344
+ // infinite loops (a recursive OpenAPI structure is valid)
345
+ if (alreadyExtractedDescendantSerializers[serializer.globalName])
346
+ return [];
347
+ if (!(0, dream_1.isDreamSerializer)(serializer))
348
+ throw new AttemptedToDeriveDescendentSerializersFromNonSerializer_js_1.default(serializer);
349
+ const immediateDescendantSerializers = new SerializerOpenapiRenderer(serializer, opts).renderedOpenapi(alreadyExtractedDescendantSerializers).referencedSerializers;
350
+ return [
351
+ ...immediateDescendantSerializers,
352
+ ...immediateDescendantSerializers.flatMap(descendantSerializer => descendantSerializers(descendantSerializer, alreadyExtractedDescendantSerializers, opts)),
353
+ ];
354
+ }
355
+ // When attempting to expand STI children, we might call `.serializers` on
356
+ // an instance that throws an error just by calling `.serializers` (so that
357
+ // they can be sure to define serializers on the STI children, but in this
358
+ // case, there might be STI children that are intermediaries to the intended
359
+ // STI children, so they don't have serializers and calling `.serializers`
360
+ // throws an error)
361
+ class CallingSerializersThrewError extends Error {
362
+ }