@geodaoyu/accessor 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ type WatchCallback = (newValue: any, oldValue: any, propertyName: string, target: Accessor) => void;
2
+ interface WatchHandle extends Object {
3
+ /**
4
+ * Removes the watch handle.
5
+ */
6
+ remove(): void;
7
+ }
8
+ declare class Accessor {
9
+ declaredClass: string;
10
+ private _handles;
11
+ constructor(props?: object);
12
+ get(path: string): any;
13
+ set(path: string | object, value: any): this;
14
+ watch(path: string | string[], callback: WatchCallback): WatchHandle;
15
+ }
16
+ export default Accessor;
@@ -0,0 +1,89 @@
1
+ class Accessor {
2
+ declaredClass;
3
+ _handles;
4
+ constructor(props = {}) {
5
+ // 为当前实例创建一个代理
6
+ const proxy = new Proxy(this, {
7
+ set: (target, key, value, receiver) => {
8
+ if (key !== '_handles' && target._handles) {
9
+ const oldValue = target[key];
10
+ target._handles.forEach((handle) => {
11
+ if (handle.path === key) {
12
+ handle.callback(value, oldValue, key, target);
13
+ }
14
+ });
15
+ }
16
+ return Reflect.set(target, key, value, receiver);
17
+ }
18
+ });
19
+ // 初始化属性
20
+ for (let prop in props) {
21
+ proxy[prop] = props[prop];
22
+ }
23
+ proxy.declaredClass = "Accessor";
24
+ proxy._handles = new Set();
25
+ return proxy;
26
+ }
27
+ get(path) {
28
+ const dotIndex = path.indexOf(".");
29
+ if (dotIndex !== -1) {
30
+ const key = path.slice(0, dotIndex);
31
+ const value = path.slice(dotIndex + 1);
32
+ return this[key] && this[key].get(value);
33
+ }
34
+ return this[path];
35
+ }
36
+ set(path, value) {
37
+ if (typeof path === "string") {
38
+ const dotIndex = path.indexOf(".");
39
+ if (dotIndex !== -1) {
40
+ const key = path.slice(0, dotIndex);
41
+ const childPath = path.slice(dotIndex + 1);
42
+ if (this[key]) {
43
+ this[key].set(childPath, value);
44
+ }
45
+ }
46
+ else {
47
+ this[path] = value;
48
+ }
49
+ }
50
+ else {
51
+ for (const key in path) {
52
+ this.set(key, path[key]);
53
+ }
54
+ }
55
+ return this;
56
+ }
57
+ watch(path, callback) {
58
+ const handles = [];
59
+ const pathArray = [];
60
+ if (typeof path === "object") {
61
+ pathArray.push(...path);
62
+ }
63
+ if (typeof path === "string") {
64
+ if (path.includes(",")) {
65
+ pathArray.push(...path.replace(" ", "").split(","));
66
+ }
67
+ else {
68
+ pathArray.push(path);
69
+ }
70
+ }
71
+ pathArray.forEach((item) => {
72
+ const dotIndex = item.indexOf(".");
73
+ const handle = dotIndex !== -1
74
+ ? this[item.slice(0, dotIndex)].watch(item.slice(dotIndex + 1), callback)
75
+ : { path: item, callback };
76
+ handles.push(handle);
77
+ this._handles.add(handle);
78
+ });
79
+ const watchHandle = {
80
+ remove: () => {
81
+ handles.forEach((handle) => {
82
+ this._handles.delete(handle);
83
+ });
84
+ },
85
+ };
86
+ return watchHandle;
87
+ }
88
+ }
89
+ export default Accessor;
@@ -0,0 +1,2 @@
1
+ import Accessor from './accessor.js';
2
+ export default Accessor;
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import Accessor from './accessor.js';
2
+ export default Accessor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geodaoyu/accessor",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "mini @arcgis/core/core/Accessor & @arcgis/core/core/reactiveUtils",
5
5
  "main": "index.js",
6
6
  "module": "dist/index.js",
@@ -17,6 +17,12 @@
17
17
  "author": "GeoDaoyu",
18
18
  "license": "MIT",
19
19
  "type": "module",
20
+ "files": [
21
+ "dist/**/*",
22
+ "src/**/*",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
20
26
  "repository": {
21
27
  "type": "git",
22
28
  "url": "https://github.com/GeoDaoyu/Accessor.git"
@@ -1,31 +0,0 @@
1
- import Accessor from '../dist/index.js';
2
- import assert from 'assert';
3
-
4
- describe('#constructor()', function() {
5
- it('typeof accessor should be "object"', function() {
6
- const accessor = new Accessor();
7
- assert.strictEqual(typeof accessor, 'object');
8
- });
9
- /**
10
- * 可以通过 对象的形式给类 赋初值
11
- */
12
- it('accessor\'s props can be an object', function() {
13
- const view = new Accessor({
14
- zoom: 4,
15
- });
16
- assert.strictEqual(view.zoom, 4);
17
- });
18
- /**
19
- * 子类可以继承Accessor
20
- */
21
- it('subclass can extend from Accessor', function() {
22
- class View extends Accessor {
23
- constructor() {
24
- super();
25
- this.declaredClass = "View";
26
- }
27
- }
28
- const view = new View();
29
- assert.strictEqual(view instanceof Accessor, true);
30
- });
31
- });
package/test/get.test.js DELETED
@@ -1,34 +0,0 @@
1
- import Accessor from '../dist/index.js';
2
- import assert from 'assert';
3
-
4
- describe('#get()', function() {
5
- /**
6
- * 属性不存在,返回undefined
7
- */
8
- it('should return undefined when the property in the path does not exist', function() {
9
- const accessor = new Accessor();
10
- assert.strictEqual(accessor.get('map'), undefined);
11
- });
12
- /**
13
- * 设值取值
14
- */
15
- it('should return 4 when the property is set to 4', function() {
16
- const view = new Accessor();
17
- view.set('zoom', 4);
18
- assert.strictEqual(view.get('zoom'), 4);
19
- });
20
- it('deep path:should return undefined when the property in the path does not exist', function() {
21
- const view = new Accessor();
22
- assert.strictEqual(view.get('map.basemap'), undefined);
23
- });
24
- /**
25
- * 获取属性的属性
26
- */
27
- it('should return the property in the deep path', function() {
28
- const map = new Accessor();
29
- const basemap = new Accessor();
30
- map.set('basemap', basemap);
31
- basemap.set('title', 'World Topographic Map');
32
- assert.strictEqual(map.get('basemap.title'), 'World Topographic Map');
33
- });
34
- });
package/test/set.test.js DELETED
@@ -1,56 +0,0 @@
1
- import Accessor from "../dist/index.js";
2
- import assert from "assert";
3
-
4
- describe("#set()", function () {
5
- it("should return 4 when the property is set to 4", function () {
6
- const view = new Accessor();
7
- view.set("zoom", 4);
8
- assert.strictEqual(view.get("zoom"), 4);
9
- });
10
- it("should return 4 when the property is 4", function () {
11
- const view = new Accessor();
12
- view.zoom = 4;
13
- assert.strictEqual(view.zoom, 4);
14
- });
15
- /**
16
- * 设置属性的属性
17
- */
18
- it("deep path set property", function () {
19
- const map = new Accessor();
20
- const basemap = new Accessor();
21
- map.set("basemap", basemap);
22
- map.set("basemap.title", "World Topographic Map");
23
- assert.strictEqual(map.get("basemap.title"), "World Topographic Map");
24
- });
25
- /**
26
- * 设置属性的属性,当属性不存在的时候,不设置
27
- */
28
- it("deep path set property which does not exist", function () {
29
- const map = new Accessor();
30
- map.set("basemap.title", "World Topographic Map");
31
- assert.strictEqual(map.get("basemap.title"), undefined);
32
- });
33
- /**
34
- * 可以通过对象的形式批量设置属性
35
- */
36
- it("An object with key-value pairs can be passed into", function () {
37
- const view = new Accessor();
38
- view.set({
39
- center: [-4.4861, 48.3904],
40
- scale: 5000,
41
- });
42
- assert.strictEqual(view.get("scale"), 5000);
43
- });
44
- /**
45
- * 柯里化
46
- */
47
- it("An object with key-value pairs can be passed into", function () {
48
- const view = new Accessor();
49
- const updateView = view.set.bind(view);
50
- updateView({
51
- center: [-4.4861, 48.3904],
52
- scale: 5000,
53
- });
54
- assert.strictEqual(view.get("scale"), 5000);
55
- });
56
- });
@@ -1,168 +0,0 @@
1
- import Accessor from "../dist/index.js";
2
- import assert from "assert";
3
- class Counter extends Accessor {
4
- constructor() {
5
- super();
6
- this.number = 0;
7
- }
8
- setNumber = (value) => {
9
- this.number = value;
10
- };
11
- }
12
-
13
- describe("#watch()", function () {
14
- it("watch property change", function () {
15
- const result = [];
16
- const callback = (newValue, oldValue, propertyName, target) => {
17
- result.push(newValue, oldValue, propertyName, target);
18
- };
19
- const view = new Accessor();
20
- view.zoom = 4;
21
- view.watch("zoom", callback);
22
- view.zoom = 5;
23
- assert.deepStrictEqual(result, [5, 4, "zoom", view]);
24
- });
25
- /**
26
- * 深层属性的变更的监听
27
- * 注意,此时callback的target是指向 拥有这个属性的类,而不是最外层的类
28
- */
29
- it("watch deep path property change", function () {
30
- const result = [];
31
- const callback = (newValue, oldValue, propertyName, target) => {
32
- result.push(newValue, oldValue, propertyName, target);
33
- };
34
- const view = new Accessor({
35
- map: new Accessor({
36
- basemap: new Accessor({
37
- title: "streets-vector",
38
- }),
39
- }),
40
- });
41
- view.watch("map.basemap.title", callback);
42
- view.map.basemap.title = "topo-vector";
43
- assert.deepStrictEqual(result, [
44
- "topo-vector",
45
- "streets-vector",
46
- "title",
47
- view.map.basemap,
48
- ]);
49
- });
50
- /**
51
- * 一个callback监听多个属性, 字符串形式
52
- */
53
- it("watch multiple propertys change in string", function () {
54
- const result = [];
55
- const callback = (newValue, oldValue, propertyName, target) => {
56
- result.push(newValue, oldValue, propertyName, target);
57
- };
58
- const view = new Accessor({
59
- zoom: 12,
60
- scale: 144447.638572,
61
- });
62
- view.watch("zoom, scale", callback);
63
- view.zoom = 11;
64
- view.scale = 288895.277144;
65
- assert.deepStrictEqual(result, [
66
- 11,
67
- 12,
68
- "zoom",
69
- view,
70
- 288895.277144,
71
- 144447.638572,
72
- "scale",
73
- view,
74
- ]);
75
- });
76
- /**
77
- * 一个callback监听多个属性, 数组形式
78
- */
79
- it("watch multiple propertys change in string array", function () {
80
- const result = [];
81
- const callback = (newValue, oldValue, propertyName, target) => {
82
- result.push(newValue, oldValue, propertyName, target);
83
- };
84
- const view = new Accessor({
85
- zoom: 12,
86
- scale: 144447.638572,
87
- });
88
- view.watch(["zoom", "scale"], callback);
89
- view.zoom = 11;
90
- view.scale = 288895.277144;
91
- assert.deepStrictEqual(result, [
92
- 11,
93
- 12,
94
- "zoom",
95
- view,
96
- 288895.277144,
97
- 144447.638572,
98
- "scale",
99
- view,
100
- ]);
101
- });
102
- /**
103
- * 调用remove方法移除handle,callback将不执行
104
- */
105
- it("remove watch handle", function () {
106
- const result = [];
107
- const callback = (newValue, oldValue, propertyName, target) => {
108
- result.push(newValue, oldValue, propertyName, target);
109
- };
110
- const view = new Accessor();
111
- view.zoom = 4;
112
- const handle = view.watch("zoom", callback);
113
- handle.remove();
114
- view.zoom = 5;
115
- assert.deepStrictEqual(result, []);
116
- });
117
- /**
118
- * 只在注册的属性变更后执行callback
119
- */
120
- it("only watch registered property", function () {
121
- const result = [];
122
- const callback = (newValue, oldValue, propertyName, target) => {
123
- result.push(newValue, oldValue, propertyName, target);
124
- };
125
- const view = new Accessor();
126
- view.zoom = 4;
127
- view.watch("scale", callback);
128
- view.zoom = 5;
129
- assert.deepStrictEqual(result, []);
130
- });
131
- /**
132
- * 子类上的方法也可以被监听
133
- */
134
- it("watch subclass member", function () {
135
- const counter = new Counter();
136
- const result = [];
137
- const callback = (newValue, oldValue, propertyName, target) => {
138
- result.push(newValue, oldValue, propertyName, target);
139
- };
140
- counter.number = 4;
141
- counter.watch("number", callback);
142
- counter.setNumber(5);
143
-
144
- assert.deepStrictEqual(result, [5, 4, "number", counter]);
145
- });
146
-
147
- /**
148
- * 子类上的方法 监听变更次数
149
- */
150
- it("watch subclass member changed times", function () {
151
- const counter = new Counter();
152
- let times = 0;
153
- const callback = () => {
154
- times++;
155
- };
156
- counter.watch("number", callback);
157
- counter.number = 1; // +1;
158
- counter.number = 1; // +1;
159
- counter.set("number", 2); // +1;
160
- counter.set("number", 2); // +1;
161
- counter.set({ number: 3 }); // +1;
162
- counter.set({ number: 3 }); // +1;
163
- counter.setNumber(4); // +1;
164
- counter.setNumber(4); // +1;
165
-
166
- assert.equal(times, 8);
167
- });
168
- });
package/tsconfig.json DELETED
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "experimentalDecorators": true,
4
- "module": "Node16",
5
- "target": "ESNext",
6
- "sourceMap": false,
7
- "rootDir": "./src",
8
- "outDir": "./dist",
9
- "esModuleInterop": true,
10
- "declaration": true,
11
- "skipLibCheck": true,
12
- "moduleResolution": "node16",
13
- "verbatimModuleSyntax": true
14
- },
15
- "include": [
16
- "src/**/*.ts",
17
- ],
18
- "exclude": []
19
- }