|
@@ -0,0 +1,182 @@
|
|
|
|
|
+const PATH = require('path');
|
|
|
|
|
+const fs = require('fs');
|
|
|
|
|
+
|
|
|
|
|
+let defaultConfig = {
|
|
|
|
|
+ path: PATH.resolve('./', 'db')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param {String} dbName 文件名
|
|
|
|
|
+ * @param {Object} obj 初始数据,若文件存在将会替换内容
|
|
|
|
|
+ * @param {Object} config 配置文件
|
|
|
|
|
+ * @returns {Proxy} 对象
|
|
|
|
|
+ */
|
|
|
|
|
+function create(dbName = Date.now() + '', obj, config) {
|
|
|
|
|
+ config = { ...defaultConfig, ...config };
|
|
|
|
|
+
|
|
|
|
|
+ if (typeof dbName !== 'string') throw TypeError('dbName must be string');
|
|
|
|
|
+ if (!PATH.isAbsolute(config.path)) throw TypeError('config.path must be a absulute path');
|
|
|
|
|
+
|
|
|
|
|
+ let totalPath = PATH.resolve(config.path, dbName + '.json');
|
|
|
|
|
+
|
|
|
|
|
+ // 目录是否存在,不存在创建一个
|
|
|
|
|
+ if (!fs.existsSync(config.path)) {
|
|
|
|
|
+ fs.mkdirSync(config.path);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 文件是否存在,不存在创建一个
|
|
|
|
|
+ if (!fs.existsSync(totalPath)) {
|
|
|
|
|
+ fs.closeSync(fs.openSync(totalPath, 'w'));
|
|
|
|
|
+ if (!obj) { obj = {} };
|
|
|
|
|
+ fs.writeFileSync(totalPath, JSON.stringify(obj));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (obj) {
|
|
|
|
|
+ fs.writeFileSync(totalPath, JSON.stringify(obj));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ obj = JSON.parse(fs.readFileSync(totalPath));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ const objectList = new WeakMap()//key: target, value: proxy
|
|
|
|
|
+
|
|
|
|
|
+ // proxyList 避免proxy对象再次被proxy
|
|
|
|
|
+ const proxyList = new WeakMap()//key: proxy, value: target
|
|
|
|
|
+
|
|
|
|
|
+ function reactive(target) {
|
|
|
|
|
+ let proxy = objectList.get(target);
|
|
|
|
|
+ //如果存在,即返回
|
|
|
|
|
+ if (proxy !== void 0) {
|
|
|
|
|
+ return proxy
|
|
|
|
|
+ }
|
|
|
|
|
+ // 如果target是proxy
|
|
|
|
|
+ if (proxyList.has(target)) {
|
|
|
|
|
+ return target
|
|
|
|
|
+ }
|
|
|
|
|
+ // 如果是基本类型,直接返回
|
|
|
|
|
+ if (!isObject(target)) {
|
|
|
|
|
+ return target
|
|
|
|
|
+ }
|
|
|
|
|
+ proxy = new Proxy(target, handle)
|
|
|
|
|
+ objectList.set(target, proxy)
|
|
|
|
|
+ proxyList.set(proxy, target)
|
|
|
|
|
+
|
|
|
|
|
+ return proxy;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ const handle = { get, set, deleteProperty };
|
|
|
|
|
+
|
|
|
|
|
+ function get(target, propKey, receiver) {
|
|
|
|
|
+ // console.log('get')
|
|
|
|
|
+ let proxy = Reflect.get(target, propKey, receiver);
|
|
|
|
|
+ track(target, 'get', propKey)
|
|
|
|
|
+ return isObject(proxy) ? reactive(proxy) : proxy;
|
|
|
|
|
+ //实现多层代理,若为对象,需要递归
|
|
|
|
|
+ }
|
|
|
|
|
+ function set(target, propKey, value, receiver) {
|
|
|
|
|
+ const oldvalue = target[propKey];
|
|
|
|
|
+
|
|
|
|
|
+ let proxy = Reflect.set(target, propKey, value, receiver)
|
|
|
|
|
+ // 当是新增的属性 或者 数据变化时 ,trigger
|
|
|
|
|
+ if (!target.hasOwnProperty(propKey)) {
|
|
|
|
|
+ trigger(target, 'add', propKey)
|
|
|
|
|
+ } else if (oldvalue !== value) {
|
|
|
|
|
+ trigger(target, 'set', propKey)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fs.writeFileSync(totalPath, JSON.stringify(obj));
|
|
|
|
|
+
|
|
|
|
|
+ return proxy
|
|
|
|
|
+ }
|
|
|
|
|
+ function deleteProperty(target, propKey) {
|
|
|
|
|
+ // console.log('删除')
|
|
|
|
|
+ let proxy = Reflect.deleteProperty(target, propKey)
|
|
|
|
|
+ trigger(target, 'delete', propKey)
|
|
|
|
|
+
|
|
|
|
|
+ fs.writeFileSync(totalPath, JSON.stringify(obj));
|
|
|
|
|
+ return proxy
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //方法
|
|
|
|
|
+ function isObject(val) {
|
|
|
|
|
+ return typeof val === 'object' && val !== null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //effect.js
|
|
|
|
|
+
|
|
|
|
|
+ //收集依赖
|
|
|
|
|
+ let targetMap = new WeakMap()//所有依赖 key:obj
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //get 时 收集依赖
|
|
|
|
|
+ function track(target, type, key) {
|
|
|
|
|
+ // console.log('track-收集依赖', type, target, key)
|
|
|
|
|
+
|
|
|
|
|
+ if (effectFn) {
|
|
|
|
|
+ let depsMap = targetMap.get(target);
|
|
|
|
|
+ //targetMap无target对象,则新建
|
|
|
|
|
+ if (depsMap === void 0) {
|
|
|
|
|
+ // console.log('无depsMap')
|
|
|
|
|
+ targetMap.set(target, (depsMap = new Map()))
|
|
|
|
|
+ }
|
|
|
|
|
+ //depsMap无有key这个属性,则新建
|
|
|
|
|
+ let dep = depsMap.get(key)
|
|
|
|
|
+ if (dep === void 0) {
|
|
|
|
|
+ // console.log('无key')
|
|
|
|
|
+ depsMap.set(key, (dep = new Set()))
|
|
|
|
|
+ }
|
|
|
|
|
+ // 放入依赖 effect就是依赖
|
|
|
|
|
+ if (!dep.has(effectFn)) {
|
|
|
|
|
+ // console.log('无effect,并放入effect')
|
|
|
|
|
+ dep.add(effectFn)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //set 时更新
|
|
|
|
|
+ function trigger(target, type, key) {
|
|
|
|
|
+ // console.log('trigger-触发依赖', type, key)
|
|
|
|
|
+
|
|
|
|
|
+ let depsMap = targetMap.get(target)
|
|
|
|
|
+
|
|
|
|
|
+ if (depsMap) {
|
|
|
|
|
+ let deps = depsMap.get(key)
|
|
|
|
|
+ if (deps) {
|
|
|
|
|
+ //将当前key对应的effect一次执行
|
|
|
|
|
+ deps.forEach(effect => {
|
|
|
|
|
+ effect()
|
|
|
|
|
+ })
|
|
|
|
|
+ // 删除
|
|
|
|
|
+ if (type == 'delete') {
|
|
|
|
|
+ // console.log('delete')
|
|
|
|
|
+ depsMap.delete(key)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ //临时存放 effect中的fn参数
|
|
|
|
|
+ let effectFn = null;
|
|
|
|
|
+
|
|
|
|
|
+ function effect(fn) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // console.log('try')
|
|
|
|
|
+ effectFn = fn;
|
|
|
|
|
+ fn();
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ // console.log('finally')
|
|
|
|
|
+ effectFn = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return reactive(obj);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+module.exports = {
|
|
|
|
|
+ create
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+
|