/* * Copyright (C) 2018, 2019 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 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 {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 * * 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, skipTypeCheck: true, 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}}); } /** * Get schema for specific StAppsCore type * @param type Type to get the schema for * @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!`); } return schema; } } /** * Get a list of validatable types from an API extractor file */ export function getValidatableTypesInPath(path: string): string[] { return Object.values(definitionsOf(lightweightProjectFromPath(path))) .filter(type => !!type.comment?.tags?.find(it => it.name === 'validatable')) .map(type => type.name); }