152 lines
4.6 KiB
TypeScript
152 lines
4.6 KiB
TypeScript
import { containsOnlyLettersAndUnderscores, PropertyMappingNameConflictError, PropertyMappingValidationError } from '../utils/Utils';
|
|
import { MediaType } from '../utils/MediaType';
|
|
|
|
export enum PropertyMappingOption {
|
|
Default = 'default',
|
|
Map = 'remap',
|
|
Remove = 'remove',
|
|
}
|
|
|
|
export const propertyMappingOptions = [PropertyMappingOption.Default, PropertyMappingOption.Map, PropertyMappingOption.Remove];
|
|
|
|
export class PropertyMappingModel {
|
|
type: MediaType;
|
|
properties: PropertyMapping[];
|
|
|
|
constructor(type: MediaType, properties?: PropertyMapping[]) {
|
|
this.type = type;
|
|
this.properties = properties ?? [];
|
|
}
|
|
|
|
validate(): { res: boolean; err?: Error } {
|
|
console.debug(`MDB | validated property mappings for ${this.type}`);
|
|
|
|
// check properties
|
|
for (const property of this.properties) {
|
|
const propertyValidation = property.validate();
|
|
if (!propertyValidation.res) {
|
|
return {
|
|
res: false,
|
|
err: propertyValidation.err,
|
|
};
|
|
}
|
|
}
|
|
|
|
// check for name collisions
|
|
for (const property of this.getMappedProperties()) {
|
|
const propertiesWithSameTarget = this.getMappedProperties().filter(x => x.newProperty === property.newProperty);
|
|
if (propertiesWithSameTarget.length === 0) {
|
|
// if we get there, then something in this code is wrong
|
|
} else if (propertiesWithSameTarget.length === 1) {
|
|
// all good
|
|
} else {
|
|
// two or more properties are mapped to the same property
|
|
return {
|
|
res: false,
|
|
err: new PropertyMappingNameConflictError(
|
|
`Multiple remapped properties (${propertiesWithSameTarget.map(x => x.toString()).toString()}) may not share the same name.`,
|
|
),
|
|
};
|
|
}
|
|
}
|
|
// remapped properties may not have the same name as any original property
|
|
for (const property of this.getMappedProperties()) {
|
|
const propertiesWithSameTarget = this.properties.filter(x => x.newProperty === property.property);
|
|
if (propertiesWithSameTarget.length === 0) {
|
|
// all good
|
|
} else {
|
|
// a mapped property shares the same name with an original property
|
|
return {
|
|
res: false,
|
|
err: new PropertyMappingNameConflictError(`Remapped property (${property}) may not share it's new name with an existing property.`),
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
res: true,
|
|
};
|
|
}
|
|
|
|
getMappedProperties() {
|
|
return this.properties.filter(x => x.mapping === PropertyMappingOption.Map);
|
|
}
|
|
|
|
copy(): PropertyMappingModel {
|
|
const copy = new PropertyMappingModel(this.type);
|
|
for (const property of this.properties) {
|
|
const propertyCopy = new PropertyMapping(property.property, property.newProperty, property.mapping, property.locked);
|
|
copy.properties.push(propertyCopy);
|
|
}
|
|
return copy;
|
|
}
|
|
}
|
|
|
|
export class PropertyMapping {
|
|
property: string;
|
|
newProperty: string;
|
|
locked: boolean;
|
|
mapping: PropertyMappingOption;
|
|
|
|
constructor(property: string, newProperty: string, mapping: PropertyMappingOption, locked?: boolean) {
|
|
this.property = property;
|
|
this.newProperty = newProperty;
|
|
this.mapping = mapping;
|
|
this.locked = locked ?? false;
|
|
}
|
|
|
|
validate(): { res: boolean; err?: Error } {
|
|
// locked property may only be default
|
|
if (this.locked) {
|
|
if (this.mapping === PropertyMappingOption.Remove) {
|
|
return {
|
|
res: false,
|
|
err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": locked property may not be removed.`),
|
|
};
|
|
}
|
|
if (this.mapping === PropertyMappingOption.Map) {
|
|
return {
|
|
res: false,
|
|
err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": locked property may not be remapped.`),
|
|
};
|
|
}
|
|
}
|
|
|
|
if (this.mapping === PropertyMappingOption.Default) {
|
|
return { res: true };
|
|
}
|
|
if (this.mapping === PropertyMappingOption.Remove) {
|
|
return { res: true };
|
|
}
|
|
|
|
if (!this.property || !containsOnlyLettersAndUnderscores(this.property)) {
|
|
return {
|
|
res: false,
|
|
err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": property may not be empty and only contain letters and underscores.`),
|
|
};
|
|
}
|
|
|
|
if (!this.newProperty || !containsOnlyLettersAndUnderscores(this.newProperty)) {
|
|
return {
|
|
res: false,
|
|
err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": new property may not be empty and only contain letters and underscores.`),
|
|
};
|
|
}
|
|
|
|
return {
|
|
res: true,
|
|
};
|
|
}
|
|
|
|
toString(): string {
|
|
if (this.mapping === PropertyMappingOption.Default) {
|
|
return this.property;
|
|
} else if (this.mapping === PropertyMappingOption.Map) {
|
|
return `${this.property} -> ${this.newProperty}`;
|
|
} else if (this.mapping === PropertyMappingOption.Remove) {
|
|
return `remove ${this.property}`;
|
|
}
|
|
|
|
return this.property;
|
|
}
|
|
}
|