mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-21 00:52:55 +00:00
feat: more fixes
This commit is contained in:
@@ -24,6 +24,10 @@ type NameOf<I extends SchemaMap[keyof SchemaMap]> = keyof IncludeProperty<Schema
|
||||
export class Validator {
|
||||
private readonly ajv: Ajv.default;
|
||||
|
||||
get errors() {
|
||||
return this.ajv.errors;
|
||||
}
|
||||
|
||||
constructor(additionalSchemas: AnySchema[] = []) {
|
||||
this.ajv = new Ajv.default({
|
||||
schemas: [schema, ...additionalSchemas],
|
||||
@@ -36,12 +40,21 @@ export class Validator {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional schemas to the validator
|
||||
*/
|
||||
public addSchema(...schema: AnySchema[]) {
|
||||
this.ajv.addSchema(schema);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<T>(instance: unknown, schema: NameOf<T>): instance is T {
|
||||
return this.ajv.validate(schema as string, instance);
|
||||
public validate<T extends SchemaMap[keyof SchemaMap]>(instance: unknown, schema: NameOf<T>): instance is T;
|
||||
public validate(instance: unknown, schema: Ajv.Schema): boolean;
|
||||
public validate(instance: unknown, schema: Ajv.Schema | string): boolean {
|
||||
return this.ajv.validate(schema, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,11 @@
|
||||
},
|
||||
"./schema.json": {
|
||||
"import": "./lib/schema.json",
|
||||
"types": "./lib/schema.d.ts"
|
||||
"types": "./lib/schema.json.d.ts"
|
||||
},
|
||||
"./elasticsearch-mappings.json": {
|
||||
"import": "./lib/elasticsearch.json",
|
||||
"types": "./lib/elasticsearch.json.d.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
"test": "c8 mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "8.12.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"@elastic/elasticsearch": "8.10.0",
|
||||
"@openstapps/json-schema-generator": "workspace:*",
|
||||
"@openstapps/tsup-plugin": "workspace:*",
|
||||
|
||||
@@ -1,85 +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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
declare module 'aggregations.json' {
|
||||
const value: AggregationSchema;
|
||||
export default value;
|
||||
}
|
||||
|
||||
/**
|
||||
* An elasticsearch bucket aggregation
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-aggregations-bucket.html
|
||||
*/
|
||||
export interface AggregationSchema {
|
||||
[aggregationName: string]: ESTermsFilter | ESNestedAggregation;
|
||||
}
|
||||
|
||||
/**
|
||||
* An elasticsearch terms filter
|
||||
*/
|
||||
export interface ESTermsFilter {
|
||||
/**
|
||||
* Terms filter definition
|
||||
*/
|
||||
terms: {
|
||||
/**
|
||||
* Field to apply filter to
|
||||
*/
|
||||
field: string;
|
||||
|
||||
/**
|
||||
* Number of results
|
||||
*/
|
||||
size?: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter that filters by name of the the field type
|
||||
*/
|
||||
export interface ESAggTypeFilter {
|
||||
/**
|
||||
* The type of the object to find
|
||||
*/
|
||||
term: {
|
||||
/**
|
||||
* The name of the type
|
||||
*/
|
||||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter that matches everything
|
||||
*/
|
||||
export interface ESAggMatchAllFilter {
|
||||
/**
|
||||
* Filter that matches everything
|
||||
*/
|
||||
match_all: object;
|
||||
}
|
||||
|
||||
/**
|
||||
* For nested aggregations
|
||||
*/
|
||||
export interface ESNestedAggregation {
|
||||
/**
|
||||
* Possible nested Aggregations
|
||||
*/
|
||||
aggs: AggregationSchema;
|
||||
/**
|
||||
* Possible filter for types
|
||||
*/
|
||||
filter: ESAggTypeFilter | ESAggMatchAllFilter;
|
||||
}
|
||||
127
packages/es-mapping-generator/schema/mappings.d.ts
vendored
127
packages/es-mapping-generator/schema/mappings.d.ts
vendored
@@ -1,124 +1,9 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import {IndicesPutTemplateRequest, MappingProperty} from '@elastic/elasticsearch/lib/api/types';
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {AggregationSchema} from './aggregations';
|
||||
import {IndicesPutTemplateRequest, SearchRequest} from '@elastic/elasticsearch/lib/api/types.js';
|
||||
|
||||
declare module 'mappings.json' {
|
||||
const value: ElasticsearchTemplateCollection;
|
||||
export default value;
|
||||
export interface ElasticsearchConfig {
|
||||
mappings: Record<string, IndicesPutTemplateRequest>;
|
||||
search: Partial<SearchRequest>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template output of the mapping generation
|
||||
*/
|
||||
export interface MappingGenTemplate {
|
||||
/**
|
||||
* All generated aggregations
|
||||
*/
|
||||
aggregations: AggregationSchema;
|
||||
|
||||
/**
|
||||
* All errors that occurred
|
||||
*/
|
||||
errors: string[];
|
||||
|
||||
/**
|
||||
* All mappings that were generated
|
||||
*/
|
||||
mappings: ElasticsearchTemplateCollection;
|
||||
}
|
||||
|
||||
export type SimpleType = MappingProperty['type'] &
|
||||
('keyword' | 'float' | 'boolean' | 'date' | 'integer' | 'text');
|
||||
|
||||
/**
|
||||
* The Typemap is used to get the corresponding ElasticsearchDataType for a name provided by the ProjectReflection
|
||||
*/
|
||||
export interface ElasticsearchTypemap {
|
||||
/**
|
||||
* The `stringLiteral` type must always be provided
|
||||
*/
|
||||
stringLiteral: {
|
||||
/**
|
||||
* The default can be chosen freely, but must be provided
|
||||
*/
|
||||
default: SimpleType;
|
||||
};
|
||||
|
||||
/**
|
||||
* The name of the JS type, so for `number` it would be number
|
||||
*/
|
||||
[name: string]: {
|
||||
/**
|
||||
* The default ElasticsearchDataType that should be used, if no tag or only not implemented tags are found
|
||||
*/
|
||||
default: SimpleType;
|
||||
|
||||
/**
|
||||
* The name of the tag, so for `@integer` it would be `integer`
|
||||
*/
|
||||
[name: string]: SimpleType;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The Fieldmap contains all tag names for fields and the corresponding fields
|
||||
*
|
||||
* The Fieldmap works in a similar fashion to the Typemap
|
||||
*/
|
||||
export interface ElasticsearchFieldmap {
|
||||
/**
|
||||
* The name of the tag, so for `@sortable` it would be `sortable`
|
||||
*/
|
||||
[name: string]: {
|
||||
/**
|
||||
* The default value if no parameter is provided
|
||||
*/
|
||||
default: {
|
||||
/**
|
||||
* To allow the usage of `prev.fields = {...prev.fields, ...fieldmap[tag.tagName].default}`
|
||||
*
|
||||
* We could also have used `default: any`, but this adds slightly more improved type-safety.
|
||||
*/
|
||||
[name: string]: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* The tag parameters that will be ignored
|
||||
*
|
||||
* Some tag parameters might not be important for your implementation, so you can add their names here to not get
|
||||
* any errors. The `default` will be used in that case.
|
||||
*/
|
||||
ignore: string[];
|
||||
|
||||
/**
|
||||
* The parameters of the tag, so for `@sortable ducet` it would be `ducet`
|
||||
*/
|
||||
[name: string]: {
|
||||
/**
|
||||
* To allow the usage of `prev.fields = {...prev.fields, ...fieldmap[tag.tagName][tag.text.trim()]}`
|
||||
*
|
||||
* We could also have used `default: any`, but this adds slightly more improved type-safety.
|
||||
*/
|
||||
[name: string]: any;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of Elasticsearch Templates
|
||||
*/
|
||||
export type ElasticsearchTemplateCollection = Record<string, Omit<IndicesPutTemplateRequest, 'name'>>;
|
||||
declare const elasticsearchConfig: ElasticsearchConfig;
|
||||
export default elasticsearchConfig;
|
||||
|
||||
@@ -58,7 +58,7 @@ export class Context {
|
||||
this.propertyPath,
|
||||
new Map(),
|
||||
);
|
||||
const result = transformDefinition(derivedContext, definition);
|
||||
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});
|
||||
|
||||
@@ -3,6 +3,7 @@ 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';
|
||||
import {ElasticsearchConfig} from '../../schema/mappings.js';
|
||||
|
||||
export interface GeneratorOptions {
|
||||
/**
|
||||
@@ -24,15 +25,16 @@ export interface GeneratorOptions {
|
||||
/**
|
||||
* Fully transform a project
|
||||
*/
|
||||
export function transformProject(project: JSONSchema7) {
|
||||
export function transformProject(project: JSONSchema7): ElasticsearchConfig {
|
||||
const context = new MappingGenerator(project, OPTIONS);
|
||||
|
||||
const results = [];
|
||||
const results: Record<string, IndicesPutTemplateRequest> = {};
|
||||
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));
|
||||
const [type, template] = context.buildTemplate(name);
|
||||
results[type] = template;
|
||||
}
|
||||
return {
|
||||
mappings: results,
|
||||
|
||||
@@ -41,7 +41,7 @@ export class MappingGenerator {
|
||||
);
|
||||
}
|
||||
|
||||
buildTemplate(name: string): IndicesPutTemplateRequest {
|
||||
buildTemplate(name: string): [string, IndicesPutTemplateRequest] {
|
||||
const thingType = ((this.project.definitions![name] as JSONSchema7).properties!.type as JSONSchema7)
|
||||
.const;
|
||||
if (typeof thingType !== 'string') {
|
||||
@@ -71,6 +71,6 @@ export class MappingGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
return request;
|
||||
return [thingType, request];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import {transformProject} from './generator/index.js';
|
||||
import {SchemaConsumer} from '@openstapps/json-schema-generator';
|
||||
import {readFile} from 'fs/promises';
|
||||
import path from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
|
||||
const mappingTypes = await readFile(
|
||||
path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'schema', 'mappings.d.ts'),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
/**
|
||||
* JSON Schema Generator plugin for Elasticsearch Mappings
|
||||
@@ -10,6 +18,7 @@ export function elasticsearchMappingGenerator(fileName: string): [string, Schema
|
||||
function (schema) {
|
||||
return {
|
||||
[fileName]: JSON.stringify(transformProject(schema)),
|
||||
[`${fileName}.d.ts`]: mappingTypes,
|
||||
};
|
||||
},
|
||||
];
|
||||
|
||||
@@ -24,10 +24,10 @@ export function compileSchema(path: string, tsconfig: string): [schma: JSONSchem
|
||||
Object.assign(fullSchema.definitions, generator.createSchema(schema).definitions);
|
||||
}
|
||||
|
||||
const schemaTypes = `import {JSONSchema7} from 'json-schema';\n\nexport interface SchemaMap {\n${[
|
||||
const schemaTypes = `import {JSONSchema7} from 'json-schema';\nimport * as index from './index.js';\n\nexport interface SchemaMap {\n${[
|
||||
...schemaNames,
|
||||
]
|
||||
.map(schemaName => ` '${schemaName}': core.${schemaName};`)
|
||||
.map(schemaName => ` '${schemaName}': index.${schemaName};`)
|
||||
.join('\n')}\n}\n\nconst schema: JSONSchema7;\nexport default schema;`;
|
||||
|
||||
return [fullSchema, schemaTypes];
|
||||
|
||||
@@ -76,7 +76,7 @@ export function jsonSchemaPlugin(
|
||||
|
||||
return {
|
||||
[schemaName]: JSON.stringify(jsonSchema),
|
||||
[`${schemaName.replace(/\.json$/, '')}.d.ts`]: types,
|
||||
[`${schemaName}.d.ts`]: types,
|
||||
};
|
||||
}).call(this);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user