refactor: update dependencies and fix resulting errors

Upgraded JSON Schema from version 6 to version 7
Upgraded TypeDoc version to latest
Replaced 'jsonschema' with 'json-schema' package to better comply with 'ts-json-schema-generator'
Replace JSON Schema validation with AJV in areas where it wasn't used previously
Removed commander help output as it causes strange issues
This commit is contained in:
Wieland Schöbl
2020-02-14 11:40:53 +01:00
committed by Rainer Killinger
parent b7cdb6a9ad
commit 5330255b7e
19 changed files with 2058 additions and 1145 deletions

2666
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -45,40 +45,42 @@
},
"dependencies": {
"@krlwlfrt/async-pool": "0.3.0",
"@openstapps/logger": "0.4.0",
"@openstapps/logger": "0.5.0",
"@types/glob": "7.1.1",
"@types/got": "9.6.9",
"@types/mustache": "0.8.32",
"@types/node": "10.17.14",
"@types/mustache": "4.0.0",
"@types/node": "10.17.21",
"@types/json-schema": "7.0.6",
"ajv": "6.11.0",
"better-ajv-errors": "0.6.7",
"chai": "4.2.0",
"commander": "2.20.3",
"deepmerge": "3.3.0",
"del": "4.1.1",
"commander": "4.1.1",
"deepmerge": "4.2.2",
"del": "5.1.0",
"flatted": "2.0.1",
"glob": "7.1.6",
"got": "9.6.0",
"got": "10.5.5",
"humanize-string": "2.1.0",
"jsonschema": "1.2.5",
"mustache": "3.0.1",
"json-schema": "0.2.5",
"mustache": "4.0.0",
"plantuml-encoder": "1.4.0",
"toposort": "2.0.2",
"ts-json-schema-generator": "0.42.0",
"ts-json-schema-generator": "0.60.0",
"ts-node": "8.6.2",
"typedoc": "0.14.2"
"typedoc": "0.18.0",
"typescript": "3.8.3"
},
"devDependencies": {
"@openstapps/configuration": "0.23.0",
"@openstapps/configuration": "0.25.0",
"@types/chai": "4.2.8",
"@types/mocha": "5.2.7",
"@types/mocha": "7.0.2",
"@types/rimraf": "2.0.3",
"conventional-changelog-cli": "2.0.31",
"mocha": "6.2.2",
"conventional-changelog-cli": "2.1.0",
"mocha": "7.2.0",
"mocha-typescript": "1.1.17",
"nock": "11.7.2",
"nock": "11.9.1",
"prepend-file-cli": "1.0.6",
"rimraf": "3.0.1",
"tslint": "5.20.1",
"typescript": "3.7.5"
"rimraf": "3.0.2",
"tslint": "6.1.3"
}
}

View File

@@ -1,10 +1,12 @@
<tr>
<td><h3>{{idx}}</h3></td>
<th scope="row"><h3>{{idx}}</h3></th>
<td>
<div class="alert {{status}}">{{message}}</div>
<pre style="max-width: 600px;">{{property}} = {{instance}}</pre>
<div class="alert {{status}}">{{name}}</div>
<p>{{message}}</p>
<p>{{suggestion}}</p>
</td>
<td>
<pre>{{schema}}</pre>
<td style="max-width: 600px">
<p>{{schemaPath}}</p>
<pre>{{instance}}</pre>
</td>
</tr>

View File

@@ -1,15 +1,17 @@
<h2>Errors in <code>{{testFile}}</code></h2>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>#</th>
<th>Error</th>
<th>Schema</th>
</tr>
</thead>
<tbody>
<div class="mw-100">
<h2>Errors in <code>{{testFile}}</code></h2>
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Error</th>
<th scope="col">Instance</th>
</tr>
</thead>
<tbody>
{{&errors}}
{{&errors}}
</tbody>
</table>
</tbody>
</table>
</div>

View File

@@ -3,26 +3,22 @@
<head>
<title>Report</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css"
integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>
<body>
<div class="container-fluid">
<h1>Validation result</h1>
<p>Timestamp: {{timestamp}}</p>
{{&report}}
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" crossorigin="anonymous"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" crossorigin="anonymous"
integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" crossorigin="anonymous"
integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ"></script>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha256-4+XzXVhsDmqanXGHaHvgh1gMQKX40OUvDEBTu8JcmNs=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"
integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
</body>
</html>

View File

@@ -15,7 +15,7 @@
import {Logger} from '@openstapps/logger';
import {Command} from 'commander';
import {existsSync, readFileSync, writeFileSync} from 'fs';
import * as got from 'got';
import got from 'got';
import {join, resolve} from 'path';
import {exit} from 'process';
import {
@@ -158,8 +158,7 @@ commander
}
const response = await got.put(`${esAddress}_template/${template}`, {
body: result.mappings[template],
json: true,
json: result.mappings[template],
});
const HTTP_STATUS_OK = 200;
@@ -353,8 +352,3 @@ commander
});
commander.parse(process.argv);
if (commander.args.length < 1) {
commander.outputHelp();
process.exit(1);
}

View File

@@ -15,11 +15,12 @@
import {Logger} from '@openstapps/logger';
import {existsSync, mkdir, PathLike, readFile, unlink, writeFile} from 'fs';
import {Glob} from 'glob';
import {Schema as JSONSchema, ValidationError} from 'jsonschema';
import {JSONSchema7 as JSONSchema} from 'json-schema';
import {platform} from 'os';
import {join, sep} from 'path';
import {Definition} from 'ts-json-schema-generator';
import {Application, ProjectReflection} from 'typedoc';
import {ModuleKind, ScriptTarget} from 'typescript';
import {promisify} from 'util';
import {LightweightType} from './uml/model/lightweight-type';
@@ -122,9 +123,67 @@ interface SchemaWithDefinitions extends JSONSchema {
}
/**
* An expectable error
* The validation result
*/
export interface ExpectableValidationError extends ValidationError {
export interface ValidationResult {
/**
* A list of errors that occurred
*/
errors: ValidationError[];
/**
* whether the validation was successful
*/
valid: boolean;
}
/**
* An error that occurred while validating
*
* This is a duplicate of the ValidationError in core/protocol/errors/validation because of incompatibilities
* between TypeDoc and TypeScript
*/
export interface ValidationError {
/**
* JSON schema path
*/
dataPath: string;
/**
* The instance
*/
instance: unknown;
/**
* The message
*
* Provided by https://www.npmjs.com/package/better-ajv-errors
*/
message: string;
/**
* Name of the error
*/
name: string;
/**
* Path within the Schema
*/
schemaPath: string;
/**
* Suggestion to fix the occurring error
*
* Provided by https://www.npmjs.com/package/better-ajv-errors
*/
suggestion?: string;
}
/**
* An expected error
*/
export interface ExpectedValidationError extends ValidationError {
/**
* Whether or not the error is expected
*/
@@ -132,10 +191,10 @@ export interface ExpectableValidationError extends ValidationError {
}
/**
* A map of files and their expectable validation errors
* A map of files and their expected validation errors
*/
export interface ExpectableValidationErrors {
[fileName: string]: ExpectableValidationError[];
export interface ExpectedValidationErrors {
[fileName: string]: ExpectedValidationError[];
}
/**
@@ -150,10 +209,14 @@ export function getProjectReflection(srcPath: PathLike, excludeExternals = true)
const tsconfigPath = getTsconfigPath(srcPath.toString());
// initialize new Typedoc application
const app = new Application({
const app = new Application();
app.options.setValues({
excludeExternals: excludeExternals,
ignoreCompilerErrors: false, // TODO: true
includeDeclarations: true,
module: 'commonjs',
module: ModuleKind.CommonJS,
target: ScriptTarget.Latest,
tsconfig: join(tsconfigPath, 'tsconfig.json'),
});
@@ -194,10 +257,11 @@ export function isSchemaWithDefinitions(
*/
export function isThingWithType(thing: unknown): thing is { type: string; } {
return typeof thing === 'object' &&
thing !== null &&
'type' in thing &&
typeof (thing as { type: string; }).type === 'string';
thing !== null &&
'type' in thing &&
typeof (thing as { type: unknown; }).type === 'string';
}
// tslint:enable: completed-docs
/**
@@ -233,16 +297,16 @@ export function getTsconfigPath(startPath: string): string {
}
/**
* Converts a comma seperated string into a string array
* Converts a comma separated string into a string array
*
* @param val Comma seperated string
* @param val Comma separated string
*/
export function toArray(val: string): string[] {
return val.split(',');
}
/**
* Creates the full name of a lightweight type recursivly
* Creates the full name of a lightweight type recursively
*
* @param type Type to get the full name of
*/

View File

@@ -51,6 +51,9 @@ const indexableTag = 'indexable';
const aggregatableTag = 'aggregatable';
const aggregatableTagParameterGlobal = 'global';
// clamp printed object to 1000 chars to keep error messages readable
const maxErrorObjectChars = 1000;
let ignoredTagsList = ['indexable', 'validatable'];
/**
@@ -91,7 +94,7 @@ export function getAllIndexableInterfaces(projectReflection: ProjectReflection):
}
/**
* Composes error messages, that are readable and contain a certain minumum of information
* 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
@@ -100,14 +103,27 @@ export function getAllIndexableInterfaces(projectReflection: ProjectReflection):
* @param message the error message
*/
function composeErrorMessage(path: string, topTypeName: string, typeName: string, object: string, message: string) {
const error = `At "${topTypeName}::${path.substr(0, path.length - 1)}" for ${typeName} "${object}": ${message}`;
const error = `At "${topTypeName}::${path.substr(0, path.length - 1)}" for ${typeName} "${trimString(object, maxErrorObjectChars)}": ${message}`;
errors.push(error);
if (showErrors) {
// tslint:disable-next-line:no-floating-promises
Logger.error(error);
Logger.error(error)
.then();
}
}
/**
* 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.substring(0, maxLength)}...` :
value;
}
/**
* Gets the Reflections and names for Generics in a ReferenceType of a DeclarationReflection
*
@@ -116,6 +132,7 @@ function composeErrorMessage(path: string, topTypeName: string, typeName: string
*
* @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
*/
@@ -161,7 +178,7 @@ function getReflectionGeneric(type: ReferenceType,
function handleExternalType(ref: ReferenceType, generics: Map<string, ElasticsearchValue>,
path: string, topTypeName: string, tags: CommentTag[]): ElasticsearchValue {
for (const premap in premaps) {
if (premap === ref.name) {
if (premap === ref.name && premaps.hasOwnProperty(premap)) {
return readFieldTags(premaps[premap], path, topTypeName, tags);
}
}
@@ -231,9 +248,9 @@ function handleDeclarationReflection(decl: DeclarationReflection,
const template: ElasticsearchDynamicTemplate = {};
template[decl.name] = {
mapping: handleType(
decl.indexSignature.type,
new Map(generics), path, topTypeName,
getCommentTags(decl.indexSignature)),
decl.indexSignature.type,
new Map(generics), path, topTypeName,
getCommentTags(decl.indexSignature)),
match: '*',
match_mapping_type: '*',
path_match: `${path}*`,
@@ -619,14 +636,16 @@ export function generateTemplate(projectReflection: ProjectReflection,
.replace('"', '');
} else {
// tslint:disable-next-line:no-floating-promises
Logger.error('Your input files seem to be incorrect, or there is a major bug in the mapping generator.');
Logger.error('Your input files seem to be incorrect, or there is a major bug in the mapping generator.')
.then();
}
} else if (typeObject.type instanceof StringLiteralType) {
Logger.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
Logger.error(`The interface ${_interface.name} is required to use an SCThingType as a type, please do so.`);
Logger.error(`The interface ${_interface.name} is required to use an SCThingType as a type, please do so.`)
.then();
}
// filter out

View File

@@ -435,9 +435,9 @@ function topologicalSort(modules: JavaScriptModule[]): JavaScriptModule[] {
// add all edges
modules.forEach((module) => {
module.dependencies.forEach((dependenciePath) => {
module.dependencies.forEach((dependencyPath) => {
// add edge from dependency to our module
edges.push([basename(dependenciePath), module.name]);
edges.push([basename(dependencyPath), module.name]);
});
nodes.push(module.name);

View File

@@ -13,9 +13,9 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Ajv from 'ajv';
import {Schema as JSONSchema} from 'jsonschema';
import {JSONSchema7 as JSONSchema} from 'json-schema';
import {join} from 'path';
import {DEFAULT_CONFIG, Definition, SchemaGenerator} from 'ts-json-schema-generator';
import {Config, DEFAULT_CONFIG, Definition, SchemaGenerator} from 'ts-json-schema-generator';
import {createFormatter} from 'ts-json-schema-generator/dist/factory/formatter';
import {createParser} from 'ts-json-schema-generator/dist/factory/parser';
import {createProgram} from 'ts-json-schema-generator/dist/factory/program';
@@ -45,13 +45,11 @@ export class Converter {
*/
constructor(path: string) {
// set config for schema generator
const config = {
const config: Config = {
...DEFAULT_CONFIG,
// expose: 'exported' as any,
// jsDoc: 'extended' as any,
path: join(getTsconfigPath(path), 'tsconfig.json'),
sortProps: true,
topRef: false,
tsconfig: join(getTsconfigPath(path), 'tsconfig.json'),
type: 'SC',
};
@@ -82,7 +80,7 @@ export class Converter {
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`;
schema.$id = `https://core.stapps.tu-berlin.de/v${version}/lib/schema/${type}.json`;
if (isSchemaWithDefinitions(schema)) {
const selfReference = {
@@ -92,7 +90,7 @@ export class Converter {
delete selfReference.$schema;
delete selfReference.definitions;
delete selfReference.id;
delete selfReference.$id;
// add self reference to definitions
schema.definitions[`SC${type}`] = {

View File

@@ -87,7 +87,7 @@ export async function createDiagram(
/**
* This will encode the plantuml code and post the code to the plantuml server
* The server will then parse the code and create a corresponding diagram
*
*
* @param modelPlantUMLCode raw PlantUML code
* @param plantUmlBaseURL PlantUML server address that shall be used
* @param outputFile filename of the output file without file extension
@@ -102,7 +102,7 @@ export async function createDiagramFromString(
const url = `${plantUmlBaseURL}/svg/${plantUMLCode}`;
let response;
try {
response = await request.get(url);
response = await request.default.get(url);
const httpOK = 200;
if (response.statusCode !== httpOK) {
await Logger.error(`Plantuml Server responded with an error.\n${response.statusMessage}`);

View File

@@ -15,9 +15,11 @@
import {Logger} from '@openstapps/logger';
import {
ArrayType,
ConditionalType,
DeclarationReflection,
IntrinsicType,
ProjectReflection,
QueryType,
ReferenceType,
ReflectionKind,
ReflectionType,
@@ -248,10 +250,43 @@ function readTypeInformation(declarationType: Type): LightweightType {
if (declarationType instanceof UnionType) {
return readAsUnionType(declarationType);
}
if (declarationType instanceof QueryType) {
return readAsQueryType(declarationType);
}
if (declarationType instanceof ConditionalType) {
return readAsConditionalType(declarationType);
}
throw new Error(`Could not read type ${declarationType.type}`);
}
/**
* Conversion method for ConditionalTypes
*
* @param _type Type to be converted
*/
function readAsConditionalType(_type: ConditionalType): LightweightType {
const returnType: LightweightType = new LightweightType();
returnType.specificationTypes = [];
returnType.name = getFullTypeName(returnType);
returnType.isUnion = true;
return returnType;
}
/**
* Conversion method for QueryTypes
*
* @param type Type to be converted
*/
function readAsQueryType(type: QueryType): LightweightType {
const out = readAsReferenceType(type.queryType);
out.isReference = true;
return out;
}
/**
* Conversion method for IntrinsicType's
*
@@ -315,10 +350,8 @@ function readAsReferenceType(type: ReferenceType): LightweightType {
// interfaces and classes in a type are a sink, since their declaration are defined elsewhere
if (
typeof tempTypeReflection.kindString !== 'undefined' &&
['Interface', 'Class', 'Enumeration', 'Type alias'].indexOf(
tempTypeReflection.kindString,
) > -1
) {
['Interface', 'Class', 'Enumeration', 'Type alias'].includes(
tempTypeReflection.kindString)) {
returnType.isReference = true;
}
}

View File

@@ -14,15 +14,20 @@
*/
import {asyncPool} from '@krlwlfrt/async-pool';
import {Logger} from '@openstapps/logger';
import Ajv from 'ajv';
import betterAjvErrors from 'better-ajv-errors';
import {PathLike} from 'fs';
import {Schema, Validator as JSONSchemaValidator, ValidatorResult} from 'jsonschema';
import {JSONSchema7} from 'json-schema';
import * as mustache from 'mustache';
import {basename, join, resolve} from 'path';
import {Schema} from 'ts-json-schema-generator';
import {
ExpectableValidationErrors,
ExpectedValidationErrors,
globPromisified,
isThingWithType,
readFilePromisified,
ValidationError,
ValidationResult,
writeFilePromisified,
} from './common';
@@ -30,21 +35,24 @@ import {
* StAppsCore validator
*/
export class Validator {
/**
* JSON Schema Validator
*/
private readonly ajv = Ajv({verbose: true, jsonPointers: true, extendRefs: true});
/**
* Map of schema names to schemas
*/
private readonly schemas: { [type: string]: Schema; } = {};
/**
* JSONSchema validator instance
* 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 readonly validator: JSONSchemaValidator;
/**
* Create a new validator
*/
constructor() {
this.validator = new JSONSchemaValidator();
private ajvValidateWrapper(schema: JSONSchema7, instance: unknown): ValidationResult {
return fromAjvResult(this.ajv.validate(schema, instance), schema, instance, this.ajv);
}
/**
@@ -65,13 +73,9 @@ export class Validator {
await asyncPool(2, schemaFiles, async (file: string) => {
// read schema file
const buffer = await readFilePromisified(file);
const schema = JSON.parse(buffer.toString());
// add schema to validator
this.validator.addSchema(schema);
// add schema to map
this.schemas[basename(file, '.json')] = schema;
this.schemas[basename(file, '.json')] = JSON.parse(buffer.toString());
Logger.info(`Added ${file} to validator.`);
});
@@ -85,17 +89,17 @@ export class Validator {
* @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): ValidatorResult {
public validate(instance: unknown, schema?: string | Schema): ValidationResult {
if (typeof schema === 'undefined') {
if (isThingWithType(instance)) {
// schema name can be infered from type string
// schema name can be inferred from type string
// tslint:disable-next-line: completed-docs
const schemaSuffix = (instance as { type: string; }).type.split(' ')
.map((part: string) => {
.map((part: string) => {
return part.substr(0, 1)
.toUpperCase() + part.substr(1);
.toUpperCase() + part.substr(1);
})
.join('');
.join('');
const schemaName = `SC${schemaSuffix}`;
return this.validate(instance, schemaName);
@@ -108,20 +112,61 @@ export class Validator {
throw new Error(`No schema available for ${schema}.`);
}
return this.validator.validate(instance, this.schemas[schema]);
// schema will be cached
return this.ajvValidateWrapper(this.schemas[schema], instance);
}
return this.validator.validate(instance, schema);
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<unknown>,
schema: JSONSchema7,
instance: unknown,
ajvInstance: Ajv.Ajv,
): ValidationResult {
// tslint:disable-next-line
// @ts-ignore function can return void, which at runtime will be undefined. TS doesn't allow to assign void to undefined
const betterErrorObject: betterAjvErrors.IOutputError[] | undefined =
betterAjvErrors(schema, instance, ajvInstance.errors, {format: 'js', indent: null});
return {
errors: ajvInstance.errors?.map((ajvError, index) => {
const error: ValidationError = {
dataPath: ajvError.dataPath,
instance: instance,
message: betterErrorObject?.[index].error!,
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 schemaDir The directory where the JSON schema files are
* @param resourcesDir The directory where the test files are
*/
export async function validateFiles(schemaDir: string, resourcesDir: string): Promise<ExpectableValidationErrors> {
export async function validateFiles(schemaDir: string, resourcesDir: string): Promise<ExpectedValidationErrors> {
// instantiate new validator
const v = new Validator();
await v.addSchemas(schemaDir);
@@ -136,7 +181,7 @@ export async function validateFiles(schemaDir: string, resourcesDir: string): Pr
Logger.log(`Found ${testFiles.length} file(s) to test.`);
// map of errors per file
const errors: ExpectableValidationErrors = {};
const errors: ExpectedValidationErrors = {};
// tslint:disable-next-line:no-magic-numbers - iterate over files to test
await asyncPool(2, testFiles, async (testFile: string) => {
@@ -162,13 +207,11 @@ export async function validateFiles(schemaDir: string, resourcesDir: string): Pr
// iterate over errors
for (const error of result.errors) {
// get idx of expected error
const errorIdx = expectedErrors.indexOf(error.name);
const errorIndex = expectedErrors.indexOf(error.name);
let expected = false;
if (errorIdx >= 0) {
// remove from list of expected errors
expectedErrors.splice(errorIdx, 1);
if (errorIndex >= 0) {
expectedErrors.splice(errorIndex, 1);
expected = true;
} else {
unexpectedErrors++;
@@ -188,14 +231,14 @@ export async function validateFiles(schemaDir: string, resourcesDir: string): Pr
await Logger.error(`Extraneous expected error '${error}' in ${testFile}.`);
errors[testFileName].push({
argument: false,
dataPath: 'undefined',
expected: false,
instance: testDescription.instance,
message: `expected error ${error} did not occur`,
instance: undefined,
// instance: testDescription.instance,
message: 'undefined',
name: `expected ${error}`,
property: 'unknown',
schema: 'undefined',
stack: 'undefined',
schemaPath: 'undefined',
suggestion: 'undefined',
});
}
} else if (unexpectedErrors === 0) {
@@ -212,7 +255,7 @@ export async function validateFiles(schemaDir: string, resourcesDir: string): Pr
* @param reportPath Path to write report to
* @param errors Errors that occurred in validation
*/
export async function writeReport(reportPath: PathLike, errors: ExpectableValidationErrors): Promise<void> {
export async function writeReport(reportPath: PathLike, errors: ExpectedValidationErrors): Promise<void> {
let buffer = await readFilePromisified(resolve(__dirname, '..', 'resources', 'file.html.mustache'));
const fileTemplate = buffer.toString();
@@ -229,15 +272,16 @@ export async function writeReport(reportPath: PathLike, errors: ExpectableValida
let fileOutput = '';
errors[fileName].forEach((error, idx) => {
fileOutput += mustache.render(errorTemplate, {
idx: idx + 1,
// tslint:disable-next-line:no-magic-numbers
instance: JSON.stringify(error.instance, null, 2),
message: error.message,
property: error.property,
// tslint:disable-next-line:no-magic-numbers
schema: JSON.stringify(error.schema, null, 2),
name: error.name,
schemaPath: error.schemaPath,
status: (error.expected) ? 'alert-success' : 'alert-danger',
suggestion: error.suggestion,
});
});

View File

@@ -73,11 +73,11 @@ export class CreateDiagramSpec {
let fileName = await createDiagram(this.definitions, this.plantUmlConfig, "http://plantuml:8080");
let filePath = resolve(__dirname, '..', fileName);
expect(await existsSync(filePath)).to.equal(true);
await unlinkSync(fileName);
this.plantUmlConfig.showAssociations = false;
this.plantUmlConfig.showInheritance = false;
this.plantUmlConfig.showInheritance = false;
fileName = await createDiagram(this.definitions, this.plantUmlConfig, "http://plantuml:8080");
filePath = resolve(__dirname, '..', fileName);
expect(await existsSync(filePath)).to.equal(true);

View File

@@ -22,17 +22,21 @@ import {ElasticsearchDataType} from '../../../../src/mappings/definitions/typema
* @indexable
*/
export interface ObjectUnion {
foo: Bar | Baz;
foo: Boo | Buu;
type: ThingType.ObjectUnion
}
interface Bar {
// we can't name them Bar or Baz, look here for more info:
// https://gitlab.com/openstapps/core-tools/-/issues/48
// or here
// https://github.com/TypeStrong/typedoc/issues/1373
interface Boo {
a: boolean;
intersection: string;
}
interface Baz {
interface Buu {
b: number;
intersection: string;
}

View File

@@ -27,7 +27,6 @@ import {genericTest} from './mapping-model/mappings/src/generics';
import {nestedTest} from './mapping-model/mappings/src/nested';
import {indexSignatureTest} from './mapping-model/mappings/src/index-signature';
import {impossibleUnionTest} from './mapping-model/mappings/src/impossible-union';
import {typeQueryTest} from './mapping-model/mappings/src/type-query';
import {objectUnionTest} from './mapping-model/mappings/src/object-union';
import {sortableTagTest} from './mapping-model/mappings/src/sortable-tag';
import {enumTest} from './mapping-model/mappings/src/enum';
@@ -91,10 +90,12 @@ export class MappingSpec {
magAppInstance.testInterfaceAgainstPath(objectUnionTest);
}
/*
https://gitlab.com/openstapps/core-tools/-/issues/47
@test
async 'Type queries should work'() {
magAppInstance.testInterfaceAgainstPath(typeQueryTest);
}
}*/
@test
async 'Impossible union should cause an error'() {

View File

@@ -16,9 +16,7 @@ import {LightweightClassDefinition} from '../../src/uml/model/lightweight-class-
import {LightweightDefinition} from '../../src/uml/model/lightweight-definition';
import {LightweightEnumDefinition} from '../../src/uml/model/lightweight-enum-definition';
export const generatedModel: Array<
LightweightDefinition | LightweightClassDefinition | LightweightEnumDefinition
> = [
export const generatedModel: Array<LightweightDefinition | LightweightClassDefinition | LightweightEnumDefinition> = [
{
name: 'TestClass',
type: 'class',
@@ -73,7 +71,7 @@ export const generatedModel: Array<
{
name: 'test2',
optional: false,
inherited: true,
inherited: true,
type: {
hasTypeInformation: true,
isArray: false,
@@ -92,7 +90,7 @@ export const generatedModel: Array<
{
name: 'test4',
optional: false,
inherited: true,
inherited: true,
type: {
hasTypeInformation: true,
isArray: false,
@@ -169,42 +167,13 @@ export const generatedModel: Array<
isLiteral: false,
isPrimitive: false,
isReference: false,
isReflection: false,
isReflection: true,
isTyped: false,
isTypeParameter: false,
isUnion: true,
specificationTypes: [
{
hasTypeInformation: true,
isArray: false,
isLiteral: false,
isPrimitive: true,
isReference: false,
isReflection: false,
isTyped: false,
isTypeParameter: false,
isUnion: false,
specificationTypes: [],
genericsTypes: [],
name: 'undefined',
},
{
hasTypeInformation: false,
isArray: false,
isLiteral: false,
isPrimitive: false,
isReference: false,
isReflection: true,
isTyped: false,
isTypeParameter: false,
isUnion: false,
specificationTypes: [],
genericsTypes: [],
name: 'object',
},
],
isUnion: false,
specificationTypes: [],
genericsTypes: [],
name: '',
name: 'object',
},
},
{
@@ -279,47 +248,18 @@ export const generatedModel: Array<
optional: true,
inherited: false,
type: {
hasTypeInformation: false,
hasTypeInformation: true,
isArray: false,
isLiteral: false,
isPrimitive: false,
isPrimitive: true,
isReference: false,
isReflection: false,
isTyped: false,
isTypeParameter: false,
isUnion: true,
specificationTypes: [
{
hasTypeInformation: true,
isArray: false,
isLiteral: false,
isPrimitive: true,
isReference: false,
isReflection: false,
isTyped: false,
isTypeParameter: false,
isUnion: false,
specificationTypes: [],
genericsTypes: [],
name: 'undefined',
},
{
hasTypeInformation: true,
isArray: false,
isLiteral: false,
isPrimitive: true,
isReference: false,
isReflection: false,
isTyped: false,
isTypeParameter: false,
isUnion: false,
specificationTypes: [],
genericsTypes: [],
name: 'number',
},
],
isUnion: false,
specificationTypes: [],
genericsTypes: [],
name: '',
name: 'number',
},
},
{
@@ -506,7 +446,7 @@ export const generatedModel: Array<
isArray: false,
isLiteral: false,
isPrimitive: false,
isReference: false,
isReference: true,
isReflection: false,
isTyped: false,
isTypeParameter: false,

View File

@@ -33,7 +33,8 @@ export class SchemaSpec {
const schema = converter.getSchema('Foo', '0.0.1');
expect(schema).to.be.deep.equal({
$schema: 'http://json-schema.org/draft-06/schema#',
$id: 'https://core.stapps.tu-berlin.de/v0.0.1/lib/schema/Foo.json',
$schema: 'http://json-schema.org/draft-07/schema#',
additionalProperties: false,
definitions: {
FooType: {
@@ -67,7 +68,6 @@ export class SchemaSpec {
},
},
description: 'This is a simple interface declaration for\ntesting the schema generation and validation.',
id: 'https://core.stapps.tu-berlin.de/v0.0.1/lib/schema/Foo.json',
properties: {
lorem: {
description: 'Dummy parameter',

View File

@@ -15,7 +15,7 @@
import {Logger} from '@openstapps/logger';
import {expect} from 'chai';
import {existsSync, mkdirSync, writeFileSync} from 'fs';
import {Schema} from 'jsonschema';
import {JSONSchema7 as Schema} from 'json-schema';
import {slow, suite, test, timeout} from 'mocha-typescript';
import {join} from 'path';
import rimraf from 'rimraf';