summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.json1
-rw-r--r--ext/bg/js/backend.js5
-rw-r--r--ext/bg/js/json-schema.js20
-rw-r--r--ext/bg/js/util.js20
-rw-r--r--ext/mixed/js/core.js67
-rw-r--r--test/dictionary-validate.js5
-rw-r--r--test/schema-validate.js5
-rw-r--r--test/test-schema.js5
8 files changed, 88 insertions, 40 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index b8b7bee8..b7ed0164 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -99,6 +99,7 @@
"getSetDifference": "readonly",
"escapeRegExp": "readonly",
"deferPromise": "readonly",
+ "clone": "readonly",
"EventDispatcher": "readonly",
"EventListenerCollection": "readonly",
"EXTENSION_IS_BROWSER_EDGE": "readonly"
diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js
index 344706d1..59a3de45 100644
--- a/ext/bg/js/backend.js
+++ b/ext/bg/js/backend.js
@@ -38,7 +38,6 @@
* profileConditionsDescriptorPromise
* requestJson
* requestText
- * utilIsolate
*/
class Backend {
@@ -875,7 +874,7 @@ class Backend {
for (const target of targets) {
try {
const result = this._modifySetting(target);
- results.push({result: utilIsolate(result)});
+ results.push({result: clone(result)});
} catch (e) {
results.push({error: errorToJson(e)});
}
@@ -889,7 +888,7 @@ class Backend {
for (const target of targets) {
try {
const result = this._getSetting(target);
- results.push({result: utilIsolate(result)});
+ results.push({result: clone(result)});
} catch (e) {
results.push({error: errorToJson(e)});
}
diff --git a/ext/bg/js/json-schema.js b/ext/bg/js/json-schema.js
index f62402f9..2e009a7a 100644
--- a/ext/bg/js/json-schema.js
+++ b/ext/bg/js/json-schema.js
@@ -90,7 +90,7 @@ class JsonSchemaProxyHandler {
throw new Error(`Property ${property} not supported`);
}
- value = JsonSchema.isolate(value);
+ value = JsonSchema.clone(value);
JsonSchemaProxyHandler.validate(value, propertySchema, new JsonSchemaTraversalInfo(value, propertySchema));
@@ -515,7 +515,7 @@ class JsonSchemaProxyHandler {
const schemaDefault = schema.default;
if (typeof schemaDefault !== 'undefined') {
- value = JsonSchema.isolate(schemaDefault);
+ value = JsonSchema.clone(schemaDefault);
type = JsonSchemaProxyHandler.getValueType(value);
assignDefault = !JsonSchemaProxyHandler.isValueTypeAny(value, type, schemaType);
}
@@ -628,19 +628,7 @@ class JsonSchema {
return JsonSchemaProxyHandler.getValidValueOrDefault(schema, value);
}
- static isolate(value) {
- if (value === null) { return null; }
-
- switch (typeof value) {
- case 'boolean':
- case 'number':
- case 'string':
- case 'bigint':
- case 'symbol':
- return value;
- }
-
- const stringValue = JSON.stringify(value);
- return typeof stringValue === 'string' ? JSON.parse(stringValue) : null;
+ static clone(value) {
+ return clone(value);
}
}
diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js
index edc19c6e..fa31b0d8 100644
--- a/ext/bg/js/util.js
+++ b/ext/bg/js/util.js
@@ -15,26 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-function utilIsolate(value) {
- if (value === null) { return null; }
-
- switch (typeof value) {
- case 'boolean':
- case 'number':
- case 'string':
- case 'bigint':
- case 'symbol':
- return value;
- }
-
- const stringValue = JSON.stringify(value);
- return typeof stringValue === 'string' ? JSON.parse(stringValue) : null;
-}
-
function utilFunctionIsolate(func) {
return function isolatedFunction(...args) {
try {
- args = args.map((v) => utilIsolate(v));
+ args = args.map((v) => clone(v));
return func.call(this, ...args);
} catch (e) {
try {
@@ -50,7 +34,7 @@ function utilFunctionIsolate(func) {
function utilBackgroundIsolate(data) {
const backgroundPage = chrome.extension.getBackgroundPage();
- return backgroundPage.utilIsolate(data);
+ return backgroundPage.clone(data);
}
function utilBackgroundFunctionIsolate(func) {
diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js
index 21b7bf5e..9b3ea3e2 100644
--- a/ext/mixed/js/core.js
+++ b/ext/mixed/js/core.js
@@ -157,6 +157,73 @@ function getSetDifference(set1, set2) {
);
}
+const clone = (() => {
+ // eslint-disable-next-line no-shadow
+ function clone(value) {
+ if (value === null) { return null; }
+ switch (typeof value) {
+ case 'boolean':
+ case 'number':
+ case 'string':
+ case 'bigint':
+ case 'symbol':
+ case 'undefined':
+ return value;
+ default:
+ return cloneInternal(value, new Set());
+ }
+ }
+
+ function cloneInternal(value, visited) {
+ if (value === null) { return null; }
+ switch (typeof value) {
+ case 'boolean':
+ case 'number':
+ case 'string':
+ case 'bigint':
+ case 'symbol':
+ case 'undefined':
+ return value;
+ case 'function':
+ return cloneObject(value, visited);
+ case 'object':
+ return Array.isArray(value) ? cloneArray(value, visited) : cloneObject(value, visited);
+ }
+ }
+
+ function cloneArray(value, visited) {
+ if (visited.has(value)) { throw new Error('Circular'); }
+ try {
+ visited.add(value);
+ const result = [];
+ for (const item of value) {
+ result.push(cloneInternal(item, visited));
+ }
+ return result;
+ } finally {
+ visited.delete(value);
+ }
+ }
+
+ function cloneObject(value, visited) {
+ if (visited.has(value)) { throw new Error('Circular'); }
+ try {
+ visited.add(value);
+ const result = {};
+ for (const key in value) {
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
+ result[key] = cloneInternal(value[key], visited);
+ }
+ }
+ return result;
+ } finally {
+ visited.delete(value);
+ }
+ }
+
+ return clone;
+})();
+
/*
* Async utilities
diff --git a/test/dictionary-validate.js b/test/dictionary-validate.js
index f1730852..446de38d 100644
--- a/test/dictionary-validate.js
+++ b/test/dictionary-validate.js
@@ -21,7 +21,10 @@ const {JSZip} = require('./yomichan-test');
const {VM} = require('./yomichan-vm');
const vm = new VM();
-vm.execute('bg/js/json-schema.js');
+vm.execute([
+ 'mixed/js/core.js',
+ 'bg/js/json-schema.js'
+]);
const JsonSchema = vm.get('JsonSchema');
diff --git a/test/schema-validate.js b/test/schema-validate.js
index 761f0a1c..4c01fa70 100644
--- a/test/schema-validate.js
+++ b/test/schema-validate.js
@@ -19,7 +19,10 @@ const fs = require('fs');
const {VM} = require('./yomichan-vm');
const vm = new VM();
-vm.execute('bg/js/json-schema.js');
+vm.execute([
+ 'mixed/js/core.js',
+ 'bg/js/json-schema.js'
+]);
const JsonSchema = vm.get('JsonSchema');
diff --git a/test/test-schema.js b/test/test-schema.js
index 7620ab16..f0a99c3b 100644
--- a/test/test-schema.js
+++ b/test/test-schema.js
@@ -19,7 +19,10 @@ const assert = require('assert');
const {VM} = require('./yomichan-vm');
const vm = new VM();
-vm.execute('bg/js/json-schema.js');
+vm.execute([
+ 'mixed/js/core.js',
+ 'bg/js/json-schema.js'
+]);
const JsonSchema = vm.get('JsonSchema');