/**
* @module Tag
*/
/**
* Tag object from API.
* @global
* @typedef {object} APITag
* @property {number|string} id Tag id.
* @property {string} type Tag type.
* @property {string} name Tag name.
* @property {number|string} count Tagged books count.
* @property {string} url Tag URL.
*/
/**
* @typedef {object} TagTypes
* @property {UnknownTagType} Unknown Unknown tag type.
* @property {TagType} Tag Tag tag type.
* @property {TagType} Category Category tag type.
* @property {TagType} Artist Artist tag type.
* @property {TagType} Parody Parody tag type.
* @property {TagType} Character Character tag type.
* @property {TagType} Group Group tag type.
* @property {TagType} Language Language tag type.
*/
/**
* Class representing tag type.
* @class
*/
class TagType {
/**
* @type {TagTypes}
* @static
*/
static knownTypes = {};
/**
* Tag type name.
* @type {?string}
* @default null
*/
type = null;
/**
* Create tag type.
* @param {string} type Tag type.
*/
constructor(type) {
if (type) {
this.type = type;
this.constructor.knownTypes[type] = this;
}
}
/**
* Check if this tag type is unknown.
* @type {boolean}
*/
get isKnown() {
return !(this instanceof UnknownTagType);
}
}
/**
* Class representing unknown tag type.
* @class
* @extends TagType
*/
class UnknownTagType extends TagType {
/**
* Create unknown tag type.
* @param {string} [type="unknown"] Unknown tag type name.
*/
constructor(type = 'unknown') {
super(null);
this.type = type;
}
}
/**
* Class representing tag.
* @class
*/
class Tag {
/**
* Tag types.
* @type {TagTypes}
* @static
*/
static types = {
Unknown : new UnknownTagType(), // Symbol('unknown')
Tag : new TagType('tag'),
Category : new TagType('category'),
Artist : new TagType('artist'),
Parody : new TagType('parody'),
Character: new TagType('character'),
Group : new TagType('group'),
Language : new TagType('language'),
/**
* Known tag types.
* @type {TagTypes}
*/
known: TagType.knownTypes,
/**
* Get tag type class instance by name.
* @param {string} type Tag type.
* @returns {TagType|UnknownTagType} Tag type class instance.
*/
get(type) {
let known;
if ('string' === typeof type)
type = type.toLowerCase();
return ((known = this.known[type])) ? known : new UnknownTagType(type);
},
};
/**
* Warp tag object with Tag class instance.
* @param {APITag|Tag} tag Tag to wrap.
* @returns {Tag} Tag.
* @static
*/
static get(tag) {
if (!(tag instanceof this))
tag = new this({
id : +tag.id,
type : tag.type,
name : tag.name,
count: +tag.count,
url : tag.url,
});
return tag;
}
/**
* Create tag.
* @param {object} [params] Tag parameters.
* @param {number} [params.id=0] Tag id.
* @param {string|TagType} [params.type=TagTypes.Unknown] Tag type.
* @param {string} [params.name=""] Tag name.
* @param {number} [params.count=0] Tagged books count.
* @param {string} [params.url=""] Tag URL.
*/
constructor({
id = 0,
type = this.constructor.types.Unknown,
name = '',
count = 0,
url = '',
} = {}) {
Object.assign(this, {
id,
type: type instanceof TagType
? type
: this.constructor.types.get(type),
name,
count,
url,
});
}
/**
* Compare this to given one.
* @param {string|Tag} tag Tag to compare with.
* @param {boolean} [strict=false] Whatever all parameters must be the same.
* @returns {boolean} Whatever tags are equal.
*/
compare(tag, strict = false) {
tag = this.constructor.get(tag);
return !![
'id',
'type',
'name',
'count',
'url',
].map(
prop => tag[prop] === this[prop]
).reduce(
(accum, current) => strict
? accum * current
: accum + current
);
}
}
export default Tag;