feat: migrate to esm

This commit is contained in:
2023-03-16 01:58:13 +01:00
parent fd740b3091
commit 4df19e8c20
512 changed files with 3016 additions and 2222 deletions

View File

@@ -0,0 +1,26 @@
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 <S, T, Options extends IInputOptions>(
schema: S,
data: T,
errors: Array<ErrorObject>,
options?: Options
): Options extends { format: 'js' } ? Array<IOutputError> : string;
}

View File

@@ -17,16 +17,17 @@ import {Command} from 'commander';
import {existsSync, readFileSync, writeFileSync} from 'fs';
import {copy} from 'fs-extra';
import path from 'path';
import {mkdirPromisified, readFilePromisified} from './common';
import {lightweightDefinitionsFromPath, lightweightProjectFromPath} from './easy-ast/easy-ast';
import {pack} from './pack';
import {openapi3Template} from './resources/openapi-303-template';
import {gatherRouteInformation, generateOpenAPIForRoute} from './routes';
import {Converter, getValidatableTypesInPath} from './schema';
import {createDiagram, createDiagramFromString} from './uml/create-diagram';
import {UMLConfig} from './uml/uml-config';
import {capitalize} from './util/string';
import {validateFiles, writeReport} from './validate';
import {mkdirPromisified, readFilePromisified} from './common.js';
import {lightweightDefinitionsFromPath, lightweightProjectFromPath} from './easy-ast/easy-ast.js';
import {pack} from './pack.js';
import {openapi3Template} from './resources/openapi-303-template.js';
import {gatherRouteInformation, generateOpenAPIForRoute} from './routes.js';
import {Converter, getValidatableTypesInPath} 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";
// handle unhandled promise rejections
process.on('unhandledRejection', async (reason: unknown) => {
@@ -40,7 +41,7 @@ process.on('unhandledRejection', async (reason: unknown) => {
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.version(JSON.parse(readFileSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json')).toString()).version);
commander.command('prototype <srcBundle> <out>').action(async (sourcePath, out) => {
const files = lightweightProjectFromPath(sourcePath);

View File

@@ -14,12 +14,12 @@
*/
import {Logger} from '@openstapps/logger';
import {existsSync, mkdir, readFile, unlink, writeFile} from 'fs';
import {Glob} from 'glob';
import glob from 'glob';
import {platform} from 'os';
import {promisify} from 'util';
import path from 'path';
export const globPromisified = promisify(Glob);
export const globPromisified = promisify(glob.Glob);
export const mkdirPromisified = promisify(mkdir);
export const readFilePromisified = promisify(readFile);
export const writeFilePromisified = promisify(writeFile);

View File

@@ -12,34 +12,9 @@
* 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 {
ArrayTypeNode,
ClassDeclaration,
ClassElement,
EnumDeclaration,
Identifier,
InterfaceDeclaration,
isArrayTypeNode,
isClassDeclaration,
isComputedPropertyName,
isEnumDeclaration,
isInterfaceDeclaration,
isPropertyDeclaration,
isPropertySignature,
isTypeAliasDeclaration,
isTypeReferenceNode,
NodeArray,
PropertyDeclaration,
PropertyName,
PropertySignature,
TypeAliasDeclaration,
TypeElement,
TypeNode,
TypeReferenceNode,
} from 'typescript';
import * as ts from 'typescript';
import {cleanupEmpty} from '../util/collections';
import {LightweightComment} from './types/lightweight-comment';
import {cleanupEmpty} from '../util/collections.js';
import {LightweightComment} from './types/lightweight-comment.js';
/** @internal */
export function extractComment(node: ts.Node): LightweightComment | undefined {
@@ -70,14 +45,14 @@ export function extractComment(node: ts.Node): LightweightComment | undefined {
/** @internal */
export function isProperty(
node: ClassElement | TypeElement,
): node is PropertyDeclaration | PropertySignature {
return isPropertyDeclaration(node) || isPropertySignature(node);
node: ts.ClassElement | ts.TypeElement,
): node is ts.PropertyDeclaration | ts.PropertySignature {
return ts.isPropertyDeclaration(node) || ts.isPropertySignature(node);
}
/** @internal */
export function filterNodeTo<T extends ts.Node, S extends T>(
node: NodeArray<T>,
node: ts.NodeArray<T>,
check: (node: T) => node is S,
): S[] {
return node.filter(check);
@@ -107,36 +82,36 @@ export function getModifiers(text: string, kind: string): string[] {
}
/** @internal */
export function resolvePropertyName(name?: PropertyName): string | undefined {
export function resolvePropertyName(name?: ts.PropertyName): string | undefined {
return name === undefined
? undefined
: isComputedPropertyName(name)
: ts.isComputedPropertyName(name)
? 'UNSUPPORTED_IDENTIFIER_TYPE'
: name.getText();
}
/** @internal */
export function resolveTypeName(type?: TypeNode): string | undefined {
export function resolveTypeName(type?: ts.TypeNode): string | undefined {
// @ts-expect-error typeName exists in reality
return type?.typeName?.escapedText ?? type?.typeName?.right?.escapedText;
}
/** @internal */
export function isArrayLikeType(typeNode?: TypeNode): typeNode is ArrayTypeNode | TypeReferenceNode {
return typeNode !== undefined && (isArrayTypeNode(typeNode) || isArrayReference(typeNode));
export function isArrayLikeType(typeNode?: ts.TypeNode): typeNode is ts.ArrayTypeNode | ts.TypeReferenceNode {
return typeNode !== undefined && (ts.isArrayTypeNode(typeNode) || isArrayReference(typeNode));
}
/** @internal */
export function isArrayReference(typeNode: TypeNode): boolean {
return isTypeReferenceNode(typeNode) && (typeNode.typeName as Identifier).escapedText === 'Array';
export function isArrayReference(typeNode: ts.TypeNode): boolean {
return ts.isTypeReferenceNode(typeNode) && (typeNode.typeName as ts.Identifier).escapedText === 'Array';
}
/** @internal */
export function isClassLikeNode(node: ts.Node): node is ClassDeclaration | InterfaceDeclaration {
return isClassDeclaration(node) || isInterfaceDeclaration(node);
export function isClassLikeNode(node: ts.Node): node is ts.ClassDeclaration | ts.InterfaceDeclaration {
return ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node);
}
/** @internal */
export function isEnumLikeNode(node: ts.Node): node is EnumDeclaration | TypeAliasDeclaration {
return isEnumDeclaration(node) || isTypeAliasDeclaration(node);
export function isEnumLikeNode(node: ts.Node): node is ts.EnumDeclaration | ts.TypeAliasDeclaration {
return ts.isEnumDeclaration(node) || ts.isTypeAliasDeclaration(node);
}

View File

@@ -13,14 +13,14 @@
* 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 {TypeFlags} from 'typescript';
import {LightweightAliasDefinition} from './types/lightweight-alias-definition';
import {LightweightClassDefinition} from './types/lightweight-class-definition';
import {LightweightDefinition} from './types/lightweight-definition';
import {LightweightDefinitionKind} from './types/lightweight-definition-kind';
import {LightweightProject} from './types/lightweight-project';
import {LightweightType} from './types/lightweight-type';
import {keyBy} from "@openstapps/collection-utils/lib/key-by";
import ts from 'typescript';
import {LightweightAliasDefinition} from './types/lightweight-alias-definition.js';
import {LightweightClassDefinition} from './types/lightweight-class-definition.js';
import {LightweightDefinition} from './types/lightweight-definition.js';
import {LightweightDefinitionKind} from './types/lightweight-definition-kind.js';
import {LightweightProject} from './types/lightweight-project.js';
import {LightweightType} from './types/lightweight-type.js';
import {keyBy} from "@openstapps/collection-utils/lib/key-by.js";
/**
* Creates a printable name of a type
@@ -46,28 +46,28 @@ export function definitionsOf(project: LightweightProject): Record<string, Light
return keyBy(Object.values(project).flatMap(Object.values), it => it.name);
}
export function isPrimitiveType(type: {flags: TypeFlags}): boolean {
return (type.flags & TypeFlags.NonPrimitive) === 0;
export function isPrimitiveType(type: { flags: ts.TypeFlags }): boolean {
return (type.flags & ts.TypeFlags.NonPrimitive) === 0;
}
export function isLiteralType(type: {flags: TypeFlags}): boolean {
return (type.flags & TypeFlags.Literal) !== 0;
export function isLiteralType(type: { flags: ts.TypeFlags }): boolean {
return (type.flags & ts.TypeFlags.Literal) !== 0;
}
export function isEnumLiteralType(type: {flags: TypeFlags}): boolean {
return (type.flags & TypeFlags.EnumLiteral) !== 0;
export function isEnumLiteralType(type: { flags: ts.TypeFlags }): boolean {
return (type.flags & ts.TypeFlags.EnumLiteral) !== 0;
}
export function isStringLiteralType(type: {flags: TypeFlags}): boolean {
return (type.flags & TypeFlags.StringLiteral) !== 0;
export function isStringLiteralType(type: { flags: ts.TypeFlags }): boolean {
return (type.flags & ts.TypeFlags.StringLiteral) !== 0;
}
export function isUnionOrIntersectionType(type: {flags: TypeFlags}): boolean {
return (type.flags & TypeFlags.UnionOrIntersection) !== 0;
export function isUnionOrIntersectionType(type: { flags: ts.TypeFlags }): boolean {
return (type.flags & ts.TypeFlags.UnionOrIntersection) !== 0;
}
export function isUnionType(type: {flags: TypeFlags}): boolean {
return (type.flags & TypeFlags.Union) !== 0;
export function isUnionType(type: { flags: ts.TypeFlags }): boolean {
return (type.flags & ts.TypeFlags.Union) !== 0;
}
export function isLightweightClass(node?: LightweightDefinition): node is LightweightClassDefinition {
@@ -78,6 +78,6 @@ export function isLightweightEnum(node?: LightweightDefinition): node is Lightwe
return node?.kind === LightweightDefinitionKind.ALIAS_LIKE;
}
export function isTypeVariable(type: {flags: TypeFlags}): boolean {
return (type.flags & TypeFlags.TypeVariable) !== 0;
export function isTypeVariable(type: { flags: ts.TypeFlags }): boolean {
return (type.flags & ts.TypeFlags.TypeVariable) !== 0;
}

View File

@@ -13,33 +13,9 @@
* 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 * as ts from 'typescript';
import {
ClassDeclaration,
ClassElement,
EnumDeclaration,
InterfaceDeclaration,
isArrayTypeNode,
isClassDeclaration,
isEnumDeclaration,
isIndexSignatureDeclaration,
isPropertyDeclaration,
isTypeLiteralNode,
isTypeReferenceNode,
NodeArray,
Program,
SourceFile,
SyntaxKind,
Type,
TypeAliasDeclaration,
TypeChecker,
TypeElement,
TypeFlags,
TypeLiteralNode,
TypeNode,
} from 'typescript';
import {cleanupEmpty, mapNotNil, rejectNil} from '../util/collections';
import {expandPathToFilesSync} from '../util/io';
import ts from 'typescript';
import {cleanupEmpty, mapNotNil, rejectNil} from '../util/collections.js';
import {expandPathToFilesSync} from '../util/io.js';
import {
extractComment,
filterChildrenTo,
@@ -51,19 +27,19 @@ import {
isProperty,
resolvePropertyName,
resolveTypeName,
} from './ast-internal-util';
import {isEnumLiteralType, isTypeVariable} from './ast-util';
import {LightweightAliasDefinition} from './types/lightweight-alias-definition';
import {LightweightClassDefinition} from './types/lightweight-class-definition';
import {LightweightDefinition} from './types/lightweight-definition';
import {LightweightDefinitionKind} from './types/lightweight-definition-kind';
import {LightweightProject} from './types/lightweight-project';
import {LightweightType} from './types/lightweight-type';
} from './ast-internal-util.js';
import {isEnumLiteralType, isTypeVariable} from './ast-util.js';
import {LightweightAliasDefinition} from './types/lightweight-alias-definition.js';
import {LightweightClassDefinition} from './types/lightweight-class-definition.js';
import {LightweightDefinition} from './types/lightweight-definition.js';
import {LightweightDefinitionKind} from './types/lightweight-definition-kind.js';
import {LightweightProject} from './types/lightweight-project.js';
import {LightweightType} from './types/lightweight-type.js';
import path from 'path';
import {LightweightProperty} from './types/lightweight-property';
import {mapValues} from "@openstapps/collection-utils/lib/map-values";
import {groupBy} from "@openstapps/collection-utils/lib/group-by";
import {keyBy} from "@openstapps/collection-utils/lib/key-by";
import {LightweightProperty} from './types/lightweight-property.js';
import {mapValues} from "@openstapps/collection-utils/lib/map-values.js";
import {groupBy} from "@openstapps/collection-utils/lib/group-by.js";
import {keyBy} from "@openstapps/collection-utils/lib/key-by.js";
/**
* Convert a TypeScript project to a lightweight Type-AST representation of the project
@@ -95,11 +71,11 @@ export function lightweightDefinitionsFromPath(
* Reads the reflection model and converts it into a flatter, easier to handle model
*/
class LightweightDefinitionBuilder {
readonly program: Program;
readonly program: ts.Program;
readonly sourceFiles: readonly SourceFile[];
readonly sourceFiles: readonly ts.SourceFile[];
readonly typeChecker: TypeChecker;
readonly typeChecker: ts.TypeChecker;
constructor(sourcePath: string | string[], readonly includeComments: boolean) {
const rootNames = Array.isArray(sourcePath)
@@ -125,13 +101,13 @@ class LightweightDefinitionBuilder {
this.sourceFiles = mapNotNil(this.program.getRootFileNames(), it => this.program.getSourceFile(it));
}
private convertAliasLike(enumLike: EnumDeclaration | TypeAliasDeclaration): LightweightAliasDefinition {
private convertAliasLike(enumLike: ts.EnumDeclaration | ts.TypeAliasDeclaration): LightweightAliasDefinition {
return cleanupEmpty({
comment: this.includeComments ? extractComment(enumLike) : undefined,
name: enumLike.name.getText() ?? 'ERROR',
kind: LightweightDefinitionKind.ALIAS_LIKE,
modifiers: getModifiers(enumLike.getText(), isEnumDeclaration(enumLike) ? 'enum' : 'type'),
type: isEnumDeclaration(enumLike)
modifiers: getModifiers(enumLike.getText(), ts.isEnumDeclaration(enumLike) ? 'enum' : 'type'),
type: ts.isEnumDeclaration(enumLike)
? enumLike.members.length > 0
? {
flags: 1_048_576,
@@ -142,7 +118,7 @@ class LightweightDefinitionBuilder {
});
}
private convertClassLike(classLike: ClassDeclaration | InterfaceDeclaration): LightweightClassDefinition {
private convertClassLike(classLike: ts.ClassDeclaration | ts.InterfaceDeclaration): LightweightClassDefinition {
const heritages = mapValues(
groupBy([...(classLike.heritageClauses!)], it => it.token.toString()),
heritages => heritages.flatMap(it => it.types),
@@ -152,15 +128,15 @@ class LightweightDefinitionBuilder {
comment: this.includeComments ? extractComment(classLike) : undefined,
name: classLike.name?.escapedText ?? 'ERROR',
kind: LightweightDefinitionKind.CLASS_LIKE,
modifiers: getModifiers(classLike.getText(), isClassDeclaration(classLike) ? 'class' : 'interface'),
modifiers: getModifiers(classLike.getText(), ts.isClassDeclaration(classLike) ? 'class' : 'interface'),
extendedDefinitions: heritages[ts.SyntaxKind.ExtendsKeyword]?.map(it => this.lightweightTypeAtNode(it)),
implementedDefinitions: heritages[ts.SyntaxKind.ImplementsKeyword]?.map(it =>
this.lightweightTypeAtNode(it),
),
indexSignatures: keyBy(
filterNodeTo(
classLike.members as NodeArray<ClassElement | TypeElement>,
isIndexSignatureDeclaration,
classLike.members as ts.NodeArray<ts.ClassElement | ts.TypeElement>,
ts.isIndexSignatureDeclaration,
).map(indexSignature =>
cleanupEmpty({
name:
@@ -183,15 +159,15 @@ class LightweightDefinitionBuilder {
});
}
collectProperties(members: NodeArray<ClassElement | TypeElement>): Record<string, LightweightProperty> {
collectProperties(members: ts.NodeArray<ts.ClassElement | ts.TypeElement>): Record<string, LightweightProperty> {
return keyBy(
filterNodeTo(members as NodeArray<ClassElement | TypeElement>, isProperty).map(property =>
filterNodeTo(members as ts.NodeArray<ts.ClassElement | ts.TypeElement>, isProperty).map(property =>
cleanupEmpty({
comment: this.includeComments ? extractComment(property) : undefined,
name: resolvePropertyName(property.name) ?? property.getText(),
type: this.lightweightTypeAtNode(property),
properties: this.collectProperties((property.type as TypeLiteralNode)?.members),
optional: isPropertyDeclaration(property)
properties: this.collectProperties((property.type as ts.TypeLiteralNode)?.members),
optional: ts.isPropertyDeclaration(property)
? property.questionToken === undefined
? undefined
: true
@@ -208,12 +184,12 @@ class LightweightDefinitionBuilder {
return this.lightweightTypeFromType(type, this.typeChecker.typeToTypeNode(type, node, undefined));
}
private lightweightTypeFromType(type: ts.Type, typeNode?: TypeNode): LightweightType {
if (typeNode?.kind === SyntaxKind.ConditionalType) {
return {value: 'UNSUPPORTED_CONDITIONAL_TYPE', flags: TypeFlags.Unknown};
private lightweightTypeFromType(type: ts.Type, typeNode?: ts.TypeNode): LightweightType {
if (typeNode?.kind === ts.SyntaxKind.ConditionalType) {
return {value: 'UNSUPPORTED_CONDITIONAL_TYPE', flags: ts.TypeFlags.Unknown};
}
if (isArrayLikeType(typeNode)) {
const elementType = isArrayTypeNode(typeNode) ? typeNode.elementType : typeNode.typeArguments?.[0]!;
const elementType = ts.isArrayTypeNode(typeNode) ? typeNode.elementType : typeNode.typeArguments?.[0]!;
const out = this.lightweightTypeFromType(
this.typeChecker.getTypeFromTypeNode(elementType),
elementType,
@@ -222,8 +198,8 @@ class LightweightDefinitionBuilder {
return out;
}
const isReference = typeNode !== undefined && isTypeReferenceNode(typeNode) && !isEnumLiteralType(type);
const isTypeLiteral = typeNode !== undefined && isTypeLiteralNode(typeNode);
const isReference = typeNode !== undefined && ts.isTypeReferenceNode(typeNode) && !isEnumLiteralType(type);
const isTypeLiteral = typeNode !== undefined && ts.isTypeLiteralNode(typeNode);
// @ts-expect-error intrinsic name & value exist
const intrinsicName = (type.intrinsicName ?? type.value) as string | undefined;
@@ -239,7 +215,7 @@ class LightweightDefinitionBuilder {
.getApparentType(type)
// @ts-expect-error resolvedTypeArguments exits
?.resolvedTypeArguments?.filter(it => !it.isThisType)
?.map((it: Type) => this.lightweightTypeFromType(it)),
?.map((it: ts.Type) => this.lightweightTypeFromType(it)),
specificationTypes:
type.isUnionOrIntersection() && !isReference
? type.types.map(it =>

View File

@@ -13,9 +13,9 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {LightweightDefinitionBase} from './lightweight-definition';
import {LightweightDefinitionKind} from './lightweight-definition-kind';
import {LightweightType} from './lightweight-type';
import {LightweightDefinitionBase} from './lightweight-definition.js';
import {LightweightDefinitionKind} from './lightweight-definition-kind.js';
import {LightweightType} from './lightweight-type.js';
/**
* Represents an enum definition
*/

View File

@@ -13,10 +13,10 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {LightweightDefinitionBase} from './lightweight-definition';
import {LightweightDefinitionKind} from './lightweight-definition-kind';
import {LightweightIndexSignature, LightweightProperty} from './lightweight-property';
import {LightweightType} from './lightweight-type';
import {LightweightDefinitionBase} from './lightweight-definition.js';
import {LightweightDefinitionKind} from './lightweight-definition-kind.js';
import {LightweightIndexSignature, LightweightProperty} from './lightweight-property.js';
import {LightweightType} from './lightweight-type.js';
/**
* Represents a class definition

View File

@@ -12,10 +12,10 @@
* 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 {LightweightDefinitionKind} from './lightweight-definition-kind';
import {LightweightComment} from './lightweight-comment';
import {LightweightClassDefinition} from './lightweight-class-definition';
import {LightweightAliasDefinition} from './lightweight-alias-definition';
import {LightweightDefinitionKind} from './lightweight-definition-kind.js';
import {LightweightComment} from './lightweight-comment.js';
import {LightweightClassDefinition} from './lightweight-class-definition.js';
import {LightweightAliasDefinition} from './lightweight-alias-definition.js';
export type LightweightDefinition = LightweightClassDefinition | LightweightAliasDefinition;

View File

@@ -12,11 +12,11 @@
* 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 {mapNotNil} from '../../util/collections';
import {definitionsOf, isLightweightClass} from '../ast-util';
import {lightweightProjectFromPath} from '../easy-ast';
import {LightweightClassDefinition} from './lightweight-class-definition';
import {LightweightDefinition} from './lightweight-definition';
import {mapNotNil} from '../../util/collections.js';
import {definitionsOf, isLightweightClass} from '../ast-util.js';
import {lightweightProjectFromPath} from '../easy-ast.js';
import {LightweightClassDefinition} from './lightweight-class-definition.js';
import {LightweightDefinition} from './lightweight-definition.js';
/**
* Build an index for a lightweight project

View File

@@ -12,8 +12,8 @@
* 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 {LightweightComment} from './lightweight-comment';
import {LightweightType} from './lightweight-type';
import {LightweightComment} from './lightweight-comment.js';
import {LightweightType} from './lightweight-type.js';
/**
* Represents a property definition

View File

@@ -17,8 +17,8 @@ import {Logger} from '@openstapps/logger';
import del from 'del';
import {existsSync} from 'fs';
import {cwd} from 'process';
import {globPromisified, readFilePromisified, unlinkPromisified, writeFilePromisified} from './common';
import {JavaScriptModule} from './types/pack';
import {globPromisified, readFilePromisified, unlinkPromisified, writeFilePromisified} from './common.js';
import {JavaScriptModule} from './types/pack.js';
import path from 'path';
const PACK_IDENTIFIER = '/* PACKED BY @openstapps/pack */';

View File

@@ -12,15 +12,14 @@
* 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 {assign, filter, map} from 'lodash';
import {OpenAPIV3} from 'openapi-types';
import {isLightweightClass} from './easy-ast/ast-util';
import {LightweightProjectWithIndex} from './easy-ast/types/lightweight-project';
import {RouteInstanceWithMeta, RouteWithMetaInformation} from './types/routes';
import {rejectNil} from './util/collections';
import {capitalize} from './util/string';
import {isLightweightClass} from './easy-ast/ast-util.js';
import {LightweightProjectWithIndex} from './easy-ast/types/lightweight-project.js';
import {RouteInstanceWithMeta, RouteWithMetaInformation} from './types/routes.js';
import {rejectNil} from './util/collections.js';
import {capitalize} from './util/string.js';
import path from 'path';
import {lightweightProjectFromPath} from './easy-ast/easy-ast';
import {lightweightProjectFromPath} from './easy-ast/easy-ast.js';
/**
* Gather relevant information of routes
@@ -34,7 +33,7 @@ export async function gatherRouteInformation(path: string): Promise<RouteWithMet
// find all classes that implement the SCAbstractRoute
return rejectNil(
await Promise.all(
map(filter(project.definitions, isLightweightClass), async node => {
Object.values(project.definitions).filter(isLightweightClass).map(async node => {
if (!node.extendedDefinitions?.some(it => it.referenceName === 'SCAbstractRoute')) {
return undefined;
}
@@ -47,7 +46,7 @@ export async function gatherRouteInformation(path: string): Promise<RouteWithMet
// eslint-disable-next-line @typescript-eslint/no-explicit-any
instantiatedRoute.errorNames.map(async (error: any) =>
// eslint-disable-next-line @typescript-eslint/ban-types
assign((await project.instantiateDefinitionByName(error.name)) as object, {name: error.name}),
Object.assign((await project.instantiateDefinitionByName(error.name)) as object, {name: error.name}),
),
);
instantiatedRoute.responseBodyDescription =

View File

@@ -14,17 +14,16 @@
*/
import Ajv from 'ajv';
import {JSONSchema7 as JSONSchema} from 'json-schema';
import {chain} from 'lodash';
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';
import {getTsconfigPath} from './common';
import {definitionsOf} from './easy-ast/ast-util';
import {lightweightProjectFromPath} from './easy-ast/easy-ast';
import {isSchemaWithDefinitions} from './util/guards';
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} from './easy-ast/ast-util.js';
import {lightweightProjectFromPath} from './easy-ast/easy-ast.js';
import {isSchemaWithDefinitions} from './util/guards.js';
import path from 'path';
import re2 from './types/re2';
import re2 from './types/re2.js';
/**
* StAppsCore converter
@@ -40,7 +39,7 @@ export class Converter {
/**
* Schema validator instance
*/
private readonly schemaValidator: Ajv;
private readonly schemaValidator: Ajv.default;
/**
* Create a new converter
@@ -66,9 +65,7 @@ export class Converter {
this.generator = new SchemaGenerator(program, createParser(program, config), createFormatter(config));
// create Ajv instance
this.schemaValidator = new Ajv({code: {regExp: re2}});
// eslint-disable-next-line @typescript-eslint/no-var-requires,unicorn/prefer-module
this.schemaValidator.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json'));
this.schemaValidator = new Ajv.default({code: {regExp: re2}});
}
/**
@@ -112,8 +109,7 @@ export class Converter {
* Get a list of validatable types from an API extractor file
*/
export function getValidatableTypesInPath(path: string): string[] {
return chain(definitionsOf(lightweightProjectFromPath(path)))
return Object.values(definitionsOf(lightweightProjectFromPath(path)))
.filter(type => !!type.comment?.tags?.find(it => it.name === 'validatable'))
.map(type => type.name)
.value();
}

View File

@@ -15,14 +15,13 @@
import {Logger} from '@openstapps/logger';
import {createWriteStream} from 'fs';
import * as request from 'got';
import {forEach, map, isEmpty} from 'lodash';
import {expandTypeValue, isLightweightClass, isUnionOrIntersectionType} from '../easy-ast/ast-util';
import {LightweightAliasDefinition} from '../easy-ast/types/lightweight-alias-definition';
import {LightweightClassDefinition} from '../easy-ast/types/lightweight-class-definition';
import {LightweightDefinition} from '../easy-ast/types/lightweight-definition';
import {LightweightProperty} from '../easy-ast/types/lightweight-property';
import {LightweightType} from '../easy-ast/types/lightweight-type';
import {UMLConfig} from './uml-config';
import {expandTypeValue, isLightweightClass} from '../easy-ast/ast-util.js';
import {LightweightAliasDefinition} from '../easy-ast/types/lightweight-alias-definition.js';
import {LightweightClassDefinition} from '../easy-ast/types/lightweight-class-definition.js';
import {LightweightDefinition} from '../easy-ast/types/lightweight-definition.js';
import {LightweightProperty} from '../easy-ast/types/lightweight-property.js';
import {LightweightType} from '../easy-ast/types/lightweight-type.js';
import {UMLConfig} from './uml-config.js';
/**
* Converts the lightweight class/enum definitions according to the configuration,
@@ -39,7 +38,7 @@ export async function createDiagram(
plantUmlBaseURL: string,
): Promise<string> {
// when non definitions were specified use all
config.definitions = map(definitions, 'name');
config.definitions = definitions.map(it => it.name);
// when providing definitions and either showing associations or inheritance the
// inherited definitions will be added automatically
@@ -54,9 +53,9 @@ export async function createDiagram(
// creates a UML definition for every specified definition name
// however if no definitions were provided all definitions will be transformed
const modelPlantUMLCode = map(
definitions.filter(it => !config.definitions.includes(it.name)),
definition =>
const modelPlantUMLCode = definitions
.filter(it => !config.definitions.includes(it.name))
.map(definition =>
isLightweightClass(definition)
? createPlantUMLCodeForClass(config, definition)
: createPlantUMLCodeForEnum(config, definition),
@@ -152,18 +151,20 @@ function getReferenceTypes(type: LightweightType): string[] {
types.push(type.referenceName);
}
forEach(type.genericsTypes, specificType => {
for (const value of getReferenceTypes(specificType)) {
types.push(value);
}
});
if ((isUnionOrIntersectionType(type) && isEmpty(type.specificationTypes)) || type.isArray) {
forEach(type.specificationTypes, specificType => {
if (type.genericsTypes) {
for (const specificType of type.genericsTypes) {
for (const value of getReferenceTypes(specificType)) {
types.push(value);
}
});
}
}
if (Array.isArray(type.specificationTypes)) {
for (const specificType of type.specificationTypes) {
for (const value of getReferenceTypes(specificType)) {
types.push(value);
}
}
}
return types;
@@ -194,35 +195,39 @@ function createPlantUMLCodeForClass(config: UMLConfig, readerClass: LightweightC
model += '{';
// add the properties to the definition body
if (config.showProperties) {
forEach(readerClass.properties, property => {
if (config.showProperties && readerClass.properties) {
for (const key in readerClass.properties) {
const property = readerClass.properties[key];
if (property.optional && !config.showOptionalProperties) {
// don't show optional attributes
return;
continue;
}
/*if (property.inherited && !config.showInheritedProperties) {
// don't show inherited properties
continue;
}*/
model += `\n\t${createPropertyLine(property)}`;
});
}
}
// close the definition body
model += '\n}\n';
// add associations from properties with references
forEach(readerClass.properties, property => {
const types: string[] = getReferenceTypes(property.type);
for (const type of types) {
if (config.showAssociations) {
/*if (property.inherited && !config.showInheritedProperties) {
continue;
}*/
model += `${readerClass.name} -up-> ${type} : ${property.name} >\n`;
if (readerClass.properties) {
for (const key in readerClass.properties) {
const property = readerClass.properties[key];
const types: string[] = getReferenceTypes(property.type);
for (const type of types) {
if (config.showAssociations) {
/*if (property.inherited && !config.showInheritedProperties) {
continue;
}*/
model += `${readerClass.name} -up-> ${type} : ${property.name} >\n`;
}
}
}
});
}
return model;
}
@@ -237,10 +242,10 @@ function createPlantUMLCodeForEnum(config: UMLConfig, readerEnum: LightweightAli
// create enum header
let model = `enum ${readerEnum.name} {`;
// add values
if (config.showEnumValues) {
forEach(readerEnum.type?.specificationTypes, value => {
if (config.showEnumValues && readerEnum.type?.specificationTypes) {
for (const value of readerEnum.type?.specificationTypes) {
model += `\n\t${value.toString()}`;
});
}
}
model += '\n}\n';

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {JSONSchema7 as JSONSchema} from 'json-schema';
import {SchemaWithDefinitions} from '../types/schema';
import {SchemaWithDefinitions} from '../types/schema.js';
/**
* Guard for if a JSON schema is in fact a schema with definitions

View File

@@ -17,14 +17,14 @@ import Ajv from 'ajv';
import betterAjvErrors, {IOutputError} from 'better-ajv-errors';
import {PathLike} from 'fs';
import {JSONSchema7} from 'json-schema';
import * as mustache from 'mustache';
import mustache from 'mustache';
import {Schema} from 'ts-json-schema-generator';
import {globPromisified, readFilePromisified, writeFilePromisified} from './common';
import {ExpectedValidationErrors, ValidationError, ValidationResult} from './types/validator';
import {isThingWithType} from './util/guards';
import {globPromisified, readFilePromisified, writeFilePromisified} from './common.js';
import {ExpectedValidationErrors, ValidationError, ValidationResult} from './types/validator.js';
import {isThingWithType} from './util/guards.js';
import path from 'path';
import re2 from './types/re2';
import {toPosixPath} from './util/posix-path';
import re2 from './types/re2.js';
import {toPosixPath} from './util/posix-path.js';
/**
* StAppsCore validator
@@ -33,7 +33,7 @@ export class Validator {
/**
* JSON Schema Validator
*/
private readonly ajv = new Ajv({
private readonly ajv = new Ajv.default({
verbose: true,
code: {regExp: re2},
});
@@ -132,7 +132,7 @@ function fromAjvResult(
result: boolean | PromiseLike<unknown>,
schema: JSONSchema7,
instance: unknown,
ajvInstance: Ajv,
ajvInstance: Ajv.default,
): ValidationResult {
const betterErrorObject: IOutputError[] | undefined = betterAjvErrors(
schema,