From c6ab4ae48b14beeef0cb8945e9e3c9a30872c258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Fri, 27 Oct 2023 22:45:44 +0200 Subject: [PATCH] feat: improve monorepo dev experience --- backend/backend/package.json | 14 +- backend/backend/src/app.ts | 21 +- backend/backend/src/common.ts | 6 - backend/backend/src/routes/route.ts | 27 +- .../src/routes/virtual-plugin-route.ts | 13 +- backend/backend/src/validator.ts | 25 + backend/backend/tsup.config.ts | 10 + package.json | 5 + packages/api-cli/package.json | 2 +- packages/api-plugin/package.json | 2 +- packages/core-tools/package.json | 8 +- packages/core-tools/src/app.ts | 111 +-- .../core-tools/src/better-ajv-errors.d.ts | 26 - packages/core-tools/src/index.ts | 5 +- packages/core-tools/src/routes.ts | 161 ---- packages/core-tools/src/schema.ts | 77 +- packages/core-tools/src/types/routes.ts | 97 -- packages/core-tools/src/util/string.ts | 6 - packages/core-tools/src/validate.ts | 314 ------ packages/core-validator/README.md | 199 ++++ .../compiler/append-schema-map.js | 14 + packages/core-validator/package.json | 80 ++ packages/core-validator/schema/.gitignore | 2 + packages/core-validator/src/index.ts | 48 + packages/core-validator/tsconfig.json | 7 + packages/core/package.json | 25 +- packages/core/src/config/app.ts | 3 +- packages/core/src/config/backend.ts | 10 +- packages/core/src/config/feature.ts | 6 +- packages/core/src/config/monitoring.ts | 6 +- packages/core/src/general/i18n.ts | 4 +- packages/core/src/general/map.ts | 44 - packages/core/src/general/time.ts | 9 +- packages/core/src/general/uuid.ts | 5 +- packages/core/src/index.ts | 1 - packages/core/src/protocol/route.ts | 7 +- .../core/src/protocol/routes/bulk-request.ts | 4 +- .../core/src/protocol/routes/search-multi.ts | 5 +- packages/core/src/protocol/search/filter.ts | 6 +- packages/core/src/protocol/search/sort.ts | 3 +- .../src/things/abstract/academic-degree.ts | 3 +- .../core/src/things/abstract/academic-term.ts | 12 +- .../core/src/things/abstract/creative-work.ts | 10 +- packages/core/src/things/abstract/place.ts | 13 +- packages/core/src/things/abstract/range.ts | 2 - .../src/things/abstract/saveable-thing.ts | 3 +- .../abstract/thing-that-accepts-payments.ts | 2 +- .../abstract/thing-that-can-be-offered.ts | 13 +- .../things/abstract/thing-with-categories.ts | 31 +- packages/core/src/things/abstract/thing.ts | 41 +- packages/core/src/things/academic-event.ts | 17 +- packages/core/src/things/article.ts | 12 +- packages/core/src/things/assessment.ts | 7 +- packages/core/src/things/book.ts | 11 +- packages/core/src/things/building.ts | 11 +- packages/core/src/things/catalog.ts | 10 +- packages/core/src/things/certification.ts | 8 +- packages/core/src/things/contact-point.ts | 13 +- packages/core/src/things/course-of-study.ts | 12 +- packages/core/src/things/date-series.ts | 13 +- packages/core/src/things/diff.ts | 6 +- packages/core/src/things/dish.ts | 25 +- packages/core/src/things/favorite.ts | 6 +- packages/core/src/things/floor.ts | 12 +- packages/core/src/things/id-card.ts | 2 +- packages/core/src/things/job-posting.ts | 7 +- packages/core/src/things/message.ts | 16 +- packages/core/src/things/organization.ts | 8 +- packages/core/src/things/periodical.ts | 11 +- packages/core/src/things/person.ts | 41 +- packages/core/src/things/point-of-interest.ts | 8 +- packages/core/src/things/publication-event.ts | 8 +- packages/core/src/things/room.ts | 16 +- packages/core/src/things/semester.ts | 12 +- packages/core/src/things/setting.ts | 1 - packages/core/src/things/sport-course.ts | 8 +- packages/core/src/things/study-module.ts | 19 +- packages/core/src/things/ticket.ts | 9 +- packages/core/src/things/todo.ts | 10 +- packages/core/src/things/tour.ts | 25 +- packages/core/src/things/video.ts | 17 +- packages/core/test/schema.spec.ts | 10 +- packages/core/tsup.config.ts | 16 + packages/es-mapping-generator/app.js | 2 - packages/es-mapping-generator/package.json | 35 +- packages/es-mapping-generator/src/app.ts | 99 -- .../src/config/fieldmap.ts | 55 -- .../es-mapping-generator/src/config/premap.ts | 64 -- .../src/config/typemap.ts | 62 -- .../es-mapping-generator/src/dsl/schema.ts | 60 ++ .../src/generator/base.ts | 47 + .../src/generator/context.ts | 115 +++ .../src/generator/definition.ts | 32 + .../es-mapping-generator/src/generator/dsl.ts | 48 + .../src/generator/index.ts | 171 ++++ .../src/generator/mapping-generator.ts | 76 ++ .../src/generator/tags.ts | 13 + .../src/generator/transformers/object.ts | 20 + .../src/generator/transformers/string.ts | 19 + packages/es-mapping-generator/src/index.ts | 21 +- packages/es-mapping-generator/src/mapping.ts | 894 ----------------- .../src/project-reflection.ts | 85 -- packages/es-mapping-generator/src/template.ts | 13 + .../src/inherited-property.mapping-test.ts | 13 +- packages/es-mapping-generator/tsconfig.json | 24 +- packages/es-mapping-generator/tsup.config.ts | 12 + packages/json-schema-generator/package.json | 78 ++ .../src/generator/compile-schema.ts | 27 + .../src/generator/get-validatable-types.ts | 34 + packages/json-schema-generator/src/index.ts | 37 + packages/json-schema-generator/tsconfig.json | 3 + packages/openapi-generator/package.json | 77 ++ .../openapi-generator/src/generator/index.ts | 49 + .../src/generator/openapi.ts | 91 ++ .../src/generator/resources/template.ts} | 0 .../openapi-generator/src/generator/routes.ts | 80 ++ .../src/generator/types/abstract-route.ts} | 13 +- .../src/generator/types/route-meta.ts | 28 + packages/openapi-generator/src/index.ts | 42 + packages/openapi-generator/tsconfig.json | 3 + packages/tsup-plugin/package.json | 76 ++ packages/tsup-plugin/src/index.ts | 31 + packages/tsup-plugin/tsconfig.json | 3 + pnpm-lock.yaml | 897 +++++++++++------- 124 files changed, 2647 insertions(+), 2857 deletions(-) create mode 100644 backend/backend/src/validator.ts create mode 100644 backend/backend/tsup.config.ts delete mode 100644 packages/core-tools/src/better-ajv-errors.d.ts delete mode 100644 packages/core-tools/src/routes.ts delete mode 100644 packages/core-tools/src/types/routes.ts delete mode 100644 packages/core-tools/src/validate.ts create mode 100644 packages/core-validator/README.md create mode 100644 packages/core-validator/compiler/append-schema-map.js create mode 100644 packages/core-validator/package.json create mode 100644 packages/core-validator/schema/.gitignore create mode 100644 packages/core-validator/src/index.ts create mode 100644 packages/core-validator/tsconfig.json delete mode 100644 packages/core/src/general/map.ts create mode 100644 packages/core/tsup.config.ts delete mode 100755 packages/es-mapping-generator/app.js delete mode 100644 packages/es-mapping-generator/src/app.ts delete mode 100644 packages/es-mapping-generator/src/config/fieldmap.ts delete mode 100644 packages/es-mapping-generator/src/config/premap.ts delete mode 100644 packages/es-mapping-generator/src/config/typemap.ts create mode 100644 packages/es-mapping-generator/src/dsl/schema.ts create mode 100644 packages/es-mapping-generator/src/generator/base.ts create mode 100644 packages/es-mapping-generator/src/generator/context.ts create mode 100644 packages/es-mapping-generator/src/generator/definition.ts create mode 100644 packages/es-mapping-generator/src/generator/dsl.ts create mode 100644 packages/es-mapping-generator/src/generator/index.ts create mode 100644 packages/es-mapping-generator/src/generator/mapping-generator.ts create mode 100644 packages/es-mapping-generator/src/generator/tags.ts create mode 100644 packages/es-mapping-generator/src/generator/transformers/object.ts create mode 100644 packages/es-mapping-generator/src/generator/transformers/string.ts delete mode 100644 packages/es-mapping-generator/src/mapping.ts delete mode 100644 packages/es-mapping-generator/src/project-reflection.ts create mode 100644 packages/es-mapping-generator/src/template.ts create mode 100644 packages/es-mapping-generator/tsup.config.ts create mode 100644 packages/json-schema-generator/package.json create mode 100644 packages/json-schema-generator/src/generator/compile-schema.ts create mode 100644 packages/json-schema-generator/src/generator/get-validatable-types.ts create mode 100644 packages/json-schema-generator/src/index.ts create mode 100644 packages/json-schema-generator/tsconfig.json create mode 100644 packages/openapi-generator/package.json create mode 100644 packages/openapi-generator/src/generator/index.ts create mode 100644 packages/openapi-generator/src/generator/openapi.ts rename packages/{core-tools/src/resources/openapi-303-template.ts => openapi-generator/src/generator/resources/template.ts} (100%) create mode 100644 packages/openapi-generator/src/generator/routes.ts rename packages/{es-mapping-generator/src/config/settings.ts => openapi-generator/src/generator/types/abstract-route.ts} (65%) create mode 100644 packages/openapi-generator/src/generator/types/route-meta.ts create mode 100644 packages/openapi-generator/src/index.ts create mode 100644 packages/openapi-generator/tsconfig.json create mode 100644 packages/tsup-plugin/package.json create mode 100644 packages/tsup-plugin/src/index.ts create mode 100644 packages/tsup-plugin/tsconfig.json diff --git a/backend/backend/package.json b/backend/backend/package.json index 8dc1141c..ca5aa85e 100644 --- a/backend/backend/package.json +++ b/backend/backend/package.json @@ -43,7 +43,7 @@ "test:unit": "cross-env NODE_CONFIG_ENV=elasticsearch ALLOW_NO_TRANSPORT=true STAPPS_LOG_LEVEL=0 mocha --exit" }, "dependencies": { - "@elastic/elasticsearch": "8.4.0", + "@elastic/elasticsearch": "8.10.0", "@openstapps/core": "workspace:*", "@openstapps/core-tools": "workspace:*", "@openstapps/logger": "workspace:*", @@ -56,6 +56,8 @@ "@types/nodemailer": "6.4.7", "@types/promise-queue": "2.2.0", "@types/uuid": "8.3.4", + "ajv": "8.12.0", + "ajv-formats": "2.1.1", "body-parser": "1.20.2", "cors": "2.8.5", "cosmiconfig": "8.1.3", @@ -102,16 +104,6 @@ "tsup": "6.7.0", "typescript": "5.1.6" }, - "tsup": { - "entry": [ - "src/cli.ts" - ], - "sourcemap": true, - "clean": true, - "target": "es2022", - "format": "esm", - "outDir": "lib" - }, "prettier": "@openstapps/prettier-config", "eslintConfig": { "extends": [ diff --git a/backend/backend/src/app.ts b/backend/backend/src/app.ts index ea4820bc..ce707d03 100644 --- a/backend/backend/src/app.ts +++ b/backend/backend/src/app.ts @@ -14,6 +14,7 @@ * along with this program. If not, see . */ import { + SCConfigFile, SCNotFoundErrorResponse, SCRequestBodyTooLargeErrorResponse, SCSyntaxErrorResponse, @@ -23,8 +24,7 @@ import {Logger} from '@openstapps/logger'; import cors from 'cors'; import {Express} from 'express'; import morgan from 'morgan'; -import path from 'path'; -import {DEFAULT_TIMEOUT, isTestEnvironment, mailer, plugins, validator} from './common.js'; +import {DEFAULT_TIMEOUT, isTestEnvironment, mailer, plugins} from './common.js'; import {getPrometheusMiddleware} from './middleware/prometheus.js'; import {MailQueue} from './notification/mail-queue.js'; import {bulkAddRouter} from './routes/bulk-add-route.js'; @@ -39,7 +39,7 @@ import {virtualPluginRoute} from './routes/virtual-plugin-route.js'; import {BulkStorage} from './storage/bulk-storage.js'; import {DatabaseConstructor} from './storage/database.js'; import {backendConfig} from './config.js'; -import {fileURLToPath} from 'url'; +import {createValidator} from './validator.js'; /** * Configure the backend @@ -143,19 +143,10 @@ export async function configureApp(app: Express, databases: {[name: string]: Dat request.on('data', chunkGatherer).on('end', endCallback); }); - // validate config file - const directory = path.dirname(fileURLToPath(import.meta.url)); - await validator.addSchemas( - path.join(directory, '..', 'node_modules', '@openstapps', 'core', 'lib', 'schema'), - ); - - // validate the config file - const configValidation = validator.validate(backendConfig, 'SCConfigFile'); - - // validation failed - if (configValidation.errors.length > 0) { + const configFileValid = createValidator('SCConfigFile'); + if (!configFileValid(backendConfig)) { throw new Error( - `Validation of config file failed. Errors were: ${JSON.stringify(configValidation.errors)}`, + `Validation of config file failed. Errors were: ${JSON.stringify(configFileValid.errors)}`, ); } diff --git a/backend/backend/src/common.ts b/backend/backend/src/common.ts index da6b2a98..7c07d6a6 100644 --- a/backend/backend/src/common.ts +++ b/backend/backend/src/common.ts @@ -14,7 +14,6 @@ * along with this program. If not, see . */ import {SCPluginMetaData} from '@openstapps/core'; -import {Validator} from '@openstapps/core-tools'; import {BackendTransport} from './notification/backend-transport.js'; /** @@ -22,11 +21,6 @@ import {BackendTransport} from './notification/backend-transport.js'; */ export const mailer = BackendTransport.getTransportInstance(); -/** - * A validator instance to check if something is a valid JSON object (e.g. a request or a thing) - */ -export const validator = new Validator(); - /** * Provides information if the backend is executed in the "test" (non-production) environment */ diff --git a/backend/backend/src/routes/route.ts b/backend/backend/src/routes/route.ts index 01280bba..fca535d8 100644 --- a/backend/backend/src/routes/route.ts +++ b/backend/backend/src/routes/route.ts @@ -19,12 +19,12 @@ import { SCRoute, SCValidationErrorResponse, } from '@openstapps/core'; -import {ValidationError} from '@openstapps/core-tools/src/types/validator.js'; import {Logger} from '@openstapps/logger'; import {Application, Router} from 'express'; import PromiseRouter from 'express-promise-router'; -import {isTestEnvironment, validator} from '../common.js'; +import {isTestEnvironment} from '../common.js'; import {isHttpMethod} from './http-types.js'; +import {createValidator} from '../validator.js'; /** * Creates a router from a route class and a handler function which implements the logic @@ -44,6 +44,8 @@ export function createRoute( ): Router { // create router const router = PromiseRouter({mergeParams: true}); + const requestValidator = createValidator(routeClass.requestBodyName); + const responseValidator = createValidator(routeClass.responseBodyName); // create route // the given type has no index signature so we have to cast to get the IRouteHandler when a HTTP method is given @@ -56,11 +58,8 @@ export function createRoute( // create a route handler for the given HTTP method route[verb](async (request, response) => { try { - // validate request - const requestValidation = validator.validate(request.body, routeClass.requestBodyName); - - if (requestValidation.errors.length > 0) { - const error = new SCValidationErrorResponse(requestValidation.errors, isTestEnvironment); + if (!requestValidator(request.body)) { + const error = new SCValidationErrorResponse(requestValidator.errors as any, isTestEnvironment); response.status(error.statusCode); response.json(error); await Logger.error(error); @@ -68,17 +67,13 @@ export function createRoute( return; } - // hand over request to handler with path parameters const handlerResponse = await handler(request.body, request.app, request.params); - // validate response generated by handler - const responseErrors: ValidationError[] = validator.validate( - handlerResponse, - routeClass.responseBodyName, - ).errors; - - if (responseErrors.length > 0) { - const validationError = new SCValidationErrorResponse(responseErrors, isTestEnvironment); + if (!responseValidator(handlerResponse)) { + const validationError = new SCValidationErrorResponse( + responseValidator.errors as any, + isTestEnvironment, + ); // The validation error is not caused by faulty user input, but through an error that originates somewhere in // the backend, therefore we use this "stacked" error. const internalServerError = new SCInternalServerErrorResponse(validationError, isTestEnvironment); diff --git a/backend/backend/src/routes/virtual-plugin-route.ts b/backend/backend/src/routes/virtual-plugin-route.ts index a96bdf80..babc2434 100644 --- a/backend/backend/src/routes/virtual-plugin-route.ts +++ b/backend/backend/src/routes/virtual-plugin-route.ts @@ -17,8 +17,9 @@ import {SCInternalServerErrorResponse, SCPluginMetaData, SCValidationErrorResponse} from '@openstapps/core'; import {Request} from 'express'; import got from 'got'; -import {isTestEnvironment, validator} from '../common.js'; +import {isTestEnvironment} from '../common.js'; import {backendConfig} from '../config.js'; +import {validator} from '../validator.js'; /** * Generic route function used to proxy actual requests to plugins @@ -28,10 +29,9 @@ import {backendConfig} from '../config.js'; */ export async function virtualPluginRoute(request: Request, plugin: SCPluginMetaData): Promise { try { - const requestValidation = validator.validate(request.body, plugin.requestSchema); - if (requestValidation.errors.length > 0) { + if (!validator.validate(request.body, plugin.requestSchema)) { // noinspection ExceptionCaughtLocallyJS - throw new SCValidationErrorResponse(requestValidation.errors, isTestEnvironment); + throw new SCValidationErrorResponse(validator.errors as any, isTestEnvironment); } // send the request to the plugin (forward the body) and save the response const response = await got.post(plugin.route.replaceAll(/^\//gi, ''), { @@ -43,10 +43,9 @@ export async function virtualPluginRoute(request: Request, plugin: SCPluginMetaD responseType: 'json', }); const responseBody = response.body; - const responseValidation = validator.validate(responseBody, plugin.responseSchema); - if (responseValidation.errors.length > 0) { + if (!validator.validate(responseBody, plugin.responseSchema)) { // noinspection ExceptionCaughtLocallyJS - throw new SCValidationErrorResponse(responseValidation.errors, isTestEnvironment); + throw new SCValidationErrorResponse(validator.errors as any, isTestEnvironment); } return responseBody as object; } catch (error) { diff --git a/backend/backend/src/validator.ts b/backend/backend/src/validator.ts new file mode 100644 index 00000000..38366c8e --- /dev/null +++ b/backend/backend/src/validator.ts @@ -0,0 +1,25 @@ +import Ajv from 'ajv'; +import addFormats from 'ajv-formats'; +import schema from '@openstapps/core?json-schema'; + +export const validator = new Ajv.default({ + schemas: [schema], + verbose: true, + allowUnionTypes: true, +}); +addFormats.default(validator, { + formats: ['date-time', 'time', 'uuid', 'duration'], + mode: 'fast', +}); + +/** + * Create a validator function + * @example + * import schema from '@openstapps/core#schema:SCThings' + * createValidator(schema) + */ +export function createValidator(schemaName: string): Ajv.ValidateFunction { + return validator.compile({ + $ref: `#/definitions/${schemaName}`, + }); +} diff --git a/backend/backend/tsup.config.ts b/backend/backend/tsup.config.ts new file mode 100644 index 00000000..bdd265c7 --- /dev/null +++ b/backend/backend/tsup.config.ts @@ -0,0 +1,10 @@ +import {defineConfig} from 'tsup'; + +export default defineConfig({ + entry: ['src/cli.ts'], + sourcemap: true, + clean: true, + target: 'es2022', + format: 'esm', + outDir: 'lib', +}); diff --git a/package.json b/package.json index d3c556a4..1114bef0 100644 --- a/package.json +++ b/package.json @@ -40,5 +40,10 @@ "turbo-ignore": "1.10.6", "typedoc": "0.24.8", "typescript": "5.1.6" + }, + "pnpm": { + "patchedDependencies": { + "@elastic/elasticsearch@8.10.0": "patches/@elastic__elasticsearch@8.10.0.patch" + } } } diff --git a/packages/api-cli/package.json b/packages/api-cli/package.json index 0aaf52af..3ce5e366 100644 --- a/packages/api-cli/package.json +++ b/packages/api-cli/package.json @@ -43,7 +43,7 @@ "@types/cli-progress": "3.11.0", "@types/express": "4.17.17", "@types/fs-extra": "9.0.13", - "@types/json-schema": "7.0.11", + "@types/json-schema": "7.0.14", "@types/junit-report-builder": "3.0.0", "@types/mocha": "10.0.1", "@types/node": "18.15.3", diff --git a/packages/api-plugin/package.json b/packages/api-plugin/package.json index 8051413d..e57c1198 100644 --- a/packages/api-plugin/package.json +++ b/packages/api-plugin/package.json @@ -38,7 +38,7 @@ "@openstapps/logger": "workspace:*", "@types/body-parser": "1.19.2", "@types/express": "4.17.17", - "@types/json-schema": "7.0.11", + "@types/json-schema": "7.0.14", "@types/morgan": "1.9.4", "body-parser": "1.20.2", "express": "4.18.2", diff --git a/packages/core-tools/package.json b/packages/core-tools/package.json index 59f97975..28fd02b9 100644 --- a/packages/core-tools/package.json +++ b/packages/core-tools/package.json @@ -49,6 +49,7 @@ "@openstapps/easy-ast": "workspace:*", "@openstapps/logger": "workspace:*", "ajv": "8.12.0", + "ajv-formats": "2.1.1", "better-ajv-errors": "1.2.0", "commander": "10.0.0", "deepmerge": "4.3.1", @@ -60,11 +61,10 @@ "humanize-string": "3.0.0", "json-schema": "0.4.0", "mustache": "4.2.0", - "openapi-types": "12.1.0", + "openapi-types": "12.1.3", "plantuml-encoder": "1.4.0", - "re2": "1.18.2", "toposort": "2.0.2", - "ts-json-schema-generator": "1.2.0" + "ts-json-schema-generator": "1.4.0" }, "devDependencies": { "@openstapps/eslint-config": "workspace:*", @@ -73,7 +73,7 @@ "@types/chai": "4.3.5", "@types/fs-extra": "9.0.13", "@types/glob": "8.0.1", - "@types/json-schema": "7.0.11", + "@types/json-schema": "7.0.14", "@types/mocha": "10.0.1", "@types/mustache": "4.2.2", "@types/node": "18.15.3", diff --git a/packages/core-tools/src/app.ts b/packages/core-tools/src/app.ts index 15f242e6..333ca158 100644 --- a/packages/core-tools/src/app.ts +++ b/packages/core-tools/src/app.ts @@ -17,15 +17,17 @@ import {Command} from 'commander'; import {existsSync, readFileSync, writeFileSync} from 'fs'; import path from 'path'; import {lightweightDefinitionsFromPath, lightweightProjectFromPath} from '@openstapps/easy-ast'; -import {openapi3Template} from './resources/openapi-303-template.js'; -import {gatherRouteInformation, generateOpenAPIForRoute} from './routes.js'; -import {Converter, getValidatableTypesInPath} from './schema.js'; +import {openapi3Template} from '../../openapi-generator/src/openapi-303-template.js'; +import { + gatherRouteInformation, + generateOpenAPIForRoute, +} from '../../openapi-generator/src/generator/routes.js'; +import {Converter, getValidatableTypesInPath, mergeSchemas} from './schema.js'; import {createDiagram, createDiagramFromString} from './uml/create-diagram.js'; import {UMLConfig} from './uml/uml-config.js'; import {capitalize} from './util/string.js'; -import {validateFiles, writeReport} from './validate.js'; import {fileURLToPath} from 'url'; -import {mkdir, readFile} from 'fs/promises'; +import {readFile} from 'fs/promises'; // handle unhandled promise rejections process.on('unhandledRejection', async (reason: unknown) => { @@ -52,56 +54,10 @@ commander.command('prototype ').action(async (sourcePath, out) commander .command('openapi ') - .action(async (relativeSourceBundlePath, relativeOutDirectoryPath) => { - // get absolute paths - const sourcePath = path.resolve(relativeSourceBundlePath); - const outDirectoryPath = path.resolve(relativeOutDirectoryPath); - const outDirectorySchemasPath = path.join(outDirectoryPath, 'schema'); + .action(async (relativeSourceBundlePath, relativeOutDirectoryPath) => {}); - // get information about routes - const routes = await gatherRouteInformation(sourcePath); - routes.sort((a, b) => a.route.urlPath.localeCompare(b.route.urlPath)); - - // change url path parameters to openapi notation - for (const routeWithMetaInformation of routes) { - routeWithMetaInformation.route.urlPath = routeWithMetaInformation.route.urlPath.replaceAll( - /:\w+/g, - (match: string) => `{${match.replace(':', '')}}`, - ); - } - - // keep openapi tags for routes that actually share url fragments - let tagsToKeep = routes.map(routeWithMetaInformation => - capitalize(routeWithMetaInformation.route.urlPath.split('/')[1]), - ); - tagsToKeep = tagsToKeep.filter( - (element, i, array) => array.indexOf(element) === i && array.lastIndexOf(element) !== i, - ); - - // initialize json output - const output = openapi3Template; - - // generate documentation for all routes - for (const routeWithMetaInformation of routes) { - routeWithMetaInformation.tags = [capitalize(routeWithMetaInformation.route.urlPath.split('/')[1])]; - - output.paths[routeWithMetaInformation.route.urlPath] = generateOpenAPIForRoute( - routeWithMetaInformation, - path.relative(relativeOutDirectoryPath, outDirectorySchemasPath), - tagsToKeep, - ); - } - - // write openapi object to file (prettified) - writeFileSync(path.join(outDirectoryPath, 'openapi.json'), JSON.stringify(output, undefined, 2)); - - Logger.ok(`OpenAPI representation resources written to ${outDirectoryPath} .`); - }); - -commander.command('schema ').action(async (relativeSourcePath, relativeSchemaPath) => { - // get absolute paths +commander.command('schema ').action(async (relativeSourcePath, schemaPath) => { const absoluteSourcePath = path.resolve(relativeSourcePath); - const schemaPath = path.resolve(relativeSchemaPath); // initialize new core converter const coreConverter = new Converter(absoluteSourcePath); @@ -111,10 +67,6 @@ commander.command('schema ').action(async (relativeSourceP Logger.info(`Found ${validatableTypes.length} type(s) to generate schemas for.`); - await mkdir(schemaPath, { - recursive: true, - }); - Logger.info(`Trying to find a package.json for ${absoluteSourcePath}.`); let packagePath = absoluteSourcePath; @@ -134,53 +86,12 @@ commander.command('schema ').action(async (relativeSourceP Logger.log(`Using ${coreVersion} as version for schemas.`); // generate and write JSONSchema files for validatable types - for (const type of validatableTypes) { - const schema = coreConverter.getSchema(type, coreVersion); - - const stringifiedSchema = JSON.stringify(schema, undefined, 2); - - const file = path.join(schemaPath, `${type}.json`); - - // write schema to file - writeFileSync(file, stringifiedSchema); - - Logger.info(`Generated schema for ${type} and saved to ${file}.`); - } + const schema = mergeSchemas(validatableTypes.map(type => coreConverter.getSchema(type, coreVersion))); + writeFileSync(schemaPath, JSON.stringify(schema, undefined, 2)); Logger.ok(`Generated schemas for ${validatableTypes.length} type(s).`); }); -commander - .command('validate [reportPath]') - .action(async (relativeSchemaPath, relativeTestPath, relativeReportPath) => { - // get absolute paths - const schemaPath = path.resolve(relativeSchemaPath); - const testPath = path.resolve(relativeTestPath); - - const errorsPerFile = await validateFiles(schemaPath, testPath); - - let unexpected = false; - for (const file in errorsPerFile) { - if (!errorsPerFile.hasOwnProperty(file)) { - continue; - } - - unexpected = unexpected || errorsPerFile[file].some(error => !error.expected); - } - - if (relativeReportPath !== undefined) { - const reportPath = path.resolve(relativeReportPath); - await writeReport(reportPath, errorsPerFile); - } - - if (unexpected) { - await Logger.error('Unexpected errors occurred during validation'); - process.exit(1); - } else { - Logger.ok('Successfully finished validation.'); - } - }); - commander .command('plantuml ') .option('--definitions ', 'Shows these specific definitions (class, interface or enum)', it => diff --git a/packages/core-tools/src/better-ajv-errors.d.ts b/packages/core-tools/src/better-ajv-errors.d.ts deleted file mode 100644 index 3d657a3e..00000000 --- a/packages/core-tools/src/better-ajv-errors.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -declare module 'better-ajv-errors' { - import type {ErrorObject} from 'ajv'; - - export interface IOutputError { - start: {line: number; column: number; offset: number}; - // Optional for required - end?: {line: number; column: number; offset: number}; - error: string; - suggestion?: string; - } - - export interface IInputOptions { - format?: 'cli' | 'js'; - indent?: number | null; - - /** Raw JSON used when highlighting error location */ - json?: string | null; - } - - export default function ( - schema: S, - data: T, - errors: Array, - options?: Options, - ): Options extends {format: 'js'} ? Array : string; -} diff --git a/packages/core-tools/src/index.ts b/packages/core-tools/src/index.ts index dfd380fd..1a47567b 100644 --- a/packages/core-tools/src/index.ts +++ b/packages/core-tools/src/index.ts @@ -1,11 +1,10 @@ -export * from './validate.js'; export * from './types/validator.js'; export * from './uml/uml-config.js'; export * from './uml/create-diagram.js'; -export * from './routes.js'; -export * from './types/routes.js'; +export * from '../../openapi-generator/src/generator/routes.js'; +export * from '../../openapi-generator/src/generator/types/routes.js'; export * from './schema.js'; export * from './types/schema.js'; diff --git a/packages/core-tools/src/routes.ts b/packages/core-tools/src/routes.ts deleted file mode 100644 index 40be6b98..00000000 --- a/packages/core-tools/src/routes.ts +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2018-2021 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {OpenAPIV3} from 'openapi-types'; -import { - isLightweightClass, - lightweightProjectFromPath, - LightweightProjectWithIndex, -} from '@openstapps/easy-ast'; -import {RouteInstanceWithMeta, RouteWithMetaInformation} from './types/routes.js'; -import {rejectNil} from './util/collections.js'; -import {capitalize} from './util/string.js'; -import path from 'path'; - -/** - * Gather relevant information of routes - * - * This gathers the information for all routes that implement the abstract class SCAbstractRoute. - * Furthermore it instantiates every route and adds it to the information. - */ -export async function gatherRouteInformation(path: string): Promise { - const project = new LightweightProjectWithIndex(lightweightProjectFromPath(path)); - - // find all classes that implement the SCAbstractRoute - return rejectNil( - await Promise.all( - Object.values(project.definitions) - .filter(isLightweightClass) - .map(async node => { - if (!node.extendedDefinitions?.some(it => it.referenceName === 'SCAbstractRoute')) { - return undefined; - } - - const instantiatedRoute = (await project.instantiateDefinitionByName( - node.name, - )) as RouteInstanceWithMeta; - // instantiate all errors - instantiatedRoute.errors = await Promise.all( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - instantiatedRoute.errorNames.map(async (error: any) => - // eslint-disable-next-line @typescript-eslint/ban-types - Object.assign((await project.instantiateDefinitionByName(error.name)) as object, { - name: error.name, - }), - ), - ); - instantiatedRoute.responseBodyDescription = - // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain - project.definitions[instantiatedRoute.responseBodyName]?.comment?.shortSummary!; - instantiatedRoute.requestBodyDescription = - // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain - project.definitions[instantiatedRoute.requestBodyName]?.comment?.shortSummary!; - - return { - description: { - shortText: node.comment?.shortSummary, - text: node.comment?.description, - }, - name: node.name!, - route: instantiatedRoute, - }; - }), - ), - ); -} - -/** - * Generate documentation snippet for one route - * @param routeWithInfo A route instance with its meta information - * @param outDirectorySchemasPath Path to directory that will contain relevant schemas for the route - * @param tagsToKeep Tags / keywords that can be used for grouping routes - */ -export function generateOpenAPIForRoute( - routeWithInfo: RouteWithMetaInformation, - outDirectorySchemasPath: string, - tagsToKeep: string[], -): OpenAPIV3.PathItemObject { - const route = routeWithInfo.route; - const openapiPath: OpenAPIV3.PathItemObject = {}; - - openapiPath[route.method.toLowerCase() as OpenAPIV3.HttpMethods] = { - summary: capitalize(routeWithInfo.description.shortText?.replace(/(Route to |Route for )/gim, '')), - description: routeWithInfo.description.text, - requestBody: { - description: route.responseBodyDescription ?? undefined, - content: { - 'application/json': { - schema: { - $ref: path.join(outDirectorySchemasPath, `${route.requestBodyName}.json`), - }, - }, - }, - }, - parameters: [ - { - name: 'X-StApps-Version', - in: 'header', - schema: { - type: 'string', - example: '2.0.0', - }, - required: true, - }, - ], - responses: {}, - tags: routeWithInfo.tags?.filter(value => tagsToKeep.includes(value)), - }; - - openapiPath[route.method.toLowerCase() as OpenAPIV3.HttpMethods]!.responses![route.statusCodeSuccess] = { - description: route.responseBodyDescription, - content: { - 'application/json': { - schema: { - $ref: path.join(outDirectorySchemasPath, `${route.responseBodyName}.json`), - }, - }, - }, - }; - - for (const error of route.errors) { - openapiPath[route.method.toLowerCase() as OpenAPIV3.HttpMethods]!.responses![error.statusCode] = { - description: - error.message ?? capitalize(error.name.replaceAll(/([A-Z][a-z])/g, ' $1').replace('SC ', '')), - content: { - 'application/json': { - schema: { - $ref: path.join(outDirectorySchemasPath, `${error.name}.json`), - }, - }, - }, - }; - } - - if (typeof route.obligatoryParameters === 'object') { - for (const [parameter, schemaDefinition] of Object.entries(route.obligatoryParameters)) { - const openapiParameter: OpenAPIV3.ParameterObject = { - in: 'path', - name: parameter, - required: true, - schema: { - // TODO make this less of a hack and search copied schemas for the first occurring definition - $ref: `schema/SCSearchResponse.json#/definitions/${schemaDefinition}`, - }, - }; - openapiPath[route.method.toLowerCase() as OpenAPIV3.HttpMethods]?.parameters?.push(openapiParameter); - } - } - - return openapiPath; -} diff --git a/packages/core-tools/src/schema.ts b/packages/core-tools/src/schema.ts index 677eaf62..00927364 100644 --- a/packages/core-tools/src/schema.ts +++ b/packages/core-tools/src/schema.ts @@ -12,17 +12,18 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import Ajv from 'ajv'; -import {JSONSchema7 as JSONSchema} from 'json-schema'; -import {Config, DEFAULT_CONFIG, Definition, SchemaGenerator} from 'ts-json-schema-generator'; -import {createFormatter} from 'ts-json-schema-generator'; -import {createParser} from 'ts-json-schema-generator'; -import {createProgram} from 'ts-json-schema-generator'; +import Ajv, {JSONSchemaType} from 'ajv'; +import { + Config, + DEFAULT_CONFIG, + SchemaGenerator, + createParser, + createFormatter, + createProgram, +} from 'ts-json-schema-generator'; import {getTsconfigPath} from './common.js'; import {definitionsOf, lightweightProjectFromPath} from '@openstapps/easy-ast'; -import {isSchemaWithDefinitions} from './util/guards.js'; import path from 'path'; -import re2 from 're2'; /** * StAppsCore converter @@ -30,74 +31,35 @@ import re2 from 're2'; * Converts TypeScript source files to JSON schema files */ export class Converter { - /** - * Generator instance - */ private readonly generator: SchemaGenerator; - /** - * Schema validator instance - */ private readonly schemaValidator: Ajv.default; /** - * Create a new converter * @param projectPath Path to the project * @param sourcePath Path to optionally point to a different directory of / or single source file */ constructor(projectPath: string, sourcePath?: string) { - // set config for schema generator const config: Config = { ...DEFAULT_CONFIG, path: sourcePath, - sortProps: true, - topRef: false, tsconfig: path.join(getTsconfigPath(projectPath), 'tsconfig.json'), - type: 'SC', }; - // create TypeScript program from config const program = createProgram(config); - - // create generator this.generator = new SchemaGenerator(program, createParser(program, config), createFormatter(config)); - - // create Ajv instance - this.schemaValidator = new Ajv.default({code: {regExp: re2 as never}}); + this.schemaValidator = new Ajv.default(); } /** * Get schema for specific StAppsCore type * @param type Type to get the schema for - * @param version Version to set for the schema + * @param _version Version to set for the schema * @returns Generated schema */ - getSchema(type: string, version: string): JSONSchema { - // generate schema for this file/type - const schema: JSONSchema = this.generator.createSchema(type); - - // set id of schema - schema.$id = `https://core.stapps.tu-berlin.de/v${version}/lib/schema/${type}.json`; - - if (isSchemaWithDefinitions(schema)) { - const selfReference = { - ...schema, - }; - - delete selfReference.$schema; - delete selfReference.definitions; - delete selfReference.$id; - - // add self reference to definitions - schema.definitions![`SC${type}`] = { - ...(selfReference as unknown as Definition), - }; - } - - if (!this.schemaValidator.validateSchema(schema)) { - throw new Error(`Generated schema for ${type} is invalid!`); - } - + getSchema(type: string, _version: string): JSONSchemaType { + const schema = this.generator.createSchema(type) as JSONSchemaType; + this.schemaValidator.validateSchema(schema, true); return schema; } } @@ -110,3 +72,14 @@ export function getValidatableTypesInPath(path: string): string[] { .filter(type => !!type.comment?.tags?.find(it => it.name === 'validatable')) .map(type => type.name); } + +/** + * Merge multiple schemas + */ +export function mergeSchemas(schemas: JSONSchemaType[]): JSONSchemaType { + const completeSchema = {definitions: {}} as JSONSchemaType; + for (const schema of schemas) { + Object.assign(completeSchema.definitions!, schema.definitions); + } + return completeSchema; +} diff --git a/packages/core-tools/src/types/routes.ts b/packages/core-tools/src/types/routes.ts deleted file mode 100644 index 48ada965..00000000 --- a/packages/core-tools/src/types/routes.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2018-2021 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type SCRoute = any; - -export interface RouteInstanceWithMeta extends SCRoute { - /** - * Possible errors on a route - */ - errors: SCErrorResponse[]; - - /** - * Description of the request body - */ - requestBodyDescription: string; - - /** - * Description of the response body - */ - responseBodyDescription: string; -} - -/** - * A route instance with its relevant meta information - */ -export interface RouteWithMetaInformation { - /** - * Description of the route - */ - description: { - /** - * Short text of the description - title - */ - shortText?: string; - /** - * Text of the description - */ - text?: string; - }; - /** - * Name of the route - */ - name: string; - - /** - * Instance of the route - */ - route: RouteInstanceWithMeta; - - /** - * Possible tags/keywords the route can be associated with - */ - tags?: [string]; -} - -/** - * A node with its relevant meta information - */ -export interface NodeWithMetaInformation { - /** - * Module the node belongs to - */ - module: string; - - /** - * Type of the node - */ - type: string; -} - -/** - * A generic error that can be returned by the backend if somethings fails during the processing of a request - */ -export interface SCErrorResponse extends Error { - /** - * Additional data that describes the error - */ - additionalData?: unknown; - - /** - * HTTP status code to return this error with - */ - statusCode: number; -} diff --git a/packages/core-tools/src/util/string.ts b/packages/core-tools/src/util/string.ts index c9a726e4..5162af4c 100644 --- a/packages/core-tools/src/util/string.ts +++ b/packages/core-tools/src/util/string.ts @@ -12,9 +12,3 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -/** - * Creates sentence cased string - */ -export function capitalize(string?: string): string { - return `${string?.charAt(0).toUpperCase()}${string?.slice(1).toLowerCase()}`; -} diff --git a/packages/core-tools/src/validate.ts b/packages/core-tools/src/validate.ts deleted file mode 100644 index 77953563..00000000 --- a/packages/core-tools/src/validate.ts +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (C) 2018-2021 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {Logger} from '@openstapps/logger'; -import Ajv from 'ajv'; -import betterAjvErrors, {IOutputError} from 'better-ajv-errors'; -import type {PathLike} from 'fs'; -import {readFile, writeFile} from 'fs/promises'; -import {JSONSchema7} from 'json-schema'; -import mustache from 'mustache'; -import {Schema} from 'ts-json-schema-generator'; -import {ExpectedValidationErrors, ValidationError, ValidationResult} from './types/validator.js'; -import {isThingWithType} from './util/guards.js'; -import path from 'path'; -import re2 from 're2'; -import {glob} from 'glob'; -import {fileURLToPath} from 'url'; - -/** - * StAppsCore validator - */ -export class Validator { - /** - * JSON Schema Validator - */ - private readonly ajv = new Ajv.default({ - verbose: true, - allowUnionTypes: true, - code: {regExp: re2 as never}, - }); - - /** - * Map of schema names to schemas - */ - private readonly schemas: {[type: string]: Schema} = {}; - - /** - * A wrapper function for Ajv that transforms the error into the compatible old error - * @param schema the schema that will be validated against - * @param instance the instance that will be validated - */ - private ajvValidateWrapper(schema: JSONSchema7, instance: unknown): ValidationResult { - return fromAjvResult(this.ajv.validate(schema, instance), schema, instance, this.ajv); - } - - /** - * Feed the schema files to the validator - * @param schemaDirectory Path to directory that contains schema files - */ - public async addSchemas(schemaDirectory: string): Promise { - const searchGlob = path.posix.join(schemaDirectory.replaceAll(path.sep, path.posix.sep), '*.json'); - const schemaFiles = await glob(searchGlob); - - if (schemaFiles.length === 0) { - throw new Error(`No schema files in ${schemaDirectory.toString()}!`); - } - - Logger.log(`Adding schemas from ${schemaDirectory} to validator.`); - - await Promise.all( - schemaFiles.map(async (file: string) => { - // read schema file - const buffer = await readFile(file); - - // add schema to map - this.schemas[path.basename(file, '.json')] = JSON.parse(buffer.toString()); - - Logger.info(`Added ${file} to validator.`); - }), - ); - - return schemaFiles; - } - - /** - * Validates anything against a given schema name or infers schema name from object - * @param instance Instance to validate - * @param schema Name of schema to validate instance against or the schema itself - */ - public validate(instance: unknown, schema?: string | Schema): ValidationResult { - if (schema === undefined) { - if (isThingWithType(instance)) { - // schema name can be inferred from type string - const schemaSuffix = (instance as {type: string}).type - .split(' ') - .map((part: string) => { - return part.slice(0, 1).toUpperCase() + part.slice(1); - }) - .join(''); - const schemaName = `SC${schemaSuffix}`; - - return this.validate(instance, schemaName); - } - throw new Error('Instance.type does not exist.'); - } - if (typeof schema === 'string') { - // if you want to access a schema that is contained in the validator object - if (typeof this.schemas[schema] !== 'object') { - throw new TypeError(`No schema available for ${schema}.`); - } - - // schema will be cached - return this.ajvValidateWrapper(this.schemas[schema], instance); - } - - return this.ajvValidateWrapper(schema, instance); - } -} - -/** - * Creates a ValidationResult from ajv - * - * Implemented for compatibility purposes - * @param result the result, now a ValidationResult - * @param schema the schema that has been validated against - * @param instance the data that has been validated - * @param ajvInstance the ajv instance with which the validation was done - */ -function fromAjvResult( - result: boolean | PromiseLike, - schema: JSONSchema7, - instance: unknown, - ajvInstance: Ajv.default, -): ValidationResult { - const betterErrorObject: IOutputError[] | undefined = betterAjvErrors( - schema, - instance, - ajvInstance.errors ?? [], - // eslint-disable-next-line unicorn/no-null - {format: 'js', indent: null}, - ); - - return { - errors: - ajvInstance.errors?.map((ajvError, index) => { - const error: ValidationError = { - dataPath: ajvError.instancePath, - instance: instance, - message: betterErrorObject?.[index]?.error ?? ajvError.message, - name: ajvError.keyword, - schemaPath: ajvError.schemaPath, - suggestion: betterErrorObject?.[index]?.suggestion, - }; - // (validationError as ValidationError).humanReadableError = betterErrorCLI?.[index] as unknown as string; - - return error; - }) ?? [], - valid: typeof result === 'boolean' ? result : false, - }; -} - -/** - * Validate all test files in the given resources directory against schema files in the given (schema) directory - * @param schemaDirectory The directory where the JSON schema files are - * @param resourcesDirectory The directory where the test files are - */ -export async function validateFiles( - schemaDirectory: string, - resourcesDirectory: string, -): Promise { - // instantiate new validator - const v = new Validator(); - await v.addSchemas(schemaDirectory); - - // get a list of files to test - const testFiles = await glob( - path.posix.join(resourcesDirectory.replaceAll(path.sep, path.posix.sep), '*.json'), - {absolute: true}, - ); - - if (testFiles.length === 0) { - throw new Error(`No test files in ${resourcesDirectory}!`); - } - - Logger.log(`Found ${testFiles.length} file(s) to test.`); - - // map of errors per file - const errors: ExpectedValidationErrors = {}; - - await Promise.all( - testFiles.map(async (testFile: string) => { - const testFileName = path.basename(testFile); - - const buffer = await readFile(testFile); - - // read test description from file - const testDescription = JSON.parse(buffer.toString()); - - // validate instance from test description - const result = v.validate(testDescription.instance, testDescription.schema); - - // list of expected errors for this test description - const expectedErrors: string[] = [...testDescription.errorNames]; - - // number of unexpected errors - let unexpectedErrors = 0; - - if (result.errors.length > 0) { - errors[testFileName] = []; - - // iterate over errors - for (const error of result.errors) { - const errorIndex = expectedErrors.indexOf(error.name); - let expected = false; - - if (errorIndex >= 0) { - expectedErrors.splice(errorIndex, 1); - expected = true; - } else { - unexpectedErrors++; - await Logger.error(`Unexpected error ${error.name} in ${testFile}`); - } - - // add error to list of errors - errors[testFileName].push({ - ...error, - expected, - }); - } - } - - if (expectedErrors.length > 0) { - for (const error of expectedErrors) { - await Logger.error(`Extraneous expected error '${error}' in ${testFile}.`); - - errors[testFileName].push({ - dataPath: 'undefined', - expected: false, - instance: undefined, - // instance: testDescription.instance, - message: 'undefined', - name: `expected ${error}`, - schemaPath: 'undefined', - suggestion: 'undefined', - }); - } - } else if (unexpectedErrors === 0) { - Logger.info(`Successfully validated ${testFile}.`); - } - }), - ); - - return errors; -} - -/** - * Write a report for errors that occurred in validation - * @param reportPath Path to write report to - * @param errors Errors that occurred in validation - */ -export async function writeReport(reportPath: PathLike, errors: ExpectedValidationErrors): Promise { - let buffer = await readFile( - path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'file.html.mustache'), - ); - const fileTemplate = buffer.toString(); - - buffer = await readFile( - path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'error.html.mustache'), - ); - const errorTemplate = buffer.toString(); - - let output = ''; - - for (const fileName in errors) { - if (!errors.hasOwnProperty(fileName)) { - continue; - } - - let fileOutput = ''; - - for (const [index, error] of errors[fileName].entries()) { - fileOutput += mustache.render(errorTemplate, { - idx: index + 1, - instance: JSON.stringify(error.instance, undefined, 2), - message: error.message, - name: error.name, - schemaPath: error.schemaPath, - status: error.expected ? 'alert-success' : 'alert-danger', - suggestion: error.suggestion, - }); - } - - output += mustache.render(fileTemplate, { - errors: fileOutput, - testFile: fileName, - }); - } - - buffer = await readFile( - path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'report.html.mustache'), - ); - const reportTemplate = buffer.toString(); - - await writeFile( - reportPath, - mustache.render(reportTemplate, { - report: output, - timestamp: new Date().toISOString(), - }), - ); - - Logger.ok(`Wrote report to ${reportPath}.`); -} diff --git a/packages/core-validator/README.md b/packages/core-validator/README.md new file mode 100644 index 00000000..7c7a456b --- /dev/null +++ b/packages/core-validator/README.md @@ -0,0 +1,199 @@ +# @openstapps/core-tools + +[![pipeline status](https://img.shields.io/gitlab/pipeline/openstapps/core-tools.svg?style=flat-square)](https://gitlab.com/openstapps/core-tools/commits/master) +[![npm](https://img.shields.io/npm/v/@openstapps/core-tools.svg?style=flat-square)](https://npmjs.com/package/@openstapps/core-tools) +[![license)](https://img.shields.io/npm/l/@openstapps/core-tools.svg?style=flat-square)](https://www.gnu.org/licenses/gpl-3.0.en.html) +[![documentation](https://img.shields.io/badge/documentation-online-blue.svg?style=flat-square)](https://openstapps.gitlab.io/core-tools) + +Tools to convert and validate StAppsCore + +## What are the tools for? + +The StAppsCore Converter is a tool for converting SC-types (TypeScript) into JSON schema files. + +JSON schema files are needed for run-time validation of SC-type objects, as this is a tedious task to do using SC-types defined in TypeScript (not possible without additional coding). That said, StAppsCore Converter practically prepares SC-types to be used for object validation (determining whether a JavaScript/JSON object is a valid object of the corresponding SC-type) using StAppsCore Validator. + +The StAppsCore Validator is a tool for run-time validation of objects (determining whether a JavaScript/JSON object is a valid object of the corresponding SC-type. It consumes JSON schema files from StAppsCore as the definitions of SC-types against which are validated concrete (actual) objects (as an example SCDish object in the example below). + +## Installation + +Installation of the npm package (using `npm install`) makes the tool available as an executable with the name `openstapps-core-tools`. + +## How to use the converter? + +Add `@validatable` to the Typedoc comment of the types that you want to convert to JSONSchema. + +The command `openstapps-core-tools` can then be called using these arguments: + +```shell +openstapps-core-tools schema +``` + +where: + +- `` is path to the project (where used `*.ts` files are, e.g. `src/core`, +- `` is directory to save output files to, e.g. `lib/schema`. + +Complete command with the example arguments is then: + +```shell +openstapps-core-tools schema src/core lib/schema +``` + +Inside of a script in `package.json` or if the npm package is installed globally, the tool `stapps-convert` can be called without its local path (`node_modules/.bin`): + +```shell +openstapps-core-tools schema src/core lib/schema +``` + +## How to use the validator? + +### Using the validator programatically + +```typescript +import {Validator} from '@openstapps/core-tools/lib/validate'; +import {SCDish, SCThingType} from '@openstapps/core'; +import {ValidatorResult} from 'jsonschema'; +import {join} from 'path'; + +const objectToValidate: SCDish = { + type: SCThingType.Dish, + // more properties +}; + +// instantiate a new validator +const validator = new Validator(); + +// make the validator read the schema files +validator.addSchemas(join('node_modules', '@openstapps', 'core', 'lib', 'schema')).then(() => { + // validate an object + const result: ValidatorResult = validator.validate(objectToValidate, 'SCDish'); +}); +``` + +#### Using validateFiles function + +The JSON files passed to the validateFiles method have an added layer. +That layer encapsulates the actual JSON data of the object to be verified and adds a property to enable true negative testing. + +Your basic JSON object: + +```json +{ + "property1": "value1", + "property2": "value2", + ... +} +``` + +JSON for validateFiles: + +```json +{ + "errorNames": [], + "instance": { + "property1": "value1", + "property2": "value2", + ... + }, + "schema": "NameOfSchema" +} +``` + +Where `errorNames` holds the string values of the name property of the expected ValidationErrors from JSON Schema. Empty array means no errors are expected. + +`schema` holds the name of the schema to validate the instance against. + +### How to use validator as a CLI tool (executable)? + +The command `openstapps-core-tools` can then be called using these arguments: + +```shell +openstapps-core-tools validate [reportPath] +``` + +where: + +- `` is a directory where JSON schema files are, e.g. `lib/schema`, +- `` is a directory where test files are, e.g. `src/test/resources`, +- `[reportPath]` is a file where the HTML report of the validation will be saved to, e.g. `report.html` (optional argument - if it's not provided no report will be written). + +Command with the example arguments is then for example: + +```shell +openstapps-core-tools validate lib/schema src/test/resources +``` + +Inside of a script in `package.json` or if the npm package is installed globally, the tool `openstapps-validate` can be called without its local path (`node_modules/.bin`): + +```shell +openstapps-core-tools validate lib/schema src/test/resources report.html +``` + +## Generate openapi JSON file for routes + +To generate a openapi JSON file that represents the routes according to openapi version 3.0.3 use the following command. + +```shell +openstapps-core-tools openapi PATH/TO/CORE/lib PATH/TO/PUT/FILES/TO +``` + +## How to use the UML generator + +The UML Generator generates PlantUML from the project reflection of the source files. By default it will include externals, which will take considerably longer to execute, you can disable this behaviour via an option. It can help you to visually explore the data model or document a specific part. + +You can either use the public PlantUML-server or start your own local instance. To run, restart or stop the container use the scripts provided in the `package.json`. + +### Generating from source-files + +```shell +openstapps-core-tools plantuml PATH/TO/SOURCEFILES http://PLANTUMLSERVER +``` + +Executing this command will generate a `.svg` file in your current working directory. + +Multiple options can be set to enhance the diagram. By default all additional information other than the definitions are disabled. You can use: + +- `--showProperties` to show all mandatory attributes of the classes and interfaces. +- `--showOptionalProperties` to show all mandatory attributes of the classes and interfaces. `--showProperties` must be set! +- `--showInheritedProperties` to show all inherited attributes of the classes and interfaces. `--showProperties` must be set! +- `--showEnumValues` to show all enumeration and type (enumeration-like) values +- `--showInheritance` to show the hierarchy of the classes and interfaces. Inherited attributes will only be shown in their parent. +- `--showAssociations` to show all references of classes and interfaces between one another +- `--excludeExternals` to exclude external definitions +- `--definitions ` to show only specific definitions to reduce the output of the diagram. `` is a comma seperated list of definitions. +- `--outputFileName ` for a custom file name, the file extension will be added automatically (.svg). Otherwise a generic file with a timestamp will be generated into the execution directory. If a file with the same name already exists it will be overwritten! + +The best way to explore models is to enable `--showInheritance` and `--showAssociations`. Start with just one definition in your `--definition `-list, generate the diagram, look at it, add a new definition that you have seen to your command and generate anew. + +#### Examples + +Show the class hierarchy of the whole project: + +```shell +openstapps-core-tools plantuml PATH/TO/SRCDIR http://PLANTUMLSERVER --showInheritance +``` + +Show the dish-module: + +```shell +openstapps-core-tools plantuml ../core http://localhost:8080 --showProperties --showOptionalProperties --showInheritance --showAssociations --showEnumValues --definitions SCDish,SCThingThatCanBeOfferedOffer +``` + +### Generating from existing file + +The plantuml code is persisted inside the generated file at the very bottom. You can tweak the model by using the function to generate UML from a PlantUML-file(simple text file). Extract the code (starting from `@startuml` to `@enduml`), edit it manually and execute this function. + +```shell +openstapps-core-tools plantuml-file /PATH/TO/Project.plantuml http://PLANTUMLSERVER OptionalCustomFileName +``` + +Example-File-Content of Project.plantuml + +``` +@startuml +interface MyClass{ + myProperty: string +} +@enduml +``` diff --git a/packages/core-validator/compiler/append-schema-map.js b/packages/core-validator/compiler/append-schema-map.js new file mode 100644 index 00000000..ca7774f7 --- /dev/null +++ b/packages/core-validator/compiler/append-schema-map.js @@ -0,0 +1,14 @@ +// @ts-check + +import {writeFile, readFile} from 'fs/promises'; + +const schemaNames = Object.keys( + JSON.parse(await readFile('schema/core.schema.json', 'utf8')).definitions, +).filter(it => /^[a-z][0-9a-z<>]*$/i.test(it)); +const source = + "import type * as core from '@openstapps/core';\n\n" + + 'export interface SchemaMap {\n' + + schemaNames.map(name => ` '${name}': core.${name.replaceAll('<', '", + "keywords": [ + "StApps", + "StAppsCore", + "converter", + "core", + "validator" + ], + "main": "./lib/index.js", + "types": "./lib/index.d.ts", + "files": [ + "lib", + "schema", + "Dockerfile", + "README.md", + "CHANGELOG.md" + ], + "scripts": { + "build": "tsup-node --dts", + "docs": "typedoc --json ./docs/docs.json --options ../../typedoc.base.json src/index.ts", + "format": "prettier . -c --ignore-path ../../.gitignore", + "format:fix": "prettier --write . --ignore-path ../../.gitignore", + "lint": "eslint --ext .ts src/", + "lint:fix": "eslint --fix --ext .ts src/", + "test": "c8 mocha" + }, + "dependencies": { + "@openstapps/core": "workspace:*", + "ajv": "8.12.0", + "ajv-formats": "2.1.1" + }, + "devDependencies": { + "@openstapps/core-tools": "workspace:*", + "@openstapps/eslint-config": "workspace:*", + "@openstapps/prettier-config": "workspace:*", + "@openstapps/tsconfig": "workspace:*", + "@types/chai": "4.3.5", + "@types/fs-extra": "9.0.13", + "@types/glob": "8.0.1", + "@types/json-schema": "7.0.14", + "@types/mocha": "10.0.1", + "@types/mustache": "4.2.2", + "@types/node": "18.15.3", + "c8": "7.14.0", + "chai": "4.3.7", + "mocha": "10.2.0", + "mocha-junit-reporter": "2.2.0", + "nock": "13.3.1", + "ts-node": "10.9.1", + "tsup": "6.7.0", + "typedoc": "0.24.8", + "typescript": "5.1.6" + }, + "tsup": { + "entry": [ + "src/app.ts", + "src/index.ts" + ], + "sourcemap": true, + "clean": true, + "format": "esm", + "outDir": "lib" + }, + "prettier": "@openstapps/prettier-config", + "eslintConfig": { + "extends": [ + "@openstapps" + ] + }, + "eslintIgnore": [ + "resources" + ] +} diff --git a/packages/core-validator/schema/.gitignore b/packages/core-validator/schema/.gitignore new file mode 100644 index 00000000..0128eb05 --- /dev/null +++ b/packages/core-validator/schema/.gitignore @@ -0,0 +1,2 @@ +core.schema.json +core.schema.d.ts diff --git a/packages/core-validator/src/index.ts b/packages/core-validator/src/index.ts new file mode 100644 index 00000000..048634f5 --- /dev/null +++ b/packages/core-validator/src/index.ts @@ -0,0 +1,48 @@ +import Ajv, {AnySchema} from 'ajv'; +import addFormats from 'ajv-formats'; +import schema from '../schema/core.schema.json'; +import {SchemaMap} from '../schema/core.schema.js'; + +export type RemoveNeverProperties = { + [K in Exclude< + keyof T, + { + // eslint-disable-next-line @typescript-eslint/ban-types + [P in keyof T]: T[P] extends Function ? P : never; + }[keyof T] + >]: T[K]; +}; + +export type IncludeProperty = RemoveNeverProperties<{ + [K in keyof T]: T[K] extends E ? T[K] : never; +}>; + +type NameOf = keyof IncludeProperty; + +/** + * StAppsCore validator + */ +export class Validator { + private readonly ajv: Ajv.default; + + constructor(additionalSchemas: AnySchema[] = []) { + this.ajv = new Ajv.default({ + schemas: [schema, ...additionalSchemas], + verbose: true, + allowUnionTypes: true, + }); + addFormats.default(this.ajv, { + formats: ['date-time', 'time', 'uuid', 'duration'], + mode: 'fast', + }); + } + + /** + * Validates anything against a given schema name or infers schema name from object + * @param instance Instance to validate + * @param schema Name of schema to validate instance against or the schema itself + */ + public validate(instance: unknown, schema: NameOf): instance is T { + return this.ajv.validate(schema as string, instance); + } +} diff --git a/packages/core-validator/tsconfig.json b/packages/core-validator/tsconfig.json new file mode 100644 index 00000000..aff26de6 --- /dev/null +++ b/packages/core-validator/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@openstapps/tsconfig", + "compilerOptions": { + "noUnusedLocals": false, + "stripInternal": true + } +} diff --git a/packages/core/package.json b/packages/core/package.json index ed5a3c23..9707086e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -32,15 +32,12 @@ "CHANGELOG.md" ], "scripts": { - "build": "tsup-node --dts && pnpm run mappings && pnpm run schema && pnpm run openapi && cp api-doc.html lib/api-doc.html", + "build": "tsup-node --dts && cp api-doc.html lib/api-doc.html", "docs": "typedoc --json ./docs/docs.json --options ../../typedoc.base.json src/index.ts", "format": "prettier . -c --ignore-path ../../.gitignore", "format:fix": "prettier --write . --ignore-path ../../.gitignore", "lint": "eslint --ext .ts src/", "lint:fix": "eslint --fix --ext .ts src/", - "mappings": "openstapps-es-mapping-generator mapping ../core/src -i minlength,pattern,see,tjs-format -m lib/mappings/mappings.json -a lib/mappings/aggregations.json", - "openapi": "openstapps-core-tools openapi lib lib && node -e \"assert(JSON.parse(require('fs').readFileSync('lib/openapi.json', 'utf8')).paths['/search'] !== undefined)\"", - "schema": "node --max-old-space-size=8192 --stack-size=10240 ./node_modules/@openstapps/core-tools/lib/app.js schema src lib/schema", "test": "c8 mocha" }, "dependencies": { @@ -56,12 +53,14 @@ "@openstapps/easy-ast": "workspace:*", "@openstapps/es-mapping-generator": "workspace:*", "@openstapps/eslint-config": "workspace:*", + "@openstapps/json-schema-generator": "workspace:*", "@openstapps/logger": "workspace:*", + "@openstapps/openapi-generator": "workspace:*", "@openstapps/prettier-config": "workspace:*", "@openstapps/tsconfig": "workspace:*", "@types/chai": "4.3.5", "@types/json-patch": "0.0.30", - "@types/json-schema": "7.0.11", + "@types/json-schema": "7.0.14", "@types/mocha": "10.0.1", "@types/node": "18.15.3", "c8": "7.14.0", @@ -97,21 +96,11 @@ { "definedTags": [ "internal", - "aggregatable", - "float", - "indexable", - "integer", - "keyword", - "sortable", - "text", - "date", "validatable", - "filterable", - "inheritTags", + "elasticsearch", "minLength", - "pattern", - "typeparam", - "TJS-format" + "integer", + "format" ] } ] diff --git a/packages/core/src/config/app.ts b/packages/core/src/config/app.ts index 19a58ad8..0af22027 100644 --- a/packages/core/src/config/app.ts +++ b/packages/core/src/config/app.ts @@ -14,7 +14,6 @@ */ import {Polygon} from 'geojson'; import {SCTranslations} from '../general/i18n.js'; -import {SCMap} from '../general/map.js'; import {SCLanguageSetting, SCSetting, SCUserGroupSetting} from '../things/setting.js'; import {SCAuthorizationProviderType} from './authorization.js'; import {SCFeatureConfiguration} from './feature.js'; @@ -89,7 +88,7 @@ export interface SCAppConfiguration { * * Mapping route -> page config */ - aboutPages: SCMap; + aboutPages: Record; /** * Polygon that encapsulates the main campus diff --git a/packages/core/src/config/backend.ts b/packages/core/src/config/backend.ts index 251e2cdb..f8c77c8c 100644 --- a/packages/core/src/config/backend.ts +++ b/packages/core/src/config/backend.ts @@ -12,7 +12,6 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import {SCMap, SCRestrictedMap} from '../general/map.js'; import {SCUuid} from '../general/uuid.js'; import {SCSearchSortType} from '../protocol/search/sort.js'; import {SCThingType} from '../things/abstract/thing.js'; @@ -105,7 +104,7 @@ export type SCSearchContext = 'default' | 'dining' | 'place'; /** * A boosting configuration for one context */ -export type SCBackendConfigurationSearchBoostingContext = SCRestrictedMap< +export type SCBackendConfigurationSearchBoostingContext = Record< SCSearchContext, SCBackendConfigurationSearchBoostingType[] >; @@ -128,10 +127,11 @@ export interface SCBackendConfigurationSearchBoostingType { * Value of the field that should be boosted by the given number * For example `"SS 2019": 2` */ - fields?: SCMap>; + fields?: Record>; /** - * Type of things the factor should be applied to + * Type discriminator + * @elasticsearch type */ type: SCThingType; } @@ -184,7 +184,7 @@ export interface SCBackendInternalConfiguration { /** * Configuration of the database */ -export interface SCBackendConfigurationDatabaseConfiguration extends SCMap { +export interface SCBackendConfigurationDatabaseConfiguration extends Record { /** * Name of the database used by the backend */ diff --git a/packages/core/src/config/feature.ts b/packages/core/src/config/feature.ts index 553c2fb2..dd1326d8 100644 --- a/packages/core/src/config/feature.ts +++ b/packages/core/src/config/feature.ts @@ -12,20 +12,18 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ - -import {SCMap} from '../general/map.js'; import {SCAuthorizationProviderType} from './authorization.js'; export interface SCFeatureConfiguration { /** * Map of extern services mapped by their name (statically) */ - extern?: SCMap; + extern?: Record; /** * Map of plugins registered with the backend mapped by their name. */ - plugins?: SCMap; + plugins?: Record; } export interface SCFeatureConfigurationPlugin { diff --git a/packages/core/src/config/monitoring.ts b/packages/core/src/config/monitoring.ts index 4a4ec341..13195f11 100644 --- a/packages/core/src/config/monitoring.ts +++ b/packages/core/src/config/monitoring.ts @@ -96,7 +96,8 @@ export interface SCMonitoringMinimumLengthCondition { length: number; /** - * Type of the condition + * Type discriminator + * @elasticsearch type */ type: 'MinimumLength'; } @@ -111,7 +112,8 @@ export interface SCMonitoringMaximumLengthCondition { length: number; /** - * Type of the condition + * Type discriminator + * @elasticsearch type */ type: 'MaximumLength'; } diff --git a/packages/core/src/general/i18n.ts b/packages/core/src/general/i18n.ts index 5cd25889..0bd5599f 100644 --- a/packages/core/src/general/i18n.ts +++ b/packages/core/src/general/i18n.ts @@ -18,13 +18,13 @@ export interface SCLanguage { /** * The two letter ISO 639-1 Code of the Language - * @filterable + * @elasticsearch filterable */ code: SCLanguageCode; /** * The Fulltext name of the Language - * @filterable + * @elasticsearch filterable */ name: SCLanguageName; } diff --git a/packages/core/src/general/map.ts b/packages/core/src/general/map.ts deleted file mode 100644 index abccc956..00000000 --- a/packages/core/src/general/map.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2019-2022 Open StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -/** - * Capsulation for a map with a string as key with values of type `T` - * - * !!! BEWARE !!! - * Can't be refactored to a `Map`, because it can't be serialized via JSON.stringify(map) - * @typeparam T Can be any type. - */ -export interface SCMap { - /** - * One value for each key - */ - [key: string]: T; -} - -/** - * Restricted map with keys, limited to values of `U`, and corresponding values of type `T` - * - * !!! BEWARE !!! - * Can't be refactored to a `Map`, because it can't be serialized via JSON.stringify(map) - * Also note, that this is a type not an interface - * @typeparam U Must be a type the `in` operator can be applied to and contains only strings or numbers - * @typeparam T Can be any type - */ -export type SCRestrictedMap = { - /** - * One value for each key - */ - [key in U]: T; -}; diff --git a/packages/core/src/general/time.ts b/packages/core/src/general/time.ts index ca54a5f3..e5748c4f 100644 --- a/packages/core/src/general/time.ts +++ b/packages/core/src/general/time.ts @@ -14,21 +14,18 @@ */ /** * An ISO8601 date - * @pattern ^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])(T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])([\.,][0-9]{0,7})?(Z|[+-](?:2[0-3]|[01][0-9])(:?[0-5][0-9])?)?)?$ - * @see https://gist.github.com/philipashlock/8830168 - * @date + * @format date-time */ export type SCISO8601Date = string; /** * An ISO8601 duration - * @pattern ^(R\d*\/)?P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$ - * @see https://gist.github.com/philipashlock/8830168 + * @format duration */ export type SCISO8601Duration = string; /** * An ISO8601 time - * @pattern ^(2[0-3]|[01][0-9]):?([0-5][0-9]):?([0-5][0-9])$ + * @format time */ export type SCISO8601Time = string; diff --git a/packages/core/src/general/uuid.ts b/packages/core/src/general/uuid.ts index 6dc45932..94037c0d 100644 --- a/packages/core/src/general/uuid.ts +++ b/packages/core/src/general/uuid.ts @@ -14,8 +14,7 @@ */ /** * Universally unique identifier of the thing - * @filterable - * @pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ - * @see http://stackoverflow.com/questions/7905929/how-to-test-valid-uuid-guid + * @elasticsearch filterable + * @format uuid */ export type SCUuid = string; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 9902c884..6e57e9f7 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -11,7 +11,6 @@ export * from './config/monitoring.js'; export * from './config/user.js'; export * from './general/i18n.js'; -export * from './general/map.js'; export * from './general/namespaces.js'; export * from './general/time.js'; export * from './general/uuid.js'; diff --git a/packages/core/src/protocol/route.ts b/packages/core/src/protocol/route.ts index 16d43a83..6848c616 100644 --- a/packages/core/src/protocol/route.ts +++ b/packages/core/src/protocol/route.ts @@ -12,7 +12,6 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import {SCMap} from '../general/map.js'; import {SCErrorResponse} from './error.js'; import {SCIndexRequest, SCIndexResponse, SCIndexRoute} from './routes/index.js'; import { @@ -61,7 +60,7 @@ export interface SCRoute { /** * Map of obligatory parameters and their type that have to be set via the requested path */ - obligatoryParameters?: SCMap; + obligatoryParameters?: Record; /** * Name of the type of the request body @@ -101,7 +100,7 @@ export abstract class SCAbstractRoute implements SCRoute { /** * @see SCRoute.obligatoryParameters */ - obligatoryParameters?: SCMap; + obligatoryParameters?: Record; /** * @see SCRoute.requestBodyName @@ -127,7 +126,7 @@ export abstract class SCAbstractRoute implements SCRoute { * Get "compiled" URL path * @param parameters Parameters to compile URL path with */ - public getUrlPath(parameters: SCMap = {}): string { + public getUrlPath(parameters: Record = {}): string { let obligatoryParameters: string[] = []; if (typeof this.obligatoryParameters === 'object') { diff --git a/packages/core/src/protocol/routes/bulk-request.ts b/packages/core/src/protocol/routes/bulk-request.ts index cb4631fa..0d42b514 100644 --- a/packages/core/src/protocol/routes/bulk-request.ts +++ b/packages/core/src/protocol/routes/bulk-request.ts @@ -53,8 +53,8 @@ export interface SCBulkParameters { source: string; /** - * Type of things that are indexed in this bulk. - * + * Type discriminator + * @elasticsearch type */ type: SCThingType; } diff --git a/packages/core/src/protocol/routes/search-multi.ts b/packages/core/src/protocol/routes/search-multi.ts index 1afe5f95..4a7e7906 100644 --- a/packages/core/src/protocol/routes/search-multi.ts +++ b/packages/core/src/protocol/routes/search-multi.ts @@ -13,7 +13,6 @@ * this program. If not, see . */ import {StatusCodes} from 'http-status-codes'; -import {SCMap} from '../../general/map.js'; import {SCInternalServerErrorResponse} from '../errors/internal-server-error.js'; import {SCMethodNotAllowedErrorResponse} from '../errors/method-not-allowed.js'; import {SCRequestBodyTooLargeErrorResponse} from '../errors/request-body-too-large.js'; @@ -33,7 +32,7 @@ import {SCSearchResult} from '../search/result.js'; * **CAUTION: This is limited to an amount of queries. Currently this limit is 5.** * @validatable */ -export type SCMultiSearchRequest = SCMap; +export type SCMultiSearchRequest = Record; /** * A multi search response @@ -41,7 +40,7 @@ export type SCMultiSearchRequest = SCMap; * This is a map of [[SCSearchResponse]]s indexed by name * @validatable */ -export type SCMultiSearchResponse = SCMap; +export type SCMultiSearchResponse = Record; /** * Route for submission of multiple search requests at once diff --git a/packages/core/src/protocol/search/filter.ts b/packages/core/src/protocol/search/filter.ts index 0eab49bc..7653ce91 100644 --- a/packages/core/src/protocol/search/filter.ts +++ b/packages/core/src/protocol/search/filter.ts @@ -12,10 +12,6 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import {SCMap} from '../../general/map.js'; -/** - * All available filter types - */ import {SCSearchAvailabilityFilter} from './filters/availability.js'; import {SCSearchBooleanFilter} from './filters/boolean.js'; import {SCSearchDistanceFilter} from './filters/distance.js'; @@ -53,7 +49,7 @@ export interface SCSearchAbstractFilter; +export type SCSearchAbstractFilterArguments = Record; /** * Available filter instructions diff --git a/packages/core/src/protocol/search/sort.ts b/packages/core/src/protocol/search/sort.ts index f9ad9bd2..83082e18 100644 --- a/packages/core/src/protocol/search/sort.ts +++ b/packages/core/src/protocol/search/sort.ts @@ -12,7 +12,6 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import {SCMap} from '../../general/map.js'; import {SCThingsField} from '../../meta.js'; import {SCDistanceSort} from './sorts/distance.js'; import {SCDucetSort} from './sorts/ducet.js'; @@ -42,7 +41,7 @@ export interface SCSearchAbstractSort { /** * Map of arguments for the sort instruction */ -export interface SCSearchAbstractSortArguments extends SCMap { +export interface SCSearchAbstractSortArguments extends Record { /** * Field to sort by */ diff --git a/packages/core/src/things/abstract/academic-degree.ts b/packages/core/src/things/abstract/academic-degree.ts index 7e0b2272..1de5183d 100644 --- a/packages/core/src/things/abstract/academic-degree.ts +++ b/packages/core/src/things/abstract/academic-degree.ts @@ -21,8 +21,7 @@ import {SCThing, SCThingMeta, SCThingWithoutReferences} from './thing.js'; export interface SCAcademicDegreeWithoutReferences extends SCThingWithoutReferences { /** * The achievable academic degree - * @filterable - * @sortable ducet + * @elasticsearch filterable sortable:ducet */ academicDegree: string; diff --git a/packages/core/src/things/abstract/academic-term.ts b/packages/core/src/things/abstract/academic-term.ts index 17452619..4fcbcd88 100644 --- a/packages/core/src/things/abstract/academic-term.ts +++ b/packages/core/src/things/abstract/academic-term.ts @@ -22,33 +22,31 @@ import {SCThing, SCThingMeta, SCThingWithoutReferences} from './thing.js'; export interface SCAcademicTermWithoutReferences extends SCThingWithoutReferences { /** * Short name of the academic term, using the given pattern - * @aggregatable - * @filterable - * @keyword + * @elasticsearch aggregatable filterable */ acronym: string; /** * End date of the academic term - * @filterable + * @elasticsearch filterable */ endDate: SCISO8601Date; /** * End date of lectures in the academic term - * @filterable + * @elasticsearch filterable */ eventsEndDate?: SCISO8601Date; /** * Start date of lectures in the academic term - * @filterable + * @elasticsearch filterable */ eventsStartDate?: SCISO8601Date; /** * Start date of the academic term - * @filterable + * @elasticsearch filterable */ startDate: SCISO8601Date; } diff --git a/packages/core/src/things/abstract/creative-work.ts b/packages/core/src/things/abstract/creative-work.ts index 4c9cd65f..d755364f 100644 --- a/packages/core/src/things/abstract/creative-work.ts +++ b/packages/core/src/things/abstract/creative-work.ts @@ -35,33 +35,28 @@ export interface SCCreativeWorkWithoutReferences extends SCThingWithoutReference /** * Edition of a creative work (e.g. the book edition or edition of an article) - * @keyword */ edition?: string; /** * Date (in text form) the creative work was published for the first time - * @keyword */ firstPublished?: string; /** * Languages this creative work is written/recorded/... in - * @filterable + * @elasticsearch filterable */ inLanguage?: SCLanguageCode; /** * Keywords of the creative work - * @aggregatable - * @filterable - * @keyword + * @elasticsearch aggregatable filterable */ keywords?: string[]; /** * Date (in text form) the creative work was most recently - * @keyword */ lastPublished?: string; @@ -112,7 +107,6 @@ export interface SCCreativeWork extends SCCreativeWorkWithoutReferences, SCThing export interface SCCreativeWorkTranslatableProperties extends SCThingTranslatableProperties { /** * Translation of the keywords of the creative work - * @keyword */ keywords?: string[]; } diff --git a/packages/core/src/things/abstract/place.ts b/packages/core/src/things/abstract/place.ts index 7e7e9cfc..2158f7f9 100644 --- a/packages/core/src/things/abstract/place.ts +++ b/packages/core/src/things/abstract/place.ts @@ -39,37 +39,37 @@ export interface SCGeoInformation { export interface SCPostalAddress { /** * Country of the address - * @filterable + * @elasticsearch filterable */ addressCountry: string; /** * City of the address - * @filterable + * @elasticsearch filterable */ addressLocality: string; /** * State of the address - * @filterable + * @elasticsearch filterable */ addressRegion?: string; /** * Zip code of the address - * @filterable + * @elasticsearch filterable */ postalCode: string; /** * Optional post box number - * @filterable + * @elasticsearch filterable */ postOfficeBoxNumber?: string; /** * Street of the address - with house number! - * @filterable + * @elasticsearch filterable */ streetAddress: string; } @@ -94,7 +94,6 @@ export interface SCPlaceWithoutReferences extends SCThingWithoutReferences { /** * Opening hours of the place * @see http://wiki.openstreetmap.org/wiki/Key:opening_hours/specification - * @keyword */ openingHours?: string; diff --git a/packages/core/src/things/abstract/range.ts b/packages/core/src/things/abstract/range.ts index 279c8a05..48cf9f89 100644 --- a/packages/core/src/things/abstract/range.ts +++ b/packages/core/src/things/abstract/range.ts @@ -16,8 +16,6 @@ import {SCISO8601Date} from '../../general/time.js'; /** * Date Range - * - * CAUTION: Changing the name requires changes in the core-tools premaps */ export type SCISO8601DateRange = SCRange; diff --git a/packages/core/src/things/abstract/saveable-thing.ts b/packages/core/src/things/abstract/saveable-thing.ts index d3290cfd..38811754 100644 --- a/packages/core/src/things/abstract/saveable-thing.ts +++ b/packages/core/src/things/abstract/saveable-thing.ts @@ -29,7 +29,8 @@ export interface SCSaveableThing extends SCSaveableThingWithoutReferences, SCThi */ data: SCIndexableThings; /** - * Type of the origin + * Type discriminator + * @elasticsearch type */ origin: SCThingUserOrigin; } diff --git a/packages/core/src/things/abstract/thing-that-accepts-payments.ts b/packages/core/src/things/abstract/thing-that-accepts-payments.ts index 918a7b55..c1dc3e7b 100644 --- a/packages/core/src/things/abstract/thing-that-accepts-payments.ts +++ b/packages/core/src/things/abstract/thing-that-accepts-payments.ts @@ -26,7 +26,7 @@ export type SCThingThatAcceptsPaymentsAcceptedPayments = 'cash' | 'credit' | 'ca export interface SCThingThatAcceptsPaymentsWithoutReferences extends SCThingWithoutReferences { /** * Accepted payments of the place - * @filterable + * @elasticsearch filterable */ paymentsAccepted?: SCThingThatAcceptsPaymentsAcceptedPayments[]; } diff --git a/packages/core/src/things/abstract/thing-that-can-be-offered.ts b/packages/core/src/things/abstract/thing-that-can-be-offered.ts index 3d894fba..4e10f345 100644 --- a/packages/core/src/things/abstract/thing-that-can-be-offered.ts +++ b/packages/core/src/things/abstract/thing-that-can-be-offered.ts @@ -25,8 +25,7 @@ import {SCThing, SCThingMeta, SCThingTranslatableProperties, SCThingWithoutRefer export interface SCPriceGroup { /** * Default price of the thing - * @sortable price - * @float + * @elasticsearch sortable:price */ default: number; } @@ -37,22 +36,19 @@ export interface SCPriceGroup { export interface SCAcademicPriceGroup extends SCPriceGroup { /** * Price for employees - * @sortable price - * @float + * @elasticsearch sortable:price */ employee?: number; /** * Price for guests - * @sortable price - * @float + * @elasticsearch sortable:price */ guest?: number; /** * Price for students - * @sortable price - * @float + * @elasticsearch sortable:price */ student?: number; } @@ -115,7 +111,6 @@ export interface SCThingThatCanBeOfferedOffer extends SC export interface SCThingThatCanBeOfferedTranslatableProperties extends SCThingTranslatableProperties { /** * Availability of an offer - * @keyword */ 'offers[].availability'?: string; } diff --git a/packages/core/src/things/abstract/thing-with-categories.ts b/packages/core/src/things/abstract/thing-with-categories.ts index 6c900862..a165d27e 100644 --- a/packages/core/src/things/abstract/thing-with-categories.ts +++ b/packages/core/src/things/abstract/thing-with-categories.ts @@ -13,7 +13,6 @@ * this program. If not, see . */ import {SCMetaTranslations, SCTranslations} from '../../general/i18n.js'; -import {SCMap} from '../../general/map.js'; import {SCThing, SCThingMeta, SCThingTranslatableProperties, SCThingWithoutReferences} from './thing.js'; /** @@ -26,9 +25,7 @@ export interface SCThingWithCategoriesWithoutReferences; + categorySpecificValues?: Record; /** * Translated fields of a thing with categories @@ -62,46 +59,42 @@ export interface SCThingWithCategories. */ import {SCMetaTranslations, SCTranslations} from '../../general/i18n.js'; -import {SCMap} from '../../general/map.js'; import {SCISO8601Date} from '../../general/time.js'; import {SCUuid} from '../../general/uuid.js'; import {SCOrganizationWithoutReferences} from '../organization.js'; @@ -62,37 +61,33 @@ export enum SCThingType { export interface SCThingWithoutReferences { /** * Alternate names of the thing - * @filterable - * @keyword + * @elasticsearch filterable */ alternateNames?: string[]; /** * Description of the thing * @minLength 1 - * @text + * @elasticsearch text */ description?: string; /** * The identifier property represents any kind of additional identifier for any kind of SCThing * - * E.g. GTIN codes, UUIDs, Database IDs etc. + * E.g., GTIN codes, UUIDs, Database IDs, etc. */ - identifiers?: SCMap; + identifiers?: Record; /** - * URL of an image of the thing - * @keyword + * URL to an image of the thing */ image?: string; /** * Name of the thing - * @filterable * @minLength 1 - * @sortable ducet - * @text + * @elasticsearch text filterable sortable:ducet */ name: string; @@ -111,10 +106,8 @@ export interface SCThingWithoutReferences { translations?: SCTranslations; /** - * Type of the thing - * @sortable ducet - * @filterable - * @aggregatable global + * Type discriminator + * @elasticsearch type */ type: SCThingType; @@ -159,7 +152,8 @@ export interface SCThingOrigin { modified?: SCISO8601Date; /** - * Type of the origin + * Type discriminator + * @elasticsearch type */ type: SCThingOriginType; } @@ -175,7 +169,7 @@ export interface SCThingRemoteOrigin extends SCThingOrigin { /** * Name of the origin - * @text + * @elasticsearch text */ name: string; @@ -192,7 +186,8 @@ export interface SCThingRemoteOrigin extends SCThingOrigin { responsibleEntity?: SCPersonWithoutReferences | SCOrganizationWithoutReferences; /** - * Type of the origin + * Type discriminator + * @elasticsearch type */ type: SCThingOriginType.Remote; @@ -217,7 +212,8 @@ export interface SCThingUserOrigin extends SCThingOrigin { deleted?: boolean; /** - * Type of the origin + * Type discriminator + * @elasticsearch type */ type: SCThingOriginType.User; @@ -233,13 +229,12 @@ export interface SCThingUserOrigin extends SCThingOrigin { export interface SCThingTranslatableProperties { /** * Translation of the description of the thing - * @text + * @elasticsearch text */ description?: string; /** * Translation of the name of the thing - * @sortable ducet - * @text + * @elasticsearch text sortable:ducet */ name?: string; /** @@ -254,7 +249,7 @@ export interface SCThingTranslatableProperties { export interface SCThingTranslatablePropertyOrigin { /** * Translation of the name of the origin - * @text + * @elasticsearch text */ name: string; } diff --git a/packages/core/src/things/academic-event.ts b/packages/core/src/things/academic-event.ts index 363820ce..c9a806b0 100644 --- a/packages/core/src/things/academic-event.ts +++ b/packages/core/src/things/academic-event.ts @@ -31,16 +31,13 @@ export interface SCAcademicEventWithoutReferences SCThingWithCategoriesWithoutReferences { /** * Majors of the academic event that this event belongs to - * @aggregatable - * @filterable - * @keyword + * @elasticsearch filterable aggregatable */ majors?: string[]; /** * Original unmapped category from the source of the academic event - * @filterable - * @keyword + * @elasticsearch filterable */ originalCategory?: string; @@ -50,7 +47,8 @@ export interface SCAcademicEventWithoutReferences translations?: SCTranslations; /** - * Type of an academic event + * Type discriminator + * @elasticsearch type */ type: SCThingType.AcademicEvent; } @@ -58,7 +56,7 @@ export interface SCAcademicEventWithoutReferences /** * An academic event * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCAcademicEvent extends SCEvent, @@ -70,7 +68,8 @@ export interface SCAcademicEvent translations?: SCTranslations; /** - * Type of an academic event + * Type discriminator + * @elasticsearch type */ type: SCThingType.AcademicEvent; } @@ -101,13 +100,11 @@ export type SCAcademicEventCategories = export interface SCAcademicEventTranslatableProperties extends SCThingWithCategoriesTranslatableProperties { /** * Translations of the majors of the academic event that this event belongs to - * @keyword */ majors?: string[]; /** * Translation of the original unmapped category from the source of the academic event - * @keyword */ originalCategory?: string; } diff --git a/packages/core/src/things/article.ts b/packages/core/src/things/article.ts index e016ad97..40f9f5c7 100644 --- a/packages/core/src/things/article.ts +++ b/packages/core/src/things/article.ts @@ -49,7 +49,7 @@ export interface SCArticleWithoutReferences SCThingWithCategoriesWithoutReferences { /** * Article itself as markdown - * @text + * @elasticsearch filterable */ articleBody?: string; @@ -64,7 +64,8 @@ export interface SCArticleWithoutReferences translations?: SCTranslations; /** - * Type of an article + * Type discriminator + * @elasticsearch type */ type: SCThingType.Article; } @@ -72,7 +73,7 @@ export interface SCArticleWithoutReferences /** * An article * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCArticle extends SCCreativeWork, @@ -93,7 +94,8 @@ export interface SCArticle translations?: SCTranslations; /** - * Type of an article + * Type discriminator + * @elasticsearch type */ type: SCThingType.Article; } @@ -107,7 +109,7 @@ export interface SCArticleTranslatableProperties SCCreativeWorkTranslatableProperties { /** * Translation of the article itself as markdown - * @text + * @elasticsearch filterable */ articleBody?: string[]; } diff --git a/packages/core/src/things/assessment.ts b/packages/core/src/things/assessment.ts index 3fbc1128..bc84b346 100644 --- a/packages/core/src/things/assessment.ts +++ b/packages/core/src/things/assessment.ts @@ -52,7 +52,6 @@ export interface SCAssessmentWithoutReferences /** * ECTS (credit-points) - * @float */ ects?: number; @@ -72,7 +71,8 @@ export interface SCAssessmentWithoutReferences translations?: SCTranslations; /** - * Type of an assessment + * Type discriminator + * @elasticsearch type */ type: SCThingType.Assessment; } @@ -101,7 +101,8 @@ export interface SCAssessment translations?: SCTranslations; /** - * Type of an assessment + * Type discriminator + * @elasticsearch type */ type: SCThingType.Assessment; } diff --git a/packages/core/src/things/book.ts b/packages/core/src/things/book.ts index 075678e5..99b81368 100644 --- a/packages/core/src/things/book.ts +++ b/packages/core/src/things/book.ts @@ -73,8 +73,7 @@ export interface SCBookWithoutReferences /** * ISBNs of a book - * @filterable - * @keyword + * @elasticsearch filterable */ ISBNs?: string[]; @@ -90,7 +89,8 @@ export interface SCBookWithoutReferences translations?: SCTranslations; /** - * Type of a book + * Type discriminator + * @elasticsearch type */ type: SCThingType.Book; } @@ -98,7 +98,7 @@ export interface SCBookWithoutReferences /** * A book * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCBook extends SCCreativeWork, @@ -110,7 +110,8 @@ export interface SCBook translations?: SCTranslations; /** - * Type of a book + * Type discriminator + * @elasticsearch type */ type: SCThingType.Book; } diff --git a/packages/core/src/things/building.ts b/packages/core/src/things/building.ts index 40703cfa..291ebe3a 100644 --- a/packages/core/src/things/building.ts +++ b/packages/core/src/things/building.ts @@ -43,8 +43,7 @@ export interface SCBuildingWithoutReferences SCPlaceWithoutReferences { /** * List of floor names of the place - * @filterable - * @keyword + * @elasticsearch filterable */ floors?: string[]; @@ -54,7 +53,8 @@ export interface SCBuildingWithoutReferences translations?: SCTranslations; /** - * Type of the building + * Type discriminator + * @elasticsearch type */ type: SCThingType.Building; } @@ -62,7 +62,7 @@ export interface SCBuildingWithoutReferences /** * A building * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCBuilding extends SCBuildingWithoutReferences, @@ -74,7 +74,8 @@ export interface SCBuilding translations?: SCTranslations; /** - * Type of the building + * Type discriminator + * @elasticsearch type */ type: SCThingType.Building; } diff --git a/packages/core/src/things/catalog.ts b/packages/core/src/things/catalog.ts index 0f85657b..72bd69b1 100644 --- a/packages/core/src/things/catalog.ts +++ b/packages/core/src/things/catalog.ts @@ -32,13 +32,14 @@ export interface SCCatalogWithoutReferences * Level of the catalog (0 for 'root catalog', 1 for its subcatalog, 2 for its subcatalog etc.) * * Needed for keeping order in catalog inheritance array. - * @filterable + * @elasticsearch filterable * @integer */ level: number; /** - * Type of a catalog + * Type discriminator + * @elasticsearch type */ type: SCThingType.Catalog; } @@ -46,7 +47,7 @@ export interface SCCatalogWithoutReferences /** * A catalog * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCCatalog extends SCCatalogWithoutReferences, @@ -73,7 +74,8 @@ export interface SCCatalog translations?: SCTranslations; /** - * Type of a catalog + * Type discriminator + * @elasticsearch type */ type: SCThingType.Catalog; } diff --git a/packages/core/src/things/certification.ts b/packages/core/src/things/certification.ts index 4750af0b..6be904e2 100644 --- a/packages/core/src/things/certification.ts +++ b/packages/core/src/things/certification.ts @@ -39,13 +39,14 @@ export interface SCCertificationWithoutReferences translations?: SCTranslations; /** - * Type of certification + * Type discriminator + * @elasticsearch type */ type: SCThingType.Certification; } /** - * @indexable + * @elasticsearch indexable * @validatable */ export interface SCCertification @@ -63,7 +64,8 @@ export interface SCCertification translations?: SCTranslations; /** - * Type of certification + * Type discriminator + * @elasticsearch type */ type: SCThingType.Certification; } diff --git a/packages/core/src/things/contact-point.ts b/packages/core/src/things/contact-point.ts index 5a9147ef..2d0decbf 100644 --- a/packages/core/src/things/contact-point.ts +++ b/packages/core/src/things/contact-point.ts @@ -23,37 +23,33 @@ import {SCRoomWithoutReferences} from './room.js'; export interface SCContactPointWithoutReferences extends SCThingWithoutReferences { /** * E-mail at the work location - * @keyword */ email?: string; /** * Fax number at the work location - * @keyword */ faxNumber?: string; /** * Office hours for contacting someone at the work location * @see http://wiki.openstreetmap.org/wiki/Key:opening_hours/specification - * @keyword */ officeHours?: string; /** * Contact number at the work location - * @keyword */ telephone?: string; /** - * Type of a contact point + * Type discriminator + * @elasticsearch type */ type: SCThingType.ContactPoint; /** * URL at the work location - * @keyword */ url?: string; } @@ -62,7 +58,7 @@ export interface SCContactPointWithoutReferences extends SCThingWithoutReference * A contact point * @see http://schema.org/ContactPoint * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCContactPoint extends SCContactPointWithoutReferences, SCThing { /** @@ -71,7 +67,8 @@ export interface SCContactPoint extends SCContactPointWithoutReferences, SCThing areaServed?: SCRoomWithoutReferences; /** - * Type of a contact point + * Type discriminator + * @elasticsearch type */ type: SCThingType.ContactPoint; } diff --git a/packages/core/src/things/course-of-study.ts b/packages/core/src/things/course-of-study.ts index 2fc9f7fb..94c246ef 100644 --- a/packages/core/src/things/course-of-study.ts +++ b/packages/core/src/things/course-of-study.ts @@ -43,13 +43,13 @@ export interface SCCourseOfStudyWithoutReferences /** * The modes the course of study is offered in - * @filterable + * @elasticsearch filterable */ mode?: SCCourseOfStudyMode; /** * The time modes the course of study is offered in - * @filterable + * @elasticsearch filterable */ timeMode?: SCCourseOfStudyTimeMode; @@ -59,7 +59,8 @@ export interface SCCourseOfStudyWithoutReferences translations?: SCTranslations; /** - * Type of the course of study + * Type discriminator + * @elasticsearch type */ type: SCThingType.CourseOfStudy; } @@ -67,7 +68,7 @@ export interface SCCourseOfStudyWithoutReferences /** * A course of study * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCCourseOfStudy extends SCCourseOfStudyWithoutReferences, @@ -95,7 +96,8 @@ export interface SCCourseOfStudy translations?: SCTranslations; /** - * Type of the course of study + * Type discriminator + * @elasticsearch type */ type: SCThingType.CourseOfStudy; } diff --git a/packages/core/src/things/date-series.ts b/packages/core/src/things/date-series.ts index 4f759483..a87c32a8 100644 --- a/packages/core/src/things/date-series.ts +++ b/packages/core/src/things/date-series.ts @@ -33,7 +33,6 @@ import {SCSportCourseWithoutReferences} from './sport-course.js'; export interface SCSportCoursePriceGroup extends SCAcademicPriceGroup { /** * Price for alumnis - * @float */ alumni?: number; } @@ -44,7 +43,7 @@ export interface SCSportCoursePriceGroup extends SCAcademicPriceGroup { export interface SCDateSeriesWithoutReferences extends SCThingThatCanBeOfferedWithoutReferences { /** * Dates of the date series that are initially planned to be held - * @filterable + * @elasticsearch filterable */ dates: SCISO8601Date[]; @@ -60,7 +59,7 @@ export interface SCDateSeriesWithoutReferences extends SCThingThatCanBeOfferedWi /** * Frequency of the date series - * @filterable + * @elasticsearch filterable */ repeatFrequency?: SCISO8601Duration; @@ -70,7 +69,8 @@ export interface SCDateSeriesWithoutReferences extends SCThingThatCanBeOfferedWi translations?: SCTranslations; /** - * Type of a date series + * Type discriminator + * @elasticsearch type */ type: SCThingType.DateSeries; } @@ -78,7 +78,7 @@ export interface SCDateSeriesWithoutReferences extends SCThingThatCanBeOfferedWi /** * A date series * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCDateSeries extends SCDateSeriesWithoutReferences, @@ -100,7 +100,8 @@ export interface SCDateSeries translations?: SCTranslations; /** - * Type of a date series + * Type discriminator + * @elasticsearch type */ type: SCThingType.DateSeries; } diff --git a/packages/core/src/things/diff.ts b/packages/core/src/things/diff.ts index b5311e0d..852b82f8 100644 --- a/packages/core/src/things/diff.ts +++ b/packages/core/src/things/diff.ts @@ -38,7 +38,8 @@ export interface SCDiffWithoutReferences extends SCThingWithoutReferences { dateCreated: SCISO8601Date; /** - * Type of a diff + * Type discriminator + * @elasticsearch type */ type: SCThingType.Diff; } @@ -54,7 +55,8 @@ export interface SCDiff extends SCDiffWithoutReferences, SCThing { object: SCIndexableThings; /** - * Type of a diff + * Type discriminator + * @elasticsearch type */ type: SCThingType.Diff; } diff --git a/packages/core/src/things/dish.ts b/packages/core/src/things/dish.ts index 5c75f39c..600479f0 100644 --- a/packages/core/src/things/dish.ts +++ b/packages/core/src/things/dish.ts @@ -38,8 +38,7 @@ export interface SCDishWithoutReferences SCThingWithCategoriesWithoutReferences { /** * Additives of the dish - * @filterable - * @keyword + * @elasticsearch filterable */ additives?: string[]; @@ -64,7 +63,8 @@ export interface SCDishWithoutReferences translations?: SCTranslations; /** - * Type of a dish + * Type discriminator + * @elasticsearch type */ type: SCThingType.Dish; } @@ -72,7 +72,7 @@ export interface SCDishWithoutReferences /** * A dish * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCDish extends SCDishWithoutReferences, @@ -94,7 +94,8 @@ export interface SCDish translations?: SCTranslations; /** - * Type of a dish + * Type discriminator + * @elasticsearch type */ type: SCThingType.Dish; } @@ -104,8 +105,7 @@ export interface SCDishTranslatableProperties SCThingThatCanBeOfferedTranslatableProperties { /** * Additives of the dish - * @filterable - * @keyword + * @elasticsearch filterable */ additives?: string[]; /** @@ -120,14 +120,12 @@ export interface SCDishTranslatableProperties export interface SCDishCharacteristic { /** * URL of an image of the characteristic - * @keyword */ image?: string; /** * Name of the characteristic - * @filterable - * @text + * @elasticsearch text filterable */ name: string; } @@ -144,43 +142,36 @@ export type SCDishCategories = 'appetizer' | 'salad' | 'main dish' | 'dessert' | export interface SCNutritionInformation { /** * Number of calories contained (in kcal) - * @float */ calories?: number; /** * Content of carbohydrates (in grams) - * @float */ carbohydrateContent?: number; /** * Content of fat (in grams) - * @float */ fatContent?: number; /** * Content of proteins (in grams) - * @float */ proteinContent?: number; /** * Content of salt (in grams) - * @float */ saltContent?: number; /** * Content of saturated fat (in grams) - * @float */ saturatedFatContent?: number; /** * Content of sugar (in grams) - * @float */ sugarContent?: number; } diff --git a/packages/core/src/things/favorite.ts b/packages/core/src/things/favorite.ts index e8a84019..1e7c6ac5 100644 --- a/packages/core/src/things/favorite.ts +++ b/packages/core/src/things/favorite.ts @@ -20,7 +20,8 @@ import {SCThingMeta, SCThingType} from './abstract/thing.js'; */ export interface SCFavoriteWithoutReferences extends SCSaveableThingWithoutReferences { /** - * Type of a favorite + * Type discriminator + * @elasticsearch type */ type: SCThingType.Favorite; } @@ -31,7 +32,8 @@ export interface SCFavoriteWithoutReferences extends SCSaveableThingWithoutRefer */ export interface SCFavorite extends SCSaveableThing { /** - * Type of a favorite + * Type discriminator + * @elasticsearch type */ type: SCThingType.Favorite; } diff --git a/packages/core/src/things/floor.ts b/packages/core/src/things/floor.ts index b254ea01..ff8b0bdc 100644 --- a/packages/core/src/things/floor.ts +++ b/packages/core/src/things/floor.ts @@ -30,7 +30,7 @@ import {SCRoomWithoutReferences} from './room.js'; export interface SCFloorWithoutReferences extends SCThingWithoutReferences { /** * Floor name in the place it is in e.g. "first floor", "ground floor". This doesn't reference the building name. - * @text + * @elasticsearch filterable */ floorName: string; @@ -45,7 +45,8 @@ export interface SCFloorWithoutReferences extends SCThingWithoutReferences { translations?: SCTranslations; /** - * Type of a floor + * Type discriminator + * @elasticsearch type */ type: SCThingType.Floor; } @@ -53,7 +54,7 @@ export interface SCFloorWithoutReferences extends SCThingWithoutReferences { /** * A floor * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCFloor extends SCFloorWithoutReferences, SCThingInPlace { /** @@ -62,7 +63,8 @@ export interface SCFloor extends SCFloorWithoutReferences, SCThingInPlace { translations?: SCTranslations; /** - * Type of a floor + * Type discriminator + * @elasticsearch type */ type: SCThingType.Floor; } @@ -95,7 +97,7 @@ export interface SCFloorFeatureWithPlace export interface SCFloorTranslatableProperties extends SCThingTranslatableProperties { /** * Translation of the floor name - * @text + * @elasticsearch filterable */ floorName?: string; } diff --git a/packages/core/src/things/id-card.ts b/packages/core/src/things/id-card.ts index 4a7b38f8..6e53badb 100644 --- a/packages/core/src/things/id-card.ts +++ b/packages/core/src/things/id-card.ts @@ -40,7 +40,7 @@ export interface SCIdCardWithoutReferences extends SCThingWithoutReferences { /** * A message * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCIdCard extends SCIdCardWithoutReferences, SCThing { /** diff --git a/packages/core/src/things/job-posting.ts b/packages/core/src/things/job-posting.ts index 30962fe8..1b4329ac 100644 --- a/packages/core/src/things/job-posting.ts +++ b/packages/core/src/things/job-posting.ts @@ -28,7 +28,8 @@ export interface SCJobPostingWithoutReferences extends SCThingWithCategoriesWithoutReferences, SCInPlace { /** - * Type of a job posting + * Type discriminator + * @elasticsearch type */ type: SCThingType.JobPosting; } @@ -36,14 +37,14 @@ export interface SCJobPostingWithoutReferences /** * A JobPosting * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCJobPosting extends SCThingWithCategories, SCJobPostingWithoutReferences { /** * A description of the employer - * @text + * @elasticsearch filterable */ employerOverview?: SCOrganizationWithoutReferences; diff --git a/packages/core/src/things/message.ts b/packages/core/src/things/message.ts index 94066cf2..1755893d 100644 --- a/packages/core/src/things/message.ts +++ b/packages/core/src/things/message.ts @@ -48,7 +48,7 @@ export interface SCMessageWithoutReferences /** * Roles for which the message is intended - * @filterable + * @elasticsearch filterable */ audiences: SCUserGroup[]; @@ -59,13 +59,13 @@ export interface SCMessageWithoutReferences /** * When the message was created - * @filterable + * @elasticsearch filterable */ dateCreated?: SCISO8601Date; /** * Message itself - * @text + * @elasticsearch filterable */ messageBody: string; @@ -80,7 +80,8 @@ export interface SCMessageWithoutReferences translations?: SCTranslations; /** - * Type of a message + * Type discriminator + * @elasticsearch type */ type: SCThingType.Message; } @@ -88,7 +89,7 @@ export interface SCMessageWithoutReferences /** * A message * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCMessage extends SCCreativeWork, SCMessageWithoutReferences { /** @@ -97,7 +98,8 @@ export interface SCMessage extends SCCreativeWork, SCMessageWithoutReferences { translations?: SCTranslations; /** - * Type of a message + * Type discriminator + * @elasticsearch type */ type: SCThingType.Message; } @@ -110,7 +112,7 @@ export interface SCMessageTranslatableProperties SCThingThatCanBeOfferedTranslatableProperties { /** * Message itself - * @text + * @elasticsearch filterable */ messageBody?: string; } diff --git a/packages/core/src/things/organization.ts b/packages/core/src/things/organization.ts index f9d90b70..aa673d48 100644 --- a/packages/core/src/things/organization.ts +++ b/packages/core/src/things/organization.ts @@ -22,7 +22,8 @@ import {SCContactPointWithoutReferences} from './contact-point.js'; */ export interface SCOrganizationWithoutReferences extends SCThingWithoutReferences { /** - * Type of an organization + * Type discriminator + * @elasticsearch type */ type: SCThingType.Organization; } @@ -30,7 +31,7 @@ export interface SCOrganizationWithoutReferences extends SCThingWithoutReference /** * An organization * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCOrganization extends SCOrganizationWithoutReferences, SCThingInPlace { /** @@ -39,7 +40,8 @@ export interface SCOrganization extends SCOrganizationWithoutReferences, SCThing contactPoints?: SCContactPointWithoutReferences[]; /** - * Type of an organization + * Type discriminator + * @elasticsearch type */ type: SCThingType.Organization; } diff --git a/packages/core/src/things/periodical.ts b/packages/core/src/things/periodical.ts index 36bff0af..a6d326af 100644 --- a/packages/core/src/things/periodical.ts +++ b/packages/core/src/things/periodical.ts @@ -52,8 +52,7 @@ export interface SCPeriodicalWithoutReferences categories: SCPeriodicalCategories[]; /** * A list of ISSNs of a periodical - * @filterable - * @keyword + * @elasticsearch filterable */ ISSNs?: string[]; @@ -63,7 +62,8 @@ export interface SCPeriodicalWithoutReferences translations?: SCTranslations; /** - * Type of a periodical + * Type discriminator + * @elasticsearch type */ type: SCThingType.Periodical; } @@ -71,7 +71,7 @@ export interface SCPeriodicalWithoutReferences /** * A publication published at regular intervals (e.g. a magazine or newspaper) * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCPeriodical extends SCCreativeWork, @@ -83,7 +83,8 @@ export interface SCPeriodical translations?: SCTranslations; /** - * Type of a periodical + * Type discriminator + * @elasticsearch type */ type: SCThingType.Periodical; } diff --git a/packages/core/src/things/person.ts b/packages/core/src/things/person.ts index 57beece8..d930e2a7 100644 --- a/packages/core/src/things/person.ts +++ b/packages/core/src/things/person.ts @@ -27,77 +27,67 @@ import {SCRoomWithoutReferences} from './room.js'; export interface SCPersonWithoutReferences extends SCThingWithoutReferences { /** * Additional first names of the person. - * @filterable - * @keyword + * @elasticsearch filterable */ additionalName?: string; /** * The birth date of the person. - * @filterable + * @elasticsearch filterable */ birthDate?: SCISO8601Date; /** * The private email address of the person. - * @TJS-format email - * @filterable - * @keyword + * @elasticsearch filterable */ email?: string; /** * The family name of the person. - * @filterable - * @keyword + * @elasticsearch filterable */ familyName?: string; /** * The private fax number of the person. - * @filterable - * @keyword + * @elasticsearch filterable */ faxNumber?: string; /** * The gender of the person. - * @filterable + * @elasticsearch filterable */ gender?: SCPersonGender; /** * The first name of the person. - * @filterable - * @keyword + * @elasticsearch filterable */ givenName?: string; /** * Honorific prefix of the person. - * @filterable - * @keyword + * @elasticsearch filterable */ honorificPrefix?: string; /** * Honorific suffix of the person. - * @filterable - * @keyword + * @elasticsearch filterable */ honorificSuffix?: string; /** * Titles of jobs that the person has. - * @filterable - * @keyword + * @elasticsearch filterable */ jobTitles?: string[]; /** * The complete name of the person combining all the parts of the name into one. - * @filterable - * @text + * @elasticsearch text filterable */ name: string; @@ -108,12 +98,12 @@ export interface SCPersonWithoutReferences extends SCThingWithoutReferences { /** * The private telephone number of the person. - * @keyword */ telephone?: string; /** - * Type of a person + * Type discriminator + * @elasticsearch type */ type: SCThingType.Person; } @@ -121,7 +111,7 @@ export interface SCPersonWithoutReferences extends SCThingWithoutReferences { /** * A person * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCPerson extends SCPersonWithoutReferences, SCThing { /** @@ -137,7 +127,8 @@ export interface SCPerson extends SCPersonWithoutReferences, SCThing { >; /** - * Type of a person + * Type discriminator + * @elasticsearch type */ type: SCThingType.Person; diff --git a/packages/core/src/things/point-of-interest.ts b/packages/core/src/things/point-of-interest.ts index fb9a8789..e353a188 100644 --- a/packages/core/src/things/point-of-interest.ts +++ b/packages/core/src/things/point-of-interest.ts @@ -39,7 +39,8 @@ export interface SCPointOfInterestWithoutReferences translations?: SCTranslations; /** - * Type of a point of interest + * Type discriminator + * @elasticsearch type */ type: SCThingType.PointOfInterest; } @@ -47,7 +48,7 @@ export interface SCPointOfInterestWithoutReferences /** * A point of interest * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCPointOfInterest extends SCPointOfInterestWithoutReferences, @@ -60,7 +61,8 @@ export interface SCPointOfInterest translations?: SCTranslations; /** - * Type of a point of interest + * Type discriminator + * @elasticsearch type */ type: SCThingType.PointOfInterest; } diff --git a/packages/core/src/things/publication-event.ts b/packages/core/src/things/publication-event.ts index 9d633b63..42ac4e9e 100644 --- a/packages/core/src/things/publication-event.ts +++ b/packages/core/src/things/publication-event.ts @@ -36,7 +36,8 @@ export interface SCPublicationEventWithoutReferences extends SCEventWithoutRefer translations?: SCTranslations; /** - * Type of an publication event + * Type discriminator + * @elasticsearch type */ type: SCThingType.PublicationEvent; } @@ -44,7 +45,7 @@ export interface SCPublicationEventWithoutReferences extends SCEventWithoutRefer /** * An publication event * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCPublicationEvent extends SCEvent, SCPublicationEventWithoutReferences { /** @@ -53,7 +54,8 @@ export interface SCPublicationEvent extends SCEvent, SCPublicationEventWithoutRe translations?: SCTranslations; /** - * Type of an publication event + * Type discriminator + * @elasticsearch type */ type: SCThingType.PublicationEvent; } diff --git a/packages/core/src/things/room.ts b/packages/core/src/things/room.ts index afff7294..53c08f48 100644 --- a/packages/core/src/things/room.ts +++ b/packages/core/src/things/room.ts @@ -13,7 +13,6 @@ * this program. If not, see . */ import {SCMetaTranslations, SCTranslations} from '../general/i18n.js'; -import {SCMap} from '../general/map.js'; import {SCPlace, SCPlaceWithoutReferences, SCPlaceWithoutReferencesMeta} from './abstract/place.js'; import {SCThingMeta, SCThingType} from './abstract/thing.js'; @@ -58,15 +57,14 @@ export interface SCRoomWithoutReferences SCThingWithCategoriesWithoutReferences { /** * The name of the floor in which the room is in. - * @filterable - * @text + * @elasticsearch text filterable */ floorName?: string; /** * The inventory of the place/room as a list of items and their quantity. */ - inventory?: SCMap; + inventory?: Record; /** * Translations of specific values of the object @@ -76,7 +74,8 @@ export interface SCRoomWithoutReferences translations?: SCTranslations; /** - * Type of the room + * Type discriminator + * @elasticsearch type */ type: SCThingType.Room; } @@ -84,7 +83,7 @@ export interface SCRoomWithoutReferences /** * A room * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCRoom extends SCRoomWithoutReferences, @@ -100,7 +99,8 @@ export interface SCRoom translations?: SCTranslations; /** - * Type of the room + * Type discriminator + * @elasticsearch type */ type: SCThingType.Room; } @@ -111,14 +111,12 @@ export interface SCRoom export interface SCRoomSpecificValues extends SCThingWithCategoriesSpecificValues { /** * Category specific opening hours of the room - * @keyword */ openingHours?: string; /** * Category specific service hours of the room (e.g. cooked food serving hours) * @see http://wiki.openstreetmap.org/wiki/Key:opening_hours/specification - * @keyword */ serviceHours?: string; } diff --git a/packages/core/src/things/semester.ts b/packages/core/src/things/semester.ts index 4392611a..8df7a2ef 100644 --- a/packages/core/src/things/semester.ts +++ b/packages/core/src/things/semester.ts @@ -26,14 +26,13 @@ import {SCThingMeta, SCThingType} from './abstract/thing.js'; export interface SCSemesterWithoutReferences extends SCAcademicTermWithoutReferences { /** * The short name of the semester, using the given pattern. - * @filterable - * @pattern ^(WS|SS|WiSe|SoSe) [0-9]{4}(/[0-9]{2})?$ - * @keyword + * @elasticsearch filterable */ acronym: string; /** - * Type of the semester + * Type discriminator + * @elasticsearch type */ type: SCThingType.Semester; } @@ -41,11 +40,12 @@ export interface SCSemesterWithoutReferences extends SCAcademicTermWithoutRefere /** * A semester * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCSemester extends SCSemesterWithoutReferences, SCAcademicTerm { /** - * Type of the semester + * Type discriminator + * @elasticsearch type */ type: SCThingType.Semester; } diff --git a/packages/core/src/things/setting.ts b/packages/core/src/things/setting.ts index c22eef9d..380dd1f8 100644 --- a/packages/core/src/things/setting.ts +++ b/packages/core/src/things/setting.ts @@ -109,7 +109,6 @@ export type SCSettingValues = SCSettingValue[]; export interface SCSettingValueTranslatableProperties extends SCThingWithCategoriesTranslatableProperties { /** * The translations of the possible values of a setting - * @keyword */ values?: string[]; } diff --git a/packages/core/src/things/sport-course.ts b/packages/core/src/things/sport-course.ts index b2415e53..c43c3ec5 100644 --- a/packages/core/src/things/sport-course.ts +++ b/packages/core/src/things/sport-course.ts @@ -21,7 +21,8 @@ import {SCThingMeta, SCThingType} from './abstract/thing.js'; */ export interface SCSportCourseWithoutReferences extends SCEventWithoutReferences { /** - * Type of a sport course + * Type discriminator + * @elasticsearch type */ type: SCThingType.SportCourse; } @@ -29,11 +30,12 @@ export interface SCSportCourseWithoutReferences extends SCEventWithoutReferences /** * A sport course * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCSportCourse extends SCEvent, SCSportCourseWithoutReferences { /** - * Type of a sport course + * Type discriminator + * @elasticsearch type */ type: SCThingType.SportCourse; } diff --git a/packages/core/src/things/study-module.ts b/packages/core/src/things/study-module.ts index 2b7be104..82baf76f 100644 --- a/packages/core/src/things/study-module.ts +++ b/packages/core/src/things/study-module.ts @@ -13,7 +13,6 @@ * this program. If not, see . */ import {SCLanguage, SCMetaTranslations, SCTranslations} from '../general/i18n.js'; -import {SCMap} from '../general/map.js'; import {SCThingMeta, SCThingType} from './abstract/thing.js'; import { SCAcademicPriceGroup, @@ -32,7 +31,6 @@ import {SCPersonWithoutReferences} from './person.js'; export interface SCStudyModuleWithoutReferences extends SCThingThatCanBeOfferedWithoutReferences { /** * ECTS points (European Credit Transfer System) - * @float */ ects: number; @@ -43,15 +41,14 @@ export interface SCStudyModuleWithoutReferences extends SCThingThatCanBeOfferedW /** * Majors that this study module is meant for - * @filterable - * @keyword + * @elasticsearch filterable */ majors: string[]; /** * Represents the modules necessity for each given major (of the major property) */ - necessity: SCMap; + necessity: Record; /** * Translated fields of a study module @@ -59,7 +56,9 @@ export interface SCStudyModuleWithoutReferences extends SCThingThatCanBeOfferedW translations?: SCTranslations; /** - * Type of the study module + * Type discriminator + * @elasticsearch type + * @elasticsearch type */ type: SCThingType.StudyModule; } @@ -67,7 +66,7 @@ export interface SCStudyModuleWithoutReferences extends SCThingThatCanBeOfferedW /** * A study module * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCStudyModule extends SCStudyModuleWithoutReferences, @@ -104,7 +103,8 @@ export interface SCStudyModule translations?: SCTranslations; /** - * Type of the study module + * Type discriminator + * @elasticsearch type */ type: SCThingType.StudyModule; } @@ -112,14 +112,13 @@ export interface SCStudyModule export interface SCStudyModuleTranslatableProperties extends SCThingThatCanBeOfferedTranslatableProperties { /** * Translations of the majors that this study module is meant for - * @keyword */ majors?: string[]; /** * Translations of the modules necessity for each given major (of the major property) */ - necessity: SCMap; + necessity: Record; } /** diff --git a/packages/core/src/things/ticket.ts b/packages/core/src/things/ticket.ts index 67cacc64..abe8969b 100644 --- a/packages/core/src/things/ticket.ts +++ b/packages/core/src/things/ticket.ts @@ -28,7 +28,6 @@ export interface SCTicketWithoutReferences extends SCThingWithoutReferences { /** * Waiting number of the ticket - * @keyword */ currentTicketNumber: string; @@ -38,7 +37,8 @@ export interface SCTicketWithoutReferences extends SCThingWithoutReferences { serviceType: string; /** - * Type of a ticket + * Type discriminator + * @elasticsearch type */ type: SCThingType.Ticket; } @@ -46,11 +46,12 @@ export interface SCTicketWithoutReferences extends SCThingWithoutReferences { /** * A ticket * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCTicket extends SCTicketWithoutReferences, SCThingInPlace { /** - * Type of a ticket + * Type discriminator + * @elasticsearch type */ type: SCThingType.Ticket; } diff --git a/packages/core/src/things/todo.ts b/packages/core/src/things/todo.ts index 4e293bb5..503c42c4 100644 --- a/packages/core/src/things/todo.ts +++ b/packages/core/src/things/todo.ts @@ -35,7 +35,7 @@ export interface SCToDoWithoutReferences /** * A date when the "to do" is due - * @filterable + * @elasticsearch filterable */ dueDate?: SCISO8601Date; @@ -45,7 +45,8 @@ export interface SCToDoWithoutReferences priority: SCToDoPriority; /** - * Type of the "to do" + * Type discriminator + * @elasticsearch type */ type: SCThingType.ToDo; } @@ -53,7 +54,7 @@ export interface SCToDoWithoutReferences /** * A "to do" * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCToDo extends SCToDoWithoutReferences, @@ -65,7 +66,8 @@ export interface SCToDo translations?: SCTranslations; /** - * Type of the "to do" + * Type discriminator + * @elasticsearch type */ type: SCThingType.ToDo; } diff --git a/packages/core/src/things/tour.ts b/packages/core/src/things/tour.ts index 3dde7d12..11e6df9d 100644 --- a/packages/core/src/things/tour.ts +++ b/packages/core/src/things/tour.ts @@ -21,7 +21,7 @@ import {SCThing, SCThingMeta, SCThingType, SCThingWithoutReferences} from './abs export interface SCTourWithoutReferences extends SCThingWithoutReferences { /** * Init script for the tour - * @text + * @elasticsearch filterable */ init?: string; @@ -31,8 +31,8 @@ export interface SCTourWithoutReferences extends SCThingWithoutReferences { steps: SCTourStep[]; /** - * Type of a tour - * @keyword + * Type discriminator + * @elasticsearch type */ type: SCThingType.Tour; } @@ -40,11 +40,12 @@ export interface SCTourWithoutReferences extends SCThingWithoutReferences { /** * A tour * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCTour extends SCTourWithoutReferences, SCThing { /** - * Type of a tour + * Type discriminator + * @elasticsearch type */ type: SCThingType.Tour; } @@ -95,12 +96,12 @@ export type SCTourStep = SCTourStepMenu | SCTourStepLocation | SCTourStepTooltip export interface SCTourStepLocation { /** * Location to go to - * @keyword */ location: string; /** - * Type of the step + * Type discriminator + * @elasticsearch type */ type: 'location'; } @@ -116,7 +117,6 @@ export interface SCTourStepTooltip { /** * Element that the tooltip shall be pointing at or a list of elements to try in the specified order - * @keyword */ element: string | string[]; @@ -132,7 +132,7 @@ export interface SCTourStepTooltip { /** * Text that the tooltip shall contain - * @text + * @elasticsearch filterable */ text: string; @@ -143,7 +143,8 @@ export interface SCTourStepTooltip { tries?: number; /** - * Type of the step + * Type discriminator + * @elasticsearch type */ type: 'tooltip'; } @@ -174,7 +175,6 @@ export interface SCTourStepMenu { export interface SCTourResolvedElement { /** * Element name - * @keyword */ element: string; } @@ -185,7 +185,6 @@ export interface SCTourResolvedElement { export interface SCTourResolvedEvent { /** * Event name - * @keyword */ event: string; } @@ -206,7 +205,6 @@ export interface SCTourResolvedLocation { export interface SCTourResolvedLocationTypeIs { /** * Specific location name - * @keyword */ is: string; } @@ -217,7 +215,6 @@ export interface SCTourResolvedLocationTypeIs { export interface SCTourResolvedLocationTypeMatch { /** * Regex location name - * @keyword */ match: string; } diff --git a/packages/core/src/things/video.ts b/packages/core/src/things/video.ts index 2109c425..cc1b2546 100644 --- a/packages/core/src/things/video.ts +++ b/packages/core/src/things/video.ts @@ -48,7 +48,6 @@ export interface SCVideoWithoutReferences /** * URLs to a thumbnails for the Video - * @keyword */ thumbnails?: string[]; @@ -59,7 +58,7 @@ export interface SCVideoWithoutReferences /** * A Transcript of the Video - * @text + * @elasticsearch filterable */ transcript?: string; @@ -69,7 +68,8 @@ export interface SCVideoWithoutReferences translations?: SCTranslations; /** - * Type of an Video + * Type discriminator + * @elasticsearch type */ type: SCThingType.Video; } @@ -83,7 +83,7 @@ export interface SCVideoSource { /** * MIME-Type of the source File - * @filterable + * @elasticsearch filterable */ mimeType: SCVideoMimeType; @@ -95,7 +95,6 @@ export interface SCVideoSource { /** * URL to the Video File - * @keyword */ url: string; @@ -114,13 +113,12 @@ export interface SCVideoTrack { /** * Content Type of the Track File - * @filterable + * @elasticsearch filterable */ type: SCVideoTrackTypes; /** * URL to the Track File - * @keyword */ url: string; } @@ -128,7 +126,7 @@ export interface SCVideoTrack { /** * A video * @validatable - * @indexable + * @elasticsearch indexable */ export interface SCVideo extends SCCreativeWork, @@ -145,7 +143,8 @@ export interface SCVideo translations?: SCTranslations; /** - * Type of a video + * Type discriminator + * @elasticsearch type */ type: SCThingType.Video; } diff --git a/packages/core/test/schema.spec.ts b/packages/core/test/schema.spec.ts index 7f9e52d8..af1c5a89 100644 --- a/packages/core/test/schema.spec.ts +++ b/packages/core/test/schema.spec.ts @@ -1,13 +1,9 @@ -import {validateFiles, writeReport} from '@openstapps/core-tools'; -import {expect} from 'chai'; -import {mkdir} from 'fs/promises'; -import path from 'path'; - describe('Schema', function () { this.timeout(15_000); this.slow(10_000); - it('should validate against test files', async function () { + // TODO + /*it('should validate against test files', async function () { const errorsPerFile = await validateFiles( path.resolve('lib', 'schema'), path.resolve('test', 'resources'), @@ -21,5 +17,5 @@ describe('Schema', function () { expect(error.expected).to.be.true; } } - }); + });*/ }); diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts new file mode 100644 index 00000000..1d181a1e --- /dev/null +++ b/packages/core/tsup.config.ts @@ -0,0 +1,16 @@ +import {defineConfig} from 'tsup'; +import {jsonSchemaPlugin} from '@openstapps/json-schema-generator'; +import {openapiPlugin} from '@openstapps/openapi-generator'; +import {elasticsearchMappingGenerator} from '@openstapps/es-mapping-generator'; + +export default defineConfig({ + entry: ['src/index.ts'], + sourcemap: true, + clean: true, + format: 'esm', + outDir: 'lib', + plugins: [ + jsonSchemaPlugin('index.schema.json', elasticsearchMappingGenerator('elasticsearch.json')), + openapiPlugin('openapi.json', 'index.schema.json'), + ], +}); diff --git a/packages/es-mapping-generator/app.js b/packages/es-mapping-generator/app.js deleted file mode 100755 index 832461c8..00000000 --- a/packages/es-mapping-generator/app.js +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -require('./lib/app.js'); diff --git a/packages/es-mapping-generator/package.json b/packages/es-mapping-generator/package.json index e0049ba3..d307b1cd 100644 --- a/packages/es-mapping-generator/package.json +++ b/packages/es-mapping-generator/package.json @@ -2,14 +2,11 @@ "name": "@openstapps/es-mapping-generator", "description": "Tool to convert TypeScript Interfaces to Elasticsearch Mappings", "version": "3.0.0", - "type": "commonjs", + "type": "module", "license": "GPL-3.0-only", "author": "Thea Schöbl ", "main": "./lib/index.js", "types": "./lib/index.d.ts", - "bin": { - "openstapps-es-mapping-generator": "app.js" - }, "files": [ "app.js", "lib", @@ -18,7 +15,8 @@ "CHANGELOG.md" ], "scripts": { - "build": "rimraf lib && tsc", + "build": "tsup-node --dts", + "dev": "tsup --watch --onSuccess \"node lib/index.js\"", "format": "prettier . -c --ignore-path ../../.gitignore", "format:fix": "prettier --write . --ignore-path ../../.gitignore", "lint": "eslint --ext .ts src/ test/", @@ -26,28 +24,33 @@ "test": "c8 mocha" }, "dependencies": { - "@elastic/elasticsearch": "8.4.0", - "commander": "10.0.0", - "deepmerge": "4.3.1", - "flatted": "3.2.7", - "typedoc": "0.18.0", - "typescript": "3.8.3" + "@elastic/elasticsearch": "8.10.0", + "@openstapps/json-schema-generator": "workspace:*", + "@openstapps/tsup-plugin": "workspace:*", + "@types/json-schema": "7.0.14", + "ajv": "8.12.0", + "better-ajv-errors": "1.2.0" }, "devDependencies": { "@openstapps/eslint-config": "workspace:*", "@openstapps/prettier-config": "workspace:*", - "@testdeck/mocha": "0.3.3", + "@openstapps/tsconfig": "workspace:*", "@types/chai": "4.3.5", + "@types/fs-extra": "9.0.13", + "@types/glob": "8.0.1", "@types/mocha": "10.0.1", - "@types/node": "14.18.38", - "@types/rimraf": "3.0.2", + "@types/mustache": "4.2.2", + "@types/node": "18.15.3", "c8": "7.14.0", "chai": "4.3.7", + "esbuild": "0.17.19", "mocha": "10.2.0", "mocha-junit-reporter": "2.2.0", "nock": "13.3.1", - "rimraf": "5.0.0", - "ts-node": "10.9.1" + "ts-node": "10.9.1", + "tsup": "6.7.0", + "typedoc": "0.24.8", + "typescript": "5.1.6" }, "prettier": "@openstapps/prettier-config", "eslintConfig": { diff --git a/packages/es-mapping-generator/src/app.ts b/packages/es-mapping-generator/src/app.ts deleted file mode 100644 index b0484e81..00000000 --- a/packages/es-mapping-generator/src/app.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2018-2021 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {Command} from 'commander'; -import {copyFileSync, mkdirSync, readFileSync, writeFileSync} from 'fs'; -import path from 'path'; -import {generateTemplate} from './mapping'; -import {getProjectReflection} from './project-reflection'; - -// handle unhandled promise rejections -process.on('unhandledRejection', async (reason: unknown) => { - if (reason instanceof Error) { - await console.error(reason.message); - console.info(reason.stack); - } - process.exit(1); -}); - -const commander = new Command('openstapps-core-tools'); - -// eslint-disable-next-line unicorn/prefer-module -commander.version(JSON.parse(readFileSync(path.resolve(__dirname, '..', 'package.json')).toString()).version); - -commander - .command('mapping ') - .option('-m, --mappingPath ', 'Mapping Path') - .option('-i, --ignoredTags ', 'Ignored Tags (comma-separated)') - .option('-a, --aggPath ', 'Aggregations Path') - .option('-e, --errorPath ', 'Error Path') - .action(async (relativeSourcePath, options) => { - // get absolute paths - const sourcePath = path.resolve(relativeSourcePath); - - let ignoredTagsList: string[] = []; - if (typeof options.ignoredTags === 'string') { - ignoredTagsList = options.ignoredTags.split(','); - } - - // get project reflection - const projectReflection = getProjectReflection(sourcePath); - - const result = generateTemplate(projectReflection, ignoredTagsList, true); - if (result.errors.length > 0) { - await console.error('Mapping generated with errors!'); - } else { - console.log('Mapping generated without errors!'); - } - - // write documentation to file - if (options.aggPath !== undefined) { - const aggPath = path.resolve(options.aggPath); - mkdirSync(path.dirname(aggPath), {recursive: true}); - // tslint:disable-next-line:no-magic-numbers - writeFileSync(aggPath, JSON.stringify(result.aggregations, null, 2)); - copyFileSync( - // eslint-disable-next-line unicorn/prefer-module - require.resolve('../schema/aggregations.d.ts'), - path.join(path.dirname(aggPath), 'aggregations.json.d.ts'), - ); - console.log(`Elasticsearch aggregations written to ${aggPath}.`); - } - if (options.mappingPath !== undefined) { - const mappingPath = path.resolve(options.mappingPath); - mkdirSync(path.dirname(mappingPath), {recursive: true}); - writeFileSync(mappingPath, JSON.stringify(result.mappings, null, 2)); - copyFileSync( - // eslint-disable-next-line unicorn/prefer-module - require.resolve('../schema/mappings.d.ts'), - path.join(path.dirname(mappingPath), 'mappings.json.d.ts'), - ); - console.log(`Elasticsearch mappings written to ${mappingPath}.`); - } - if (options.errorPath !== undefined) { - const errorPath = path.resolve(options.errorPath); - mkdirSync(path.dirname(errorPath), {recursive: true}); - // tslint:disable-next-line:no-magic-numbers - writeFileSync(errorPath, JSON.stringify(result.errors, null, 2)); - console.log(`Mapping errors written to ${errorPath}.`); - } else if (result.errors.length > 0) { - for (const error of result.errors) { - await console.error(error); - } - - throw new Error('Mapping generation failed'); - } - }); - -commander.parse(process.argv); diff --git a/packages/es-mapping-generator/src/config/fieldmap.ts b/packages/es-mapping-generator/src/config/fieldmap.ts deleted file mode 100644 index 6ff1fb28..00000000 --- a/packages/es-mapping-generator/src/config/fieldmap.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2019-2021 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {MappingProperty} from '@elastic/elasticsearch/lib/api/types'; -import type {ElasticsearchFieldmap, SimpleType} from '../../schema/mappings.js'; - -const ducetSort = { - type: 'icu_collation_keyword', - language: 'de', - country: 'DE', - variant: '@collation=phonebook', -}; - -const keyword: MappingProperty['type'] = 'keyword'; - -export const fieldmap: ElasticsearchFieldmap = { - aggregatable: { - default: { - raw: { - ignore_above: 10_000, - type: keyword, - }, - }, - ignore: ['global'], - }, - sortable: { - default: { - sort: ducetSort, - }, - ducet: { - sort: ducetSort, - }, - ignore: ['price'], - }, -}; - -export const filterableTagName = 'filterable'; - -export const filterableMap: Record = { - date: 'keyword', - keyword: 'keyword', - text: 'keyword', - integer: 'integer', -}; diff --git a/packages/es-mapping-generator/src/config/premap.ts b/packages/es-mapping-generator/src/config/premap.ts deleted file mode 100644 index 614b4715..00000000 --- a/packages/es-mapping-generator/src/config/premap.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2019-2021 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {MappingProperty} from '@elastic/elasticsearch/lib/api/types'; - -export const premaps: Record = { - 'CoordinateReferenceSystem': { - dynamic: true, - properties: { - type: { - type: 'keyword', - }, - }, - }, - 'LineString': { - type: 'geo_shape', - }, - 'Point': { - properties: { - type: { - type: 'keyword', - }, - coordinates: { - type: 'geo_point', - }, - }, - dynamic: 'strict', - }, - 'Polygon': { - type: 'geo_shape', - }, - 'SCISO8601DateRange': { - type: 'date_range', - }, - 'jsonpatch.OpPatch': { - dynamic: 'strict', - properties: { - from: { - type: 'keyword', - }, - op: { - type: 'keyword', - }, - path: { - type: 'keyword', - }, - value: { - // this is actually an 'any' type; however, ES does not really support that. - type: 'keyword', - }, - }, - }, -}; diff --git a/packages/es-mapping-generator/src/config/typemap.ts b/packages/es-mapping-generator/src/config/typemap.ts deleted file mode 100644 index 552ac0d5..00000000 --- a/packages/es-mapping-generator/src/config/typemap.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019-2021 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {MappingFloatNumberProperty} from '@elastic/elasticsearch/lib/api/types'; -import type {ElasticsearchTypemap} from '../../schema/mappings'; - -export const PARSE_ERROR = 'PARSE_ERROR' as MappingFloatNumberProperty['type']; -export const MISSING_PREMAP = 'MISSING_PREMAP' as MappingFloatNumberProperty['type']; -export const TYPE_CONFLICT = 'TYPE_CONFLICT' as MappingFloatNumberProperty['type']; - -export const typemap: ElasticsearchTypemap = { - boolean: { - default: 'boolean', - }, - false: { - default: 'boolean', - }, - number: { - default: 'integer', - float: 'float', - integer: 'integer', - date: 'date', - }, - string: { - default: 'text', - keyword: 'keyword', - text: 'text', - date: 'date', - }, - stringLiteral: { - default: 'keyword', - }, - true: { - default: 'boolean', - }, -}; - -/** - * If the string is a tag type - */ -export function isTagType(string_: string): boolean { - for (const key in typemap) { - if (typemap.hasOwnProperty(key) && typemap[key][string_] !== undefined) { - return true; - } - } - - return false; -} - -export const dynamicTypes = ['any', 'unknown']; diff --git a/packages/es-mapping-generator/src/dsl/schema.ts b/packages/es-mapping-generator/src/dsl/schema.ts new file mode 100644 index 00000000..db968308 --- /dev/null +++ b/packages/es-mapping-generator/src/dsl/schema.ts @@ -0,0 +1,60 @@ +import {MappingProperty, SearchRequest} from '@elastic/elasticsearch/lib/api/types.js'; +import Ajv from 'ajv'; +import {readFile} from 'fs/promises'; +import {fileURLToPath} from 'url'; +import path from 'path'; +import {Context} from '../generator/context.js'; + +/** + * @validatable + */ +export interface ElasticsearchOptionsDSL { + /** + * Mark an interface as indexable + */ + indexable?: true; + /** + * Inherit customization options from another item + */ + extends?: string[]; + /** + * Completely override the property + */ + override?: MappingProperty; + /** + * Merge property values + */ + merge?: MappingProperty; + /** + * Modify the search request + * + * Supports `{name}`, `{type}` and `{prop}` templates substitutions anywhere + */ + search?: Partial; +} + +const schema = JSON.parse( + await readFile(path.join(path.dirname(fileURLToPath(import.meta.url)), 'index.schema.json'), 'utf8'), +); +const ajv = new Ajv.default({schemas: [schema], allowUnionTypes: true}); + +/** + * Validate that the options are valid + */ +export function validateElasticsearchOptionsDsl( + context: Context, + value: unknown, +): value is ElasticsearchOptionsDSL { + return ajv.validate('#/definitions/ElasticsearchOptionsDSL', value) + ? true + : context.bail(JSON.stringify(ajv.errors)); +} + +/** + * Validate that the mapping result is correct + */ +export function validateMappingResult(context: Context, value: unknown): value is MappingProperty { + return ajv.validate('#/definitions/MappingProperty', value) + ? true + : context.bail(JSON.stringify(ajv.errors)); +} diff --git a/packages/es-mapping-generator/src/generator/base.ts b/packages/es-mapping-generator/src/generator/base.ts new file mode 100644 index 00000000..62f23baf --- /dev/null +++ b/packages/es-mapping-generator/src/generator/base.ts @@ -0,0 +1,47 @@ +import {JSONSchema7} from 'json-schema'; +import {MappingProperty} from '@elastic/elasticsearch/lib/api/types.js'; +import {transformObject} from './transformers/object.js'; +import {transformString} from './transformers/string.js'; +import {Context} from './context.js'; +import {transformDefinition} from './definition.js'; + +/** + * Transform JSONSchema without applying custom tag logic + */ +export function transformBase(context: Context, definition: JSONSchema7): MappingProperty { + if (definition.anyOf) { + return context.resolveUnion(definition.anyOf as JSONSchema7[]); + } + + switch (definition.type) { + case 'array': { + if (Array.isArray(definition.items)) { + return context.resolveUnion(definition.items as JSONSchema7[]); + } else if (typeof definition.items === 'object') { + return transformDefinition(context, definition.items); + } else { + return context.bail(`Not implemented array type ${typeof definition.items}`); + } + } + case 'object': { + return transformObject(context, definition); + } + case 'string': { + return transformString(definition); + } + case 'number': { + return {type: 'float'}; + } + case 'integer': { + return {type: 'integer'}; + } + case 'boolean': { + return {type: 'boolean'}; + } + default: { + return { + dynamic: false, + }; + } + } +} diff --git a/packages/es-mapping-generator/src/generator/context.ts b/packages/es-mapping-generator/src/generator/context.ts new file mode 100644 index 00000000..385210b7 --- /dev/null +++ b/packages/es-mapping-generator/src/generator/context.ts @@ -0,0 +1,115 @@ +import {JSONSchema7} from 'json-schema'; +import {transformDefinition} from './definition.js'; +import crypto from 'crypto'; +import { + MappingProperty, + MappingDynamicProperty, + SearchRequest, +} from '@elastic/elasticsearch/lib/api/types.js'; +import deepmerge from 'deepmerge'; +import {MappingGenerator, sanitizeTypeName} from './mapping-generator.js'; +import {renderTemplate} from '../template.js'; + +/** + * Get the name from a $ref such as `#/definitions/SCThing` + */ +function getNameFromRef(ref: string): string { + return decodeURI(ref).replace(/^#\/definitions\//, ''); +} + +export class Context { + constructor( + readonly generator: MappingGenerator, + readonly thingType: string, + readonly path: string[], + readonly propertyPath: string[], + readonly dependencies: Map>, + ) {} + + resolveReference(reference: string): MappingProperty { + return this.deriveContext(reference)[1]; + } + + resolveUnion(types: JSONSchema7[]): MappingDynamicProperty { + for (const type of types) { + const [name] = this.deriveContext(type.$ref ?? type); + this.addDependency(name, this.propertyPath.join('.')); + } + + return { + type: '{dynamic_property}', + }; + } + + private deriveContext(reference: string | JSONSchema7): [dependencyName: string, mapping: MappingProperty] { + let referenceName = typeof reference === 'string' ? getNameFromRef(reference) : undefined; + let definition = typeof reference === 'string' ? undefined : reference; + + if (!definition && !this.generator.cache.has(referenceName!)) { + definition = this.generator.project.definitions![referenceName!] as JSONSchema7; + if (typeof definition !== 'object') this.bail(`Invalid path ${referenceName!}`); + } + + if (!referenceName || !this.generator.cache.has(referenceName)) { + const derivedContext = new Context( + this.generator, + this.thingType, + referenceName ? [referenceName] : [], + this.propertyPath, + new Map(), + ); + const result = transformDefinition(derivedContext, definition); + referenceName ??= crypto.createHash('md5').update(JSON.stringify(result)).digest('hex'); + + this.generator.cache.set(referenceName, {mapping: result, dependencies: derivedContext.dependencies}); + } + + const {mapping, dependencies} = this.generator.cache.get(referenceName)!; + for (const [name, paths] of dependencies) { + for (const path of paths) { + this.addDependency(name, [...this.propertyPath.slice(0, -1), path].join('.')); + } + } + return [referenceName, mapping]; + } + + registerSearchMod(modification: Partial) { + this.generator.searchMods.mods = deepmerge>( + this.generator.searchMods.mods, + renderTemplate(modification, [ + ['{name}', this.path[0]], + ['{prop}', this.propertyPath.join('.')], + ['{type}', this.thingType], + ['{_type}', sanitizeTypeName(this.thingType)], + ]), + ); + } + + private addDependency(name: string, path: string) { + if (!this.dependencies.has(name)) { + this.dependencies.set(name, new Set([path])); + } else { + this.dependencies.get(name)!.add(path); + } + } + + /** + * Step down into a property + */ + step(property: string): Context { + return new Context( + this.generator, + this.thingType, + [...this.path, property], + [...this.propertyPath, property], + this.dependencies, + ); + } + + /** + * Bail and throw + */ + bail(reason: string): never { + throw new Error(`${this.path.join('.')} ${reason}`); + } +} diff --git a/packages/es-mapping-generator/src/generator/definition.ts b/packages/es-mapping-generator/src/generator/definition.ts new file mode 100644 index 00000000..3ae15705 --- /dev/null +++ b/packages/es-mapping-generator/src/generator/definition.ts @@ -0,0 +1,32 @@ +import {JSONSchema7} from 'json-schema'; +import {MappingProperty} from '@elastic/elasticsearch/lib/api/types.js'; +import {transformBase} from './base.js'; +import {Context} from './context.js'; +import deepmerge from 'deepmerge'; +import {resolveDsl} from './dsl.js'; +import {getTags, INDEXABLE_TAG_NAME} from './tags.js'; + +/** + * Transform JSONSchema + */ +export function transformDefinition(context: Context, definition: JSONSchema7): MappingProperty { + if (definition.$ref) return context.resolveReference(definition.$ref); + const tags = getTags(definition); + tags.delete(INDEXABLE_TAG_NAME); + let base = transformBase(context, definition); + + if (tags.size > 0) { + const options = resolveDsl(context, {extends: [...tags]}); + if (options.override) { + base = options.override; + } + if (options.merge) { + base = deepmerge(base, options.merge); + } + if (options.search) { + context.registerSearchMod(options.search); + } + } + + return base; +} diff --git a/packages/es-mapping-generator/src/generator/dsl.ts b/packages/es-mapping-generator/src/generator/dsl.ts new file mode 100644 index 00000000..e612a06d --- /dev/null +++ b/packages/es-mapping-generator/src/generator/dsl.ts @@ -0,0 +1,48 @@ +import {Context} from './context.js'; +import {ElasticsearchOptionsDSL} from '../dsl/schema.js'; +import deepmerge from 'deepmerge'; + +type ResolvedOptions = Omit; + +/** + * Resolve DSL inheritance + */ +export function resolveDsl( + context: Context, + {extends: parents, ...result}: ElasticsearchOptionsDSL, +): ResolvedOptions { + for (const reference of parents ?? []) { + result = deepmerge( + result, + reference.startsWith('@') + ? resolveReferencePath(context, reference) + : resolvePresetReference(context, reference), + ); + } + + return result; +} + +/** + * Resolve preset references + */ +function resolvePresetReference(context: Context, reference: string): ResolvedOptions { + if (!context.generator.presets.has(reference)) return context.bail(`Missing preset ${reference}`); + return resolveDsl(context, context.generator.presets.get(reference)!); +} + +/** + * Resolve @references + */ +function resolveReferencePath(context: Context, reference: string): ResolvedOptions { + const [type, ...path] = reference.replace(/^@/, '').split('.'); + let declaration = context.resolveReference(type); + while (path.length > 0) { + const property = path.shift()!; + if (!('properties' in declaration && declaration.properties && property in declaration.properties)) + context.bail(`Invalid reference ${reference}`); + + declaration = declaration.properties[property]; + } + return {override: declaration}; +} diff --git a/packages/es-mapping-generator/src/generator/index.ts b/packages/es-mapping-generator/src/generator/index.ts new file mode 100644 index 00000000..ecfd5cb6 --- /dev/null +++ b/packages/es-mapping-generator/src/generator/index.ts @@ -0,0 +1,171 @@ +import type {JSONSchema7} from 'json-schema'; +import {ElasticsearchOptionsDSL} from '../dsl/schema.js'; +import {IndicesPutTemplateRequest, MappingProperty} from '@elastic/elasticsearch/lib/api/types.js'; +import {MappingGenerator} from './mapping-generator.js'; +import {getTags, INDEXABLE_TAG_NAME} from './tags.js'; + +export interface GeneratorOptions { + /** + * Presets you can extend + */ + presets: Record; + /** + * Override specific types + */ + overrides: Record; + /** + * Template for the generated index request + * + * Supports `{type}` and `{sanitized_type}` (same as `{type}`, but no spaces) template substitutions + */ + template: Partial; +} + +/** + * Fully transform a project + */ +export function transformProject(project: JSONSchema7) { + const context = new MappingGenerator(project, OPTIONS); + + const results = []; + for (const name in project.definitions) { + const definition = project.definitions[name]; + if (typeof definition !== 'object' || !getTags(definition).has(INDEXABLE_TAG_NAME)) continue; + + results.push(context.buildTemplate(name)); + } + return { + mappings: results, + search: context.searchMods.mods, + }; +} + +const OPTIONS: GeneratorOptions = { + template: { + name: 'template_{_type}', + index_patterns: 'stapps_{_type}*', + settings: { + 'mapping.total_fields.limit': 10_000, + 'max_result_window': 30_000, + 'number_of_replicas': 0, + 'number_of_shards': 1, + }, + mappings: { + date_detection: false, + _source: { + excludes: ['creation_date'], + }, + properties: { + creation_date: { + type: 'date', + }, + }, + }, + }, + overrides: { + 'CoordinateReferenceSystem': { + dynamic: true, + properties: { + type: { + type: 'keyword', + }, + }, + }, + 'LineString': { + type: 'geo_shape', + }, + 'Point': { + properties: { + type: { + type: 'keyword', + }, + coordinates: { + type: 'geo_point', + }, + }, + dynamic: 'strict', + }, + 'Polygon': { + type: 'geo_shape', + }, + 'SCISO8601DateRange': { + type: 'date_range', + }, + 'jsonpatch.OpPatch': { + dynamic: 'strict', + properties: { + from: { + type: 'keyword', + }, + op: { + type: 'keyword', + }, + path: { + type: 'keyword', + }, + value: { + // this is actually an 'any' type; however, ES does not really support that. + type: 'keyword', + }, + }, + }, + }, + presets: { + 'type': {extends: ['sortable:ducet', 'filterable', 'aggregatable:global']}, + 'text': { + merge: {type: 'text'}, + }, + 'filterable': { + merge: { + fields: { + raw: {type: 'keyword'}, + }, + }, + }, + 'sortable:ducet': { + merge: { + fields: { + sort: { + type: 'icu_collation_keyword', + language: 'de', + country: 'DE', + variant: '@collation=phonebook', + } as never, + }, + }, + }, + 'sortable': { + extends: ['sortable:ducet'], + }, + 'sortable:price': {}, + 'aggregatable': { + search: { + aggs: { + '{type}': { + aggs: { + '{prop}': { + terms: { + field: '{prop}.raw', + size: 1000, + }, + }, + }, + filter: {term: {type: '{type}'}}, + }, + }, + }, + }, + 'aggregatable:global': { + search: { + aggs: { + '@all.{prop}': { + terms: { + field: '{prop}.raw', + size: 1000, + }, + }, + }, + }, + }, + }, +}; diff --git a/packages/es-mapping-generator/src/generator/mapping-generator.ts b/packages/es-mapping-generator/src/generator/mapping-generator.ts new file mode 100644 index 00000000..379f736a --- /dev/null +++ b/packages/es-mapping-generator/src/generator/mapping-generator.ts @@ -0,0 +1,76 @@ +import {GeneratorOptions} from './index.js'; +import {JSONSchema7} from 'json-schema'; +import {ElasticsearchOptionsDSL} from '../dsl/schema.js'; +import { + IndicesPutTemplateRequest, + MappingProperty, + MappingTypeMapping, + SearchRequest, +} from '@elastic/elasticsearch/lib/api/types.js'; +import {Context} from './context.js'; +import deepmerge from 'deepmerge'; +import {renderTemplate} from '../template.js'; + +/** + * Sanitize a type name + */ +export function sanitizeTypeName(typeName: string): string { + return typeName.replaceAll(' ', '_'); +} + +export class MappingGenerator { + readonly presets: Map; + + readonly cache: Map>}>; + + readonly searchMods: {mods: Partial} = {mods: {}}; + + readonly template: Partial; + + constructor(readonly project: JSONSchema7, options: GeneratorOptions) { + this.template = options.template ?? {}; + this.presets = new Map(Object.entries(options.presets)); + this.cache = new Map( + Object.entries(options.overrides).map(([name, mapping]) => [ + name, + { + mapping, + dependencies: new Map(), + }, + ]), + ); + } + + buildTemplate(name: string): IndicesPutTemplateRequest { + const thingType = ((this.project.definitions![name] as JSONSchema7).properties!.type as JSONSchema7) + .const; + if (typeof thingType !== 'string') { + throw new TypeError(`${name} needs a valid thing type`); + } + const mappingContext = new Context(this, thingType, [name], [], new Map()); + const mappings = mappingContext.resolveReference(name); + + const request: IndicesPutTemplateRequest = deepmerge( + {mappings: mappings as MappingTypeMapping}, + renderTemplate(this.template, [ + ['{name}', name], + ['{type}', thingType], + ['{_type}', sanitizeTypeName(thingType)], + ]), + ); + + if (mappingContext.dependencies.size > 0) { + request.mappings!.dynamic_templates = []; + for (const [name, paths] of mappingContext.dependencies) { + request.mappings!.dynamic_templates.push({ + [name]: { + path_match: paths.size > 1 ? [...paths] : paths.values().next().value, + mapping: mappingContext.resolveReference(name), + }, + }); + } + } + + return request; + } +} diff --git a/packages/es-mapping-generator/src/generator/tags.ts b/packages/es-mapping-generator/src/generator/tags.ts new file mode 100644 index 00000000..d1438df5 --- /dev/null +++ b/packages/es-mapping-generator/src/generator/tags.ts @@ -0,0 +1,13 @@ +import {JSONSchema7} from 'json-schema'; + +export const INDEXABLE_TAG_NAME = 'indexable'; + +/** + * Get elasticsearch tags + */ +export function getTags(definition: JSONSchema7): Set { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return new Set( + (definition as {elasticsearch: string}).elasticsearch?.split(/\s/).map(it => it.trim()) ?? [], + ); +} diff --git a/packages/es-mapping-generator/src/generator/transformers/object.ts b/packages/es-mapping-generator/src/generator/transformers/object.ts new file mode 100644 index 00000000..957e7b01 --- /dev/null +++ b/packages/es-mapping-generator/src/generator/transformers/object.ts @@ -0,0 +1,20 @@ +import {JSONSchema7} from 'json-schema'; +import {MappingProperty} from '@elastic/elasticsearch/lib/api/types.js'; +import {transformDefinition} from '../definition.js'; +import {Context} from '../context.js'; + +/** + * Transform a JSON Schema with `object` type + */ +export function transformObject(context: Context, definition: JSONSchema7): MappingProperty { + const value = { + dynamic: definition.additionalProperties === true ? undefined : 'strict', + properties: {} as Record, + } satisfies MappingProperty; + + for (const key in definition.properties!) { + value.properties[key] = transformDefinition(context.step(key), definition.properties[key] as JSONSchema7); + } + + return value; +} diff --git a/packages/es-mapping-generator/src/generator/transformers/string.ts b/packages/es-mapping-generator/src/generator/transformers/string.ts new file mode 100644 index 00000000..dfb780d9 --- /dev/null +++ b/packages/es-mapping-generator/src/generator/transformers/string.ts @@ -0,0 +1,19 @@ +import {JSONSchema7} from 'json-schema'; +import {MappingProperty} from '@elastic/elasticsearch/lib/api/types.js'; + +const stringFormats = new Map([ + ['date', {type: 'date', format: 'date'}], + ['time', {type: 'date', format: 'time'}], + ['date-time', {type: 'date', format: 'date_optional_time'}], + ['ipv4', {type: 'ip'}], + ['ipv6', {type: 'ip'}], +]); + +/** + * Transform a JSON Schema with `string` type + */ +export function transformString(definition: JSONSchema7): MappingProperty { + return definition.format && stringFormats.has(definition.format) + ? stringFormats.get(definition.format)! + : {type: 'keyword'}; +} diff --git a/packages/es-mapping-generator/src/index.ts b/packages/es-mapping-generator/src/index.ts index b92e5e1c..337238fa 100644 --- a/packages/es-mapping-generator/src/index.ts +++ b/packages/es-mapping-generator/src/index.ts @@ -1,7 +1,16 @@ -export * from './mapping'; -export * from './project-reflection'; +import {transformProject} from './generator/index.js'; +import {SchemaConsumer} from '@openstapps/json-schema-generator'; -export * from './config/premap'; -export * from './config/fieldmap'; -export * from './config/settings'; -export * from './config/typemap'; +/** + * JSON Schema Generator plugin for Elasticsearch Mappings + */ +export function elasticsearchMappingGenerator(fileName: string): [string, SchemaConsumer] { + return [ + 'Elasticsearch-Mappings', + function (schema) { + return { + [fileName]: JSON.stringify(transformProject(schema)), + }; + }, + ]; +} diff --git a/packages/es-mapping-generator/src/mapping.ts b/packages/es-mapping-generator/src/mapping.ts deleted file mode 100644 index 01744c1a..00000000 --- a/packages/es-mapping-generator/src/mapping.ts +++ /dev/null @@ -1,894 +0,0 @@ -/* - * Copyright (C) 2019-2021 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import { - MappingDynamicTemplate, - MappingObjectProperty, - MappingProperty, -} from '@elastic/elasticsearch/lib/api/types'; -import merge from 'deepmerge'; -import {stringify} from 'flatted'; -import {DeclarationReflection, ProjectReflection, SignatureReflection} from 'typedoc'; -import { - ArrayType, - Comment, - CommentTag, - IntrinsicType, - ReferenceType, - ReflectionType, - StringLiteralType, - Type, - TypeParameterType, - UnionType, -} from 'typedoc/dist/lib/models'; -import {fieldmap, filterableMap, filterableTagName} from './config/fieldmap'; -import {premaps} from './config/premap'; -import {settings} from './config/settings'; -import {dynamicTypes, isTagType, MISSING_PREMAP, PARSE_ERROR, TYPE_CONFLICT, typemap} from './config/typemap'; -import type {AggregationSchema, ESNestedAggregation} from '../schema/aggregations'; -import type {ElasticsearchTemplateCollection, MappingGenTemplate} from '../schema/mappings'; -import * as console from 'console'; - -let dynamicTemplates: Record[] = []; -let errors: string[] = []; -let showErrors = true; - -let aggregations: AggregationSchema = {}; - -const indexableTag = 'indexable'; -const aggregatableTag = 'aggregatable'; -const aggregatableTagParameterGlobal = 'global'; -const inheritTagsName = 'inherittags'; - -// clamp printed object to 1000 chars to keep error messages readable -const maxErrorObjectChars = 1000; - -let ignoredTagsList = ['indexable', 'validatable', inheritTagsName]; -let inheritTagsMap: {[path: string]: CommentTag[]} = {}; - -/** - * Gets all interfaces that have an @indexable tag - * @param projectReflection the project reflection from which to extract the indexable interfaces - */ -export function getAllIndexableInterfaces(projectReflection: ProjectReflection): DeclarationReflection[] { - let indexableInterfaces: DeclarationReflection[] = []; - - if (!Array.isArray(projectReflection.children) || projectReflection.children.length === 0) { - throw new Error('No DeclarationReflections found. Please check your input path'); - } - - // push all declaration reflections into one array - for (const declarationReflection of projectReflection.children) { - if (Array.isArray(declarationReflection.children)) { - indexableInterfaces = [...indexableInterfaces, ...declarationReflection.children]; - } - } - - // filter all declaration reflections with an @indexable tag - indexableInterfaces = indexableInterfaces.filter(declarationReflection => { - if (declarationReflection.comment === undefined || declarationReflection.comment.tags === undefined) { - return false; - } - - return declarationReflection.comment.tags.some(commentTag => { - return commentTag.tagName === indexableTag; - }); - }); - - return indexableInterfaces; -} - -/** - * Composes error messages, that are readable and contain a certain minimum of information - * @param path the path where the error took place - * @param topTypeName the name of the SCThingType - * @param typeName the name of the object, with which something went wrong - * @param object the object or name - * @param message the error message - */ -function composeErrorMessage( - path: string, - topTypeName: string, - typeName: string, - object: string, - message: string, -) { - const error = `At "${topTypeName}::${path.slice( - 0, - Math.max(0, path.length - 1), - )}" for ${typeName} "${trimString(object, maxErrorObjectChars)}": ${message}`; - errors.push(error); - if (showErrors) { - // tslint:disable-next-line:no-floating-promises - void console.error(error); - } -} - -/** - * Trims a string to a readable size and appends "..." - * @param value the string to trim - * @param maxLength the maximum allowed length before it is clamped - */ -function trimString(value: string, maxLength: number): string { - return value.length > maxLength ? `${value.slice(0, Math.max(0, maxLength))}...` : value; -} - -/** - * Gets the Reflections and names for Generics in a ReferenceType of a DeclarationReflection - * - * Warning to future maintainers: The code for generics doesn't account for depth. when there is a new generic, it will - * override the previous one, if there isn't, it will just continue passing it down. - * @param type the ReferenceType of a DeclarationReflection - * @param out the previous reflection, it then overrides all parameters or keeps old ones - * @param topTypeName the name of the object, with which something went wrong - * @param path the current path to the object we are in - * @param tags any tags attached to the type - */ -function getReflectionGeneric( - type: ReferenceType, - out: Map, - topTypeName: string, - path: string, - tags: CommentTag[], -): Map { - if ( - type.typeArguments !== undefined && - type.reflection instanceof DeclarationReflection && - type.reflection.typeParameters !== undefined - ) { - for (let i = 0; i < type.reflection.typeParameters.length; i++) { - if (i < type.typeArguments.length) { - out.set( - type.reflection.typeParameters[i].name, - handleType(type.typeArguments[i], out, topTypeName, path, tags), - ); - } else { - // this can happen due to a bug in TypeDoc https://github.com/TypeStrong/typedoc/issues/1061 - // we have no way to know the type here, so we have to use this. - out.set(type.reflection.typeParameters[i].name, { - dynamic: true, - properties: {}, - }); - - console.warn( - `Type "${type.name}": Defaults of generics (Foo) currently don't work due to a bug` + - ` in TypeDoc. It has been replaced by a dynamic type.`, - ); - } - } - } - - return out; -} - -/** - * Handles a ReferenceType that has no value - * - * Most of the times that is an external type. - * @param ref the ReferenceType - * @param generics the generics from levels above, so we can use them without having access to the parent - * @param path the current path to the object we are in - * @param topTypeName the name of the SCThingType - * @param tags any tags attached to the type - */ -function handleExternalType( - ref: ReferenceType, - generics: Map, - path: string, - topTypeName: string, - tags: CommentTag[], -): MappingProperty { - for (const premap of Object.keys(premaps)) { - if (premap === ref.name) { - return readFieldTags(premaps[premap], path, topTypeName, tags); - } - } - - if (ref.name === 'Array') { - // basically an external type, but Array is quite common, especially with generics - if (ref.typeArguments === undefined || ref.typeArguments[0] === undefined) { - composeErrorMessage(path, topTypeName, 'Array with generics', 'array', 'Failed to parse'); - - return {type: PARSE_ERROR}; - } - - return readFieldTags( - handleType( - ref.typeArguments[0], - getReflectionGeneric(ref, new Map(generics), path, topTypeName, tags), - path, - topTypeName, - tags, - ), - path, - topTypeName, - tags, - ); - } - if (ref.name === '__type') { - // empty object - return { - dynamic: 'strict', - properties: {}, - }; - } - - composeErrorMessage(path, topTypeName, 'external type', ref.name, 'Missing pre-map'); - - return readFieldTags({type: MISSING_PREMAP}, path, topTypeName, tags); -} - -/** - * Handles an object - * @param decl the DeclarationReflection of the object - * @param generics the generics from levels above, so we can use them without having access to the parent - * @param path the current path to the object we are in - * @param topTypeName the name of the SCThingType - * @param inheritedTags the inherited tags - */ -function handleDeclarationReflection( - decl: DeclarationReflection, - generics: Map, - path: string, - topTypeName: string, - inheritedTags?: CommentTag[], -): MappingProperty { - // check if we have an object referencing a generic - if (generics.has(decl.name)) { - // if the object name is the same as the generic name - return readFieldTags(generics.get(decl.name)!, path, topTypeName, decl.comment?.tags ?? []); - // use the value defined by the generic - } - - // start the actual handling process - const out: MappingProperty = { - dynamic: 'strict', - properties: {}, - }; - - let empty = true; - // first check if there are any index signatures, so for example `[name: string]: Foo` - if (decl.indexSignature !== undefined) { - out.dynamic = true; - - if (decl.indexSignature.type !== undefined) { - empty = false; - const template: Record = {}; - template[decl.name] = { - mapping: handleType( - decl.indexSignature.type, - new Map(generics), - path, - topTypeName, - getCommentTags(decl.indexSignature, path, topTypeName), - ), - match: '*', - match_mapping_type: '*', - path_match: `${path}*`, - }; - dynamicTemplates.push(template); - } - } - - if (decl.kindString === 'Enumeration') { - return readTypeTags('string', path, topTypeName, getCommentTags(decl, path, topTypeName, inheritedTags)); - } - - // check all the children, so in this case we are dealing with an OBJECT - if (decl.children !== undefined && decl.children.length > 0) { - for (const child of decl.children) { - empty = false; - out.properties![child.name] = handleDeclarationReflection( - child, - new Map(generics), - `${path}${child.name}.`, - topTypeName, - ); - } - } else if (decl.type instanceof Type) { - // if the object is a type, so we are dealing with a PROPERTY - // get inherited tags - const tags = - (inheritedTags ?? []).length > 0 - ? inheritedTags!.some(it => isTagType(it.tagName)) - ? inheritedTags! - : [...(inheritedTags ?? []), ...getCommentTags(decl, path, topTypeName)] - : getCommentTags(decl, path, topTypeName); - - return handleType(decl.type, new Map(generics), path, topTypeName, tags); - } else if (decl.kindString === 'Enumeration member') { - return readTypeTags( - typeof decl.defaultValue, - path, - topTypeName, - getCommentTags(decl, path, topTypeName, inheritedTags), - ); - } - - if (empty) { - composeErrorMessage(path, topTypeName, 'object', decl.name, 'Empty object'); - } - - return readFieldTags(out, path, topTypeName, getCommentTags(decl, path, topTypeName)); -} - -/** - * Reads all comment tags, including inherited ones - * @param decl the DeclarationReflection to read the tags from - * @param path the path on which the comments lie - * @param topTypeName the name of the SCThingType - * @param inheritedTags any tags that might have been inherited by a parent - * @param breakId the id of the previous reflection to prevent infinite recursion in some cases - */ -function getCommentTags( - decl: DeclarationReflection | SignatureReflection, - path: string, - topTypeName: string, - inheritedTags: CommentTag[] = [], - // tslint:disable-next-line:no-unnecessary-initializer - breakId: number | undefined = undefined, -): CommentTag[] { - if (decl.id === breakId) { - return []; - } - - let out: CommentTag[] = - decl.comment instanceof Comment - ? decl.comment.tags !== undefined - ? decl.comment.tags - : inheritedTags - : inheritedTags; - if ( - decl.overwrites instanceof ReferenceType && - decl.overwrites.reflection instanceof DeclarationReflection - ) { - out = arrayPriorityJoin( - getCommentTags(decl.overwrites.reflection, path, topTypeName, inheritedTags, decl.id), - out, - ); - } - if ( - decl.inheritedFrom instanceof ReferenceType && - decl.inheritedFrom.reflection instanceof DeclarationReflection - ) { - out = arrayPriorityJoin( - getCommentTags(decl.inheritedFrom.reflection, path, topTypeName, inheritedTags, decl.id), - out, - ); - } - - saveCommentTags(out, path, topTypeName); - const inheritTag = out.find(value => value.tagName === inheritTagsName); - if (inheritTag !== undefined) { - out = arrayPriorityJoin(out, retrieveCommentTags(inheritTag.text.trim(), path, topTypeName)); - } - - return out; -} - -/** - * Saves all comment tags to the map - * @param tags all tags to be saved (@see and @[inheritTags] will be stripped) - * @param path the path of field - * @param topTypeName the name of the SCThingType - */ -function saveCommentTags(tags: CommentTag[], path: string, topTypeName: string) { - inheritTagsMap[`${topTypeName}::${path.slice(0, Math.max(0, path.length - 1))}`] = tags.filter( - value => value.tagName !== 'see' && value.tagName !== inheritTagsName, - ); -} - -/** - * Retrieves any saved tags - * @param path the path to the original field - * @param currentPath the current path to the object we are in - * @param topTypeName the name of the SCThingType - */ -function retrieveCommentTags(path: string, currentPath: string, topTypeName: string): CommentTag[] { - if (!(path in inheritTagsMap)) { - composeErrorMessage(currentPath, topTypeName, path, 'Comment', 'Referenced path to tags does not exist!'); - - return []; - } - - return inheritTagsMap[path]; -} - -/** - * Joins two arrays of CommentTags, but overrides all original CommentTags with the same tagName - * @param originals the original array - * @param overrider the array that should be appended and provide the override values - */ -function arrayPriorityJoin(originals: CommentTag[], overrider: CommentTag[]): CommentTag[] { - const out: CommentTag[] = overrider; - - for (const original of originals) { - const result = overrider.find(element => original.tagName === element.tagName); - - // no support for multiple tags with the same name - if (!(result instanceof CommentTag)) { - out.push(original); - } - } - - return out; -} - -/** - * Handles UnionTypes - * - * Put into a separate function as it is a little bit more complex - * Works fairly reliable, although there are issues with primitive union types, which don't work at all (And never will) - * @param type the type object - * @param generics the generics from levels above, so we can use them without having access to the parent - * @param path the current path to the object we are in - * @param topTypeName the name of the SCThingType - * @param tags any tags attached to the type - */ -function handleUnionType( - type: UnionType, - generics: Map, - path: string, - topTypeName: string, - tags: CommentTag[], -): MappingProperty { - const list: MappingProperty[] = []; - - for (const subType of type.types) { - if (subType instanceof IntrinsicType && subType.name === 'undefined') { - continue; - } - list.push(handleType(subType, new Map(generics), path, topTypeName, tags)); - } - - if (list.length > 0) { - let out = list[0]; - - for (const item of list) { - out = merge(out, item); - } - - return out; - } - - composeErrorMessage( - path, - topTypeName, - 'Union Type', - stringify(list), - 'Empty union type. This is likely not a user error.', - ); - - return {type: PARSE_ERROR}; -} - -/** - * Serves as a kind of distributor for the different types, should not contain any specific code - * @param type the type object - * @param generics the generics from levels above, so we can use them without having access to the parent - * @param path the current path to the object we are in - * @param topTypeName the name of the SCThingType - * @param tags any tags attached to the type - */ -function handleType( - type: Type, - generics: Map, - path: string, - topTypeName: string, - tags: CommentTag[], -): MappingProperty { - // logger.log((type as any).name); - if (type instanceof ArrayType) { - // array is irrelevant in Elasticsearch, so just go with the element type - const esType = handleType(type.elementType, new Map(generics), path, topTypeName, tags); - // also merge tags of the array to the element type - // filter out the type tags lazily, this can lead to double messages for "Not implemented tag" - let newTags = tags; - if ('type' in esType) { - newTags = tags.filter(tag => { - return !(tag.tagName === esType.type); - }); - } - - return readFieldTags(esType, path, topTypeName, newTags); - } - if (type.type === 'stringLiteral') { - // a string literal, usually for type - return readTypeTags(type.type, path, topTypeName, tags); - } - if (type instanceof IntrinsicType) { - // the absolute default type, like strings - return readTypeTags(type.name, path, topTypeName, tags); - } - if (type instanceof UnionType) { - // the union type... - return handleUnionType(type, new Map(generics), path, topTypeName, tags); - } - if (type instanceof ReferenceType) { - if (premaps[type.name] === undefined && type.reflection !== undefined) { - // there is really no way to make this typesafe, every element in DeclarationReflection is optional. - return handleDeclarationReflection( - type.reflection as DeclarationReflection, - getReflectionGeneric(type, new Map(generics), path, topTypeName, tags), - path, - topTypeName, - tags, - ); - } - - return handleExternalType(type, new Map(generics), path, topTypeName, tags); - } - if (type instanceof TypeParameterType) { - // check if we have an object referencing a generic - if (generics.has(type.name)) { - return generics.get(type.name)!; - } - composeErrorMessage(path, topTypeName, 'Generic', type.name, 'Missing reflection, please report!'); - - return {type: PARSE_ERROR}; - } - if (type instanceof ReflectionType) { - return readFieldTags( - handleDeclarationReflection(type.declaration, new Map(generics), path, topTypeName), - path, - topTypeName, - tags, - ); - } - - composeErrorMessage(path, topTypeName, 'type', stringify(type), 'Not implemented type'); - - return {type: PARSE_ERROR}; -} - -/** - * Adds an aggregatable to the aggregations list - * @param path the current path - * @param topTypeName the name of the top type - * @param global whether the topTypeName will be used - */ -function addAggregatable(path: string, topTypeName: string, global: boolean) { - // push type.path and remove the '.' at the end of the path - - if (global) { - const property_ = path.slice(0, -1).split('.').pop() as string; // cannot be undefined - - return ((aggregations['@all'] as ESNestedAggregation).aggs[property_.split('.').pop() as string] = { - terms: { - field: `${property_}.raw`, - size: 1000, - }, - }); - } - - const property = path.slice(0, -1); - - return ((aggregations[topTypeName] as ESNestedAggregation).aggs[property] = { - terms: { - field: `${property}.raw`, - size: 1000, - }, - }); -} - -/** - * Reads all tags related to Elasticsearch fields from the fieldMap - * @param previous the previous ElasticsearchValue, for example and object - * @param path the current path to the object we are in - * @param topTypeName the name of the SCThingType - * @param tags tags attached to the value - * @param dataType the ElasticsearchDataType, for checking if a tag is a type tag - */ -function readFieldTags( - previous: MappingProperty, - path: string, - topTypeName: string, - tags: CommentTag[], - dataType?: string, -): MappingProperty { - for (const tag of tags) { - if (tag.tagName === aggregatableTag) { - addAggregatable(path, topTypeName, tag.text.trim() === aggregatableTagParameterGlobal); - } - - if (!ignoredTagsList.includes(tag.tagName)) { - if (fieldmap[tag.tagName] !== undefined) { - if (previous.fields === undefined) { - // create in case it doesn't exist - previous.fields = {}; - } - if (tag.text.trim() === '') { - // merge fields - previous.fields = {...previous.fields, ...fieldmap[tag.tagName].default}; - } else if (fieldmap[tag.tagName][tag.text.trim()] !== undefined) { - // merge fields - previous.fields = {...previous.fields, ...fieldmap[tag.tagName][tag.text.trim()]}; - } else if (!fieldmap[tag.tagName].ignore.includes(tag.text.trim())) { - // when there is an unidentified tag - composeErrorMessage( - path, - topTypeName, - 'tag', - tag.tagName, - `Not implemented tag param "${tag.text.trim()}"`, - ); - } - } else if (tag.tagName === filterableTagName) { - if (previous.fields === undefined) { - previous.fields = {}; - } - if ('type' in previous) { - const type = filterableMap[previous.type!]; - if (type !== undefined) { - // merge fields - previous.fields = {...previous.fields, raw: {type: type}}; - } else { - composeErrorMessage( - path, - topTypeName, - 'tag', - tag.tagName, - `Not implemented for ${previous.type}`, - ); - } - } else { - composeErrorMessage(path, topTypeName, 'tag', tag.tagName, 'Not applicable for object types'); - } - } else if (dataType === undefined || typemap[dataType][tag.tagName] === undefined) { - composeErrorMessage(path, topTypeName, 'tag', tag.tagName, `Not implemented tag`); - } - } - } - - return previous; -} - -/** - * Reads all types related to Elasticsearch fields from the fieldMap - * @param type the type of the value - * @param path the current path to the object we are in - * @param topTypeName the name of the SCThingType - * @param tags tags attached to the value - */ -function readTypeTags(type: string, path: string, topTypeName: string, tags: CommentTag[]): MappingProperty { - let out: MappingProperty = {type: PARSE_ERROR}; - - if (typemap[type] !== undefined) { - // first look if the value has a definition in the typemap - for (let i = tags.length - 1; i >= 0; i--) { - if (!ignoredTagsList.includes(tags[i].tagName) && typemap[type][tags[i].tagName] !== undefined) { - // if we have a tag that indicates a type - if (out.type !== PARSE_ERROR) { - composeErrorMessage( - path, - topTypeName, - 'type', - type, - `Type conflict; "${typemap[type][tags[i].tagName]}" would override "${ - (out as MappingProperty).type - }"`, - ); - (out as MappingProperty).type = TYPE_CONFLICT; - continue; - } - (out as MappingProperty).type = typemap[type][tags[i].tagName]; - } - } - - if (out.type === PARSE_ERROR) { - (out as MappingProperty).type = typemap[type].default; - } - - out = readFieldTags(out, path, topTypeName, tags, type); - - return out; - } - if (dynamicTypes.includes(type)) { - // Elasticsearch dynamic type TODO: doesn't work for direct types - return { - dynamic: true, - properties: {}, - }; - } - - composeErrorMessage(path, topTypeName, 'type', type, 'Not implemented type'); - - return out; -} - -/** - * Reset the state - * - * This is kind of a suboptimal solution and should be changed in the future. - * https://gitlab.com/openstapps/core-tools/-/issues/49 - * @param resetInheritTags whether inherited tags should be reset as well - */ -function reset(resetInheritTags = true) { - errors = []; - dynamicTemplates = []; - aggregations = { - '@all': { - aggs: {}, - filter: { - match_all: {}, - }, - }, - }; - - if (resetInheritTags) { - inheritTagsMap = {}; - } -} - -/** - * Takes a project reflection and generates an ElasticsearchTemplate from it - * - * Serves as the entry point for getting the mapping, so if you just want to get the mapping files for Elasticsearch, - * you can do so by calling this function, `RETURNED_VALUE.template` contains the mapping in a fashion that is directly - * readable by Elasticsearch. - * @param projectReflection a reflection of the project you want to get the ES Mappings from - * @param ignoredTags the tag names for which the error output should be suppressed - * @param showErrorOutput whether to print all errors in the command line or not - * @param interfaceFilter only parse specific interfaces, this is for testing purposes - */ -export function generateTemplate( - projectReflection: ProjectReflection, - ignoredTags: string[], - showErrorOutput = true, - interfaceFilter: string[] = [], -): MappingGenTemplate { - reset(); - - showErrors = showErrorOutput; - - ignoredTagsList = ['indexable', 'validatable', inheritTagsName]; - // eslint-disable-next-line prefer-spread - ignoredTagsList.push.apply(ignoredTagsList, ignoredTags); - - const indexableInterfaces = getAllIndexableInterfaces(projectReflection); - - const out: ElasticsearchTemplateCollection = {}; - - for (const _interface of indexableInterfaces) { - // TODO: lots of duplicate code, this all needs to be changed https://gitlab.com/openstapps/core-tools/-/issues/49 - if (!Array.isArray(_interface.children) || _interface.children.length === 0) { - throw new Error('Interface needs at least some properties to be indexable'); - } - - const typeObject = _interface.children.find(declarationReflection => { - return declarationReflection.name === 'type'; - }); - - if (typeObject === undefined || typeObject.type === undefined) { - throw new TypeError('Interface needs a type to be indexable'); - } - - let typeName = 'INVALID_TYPE'; - if (typeObject.type instanceof ReferenceType) { - if ( - typeObject.type.reflection instanceof DeclarationReflection && - typeof typeObject.type.reflection.defaultValue === 'string' - ) { - typeName = typeObject.type.reflection.defaultValue.replace('"', '').replace('"', ''); - } else { - // tslint:disable-next-line:no-floating-promises - void console.error( - 'Your input files seem to be incorrect, or there is a major bug in the mapping generator.', - ); - } - } else if (typeObject.type instanceof StringLiteralType) { - console.warn(`The interface ${_interface.name} uses a string literal as type, please use SCThingType.`); - typeName = typeObject.type.value; - } else { - // tslint:disable-next-line:no-floating-promises - void console.error( - `The interface ${_interface.name} is required to use an SCThingType as a type, please do so.`, - ); - } - // init aggregation schema for type - aggregations[typeName] = { - aggs: {}, - filter: { - term: { - type: typeName, - }, - }, - }; - handleDeclarationReflection(_interface, new Map(), '', typeName); - } - - // second traversal - reset(false); - - for (const _interface of indexableInterfaces) { - if (!Array.isArray(_interface.children) || _interface.children.length === 0) { - throw new Error('Interface needs at least some properties to be indexable'); - } - - const typeObject = _interface.children.find(declarationReflection => { - return declarationReflection.name === 'type'; - }); - - if (typeObject === undefined || typeObject.type === undefined) { - throw new TypeError('Interface needs a type to be indexable'); - } - - let typeName = 'INVALID_TYPE'; - if (typeObject.type instanceof ReferenceType) { - if ( - typeObject.type.reflection instanceof DeclarationReflection && - typeof typeObject.type.reflection.defaultValue === 'string' - ) { - typeName = typeObject.type.reflection.defaultValue.replace('"', '').replace('"', ''); - } else { - // tslint:disable-next-line:no-floating-promises - void console.error( - 'Your input files seem to be incorrect, or there is a major bug in the mapping generator.', - ); - } - } else if (typeObject.type instanceof StringLiteralType) { - console.warn(`The interface ${_interface.name} uses a string literal as type, please use SCThingType.`); - typeName = typeObject.type.value; - } else { - // tslint:disable-next-line:no-floating-promises - void console.error( - `The interface ${_interface.name} is required to use an SCThingType as a type, please do so.`, - ); - } - - // filter out - if (interfaceFilter.length > 0 && !interfaceFilter.includes(typeName)) { - continue; - } - - // init aggregation schema for type - aggregations[typeName] = { - aggs: {}, - filter: { - term: { - type: typeName, - }, - }, - }; - - // eslint-disable-next-line unicorn/prefer-string-replace-all - const typeNameWithoutSpaces = typeName.toLowerCase().replace(/\s/g, '_'); - const templateName = `template_${typeNameWithoutSpaces}`; - - out[templateName] = { - mappings: handleDeclarationReflection(_interface, new Map(), '', typeName) as MappingObjectProperty, - settings: settings, - index_patterns: [`stapps_${typeNameWithoutSpaces}*`], - }; - out[templateName].mappings!.properties!.creation_date = { - type: 'date', - }; - - out[templateName].mappings!.dynamic_templates = dynamicTemplates; - - // Set some properties - out[templateName].mappings!._source = { - excludes: ['creation_date'], - }; - out[templateName].mappings!.date_detection = false; - - dynamicTemplates = []; - - if (Object.keys((aggregations[typeName] as ESNestedAggregation).aggs).length === 0) { - delete aggregations[typeName]; - } - } - - return {aggregations, mappings: out, errors}; -} diff --git a/packages/es-mapping-generator/src/project-reflection.ts b/packages/es-mapping-generator/src/project-reflection.ts deleted file mode 100644 index 73496a47..00000000 --- a/packages/es-mapping-generator/src/project-reflection.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2018-2021 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {existsSync, PathLike} from 'fs'; -import {platform} from 'os'; -import path from 'path'; -import {Application, ProjectReflection} from 'typedoc'; - -/** - * Get a project reflection from a path - * @param sourcePath Path to get reflection from - * @param excludeExternals Exclude external dependencies - */ -export function getProjectReflection(sourcePath: PathLike, excludeExternals = true): ProjectReflection { - console.info(`Generating project reflection for ${sourcePath.toString()}.`); - - const tsconfigPath = getTsconfigPath(sourcePath.toString()); - - // initialize new Typedoc application - const app = new Application(); - - app.bootstrap({ - excludeExternals: excludeExternals, - ignoreCompilerErrors: true, - includeDeclarations: true, - tsconfig: path.join(tsconfigPath, 'tsconfig.json'), - }); - - let inputFilePath = sourcePath; - if (inputFilePath === tsconfigPath) { - inputFilePath = path.join(tsconfigPath, 'src'); - } - - // get input files - const inputFiles = app.expandInputFiles([inputFilePath.toString()]); - - // get project reflection from input files - const result = app.convert(inputFiles); - - if (result === undefined) { - throw new TypeError('Project reflection could not be generated.'); - } - - return result; -} - -/** - * Get path that contains a tsconfig.json - * @param startPath Path from where to start searching "upwards" - */ -export function getTsconfigPath(startPath: string): string { - let tsconfigPath = startPath; - - // see https://stackoverflow.com/questions/9652043/identifying-the-file-system-root-with-node-js - const root = platform() === 'win32' ? process.cwd().split(path.sep)[0] : '/'; - - // repeat until a tsconfig.json is found - while (!existsSync(path.join(tsconfigPath, 'tsconfig.json'))) { - if (tsconfigPath === root) { - throw new Error( - `Reached file system root ${root} while searching for 'tsconfig.json' in ${startPath}!`, - ); - } - - // pop last directory - const tsconfigPathParts = tsconfigPath.split(path.sep); - tsconfigPathParts.pop(); - tsconfigPath = tsconfigPathParts.join(path.sep); - } - - console.info(`Using 'tsconfig.json' from ${tsconfigPath}.`); - - return tsconfigPath; -} diff --git a/packages/es-mapping-generator/src/template.ts b/packages/es-mapping-generator/src/template.ts new file mode 100644 index 00000000..5476f382 --- /dev/null +++ b/packages/es-mapping-generator/src/template.ts @@ -0,0 +1,13 @@ +/** + * Render a template + * @param template The template to render (must be stringify-able) + * @param substitutions the substitutions + */ +export function renderTemplate(template: T, substitutions: [string, string][]): T { + return JSON.parse( + substitutions.reduce( + (template, [search, replace]) => template.replaceAll(search, replace), + JSON.stringify(template), + ), + ); +} diff --git a/packages/es-mapping-generator/test/mapping-model/mappings/src/inherited-property.mapping-test.ts b/packages/es-mapping-generator/test/mapping-model/mappings/src/inherited-property.mapping-test.ts index b078d158..cd92eef5 100644 --- a/packages/es-mapping-generator/test/mapping-model/mappings/src/inherited-property.mapping-test.ts +++ b/packages/es-mapping-generator/test/mapping-model/mappings/src/inherited-property.mapping-test.ts @@ -15,25 +15,28 @@ import {ThingType} from './types'; import {MapAggTestOptions} from '../../map-agg-test-options'; +/** @integer */ +export type Integer = number; + /** * @indexable */ export interface InheritedProperty extends Bar { - foo: number; + /** @filterable */ + foo: Integer; - type: ThingType.InheritedProperty; + // type: ThingType.InheritedProperty; } interface Bar { /** * @keyword */ - bar: string; - + //bar: string; /** * @float */ - baz: number; + // baz: number; } export const testConfig: MapAggTestOptions = { diff --git a/packages/es-mapping-generator/tsconfig.json b/packages/es-mapping-generator/tsconfig.json index 03808a28..579a39ff 100644 --- a/packages/es-mapping-generator/tsconfig.json +++ b/packages/es-mapping-generator/tsconfig.json @@ -1,25 +1,3 @@ { - "compilerOptions": { - "alwaysStrict": true, - "charset": "utf8", - "declaration": true, - "esModuleInterop": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "inlineSourceMap": true, - "skipLibCheck": true, - "module": "CommonJS", - "moduleResolution": "Node", - "noErrorTruncation": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitReturns": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "outDir": "./lib/", - "strict": true, - "skipLibCheck": true, - "target": "ES2020" - }, - "exclude": ["./lib/", "./test/"] + "extends": "@openstapps/tsconfig" } diff --git a/packages/es-mapping-generator/tsup.config.ts b/packages/es-mapping-generator/tsup.config.ts new file mode 100644 index 00000000..9744c888 --- /dev/null +++ b/packages/es-mapping-generator/tsup.config.ts @@ -0,0 +1,12 @@ +import {defineConfig} from 'tsup'; +import {jsonSchemaPlugin} from '@openstapps/json-schema-generator'; + +export default defineConfig({ + entry: ['src/index.ts'], + sourcemap: true, + clean: true, + format: 'esm', + outDir: 'lib', + external: ['./index.schema.json'], + plugins: [jsonSchemaPlugin('index.schema.json')], +}); diff --git a/packages/json-schema-generator/package.json b/packages/json-schema-generator/package.json new file mode 100644 index 00000000..b12d3a89 --- /dev/null +++ b/packages/json-schema-generator/package.json @@ -0,0 +1,78 @@ +{ + "name": "@openstapps/json-schema-generator", + "description": "Validator for @openstapps/core", + "version": "3.0.0", + "type": "module", + "license": "GPL-3.0-only", + "repository": "git@gitlab.com:openstapps/openstapps.git", + "author": "Thea Schöbl ", + "keywords": [ + "StApps", + "StAppsCore", + "converter", + "core", + "validator" + ], + "main": "lib/index.js", + "types": "lib/index.d.ts", + "files": [ + "lib", + "README.md", + "CHANGELOG.md" + ], + "scripts": { + "build": "tsup-node --dts", + "docs": "typedoc --json ./docs/docs.json --options ../../typedoc.base.json src/index.ts", + "format": "prettier . -c --ignore-path ../../.gitignore", + "format:fix": "prettier --write . --ignore-path ../../.gitignore", + "lint": "eslint --ext .ts src/", + "lint:fix": "eslint --fix --ext .ts src/", + "test": "c8 mocha" + }, + "dependencies": { + "@openstapps/tsup-plugin": "workspace:*", + "deepmerge": "4.3.1", + "ts-json-schema-generator": "1.4.0" + }, + "devDependencies": { + "@openstapps/eslint-config": "workspace:*", + "@openstapps/prettier-config": "workspace:*", + "@openstapps/tsconfig": "workspace:*", + "@types/chai": "4.3.5", + "@types/fs-extra": "9.0.13", + "@types/glob": "8.0.1", + "@types/json-schema": "7.0.14", + "@types/mocha": "10.0.1", + "@types/mustache": "4.2.2", + "@types/node": "18.15.3", + "c8": "7.14.0", + "chai": "4.3.7", + "esbuild": "0.17.19", + "mocha": "10.2.0", + "mocha-junit-reporter": "2.2.0", + "nock": "13.3.1", + "ts-node": "10.9.1", + "tsup": "6.7.0", + "typedoc": "0.24.8", + "typescript": "5.1.6" + }, + "tsup": { + "entry": [ + "src/app.ts", + "src/index.ts" + ], + "sourcemap": true, + "clean": true, + "format": "esm", + "outDir": "lib" + }, + "prettier": "@openstapps/prettier-config", + "eslintConfig": { + "extends": [ + "@openstapps" + ] + }, + "eslintIgnore": [ + "resources" + ] +} diff --git a/packages/json-schema-generator/src/generator/compile-schema.ts b/packages/json-schema-generator/src/generator/compile-schema.ts new file mode 100644 index 00000000..50d9243b --- /dev/null +++ b/packages/json-schema-generator/src/generator/compile-schema.ts @@ -0,0 +1,27 @@ +import {createGenerator, SchemaGenerator} from 'ts-json-schema-generator'; +import {getValidatableTypes} from './get-validatable-types.js'; + +/** + * Compile the JSON schema for a path + */ +export function compileSchema(path: string, tsconfig: string): ReturnType { + const generator = createGenerator({ + path, + tsconfig, + extraTags: ['elasticsearch'], + skipTypeCheck: true, + }); + // @ts-expect-error private access + const program = generator.program; + const schemaNames = getValidatableTypes(program); + const fullSchema = { + $schema: 'http://json-schema.org/draft-07/schema#', + definitions: {}, + }; + + for (const schema of schemaNames) { + Object.assign(fullSchema.definitions, generator.createSchema(schema).definitions); + } + + return fullSchema; +} diff --git a/packages/json-schema-generator/src/generator/get-validatable-types.ts b/packages/json-schema-generator/src/generator/get-validatable-types.ts new file mode 100644 index 00000000..fbc1fb62 --- /dev/null +++ b/packages/json-schema-generator/src/generator/get-validatable-types.ts @@ -0,0 +1,34 @@ +import {ts} from 'ts-json-schema-generator'; + +/** + * Get all types with `@validatable` annotations + */ +export function getValidatableTypes(program: ts.Program) { + const checker = program.getTypeChecker(); + const declarationNames: string[] = []; + + for (const sourceFile of program.getSourceFiles()) { + const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile); + if (!sourceFileSymbol) continue; + for (const exportSymbol of checker.getExportsOfModule(sourceFileSymbol)) { + for (const declaration of exportSymbol.getDeclarations() ?? []) { + const validatableTags = ts.getAllJSDocTags(declaration, isValidatableJSDocTag); + const name = ts.getNameOfDeclaration(declaration); + + if (name && validatableTags.length > 0) { + declarationNames.push(name.getText()); + } + } + } + } + + return declarationNames; +} + +/** + * Type predicate for if a JSDoc tag is `@validatable` + */ +// eslint-disable-next-line unicorn/prevent-abbreviations +function isValidatableJSDocTag(tag: ts.JSDocTag): tag is ts.JSDocTag { + return tag.tagName.escapedText === 'validatable'; +} diff --git a/packages/json-schema-generator/src/index.ts b/packages/json-schema-generator/src/index.ts new file mode 100644 index 00000000..72ebba30 --- /dev/null +++ b/packages/json-schema-generator/src/index.ts @@ -0,0 +1,37 @@ +import {compileSchema} from './generator/compile-schema.js'; +import {generateFiles, Plugin, PluginContext} from '@openstapps/tsup-plugin'; + +export type SchemaConsumer = ( + this: PluginContext, + schema: ReturnType, +) => Record; + +/** + * TSUp plugin for generating JSONSchema files + * @param schemaName the name of the generated schema + * @param schemaConsumers any consumers that can directly use the schema + */ +export function jsonSchemaPlugin( + schemaName: string, + ...schemaConsumers: Array<[string, SchemaConsumer]> +): Plugin { + return { + name: 'json-schema-generator', + async buildEnd() { + let schema: ReturnType; + await generateFiles('JSON-Schema', async function () { + schema = compileSchema((this.options.entry as string[])[0], this.options.tsconfig!); + + return { + [schemaName]: JSON.stringify(schema), + }; + }).call(this); + + for (const [name, consumer] of schemaConsumers) { + await generateFiles(name, async function () { + return consumer.call(this, schema); + }).call(this); + } + }, + }; +} diff --git a/packages/json-schema-generator/tsconfig.json b/packages/json-schema-generator/tsconfig.json new file mode 100644 index 00000000..579a39ff --- /dev/null +++ b/packages/json-schema-generator/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@openstapps/tsconfig" +} diff --git a/packages/openapi-generator/package.json b/packages/openapi-generator/package.json new file mode 100644 index 00000000..75d7ff52 --- /dev/null +++ b/packages/openapi-generator/package.json @@ -0,0 +1,77 @@ +{ + "name": "@openstapps/openapi-generator", + "description": "Validator for @openstapps/core", + "version": "3.0.0", + "type": "module", + "license": "GPL-3.0-only", + "repository": "git@gitlab.com:openstapps/openstapps.git", + "author": "Thea Schöbl ", + "keywords": [ + "StApps", + "StAppsCore", + "converter", + "core", + "validator" + ], + "main": "lib/index.js", + "types": "lib/index.d.ts", + "files": [ + "lib", + "README.md", + "CHANGELOG.md" + ], + "scripts": { + "build": "tsup-node --dts", + "docs": "typedoc --json ./docs/docs.json --options ../../typedoc.base.json src/generator/index.ts", + "format": "prettier . -c --ignore-path ../../.gitignore", + "format:fix": "prettier --write . --ignore-path ../../.gitignore", + "lint": "eslint --ext .ts src/", + "lint:fix": "eslint --fix --ext .ts src/", + "test": "c8 mocha" + }, + "dependencies": { + "@openstapps/tsup-plugin": "workspace:*", + "openapi-types": "12.1.3" + }, + "devDependencies": { + "@openstapps/eslint-config": "workspace:*", + "@openstapps/prettier-config": "workspace:*", + "@openstapps/tsconfig": "workspace:*", + "@types/chai": "4.3.5", + "@types/fs-extra": "9.0.13", + "@types/glob": "8.0.1", + "@types/json-schema": "7.0.14", + "@types/mocha": "10.0.1", + "@types/mustache": "4.2.2", + "@types/node": "18.15.3", + "c8": "7.14.0", + "chai": "4.3.7", + "esbuild": "0.17.19", + "mocha": "10.2.0", + "mocha-junit-reporter": "2.2.0", + "nock": "13.3.1", + "ts-node": "10.9.1", + "tsup": "6.7.0", + "typedoc": "0.24.8", + "typescript": "5.1.6" + }, + "tsup": { + "entry": [ + "src/app.ts", + "src/index.ts" + ], + "sourcemap": true, + "clean": true, + "format": "esm", + "outDir": "lib" + }, + "prettier": "@openstapps/prettier-config", + "eslintConfig": { + "extends": [ + "@openstapps" + ] + }, + "eslintIgnore": [ + "resources" + ] +} diff --git a/packages/openapi-generator/src/generator/index.ts b/packages/openapi-generator/src/generator/index.ts new file mode 100644 index 00000000..60661317 --- /dev/null +++ b/packages/openapi-generator/src/generator/index.ts @@ -0,0 +1,49 @@ +import {getRoutes} from './routes.js'; +import {openapi3Template} from './resources/template.js'; +import {capitalize, generateOpenAPIForRoute} from './openapi.js'; +import ts from 'typescript'; + +/** + * Generate OpenAPI definitions + */ +export async function generateOpenAPI( + schemaName: string, + program: ts.Program, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + instances: Record, +) { + const routes = await getRoutes(program, instances); + routes.sort((a, b) => a.route.instance.urlPath.localeCompare(b.route.instance.urlPath)); + + // change url path parameters to openapi notation + for (const routeWithMetaInformation of routes) { + routeWithMetaInformation.route.instance.urlPath = + routeWithMetaInformation.route.instance.urlPath.replaceAll( + /:\w+/g, + (match: string) => `{${match.replace(':', '')}}`, + ); + } + + // keep openapi tags for routes that actually share url fragments + let tagsToKeep = routes.map(routeWithMetaInformation => + capitalize(routeWithMetaInformation.route.instance.urlPath.split('/')[1]), + ); + tagsToKeep = tagsToKeep.filter( + (element, i, array) => array.indexOf(element) === i && array.lastIndexOf(element) !== i, + ); + + const output = openapi3Template; + for (const routeWithMetaInformation of routes) { + routeWithMetaInformation.tags = [ + capitalize(routeWithMetaInformation.route.instance.urlPath.split('/')[1]), + ]; + + output.paths[routeWithMetaInformation.route.instance.urlPath] = generateOpenAPIForRoute( + routeWithMetaInformation, + schemaName, + tagsToKeep, + ); + } + + return output; +} diff --git a/packages/openapi-generator/src/generator/openapi.ts b/packages/openapi-generator/src/generator/openapi.ts new file mode 100644 index 00000000..4cf32c1f --- /dev/null +++ b/packages/openapi-generator/src/generator/openapi.ts @@ -0,0 +1,91 @@ +import {RouteMeta} from './types/route-meta.js'; +import {OpenAPIV3} from 'openapi-types'; + +/** + * Creates sentence cased string + */ +export function capitalize(string?: string): string { + return `${string?.charAt(0).toUpperCase()}${string?.slice(1).toLowerCase()}`; +} + +/** + * Generate documentation snippet for one route + * @param routeMeta A route instance with its meta information + * @param schemaName Path to directory that will contain relevant schemas for the route + * @param tagsToKeep Tags / keywords that can be used for grouping routes + */ +export function generateOpenAPIForRoute( + routeMeta: RouteMeta, + schemaName: string, + tagsToKeep: string[], +): OpenAPIV3.PathItemObject { + const route = routeMeta.route; + const openapiPath: OpenAPIV3.PathItemObject = {}; + const schema = (name: string) => ({$ref: `./${schemaName}#/definitions/${name}`}); + + openapiPath[route.instance.method.toLowerCase() as OpenAPIV3.HttpMethods] = { + summary: capitalize(routeMeta.description?.replace(/(Route to |Route for )/gim, '')), + requestBody: { + description: route.responseBodyDescription ?? undefined, + content: { + 'application/json': { + schema: schema(route.instance.requestBodyName), + }, + }, + }, + parameters: [ + { + name: 'X-StApps-Version', + in: 'header', + schema: { + type: 'string', + example: '2.0.0', + }, + required: true, + }, + ], + responses: {}, + tags: routeMeta.tags?.filter(value => tagsToKeep.includes(value)), + }; + + openapiPath[route.instance.method.toLowerCase() as OpenAPIV3.HttpMethods]!.responses![ + route.instance.statusCodeSuccess + ] = { + description: route.responseBodyDescription, + content: { + 'application/json': { + schema: schema(route.instance.responseBodyName), + }, + }, + }; + + for (const RouteError of route.instance.errorNames) { + const error = new RouteError(); + openapiPath[route.instance.method.toLowerCase() as OpenAPIV3.HttpMethods]!.responses![error.statusCode] = + { + description: + error.message ?? capitalize(error.name.replaceAll(/([A-Z][a-z])/g, ' $1').replace('SC ', '')), + content: { + 'application/json': { + schema: schema(RouteError.name), + }, + }, + }; + } + + if (typeof route.instance.obligatoryParameters === 'object') { + for (const [parameter, schemaDefinition] of Object.entries(route.instance.obligatoryParameters)) { + const openapiParameter: OpenAPIV3.ParameterObject = { + in: 'path', + name: parameter, + required: true, + schema: schema(schemaDefinition), + }; + openapiPath[route.instance.method.toLowerCase() as OpenAPIV3.HttpMethods]?.parameters?.push( + openapiParameter, + ); + } + } + + return openapiPath; +} diff --git a/packages/core-tools/src/resources/openapi-303-template.ts b/packages/openapi-generator/src/generator/resources/template.ts similarity index 100% rename from packages/core-tools/src/resources/openapi-303-template.ts rename to packages/openapi-generator/src/generator/resources/template.ts diff --git a/packages/openapi-generator/src/generator/routes.ts b/packages/openapi-generator/src/generator/routes.ts new file mode 100644 index 00000000..0bfd32c4 --- /dev/null +++ b/packages/openapi-generator/src/generator/routes.ts @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018-2023 StApps + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +import {RouteMeta} from './types/route-meta.js'; +import ts from 'typescript'; +import {SCAbstractRoute} from '../../../core/lib/index.js'; + +/** + * Get all routes + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export async function getRoutes(program: ts.Program, instances: Record) { + const checker = program.getTypeChecker(); + const routes: RouteMeta[] = []; + const interfaces = new Map(); + const routeClasses: ts.ClassDeclaration[] = []; + + for (const sourceFile of program.getSourceFiles()) { + const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile); + if (!sourceFileSymbol) continue; + for (const exportSymbol of checker.getExportsOfModule(sourceFileSymbol)) { + for (const declaration of exportSymbol.getDeclarations() ?? []) { + if (ts.isClassDeclaration(declaration) && extendsAbstractRoute(declaration)) { + routeClasses.push(declaration); + } else if (ts.isInterfaceDeclaration(declaration)) { + interfaces.set(ts.getNameOfDeclaration(declaration)!.getText(), declaration); + } + } + } + } + + for (const route of routeClasses) { + const name = ts.getNameOfDeclaration(route)!.getText(); + const instance: SCAbstractRoute = new instances[name](); + routes.push({ + name, + description: getDescription(route), + route: { + instance, + requestBodyDescription: getDescription(interfaces.get(instance.requestBodyName)!), + responseBodyDescription: getDescription(interfaces.get(instance.responseBodyName)!), + }, + }); + } + + return routes; +} + +/** + * If a declaration extends `SCAbstractRoute` + */ +function extendsAbstractRoute(declaration: ts.ClassDeclaration): boolean { + return ( + declaration.heritageClauses?.some(clause => + clause.types.some(it => it.getText() === 'SCAbstractRoute'), + ) === true + ); +} + +/** + * Gets the description of a declaration + */ +function getDescription(declaration: ts.Declaration) { + return ts + .getJSDocCommentsAndTags(declaration) + .filter(ts.isJSDoc) + .map(it => ts.getTextOfJSDocComment(it.comment)) + .join(''); +} diff --git a/packages/es-mapping-generator/src/config/settings.ts b/packages/openapi-generator/src/generator/types/abstract-route.ts similarity index 65% rename from packages/es-mapping-generator/src/config/settings.ts rename to packages/openapi-generator/src/generator/types/abstract-route.ts index 24ec9660..b70444ad 100644 --- a/packages/es-mapping-generator/src/config/settings.ts +++ b/packages/openapi-generator/src/generator/types/abstract-route.ts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 StApps + * Copyright (C) 2018-2023 StApps * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 3. @@ -12,11 +12,6 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import {IndicesPutTemplateRequest} from '@elastic/elasticsearch/lib/api/types'; - -export const settings: IndicesPutTemplateRequest['settings'] = { - 'mapping.total_fields.limit': 10_000, - 'max_result_window': 30_000, - 'number_of_replicas': 0, - 'number_of_shards': 1, -}; +// sneaky import here +// noinspection ES6PreferShortImport +export type {SCAbstractRoute} from '../../../../core/src/protocol/route.js'; diff --git a/packages/openapi-generator/src/generator/types/route-meta.ts b/packages/openapi-generator/src/generator/types/route-meta.ts new file mode 100644 index 00000000..26e3d8aa --- /dev/null +++ b/packages/openapi-generator/src/generator/types/route-meta.ts @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018-2023 StApps + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +import {SCAbstractRoute} from '../../../../core/src/index.js'; + +export interface RouteInstanceMeta { + instance: SCAbstractRoute; + requestBodyDescription: string; + responseBodyDescription: string; +} + +export interface RouteMeta { + name: string; + description?: string; + route: RouteInstanceMeta; + tags?: string[]; +} diff --git a/packages/openapi-generator/src/index.ts b/packages/openapi-generator/src/index.ts new file mode 100644 index 00000000..fb671db8 --- /dev/null +++ b/packages/openapi-generator/src/index.ts @@ -0,0 +1,42 @@ +import {generateOpenAPI} from './generator/index.js'; +import path from 'path'; +import {generateFiles, Plugin} from '@openstapps/tsup-plugin'; +import ts from 'typescript'; +import {readFile} from 'fs/promises'; + +/** + * TSUp plugin for generating OpenAPI files + * @param filename the name of the generated OpenAPI definitions + * @param schemaName the name of the generated JSON Schema for reference in the OpenAPI file + */ +export function openapiPlugin(filename: string, schemaName: string): Plugin { + return { + name: 'openapi-generator', + async buildEnd({writtenFiles}) { + await generateFiles('OpenAPI', async function () { + const rootNames = this.options.entry as string[]; + const projectDirectory = path.dirname(this.options.tsconfig!); + const generatedFile = writtenFiles.find(it => it.name.endsWith('.js'))!; + const instances = await import(`${projectDirectory}/${generatedFile.name}`); + const tsconfig = ts.parseJsonConfigFileContent( + await readFile(this.options.tsconfig!, 'utf8').then(it => JSON.parse(it)), + ts.sys, + projectDirectory, + ); + const program = ts.createProgram({ + options: tsconfig.options, + rootNames: rootNames.map(it => `${projectDirectory}/${it}`), + }); + + const file = await generateOpenAPI(schemaName, program, instances); + if (file.paths['/search'] === undefined) { + this.logger.log('OpenAPI', 'error', 'OpenAPI /search route missing, this is likely an error'); + throw new Error('Missing /search route'); + } + return { + [filename]: JSON.stringify(file), + }; + }).call(this); + }, + }; +} diff --git a/packages/openapi-generator/tsconfig.json b/packages/openapi-generator/tsconfig.json new file mode 100644 index 00000000..579a39ff --- /dev/null +++ b/packages/openapi-generator/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@openstapps/tsconfig" +} diff --git a/packages/tsup-plugin/package.json b/packages/tsup-plugin/package.json new file mode 100644 index 00000000..657c1b38 --- /dev/null +++ b/packages/tsup-plugin/package.json @@ -0,0 +1,76 @@ +{ + "name": "@openstapps/tsup-plugin", + "description": "Validator for @openstapps/core", + "version": "3.0.0", + "type": "module", + "license": "GPL-3.0-only", + "repository": "git@gitlab.com:openstapps/openstapps.git", + "author": "Thea Schöbl ", + "keywords": [ + "StApps", + "StAppsCore", + "converter", + "core", + "validator" + ], + "main": "lib/index.js", + "types": "lib/index.d.ts", + "files": [ + "lib", + "README.md", + "CHANGELOG.md" + ], + "scripts": { + "build": "tsup-node --dts", + "docs": "typedoc --json ./docs/docs.json --options ../../typedoc.base.json src/index.ts", + "format": "prettier . -c --ignore-path ../../.gitignore", + "format:fix": "prettier --write . --ignore-path ../../.gitignore", + "lint": "eslint --ext .ts src/", + "lint:fix": "eslint --fix --ext .ts src/", + "test": "c8 mocha" + }, + "dependencies": { + "colorette": "2.0.20" + }, + "devDependencies": { + "@openstapps/eslint-config": "workspace:*", + "@openstapps/prettier-config": "workspace:*", + "@openstapps/tsconfig": "workspace:*", + "@types/chai": "4.3.5", + "@types/fs-extra": "9.0.13", + "@types/glob": "8.0.1", + "@types/json-schema": "7.0.14", + "@types/mocha": "10.0.1", + "@types/mustache": "4.2.2", + "@types/node": "18.15.3", + "c8": "7.14.0", + "chai": "4.3.7", + "esbuild": "0.17.19", + "mocha": "10.2.0", + "mocha-junit-reporter": "2.2.0", + "nock": "13.3.1", + "ts-node": "10.9.1", + "tsup": "6.7.0", + "typedoc": "0.24.8", + "typescript": "5.1.6" + }, + "tsup": { + "entry": [ + "src/app.ts", + "src/index.ts" + ], + "sourcemap": true, + "clean": true, + "format": "esm", + "outDir": "lib" + }, + "prettier": "@openstapps/prettier-config", + "eslintConfig": { + "extends": [ + "@openstapps" + ] + }, + "eslintIgnore": [ + "resources" + ] +} diff --git a/packages/tsup-plugin/src/index.ts b/packages/tsup-plugin/src/index.ts new file mode 100644 index 00000000..340e2602 --- /dev/null +++ b/packages/tsup-plugin/src/index.ts @@ -0,0 +1,31 @@ +import {Options} from 'tsup'; +import {writeFile, stat} from 'fs/promises'; +import {bold, green} from 'colorette'; + +type ArrayElement = ArrayType extends readonly (infer ElementType)[] + ? ElementType + : never; + +export type Plugin = ArrayElement['plugins']>; +export type PluginContext = ThisParameterType['buildEnd']>; + +/** + * Utility function for generating files in a TSUp plugin + */ +export function generateFiles( + label: string, + build: (this: PluginContext) => Promise>, +) { + return async function (this: PluginContext) { + this.logger.info(label, 'Build start'); + const time = performance.now(); + const result = await build.call(this); + this.logger.success(label, `⚡️ Build success in ${Math.floor(performance.now() - time)}ms`); + for (const file in result) { + const filePath = `${this.options.outDir}/${file}`; + await writeFile(filePath, result[file]); + const info = await stat(filePath); + this.logger.success(label, bold(filePath), green(`${(info.size / 1000).toFixed(2)} KB`)); + } + }; +} diff --git a/packages/tsup-plugin/tsconfig.json b/packages/tsup-plugin/tsconfig.json new file mode 100644 index 00000000..579a39ff --- /dev/null +++ b/packages/tsup-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@openstapps/tsconfig" +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f8218f9..6ed535cd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +patchedDependencies: + '@elastic/elasticsearch@8.10.0': + hash: cbqivwahgcyqqvtkergczzr7wq + path: patches/@elastic__elasticsearch@8.10.0.patch + importers: .: @@ -48,8 +53,8 @@ importers: backend/backend: dependencies: '@elastic/elasticsearch': - specifier: 8.4.0 - version: 8.4.0 + specifier: 8.10.0 + version: 8.10.0(patch_hash=cbqivwahgcyqqvtkergczzr7wq) '@openstapps/core': specifier: workspace:* version: link:../../packages/core @@ -86,6 +91,12 @@ importers: '@types/uuid': specifier: 8.3.4 version: 8.3.4 + ajv: + specifier: 8.12.0 + version: 8.12.0 + ajv-formats: + specifier: 2.1.1 + version: 2.1.1(ajv@8.12.0) body-parser: specifier: 1.20.2 version: 1.20.2 @@ -1240,8 +1251,8 @@ importers: specifier: 9.0.13 version: 9.0.13 '@types/json-schema': - specifier: 7.0.11 - version: 7.0.11 + specifier: 7.0.14 + version: 7.0.14 '@types/junit-report-builder': specifier: 3.0.0 version: 3.0.0 @@ -1340,8 +1351,8 @@ importers: specifier: 4.17.17 version: 4.17.17 '@types/json-schema': - specifier: 7.0.11 - version: 7.0.11 + specifier: 7.0.14 + version: 7.0.14 '@types/morgan': specifier: 1.9.4 version: 1.9.4 @@ -1542,9 +1553,15 @@ importers: '@openstapps/eslint-config': specifier: workspace:* version: link:../../configuration/eslint-config + '@openstapps/json-schema-generator': + specifier: workspace:* + version: link:../json-schema-generator '@openstapps/logger': specifier: workspace:* version: link:../logger + '@openstapps/openapi-generator': + specifier: workspace:* + version: link:../openapi-generator '@openstapps/prettier-config': specifier: workspace:* version: link:../../configuration/prettier-config @@ -1558,8 +1575,8 @@ importers: specifier: 0.0.30 version: 0.0.30 '@types/json-schema': - specifier: 7.0.11 - version: 7.0.11 + specifier: 7.0.14 + version: 7.0.14 '@types/mocha': specifier: 10.0.1 version: 10.0.1 @@ -1638,6 +1655,9 @@ importers: ajv: specifier: 8.12.0 version: 8.12.0 + ajv-formats: + specifier: 2.1.1 + version: 2.1.1(ajv@8.12.0) better-ajv-errors: specifier: 1.2.0 version: 1.2.0(ajv@8.12.0) @@ -1672,20 +1692,17 @@ importers: specifier: 4.2.0 version: 4.2.0 openapi-types: - specifier: 12.1.0 - version: 12.1.0 + specifier: 12.1.3 + version: 12.1.3 plantuml-encoder: specifier: 1.4.0 version: 1.4.0 - re2: - specifier: 1.18.2 - version: 1.18.2 toposort: specifier: 2.0.2 version: 2.0.2 ts-json-schema-generator: - specifier: 1.2.0 - version: 1.2.0 + specifier: 1.4.0 + version: 1.4.0 devDependencies: '@openstapps/eslint-config': specifier: workspace:* @@ -1706,8 +1723,105 @@ importers: specifier: 8.0.1 version: 8.0.1 '@types/json-schema': - specifier: 7.0.11 - version: 7.0.11 + specifier: 7.0.14 + version: 7.0.14 + '@types/mocha': + specifier: 10.0.1 + version: 10.0.1 + '@types/mustache': + specifier: 4.2.2 + version: 4.2.2 + '@types/node': + specifier: 18.15.3 + version: 18.15.3 + '@typescript-eslint/eslint-plugin': + specifier: 5.60.1 + version: 5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6) + '@typescript-eslint/parser': + specifier: 5.60.1 + version: 5.60.1(eslint@8.43.0)(typescript@5.1.6) + c8: + specifier: 7.14.0 + version: 7.14.0 + chai: + specifier: 4.3.7 + version: 4.3.7 + eslint: + specifier: 8.43.0 + version: 8.43.0 + eslint-config-prettier: + specifier: 8.8.0 + version: 8.8.0(eslint@8.43.0) + eslint-plugin-jsdoc: + specifier: 46.4.2 + version: 46.4.2(eslint@8.43.0) + eslint-plugin-prettier: + specifier: 4.2.1 + version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.43.0)(prettier@2.8.6) + eslint-plugin-unicorn: + specifier: 47.0.0 + version: 47.0.0(eslint@8.43.0) + mocha: + specifier: 10.2.0 + version: 10.2.0 + mocha-junit-reporter: + specifier: 2.2.0 + version: 2.2.0(mocha@10.2.0) + nock: + specifier: 13.3.1 + version: 13.3.1 + prettier: + specifier: 2.8.6 + version: 2.8.6 + ts-node: + specifier: 10.9.1 + version: 10.9.1(@types/node@18.15.3)(typescript@5.1.6) + tsup: + specifier: 6.7.0 + version: 6.7.0(ts-node@10.9.1)(typescript@5.1.6) + typedoc: + specifier: 0.24.8 + version: 0.24.8(typescript@5.1.6) + typescript: + specifier: 5.1.6 + version: 5.1.6 + + packages/core-validator: + dependencies: + '@openstapps/core': + specifier: workspace:* + version: link:../core + ajv: + specifier: 8.12.0 + version: 8.12.0 + ajv-formats: + specifier: 2.1.1 + version: 2.1.1(ajv@8.12.0) + devDependencies: + '@openstapps/core-tools': + specifier: workspace:* + version: link:../core-tools + '@openstapps/eslint-config': + specifier: workspace:* + version: link:../../configuration/eslint-config + '@openstapps/prettier-config': + specifier: workspace:* + version: link:../../configuration/prettier-config + '@openstapps/tsconfig': + specifier: workspace:* + version: link:../../configuration/tsconfig + '@types/chai': + specifier: 4.3.5 + version: 4.3.5 + '@types/fs-extra': + specifier: 9.0.13 + version: 9.0.13 + '@types/glob': + specifier: 8.0.1 + version: 8.0.1 + '@types/json-schema': + specifier: 7.0.14 + version: 7.0.14 '@types/mocha': specifier: 10.0.1 version: 10.0.1 @@ -1851,23 +1965,23 @@ importers: packages/es-mapping-generator: dependencies: '@elastic/elasticsearch': - specifier: 8.4.0 - version: 8.4.0 - commander: - specifier: 10.0.0 - version: 10.0.0 - deepmerge: - specifier: 4.3.1 - version: 4.3.1 - flatted: - specifier: 3.2.7 - version: 3.2.7 - typedoc: - specifier: 0.18.0 - version: 0.18.0(typescript@3.8.3) - typescript: - specifier: 3.8.3 - version: 3.8.3 + specifier: 8.10.0 + version: 8.10.0(patch_hash=cbqivwahgcyqqvtkergczzr7wq) + '@openstapps/json-schema-generator': + specifier: workspace:* + version: link:../json-schema-generator + '@openstapps/tsup-plugin': + specifier: workspace:* + version: link:../tsup-plugin + '@types/json-schema': + specifier: 7.0.14 + version: 7.0.14 + ajv: + specifier: 8.12.0 + version: 8.12.0 + better-ajv-errors: + specifier: 1.2.0 + version: 1.2.0(ajv@8.12.0) devDependencies: '@openstapps/eslint-config': specifier: workspace:* @@ -1875,33 +1989,42 @@ importers: '@openstapps/prettier-config': specifier: workspace:* version: link:../../configuration/prettier-config - '@testdeck/mocha': - specifier: 0.3.3 - version: 0.3.3 + '@openstapps/tsconfig': + specifier: workspace:* + version: link:../../configuration/tsconfig '@types/chai': specifier: 4.3.5 version: 4.3.5 + '@types/fs-extra': + specifier: 9.0.13 + version: 9.0.13 + '@types/glob': + specifier: 8.0.1 + version: 8.0.1 '@types/mocha': specifier: 10.0.1 version: 10.0.1 + '@types/mustache': + specifier: 4.2.2 + version: 4.2.2 '@types/node': - specifier: 14.18.38 - version: 14.18.38 - '@types/rimraf': - specifier: 3.0.2 - version: 3.0.2 + specifier: 18.15.3 + version: 18.15.3 '@typescript-eslint/eslint-plugin': specifier: 5.60.1 - version: 5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@3.8.3) + version: 5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6) '@typescript-eslint/parser': specifier: 5.60.1 - version: 5.60.1(eslint@8.43.0)(typescript@3.8.3) + version: 5.60.1(eslint@8.43.0)(typescript@5.1.6) c8: specifier: 7.14.0 version: 7.14.0 chai: specifier: 4.3.7 version: 4.3.7 + esbuild: + specifier: 0.17.19 + version: 0.17.19 eslint: specifier: 8.43.0 version: 8.43.0 @@ -1929,12 +2052,18 @@ importers: prettier: specifier: 2.8.6 version: 2.8.6 - rimraf: - specifier: 5.0.0 - version: 5.0.0 ts-node: specifier: 10.9.1 - version: 10.9.1(@types/node@14.18.38)(typescript@3.8.3) + version: 10.9.1(@types/node@18.15.3)(typescript@5.1.6) + tsup: + specifier: 6.7.0 + version: 6.7.0(ts-node@10.9.1)(typescript@5.1.6) + typedoc: + specifier: 0.24.8 + version: 0.24.8(typescript@5.1.6) + typescript: + specifier: 5.1.6 + version: 5.1.6 packages/gitlab-api: dependencies: @@ -1997,6 +2126,103 @@ importers: specifier: 5.1.6 version: 5.1.6 + packages/json-schema-generator: + dependencies: + '@openstapps/tsup-plugin': + specifier: workspace:* + version: link:../tsup-plugin + deepmerge: + specifier: 4.3.1 + version: 4.3.1 + ts-json-schema-generator: + specifier: 1.4.0 + version: 1.4.0 + devDependencies: + '@openstapps/eslint-config': + specifier: workspace:* + version: link:../../configuration/eslint-config + '@openstapps/prettier-config': + specifier: workspace:* + version: link:../../configuration/prettier-config + '@openstapps/tsconfig': + specifier: workspace:* + version: link:../../configuration/tsconfig + '@types/chai': + specifier: 4.3.5 + version: 4.3.5 + '@types/fs-extra': + specifier: 9.0.13 + version: 9.0.13 + '@types/glob': + specifier: 8.0.1 + version: 8.0.1 + '@types/json-schema': + specifier: 7.0.14 + version: 7.0.14 + '@types/mocha': + specifier: 10.0.1 + version: 10.0.1 + '@types/mustache': + specifier: 4.2.2 + version: 4.2.2 + '@types/node': + specifier: 18.15.3 + version: 18.15.3 + '@typescript-eslint/eslint-plugin': + specifier: 5.60.1 + version: 5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6) + '@typescript-eslint/parser': + specifier: 5.60.1 + version: 5.60.1(eslint@8.43.0)(typescript@5.1.6) + c8: + specifier: 7.14.0 + version: 7.14.0 + chai: + specifier: 4.3.7 + version: 4.3.7 + esbuild: + specifier: 0.17.19 + version: 0.17.19 + eslint: + specifier: 8.43.0 + version: 8.43.0 + eslint-config-prettier: + specifier: 8.8.0 + version: 8.8.0(eslint@8.43.0) + eslint-plugin-jsdoc: + specifier: 46.4.2 + version: 46.4.2(eslint@8.43.0) + eslint-plugin-prettier: + specifier: 4.2.1 + version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.43.0)(prettier@2.8.6) + eslint-plugin-unicorn: + specifier: 47.0.0 + version: 47.0.0(eslint@8.43.0) + mocha: + specifier: 10.2.0 + version: 10.2.0 + mocha-junit-reporter: + specifier: 2.2.0 + version: 2.2.0(mocha@10.2.0) + nock: + specifier: 13.3.1 + version: 13.3.1 + prettier: + specifier: 2.8.6 + version: 2.8.6 + ts-node: + specifier: 10.9.1 + version: 10.9.1(@types/node@18.15.3)(typescript@5.1.6) + tsup: + specifier: 6.7.0 + version: 6.7.0(ts-node@10.9.1)(typescript@5.1.6) + typedoc: + specifier: 0.24.8 + version: 0.24.8(typescript@5.1.6) + typescript: + specifier: 5.1.6 + version: 5.1.6 + packages/logger: dependencies: '@types/nodemailer': @@ -2091,6 +2317,191 @@ importers: specifier: 5.1.6 version: 5.1.6 + packages/openapi-generator: + dependencies: + '@openstapps/tsup-plugin': + specifier: workspace:* + version: link:../tsup-plugin + openapi-types: + specifier: 12.1.3 + version: 12.1.3 + devDependencies: + '@openstapps/eslint-config': + specifier: workspace:* + version: link:../../configuration/eslint-config + '@openstapps/prettier-config': + specifier: workspace:* + version: link:../../configuration/prettier-config + '@openstapps/tsconfig': + specifier: workspace:* + version: link:../../configuration/tsconfig + '@types/chai': + specifier: 4.3.5 + version: 4.3.5 + '@types/fs-extra': + specifier: 9.0.13 + version: 9.0.13 + '@types/glob': + specifier: 8.0.1 + version: 8.0.1 + '@types/json-schema': + specifier: 7.0.14 + version: 7.0.14 + '@types/mocha': + specifier: 10.0.1 + version: 10.0.1 + '@types/mustache': + specifier: 4.2.2 + version: 4.2.2 + '@types/node': + specifier: 18.15.3 + version: 18.15.3 + '@typescript-eslint/eslint-plugin': + specifier: 5.60.1 + version: 5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6) + '@typescript-eslint/parser': + specifier: 5.60.1 + version: 5.60.1(eslint@8.43.0)(typescript@5.1.6) + c8: + specifier: 7.14.0 + version: 7.14.0 + chai: + specifier: 4.3.7 + version: 4.3.7 + esbuild: + specifier: 0.17.19 + version: 0.17.19 + eslint: + specifier: 8.43.0 + version: 8.43.0 + eslint-config-prettier: + specifier: 8.8.0 + version: 8.8.0(eslint@8.43.0) + eslint-plugin-jsdoc: + specifier: 46.4.2 + version: 46.4.2(eslint@8.43.0) + eslint-plugin-prettier: + specifier: 4.2.1 + version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.43.0)(prettier@2.8.6) + eslint-plugin-unicorn: + specifier: 47.0.0 + version: 47.0.0(eslint@8.43.0) + mocha: + specifier: 10.2.0 + version: 10.2.0 + mocha-junit-reporter: + specifier: 2.2.0 + version: 2.2.0(mocha@10.2.0) + nock: + specifier: 13.3.1 + version: 13.3.1 + prettier: + specifier: 2.8.6 + version: 2.8.6 + ts-node: + specifier: 10.9.1 + version: 10.9.1(@types/node@18.15.3)(typescript@5.1.6) + tsup: + specifier: 6.7.0 + version: 6.7.0(ts-node@10.9.1)(typescript@5.1.6) + typedoc: + specifier: 0.24.8 + version: 0.24.8(typescript@5.1.6) + typescript: + specifier: 5.1.6 + version: 5.1.6 + + packages/tsup-plugin: + dependencies: + colorette: + specifier: 2.0.20 + version: 2.0.20 + devDependencies: + '@openstapps/eslint-config': + specifier: workspace:* + version: link:../../configuration/eslint-config + '@openstapps/prettier-config': + specifier: workspace:* + version: link:../../configuration/prettier-config + '@openstapps/tsconfig': + specifier: workspace:* + version: link:../../configuration/tsconfig + '@types/chai': + specifier: 4.3.5 + version: 4.3.5 + '@types/fs-extra': + specifier: 9.0.13 + version: 9.0.13 + '@types/glob': + specifier: 8.0.1 + version: 8.0.1 + '@types/json-schema': + specifier: 7.0.14 + version: 7.0.14 + '@types/mocha': + specifier: 10.0.1 + version: 10.0.1 + '@types/mustache': + specifier: 4.2.2 + version: 4.2.2 + '@types/node': + specifier: 18.15.3 + version: 18.15.3 + '@typescript-eslint/eslint-plugin': + specifier: 5.60.1 + version: 5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6) + '@typescript-eslint/parser': + specifier: 5.60.1 + version: 5.60.1(eslint@8.43.0)(typescript@5.1.6) + c8: + specifier: 7.14.0 + version: 7.14.0 + chai: + specifier: 4.3.7 + version: 4.3.7 + esbuild: + specifier: 0.17.19 + version: 0.17.19 + eslint: + specifier: 8.43.0 + version: 8.43.0 + eslint-config-prettier: + specifier: 8.8.0 + version: 8.8.0(eslint@8.43.0) + eslint-plugin-jsdoc: + specifier: 46.4.2 + version: 46.4.2(eslint@8.43.0) + eslint-plugin-prettier: + specifier: 4.2.1 + version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.43.0)(prettier@2.8.6) + eslint-plugin-unicorn: + specifier: 47.0.0 + version: 47.0.0(eslint@8.43.0) + mocha: + specifier: 10.2.0 + version: 10.2.0 + mocha-junit-reporter: + specifier: 2.2.0 + version: 2.2.0(mocha@10.2.0) + nock: + specifier: 13.3.1 + version: 13.3.1 + prettier: + specifier: 2.8.6 + version: 2.8.6 + ts-node: + specifier: 10.9.1 + version: 10.9.1(@types/node@18.15.3)(typescript@5.1.6) + tsup: + specifier: 6.7.0 + version: 6.7.0(ts-node@10.9.1)(typescript@5.1.6) + typedoc: + specifier: 0.24.8 + version: 0.24.8(typescript@5.1.6) + typescript: + specifier: 5.1.6 + version: 5.1.6 + packages: /@aashutoshrathi/word-wrap@1.2.6: @@ -2665,7 +3076,7 @@ packages: rxjs: ^5.5.0 || ^6.5.0 || ^7.3.0 dependencies: '@awesome-cordova-plugins/core': 5.45.0(rxjs@7.8.1) - '@types/cordova': 11.0.1 + '@types/cordova': 11.0.2 rxjs: 7.8.1 dev: false @@ -2674,7 +3085,7 @@ packages: peerDependencies: rxjs: ^5.5.0 || ^6.5.0 || ^7.3.0 dependencies: - '@types/cordova': 11.0.1 + '@types/cordova': 11.0.2 rxjs: 7.8.1 dev: false @@ -5416,18 +5827,19 @@ packages: engines: {node: '>=10.0.0'} dev: true - /@elastic/elasticsearch@8.4.0: - resolution: {integrity: sha512-0QZDBePnb5a+d76zjlMYq96IDf0AOuGP7JHugFUYlYwTC7rZvROuZSpoUsvpUjNH2CzMqWgNLIekIR6EHRMIQA==} + /@elastic/elasticsearch@8.10.0(patch_hash=cbqivwahgcyqqvtkergczzr7wq): + resolution: {integrity: sha512-RIEyqz0D18bz/dK+wJltaak+7wKaxDELxuiwOJhuMrvbrBsYDFnEoTdP/TZ0YszHBgnRPGqBDBgH/FHNgHObiQ==} engines: {node: '>=14'} dependencies: - '@elastic/transport': 8.3.2 + '@elastic/transport': 8.3.4 tslib: 2.4.1 transitivePeerDependencies: - supports-color dev: false + patched: true - /@elastic/transport@8.3.2: - resolution: {integrity: sha512-ZiBYRVPj6pwYW99fueyNU4notDf7ZPs7Ix+4T1btIJsKJmeaORIItIfs+0O7KV4vV+DcvyMhkY1FXQx7kQOODw==} + /@elastic/transport@8.3.4: + resolution: {integrity: sha512-+0o8o74sbzu3BO7oOZiP9ycjzzdOt4QwmMEjFc1zfO7M0Fh7QX1xrpKqZbSd8vBwihXNlSq/EnMPfgD2uFEmFg==} engines: {node: '>=14'} dependencies: debug: 4.3.4(supports-color@8.1.1) @@ -5765,7 +6177,7 @@ packages: peerDependencies: rxjs: ^5.5.0 || ^6.5.0 dependencies: - '@types/cordova': 11.0.1 + '@types/cordova': 11.0.2 rxjs: 7.8.1 dev: false @@ -5777,7 +6189,7 @@ packages: rxjs: ^5.5.0 || ^6.5.0 dependencies: '@ionic-native/core': 5.36.0(rxjs@7.8.1) - '@types/cordova': 11.0.1 + '@types/cordova': 11.0.2 rxjs: 7.8.1 dev: false optional: true @@ -5790,7 +6202,7 @@ packages: rxjs: ^5.5.0 || ^6.5.0 dependencies: '@ionic-native/core': 5.36.0(rxjs@7.8.1) - '@types/cordova': 11.0.1 + '@types/cordova': 11.0.2 rxjs: 7.8.1 dev: false optional: true @@ -5803,7 +6215,7 @@ packages: rxjs: ^5.5.0 || ^6.5.0 dependencies: '@ionic-native/core': 5.36.0(rxjs@7.8.1) - '@types/cordova': 11.0.1 + '@types/cordova': 11.0.2 rxjs: 7.8.1 dev: false optional: true @@ -5816,7 +6228,7 @@ packages: rxjs: ^5.5.0 || ^6.5.0 dependencies: '@ionic-native/core': 5.36.0(rxjs@7.8.1) - '@types/cordova': 11.0.1 + '@types/cordova': 11.0.2 rxjs: 7.8.1 dev: false optional: true @@ -6235,6 +6647,7 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: semver: 7.3.8 + dev: true /@npmcli/git@4.1.0: resolution: {integrity: sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==} @@ -6633,6 +7046,7 @@ packages: /@tootallnate/once@2.0.0: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} + dev: true /@transistorsoft/capacitor-background-fetch@1.0.2(@capacitor/core@4.6.1): resolution: {integrity: sha512-eF92oeLYg7cZNGtlUMq6nZH1Q0i3wIXyQKlsWRBlaSey/DhL+Ncv1//ejbH+FQ427bC+CT1PPAD/OrPsJeL7+g==} @@ -6738,8 +7152,8 @@ packages: resolution: {integrity: sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==} dev: true - /@types/cordova@11.0.1: - resolution: {integrity: sha512-Zd6LAhYUAdn0mL0SbxHeF4fO/3uzkcW3fzE0ZIK1wDlTRCWlI4/0i+Phb+otP9ryziyeW2LKofRNSP5yil85hA==} + /@types/cordova@11.0.2: + resolution: {integrity: sha512-swXLtFffXPQYz80eEX4URII7obHBZCS01JtI2Fh0Gt6dxgwoyDB7ZzfkRZgHHDxl1qRdMVRICMvfx2USIHPWCA==} dev: false /@types/cors@2.8.13: @@ -6776,7 +7190,7 @@ packages: resolution: {integrity: sha512-gsF+c/0XOguWgaOgvFs+xnnRqt9GwgTvIks36WpE6ueeI4KCEHHd8K/CKHqhOqrJKsYH8m27kRzQEvWXAwXUTw==} dependencies: '@types/estree': 1.0.1 - '@types/json-schema': 7.0.11 + '@types/json-schema': 7.0.14 dev: true /@types/estree@1.0.1: @@ -6879,8 +7293,8 @@ packages: resolution: {integrity: sha512-MhCUjojzDhVLnZnxwPwa+rETFRDQ0ffjxYdrqOP6TBO2O0/Z64PV5tNeYApo4bc4y4frbWOrRwv/eEkXlI13Rw==} dev: true - /@types/json-schema@7.0.11: - resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + /@types/json-schema@7.0.14: + resolution: {integrity: sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==} /@types/jsonpath@0.2.0: resolution: {integrity: sha512-v7qlPA0VpKUlEdhghbDqRoKMxFB3h3Ch688TApBJ6v+XLDdvWCGLJIYiPKGZnS6MAOie+IorCfNYVHOPIHSWwQ==} @@ -6967,10 +7381,6 @@ packages: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true - /@types/node@14.18.38: - resolution: {integrity: sha512-zMRIidN2Huikv/+/U7gRPFYsXDR/7IGqFZzTLnCEj5+gkrQjsowfamaxEnyvArct5hxGA3bTxMXlYhH78V6Cew==} - dev: true - /@types/node@18.15.3: resolution: {integrity: sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==} @@ -7008,13 +7418,6 @@ packages: /@types/retry@0.12.0: resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} - /@types/rimraf@3.0.2: - resolution: {integrity: sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==} - dependencies: - '@types/glob': 8.0.1 - '@types/node': 18.15.3 - dev: true - /@types/semver@6.2.3: resolution: {integrity: sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==} dev: true @@ -7139,34 +7542,6 @@ packages: dev: true optional: true - /@typescript-eslint/eslint-plugin@5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@3.8.3): - resolution: {integrity: sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 5.60.1(eslint@8.43.0)(typescript@3.8.3) - '@typescript-eslint/scope-manager': 5.60.1 - '@typescript-eslint/type-utils': 5.60.1(eslint@8.43.0)(typescript@3.8.3) - '@typescript-eslint/utils': 5.60.1(eslint@8.43.0)(typescript@3.8.3) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.43.0 - grapheme-splitter: 1.0.4 - ignore: 5.2.4 - natural-compare-lite: 1.4.0 - semver: 7.3.8 - tsutils: 3.21.0(typescript@3.8.3) - typescript: 3.8.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/eslint-plugin@5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6): resolution: {integrity: sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7194,26 +7569,6 @@ packages: transitivePeerDependencies: - supports-color - /@typescript-eslint/parser@5.60.1(eslint@8.43.0)(typescript@3.8.3): - resolution: {integrity: sha512-pHWlc3alg2oSMGwsU/Is8hbm3XFbcrb6P5wIxcQW9NsYBfnrubl/GhVVD/Jm/t8HXhA2WncoIRfBtnCgRGV96Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 5.60.1 - '@typescript-eslint/types': 5.60.1 - '@typescript-eslint/typescript-estree': 5.60.1(typescript@3.8.3) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.43.0 - typescript: 3.8.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/parser@5.60.1(eslint@8.43.0)(typescript@5.1.6): resolution: {integrity: sha512-pHWlc3alg2oSMGwsU/Is8hbm3XFbcrb6P5wIxcQW9NsYBfnrubl/GhVVD/Jm/t8HXhA2WncoIRfBtnCgRGV96Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7248,26 +7603,6 @@ packages: '@typescript-eslint/visitor-keys': 5.62.0 dev: true - /@typescript-eslint/type-utils@5.60.1(eslint@8.43.0)(typescript@3.8.3): - resolution: {integrity: sha512-vN6UztYqIu05nu7JqwQGzQKUJctzs3/Hg7E2Yx8rz9J+4LgtIDFWjjl1gm3pycH0P3mHAcEUBd23LVgfrsTR8A==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '*' - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/typescript-estree': 5.60.1(typescript@3.8.3) - '@typescript-eslint/utils': 5.60.1(eslint@8.43.0)(typescript@3.8.3) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.43.0 - tsutils: 3.21.0(typescript@3.8.3) - typescript: 3.8.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/type-utils@5.60.1(eslint@8.43.0)(typescript@5.1.6): resolution: {integrity: sha512-vN6UztYqIu05nu7JqwQGzQKUJctzs3/Hg7E2Yx8rz9J+4LgtIDFWjjl1gm3pycH0P3mHAcEUBd23LVgfrsTR8A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7316,27 +7651,6 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@5.60.1(typescript@3.8.3): - resolution: {integrity: sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.60.1 - '@typescript-eslint/visitor-keys': 5.60.1 - debug: 4.3.4(supports-color@8.1.1) - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.3.8 - tsutils: 3.21.0(typescript@3.8.3) - typescript: 3.8.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/typescript-estree@5.60.1(typescript@5.1.6): resolution: {integrity: sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7378,26 +7692,6 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@5.60.1(eslint@8.43.0)(typescript@3.8.3): - resolution: {integrity: sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) - '@types/json-schema': 7.0.11 - '@types/semver': 7.3.13 - '@typescript-eslint/scope-manager': 5.60.1 - '@typescript-eslint/types': 5.60.1 - '@typescript-eslint/typescript-estree': 5.60.1(typescript@3.8.3) - eslint: 8.43.0 - eslint-scope: 5.1.1 - semver: 7.3.8 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /@typescript-eslint/utils@5.60.1(eslint@8.43.0)(typescript@5.1.6): resolution: {integrity: sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7405,7 +7699,7 @@ packages: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) - '@types/json-schema': 7.0.11 + '@types/json-schema': 7.0.14 '@types/semver': 7.3.13 '@typescript-eslint/scope-manager': 5.60.1 '@typescript-eslint/types': 5.60.1 @@ -7424,7 +7718,7 @@ packages: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) - '@types/json-schema': 7.0.11 + '@types/json-schema': 7.0.14 '@types/semver': 7.3.13 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 @@ -7613,6 +7907,7 @@ packages: /abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} @@ -7683,6 +7978,7 @@ packages: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color + dev: true /agentkeepalive@4.3.0: resolution: {integrity: sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==} @@ -7693,6 +7989,7 @@ packages: humanize-ms: 1.2.1 transitivePeerDependencies: - supports-color + dev: true /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} @@ -7721,7 +8018,6 @@ packages: optional: true dependencies: ajv: 8.12.0 - dev: true /ajv-formats@2.1.1(ajv@8.9.0): resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} @@ -7884,6 +8180,7 @@ packages: /aproba@2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: true /arch@2.2.0: resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} @@ -7899,6 +8196,7 @@ packages: dependencies: delegates: 1.0.0 readable-stream: 3.6.2 + dev: true /arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -8023,6 +8321,7 @@ packages: /at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} + dev: true /autoprefixer@10.4.14(postcss@8.4.24): resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} @@ -8516,6 +8815,7 @@ packages: ssri: 10.0.4 tar: 6.1.15 unique-filename: 3.0.0 + dev: true /cacheable-lookup@7.0.0: resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} @@ -8712,6 +9012,7 @@ packages: /chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + dev: true /chrome-trace-event@1.0.3: resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} @@ -8899,6 +9200,7 @@ packages: /color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true + dev: true /color@4.2.3: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} @@ -8914,7 +9216,6 @@ packages: /colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - dev: true /colors@1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} @@ -8936,6 +9237,11 @@ packages: engines: {node: '>=14'} dev: true + /commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + dev: false + /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true @@ -8964,6 +9270,7 @@ packages: /commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} + dev: true /comment-parser@1.3.1: resolution: {integrity: sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==} @@ -9054,6 +9361,7 @@ packages: /console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + dev: true /content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} @@ -10162,6 +10470,7 @@ packages: /delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + dev: true /depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} @@ -10439,6 +10748,7 @@ packages: requiresBuild: true dependencies: iconv-lite: 0.6.3 + dev: true optional: true /end-of-stream@1.4.4: @@ -10497,9 +10807,11 @@ packages: /env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + dev: true /err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + dev: true /errno@0.1.8: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} @@ -11000,6 +11312,7 @@ packages: /exponential-backoff@3.1.1: resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} + dev: true /express-prom-bundle@6.6.0(prom-client@14.1.1): resolution: {integrity: sha512-tZh2P2p5a8/yxQ5VbRav011Poa4R0mHqdFwn9Swe/obXDe5F0jY9wtRAfNYnqk4LXY7akyvR/nrvAHxQPWUjsQ==} @@ -11464,18 +11777,21 @@ packages: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 + dev: true /fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} dependencies: minipass: 3.3.6 + dev: true /fs-minipass@3.0.2: resolution: {integrity: sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: minipass: 5.0.0 + dev: true /fs-monkey@1.0.4: resolution: {integrity: sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==} @@ -11539,6 +11855,7 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wide-align: 1.1.5 + dev: true /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -11902,6 +12219,7 @@ packages: wordwrap: 1.0.0 optionalDependencies: uglify-js: 3.17.4 + dev: true /har-schema@2.0.0: resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} @@ -11957,6 +12275,7 @@ packages: /has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + dev: true /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} @@ -11992,10 +12311,6 @@ packages: engines: {node: '>=8'} dev: true - /highlight.js@10.7.3: - resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - dev: false - /hoek@4.2.1: resolution: {integrity: sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==} engines: {node: '>=4.0.0'} @@ -12139,6 +12454,7 @@ packages: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color + dev: true /http-proxy-middleware@2.0.6(@types/express@4.17.17): resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==} @@ -12231,6 +12547,7 @@ packages: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color + dev: true /human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} @@ -12250,6 +12567,7 @@ packages: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} dependencies: ms: 2.1.3 + dev: true /humanize-string@3.0.0: resolution: {integrity: sha512-jhWD2GAZRMELz0IEIfqpEdi0M4CMQF1GpJpBYIopFN6wT+78STiujfQTKcKqZzOJgUkIgJSo2xFeHdsg922JZQ==} @@ -12442,11 +12760,6 @@ packages: deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. dev: true - /install-artifact-from-github@1.3.3: - resolution: {integrity: sha512-x79SL0d8WOi1ZjXSTUqqs0GPQZ92YArJAN9O46wgU9wdH2U9ecyyhB9YGDbPe2OLV4ptmt6AZYRQZ2GydQZosQ==} - hasBin: true - dev: false - /internal-slot@1.0.5: resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} engines: {node: '>= 0.4'} @@ -12463,11 +12776,6 @@ packages: dev: false optional: true - /interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} - dev: false - /ionic-appauth@0.9.0(rxjs@7.8.1): resolution: {integrity: sha512-VayICoCf1MvX3KYOxv4GZ/Z4xNRCEmVzn8NovZVvIfw9BqRYoSIQ3+xP5a+R/PCOhNLMXNr33ygpfsV0OeJSiw==} peerDependencies: @@ -12515,6 +12823,7 @@ packages: /ip@2.0.0: resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} + dev: true /ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} @@ -12658,6 +12967,7 @@ packages: /is-lambda@1.0.1: resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + dev: true /is-map@2.0.2: resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} @@ -13717,9 +14027,11 @@ packages: /lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + dev: true /lunr@2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + dev: true /macos-release@2.5.1: resolution: {integrity: sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==} @@ -13785,6 +14097,7 @@ packages: ssri: 10.0.4 transitivePeerDependencies: - supports-color + dev: true /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} @@ -13800,12 +14113,6 @@ packages: resolution: {integrity: sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==} dev: true - /marked@1.2.9: - resolution: {integrity: sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==} - engines: {node: '>= 8.16.2'} - hasBin: true - dev: false - /marked@4.3.0: resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} engines: {node: '>= 12'} @@ -14061,6 +14368,7 @@ packages: engines: {node: '>= 8'} dependencies: minipass: 3.3.6 + dev: true /minipass-fetch@3.0.3: resolution: {integrity: sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==} @@ -14071,12 +14379,14 @@ packages: minizlib: 2.1.2 optionalDependencies: encoding: 0.1.13 + dev: true /minipass-flush@1.0.5: resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} engines: {node: '>= 8'} dependencies: minipass: 3.3.6 + dev: true /minipass-json-stream@1.0.1: resolution: {integrity: sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==} @@ -14090,22 +14400,26 @@ packages: engines: {node: '>=8'} dependencies: minipass: 3.3.6 + dev: true /minipass-sized@1.0.3: resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} engines: {node: '>=8'} dependencies: minipass: 3.3.6 + dev: true /minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} dependencies: yallist: 4.0.0 + dev: true /minipass@5.0.0: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} + dev: true /minipass@6.0.2: resolution: {integrity: sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==} @@ -14117,6 +14431,7 @@ packages: dependencies: minipass: 3.3.6 yallist: 4.0.0 + dev: true /mixme@0.5.9: resolution: {integrity: sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==} @@ -14137,6 +14452,7 @@ packages: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true + dev: true /mocha-junit-reporter@2.2.0(mocha@10.2.0): resolution: {integrity: sha512-W83Ddf94nfLiTBl24aS8IVyFvO8aRDLlCvb+cKb/VEaN5dEbcqu3CXiTe8MQK2DvzS7oKE1RsFTxzN302GGbDQ==} @@ -14326,6 +14642,7 @@ packages: /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true /netmask@2.0.2: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} @@ -14495,6 +14812,7 @@ packages: which: 2.0.2 transitivePeerDependencies: - supports-color + dev: true /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} @@ -14525,6 +14843,7 @@ packages: hasBin: true dependencies: abbrev: 1.1.1 + dev: true /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -14648,6 +14967,7 @@ packages: console-control-strings: 1.1.0 gauge: 4.0.4 set-blocking: 2.0.0 + dev: true /nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} @@ -14816,8 +15136,8 @@ packages: is-wsl: 2.2.0 dev: true - /openapi-types@12.1.0: - resolution: {integrity: sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA==} + /openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} dev: false /opencollective-postinstall@2.0.3: @@ -15511,11 +15831,6 @@ packages: engines: {node: '>=0.4.0'} dev: true - /progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - dev: false - /prom-client@14.1.1: resolution: {integrity: sha512-hFU32q7UZQ59bVJQGUtm3I2PrJ3gWvoCkilX9sF165ks1qflhugVCeK+S1JjJYHvyt3o5kj68+q3bchormjnzw==} engines: {node: '>=10'} @@ -15543,6 +15858,7 @@ packages: dependencies: err-code: 2.0.3 retry: 0.12.0 + dev: true /prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} @@ -15718,17 +16034,6 @@ packages: strip-json-comments: 2.0.1 dev: true - /re2@1.18.2: - resolution: {integrity: sha512-9r1/ZWC46rmTf+q/qNRa6mVbWaX0PnWclBDwozaa7UfvS8hny6ENejEtwNUwmNRDGFpOISERPQeZ6EE+6djHyA==} - requiresBuild: true - dependencies: - install-artifact-from-github: 1.3.3 - nan: 2.17.0 - node-gyp: 9.4.0 - transitivePeerDependencies: - - supports-color - dev: false - /read-installed@4.0.3: resolution: {integrity: sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==} dependencies: @@ -15893,13 +16198,6 @@ packages: picomatch: 2.3.1 dev: true - /rechoir@0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} - dependencies: - resolve: 1.22.2 - dev: false - /redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -16098,6 +16396,7 @@ packages: /retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} + dev: true /retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} @@ -16123,14 +16422,6 @@ packages: dependencies: glob: 7.2.3 - /rimraf@5.0.0: - resolution: {integrity: sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==} - engines: {node: '>=14'} - hasBin: true - dependencies: - glob: 10.2.7 - dev: true - /robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} requiresBuild: true @@ -16252,7 +16543,7 @@ packages: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/json-schema': 7.0.11 + '@types/json-schema': 7.0.14 ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) dev: true @@ -16261,7 +16552,7 @@ packages: resolution: {integrity: sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==} engines: {node: '>= 12.13.0'} dependencies: - '@types/json-schema': 7.0.11 + '@types/json-schema': 7.0.14 ajv: 8.12.0 ajv-formats: 2.1.1(ajv@8.12.0) ajv-keywords: 5.1.0(ajv@8.12.0) @@ -16402,6 +16693,7 @@ packages: /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: true /setprototypeof@1.1.0: resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} @@ -16462,16 +16754,6 @@ packages: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} dev: true - /shelljs@0.8.5: - resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} - engines: {node: '>=4'} - hasBin: true - dependencies: - glob: 7.2.3 - interpret: 1.4.0 - rechoir: 0.6.2 - dev: false - /shiki@0.14.3: resolution: {integrity: sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==} dependencies: @@ -16490,6 +16772,7 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true /signal-exit@4.0.2: resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} @@ -16601,6 +16884,7 @@ packages: /smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + dev: true /smartwrap@2.0.2: resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} @@ -16679,6 +16963,7 @@ packages: socks: 2.7.1 transitivePeerDependencies: - supports-color + dev: true /socks@2.7.1: resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} @@ -16686,6 +16971,7 @@ packages: dependencies: ip: 2.0.0 smart-buffer: 4.2.0 + dev: true /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} @@ -16728,6 +17014,7 @@ packages: /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + dev: true /source-map@0.7.3: resolution: {integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==} @@ -16894,6 +17181,7 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: minipass: 5.0.0 + dev: true /static-eval@2.1.0: resolution: {integrity: sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw==} @@ -17468,6 +17756,7 @@ packages: minizlib: 2.1.2 mkdirp: 1.0.4 yallist: 4.0.0 + dev: true /tarr@1.1.0: resolution: {integrity: sha512-tENbQ43IQckay71stp1p1lljRhoEZpZk10FzEZKW2tJcMcnLwV3CfZdxBAERlH6nwnFvnHMS9eJOJl6IzSsG0g==} @@ -17722,18 +18011,18 @@ packages: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true - /ts-json-schema-generator@1.2.0: - resolution: {integrity: sha512-tUMeO3ZvA12d3HHh7T/AK8W5hmUhDRNtqWRHSMN3ZRbUFt+UmV0oX8k1RK4SA+a+BKNHpmW2v06MS49e8Fi3Yg==} + /ts-json-schema-generator@1.4.0: + resolution: {integrity: sha512-wm8vyihmGgYpxrqRshmYkWGNwEk+sf3xV2rUgxv8Ryeh7bSpMO7pZQOht+2rS002eDkFTxR7EwRPXVzrS0WJTg==} engines: {node: '>=10.0.0'} hasBin: true dependencies: - '@types/json-schema': 7.0.11 - commander: 9.5.0 + '@types/json-schema': 7.0.14 + commander: 11.1.0 glob: 8.1.0 json5: 2.2.3 normalize-path: 3.0.0 safe-stable-stringify: 2.4.3 - typescript: 4.9.5 + typescript: 5.2.2 dev: false /ts-morph@13.0.3: @@ -17743,37 +18032,6 @@ packages: code-block-writer: 11.0.3 dev: true - /ts-node@10.9.1(@types/node@14.18.38)(typescript@3.8.3): - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 14.18.38 - acorn: 8.10.0 - acorn-walk: 8.2.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 3.8.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - /ts-node@10.9.1(@types/node@18.15.3)(typescript@5.1.6): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true @@ -17863,16 +18121,6 @@ packages: - ts-node dev: true - /tsutils@3.21.0(typescript@3.8.3): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - dependencies: - tslib: 1.14.1 - typescript: 3.8.3 - dev: true - /tsutils@3.21.0(typescript@5.1.6): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -18080,33 +18328,6 @@ packages: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true - /typedoc-default-themes@0.10.2: - resolution: {integrity: sha512-zo09yRj+xwLFE3hyhJeVHWRSPuKEIAsFK5r2u47KL/HBKqpwdUSanoaz5L34IKiSATFrjG5ywmIu98hPVMfxZg==} - engines: {node: '>= 8'} - dependencies: - lunr: 2.3.9 - dev: false - - /typedoc@0.18.0(typescript@3.8.3): - resolution: {integrity: sha512-UgDQwapCGQCCdYhEQzQ+kGutmcedklilgUGf62Vw6RdI29u6FcfAXFQfRTiJEbf16aK3YnkB20ctQK1JusCRbA==} - engines: {node: '>= 10.0.0'} - hasBin: true - peerDependencies: - typescript: '>=3.8.3' - dependencies: - fs-extra: 9.1.0 - handlebars: 4.7.7 - highlight.js: 10.7.3 - lodash: 4.17.21 - lunr: 2.3.9 - marked: 1.2.9 - minimatch: 3.1.2 - progress: 2.0.3 - shelljs: 0.8.5 - typedoc-default-themes: 0.10.2 - typescript: 3.8.3 - dev: false - /typedoc@0.24.8(typescript@5.1.6): resolution: {integrity: sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==} engines: {node: '>= 14.14'} @@ -18121,22 +18342,17 @@ packages: typescript: 5.1.6 dev: true - /typescript@3.8.3: - resolution: {integrity: sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==} - engines: {node: '>=4.2.0'} - hasBin: true - - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: false - /typescript@5.1.6: resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} engines: {node: '>=14.17'} hasBin: true + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + dev: false + /ua-parser-js@0.7.35: resolution: {integrity: sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==} dev: true @@ -18146,6 +18362,7 @@ packages: engines: {node: '>=0.8.0'} hasBin: true requiresBuild: true + dev: true optional: true /unbox-primitive@1.0.2: @@ -18212,12 +18429,14 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: unique-slug: 4.0.0 + dev: true /unique-slug@4.0.0: resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: imurmurhash: 0.1.4 + dev: true /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} @@ -18730,6 +18949,7 @@ packages: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} dependencies: string-width: 4.2.3 + dev: true /wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} @@ -18749,6 +18969,7 @@ packages: /wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + dev: true /workerpool@6.2.1: resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==}