Spaces:
Running
Running
/** | |
* Validates the data structure of character cards. | |
* Supported specs: V1, V2 | |
* Up to: 8083fb3 | |
* | |
* @link https://github.com/malfoyslastname/character-card-spec-v2 | |
*/ | |
class TavernCardValidator { | |
/** | |
* @type {string|null} | |
*/ | |
#lastValidationError = null; | |
constructor(card) { | |
this.card = card; | |
} | |
/** | |
* Field that caused the validation to fail | |
* | |
* @returns {null|string} | |
*/ | |
get lastValidationError() { | |
return this.#lastValidationError; | |
} | |
/** | |
* Validate against V1 or V2 spec. | |
* | |
* @returns {number|boolean} - false when neither V1 nor V2 spec were matched. Specification version number otherwise. | |
*/ | |
validate() { | |
this.#lastValidationError = null; | |
if (this.validateV1()) { | |
return 1; | |
} | |
if (this.validateV2()) { | |
return 2; | |
} | |
if (this.validateV3()) { | |
return 3; | |
} | |
return false; | |
} | |
/** | |
* Validate against V1 specification | |
* | |
* @returns {this is string[]} | |
*/ | |
validateV1() { | |
const requiredFields = ['name', 'description', 'personality', 'scenario', 'first_mes', 'mes_example']; | |
return requiredFields.every(field => { | |
if (!Object.hasOwn(this.card, field)) { | |
this.#lastValidationError = field; | |
return false; | |
} | |
return true; | |
}); | |
} | |
/** | |
* Validate against V2 specification | |
* | |
* @returns {false|boolean|*} | |
*/ | |
validateV2() { | |
return this.#validateSpecV2() | |
&& this.#validateSpecVersionV2() | |
&& this.#validateDataV2() | |
&& this.#validateCharacterBookV2(); | |
} | |
/** | |
* Validate against V3 specification | |
* @returns {boolean} | |
*/ | |
validateV3() { | |
return this.#validateSpecV3() | |
&& this.#validateSpecVersionV3() | |
&& this.#validateDataV3(); | |
} | |
#validateSpecV2() { | |
if (this.card.spec !== 'chara_card_v2') { | |
this.#lastValidationError = 'spec'; | |
return false; | |
} | |
return true; | |
} | |
#validateSpecVersionV2() { | |
if (this.card.spec_version !== '2.0') { | |
this.#lastValidationError = 'spec_version'; | |
return false; | |
} | |
return true; | |
} | |
#validateDataV2() { | |
const data = this.card.data; | |
if (!data) { | |
this.#lastValidationError = 'No tavern card data found'; | |
return false; | |
} | |
const requiredFields = ['name', 'description', 'personality', 'scenario', 'first_mes', 'mes_example', 'creator_notes', 'system_prompt', 'post_history_instructions', 'alternate_greetings', 'tags', 'creator', 'character_version', 'extensions']; | |
const isAllRequiredFieldsPresent = requiredFields.every(field => { | |
if (!Object.hasOwn(data, field)) { | |
this.#lastValidationError = `data.${field}`; | |
return false; | |
} | |
return true; | |
}); | |
return isAllRequiredFieldsPresent && Array.isArray(data.alternate_greetings) && Array.isArray(data.tags) && typeof data.extensions === 'object'; | |
} | |
#validateCharacterBookV2() { | |
const characterBook = this.card.data.character_book; | |
if (!characterBook) { | |
return true; | |
} | |
const requiredFields = ['extensions', 'entries']; | |
const isAllRequiredFieldsPresent = requiredFields.every(field => { | |
if (!Object.hasOwn(characterBook, field)) { | |
this.#lastValidationError = `data.character_book.${field}`; | |
return false; | |
} | |
return true; | |
}); | |
return isAllRequiredFieldsPresent && Array.isArray(characterBook.entries) && typeof characterBook.extensions === 'object'; | |
} | |
#validateSpecV3() { | |
if (this.card.spec !== 'chara_card_v3') { | |
this.#lastValidationError = 'spec'; | |
return false; | |
} | |
return true; | |
} | |
#validateSpecVersionV3() { | |
if (Number(this.card.spec_version) < 3.0 || Number(this.card.spec_version) >= 4.0) { | |
this.#lastValidationError = 'spec_version'; | |
return false; | |
} | |
return true; | |
} | |
#validateDataV3() { | |
const data = this.card.data; | |
if (!data || typeof data !== 'object') { | |
this.#lastValidationError = 'No tavern card data found'; | |
return false; | |
} | |
return true; | |
} | |
} | |
module.exports = { TavernCardValidator }; | |