229 lines
7.9 KiB
TypeScript
229 lines
7.9 KiB
TypeScript
import { Observable } from "rxjs";
|
|
import { Injectable } from "@angular/core";
|
|
import { ApiService } from "./crud.service";
|
|
import {JSONSchema7} from "json-schema";
|
|
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class JsonschemasService {
|
|
private rawSchemas: any | null = null;
|
|
|
|
constructor(
|
|
private apiService: ApiService
|
|
) {}
|
|
|
|
getSchemas(): Observable<Schema> {
|
|
return new Observable<Schema>((observer) => {
|
|
if (this.rawSchemas === null) {
|
|
this.apiService.getSchema().subscribe((jsonSchemas: any) => {
|
|
this.rawSchemas = jsonSchemas;
|
|
observer.next(this.rawSchemas)
|
|
});
|
|
} else {
|
|
observer.next(this.rawSchemas)
|
|
}
|
|
});
|
|
}
|
|
|
|
buildResource(resourceName: string) {
|
|
let resource;
|
|
|
|
resource = { ... this.rawSchemas.components.schemas[resourceName]};
|
|
resource.components = { schemas: {} };
|
|
for (let prop_name in resource.properties) {
|
|
let prop = resource.properties[prop_name];
|
|
|
|
if (prop_name === '_id') {
|
|
delete resource.properties[prop_name]
|
|
} else if (this.is_reference(prop)) {
|
|
this.resolveReference(resource, prop);
|
|
} else if (this.is_union(prop)) {
|
|
for (let i in prop.oneOf) {
|
|
this.resolveReference(resource, prop.oneOf[i]);
|
|
}
|
|
} else if (this.is_enum(prop)) {
|
|
for (let i in prop.allOf) {
|
|
this.resolveReference(resource, prop.allOf[i]);
|
|
}
|
|
} else if (this.is_array(prop) && this.is_reference(prop.items)) {
|
|
this.resolveReference(resource, prop.items);
|
|
}
|
|
}
|
|
|
|
return resource;
|
|
}
|
|
|
|
resolveReference(resource: any, prop_reference: any) {
|
|
let subresourceName = this.get_reference_name(prop_reference);
|
|
let subresource = this.buildResource(subresourceName);
|
|
resource.components.schemas[subresourceName] = subresource;
|
|
for (let subsubresourceName in subresource.components.schemas) {
|
|
if (! resource.components.schemas.hasOwnProperty(subsubresourceName)) {
|
|
resource.components.schemas[subsubresourceName] = subresource.components.schemas[subsubresourceName];
|
|
}
|
|
}
|
|
}
|
|
|
|
getReferencedSchema() {
|
|
|
|
}
|
|
|
|
getCreateResource(resourceName: string): Observable<Schema> {
|
|
return new Observable<Schema>((observer) => {
|
|
this.getSchemas().subscribe(() => {
|
|
observer.next(this.buildResource(resourceName + 'Create'))
|
|
})
|
|
})
|
|
}
|
|
|
|
getUpdateResource(resourceName: string): Observable<Schema> {
|
|
return new Observable<Schema>((observer) => {
|
|
this.getSchemas().subscribe(() => {
|
|
let resource = this.buildResource(resourceName + 'Read');
|
|
let updateResource = this.rawSchemas.components.schemas[resourceName + 'Update']
|
|
|
|
for (let prop_name in resource.properties) {
|
|
if (! updateResource.properties.hasOwnProperty(prop_name)) {
|
|
if (this.is_reference(resource.properties[prop_name])) {
|
|
let subresourceName = this.get_reference_name(resource.properties[prop_name]);
|
|
resource.components.schemas[subresourceName].readOnly = true;
|
|
} else {
|
|
resource.properties[prop_name].readOnly = true;
|
|
}
|
|
}
|
|
}
|
|
this.changePropertiesOrder(resource);
|
|
observer.next(resource);
|
|
})
|
|
})
|
|
}
|
|
|
|
changePropertiesOrder(resource: any) {
|
|
let created_at;
|
|
let updated_at;
|
|
let new_properties: any = {};
|
|
for (let prop_name in resource.properties) {
|
|
if (prop_name == 'created_at') {
|
|
created_at = resource.properties[prop_name];
|
|
} else if (prop_name == 'updated_at') {
|
|
updated_at = resource.properties[prop_name];
|
|
} else {
|
|
new_properties[prop_name] = resource.properties[prop_name];
|
|
}
|
|
}
|
|
if (created_at) {
|
|
new_properties['created_at'] = created_at;
|
|
}
|
|
if (updated_at) {
|
|
new_properties['updated_at'] = updated_at;
|
|
}
|
|
resource.properties = new_properties
|
|
}
|
|
|
|
private is_object(prop: any) {
|
|
return prop.hasOwnProperty('properties')
|
|
}
|
|
|
|
private is_reference(prop: any) {
|
|
return prop.hasOwnProperty('$ref');
|
|
}
|
|
|
|
private is_array(prop: any) {
|
|
return prop.hasOwnProperty('items');
|
|
}
|
|
|
|
private is_union(prop: any) {
|
|
return prop.hasOwnProperty('oneOf');
|
|
}
|
|
|
|
private is_enum(prop: any) {
|
|
return prop.hasOwnProperty('allOf');
|
|
}
|
|
|
|
private get_reference_name(prop: any) {
|
|
return prop['$ref'].substring(prop['$ref'].lastIndexOf('/')+1);
|
|
}
|
|
|
|
has_descendant(resource: JSONSchema7, property_name: string): boolean {
|
|
if (this.is_array(resource)) {
|
|
return property_name == 'items';
|
|
} else if (this.is_object(resource)) {
|
|
return property_name in resource.properties!;
|
|
} else if (this.is_reference(resource)) {
|
|
let subresourceName = this.get_reference_name(resource);
|
|
return this.has_descendant(this.buildResource(subresourceName), property_name);
|
|
} else if (this.is_union(resource)) {
|
|
for (const ref of resource.oneOf!) {
|
|
// @ts-ignore
|
|
if (this.has_descendant(ref, property_name)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
throw new Error("Jsonschema format not implemented in property finder");
|
|
return false;
|
|
}
|
|
|
|
get_descendant(resource: JSONSchema7, property_name: string): JSONSchema7 {
|
|
if (this.is_array(resource) && property_name == 'items') {
|
|
// @ts-ignore
|
|
return resource.items;
|
|
} else if (this.is_object(resource) && property_name in resource.properties!) {
|
|
// @ts-ignore
|
|
return resource.properties[property_name];
|
|
} else if (this.is_reference(resource)) {
|
|
let subresourceName = this.get_reference_name(resource);
|
|
let subresource = this.buildResource(subresourceName);
|
|
return this.get_descendant(subresource, property_name);
|
|
} else if (this.is_union(resource)) {
|
|
for (const ref of resource.oneOf!) {
|
|
// @ts-ignore
|
|
if (this.has_descendant(ref, property_name)) {
|
|
// @ts-ignore
|
|
return this.get_descendant(ref, property_name);
|
|
}
|
|
}
|
|
}
|
|
throw new Error("property not found or Jsonschema format not implemented");
|
|
}
|
|
|
|
path_exists(resource: JSONSchema7, path: string): boolean{
|
|
const pointFirstPosition = path.indexOf('.')
|
|
if (pointFirstPosition == -1) {
|
|
return this.has_descendant(resource, path);
|
|
}
|
|
|
|
|
|
return this.has_descendant(resource, path.substring(0, pointFirstPosition))
|
|
&& this.path_exists(
|
|
this.get_descendant(
|
|
resource,
|
|
path.substring(0, pointFirstPosition)
|
|
),
|
|
path.substring(pointFirstPosition + 1)
|
|
);
|
|
}
|
|
|
|
get_property_by_path(resource: JSONSchema7, path: string): JSONSchema7 {
|
|
const pointFirstPosition = path.indexOf('.')
|
|
if (pointFirstPosition == -1) {
|
|
return this.get_descendant(resource, path);
|
|
}
|
|
|
|
return this.get_property_by_path(
|
|
this.get_descendant(
|
|
resource,
|
|
path.substring(0, pointFirstPosition)
|
|
),
|
|
path.substring(pointFirstPosition + 1)
|
|
);
|
|
}
|
|
}
|
|
|
|
export interface Schema {
|
|
components: { };
|
|
}
|