mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
1c739470b5
Closes #11882 BREAKING CHANGE: Previously when `--location` was set, the unique storage key was derived from the the URL of the location instead of just the origin. This change correctly uses just the origin. This may cause previously persisted storage to change its key and data to not be available with the same location as before.
190 lines
4.8 KiB
JavaScript
190 lines
4.8 KiB
JavaScript
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
|
|
|
/// <reference path="../../core/internal.d.ts" />
|
|
|
|
((window) => {
|
|
const core = window.Deno.core;
|
|
const webidl = window.__bootstrap.webidl;
|
|
const {
|
|
Symbol,
|
|
SymbolFor,
|
|
ObjectDefineProperty,
|
|
ObjectFromEntries,
|
|
ObjectEntries,
|
|
ReflectGet,
|
|
Proxy,
|
|
} = window.__bootstrap.primordials;
|
|
|
|
const _persistent = Symbol("[[persistent]]");
|
|
|
|
class Storage {
|
|
[_persistent];
|
|
|
|
constructor() {
|
|
webidl.illegalConstructor();
|
|
}
|
|
|
|
get length() {
|
|
webidl.assertBranded(this, Storage);
|
|
return core.opSync("op_webstorage_length", this[_persistent]);
|
|
}
|
|
|
|
key(index) {
|
|
webidl.assertBranded(this, Storage);
|
|
const prefix = "Failed to execute 'key' on 'Storage'";
|
|
webidl.requiredArguments(arguments.length, 1, { prefix });
|
|
index = webidl.converters["unsigned long"](index, {
|
|
prefix,
|
|
context: "Argument 1",
|
|
});
|
|
|
|
return core.opSync("op_webstorage_key", index, this[_persistent]);
|
|
}
|
|
|
|
setItem(key, value) {
|
|
webidl.assertBranded(this, Storage);
|
|
const prefix = "Failed to execute 'setItem' on 'Storage'";
|
|
webidl.requiredArguments(arguments.length, 2, { prefix });
|
|
key = webidl.converters.DOMString(key, {
|
|
prefix,
|
|
context: "Argument 1",
|
|
});
|
|
value = webidl.converters.DOMString(value, {
|
|
prefix,
|
|
context: "Argument 2",
|
|
});
|
|
|
|
core.opSync("op_webstorage_set", {
|
|
keyName: key,
|
|
keyValue: value,
|
|
}, this[_persistent]);
|
|
}
|
|
|
|
getItem(key) {
|
|
webidl.assertBranded(this, Storage);
|
|
const prefix = "Failed to execute 'getItem' on 'Storage'";
|
|
webidl.requiredArguments(arguments.length, 1, { prefix });
|
|
key = webidl.converters.DOMString(key, {
|
|
prefix,
|
|
context: "Argument 1",
|
|
});
|
|
|
|
return core.opSync("op_webstorage_get", key, this[_persistent]);
|
|
}
|
|
|
|
removeItem(key) {
|
|
webidl.assertBranded(this, Storage);
|
|
const prefix = "Failed to execute 'removeItem' on 'Storage'";
|
|
webidl.requiredArguments(arguments.length, 1, { prefix });
|
|
key = webidl.converters.DOMString(key, {
|
|
prefix,
|
|
context: "Argument 1",
|
|
});
|
|
|
|
core.opSync("op_webstorage_remove", key, this[_persistent]);
|
|
}
|
|
|
|
clear() {
|
|
webidl.assertBranded(this, Storage);
|
|
core.opSync("op_webstorage_clear", this[_persistent]);
|
|
}
|
|
}
|
|
|
|
function createStorage(persistent) {
|
|
const storage = webidl.createBranded(Storage);
|
|
storage[_persistent] = persistent;
|
|
|
|
const proxy = new Proxy(storage, {
|
|
deleteProperty(target, key) {
|
|
if (typeof key == "symbol") {
|
|
delete target[key];
|
|
} else {
|
|
target.removeItem(key);
|
|
}
|
|
return true;
|
|
},
|
|
defineProperty(target, key, descriptor) {
|
|
if (typeof key == "symbol") {
|
|
ObjectDefineProperty(target, key, descriptor);
|
|
} else {
|
|
target.setItem(key, descriptor.value);
|
|
}
|
|
return true;
|
|
},
|
|
get(target, key) {
|
|
if (typeof key == "symbol") return target[key];
|
|
if (key in target) {
|
|
return ReflectGet(...arguments);
|
|
} else {
|
|
return target.getItem(key) ?? undefined;
|
|
}
|
|
},
|
|
set(target, key, value) {
|
|
if (typeof key == "symbol") {
|
|
ObjectDefineProperty(target, key, {
|
|
value,
|
|
configurable: true,
|
|
});
|
|
} else {
|
|
target.setItem(key, value);
|
|
}
|
|
return true;
|
|
},
|
|
has(target, p) {
|
|
return p === SymbolFor("Deno.customInspect") ||
|
|
(typeof target.getItem(p)) === "string";
|
|
},
|
|
ownKeys() {
|
|
return core.opSync("op_webstorage_iterate_keys", persistent);
|
|
},
|
|
getOwnPropertyDescriptor(target, key) {
|
|
if (arguments.length === 1) {
|
|
return undefined;
|
|
}
|
|
if (key in target) {
|
|
return undefined;
|
|
}
|
|
const value = target.getItem(key);
|
|
if (value === null) {
|
|
return undefined;
|
|
}
|
|
return {
|
|
value,
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
};
|
|
},
|
|
});
|
|
|
|
proxy[SymbolFor("Deno.customInspect")] = function (inspect) {
|
|
return `${this.constructor.name} ${
|
|
inspect({
|
|
length: this.length,
|
|
...ObjectFromEntries(ObjectEntries(proxy)),
|
|
})
|
|
}`;
|
|
};
|
|
|
|
return proxy;
|
|
}
|
|
|
|
let localStorage;
|
|
let sessionStorage;
|
|
|
|
window.__bootstrap.webStorage = {
|
|
localStorage() {
|
|
if (!localStorage) {
|
|
localStorage = createStorage(true);
|
|
}
|
|
return localStorage;
|
|
},
|
|
sessionStorage() {
|
|
if (!sessionStorage) {
|
|
sessionStorage = createStorage(false);
|
|
}
|
|
return sessionStorage;
|
|
},
|
|
Storage,
|
|
};
|
|
})(this);
|