UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

1,291 lines (1,289 loc) 46.6 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. Object.defineProperty(exports, "__esModule", { value: true }); const CartoApp_1 = require("../app/CartoApp"); const IField_1 = require("../dataform/IField"); const Log_1 = require("./Log"); const singleComment = Symbol("singleComment"); const multiComment = Symbol("multiComment"); class Utilities { static async sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } static get isPreview() { return false; } static get isAppSim() { if (Utilities._isAppSim === undefined) { Utilities._isAppSim = false; } return Utilities._isAppSim; } static get isDebug() { if (Utilities._isDebug === undefined) { Utilities._isDebug = false; } return Utilities._isDebug; } static selectJsonObject(jsonO, select, ensureObjects) { const selectors = select.split("/"); for (const selector of selectors) { if (selector.length > 0) { jsonO = jsonO[selector]; if (!jsonO && !ensureObjects) { return undefined; } if (!jsonO && ensureObjects) { jsonO[selector] = {}; jsonO = jsonO[selector]; } } } return jsonO; } static removeItemInArray(objToRemove, stringArr) { const nextArray = []; for (const candStr of stringArr) { if (candStr !== objToRemove) { nextArray.push(candStr); } } return nextArray; } static isArrayNonNegative(arr) { for (const val of arr) { if (val < 0) { return false; } } return true; } static arrayHasNegativeAndIsNumeric(arr) { let foundNegative = false; for (const val of arr) { if (typeof val !== "number") { return false; } else if (val < 0) { foundNegative = true; } } return foundNegative; } static encodeObjectWithSequentialRunLengthEncodeUsingNegative(obj) { for (const key in obj) { const val = obj[key]; if (val !== undefined) { if (typeof val === "object" && !Array.isArray(val)) { this.encodeObjectWithSequentialRunLengthEncodeUsingNegative(val); } else if (Array.isArray(val)) { let isNumericArray = true; for (const arrVal of val) { if (typeof arrVal !== "number") { isNumericArray = false; break; } } if (isNumericArray) { obj[key] = this.encodeSequentialRunLengthUsingNegative(val); } } } } } static decodeSequentialRunLengthUsingNegative(arr) { if (this.isArrayNonNegative(arr)) { return arr; } const newArr = []; newArr.push(arr[0]); for (let i = 1; i < arr.length; i++) { if (arr[i] < 0) { let startVal = arr[i - 1]; for (let j = 0; j < Math.abs(arr[i]); j++) { startVal++; newArr.push(startVal); } } else { newArr.push(arr[i]); } } return newArr; } /* Convert a numeric array from: [1, 2, 3, 7, 9, 10, 15, 16, 17, 18] to a "sequential run length encode", where negative numbers are used to indicate a "run" so the above becomes [1, -2, 7, 9, -1, 15, -3] */ static encodeSequentialRunLengthUsingNegative(arr) { if (!this.isArrayNonNegative(arr)) { return arr; } arr.sort(); const newArr = []; newArr.push(arr[0]); let streak = -1; for (let i = 1; i < arr.length; i++) { if (arr[i] === arr[i - 1] + 1) { if (streak < 1) { streak = 1; } else { streak++; } } else { if (streak >= 1) { newArr.push(-streak); streak = -1; } newArr.push(arr[i]); } } if (streak >= 1) { newArr.push(-streak); streak = -1; } return newArr; } static trimEllipsis(text, length) { if (text.length > length) { text = text.substring(0, length - 1) + "…"; } return text; } static makeHashFileSafe(hash) { hash = hash.replace(/\//gi, "-S"); hash = hash.replace(/\+/gi, "-P"); hash = hash.replace(/\\/gi, "-B"); hash = hash.replace(/=/gi, "-E"); hash = hash.replace(/,/gi, "-C"); return hash; } static getSimpleNumeric(num) { if (num === undefined) { return ""; } if (num < 1000) { return num.toString(); } if (num < 1000) { return Math.floor(num / 100) / 10 + "k"; } if (num > 1000000) { return Math.floor(num / 100000) / 10 + "m"; } return Math.floor(num / 1000) + "k"; } static humanifyJsName(name) { if (typeof name === "boolean" || typeof name === "number") { return name.toString(); } let retVal = ""; for (let i = 0; i < name.length; i++) { if (i === 0) { retVal += name[i].toUpperCase(); } else { if (name[i] >= "A" && name[i] <= "Z") { retVal += " "; } retVal += name[i]; } } retVal = retVal.replace("Java Script", "JavaScript"); return retVal; } static humanifyObject(sampVal) { if (typeof sampVal === "object") { sampVal = JSON.stringify(sampVal, undefined, 2); } else { sampVal = sampVal.toString(); } sampVal = sampVal.trim(); if (sampVal.startsWith("[") && sampVal.endsWith("]")) { sampVal = sampVal.substring(1, sampVal.length - 1); sampVal = sampVal.replace(/"/gi, ""); } if (sampVal.startsWith("{") && sampVal.endsWith("}")) { sampVal = sampVal.substring(1, sampVal.length - 1); } return sampVal; } static ensureLooksLikeSentence(name) { if (name.length > 1) { if (name[0] >= "a" && name[0] <= "z") { name = name[0].toUpperCase() + name.substring(1, name.length); } } if (!name.endsWith(".")) { name = name + "."; } return name; } static dehumanify(val, humanify) { if (!humanify) { return val; } return Utilities.dehumanifyMinecraftName(val); } static humanify(val, humanify) { if (!humanify || val === undefined) { return val; } if (humanify === IField_1.FieldValueHumanify.general) { return Utilities.humanifyObject(val); } if (typeof val === "object") { return JSON.stringify(val); } if (Array.isArray(val)) { return val; } return Utilities.humanifyMinecraftName(val); } static ensureFirstCharIsUpperCase(name) { if (name.length > 1) { if (name[0] >= "a" && name[0] <= "z") { name = name[0].toUpperCase() + name.substring(1, name.length); } } return name; } static humanifyString(val, humanify) { if (!humanify || val === undefined) { return val; } if (humanify === IField_1.FieldValueHumanify.general) { return Utilities.humanifyObject(val).toString(); } return Utilities.humanifyMinecraftName(val); } static getHumanifiedObjectName(name) { if (typeof name !== "string") { name = name.toString(); } let firstColon = name.indexOf(":"); if (firstColon >= 0) { name = name.substring(firstColon + 1); } name = Utilities.humanifyMinecraftName(name); name = name.replace(/ /gi, ""); return name; } static sanitizeJavascriptName(name) { name = name.trim(); name = name.replace(/</gi, "LessThan"); name = name.replace(/>/gi, "GreaterThan"); name = name.replace(/=/gi, "Equals"); name = name.replace(/!/gi, "Not"); name = name.replace(/\+/gi, "Plus"); name = name.replace(/,/gi, ""); name = name.replace(/-/gi, ""); name = name.replace(/\./gi, ""); name = name.replace(/'/gi, ""); name = name.replace(/ /gi, ""); name = name.replace(/\[/gi, ""); name = name.replace(/\]/gi, ""); name = name.replace(/"/gi, ""); name = name.replace(/\{/gi, ""); name = name.replace(/\}/gi, ""); name = name.replace(/</gi, ""); name = name.replace(/>/gi, ""); name = name.replace(/\*/gi, ""); name = name.replace(/\?/gi, ""); name = name.replace(/\\/gi, ""); name = name.replace(/\|/gi, ""); if (name.length > 0 && name[0] >= "0" && name[0] <= "9") { name = "_" + name; } if (name.indexOf(":") >= 0) { name = '"' + name + '"'; } return name; } static javascriptifyName(name, capitalizeFrst) { name = name.trim(); let retVal = ""; let capitalizeNext = capitalizeFrst === true; for (let i = 0; i < name.length; i++) { if (name[i] === " " || name[i] === "_" || name[i] === ":" || name[i] === "," || name[i] === "." || name[i] === '"' || name[i] === "'" || name[i] === "+" || name[i] === "-" || name[i] === ":" || name[i] === "[" || name[i] === "]") { capitalizeNext = true; } else { if (capitalizeNext) { retVal += name[i].toUpperCase(); capitalizeNext = false; } else { retVal += name[i]; } } } retVal = this.sanitizeJavascriptName(retVal); return retVal; } static humanifyMinecraftName(name) { if (typeof name === "boolean" || typeof name === "number") { return name.toString(); } if (name.endsWith(".behavior")) { name = name.substring(0, name.length - 9); } else if (name.endsWith(".geo")) { name = name.substring(0, name.length - 4); } else if (name.endsWith(".entity")) { name = name.substring(0, name.length - 7); } const colon = name.indexOf(":"); if (colon >= 0 && name.substring(0, colon) === "minecraft") { name = name.substring(colon + 1); } const leftBracket = name.indexOf("["); const rightBracket = name.indexOf("]"); if (leftBracket >= 0 && rightBracket > leftBracket) { name = name.substring(0, leftBracket) + name.substring(rightBracket + 1); } if (name.endsWith(".")) { name = name.substring(0, name.length - 1); } name = name.replace(/[_]/gi, " "); if (name.endsWith("_bit")) { name = name.substring(0, name.length - 4); } name = name.replace(/::/gi, " "); name = name.replace(/:/gi, " "); name = name.replace("SharedTypes ", ""); if (name.startsWith("Struct ") || name.startsWith("struct ")) { name = name.substring(7); } if ((name.startsWith("Enum ") || name.startsWith("enum ")) && name.indexOf("num_property") < 0) { name = name.substring(5); } const lastPeriod = name.indexOf("."); if (lastPeriod >= 4) { name = name.substring(lastPeriod + 1) + " " + name.substring(0, lastPeriod); } /* if (name.length > 1) { if (name[0] >= "a" && name[0] <= "z") { name = name[0].toUpperCase() + name.substring(1, name.length); } }*/ let lastCharWasSpace = false; for (let i = 0; i < name.length; i++) { if (name[i] === " ") { lastCharWasSpace = true; } else { if ((lastCharWasSpace || i === 0) && name[i] >= "a" && name[i] <= "z") { name = name.substring(0, i) + name[i].toUpperCase() + name.substring(i + 1); } lastCharWasSpace = false; } } return name; } static dehumanifyMinecraftName(name) { if (!name || typeof name === "boolean" || typeof name === "number") { return name; } // if this is already a technical name, return; if (name.indexOf(":") >= 0) { return name; } name = name.toLowerCase(); name = name.replace(/ /gi, "_"); name = "minecraft:" + name; return name; } static stringFormat(templateString, ...vals) { var args = arguments; return arguments[0].replace(/{(\d+)}/g, function (content, interior) { try { const num = parseInt(interior); if (!isNaN(num)) { return args[num + 1] !== undefined ? args[num + 1] : content; } } catch (e) { } return content; }); } static convertToHexString(byteArray) { return Array.from(byteArray, function (byte) { return ("0" + (byte & 0xff).toString(16)).slice(-2); }).join(""); } static countSignificantLines(content) { if (content.length <= 0) { return 0; } let lineCount = 1; let curStart = 0; let nextNewline = content.indexOf("\n"); while (nextNewline >= curStart) { let curContent = content.substring(curStart, nextNewline).trim(); if (curContent.length > 1) { lineCount++; } curStart = nextNewline + 1; nextNewline = content.indexOf("\n", curStart); } return lineCount; } static stripLinesContaining(content, lineContains) { let i = content.indexOf(lineContains); while (i >= 0) { let prevNewLine = content.lastIndexOf("\n", i); if (prevNewLine < 0) { prevNewLine = 0; } let nextNewLine = content.indexOf("\n", i); if (nextNewLine < 0) { nextNewLine = content.length; } content = content.substring(0, prevNewLine) + content.substring(nextNewLine, content.length); i = content.indexOf(lineContains); } return content; } static replaceJsonValue(jsonContent, attributeName, newValue) { let nextAttribute = jsonContent.indexOf('"' + attributeName + '":'); while (nextAttribute >= 0) { const subsequentOpenQuote = jsonContent.indexOf('"', nextAttribute + attributeName.length + 3); if (subsequentOpenQuote > nextAttribute + attributeName.length + 2 && subsequentOpenQuote < nextAttribute + attributeName.length + 7) { const subsequentEndQuote = jsonContent.indexOf('"', subsequentOpenQuote + 1); if (subsequentEndQuote > subsequentOpenQuote) { jsonContent = jsonContent.substring(0, subsequentOpenQuote + 1) + newValue + jsonContent.substring(subsequentEndQuote); } } nextAttribute = jsonContent.indexOf('"' + attributeName + '":', nextAttribute + attributeName.length + 2); } return jsonContent; } static makeJsonVersionAgnostic(jsonContent) { jsonContent = Utilities.replaceJsonValue(jsonContent, "generatorVersion", "TESTSUB"); jsonContent = Utilities.replaceJsonValue(jsonContent, "uuid", "TESTSUB"); return jsonContent; } static isEscaped(jsonString, quotePosition) { let index = quotePosition - 1; let backslashCount = 0; while (jsonString[index] === "\\") { index -= 1; backslashCount += 1; } return Boolean(backslashCount % 2); } static fixJsonContent(jsonString, { whitespace = true, trailingCommas = false } = {}) { if (typeof jsonString !== "string") { throw new TypeError(`Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``); } const strip = whitespace ? Utilities.stripWithWhitespace : Utilities.stripWithoutWhitespace; let isInsideString = false; let isInsideComment = false; let offset = 0; let buffer = ""; let result = ""; let commaIndex = -1; for (let index = 0; index < jsonString.length; index++) { const currentCharacter = jsonString[index]; const nextCharacter = jsonString[index + 1]; if (!isInsideComment && currentCharacter === '"') { // Enter or exit string const escaped = Utilities.isEscaped(jsonString, index); if (!escaped) { isInsideString = !isInsideString; } } if (isInsideString) { // fix control characters inside of strings, if they exist if (currentCharacter === "\r" || currentCharacter === "\n" || currentCharacter === "\t") { jsonString = jsonString.substring(0, index) + " " + jsonString.substring(index + 1); } continue; } if (!isInsideComment && currentCharacter + nextCharacter === "//") { // Enter single-line comment buffer += jsonString.slice(offset, index); offset = index; isInsideComment = singleComment; index++; } else if (isInsideComment === singleComment && currentCharacter + nextCharacter === "\r\n") { // Exit single-line comment via \r\n index++; isInsideComment = false; buffer += strip(jsonString, offset, index); offset = index; continue; } else if (isInsideComment === singleComment && currentCharacter === "\n") { // Exit single-line comment via \n isInsideComment = false; buffer += strip(jsonString, offset, index); offset = index; } else if (!isInsideComment && currentCharacter + nextCharacter === "/*") { // Enter multiline comment buffer += jsonString.slice(offset, index); offset = index; isInsideComment = multiComment; index++; continue; } else if (isInsideComment === multiComment && currentCharacter + nextCharacter === "*/") { // Exit multiline comment index++; isInsideComment = false; buffer += strip(jsonString, offset, index + 1); offset = index + 1; continue; } else if (trailingCommas && !isInsideComment) { if (commaIndex !== -1) { if (currentCharacter === "}" || currentCharacter === "]") { // Strip trailing comma buffer += jsonString.slice(offset, index); result += strip(buffer, 0, 1) + buffer.slice(1); buffer = ""; offset = index; commaIndex = -1; } else if (currentCharacter !== " " && currentCharacter !== "\t" && currentCharacter !== "\r" && currentCharacter !== "\n") { // Hit non-whitespace following a comma; comma is not trailing buffer += jsonString.slice(offset, index); offset = index; commaIndex = -1; } } else if (currentCharacter === ",") { // Flush buffer prior to this point, and save new comma index result += buffer + jsonString.slice(offset, index); buffer = ""; offset = index; commaIndex = index; } } } let results = result + buffer + (isInsideComment ? strip(jsonString.slice(offset), undefined, undefined) : jsonString.slice(offset)); results = results.replace(/,(\s*)]/g, "]"); // ["a", "b", ] => ["a", "b"] results = results.replace(/,(\s*)}/g, "}"); // { "foo": "bar", } => { "foo": "bar"} return results; } static setIsDebug(boolVal) { Utilities._isDebug = boolVal; } static getBaseUrl(url) { if (url.length < 8) { return url; } const slashIndex = url.indexOf("/", 9); if (slashIndex < 0) { return url; } return url.substring(0, slashIndex); } static getDateStr(date) { let dateStr = Utilities.frontPadToLength(date.getFullYear(), 4, "0"); dateStr += Utilities.frontPadToLength(date.getMonth() + 1, 2, "0"); dateStr += Utilities.frontPadToLength(date.getDate(), 2, "0"); dateStr += Utilities.frontPadToLength(date.getHours(), 2, "0"); dateStr += Utilities.frontPadToLength(date.getMinutes(), 2, "0"); dateStr += Utilities.frontPadToLength(date.getSeconds(), 2, "0"); return dateStr; } static getDateFromStr(dateStr) { if (!Utilities.isNumeric(dateStr) || dateStr.length !== 14) { throw new Error("Improperly formatted date string: " + dateStr); } const year = parseInt(dateStr.substring(0, 4)), month = parseInt(dateStr.substring(4, 6)), day = parseInt(dateStr.substring(6, 8)), hours = parseInt(dateStr.substring(8, 10)), minutes = parseInt(dateStr.substring(10, 12)), seconds = parseInt(dateStr.substring(12, 14)); Log_1.default.assert(year >= 2022, "Invalid year: " + dateStr); Log_1.default.assert(month >= 1 && month <= 12, "Invalid month: " + dateStr); Log_1.default.assert(day >= 0 && day <= 31, "Invalid day: " + dateStr); Log_1.default.assert(hours >= 0 && hours <= 23, "Invalid hours: " + dateStr); Log_1.default.assert(minutes >= 0 && minutes <= 59, "Invalid minutes: " + dateStr); Log_1.default.assert(seconds >= 0 && seconds <= 59, "Invalid seconds: " + dateStr); return new Date(year, month - 1, day, hours, minutes, seconds); } static lengthOfDictionary(d) { let c = 0; for (const i in d) { if (i) { ++c; } } return c; } static makeSafeForJson(content) { content = content.replace(/\\/g, "/"); content = content.replace(/"/gi, "'"); // this isn't the full way to do it, but for now... return content; } static isAlphaNumeric(candidate) { for (let i = 0; i < candidate.length; i++) { const charCode = candidate[i]; if (!((charCode >= "0" && charCode <= "9") || (charCode >= "a" && charCode <= "z") || (charCode >= "A" && charCode <= "Z"))) { return false; } } return true; } static getJsonObject(contents) { let jsonObject = undefined; contents = Utilities.fixJsonContent(contents); try { jsonObject = JSON.parse(contents); } catch (e) { Log_1.default.fail("Could not parse JSON: " + e.message); } return jsonObject; } static appendErrors(source, add, context) { if (!add.isInErrorState) { return; } source.isInErrorState = true; if (add.errorMessages) { if (source.errorMessages === undefined) { source.errorMessages = []; } for (const err of add.errorMessages) { let newContext = undefined; if (context) { newContext = err.context ? context + ": " + err.context : context; } else { newContext = err.context; } source.errorMessages.push({ message: err.message, context: newContext, }); } } } static isNumeric(candidate) { for (let i = 0; i < candidate.length; i++) { const charCode = candidate[i]; if ((charCode < "0" || charCode > "9") && charCode !== "." && (i > 0 || charCode !== "-")) { return false; } } return true; } static isNumericIsh(candidate) { for (let i = 0; i < candidate.length; i++) { const charCode = candidate[i]; if ((charCode < "0" || charCode > "9") && charCode !== "e" && charCode !== "+" && charCode !== "," && charCode !== "." && charCode !== "-") { return false; } } return true; } static removeQuotes(candidate) { candidate = candidate.trim(); if (candidate.startsWith('"')) { candidate = candidate.substring(1); } else if (candidate.startsWith('"')) { candidate = candidate.substring(0, candidate.length - 1); } return candidate; } static normalizeVersionString(candidate) { candidate = candidate.replace(/v/gi, "").trim(); candidate = candidate.trim(); if (candidate.startsWith(".")) { candidate = "0" + candidate; } if (candidate.endsWith(".")) { candidate = candidate.substring(0, candidate.length - 1); } return candidate; } static isVersionString(candidate) { for (let i = 0; i < candidate.length; i++) { const charCode = candidate[i]; if ((charCode < "0" || charCode > "9") && charCode !== "." && charCode !== "v") { return false; } } return true; } static isAlpha(candidate) { for (let i = 0; i < candidate.length; i++) { const charCode = candidate[i]; if (!((charCode >= "a" && charCode <= "z") || (charCode >= "A" && charCode <= "Z"))) { return false; } } return true; } static shallowCloneArray(source) { const newArr = new Array(source.length); for (let i = 0; i < source.length; i++) { newArr[i] = source[i]; } return newArr; } static uint8ArrayToBase64(bytes) { let binary = ""; const len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } if (CartoApp_1.default.isWeb || CartoApp_1.default.hostType === CartoApp_1.HostType.vsCodeMainWeb || CartoApp_1.default.hostType === CartoApp_1.HostType.vsCodeWebService) { return btoa(binary); } return Buffer.from(binary).toString("base64"); //btoa(binary); } static arrayBufferToBase64(buffer) { let binary = ""; const bytes = new Uint8Array(buffer); const len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } if (CartoApp_1.default.isWeb || CartoApp_1.default.hostType === CartoApp_1.HostType.vsCodeMainWeb || CartoApp_1.default.hostType === CartoApp_1.HostType.vsCodeWebService) { return btoa(binary); } return Buffer.from(binary).toString("base64"); // btoa(binary); } static base64ToArrayBuffer(base64buffer) { const start = base64buffer.indexOf(";base64,"); if (start > 0 && start < 50) { base64buffer = base64buffer.substring(start + 8); } const binary = atob(base64buffer); const arrayBuffer = new ArrayBuffer(binary.length); const bytes = new Uint8Array(arrayBuffer); const len = binary.length; for (var i = 0; i < len; i++) { bytes[i] = binary.charCodeAt(i); } return arrayBuffer; } static base64ToUint8Array(base64buffer) { const start = base64buffer.indexOf(";base64,"); if (start > 0 && start < 50) { base64buffer = base64buffer.substring(start + 8); } const binary = atob(base64buffer); const arrayBuffer = new ArrayBuffer(binary.length); const bytes = new Uint8Array(arrayBuffer); const len = binary.length; for (var i = 0; i < len; i++) { bytes[i] = binary.charCodeAt(i); } return bytes; } static canonicalizeId(id) { return id.toLowerCase(); } static readStringUTF8(buf, byteOffset, bytesToRead) { const nullTerm = typeof bytesToRead === "undefined"; var readPos = byteOffset || 0; if (!nullTerm && readPos + bytesToRead > buf.byteLength) { throw new Error("Attempted to read " + (readPos + bytesToRead - buf.byteLength) + " bytes past end of buffer"); } var str = ""; const charStruct = { bytesRead: 0, charVal: 0 }; while (readPos < buf.byteLength && (nullTerm || bytesToRead > readPos - byteOffset)) { Utilities._utf8ReadChar(charStruct, buf, readPos, nullTerm ? buf.byteLength - (readPos + byteOffset) : bytesToRead - (readPos - byteOffset)); readPos += charStruct.bytesRead; if (nullTerm && !charStruct.charVal) { break; } str += String.fromCharCode(charStruct.charVal); } return { str: str, byteLength: readPos - byteOffset, }; } static readStringASCII(buf, byteOffset, bytesToRead) { var str = ""; var byteLength = 0; byteOffset = byteOffset || 0; var nullTerm = false; if (typeof bytesToRead === "undefined") { nullTerm = true; bytesToRead = buf.byteLength - buf.byteOffset; } var charCode; for (var i = 0; i < bytesToRead; i++) { charCode = buf.getUint8(i + byteOffset); if (charCode === 0 && nullTerm) { break; } str += String.fromCharCode(charCode); byteLength++; } return { str: str, byteLength: byteLength + (nullTerm ? 1 : 0), }; } static readStringASCIIBuffer(buf, byteOffset, bytesToRead) { var str = ""; byteOffset = byteOffset || 0; var nullTerm = false; if (typeof bytesToRead === "undefined") { nullTerm = true; bytesToRead = buf.byteLength - buf.byteOffset; } var charCode; for (var i = 0; i < bytesToRead; i++) { charCode = buf[i + byteOffset]; if (charCode === 0 && nullTerm) { break; } str += String.fromCharCode(charCode); } return str; } static _createUtf8Char(charCode, arr) { if (charCode < 0x80) { arr.push(charCode); } else { const limits = [0x7f, 0x07ff, 0xffff, 0x1fffff]; let i = 0; while (true) { i++; if (i === limits.length) { Utilities._createUtf8Char(Utilities.replacementChar, arr); return; } if (charCode <= limits[i]) { i += 1; var aByte = 0; var j; for (j = 0; j < i; j++) { aByte <<= 1; aByte |= 1; } aByte <<= 8 - i; aByte |= charCode >> (6 * (i - 1)); arr.push(aByte); for (j = 1; j < i; j++) { aByte = 0x80; aByte |= (charCode >> (6 * (i - (j + 1)))) & 0xbf; arr.push(aByte); } return; } } } } static convertStringToBytes(str, encoding) { if (encoding === "UTF-8") { const arr = []; for (let i = 0; i < str.length; i++) { Utilities._createUtf8Char(str.charCodeAt(i), arr); } return arr; } else if (encoding === "ASCII") { const arr = []; for (let i = 0; i < str.length; i++) { let chr = str.charCodeAt(i); if (chr > 255) { chr = "?".charCodeAt(0); } arr.push(chr); } return arr; } throw new Error(); } static ensureNotStartsWithSlash(pathSegment) { while (pathSegment.startsWith("/")) { pathSegment = pathSegment.substring(1); } return pathSegment; } static ensureStartsWithSlash(pathSegment) { if (!pathSegment.startsWith("/")) { pathSegment = "/" + pathSegment; } return pathSegment; } static ensureEndsWithSlash(pathSegment) { if (!pathSegment.endsWith("/")) { pathSegment += "/"; } return pathSegment; } static ensureNotEndsWithSlash(pathSegment) { while (pathSegment.length > 0 && pathSegment.endsWith("/")) { pathSegment = pathSegment.substring(0, pathSegment.length - 1); } return pathSegment; } static ensureStartsWithBackSlash(pathSegment) { if (!pathSegment.startsWith("\\")) { pathSegment = "\\" + pathSegment; } return pathSegment; } static ensureEndsWithBackSlash(pathSegment) { if (!pathSegment.endsWith("\\")) { pathSegment += "\\"; } return pathSegment; } static replaceAll(content, fromToken, toToken) { let nextIndex = content.indexOf(fromToken); while (nextIndex >= 0) { content = content.substring(0, nextIndex) + toToken + content.substring(nextIndex + fromToken.length); nextIndex = content.indexOf(fromToken, nextIndex + toToken.length); } return content; } static replaceAllExceptInLines(content, fromToken, toToken, exceptInLinesWith) { let nextIndex = content.indexOf(fromToken); while (nextIndex >= 0) { let doReplace = true; let previousNewLine = content.lastIndexOf("\n", nextIndex); if (previousNewLine >= 0) { const previousPreviousNewLine = content.lastIndexOf("\n", previousNewLine - 1); if (previousPreviousNewLine >= 0) { previousNewLine = previousPreviousNewLine; } const lineSegment = content.substring(previousNewLine, nextIndex); for (const exceptIn of exceptInLinesWith) { if (lineSegment.indexOf(exceptIn) > 0) { doReplace = false; } } } if (doReplace) { content = content.substring(0, nextIndex) + toToken + content.substring(nextIndex + fromToken.length); nextIndex = content.indexOf(fromToken, nextIndex + toToken.length); } else { nextIndex = content.indexOf(fromToken, nextIndex + 1); } } return content; } static createRandomId(length) { let id = ""; for (let i = 0; i < length; i++) { const main = Math.random() * 6; if (main < 1) { id += String.fromCharCode(Math.floor(Math.random() * 10) + 48); } else if (main < 4) { id += String.fromCharCode(Math.floor(Math.random() * 26) + 65); } else { id += String.fromCharCode(Math.floor(Math.random() * 26) + 97); } } return id; } static canonicalizeUuid(uuidString) { return uuidString.trim().toLowerCase(); } static isValidUuid(uuidString) { return uuidString.length === 36; } static uuidEqual(uuidStringA, uuidStringB) { return Utilities.canonicalizeId(uuidStringA) === Utilities.canonicalizeId(uuidStringB); } static createUuid() { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { let val = CartoApp_1.default.generateCryptoRandomNumber(16); const r = val | 0, v = c === "x" ? r : (r & 0x3) | 0x8; return v.toString(16); }); } static uint8ArraysAreEqual(arrayA, arrayB) { if (arrayA.length !== arrayB.length) { return false; } for (let i = 0; i < arrayA.length; i++) { if (arrayA[i] !== arrayB[i]) { return false; } } return true; } static throwIfUint8ArraysNotEqual(arrayA, arrayB) { if (arrayA.length !== arrayB.length) { throw new Error("Arrays are of mismatched length."); } for (let i = 0; i < arrayA.length; i++) { if (arrayA[i] !== arrayB[i]) { throw new Error("Mismatch at position " + i + " value A: " + arrayA[i] + " value B:" + arrayB[i]); } } } static getString(view, byteOffset, byteLength, encoding) { if (encoding === "UTF8" || encoding === undefined) { const result = Utilities.readStringUTF8(view, byteOffset, byteLength); Log_1.default.assert(result.byteLength === byteLength, "UTGS"); return result.str; } else if (encoding === "ASCII") { const result = Utilities.readStringASCII(view, byteOffset, byteLength); return result.str; } return undefined; } static getSimpleString(str) { str = str.trim(); str = str.replace(/ /gi, ""); str = str.replace(/=/gi, ""); str = str.replace(/\?/gi, ""); return str; } static getAsciiString(view, byteOffset, byteLength, encoding) { const result = Utilities.readStringASCII(view, byteOffset, byteLength); return result.str; } static getAsciiStringFromBytes(bytes) { let str = ""; for (let i = 0; i < bytes.length; i++) { str += String.fromCharCode(bytes[i]); } return str; } static getAsciiStringFromUint8Array(bytes) { let str = ""; for (let i = 0; i < bytes.length; i++) { str += String.fromCharCode(bytes[i]); } return str; } static writeString(view, byteOffset, value, encoding) { const arr = Utilities.convertStringToBytes(value, encoding); if (arr === undefined) { return byteOffset; } let i = 0; for (i = 0; i < arr.length && byteOffset + i < view.byteLength; i++) { view.setUint8(byteOffset + i, arr[i]); } return byteOffset + i; } static frontPadToLength(val, length, pad) { val = val + ""; while (val.length < length) { val = pad + val; } return val; } static getShortYear(year) { let short = year + ""; // cast to string if (short.length === 4) { short = short.substring(2, 4); } return short; } static getFriendlySummary(date) { if (date === undefined || !(date instanceof Date)) { Log_1.default.fail("Empty/wrong-typed date passed in."); } let returnValue = this.monthShortNames[date.getMonth()] + " " + Utilities.frontPadToLength(date.getDate(), 2, "0"); const now = new Date(); if (date.getFullYear() !== now.getFullYear()) { returnValue += " " + this.getShortYear(date.getFullYear()); } else { let hours = date.getHours() % 12; if (hours === 0) { hours = 12; } returnValue += " " + Utilities.frontPadToLength(hours, 2, "0") + ":" + Utilities.frontPadToLength(date.getMinutes(), 2, "0"); } return returnValue; } static getFriendlySummarySeconds(date) { if (date === undefined || !(date instanceof Date)) { Log_1.default.fail("Empty/wrong-typed date passed in."); } return (this.monthShortNames[date.getMonth()] + " " + Utilities.frontPadToLength(date.getDate(), 2, "0") + " " + this.getShortYear(date.getFullYear()) + " " + Utilities.frontPadToLength(date.getHours(), 2, "0") + Utilities.frontPadToLength(date.getMinutes(), 2, "0") + "." + Utilities.frontPadToLength(date.getSeconds(), 2, "0")); } static getFileFriendlySummarySeconds(date) { if (date === undefined || !(date instanceof Date)) { Log_1.default.fail("Empty/wrong-typed date passed in."); } return (Utilities.frontPadToLength(date.getMonth() + 1, 2, "0") + "-" + Utilities.frontPadToLength(date.getDate(), 2, "0") + "-" + Utilities.frontPadToLength(date.getHours(), 2, "0") + Utilities.frontPadToLength(date.getMinutes(), 2, "0") + Utilities.frontPadToLength(date.getSeconds(), 2, "0")); } static getDateSummary(date) { return (date.getMonth() + 1 + "." + date.getDate() + "." + (date.getFullYear() - 2000) + "." + date.getHours() + "." + date.getMinutes() + "." + date.getSeconds()); } static countChar(source, find) { let count = 0; let index = source.indexOf(find); while (index >= 0) { count++; index = source.indexOf(find, index + find.length); } return count; } static isString(obj) { return typeof obj == "string"; } static isNullOrUndefined(object) { return object === undefined || object === null; } } exports.default = Utilities; Utilities.defaultEncoding = "UTF-8"; Utilities.replacementChar = 0xfffd; Utilities.stripWithoutWhitespace = () => ""; Utilities.stripWithWhitespace = (str, start, end) => str.slice(start, end).replace(/\S/g, " "); Utilities.monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ]; Utilities.monthShortNames = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ]; // UTF8 related string functions adapted from StrangelyTyped/StringView. Utilities._utf8ReadChar = function (charStruct, buf, readPos, maxBytes) { const firstByte = buf.getUint8(readPos); charStruct.bytesRead = 1; charStruct.charVal = 0; if (firstByte & 0x80) { var numBytes = 0; var aByte = firstByte; while (aByte & 0x80) { numBytes++; aByte <<= 1; } if (numBytes === 1) { charStruct.charVal = Utilities.replacementChar; return; } if (numBytes > maxBytes) { charStruct.charVal = Utilities.replacementChar; return; } //2 bytes means 3 bits reserved for UTF8 byte encoding, 5 bytes remaining for codepoint, and so on charStruct.charVal = firstByte & (0xff >> (numBytes + 1)); for (var i = 1; i < numBytes; i++) { aByte = buf.getUint8(readPos + i); //0xC0 should isolate the continuation flag which should be 0x80 if ((aByte & 0xc0) !== 0x80) { console.error("UTF-8 read - attempted to read " + numBytes + " byte character, found non-continuation at byte " + i); charStruct.charVal = Utilities.replacementChar; charStruct.bytesRead = 1; return; } charStruct.charVal <<= 6; charStruct.charVal |= aByte & 0x3f; if (i === 1) { const rshift = 8 - (numBytes + 1) - 1; if (charStruct.charVal >> rshift === 0) { charStruct.charVal = Utilities.replacementChar; charStruct.bytesRead = 1; return; } } charStruct.bytesRead++; } if (charStruct.charVal > 0x10ffff) { console.error("UTF-8 read - found illegally high code point " + charStruct.charVal); charStruct.charVal = Utilities.replacementChar; charStruct.bytesRead = 1; return; } } else { charStruct.charVal = firstByte; } }; //# sourceMappingURL=../maps/core/Utilities.js.map