@rvoh/psychic 0.37.0-beta.3 → 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 (60) 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/error/openapi/AttemptedToDeriveDescendentSerializersFromNonSerializer.js +16 -0
  4. package/dist/cjs/src/error/openapi/ExpectedSerializerForRendersOneOrManyOption.js +36 -0
  5. package/dist/cjs/src/error/openapi/NoSerializerFoundForRendersOneAndMany.js +16 -0
  6. package/dist/cjs/src/error/openapi/NonSerializerPassedToSerializerOpenapiRenderer.js +16 -0
  7. package/dist/cjs/src/error/openapi/NonSerializerSerializerOverrideProvided.js +23 -0
  8. package/dist/cjs/src/error/openapi/ObjectSerializerRendersOneAndManyRequireClassType.js +19 -0
  9. package/dist/cjs/src/helpers/isObject.js +12 -0
  10. package/dist/cjs/src/helpers/pathifyNestedObject.js +5 -2
  11. package/dist/cjs/src/openapi-renderer/SerializerOpenapiRenderer.js +362 -0
  12. package/dist/cjs/src/openapi-renderer/body-segment.js +5 -3
  13. package/dist/cjs/src/openapi-renderer/endpoint.js +6 -5
  14. package/dist/cjs/src/openapi-renderer/helpers/allSerializersFromHandWrittenOpenapi.js +34 -0
  15. package/dist/cjs/src/openapi-renderer/helpers/allSerializersToRefsInOpenapi.js +52 -0
  16. package/dist/cjs/src/openapi-renderer/helpers/dreamAttributeOpenapiShape.js +145 -0
  17. package/dist/cjs/src/openapi-renderer/helpers/isOpenapiShorthand.js +16 -0
  18. package/dist/cjs/src/openapi-renderer/helpers/maybeNullOpenapiShorthandToOpenapiShorthand.js +17 -0
  19. package/dist/cjs/src/openapi-renderer/helpers/openapiShorthandToOpenapi.js +111 -0
  20. package/dist/cjs/src/openapi-renderer/helpers/primitiveOpenapiStatementToOpenapi.js +5 -2
  21. package/dist/cjs/src/server/params.js +4 -4
  22. package/dist/esm/src/bin/index.js +1 -1
  23. package/dist/esm/src/controller/helpers/isPaginatedResult.js +1 -1
  24. package/dist/esm/src/error/openapi/AttemptedToDeriveDescendentSerializersFromNonSerializer.js +13 -0
  25. package/dist/esm/src/error/openapi/ExpectedSerializerForRendersOneOrManyOption.js +33 -0
  26. package/dist/esm/src/error/openapi/NoSerializerFoundForRendersOneAndMany.js +13 -0
  27. package/dist/esm/src/error/openapi/NonSerializerPassedToSerializerOpenapiRenderer.js +13 -0
  28. package/dist/esm/src/error/openapi/NonSerializerSerializerOverrideProvided.js +20 -0
  29. package/dist/esm/src/error/openapi/ObjectSerializerRendersOneAndManyRequireClassType.js +16 -0
  30. package/dist/esm/src/helpers/isObject.js +9 -0
  31. package/dist/esm/src/helpers/pathifyNestedObject.js +1 -1
  32. package/dist/esm/src/openapi-renderer/SerializerOpenapiRenderer.js +356 -0
  33. package/dist/esm/src/openapi-renderer/body-segment.js +3 -1
  34. package/dist/esm/src/openapi-renderer/endpoint.js +2 -1
  35. package/dist/esm/src/openapi-renderer/helpers/allSerializersFromHandWrittenOpenapi.js +28 -0
  36. package/dist/esm/src/openapi-renderer/helpers/allSerializersToRefsInOpenapi.js +46 -0
  37. package/dist/esm/src/openapi-renderer/helpers/dreamAttributeOpenapiShape.js +136 -0
  38. package/dist/esm/src/openapi-renderer/helpers/isOpenapiShorthand.js +10 -0
  39. package/dist/esm/src/openapi-renderer/helpers/maybeNullOpenapiShorthandToOpenapiShorthand.js +14 -0
  40. package/dist/esm/src/openapi-renderer/helpers/openapiShorthandToOpenapi.js +102 -0
  41. package/dist/esm/src/openapi-renderer/helpers/primitiveOpenapiStatementToOpenapi.js +1 -1
  42. package/dist/esm/src/server/params.js +3 -3
  43. package/dist/types/src/error/openapi/AttemptedToDeriveDescendentSerializersFromNonSerializer.d.ts +5 -0
  44. package/dist/types/src/error/openapi/ExpectedSerializerForRendersOneOrManyOption.d.ts +8 -0
  45. package/dist/types/src/error/openapi/NoSerializerFoundForRendersOneAndMany.d.ts +5 -0
  46. package/dist/types/src/error/openapi/NonSerializerPassedToSerializerOpenapiRenderer.d.ts +5 -0
  47. package/dist/types/src/error/openapi/NonSerializerSerializerOverrideProvided.d.ts +6 -0
  48. package/dist/types/src/error/openapi/ObjectSerializerRendersOneAndManyRequireClassType.d.ts +5 -0
  49. package/dist/types/src/helpers/isObject.d.ts +1 -0
  50. package/dist/types/src/openapi-renderer/SerializerOpenapiRenderer.d.ts +25 -0
  51. package/dist/types/src/openapi-renderer/helpers/allSerializersFromHandWrittenOpenapi.d.ts +2 -0
  52. package/dist/types/src/openapi-renderer/helpers/allSerializersToRefsInOpenapi.d.ts +2 -0
  53. package/dist/types/src/openapi-renderer/helpers/dreamAttributeOpenapiShape.d.ts +780 -0
  54. package/dist/types/src/openapi-renderer/helpers/isOpenapiShorthand.d.ts +1 -0
  55. package/dist/types/src/openapi-renderer/helpers/maybeNullOpenapiShorthandToOpenapiShorthand.d.ts +2 -0
  56. package/dist/types/src/openapi-renderer/helpers/openapiShorthandToOpenapi.d.ts +16 -0
  57. package/package.json +2 -2
  58. package/dist/cjs/src/helpers/typechecks.js +0 -20
  59. package/dist/esm/src/helpers/typechecks.js +0 -16
  60. package/dist/types/src/helpers/typechecks.d.ts +0 -2
@@ -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);
@@ -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
+ }
@@ -8,8 +8,10 @@ const dream_1 = require("@rvoh/dream");
8
8
  const NonSerializerSuppliedToSerializerBodySegment_js_1 = __importDefault(require("../error/openapi/NonSerializerSuppliedToSerializerBodySegment.js"));
9
9
  const isArrayParamName_js_1 = __importDefault(require("../helpers/isArrayParamName.js"));
10
10
  const isBlankDescription_js_1 = __importDefault(require("./helpers/isBlankDescription.js"));
11
+ const maybeNullOpenapiShorthandToOpenapiShorthand_js_1 = __importDefault(require("./helpers/maybeNullOpenapiShorthandToOpenapiShorthand.js"));
11
12
  const primitiveOpenapiStatementToOpenapi_js_1 = __importDefault(require("./helpers/primitiveOpenapiStatementToOpenapi.js"));
12
13
  const schemaToRef_js_1 = __importDefault(require("./helpers/schemaToRef.js"));
14
+ const SerializerOpenapiRenderer_js_1 = __importDefault(require("./SerializerOpenapiRenderer.js"));
13
15
  class OpenapiBodySegmentRenderer {
14
16
  bodySegment;
15
17
  casing;
@@ -133,7 +135,7 @@ class OpenapiBodySegmentRenderer {
133
135
  else if (this.maybeNullTypeToType(arrayBodySegment) === 'array')
134
136
  return 'array';
135
137
  else {
136
- const primitiveString = (0, dream_1.maybeNullOpenapiShorthandToOpenapiShorthand)(bodySegment);
138
+ const primitiveString = (0, maybeNullOpenapiShorthandToOpenapiShorthand_js_1.default)(bodySegment);
137
139
  if (typeof primitiveString === 'string' && dream_1.openapiShorthandPrimitiveTypes.includes(primitiveString))
138
140
  return 'openapi_primitive_literal';
139
141
  if (typeof bodySegment === 'object') {
@@ -340,7 +342,7 @@ class OpenapiBodySegmentRenderer {
340
342
  }
341
343
  }
342
344
  typeIsOpenapiArrayPrimitive(openapiType) {
343
- return (0, isArrayParamName_js_1.default)((0, dream_1.maybeNullOpenapiShorthandToOpenapiShorthand)(openapiType));
345
+ return (0, isArrayParamName_js_1.default)((0, maybeNullOpenapiShorthandToOpenapiShorthand_js_1.default)(openapiType));
344
346
  }
345
347
  applyConfigurationOptions(obj) {
346
348
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -386,7 +388,7 @@ The following values will be allowed:
386
388
  const serializer = serializerRefBodySegment.$serializer;
387
389
  if (!(0, dream_1.isDreamSerializer)(serializer))
388
390
  throw new NonSerializerSuppliedToSerializerBodySegment_js_1.default(this.bodySegment, serializer);
389
- const serializerRef = new dream_1.SerializerOpenapiRenderer(serializer, {
391
+ const serializerRef = new SerializerOpenapiRenderer_js_1.default(serializer, {
390
392
  casing: this.casing,
391
393
  suppressResponseEnums: this.suppressResponseEnums,
392
394
  }).serializerRef;
@@ -16,6 +16,7 @@ const openapiRoute_js_1 = __importDefault(require("./helpers/openapiRoute.js"));
16
16
  const pageParamOpenapiProperty_js_1 = __importDefault(require("./helpers/pageParamOpenapiProperty.js"));
17
17
  const primitiveOpenapiStatementToOpenapi_js_1 = __importDefault(require("./helpers/primitiveOpenapiStatementToOpenapi.js"));
18
18
  const safelyAttachPaginationParamsToBodySegment_js_1 = __importDefault(require("./helpers/safelyAttachPaginationParamsToBodySegment.js"));
19
+ const SerializerOpenapiRenderer_js_1 = __importDefault(require("./SerializerOpenapiRenderer.js"));
19
20
  class OpenapiEndpointRenderer {
20
21
  dreamsOrSerializers;
21
22
  controllerClass;
@@ -716,7 +717,7 @@ class OpenapiEndpointRenderer {
716
717
  if (!(0, dream_1.isDreamSerializer)(serializer)) {
717
718
  throw new SerializerForEndpointNotAFunction_js_1.default(this.controllerClass, this.action, serializer);
718
719
  }
719
- const serializerOpenapiRenderer = new dream_1.SerializerOpenapiRenderer(serializer, renderOpts);
720
+ const serializerOpenapiRenderer = new SerializerOpenapiRenderer_js_1.default(serializer, renderOpts);
720
721
  const finalOutput = {
721
722
  content: {
722
723
  'application/json': {
@@ -789,10 +790,10 @@ class OpenapiEndpointRenderer {
789
790
  if (!(0, dream_1.isDreamSerializer)(serializer))
790
791
  throw new NonSerializerDerivedInOpenapiEndpointRenderer_js_1.default(this.controllerClass, this.action, serializer);
791
792
  });
792
- const sortedSerializerClasses = (0, dream_1.sortBy)(serializers, serializer => new dream_1.SerializerOpenapiRenderer(serializer, renderOpts).openapiName);
793
+ const sortedSerializerClasses = (0, dream_1.sortBy)(serializers, serializer => new SerializerOpenapiRenderer_js_1.default(serializer, renderOpts).openapiName);
793
794
  let referencedSerializers = [];
794
795
  sortedSerializerClasses.forEach(serializer => {
795
- const serializerOpenapiRenderer = new dream_1.SerializerOpenapiRenderer(serializer, renderOpts);
796
+ const serializerOpenapiRenderer = new SerializerOpenapiRenderer_js_1.default(serializer, renderOpts);
796
797
  anyOf.anyOf.push(serializerOpenapiRenderer.serializerRef);
797
798
  referencedSerializers = [
798
799
  ...referencedSerializers,
@@ -977,12 +978,12 @@ function serializersToSchemaObjects(controllerClass, actionName, serializers, {
977
978
  if (!(0, dream_1.isDreamSerializer)(serializer))
978
979
  throw new NonSerializerDerivedInToSchemaObjects_js_1.default(controllerClass, actionName, serializer);
979
980
  });
980
- serializers = serializers.filter(serializer => !renderedSchemasOpenapi[new dream_1.SerializerOpenapiRenderer(serializer, renderOpts).openapiName]);
981
+ serializers = serializers.filter(serializer => !renderedSchemasOpenapi[new SerializerOpenapiRenderer_js_1.default(serializer, renderOpts).openapiName]);
981
982
  if (!serializers.length)
982
983
  return;
983
984
  let dependentOnSerializers = [];
984
985
  serializers.forEach(serializer => {
985
- const renderer = new dream_1.SerializerOpenapiRenderer(serializer, renderOpts);
986
+ const renderer = new SerializerOpenapiRenderer_js_1.default(serializer, renderOpts);
986
987
  const results = renderer.renderedOpenapi(alreadyExtractedDescendantSerializers);
987
988
  const segmentRendererResults = new body_segment_js_1.default(results.openapi, {
988
989
  openapiName,