@tahminator/sapling 2.0.5-beta.18ab8bae → 2.0.5-beta.18e683d9

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.
package/dist/index.cjs CHANGED
@@ -548,50 +548,70 @@ var OpenAPIGenerator = class {
548
548
  const schemas = _getValidatorSchema(controllerClass, route.fnName);
549
549
  const routeSchema = _getRouteSchema(controllerClass, route.fnName);
550
550
  if (route.path instanceof RegExp) throw new Error(`You have a route with a regex path of ${route.path.source}. This is not compatible with OpenAPI.`);
551
- const openApiPath = prefix + route.path;
551
+ const openApiPath = (prefix + route.path).replace(/:([A-Za-z0-9_]+)/g, "{$1}");
552
552
  if (!paths[openApiPath]) paths[openApiPath] = {};
553
553
  const responses = {};
554
- if (schemas?.responseBody) responses["200"] = {
555
- description: "Successful response",
556
- content: { "application/json": { schema: this.toJsonSchema(schemas.responseBody) } }
557
- };
558
- else responses["200"] = { description: "Successful response" };
559
- if (routeSchema?.responses) for (const resp of routeSchema.responses) responses[String(resp.statusCode)] = {
560
- description: `Response ${resp.statusCode}`,
561
- content: { "application/json": { schema: this.toJsonSchema(resp.schema) } }
562
- };
554
+ if (schemas?.responseBody) {
555
+ const responseSchema = this.toJsonSchema(schemas.responseBody, "output");
556
+ responses["200"] = {
557
+ description: responseSchema.description ?? "Successful response",
558
+ content: { "application/json": { schema: responseSchema } }
559
+ };
560
+ } else responses["200"] = { description: "Successful response" };
561
+ if (routeSchema?.responses) for (const resp of routeSchema.responses) {
562
+ const statusCode = String(resp.statusCode);
563
+ const existingResponse = responses[statusCode];
564
+ const existingSchema = existingResponse && "content" in existingResponse ? existingResponse.content?.["application/json"]?.schema : void 0;
565
+ const responseSchema = resp.schema ? this.toJsonSchema(resp.schema, "output") : statusCode === "200" ? existingSchema : void 0;
566
+ responses[statusCode] = {
567
+ ...existingResponse,
568
+ description: resp.description ?? responseSchema?.description ?? existingResponse?.description ?? `Response ${resp.statusCode}`,
569
+ ...responseSchema ? { content: { "application/json": { schema: responseSchema } } } : {}
570
+ };
571
+ }
563
572
  const operation = {
564
573
  responses,
574
+ summary: routeSchema?.summary,
565
575
  description: routeSchema?.description,
566
576
  tags: controllerSchema?.title ? [controllerSchema.title] : void 0
567
577
  };
568
578
  const parameters = [];
569
579
  if (schemas?.requestParam) {
570
- const paramSchema = this.toJsonSchema(schemas.requestParam);
571
- if (paramSchema.type === "object" && paramSchema.properties) for (const [name, schema] of Object.entries(paramSchema.properties)) parameters.push({
572
- name,
573
- in: "path",
574
- required: true,
575
- schema
576
- });
580
+ const paramSchema = this.toJsonSchema(schemas.requestParam, "input");
581
+ if (paramSchema.type === "object" && paramSchema.properties) for (const [name, schema] of Object.entries(paramSchema.properties)) {
582
+ const parameterSchema = schema;
583
+ parameters.push({
584
+ name,
585
+ in: "path",
586
+ required: true,
587
+ description: parameterSchema.description,
588
+ schema: parameterSchema
589
+ });
590
+ }
577
591
  }
578
592
  if (schemas?.requestQuery) {
579
- const querySchema = this.toJsonSchema(schemas.requestQuery);
593
+ const querySchema = this.toJsonSchema(schemas.requestQuery, "input");
580
594
  if (querySchema.type === "object" && querySchema.properties) for (const [name, schema] of Object.entries(querySchema.properties)) {
581
595
  const isRequired = Array.isArray(querySchema.required) && querySchema.required.includes(name);
596
+ const parameterSchema = schema;
582
597
  parameters.push({
583
598
  name,
584
599
  in: "query",
585
600
  required: isRequired,
586
- schema
601
+ description: parameterSchema.description,
602
+ schema: parameterSchema
587
603
  });
588
604
  }
589
605
  }
590
606
  if (parameters.length > 0) operation.parameters = parameters;
591
- if (schemas?.requestBody) operation.requestBody = {
592
- required: true,
593
- content: { "application/json": { schema: this.toJsonSchema(schemas.requestBody) } }
594
- };
607
+ if (schemas?.requestBody) {
608
+ const requestSchema = this.toJsonSchema(schemas.requestBody, "input");
609
+ operation.requestBody = {
610
+ required: true,
611
+ description: requestSchema.description,
612
+ content: { "application/json": { schema: requestSchema } }
613
+ };
614
+ }
595
615
  const method = route.method.toLowerCase();
596
616
  paths[openApiPath][method] = operation;
597
617
  }
@@ -607,9 +627,11 @@ var OpenAPIGenerator = class {
607
627
  paths
608
628
  };
609
629
  }
610
- toJsonSchema(schema) {
630
+ toJsonSchema(schema, direction = "output") {
611
631
  try {
612
- return schema["~standard"].jsonSchema.output({ target: "openapi-3.0" });
632
+ const jsonSchema = schema["~standard"].jsonSchema;
633
+ if (direction === "input" && jsonSchema.input) return jsonSchema.input({ target: "openapi-3.0" });
634
+ return jsonSchema.output({ target: "openapi-3.0" });
613
635
  } catch (e) {
614
636
  if (e instanceof Error && e.message.includes("Transforms cannot be represented in JSON Schema")) throw new Error(`${e.message}.\nIt appears that you are using z.transform() - it is highly recommended that you use z.codec instead - https://zod.dev/codecs`);
615
637
  throw e;
@@ -800,7 +822,7 @@ function _getOrCreateSchemaDefinition(ctor, fnName) {
800
822
  async function _parseOrThrow(schema, input, kind) {
801
823
  const result = await schema["~standard"].validate(input);
802
824
  if (result.issues) {
803
- console.debug(`Failed to parse a schema`);
825
+ console.debug(`Failed to parse ${schema["~standard"].vendor} schema\nissues: ${result.issues}`);
804
826
  throw new ParserError(kind, result.issues, schema["~standard"].vendor);
805
827
  }
806
828
  return result.value;
package/dist/index.d.cts CHANGED
@@ -892,9 +892,11 @@ declare function _setOnce(def: ValidatorSchema, key: keyof ValidatorSchema, sche
892
892
  //#region src/annotation/schema.d.ts
893
893
  type ResponseSchema = {
894
894
  statusCode: HttpStatus;
895
- schema: StandardSchemaV1 & StandardJSONSchemaV1;
895
+ description?: string;
896
+ schema?: StandardSchemaV1 & StandardJSONSchemaV1;
896
897
  };
897
898
  type RouteSchemaDefinition = {
899
+ summary?: string;
898
900
  description?: string;
899
901
  responses?: ResponseSchema[];
900
902
  };
@@ -907,6 +909,7 @@ declare function ControllerSchema(options: {
907
909
  description?: string;
908
910
  }): ClassDecorator;
909
911
  declare function RouteSchema(options: {
912
+ summary?: string;
910
913
  description?: string;
911
914
  responses?: ResponseSchema[];
912
915
  }): MethodDecorator;
package/dist/index.d.mts CHANGED
@@ -892,9 +892,11 @@ declare function _setOnce(def: ValidatorSchema, key: keyof ValidatorSchema, sche
892
892
  //#region src/annotation/schema.d.ts
893
893
  type ResponseSchema = {
894
894
  statusCode: HttpStatus;
895
- schema: StandardSchemaV1 & StandardJSONSchemaV1;
895
+ description?: string;
896
+ schema?: StandardSchemaV1 & StandardJSONSchemaV1;
896
897
  };
897
898
  type RouteSchemaDefinition = {
899
+ summary?: string;
898
900
  description?: string;
899
901
  responses?: ResponseSchema[];
900
902
  };
@@ -907,6 +909,7 @@ declare function ControllerSchema(options: {
907
909
  description?: string;
908
910
  }): ClassDecorator;
909
911
  declare function RouteSchema(options: {
912
+ summary?: string;
910
913
  description?: string;
911
914
  responses?: ResponseSchema[];
912
915
  }): MethodDecorator;
package/dist/index.mjs CHANGED
@@ -523,50 +523,70 @@ var OpenAPIGenerator = class {
523
523
  const schemas = _getValidatorSchema(controllerClass, route.fnName);
524
524
  const routeSchema = _getRouteSchema(controllerClass, route.fnName);
525
525
  if (route.path instanceof RegExp) throw new Error(`You have a route with a regex path of ${route.path.source}. This is not compatible with OpenAPI.`);
526
- const openApiPath = prefix + route.path;
526
+ const openApiPath = (prefix + route.path).replace(/:([A-Za-z0-9_]+)/g, "{$1}");
527
527
  if (!paths[openApiPath]) paths[openApiPath] = {};
528
528
  const responses = {};
529
- if (schemas?.responseBody) responses["200"] = {
530
- description: "Successful response",
531
- content: { "application/json": { schema: this.toJsonSchema(schemas.responseBody) } }
532
- };
533
- else responses["200"] = { description: "Successful response" };
534
- if (routeSchema?.responses) for (const resp of routeSchema.responses) responses[String(resp.statusCode)] = {
535
- description: `Response ${resp.statusCode}`,
536
- content: { "application/json": { schema: this.toJsonSchema(resp.schema) } }
537
- };
529
+ if (schemas?.responseBody) {
530
+ const responseSchema = this.toJsonSchema(schemas.responseBody, "output");
531
+ responses["200"] = {
532
+ description: responseSchema.description ?? "Successful response",
533
+ content: { "application/json": { schema: responseSchema } }
534
+ };
535
+ } else responses["200"] = { description: "Successful response" };
536
+ if (routeSchema?.responses) for (const resp of routeSchema.responses) {
537
+ const statusCode = String(resp.statusCode);
538
+ const existingResponse = responses[statusCode];
539
+ const existingSchema = existingResponse && "content" in existingResponse ? existingResponse.content?.["application/json"]?.schema : void 0;
540
+ const responseSchema = resp.schema ? this.toJsonSchema(resp.schema, "output") : statusCode === "200" ? existingSchema : void 0;
541
+ responses[statusCode] = {
542
+ ...existingResponse,
543
+ description: resp.description ?? responseSchema?.description ?? existingResponse?.description ?? `Response ${resp.statusCode}`,
544
+ ...responseSchema ? { content: { "application/json": { schema: responseSchema } } } : {}
545
+ };
546
+ }
538
547
  const operation = {
539
548
  responses,
549
+ summary: routeSchema?.summary,
540
550
  description: routeSchema?.description,
541
551
  tags: controllerSchema?.title ? [controllerSchema.title] : void 0
542
552
  };
543
553
  const parameters = [];
544
554
  if (schemas?.requestParam) {
545
- const paramSchema = this.toJsonSchema(schemas.requestParam);
546
- if (paramSchema.type === "object" && paramSchema.properties) for (const [name, schema] of Object.entries(paramSchema.properties)) parameters.push({
547
- name,
548
- in: "path",
549
- required: true,
550
- schema
551
- });
555
+ const paramSchema = this.toJsonSchema(schemas.requestParam, "input");
556
+ if (paramSchema.type === "object" && paramSchema.properties) for (const [name, schema] of Object.entries(paramSchema.properties)) {
557
+ const parameterSchema = schema;
558
+ parameters.push({
559
+ name,
560
+ in: "path",
561
+ required: true,
562
+ description: parameterSchema.description,
563
+ schema: parameterSchema
564
+ });
565
+ }
552
566
  }
553
567
  if (schemas?.requestQuery) {
554
- const querySchema = this.toJsonSchema(schemas.requestQuery);
568
+ const querySchema = this.toJsonSchema(schemas.requestQuery, "input");
555
569
  if (querySchema.type === "object" && querySchema.properties) for (const [name, schema] of Object.entries(querySchema.properties)) {
556
570
  const isRequired = Array.isArray(querySchema.required) && querySchema.required.includes(name);
571
+ const parameterSchema = schema;
557
572
  parameters.push({
558
573
  name,
559
574
  in: "query",
560
575
  required: isRequired,
561
- schema
576
+ description: parameterSchema.description,
577
+ schema: parameterSchema
562
578
  });
563
579
  }
564
580
  }
565
581
  if (parameters.length > 0) operation.parameters = parameters;
566
- if (schemas?.requestBody) operation.requestBody = {
567
- required: true,
568
- content: { "application/json": { schema: this.toJsonSchema(schemas.requestBody) } }
569
- };
582
+ if (schemas?.requestBody) {
583
+ const requestSchema = this.toJsonSchema(schemas.requestBody, "input");
584
+ operation.requestBody = {
585
+ required: true,
586
+ description: requestSchema.description,
587
+ content: { "application/json": { schema: requestSchema } }
588
+ };
589
+ }
570
590
  const method = route.method.toLowerCase();
571
591
  paths[openApiPath][method] = operation;
572
592
  }
@@ -582,9 +602,11 @@ var OpenAPIGenerator = class {
582
602
  paths
583
603
  };
584
604
  }
585
- toJsonSchema(schema) {
605
+ toJsonSchema(schema, direction = "output") {
586
606
  try {
587
- return schema["~standard"].jsonSchema.output({ target: "openapi-3.0" });
607
+ const jsonSchema = schema["~standard"].jsonSchema;
608
+ if (direction === "input" && jsonSchema.input) return jsonSchema.input({ target: "openapi-3.0" });
609
+ return jsonSchema.output({ target: "openapi-3.0" });
588
610
  } catch (e) {
589
611
  if (e instanceof Error && e.message.includes("Transforms cannot be represented in JSON Schema")) throw new Error(`${e.message}.\nIt appears that you are using z.transform() - it is highly recommended that you use z.codec instead - https://zod.dev/codecs`);
590
612
  throw e;
@@ -775,7 +797,7 @@ function _getOrCreateSchemaDefinition(ctor, fnName) {
775
797
  async function _parseOrThrow(schema, input, kind) {
776
798
  const result = await schema["~standard"].validate(input);
777
799
  if (result.issues) {
778
- console.debug(`Failed to parse a schema`);
800
+ console.debug(`Failed to parse ${schema["~standard"].vendor} schema\nissues: ${result.issues}`);
779
801
  throw new ParserError(kind, result.issues, schema["~standard"].vendor);
780
802
  }
781
803
  return result.value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tahminator/sapling",
3
- "version": "2.0.5-beta.18ab8bae",
3
+ "version": "2.0.5-beta.18e683d9",
4
4
  "author": "Tahmid Ahmed",
5
5
  "description": "A library to help you write cleaner Express.js code",
6
6
  "repository": {