@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
1,291 lines (1,289 loc) • 46.6 kB
JavaScript
;
// 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