diff options
Diffstat (limited to 'ext/webstorage/01_webstorage.js')
-rw-r--r-- | ext/webstorage/01_webstorage.js | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/ext/webstorage/01_webstorage.js b/ext/webstorage/01_webstorage.js new file mode 100644 index 000000000..558522a3c --- /dev/null +++ b/ext/webstorage/01_webstorage.js @@ -0,0 +1,191 @@ +// 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) { + if (persistent) window.location; + + 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 (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); |