test.js
code:test.js
export function type(obj) {
if (obj == null) {
return (obj + "").toLowerCase();
}
var deepType = Object.prototype.toString
.call(obj)
.slice(8, -1)
.toLowerCase();
if (deepType === "generatorfunction") {
return "function";
}
return deepType.match(
/^(array|bigint|date|error|function|generator|regexp|symbol)$/
)
? deepType
: typeof obj === "object" || typeof obj === "function"
? "object"
: typeof obj;
}
const escapedReplacements = new Map([
"\\'",
"\\x3C!--",
]);
const formatAsJSLiteral = (content) => {
const patternsToEscape =
/(\\|<(?:!--|\/?script))|(\p{Control})|(\p{Surrogate})/gu;
const patternsToEscapePlusSingleQuote =
/(\\|'|<(?:!--|\/?script))|(\p{Control})|(\p{Surrogate})/gu;
const escapePattern = (match, pattern, controlChar, loneSurrogate) => {
if (controlChar) {
if (escapedReplacements.has(controlChar)) {
return escapedReplacements.get(controlChar);
}
const twoDigitHex = toHexadecimal(controlChar.charCodeAt(0), 2);
return "\\x" + twoDigitHex;
}
if (loneSurrogate) {
const fourDigitHex = toHexadecimal(loneSurrogate.charCodeAt(0), 4);
return "\\u" + fourDigitHex;
}
if (pattern) {
return escapedReplacements.get(pattern) || "";
}
return match;
};
let escapedContent = "";
let quote = "";
if (!content.includes("'")) {
quote = "'";
escapedContent = content.replaceAll(patternsToEscape, escapePattern);
} else if (!content.includes('"')) {
quote = '"';
escapedContent = content.replaceAll(patternsToEscape, escapePattern);
} else if (!content.includes("`") && !content.includes("${")) {
quote = "`";
escapedContent = content.replaceAll(patternsToEscape, escapePattern);
} else {
quote = "'";
escapedContent = content.replaceAll(
patternsToEscapePlusSingleQuote,
escapePattern
);
}
return ${quote}${escapedContent}${quote};
};
class Serializable {
static check() {}
}
export class ObjectSerializer {
error = null;
indexStack = [];
deepTracing = false;
root = null;
constructor() {}
serialize(data) {
this.resetIndex();
const serializable = this.serializable(data);
return this.stringify(serializable);
}
serializable(data) {
const safeInput = this.getSafeSurface(data);
try {
this.tryStringify(safeInput);
this.deepTracing = false;
} catch (error) {
console.log({ error, safeInput });
this.error = error;
this.sanitizer(safeInput);
this.serializable(safeInput);
}
return safeInput;
}
stringify(data) {
return JSON.stringify(data, this.replacer.bind(this), 4);
// return JSON.stringify(data, null, 4);
}
tryStringify(data) {
this.stringify(data);
}
makeStringKeysObject(data) {
let output = {};
const keys = this.getKeys(data);
if (keys.length === 0) {
if ("toJSON" in data) {
output = data.toJSON();
} else {
output = this.getTag(data);
}
} else {
output = Object.fromEntries(
keys.map((x) => {
return [x.toString(), datax]; })
);
}
return output;
}
replacer(key, value) {
console.log({ key, value });
if (this.root === null) {
this.root = value;
}
let pointer = { "": this.root };
let flag = false;
this.indexStack = this.indexStack.reduce((newStack, index) => {
if (pointerkey === value && index === key.toString()) { flag = true;
return newStack;
} else if (flag) {
return newStack;
}
newStack.push(index);
return newStack;
}, []);
this.indexStack.push(key.toString());
// this.indexStack.push(key);
// if (this.previouskey !== value) { // this.resetIndex();
// }
// this.previous = value;
return this.getSafeSurface(value);
}
getErrorText(error) {
return error.toString();
}
getSafeSurface(data) {
let output = "";
const dataType = type(data);
switch (dataType) {
case "string":
output = data;
break;
case "number":
case "bigint":
case "boolean":
case "symbol":
case "regexp":
case "generator":
case "function":
output = data.toString();
break;
case "undefined":
output = "undefined";
break;
case "null":
output = "null";
break;
case "error":
output = this.getErrorText(data);
break;
case "date":
output = data.toLocaleString();
case "array":
output = data;
break;
default:
case "object":
output = this.makeStringKeysObject(data);
break;
}
return output;
}
// checkCircular(data) {
// let flag = false;
// if (this.objectStack.find((x) => x === data)) {
// flag = true;
// }
// this.objectStack.push(data);
// return flag;
// }
getKeys(data) {
const keys = [
Object.getOwnPropertyNames(data),
Object.getOwnPropertySymbols(data),
].flat();
return keys;
}
getTag(obj) {
return Object.prototype.toString.call(obj);
}
// getErrorType(error) {
// switch (error.name) {
// case "TypeError":
// if (error.message.toLowerCase().includes("circular")) {
// return "circular";
// }
// default:
// return "unknown";
// }
// }
sanitizer(data) {
// correct error in-place
// const errorRoot = this.getErrorRoot(data);
const errorParent = this.getErrorRootParent(data);
const errorKey = this.indexStack.slice(-1)0; // const errorText = this.getErrorText(this.error);
// const errorType = this.getErrorType(this.error);
const broken = new BrokenObject(errorParent, errorKey, this.error);
if (broken.trySimpleFix()) {
return;
}
this.resetIndex();
broken.mod((x) => this.getSafeSurface(x));
broken.test(this.tryStringify.bind(this)).catch((error) => {
// console.log({ error });
if (this.getErrorRootParent(broken.target) === null) {
broken.fixWithErrorText();
return;
}
const tempSerializer = new ObjectSerializer();
broken
.deepTest(tempSerializer.tryStringify.bind(tempSerializer))
.then(broken.fixWithErrorText.bind(broken), (error) => {
tempSerializer.resetIndex();
broken.mod((x) => tempSerializer.serializable(x));
});
});
// try {
// this.tryStringify(safeInput);
// } catch (error) {
// if (this.getErrorRootParent(safeInput) === null) {
// } else {
// // this.sanitizer(errorRoot);
// const keys = this.getKeys(safeInput);
// let errorCount = 0;
// const tempSerializer = new ObjectSerializer();
// for (const key in keys) {
// try {
// if (
// ) {
// tempSerializer.tryStringify(safeInputkey); // break;
// } else {
// throw new Error("");
// }
// } catch (error) {
// errorCount++;
// }
// }
// if (errorCount === keys.length) {
// } else {
// // safeinputに訂正してもエラーになるが、エラー発生地点は下位層であり、エラーにならないArray/Objectのchildをもっている
// // よって再帰実行で分割統治ができる
// tempSerializer.resetIndex();
// tempSerializer.serializable(safeInput);
// }
// }
// return;
// }
}
getErrorRoot(data) {
if (this.indexStack.length === 0) {
return data;
}
let index = this.indexStack.slice(-1)0; const parent = this.getErrorRootParent(data);
}
getErrorRootParent(data) {
let index = indexStack.shift();
if (
typeof index === "undefined" ||
(index === "" && indexStack.length === 0)
) {
return null;
}
let tracking = { "": data };
let parentOfParent = null;
while (indexStack.length > 0) {
parentOfParent = tracking;
tracking = trackingindex; index = indexStack.shift();
}
if (this.indexStack.length >= 2) {
tracking = this.makeStringKeysObject(tracking);
parentOfParent[this.indexStack.slice(-2)0] = tracking; }
return tracking;
}
resetIndex() {
this.indexStack = [];
}
}
class BrokenObject {
constructor(parent, key, error) {
this.parent = parent;
this.key = key;
this.error = error;
}
get target() {
}
set target(value) {
try {
Object.defineProperty(this.parent, this.key, {
value,
writable: true,
enumerable: true,
configurable: true,
});
} catch (error) {
this.fixWithErrorText();
}
}
get errorText() {
return this.error.toString();
}
mod(modifier) {
this.target = modifier(this.target);
}
getKeys() {
return [
Object.getOwnPropertyNames(this.target),
Object.getOwnPropertySymbols(this.target),
].flat();
}
test(testFunction) {
return new Promise((resolve, reject) => {
try {
testFunction(this.target);
resolve();
} catch (error) {
reject(error);
}
});
}
deepTest(testFunction) {
const keys = this.getKeys().filter((key) => {
return (
type(this.targetkey) === "object" || type(this.targetkey) === "array" );
});
return Promise.all(
keys.map((key) => {
const child = new BrokenObject(this.target, key, this.error);
return child.test(testFunction);
})
);
}
getErrorText() {
return this.error.toString();
}
getErrorType() {
switch (this.error.name) {
case "TypeError":
if (this.error.message.toLowerCase().includes("circular")) {
return "circular";
}
default:
return "unknown";
}
}
trySimpleFix() {
const errorType = this.getErrorType();
if (errorType === "circular") {
this.fixWithErrorText();
return true;
}
return false;
}
fixWithErrorText() {
this.mod(() => this.getErrorText());
}
}
export function strongAlert(data) {
alert(new ObjectSerializer().serialize(data));
// alert(objectSerializer(data));
}
export function strongConfirm(data) {
// return confirm(objectSerializer(data));
return confirm(new ObjectSerializer().serialize(data));
}
export function bisect(data, test) {
let _data = [];
if (test(data)) {
if (data.length === 1) {
return data;
} else {
const sep = Math.floor(data.length / 2);
_data = [
bisect(data.slice(0, sep), test),
bisect(data.slice(sep), test),
].flat();
}
}
return _data;
}
code:test_of_test.js
import(/api/code/${scrapbox.Project.name}/${scrapbox.Page.title}/test.js).then(({strongAlert}) => {
const report = {};
var cyclic = [];
cyclic.push(cyclic);
//report"sheets" = document.styleSheets; //debugger;
strongAlert(report);
})