@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
165 lines (143 loc) • 4.26 kB
JavaScript
/**
* Copyright © schukai GmbH 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 schukai GmbH.
*
* 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 schukai GmbH
* @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);
}