UNPKG

7.07 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var fs = require('fs');
6
7const hookKeys = Object.getOwnPropertyNames(Reflect);
8class DeepProxy {
9 constructor(root = {}) {
10 this._paths = new WeakMap();
11 if (typeof root !== "object") {
12 throw TypeError("Root value has to be of type object");
13 }
14 this._root = root;
15 const handler = {};
16 for (const hook of hookKeys) {
17 handler[hook] = (t, ...args) => {
18 const path = this._paths.get(t);
19 if (!path)
20 throw Error("Path not found");
21 //console.log(hook, ["root", ...path].join("."));
22 return this[hook](path,
23 //@ts-ignore
24 ...args);
25 };
26 }
27 this._handler = handler;
28 this.proxy = this.addPath([], Object.getPrototypeOf(this._root));
29 }
30 addPath(path, proto) {
31 const t = Array.isArray(proto) ? [] : Object.create(proto);
32 this._paths.set(t, path);
33 return new Proxy(t, this._handler);
34 }
35 getByPath(path) {
36 try {
37 const obj = path.reduce((o, k) => o[k], this._root);
38 if (!obj)
39 throw Error();
40 return obj;
41 }
42 catch (e) {
43 /* istanbul ignore next */
44 throw Error(`Trying to access property ${path.join(".")} failed. Probably because it was removed.`);
45 }
46 }
47 /** Always configurable to comply with:
48 * > A property cannot be reported as non-configurable, if it does not exists as an own property of the target object or if it exists as a configurable own property of the target object.
49 * > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/getOwnPropertyDescriptor (Invariants)
50 * */
51 getOwnPropertyDescriptor(path, prop) {
52 const target = this.getByPath(path);
53 const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
54 if (!descriptor)
55 return undefined;
56 return Object.assign(descriptor, { configurable: true });
57 }
58 get(path, prop) {
59 const target = this.getByPath(path);
60 const val = Reflect.get(target, prop);
61 if (typeof val === "object" && val) {
62 return this.addPath([...path, prop], Object.getPrototypeOf(val));
63 }
64 return val;
65 }
66}
67for (const key of Object.getOwnPropertyNames(Reflect)) {
68 // Ignore already defined hooks
69 if (DeepProxy.prototype[key])
70 continue;
71 // Create hook for all other traps
72 DeepProxy.prototype[key] = function (path, ...args) {
73 const target = this.getByPath(path);
74 return Reflect[key](target,
75 //@ts-ignore typescript miscalculates the length of args
76 ...args);
77 };
78}
79
80class BaseProxyStore extends DeepProxy {
81 constructor(root = {}) {
82 super(root);
83 }
84 get store() {
85 return this.proxy;
86 }
87 set store(store) {
88 // not 100% sure, this is safe
89 this._root = store;
90 this.set([], BaseProxyStore.ROOT);
91 }
92}
93BaseProxyStore.ROOT = Symbol("ProxyStore root");
94
95/*! *****************************************************************************
96Copyright (c) Microsoft Corporation. All rights reserved.
97Licensed under the Apache License, Version 2.0 (the "License"); you may not use
98this file except in compliance with the License. You may obtain a copy of the
99License at http://www.apache.org/licenses/LICENSE-2.0
100
101THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
102KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
103WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
104MERCHANTABLITY OR NON-INFRINGEMENT.
105
106See the Apache Version 2.0 License for specific language governing permissions
107and limitations under the License.
108***************************************************************************** */
109
110function __awaiter(thisArg, _arguments, P, generator) {
111 return new (P || (P = Promise))(function (resolve, reject) {
112 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
113 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
114 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
115 step((generator = generator.apply(thisArg, _arguments || [])).next());
116 });
117}
118
119function readJSON(path, fallback) {
120 try {
121 const json = fs.readFileSync(path).toString();
122 return JSON.parse(json);
123 }
124 catch (e) {
125 if (typeof fallback === "undefined")
126 throw e;
127 return fallback;
128 }
129}
130function writeJSON(path, obj, { pretty } = {}) {
131 if (pretty === true)
132 pretty = 2;
133 else if (pretty === false)
134 pretty = undefined;
135 fs.writeFileSync(path, JSON.stringify(obj, null, pretty));
136}
137class ProxyStore extends BaseProxyStore {
138 constructor(root = {}, { init = false, path, pretty = false, watch = false } = {
139 path: ""
140 }) {
141 if (typeof path !== "string" || !path) {
142 throw TypeError(`Invalid option path="${path}"`);
143 }
144 let r = root;
145 if (init) {
146 r = readJSON(path, r);
147 }
148 super(r);
149 this.path = path;
150 this.pretty = pretty;
151 if (watch) {
152 this.watcher = fs.watch(this.path, () => this.load());
153 }
154 }
155 load() {
156 this._root = readJSON(this.path, this._root);
157 }
158 save() {
159 return __awaiter(this, void 0, void 0, function* () {
160 writeJSON(this.path, this._root, { pretty: this.pretty });
161 });
162 }
163 //@ts-ignore
164 set(path, prop, val) {
165 const ret = prop === ProxyStore.ROOT ? true : super.set(path, prop, val);
166 this.save();
167 return ret;
168 }
169 //@ts-ignore
170 deleteProperty(path, prop) {
171 const ret = super.deleteProperty(path, prop);
172 this.save();
173 return ret;
174 }
175}
176
177function isProxyStoreConstructor(obj) {
178 return (BaseProxyStore === obj || Object.prototype.isPrototypeOf.call(BaseProxyStore, obj));
179}
180function proxy(param1, param2, param3) {
181 // First argument is a ProxyStore
182 if (isProxyStoreConstructor(param1)) {
183 const PS = param1;
184 return new PS({}, param2).store;
185 }
186 // Second argument is a ProxyStore
187 if (isProxyStoreConstructor(param2)) {
188 const PS = param2;
189 return new PS(param1, param3).store;
190 }
191 // No ProxyStore provided
192 throw TypeError("No ProxyStore or derivative of it provided");
193}
194
195exports.DeepProxy = DeepProxy;
196exports.ProxyStore = BaseProxyStore;
197exports.ProxyStoreFS = ProxyStore;
198exports.default = proxy;
199exports.proxy = proxy;