UNPKG

@schukai/monster

Version:

Monster is a simple library for creating fast, robust and lightweight websites.

165 lines (143 loc) 4.27 kB
/** * Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved. * Node module: @schukai/monster * * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3). * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html * * For those who do not wish to adhere to the AGPLv3, a commercial license is available. * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms. * For more information about purchasing a commercial license, please contact Volker Schukai. * * SPDX-License-Identifier: AGPL-3.0 */ import { Base } from "./base.mjs"; import { isString } from "./is.mjs"; import { MediaType, parseMediaType } from "./mediatype.mjs"; import { validateBoolean, validateInstance, validateString, } from "./validate.mjs"; import { instanceSymbol } from "../constants.mjs"; export { DataUrl, parseDataURL }; /** * @private * @type {symbol} */ const internal = Symbol("internal"); /** * You can create an object via the monster namespace `new DataUrl()`. * * @license AGPLv3 * @since 1.8.0 * @copyright Volker Schukai * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs * @see https://datatracker.ietf.org/doc/html/rfc2397 */ class DataUrl extends Base { /** * * @param {String} content * @param {String|MediaType} mediatype * @param {boolean} base64=true */ constructor(content, mediatype, base64) { super(); if (isString(mediatype)) { mediatype = parseMediaType(mediatype); } this[internal] = { content: validateString(content), mediatype: validateInstance(mediatype, MediaType), base64: validateBoolean(base64 === undefined ? true : base64), }; } /** * This method is called by the `instanceof` operator. * @return {symbol} * @since 2.1.0 */ static get [instanceSymbol]() { return Symbol.for("@schukai/monster/types/data-url"); } get content() { return this[internal].base64 ? atob(this[internal].content) : this[internal].content; } get mediatype() { return this[internal].mediatype; } /** * Converts the current object to a URL instance. * * @return {URL} A URL instance created from the string representation of the object. */ toURL() { return new URL(this.toString()); } /** * * @return {string} * @see https://datatracker.ietf.org/doc/html/rfc2397 */ toString() { let content = this[internal].content; if (this[internal].base64 === true) { content = `;base64,${content}`; } else { content = `,${encodeURIComponent(content)}`; } return `data:${this[internal].mediatype.toString()}${content}`; } } /** * You can call the function via the monster namespace `parseDataURL()`. * * Specification: * * ``` * dataurl := "data:" [ mediatype ] [ ";base64" ] "," data * mediatype := [ type "/" subtype ] *( ";" parameter ) * data := *urlchar * parameter := attribute "=" value * ``` * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs * @see https://datatracker.ietf.org/doc/html/rfc2397 * @throws {TypeError} incorrect or missing data protocol * @throws {TypeError} malformed data url * @param {string} dataurl * @return {DataUrl} */ function parseDataURL(dataurl) { validateString(dataurl); dataurl = dataurl.trim(); if (dataurl.substring(0, 5) !== "data:") { throw new TypeError("incorrect or missing data protocol"); } dataurl = dataurl.substring(5); const p = dataurl.indexOf(","); if (p === -1) { throw new TypeError("malformed data url"); } let content = dataurl.substring(p + 1); const mediatypeAndBase64 = dataurl.substring(0, p).trim(); let mediatype = "text/plain;charset=US-ASCII"; let base64Flag = false; if (mediatypeAndBase64 !== "") { mediatype = mediatypeAndBase64; if (mediatypeAndBase64.endsWith("base64")) { const i = mediatypeAndBase64.lastIndexOf(";"); mediatype = mediatypeAndBase64.substring(0, i); base64Flag = true; } else { content = decodeURIComponent(content); } mediatype = parseMediaType(mediatype); } else { content = decodeURIComponent(content); } return new DataUrl(content, mediatype, base64Flag); }