Doctype.js

import Node from './Node';

/** Return a new {@link Doctype} {@link Node}.
* @extends Node
*/
class Doctype extends Node {
	/**
	* @param {DoctypeSettings|string} settings - Custom settings applied to the {@link Doctype}, or the name of the {@link Doctype}.
	* @example
	* new Doctype({ name: 'html' }) // <!doctype html>
	*/
	constructor (settings) {
		super();

		if (typeof settings === 'string') {
			settings = { name: settings };
		}

		/** Type identifier of the Doctype
		* @type {'doctype'} */
		this.type = 'doctype';

		/** Label of the Doctype
		* @type {string} */
		this.doctype = String(Object(settings).doctype || 'doctype');

		/** Name of the Doctype
		* @type {string} */
		this.name = String(Object(settings).name || 'html');

		/** Public identifier portion of the Doctype
		* @type {string|null} */
		this.publicId = Object(settings).publicId || null;

		/** System identifier portion of the Doctype
		* @type {string|null} */
		this.systemId = Object(settings).systemId || null;

		/** Source mapping of the Doctype
		* @type {DoctypeSource} */
		this.source = Object.assign({
			before: Object(Object(settings).source).before || ' ',
			after: Object(Object(settings).source).after || '',
			beforePublicId: Object(Object(settings).source).beforePublicId || null,
			beforeSystemId: Object(Object(settings).source).beforeSystemId || null
		}, Object(settings).source);
	}

	/**
	* Return a clone of the current {@link Doctype}.
	* @param {DoctypeSettings} settings - Custom settings applied to the cloned {@link Doctype}.
	* @returns {Doctype}
	* @example
	* doctype.clone()
	* @example <caption>Clone the current text with new source.</caption>
	* doctype.clone({ source: { input: 'modified source' } })
	*/
	clone (settings) {
		return new this.constructor(Object.assign({}, this, settings, {
			source: Object.assign({}, this.source, Object(settings).source)
		}));
	}

	/**
	* Return the current {@link Doctype} as a String.
	*/
	toString () {
		const publicId = this.publicId ? `${this.source.beforePublicId || ' '}${this.publicId}` : '';
		const systemId = this.systemId ? `${this.source.beforeSystemId || ' '}${this.systemId}` : '';

		return `<!${this.doctype}${this.source.before}${this.name}${this.source.after}${publicId}${systemId}>`;
	}

	/**
	* Return the current {@link Doctype} as an Object.
	*/
	toJSON () {
		return {
			name: this.name,
			publicId: this.publicId,
			systemId: this.systemId
		};
	}
}

export default Doctype;

/**
* @typedef {Object} DoctypeSettings - Custom settings applied to the Doctype, or the content of the Doctype.
* @property {string} doctype - Label of the Doctype.
* @property {string} [name] - Name of the Doctype.
* @property {string} [publicId] - Public identifier portion of the Doctype.
* @property {string} [systemId] - System identifier portion of the Doctype.
* @property {DoctypeSource} [source] - Source mapping of the Doctype.
*
* @typedef {Object} DoctypeSource - Source mapping of the Doctype.
* @property {{ html: string }} input - Raw HTML source of the Doctype.
* @property {number} before - Starting content within the Doctype.
* @property {number} after - Starting content within the Doctype.
* @property {number} beforePublicId - Ending offset within the Doctype.
* @property {number} afterPublicId - Ending offset within the Doctype.
*/