From d18a579cb8db07524cbb1e64ac2ea9ebf1f4e537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Wed, 1 Nov 2023 14:44:45 +0100 Subject: [PATCH] refactor: revert json schema changes --- .../src/plugin/minimal-plugin.ts | 9 +-- .../src/plugin/protocol/request.ts | 1 + .../src/plugin/protocol/response.ts | 3 +- examples/minimal-plugin/src/schemas.d.ts | 5 -- examples/minimal-plugin/tsup.config.ts | 6 +- packages/core/src/elasticsearch.ts | 61 ----------------- packages/core/src/generators.d.ts | 10 --- packages/core/src/protocol/route.ts | 17 +++-- packages/core/src/protocol/routes/bulk-add.ts | 8 +-- packages/core/src/protocol/routes/index.ts | 41 ++++++------ .../src/protocol/routes/plugin-register.ts | 45 ++++++------- packages/core/src/protocol/routes/rating.ts | 41 ++++++------ .../core/src/protocol/routes/search-multi.ts | 43 ++++++------ packages/core/src/protocol/routes/search.ts | 41 ++++++------ .../core/src/protocol/routes/thing-update.ts | 51 +++++++------- packages/core/src/schemas.ts | 67 ------------------- packages/core/src/things/academic-event.ts | 4 +- packages/core/src/things/ticket.ts | 1 + packages/core/tsup.config.ts | 11 +-- .../src/generator/index.ts | 2 +- packages/es-mapping-generator/src/index.ts | 45 +------------ packages/json-schema-generator/src/index.ts | 32 ++++----- 22 files changed, 173 insertions(+), 371 deletions(-) delete mode 100644 examples/minimal-plugin/src/schemas.d.ts delete mode 100644 packages/core/src/elasticsearch.ts delete mode 100644 packages/core/src/generators.d.ts delete mode 100644 packages/core/src/schemas.ts diff --git a/examples/minimal-plugin/src/plugin/minimal-plugin.ts b/examples/minimal-plugin/src/plugin/minimal-plugin.ts index 9b96f14f..b78ad5c6 100644 --- a/examples/minimal-plugin/src/plugin/minimal-plugin.ts +++ b/examples/minimal-plugin/src/plugin/minimal-plugin.ts @@ -14,8 +14,9 @@ */ import {Plugin} from '@openstapps/api-plugin'; import * as express from 'express'; -import {requestSchema, SCMinimalRequest} from './protocol/request.js'; -import {responseSchema, SCMinimalResponse} from './protocol/response.js'; +import schema from '../../lib/schema.json'; +import {SCMinimalRequest} from './protocol/request.js'; +import {SCMinimalResponse} from './protocol/response.js'; /** * The Plugin Class @@ -24,9 +25,9 @@ import {responseSchema, SCMinimalResponse} from './protocol/response.js'; * TODO: rename the class */ export class MinimalPlugin extends Plugin { - requestSchema = requestSchema; + requestSchema = schema.SCMinimalRequest; - responseSchema = responseSchema; + responseSchema = schema.SCMinimalResponse; /** * Calculates the sum of a list of numbers diff --git a/examples/minimal-plugin/src/plugin/protocol/request.ts b/examples/minimal-plugin/src/plugin/protocol/request.ts index eeb4029d..a31bfca7 100644 --- a/examples/minimal-plugin/src/plugin/protocol/request.ts +++ b/examples/minimal-plugin/src/plugin/protocol/request.ts @@ -19,6 +19,7 @@ * All incoming requests will look like this, this is being checked by the backend. You need to add the @validatable tag * like shown below for the plugin to work. The request can have any layout you like. * TODO: remove body of the interface and replace with your own layout + * @validatable */ export interface SCMinimalRequest { /** diff --git a/examples/minimal-plugin/src/plugin/protocol/response.ts b/examples/minimal-plugin/src/plugin/protocol/response.ts index 68d4ad07..6bd91e60 100644 --- a/examples/minimal-plugin/src/plugin/protocol/response.ts +++ b/examples/minimal-plugin/src/plugin/protocol/response.ts @@ -19,6 +19,7 @@ * All your responses to the backend are required to look like this. You need to add the @validatable tag like shown * below for the plugin to work. The response can have any layout you like. * TODO: remove body of the interface and replace with your own layout + * @validatable */ export interface SCMinimalResponse { /** @@ -27,4 +28,4 @@ export interface SCMinimalResponse { sum: number; } -export {default as responseSchema} from 'schema:#SCMinimalResponse'; +export {default as requestSchema} from 'schema:#SCMinimalResponse'; diff --git a/examples/minimal-plugin/src/schemas.d.ts b/examples/minimal-plugin/src/schemas.d.ts deleted file mode 100644 index 2a2f1d15..00000000 --- a/examples/minimal-plugin/src/schemas.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'schema:*' { - import {JSONSchema7} from 'json-schema'; - const schema: JSONSchema7; - export default schema; -} diff --git a/examples/minimal-plugin/tsup.config.ts b/examples/minimal-plugin/tsup.config.ts index 18b53f08..1f2c6b40 100644 --- a/examples/minimal-plugin/tsup.config.ts +++ b/examples/minimal-plugin/tsup.config.ts @@ -1,5 +1,5 @@ import {defineConfig} from 'tsup'; -import {esbuildJsonSchemaPlugin} from '@openstapps/json-schema-generator'; +import {jsonSchemaPlugin} from '@openstapps/json-schema-generator'; export default defineConfig({ entry: ['src/app.ts'], @@ -7,6 +7,6 @@ export default defineConfig({ clean: true, format: 'esm', outDir: 'lib', - noExternal: [/schema:.*/], - esbuildPlugins: [esbuildJsonSchemaPlugin], + noExternal: [/.*:schema#.*/], + plugins: [jsonSchemaPlugin('schema.json')], }); diff --git a/packages/core/src/elasticsearch.ts b/packages/core/src/elasticsearch.ts deleted file mode 100644 index dcd2bff9..00000000 --- a/packages/core/src/elasticsearch.ts +++ /dev/null @@ -1,61 +0,0 @@ -import academicEventMapping from 'elasticsearch:./things/academic-event.js#SCAcademicEvent'; -import articleMapping from 'elasticsearch:./things/article.js#SCArticle'; -import assessmentMapping from 'elasticsearch:./things/assessment.js#SCAssessment'; -import bookMapping from 'elasticsearch:./things/book.js#SCBook'; -import buildingMapping from 'elasticsearch:./things/building.js#SCBuilding'; -import catalogMapping from 'elasticsearch:./things/catalog.js#SCCatalog'; -import certificationMapping from 'elasticsearch:./things/certification.js#SCCertification'; -import contactPointMapping from 'elasticsearch:./things/contact-point.js#SCContactPoint'; -import courseOfStudyMapping from 'elasticsearch:./things/course-of-study.js#SCCourseOfStudy'; -import dateSeriesMapping from 'elasticsearch:./things/date-series.js#SCDateSeries'; -import dishMapping from 'elasticsearch:./things/dish.js#SCDish'; -import floorMapping from 'elasticsearch:./things/floor.js#SCFloor'; -import idCardMapping from 'elasticsearch:./things/id-card.js#SCIdCard'; -import jopPostingMapping from 'elasticsearch:./things/job-posting.js#SCJobPosting'; -import messageMapping from 'elasticsearch:./things/message.js#SCMessage'; -import organizationMapping from 'elasticsearch:./things/organization.js#SCOrganization'; -import periodicalMapping from 'elasticsearch:./things/periodical.js#SCPeriodical'; -import personMapping from 'elasticsearch:./things/person.js#SCPerson'; -import pointOfInterestMapping from 'elasticsearch:./things/point-of-interest.js#SCPointOfInterest'; -import publicationEventMapping from 'elasticsearch:./things/publication-event.js#SCPublicationEvent'; -import roomMapping from 'elasticsearch:./things/room.js#SCRoom'; -import semesterMapping from 'elasticsearch:./things/semester.js#SCSemester'; -import sportCourseMapping from 'elasticsearch:./things/sport-course.js#SCSportCourse'; -import studyModuleMapping from 'elasticsearch:./things/study-module.js#SCStudyModule'; -import ticketMapping from 'elasticsearch:./things/ticket.js#SCTicket'; -import todoMapping from 'elasticsearch:./things/todo.js#SCToDo'; -import tourMapping from 'elasticsearch:./things/tour.js#SCTour'; -import videoMapping from 'elasticsearch:./things/video.js#SCVideo'; -import {SCIndexableThings} from './meta.js'; - -export type IndexableThingTypes = SCIndexableThings['type']; -export const elasticsearchMappings: Record = { - 'academic event': academicEventMapping, - 'article': articleMapping, - 'assessment': assessmentMapping, - 'book': bookMapping, - 'building': buildingMapping, - 'catalog': catalogMapping, - 'certification': certificationMapping, - 'contact point': contactPointMapping, - 'course of study': courseOfStudyMapping, - 'date series': dateSeriesMapping, - 'dish': dishMapping, - 'floor': floorMapping, - 'id card': idCardMapping, - 'job posting': jopPostingMapping, - 'message': messageMapping, - 'organization': organizationMapping, - 'periodical': periodicalMapping, - 'person': personMapping, - 'point of interest': pointOfInterestMapping, - 'publication event': publicationEventMapping, - 'room': roomMapping, - 'semester': semesterMapping, - 'sport course': sportCourseMapping, - 'study module': studyModuleMapping, - 'ticket': ticketMapping, - 'todo': todoMapping, - 'tour': tourMapping, - 'video': videoMapping, -}; diff --git a/packages/core/src/generators.d.ts b/packages/core/src/generators.d.ts deleted file mode 100644 index d5df378c..00000000 --- a/packages/core/src/generators.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -declare module 'schema:*' { - import {JSONSchema7} from 'json-schema'; - const schema: JSONSchema7; - export default schema; -} - -declare module 'elasticsearch:*' { - const indexRequest: unknown; - export default indexRequest; -} diff --git a/packages/core/src/protocol/route.ts b/packages/core/src/protocol/route.ts index 9ce42e48..6848c616 100644 --- a/packages/core/src/protocol/route.ts +++ b/packages/core/src/protocol/route.ts @@ -27,7 +27,6 @@ import {SCSearchRequest, SCSearchResponse, SCSearchRoute} from './routes/search. import {SCMultiSearchRequest, SCMultiSearchResponse, SCMultiSearchRoute} from './routes/search-multi.js'; import {SCThingUpdateRequest, SCThingUpdateResponse, SCThingUpdateRoute} from './routes/thing-update.js'; import {SCRatingRequest, SCRatingResponse, SCRatingRoute} from './routes/rating.js'; -import {JSONSchema7} from 'json-schema'; /** * Possible Verbs for HTTP requests @@ -51,7 +50,7 @@ export interface SCRoute { /** * A map of names of possible errors that can be returned by the route with their appropriate status codes */ - errors: ReadonlyArray; + errorNames: SCErrorResponseConstructor[]; /** * HTTP verb to use to request the route @@ -66,12 +65,12 @@ export interface SCRoute { /** * Name of the type of the request body */ - requestBodySchema: JSONSchema7; + requestBodyName: string; /** * Name of the type of the response body */ - responseBodySchema: JSONSchema7; + responseBodyName: string; /** * Status code for success @@ -91,7 +90,7 @@ export abstract class SCAbstractRoute implements SCRoute { /** * @see SCRoute.errorNames */ - errorSchemas: SCErrorResponseConstructor[] = []; + errorNames: SCErrorResponseConstructor[] = []; /** * @see SCRoute.method @@ -104,14 +103,14 @@ export abstract class SCAbstractRoute implements SCRoute { obligatoryParameters?: Record; /** - * @see SCRoute.requestBodySchema + * @see SCRoute.requestBodyName */ - abstract requestBodySchema: JSONSchema7; + requestBodyName = 'any'; /** - * @see SCRoute.responseBodySchema + * @see SCRoute.responseBodyName */ - abstract responseBodySchema: JSONSchema7; + responseBodyName = 'any'; /** * @see SCRoute.statusCodeSuccess diff --git a/packages/core/src/protocol/routes/bulk-add.ts b/packages/core/src/protocol/routes/bulk-add.ts index 9dfedf8c..079a75f1 100644 --- a/packages/core/src/protocol/routes/bulk-add.ts +++ b/packages/core/src/protocol/routes/bulk-add.ts @@ -28,23 +28,17 @@ import {SCAbstractRoute, SCRouteHttpVerbs} from '../route.js'; * @validatable */ export type SCBulkAddRequest = SCThings; -import {default as bulkAddRequestSchema} from 'schema:#SCBulkAddRequest'; /** * Response to a request to add a thing to a bulk * @validatable */ export interface SCBulkAddResponse {} -import {default as bulkAddResponseSchema} from 'schema:#SCBulkAddResponse'; /** * Route for indexing SC things in a bulk */ export class SCBulkAddRoute extends SCAbstractRoute { - responseBodySchema = bulkAddRequestSchema; - - requestBodySchema = bulkAddResponseSchema; - constructor() { super(); this.errorNames = [ @@ -60,6 +54,8 @@ export class SCBulkAddRoute extends SCAbstractRoute { this.obligatoryParameters = { UID: 'SCUuid', }; + this.requestBodyName = 'SCBulkAddRequest'; + this.responseBodyName = 'SCBulkAddResponse'; this.statusCodeSuccess = StatusCodes.CREATED; this.urlPath = '/bulk/:UID'; } diff --git a/packages/core/src/protocol/routes/index.ts b/packages/core/src/protocol/routes/index.ts index 09c46062..00d56748 100644 --- a/packages/core/src/protocol/routes/index.ts +++ b/packages/core/src/protocol/routes/index.ts @@ -22,17 +22,17 @@ import {SCRequestBodyTooLargeErrorResponse} from '../errors/request-body-too-lar import {SCSyntaxErrorResponse} from '../errors/syntax-error.js'; import {SCUnsupportedMediaTypeErrorResponse} from '../errors/unsupported-media-type.js'; import {SCValidationErrorResponse} from '../errors/validation.js'; -import {SCAbstractRoute, SCRouteHttpVerbs} from '../route.js'; +import {SCRoute, SCRouteHttpVerbs} from '../route.js'; +import {default as indexRequestSchema} from 'schema:#SCIndexRequest'; +import {default as indexResponseSchema} from 'schema:#SCIndexResponse'; /** * Index request - * @validatable */ export interface SCIndexRequest {} /** * A response to an index request - * @validatable */ export interface SCIndexResponse { /** @@ -54,21 +54,20 @@ export interface SCIndexResponse { /** * Route to request meta information about the deployment */ -export class SCIndexRoute extends SCAbstractRoute { - constructor() { - super(); - this.errorNames = [ - SCInternalServerErrorResponse, - SCMethodNotAllowedErrorResponse, - SCRequestBodyTooLargeErrorResponse, - SCSyntaxErrorResponse, - SCUnsupportedMediaTypeErrorResponse, - SCValidationErrorResponse, - ]; - this.method = SCRouteHttpVerbs.POST; - this.requestBodyName = 'SCIndexRequest'; - this.responseBodyName = 'SCIndexResponse'; - this.statusCodeSuccess = StatusCodes.OK; - this.urlPath = '/'; - } -} +export type SCIndexRoute = typeof indexRoute; + +export const indexRoute = Object.freeze({ + errors: [ + SCInternalServerErrorResponse, + SCMethodNotAllowedErrorResponse, + SCRequestBodyTooLargeErrorResponse, + SCSyntaxErrorResponse, + SCUnsupportedMediaTypeErrorResponse, + SCValidationErrorResponse, + ] as const, + method: SCRouteHttpVerbs.POST, + requestBodySchema: indexRequestSchema, + responseBodySchema: indexResponseSchema, + statusCodeSuccess: StatusCodes.OK, + urlPath: '/', +}) satisfies Readonly; diff --git a/packages/core/src/protocol/routes/plugin-register.ts b/packages/core/src/protocol/routes/plugin-register.ts index a6938e71..1c860a47 100644 --- a/packages/core/src/protocol/routes/plugin-register.ts +++ b/packages/core/src/protocol/routes/plugin-register.ts @@ -22,11 +22,12 @@ import {SCPluginAlreadyRegisteredErrorResponse} from '../errors/plugin-already-r import {SCPluginRegisteringFailedErrorResponse} from '../errors/plugin-registering-failed.js'; import {SCRequestBodyTooLargeErrorResponse} from '../errors/request-body-too-large.js'; import {SCSyntaxErrorResponse} from '../errors/syntax-error.js'; -import {SCAbstractRoute, SCRouteHttpVerbs} from '../route.js'; +import {SCRoute, SCRouteHttpVerbs} from '../route.js'; +import {default as pluginRegisterRequestSchema} from 'schema:#SCPluginRegisterRequest'; +import {default as pluginRegisterResponseSchema} from 'schema:#SCPluginRegisterResponse'; /** * Plugin register request - * @validatable */ export type SCPluginRegisterRequest = SCPluginAdd | SCPluginRemove; @@ -92,7 +93,6 @@ export interface SCPluginMetaData { /** * Plugin register response - * @validatable */ export interface SCPluginRegisterResponse { /** @@ -104,23 +104,22 @@ export interface SCPluginRegisterResponse { /** * Route to register plugins */ -export class SCPluginRegisterRoute extends SCAbstractRoute { - constructor() { - super(); - this.errorNames = [ - SCInternalServerErrorResponse, - SCMethodNotAllowedErrorResponse, - SCNotFoundErrorResponse, - SCParametersNotAcceptable, - SCPluginAlreadyRegisteredErrorResponse, - SCPluginRegisteringFailedErrorResponse, - SCRequestBodyTooLargeErrorResponse, - SCSyntaxErrorResponse, - ]; - this.method = SCRouteHttpVerbs.POST; - this.requestBodyName = 'SCPluginRegisterRequest'; - this.responseBodyName = 'SCPluginRegisterResponse'; - this.statusCodeSuccess = StatusCodes.OK; - this.urlPath = '/plugin/register'; - } -} +export type SCPluginRegisterRoute = typeof pluginRegisterRoute; + +export const pluginRegisterRoute = Object.freeze({ + errors: [ + SCInternalServerErrorResponse, + SCMethodNotAllowedErrorResponse, + SCNotFoundErrorResponse, + SCParametersNotAcceptable, + SCPluginAlreadyRegisteredErrorResponse, + SCPluginRegisteringFailedErrorResponse, + SCRequestBodyTooLargeErrorResponse, + SCSyntaxErrorResponse, + ], + method: SCRouteHttpVerbs.POST, + requestBodySchema: pluginRegisterRequestSchema, + responseBodySchema: pluginRegisterResponseSchema, + statusCodeSuccess: StatusCodes.OK, + urlPath: '/plugin/register', +}) satisfies Readonly; diff --git a/packages/core/src/protocol/routes/rating.ts b/packages/core/src/protocol/routes/rating.ts index 2d8b1752..ce399089 100644 --- a/packages/core/src/protocol/routes/rating.ts +++ b/packages/core/src/protocol/routes/rating.ts @@ -18,17 +18,16 @@ import {SCMethodNotAllowedErrorResponse} from '../errors/method-not-allowed.js'; import {SCRequestBodyTooLargeErrorResponse} from '../errors/request-body-too-large.js'; import {SCSyntaxErrorResponse} from '../errors/syntax-error.js'; import {SCUnsupportedMediaTypeErrorResponse} from '../errors/unsupported-media-type.js'; -import {SCRoute, SCRouteHttpVerbs} from '../route.js'; +import {SCAbstractRoute, SCRouteHttpVerbs} from '../route.js'; import {SCThing} from '../../things/abstract/thing.js'; import {SCUserGroupSetting} from '../../things/setting.js'; import {SCValidationErrorResponse} from '../errors/validation.js'; -import {default as ratingRequestSchema} from 'schema:#SCRatingRequest'; -import {default as ratingResponseSchema} from 'schema:#SCRatingResponse'; /** * User rating from the app * Plugin needs to define its own rating request to hit the target rating system. * That request should extend this one and contain timestamp and other needed data. + * @validatable */ export interface SCRatingRequest { /** @@ -49,26 +48,28 @@ export interface SCRatingRequest { /** * A response to a rating request + * @validatable */ export interface SCRatingResponse {} /** * Route for rating submission */ -export type SCRatingRoute = typeof ratingRoute; - -export const ratingRoute = Object.freeze({ - errors: [ - SCInternalServerErrorResponse, - SCMethodNotAllowedErrorResponse, - SCRequestBodyTooLargeErrorResponse, - SCSyntaxErrorResponse, - SCUnsupportedMediaTypeErrorResponse, - SCValidationErrorResponse, - ] as const, - method: SCRouteHttpVerbs.POST, - requestBodySchema: ratingRequestSchema, - responseBodySchema: ratingResponseSchema, - statusCodeSuccess: StatusCodes.OK, - urlPath: '/rating', -}) satisfies Readonly; +export class SCRatingRoute extends SCAbstractRoute { + constructor() { + super(); + this.errorNames = [ + SCInternalServerErrorResponse, + SCMethodNotAllowedErrorResponse, + SCRequestBodyTooLargeErrorResponse, + SCSyntaxErrorResponse, + SCUnsupportedMediaTypeErrorResponse, + SCValidationErrorResponse, + ]; + this.method = SCRouteHttpVerbs.POST; + this.requestBodyName = 'SCRatingRequest'; + this.responseBodyName = 'SCRatingResponse'; + this.statusCodeSuccess = StatusCodes.OK; + this.urlPath = '/rating'; + } +} diff --git a/packages/core/src/protocol/routes/search-multi.ts b/packages/core/src/protocol/routes/search-multi.ts index b4c4005a..4a7e7906 100644 --- a/packages/core/src/protocol/routes/search-multi.ts +++ b/packages/core/src/protocol/routes/search-multi.ts @@ -20,11 +20,9 @@ import {SCSyntaxErrorResponse} from '../errors/syntax-error.js'; import {SCTooManyRequestsErrorResponse} from '../errors/too-many-requests.js'; import {SCUnsupportedMediaTypeErrorResponse} from '../errors/unsupported-media-type.js'; import {SCValidationErrorResponse} from '../errors/validation.js'; -import {SCRoute, SCRouteHttpVerbs} from '../route.js'; +import {SCAbstractRoute, SCRouteHttpVerbs} from '../route.js'; import {SCSearchQuery} from '../search/query.js'; import {SCSearchResult} from '../search/result.js'; -import {default as multiSearchRequestSchema} from 'schema:#SCMultiSearchRequest'; -import {default as multiSearchResponseSchema} from 'schema:#SCMultiSearchResponse'; /** * A multi search request @@ -32,6 +30,7 @@ import {default as multiSearchResponseSchema} from 'schema:#SCMultiSearchRespons * This is a map of [[SCSearchRequest]]s indexed by name. * * **CAUTION: This is limited to an amount of queries. Currently this limit is 5.** + * @validatable */ export type SCMultiSearchRequest = Record; @@ -39,27 +38,29 @@ export type SCMultiSearchRequest = Record; * A multi search response * * This is a map of [[SCSearchResponse]]s indexed by name + * @validatable */ export type SCMultiSearchResponse = Record; /** * Route for submission of multiple search requests at once */ -export type SCMultiSearchRoute = typeof multiSearchRoute; - -export const multiSearchRoute = Object.freeze({ - errors: [ - SCInternalServerErrorResponse, - SCMethodNotAllowedErrorResponse, - SCRequestBodyTooLargeErrorResponse, - SCSyntaxErrorResponse, - SCTooManyRequestsErrorResponse, - SCUnsupportedMediaTypeErrorResponse, - SCValidationErrorResponse, - ] as const, - method: SCRouteHttpVerbs.POST, - requestBodySchema: multiSearchRequestSchema, - responseBodySchema: multiSearchResponseSchema, - statusCodeSuccess: StatusCodes.OK, - urlPath: '/search/multi', -}) satisfies Readonly; +export class SCMultiSearchRoute extends SCAbstractRoute { + constructor() { + super(); + this.errorNames = [ + SCInternalServerErrorResponse, + SCMethodNotAllowedErrorResponse, + SCRequestBodyTooLargeErrorResponse, + SCSyntaxErrorResponse, + SCTooManyRequestsErrorResponse, + SCUnsupportedMediaTypeErrorResponse, + SCValidationErrorResponse, + ]; + this.method = SCRouteHttpVerbs.POST; + this.requestBodyName = 'SCMultiSearchRequest'; + this.responseBodyName = 'SCMultiSearchResponse'; + this.statusCodeSuccess = StatusCodes.OK; + this.urlPath = '/search/multi'; + } +} diff --git a/packages/core/src/protocol/routes/search.ts b/packages/core/src/protocol/routes/search.ts index 661724d8..2c19db23 100644 --- a/packages/core/src/protocol/routes/search.ts +++ b/packages/core/src/protocol/routes/search.ts @@ -19,39 +19,40 @@ import {SCRequestBodyTooLargeErrorResponse} from '../errors/request-body-too-lar import {SCSyntaxErrorResponse} from '../errors/syntax-error.js'; import {SCUnsupportedMediaTypeErrorResponse} from '../errors/unsupported-media-type.js'; import {SCValidationErrorResponse} from '../errors/validation.js'; -import {SCRoute, SCRouteHttpVerbs} from '../route.js'; +import {SCAbstractRoute, SCRouteHttpVerbs} from '../route.js'; import {SCSearchQuery} from '../search/query.js'; import {SCSearchResult} from '../search/result.js'; -import {default as searchRequestSchema} from 'schema:#SCSearchRequest'; -import {default as searchResponseSchema} from 'schema:#SCSearchResponse'; /** * A search request + * @validatable */ export type SCSearchRequest = SCSearchQuery; /** * A search response + * @validatable */ export type SCSearchResponse = SCSearchResult; /** * Route for searching things */ -export type SCSearchRoute = typeof searchRoute; - -export const searchRoute = Object.freeze({ - errors: [ - SCInternalServerErrorResponse, - SCMethodNotAllowedErrorResponse, - SCRequestBodyTooLargeErrorResponse, - SCSyntaxErrorResponse, - SCUnsupportedMediaTypeErrorResponse, - SCValidationErrorResponse, - ] as const, - method: SCRouteHttpVerbs.POST, - requestBodySchema: searchRequestSchema, - responseBodySchema: searchResponseSchema, - statusCodeSuccess: StatusCodes.OK, - urlPath: '/search', -}) satisfies Readonly; +export class SCSearchRoute extends SCAbstractRoute { + constructor() { + super(); + this.errorNames = [ + SCInternalServerErrorResponse, + SCMethodNotAllowedErrorResponse, + SCRequestBodyTooLargeErrorResponse, + SCSyntaxErrorResponse, + SCUnsupportedMediaTypeErrorResponse, + SCValidationErrorResponse, + ]; + this.method = SCRouteHttpVerbs.POST; + this.requestBodyName = 'SCSearchRequest'; + this.responseBodyName = 'SCSearchResponse'; + this.statusCodeSuccess = StatusCodes.OK; + this.urlPath = '/search'; + } +} diff --git a/packages/core/src/protocol/routes/thing-update.ts b/packages/core/src/protocol/routes/thing-update.ts index fac9d378..aca5577a 100644 --- a/packages/core/src/protocol/routes/thing-update.ts +++ b/packages/core/src/protocol/routes/thing-update.ts @@ -21,42 +21,43 @@ import {SCRequestBodyTooLargeErrorResponse} from '../errors/request-body-too-lar import {SCSyntaxErrorResponse} from '../errors/syntax-error.js'; import {SCUnsupportedMediaTypeErrorResponse} from '../errors/unsupported-media-type.js'; import {SCValidationErrorResponse} from '../errors/validation.js'; -import {SCRoute, SCRouteHttpVerbs} from '../route.js'; -import {default as thingUpdateRequestSchema} from 'schema:#SCThingUpdateRequest'; -import {default as thingUpdateResponseSchema} from 'schema:#SCThingUpdateResponse'; +import {SCAbstractRoute, SCRouteHttpVerbs} from '../route.js'; /** * Request to update an existing thing + * @validatable */ export type SCThingUpdateRequest = SCThings; /** * Response for an entity update request + * @validatable */ export interface SCThingUpdateResponse {} /** * Route for updating existing things */ -export type SCThingUpdateRoute = typeof thingUpdateRoute; - -export const thingUpdateRoute = Object.freeze({ - errors: [ - SCInternalServerErrorResponse, - SCMethodNotAllowedErrorResponse, - SCNotFoundErrorResponse, - SCRequestBodyTooLargeErrorResponse, - SCSyntaxErrorResponse, - SCUnsupportedMediaTypeErrorResponse, - SCValidationErrorResponse, - ] as const, - method: SCRouteHttpVerbs.PUT, - obligatoryParameters: { - TYPE: 'SCThingType', - UID: 'SCUuid', - }, - requestBodySchema: thingUpdateRequestSchema, - responseBodySchema: thingUpdateResponseSchema, - statusCodeSuccess: StatusCodes.OK, - urlPath: '/:TYPE/:UID', -}) satisfies Readonly; +export class SCThingUpdateRoute extends SCAbstractRoute { + constructor() { + super(); + this.errorNames = [ + SCInternalServerErrorResponse, + SCMethodNotAllowedErrorResponse, + SCNotFoundErrorResponse, + SCRequestBodyTooLargeErrorResponse, + SCSyntaxErrorResponse, + SCUnsupportedMediaTypeErrorResponse, + SCValidationErrorResponse, + ]; + this.method = SCRouteHttpVerbs.PUT; + this.obligatoryParameters = { + TYPE: 'SCThingType', + UID: 'SCUuid', + }; + this.requestBodyName = 'SCThingUpdateRequest'; + this.responseBodyName = 'SCThingUpdateResponse'; + this.statusCodeSuccess = StatusCodes.OK; + this.urlPath = '/:TYPE/:UID'; + } +} diff --git a/packages/core/src/schemas.ts b/packages/core/src/schemas.ts deleted file mode 100644 index 81a9b631..00000000 --- a/packages/core/src/schemas.ts +++ /dev/null @@ -1,67 +0,0 @@ -import academicEventSchema from 'schema:./things/academic-event.js#SCAcademicEvent'; -import articleSchema from 'schema:./things/article.js#SCArticle'; -import assessmentSchema from 'schema:./things/assessment.js#SCAssessment'; -import bookSchema from 'schema:./things/book.js#SCBook'; -import buildingSchema from 'schema:./things/building.js#SCBuilding'; -import catalogSchema from 'schema:./things/catalog.js#SCCatalog'; -import certificationSchema from 'schema:./things/certification.js#SCCertification'; -import contactPointSchema from 'schema:./things/contact-point.js#SCContactPoint'; -import courseOfStudySchema from 'schema:./things/course-of-study.js#SCCourseOfStudy'; -import dateSeriesSchema from 'schema:./things/date-series.js#SCDateSeries'; -import diffSchema from 'schema:./things/diff.js#SCDiff'; -import dishSchema from 'schema:./things/dish.js#SCDish'; -import favoriteSchema from 'schema:./things/favorite.js#SCFavorite'; -import floorSchema from 'schema:./things/floor.js#SCFloor'; -import idCardSchema from 'schema:./things/id-card.js#SCIdCard'; -import jopPostingSchema from 'schema:./things/job-posting.js#SCJobPosting'; -import messageSchema from 'schema:./things/message.js#SCMessage'; -import organizationSchema from 'schema:./things/organization.js#SCOrganization'; -import periodicalSchema from 'schema:./things/periodical.js#SCPeriodical'; -import personSchema from 'schema:./things/person.js#SCPerson'; -import pointOfInterestSchema from 'schema:./things/point-of-interest.js#SCPointOfInterest'; -import publicationEventSchema from 'schema:./things/publication-event.js#SCPublicationEvent'; -import roomSchema from 'schema:./things/room.js#SCRoom'; -import semesterSchema from 'schema:./things/semester.js#SCSemester'; -import settingSchema from 'schema:./things/setting.js#SCSetting'; -import sportCourseSchema from 'schema:./things/sport-course.js#SCSportCourse'; -import studyModuleSchema from 'schema:./things/study-module.js#SCStudyModule'; -import ticketSchema from 'schema:./things/ticket.js#SCTicket'; -import todoSchema from 'schema:./things/todo.js#SCToDo'; -import tourSchema from 'schema:./things/tour.js#SCTour'; -import videoSchema from 'schema:./things/video.js#SCVideo'; -import {SCThingType} from './things/abstract/thing.js'; -import {JSONSchema7} from 'json-schema'; - -export const thingSchemas: Record = { - 'academic event': academicEventSchema, - 'article': articleSchema, - 'assessment': assessmentSchema, - 'book': bookSchema, - 'building': buildingSchema, - 'catalog': catalogSchema, - 'certification': certificationSchema, - 'contact point': contactPointSchema, - 'course of study': courseOfStudySchema, - 'date series': dateSeriesSchema, - 'diff': diffSchema, - 'dish': dishSchema, - 'favorite': favoriteSchema, - 'floor': floorSchema, - 'id card': idCardSchema, - 'job posting': jopPostingSchema, - 'message': messageSchema, - 'organization': organizationSchema, - 'periodical': periodicalSchema, - 'person': personSchema, - 'point of interest': pointOfInterestSchema, - 'publication event': publicationEventSchema, - 'room': roomSchema, - 'semester': semesterSchema, - 'setting': settingSchema, - 'sport course': sportCourseSchema, - 'study module': studyModuleSchema, - 'ticket': ticketSchema, - 'todo': todoSchema, - 'tour': tourSchema, - 'video': videoSchema, -}; diff --git a/packages/core/src/things/academic-event.ts b/packages/core/src/things/academic-event.ts index 5bc09496..c9a806b0 100644 --- a/packages/core/src/things/academic-event.ts +++ b/packages/core/src/things/academic-event.ts @@ -55,6 +55,7 @@ export interface SCAcademicEventWithoutReferences /** * An academic event + * @validatable * @elasticsearch indexable */ export interface SCAcademicEvent @@ -73,9 +74,6 @@ export interface SCAcademicEvent type: SCThingType.AcademicEvent; } -// export {default as academicEventSchema} from 'schema:#SCAcademicEvent'; -// export {default as academicEventElasticsearchMapping} from 'elasticsearch:#SCAcademicEvent'; - /** * Categories of academic events */ diff --git a/packages/core/src/things/ticket.ts b/packages/core/src/things/ticket.ts index 400c9e4a..abe8969b 100644 --- a/packages/core/src/things/ticket.ts +++ b/packages/core/src/things/ticket.ts @@ -45,6 +45,7 @@ export interface SCTicketWithoutReferences extends SCThingWithoutReferences { /** * A ticket + * @validatable * @elasticsearch indexable */ export interface SCTicket extends SCTicketWithoutReferences, SCThingInPlace { diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts index b9aad40b..299c4daf 100644 --- a/packages/core/tsup.config.ts +++ b/packages/core/tsup.config.ts @@ -1,19 +1,14 @@ import {defineConfig} from 'tsup'; -import {esbuildJsonSchemaPlugin, jsonSchemaPlugin} from '@openstapps/json-schema-generator'; +import {jsonSchemaPlugin} from '@openstapps/json-schema-generator'; import {openapiPlugin} from '@openstapps/openapi-generator'; -import { - elasticsearchMappingGenerator, - esbuildElasticsearchMappingPlugin, -} from '@openstapps/es-mapping-generator'; +import {elasticsearchMappingGenerator} from '@openstapps/es-mapping-generator'; export default defineConfig({ - entry: ['src/index.ts', 'src/schemas.ts', 'src/elasticsearch.ts'], + entry: ['src/index.ts'], sourcemap: true, clean: true, format: 'esm', outDir: 'lib', - esbuildPlugins: [esbuildJsonSchemaPlugin, esbuildElasticsearchMappingPlugin], - noExternal: [/schema:*/, /elasticsearch:*/], plugins: [ jsonSchemaPlugin('schema.json', elasticsearchMappingGenerator('elasticsearch.json')), openapiPlugin('openapi.json', 'schema.json'), diff --git a/packages/es-mapping-generator/src/generator/index.ts b/packages/es-mapping-generator/src/generator/index.ts index c84e8028..ecfd5cb6 100644 --- a/packages/es-mapping-generator/src/generator/index.ts +++ b/packages/es-mapping-generator/src/generator/index.ts @@ -40,7 +40,7 @@ export function transformProject(project: JSONSchema7) { }; } -export const OPTIONS: GeneratorOptions = { +const OPTIONS: GeneratorOptions = { template: { name: 'template_{_type}', index_patterns: 'stapps_{_type}*', diff --git a/packages/es-mapping-generator/src/index.ts b/packages/es-mapping-generator/src/index.ts index 2dac6138..337238fa 100644 --- a/packages/es-mapping-generator/src/index.ts +++ b/packages/es-mapping-generator/src/index.ts @@ -1,48 +1,5 @@ -import {OPTIONS, transformProject} from './generator/index.js'; +import {transformProject} from './generator/index.js'; import {SchemaConsumer} from '@openstapps/json-schema-generator'; -import {Plugin} from 'esbuild'; -// eslint-disable-next-line unicorn/import-style -import {dirname} from 'path'; -import {MappingGenerator} from './generator/mapping-generator.js'; - -export const esbuildElasticsearchMappingPlugin: Plugin = { - name: 'elasticsearch-mappings', - setup(build) { - const fileRegex = /^elasticsearch:/; - const namespace = 'elasticsearch-mappings-ns'; - const mappings = new Map(); - - build.onResolve({filter: fileRegex}, async ({path, importer}) => { - const [from, name] = path.replace(fileRegex, '').split('#', 2); - - return { - path: `${ - from - ? await build - .resolve(from, {resolveDir: dirname(importer), kind: 'import-statement'}) - .then(it => it.path) - : importer - }#${name}`, - namespace, - }; - }); - - build.onLoad({filter: /.*/, namespace}, async ({path}) => { - if (!mappings.has(path)) { - const result = await build.resolve(`schema:${path}`, {kind: 'import-statement'}); - console.log(result); - const context = new MappingGenerator(result.pluginData.schema, OPTIONS); - const name = path.split('#', 2)[1]; - - mappings.set(path, JSON.stringify(context.buildTemplate(name))); - } - return { - contents: mappings.get(path), - loader: 'json', - }; - }); - }, -}; /** * JSON Schema Generator plugin for Elasticsearch Mappings diff --git a/packages/json-schema-generator/src/index.ts b/packages/json-schema-generator/src/index.ts index 6a4fe488..22711aa0 100644 --- a/packages/json-schema-generator/src/index.ts +++ b/packages/json-schema-generator/src/index.ts @@ -3,41 +3,35 @@ import {generateFiles, Plugin, PluginContext} from '@openstapps/tsup-plugin'; import {JSONSchema7} from 'json-schema'; import {Plugin as EsbuildPlugin} from 'esbuild'; import {createGenerator} from 'ts-json-schema-generator'; -import {dirname} from 'path'; export type SchemaConsumer = (this: PluginContext, schema: JSONSchema7) => Record; -export const esbuildJsonSchemaPlugin: EsbuildPlugin = { +export const jsonSchema: EsbuildPlugin = { name: 'json-schema', setup(build) { const fileRegex = /^schema:/; const namespace = 'json-schema-ns'; const schemas = new Map(); - build.onResolve({filter: fileRegex}, async ({path, importer}) => { - const [from, name] = path.replace(fileRegex, '').split('#', 2); - const outputName = `${name}.schema.json`; - if (!schemas.has(outputName)) { - const generator = createGenerator({ - path: from - ? await build - .resolve(from, {resolveDir: dirname(importer), kind: 'import-statement'}) - .then(it => it.path) - : importer, - extraTags: ['elasticsearch'], - skipTypeCheck: true, - }); - schemas.set(outputName, JSON.stringify(generator.createSchema(name))); - } + build.onResolve({filter: fileRegex}, ({path, importer}) => { + const [from, name] = path.replace(fileRegex, '').split('#', 1); return { - path: outputName, - pluginData: {schema: JSON.parse(schemas.get(outputName)!)}, + path: `${from === 'file' ? importer : from}#${name}`, namespace, }; }); build.onLoad({filter: /.*/, namespace}, ({path}) => { + if (!schemas.has(path)) { + const [sourcePath, schemaName] = path.split('#', 1); + const generator = createGenerator({ + path: sourcePath, + extraTags: ['elasticsearch'], + skipTypeCheck: true, + }); + schemas.set(path, JSON.stringify(generator.createSchema(schemaName))); + } return { contents: schemas.get(path), loader: 'json',