extwee
Version:
A story compiler tool using Twine-compatible formats
301 lines (265 loc) • 6.56 kB
JavaScript
import { valid } from 'semver';
/**
* StoryFormat representing a Twine 2 story format.
*
* This class has type checking on all of its properties.
* If a property is set to a value of the wrong type, a TypeError will be thrown.
*
* @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-storyformats-spec.md Twine 2 Story Formats Specification}
*
* @class
* @classdesc A class representing a Twine 2 story format.
* @property {string} name - The name of the story format.
* @property {string} version - The semantic version of the story format.
* @property {string} description - The description of the story format.
* @property {string} author - The author of the story format.
* @property {string} image - The image of the story format.
* @property {string} url - The URL of the story format.
* @property {string} license - The license of the story format.
* @property {boolean} proofing - The proofing of the story format.
* @property {string} source - The source of the story format.
* @example
* const sf = new StoryFormat();
* sf.name = 'New';
* sf.version = '1.0.0';
* sf.description = 'New';
* sf.author = 'New';
* sf.image = 'New';
* sf.url = 'New';
* sf.license = 'New';
* sf.proofing = true;
* sf.source = 'New';
*/
export default class StoryFormat {
/**
* Internal name.
* @private
*/
#_name = 'Untitled Story Format';
/**
* Internal version.
* @private
*/
#_version = '';
/**
* Internal description.
* @private
*/
#_description = '';
/**
* Internal author.
* @private
*/
#_author = '';
/**
* Internal image.
* @private
*/
#_image = '';
/**
* Internal URL.
* @private
*/
#_url = '';
/**
* Internal license.
* @private
*/
#_license = '';
/**
* Internal proofing.
* @private
*/
#_proofing = false;
/**
* Internal source.
* @private
*/
#_source = '';
// Constructor with all parameters.
constructor(name = 'Untitled Story Format', version = '', description = '', author = '', image = '', url = '', license = '', proofing = false, source = '') {
this.name = name;
this.version = version;
this.description = description;
this.author = author;
this.image = image;
this.url = url;
this.license = license;
this.proofing = proofing;
this.source = source;
}
/**
* Name
* @returns {string} Name.
*/
get name () { return this.#_name; }
/**
* @param {string} n - Replacement name.
*/
set name (n) {
if (typeof n === 'string') {
this.#_name = n;
} else {
throw new TypeError('Name must be a string!');
}
}
/**
* Version.
* @returns {string} Version.
*/
get version () { return this.#_version; }
/**
* @param {string} n - Replacement version.
*/
set version (n) {
if (typeof n === 'string') {
this.#_version = n;
} else {
throw new TypeError('Version must be a string!');
}
}
/**
* Description.
* @returns {string} Description.
*/
get description () { return this.#_description; }
/**
* @param {string} d - Replacement description.
*/
set description (d) {
if (typeof d === 'string') {
this.#_description = d;
} else {
throw new TypeError('Description must be a string!');
}
}
/**
* Author.
* @returns {string} Author.
*/
get author () { return this.#_author; }
/**
* @param {string} a - Replacement author.
*/
set author (a) {
if (typeof a === 'string') {
this.#_author = a;
} else {
throw new TypeError('Author must be a string!');
}
}
/**
* Image.
* @returns {string} Image.
*/
get image () { return this.#_image; }
/**
* @param {string} i - Replacement image.
*/
set image (i) {
if (typeof i === 'string') {
this.#_image = i;
} else {
throw new TypeError('Image must be a string!');
}
}
/**
* URL.
* @returns {string} URL.
*/
get url () { return this.#_url; }
/**
* @param {string} u - Replacement URL.
*/
set url (u) {
if (typeof u === 'string') {
this.#_url = u;
} else {
throw new TypeError('URL must be a string!');
}
}
/**
* License.
* @returns {string} License.
*/
get license () { return this.#_license; }
/**
* @param {string} l - Replacement license.
*/
set license (l) {
if (typeof l === 'string') {
this.#_license = l;
} else {
throw new TypeError('License must be a string!');
}
}
/**
* Proofing.
* @returns {boolean} Proofing.
*/
get proofing () { return this.#_proofing; }
/**
* @param {boolean} p - Replacement proofing.
*/
set proofing (p) {
if (typeof p === 'boolean') {
this.#_proofing = p;
} else {
throw new TypeError('Proofing must be a Boolean!');
}
}
/**
* Source.
* @returns {string} Source.
*/
get source () { return this.#_source; }
/**
* @param {string} s - Replacement source.
*/
set source (s) {
if (typeof s === 'string') {
this.#_source = s;
} else {
throw new TypeError('Source must be a String!');
}
}
/**
* Produces a string representation of the story format object.
* @method toString
* @returns {string} - A string representation of the story format.
*/
toString() {
return JSON.stringify(this, null, "\t");
}
/**
* Produces a JSON representation of the story format object.
* @method toJSON
* @returns {object} - A JSON representation of the story format.
*/
toJSON() {
// name: (string) Optional. The name of the story format. (Omitting the name will lead to an Untitled Story Format.)
// Set a default name.
let name = "Untitled Story Format";
// Check if the story format is not an empty string.
if (this.name.length > 0) {
// Update the name.
name = this.name;
}
// version: (string) Required, and semantic version-style formatting (x.y.z, e.g., 1.2.1) of the version is also required.
// Check if the version is valid. If not, throw an error.
if (!valid(this.version)) {
throw new TypeError('ERROR: Version must be a valid semantic version!');
}
return JSON.stringify({
name,
version: this.version,
description: this.description,
author: this.author,
image: this.image,
url: this.url,
license: this.license,
proofing: this.proofing,
source: this.source
});
}
}