@shaxpir/duiduidui-models 1.3.2 → 1.3.4
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.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/models/Model.d.ts +2 -0
- package/dist/models/Model.js +13 -2
- package/dist/repo/ShareSync.js +24 -5
- package/package.json +5 -1
- package/lib/index.ts +0 -7
- package/lib/models/ArrayView.ts +0 -203
- package/lib/models/BayesianScore.ts +0 -32
- package/lib/models/ChangeModel.ts +0 -94
- package/lib/models/Content.ts +0 -107
- package/lib/models/ContentKind.ts +0 -19
- package/lib/models/Device.ts +0 -90
- package/lib/models/GeoLocation.ts +0 -4
- package/lib/models/Hanzi.ts +0 -16
- package/lib/models/Manifest.ts +0 -171
- package/lib/models/Media.ts +0 -125
- package/lib/models/Metric.ts +0 -233
- package/lib/models/Model.ts +0 -325
- package/lib/models/Operation.ts +0 -205
- package/lib/models/Permissions.ts +0 -19
- package/lib/models/Phrase.ts +0 -53
- package/lib/models/Profile.ts +0 -117
- package/lib/models/Progress.ts +0 -101
- package/lib/models/Review.ts +0 -18
- package/lib/models/Session.ts +0 -149
- package/lib/models/Term.ts +0 -202
- package/lib/models/User.ts +0 -97
- package/lib/models/Workspace.ts +0 -129
- package/lib/models/index.ts +0 -24
- package/lib/repo/ConnectionListener.ts +0 -25
- package/lib/repo/PermissiveJson1.ts +0 -14
- package/lib/repo/ShareSync.ts +0 -383
- package/lib/repo/TextEditOps.ts +0 -50
- package/lib/repo/index.ts +0 -6
- package/lib/util/Encryption.ts +0 -5
- package/lib/util/Logging.ts +0 -568
- package/lib/util/index.ts +0 -4
- package/tsconfig.json +0 -25
- package/tslint.json +0 -46
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
/// <reference path="../decs.d.ts" />
|
|
19
|
+
require("../decs.d.ts");
|
|
19
20
|
__exportStar(require("./models"), exports);
|
|
20
21
|
__exportStar(require("./repo"), exports);
|
|
21
22
|
__exportStar(require("./util"), exports);
|
package/dist/models/Model.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export declare abstract class Model {
|
|
|
12
12
|
private _isForbidden;
|
|
13
13
|
private _shouldPerformModelChangeAnalysis;
|
|
14
14
|
private _dataBeforeOpBatch;
|
|
15
|
+
private _hasEventListeners;
|
|
16
|
+
private _setupEventListeners;
|
|
15
17
|
private _clearEventListeners;
|
|
16
18
|
protected shareSync: ShareSync;
|
|
17
19
|
private _subscribingPromise;
|
package/dist/models/Model.js
CHANGED
|
@@ -8,6 +8,7 @@ const ChangeModel_1 = require("./ChangeModel");
|
|
|
8
8
|
class Model {
|
|
9
9
|
constructor(doc, shouldAcquire, shareSync) {
|
|
10
10
|
this._dataBeforeOpBatch = null;
|
|
11
|
+
this._setupEventListeners = null;
|
|
11
12
|
this._clearEventListeners = null;
|
|
12
13
|
this._subscribingPromise = null;
|
|
13
14
|
this._acquireCount = 0;
|
|
@@ -16,6 +17,7 @@ class Model {
|
|
|
16
17
|
model.shareSync = shareSync;
|
|
17
18
|
model._isDisposed = false;
|
|
18
19
|
model._isForbidden = false;
|
|
20
|
+
model._hasEventListeners = false;
|
|
19
21
|
// When a model is newly created, or retrieved via a "fetch query", treat that as an implicit
|
|
20
22
|
// call to "acquire", since the SharedDB doc object will eventually need to be disposed.
|
|
21
23
|
if (shouldAcquire) {
|
|
@@ -46,12 +48,18 @@ class Model {
|
|
|
46
48
|
shaxpir_common_1.Dispatch.publish(Model.CHANGED, change);
|
|
47
49
|
}
|
|
48
50
|
};
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
this._setupEventListeners = function () {
|
|
52
|
+
if (model.doc && model.doc.on) {
|
|
53
|
+
model.doc.on('before op batch', onBeforeOpBatch);
|
|
54
|
+
model.doc.on('op batch', onOpBatch);
|
|
55
|
+
model._hasEventListeners = true;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
51
58
|
this._clearEventListeners = function () {
|
|
52
59
|
if (model.doc && model.doc.off) {
|
|
53
60
|
model.doc.off('before op batch', onBeforeOpBatch);
|
|
54
61
|
model.doc.off('op batch', onOpBatch);
|
|
62
|
+
model._hasEventListeners = false;
|
|
55
63
|
}
|
|
56
64
|
};
|
|
57
65
|
}
|
|
@@ -78,6 +86,9 @@ class Model {
|
|
|
78
86
|
}
|
|
79
87
|
async acquire(minVersion) {
|
|
80
88
|
this._acquireCount++;
|
|
89
|
+
if (!this._hasEventListeners) {
|
|
90
|
+
this._setupEventListeners();
|
|
91
|
+
}
|
|
81
92
|
if (minVersion) {
|
|
82
93
|
this.log(`ACQUIRE: (${this.compoundKey}) at minVersion '${minVersion}'; acquireCount = ${this.acquireCount}`);
|
|
83
94
|
return this.ensureRecentData(minVersion);
|
package/dist/repo/ShareSync.js
CHANGED
|
@@ -45,6 +45,7 @@ const Content_1 = require("../models/Content");
|
|
|
45
45
|
const ContentKind_1 = require("../models/ContentKind");
|
|
46
46
|
const Device_1 = require("../models/Device");
|
|
47
47
|
const Manifest_1 = require("../models/Manifest");
|
|
48
|
+
const Session_1 = require("../models/Session");
|
|
48
49
|
const User_1 = require("../models/User");
|
|
49
50
|
// Register the ShareDB types
|
|
50
51
|
const Json1 = __importStar(require("./PermissiveJson1"));
|
|
@@ -335,18 +336,36 @@ class ShareSync {
|
|
|
335
336
|
}
|
|
336
337
|
wrap(kind, doc, shouldAcquire) {
|
|
337
338
|
const shareSync = this;
|
|
338
|
-
if (kind === ContentKind_1.ContentKind.
|
|
339
|
+
if (kind === ContentKind_1.ContentKind.DEVICE) {
|
|
340
|
+
return new Device_1.Device(doc, shouldAcquire, shareSync);
|
|
341
|
+
}
|
|
342
|
+
else if (kind === ContentKind_1.ContentKind.MANIFEST) {
|
|
339
343
|
return new Manifest_1.Manifest(doc, shouldAcquire, shareSync);
|
|
340
344
|
}
|
|
341
|
-
else if (kind === ContentKind_1.ContentKind.
|
|
342
|
-
return new
|
|
345
|
+
else if (kind === ContentKind_1.ContentKind.METRIC) {
|
|
346
|
+
return new models_1.Metric(doc, shouldAcquire, shareSync);
|
|
343
347
|
}
|
|
344
|
-
else if (kind === ContentKind_1.ContentKind.
|
|
345
|
-
return new
|
|
348
|
+
else if (kind === ContentKind_1.ContentKind.MEDIA) {
|
|
349
|
+
return new models_1.Media(doc, shouldAcquire, shareSync);
|
|
346
350
|
}
|
|
347
351
|
else if (kind === ContentKind_1.ContentKind.PROFILE) {
|
|
348
352
|
return new models_1.Profile(doc, shouldAcquire, shareSync);
|
|
349
353
|
}
|
|
354
|
+
else if (kind === ContentKind_1.ContentKind.PROGRESS) {
|
|
355
|
+
return new models_1.Progress(doc, shouldAcquire, shareSync);
|
|
356
|
+
}
|
|
357
|
+
else if (kind === ContentKind_1.ContentKind.SESSION) {
|
|
358
|
+
return new Session_1.Session(doc, shouldAcquire, shareSync);
|
|
359
|
+
}
|
|
360
|
+
else if (kind === ContentKind_1.ContentKind.TERM) {
|
|
361
|
+
return new models_1.Term(doc, shouldAcquire, shareSync);
|
|
362
|
+
}
|
|
363
|
+
else if (kind === ContentKind_1.ContentKind.USER) {
|
|
364
|
+
return new User_1.User(doc, shouldAcquire, shareSync);
|
|
365
|
+
}
|
|
366
|
+
else if (kind === ContentKind_1.ContentKind.WORKSPACE) {
|
|
367
|
+
return new models_1.Workspace(doc, shouldAcquire, shareSync);
|
|
368
|
+
}
|
|
350
369
|
throw new Error(`can't wrap content ${kind}/${doc.id}`);
|
|
351
370
|
}
|
|
352
371
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shaxpir/duiduidui-models",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.4",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/shaxpir/duiduidui-models"
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
},
|
|
13
13
|
"main": "dist/index.js",
|
|
14
14
|
"types": "dist/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"decs.d.ts"
|
|
18
|
+
],
|
|
15
19
|
"dependencies": {
|
|
16
20
|
"@shaxpir/sharedb": "^5.3.0",
|
|
17
21
|
"@shaxpir/shaxpir-common": "1.3.0",
|
package/lib/index.ts
DELETED
package/lib/models/ArrayView.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { JsonPath, Struct } from '@shaxpir/shaxpir-common';
|
|
2
|
-
import { Content } from "./Content";
|
|
3
|
-
import { BatchOperation, JsonPathSelect } from './Operation';
|
|
4
|
-
|
|
5
|
-
export class ArrayView<T> {
|
|
6
|
-
|
|
7
|
-
protected content:Content;
|
|
8
|
-
protected path:JsonPath;
|
|
9
|
-
|
|
10
|
-
constructor (content:Content, path:JsonPath) {
|
|
11
|
-
this.content = content;
|
|
12
|
-
this.path = path;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
private get root():T[] {
|
|
16
|
-
this.content.checkDisposed("ArrayView.root");
|
|
17
|
-
return JsonPathSelect.getValueAtPath(this.content.doc, this.path);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public get length():number {
|
|
21
|
-
this.content.checkDisposed("ArrayView.length");
|
|
22
|
-
return this.root.length;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
public get values():T[] {
|
|
26
|
-
this.content.checkDisposed("ArrayView.values");
|
|
27
|
-
return Struct.clone(this.root);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public get(idx:number):T {
|
|
31
|
-
this.content.checkDisposed("ArrayView.get");
|
|
32
|
-
return Struct.clone(this.root[idx]);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public indexOf(value:any):number {
|
|
36
|
-
this.content.checkDisposed("ArrayView.indexOf");
|
|
37
|
-
const array:T[] = JsonPathSelect.getValueAtPath(this.content.doc, this.path);
|
|
38
|
-
for (let i:number = 0; i < array.length; i++) {
|
|
39
|
-
if (array[i] == value) {
|
|
40
|
-
return i;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return -1;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
public includes(value:any):boolean {
|
|
47
|
-
this.content.checkDisposed("ArrayView.includes");
|
|
48
|
-
const array:T[] = JsonPathSelect.getValueAtPath(this.content.doc, this.path);
|
|
49
|
-
for (let i:number = 0; i < array.length; i++) {
|
|
50
|
-
if (array[i] == value) {
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
public firstIndexWhere(
|
|
58
|
-
predicate:(value:T) => boolean
|
|
59
|
-
):number {
|
|
60
|
-
this.content.checkDisposed("ArrayView.firstIndexWhere");
|
|
61
|
-
const array:T[] = JsonPathSelect.getValueAtPath(this.content.doc, this.path);
|
|
62
|
-
for (let i:number = 0; i < array.length; i++) {
|
|
63
|
-
if (predicate(array[i])) {
|
|
64
|
-
return i;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return -1;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public removeFirstWhere(
|
|
71
|
-
predicate:(value:T) => boolean
|
|
72
|
-
):void {
|
|
73
|
-
this.content.checkDisposed("ArrayView.removeFirstWhere");
|
|
74
|
-
const index:number = this.firstIndexWhere(predicate);
|
|
75
|
-
this.removeAt(index);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public removeAllWhere(
|
|
79
|
-
predicate:(value:T) => boolean
|
|
80
|
-
):void {
|
|
81
|
-
this.content.checkDisposed("ArrayView.removeAllWhere");
|
|
82
|
-
let foundMatch = false;
|
|
83
|
-
const batch = new BatchOperation(this.content);
|
|
84
|
-
const array:T[] = JsonPathSelect.getValueAtPath(this.content.doc, this.path);
|
|
85
|
-
for (let i:number = 0; i < array.length; i++) {
|
|
86
|
-
if (predicate(array[i])) {
|
|
87
|
-
const pathToElement:JsonPath = Struct.clone(this.path);
|
|
88
|
-
pathToElement.push(i);
|
|
89
|
-
batch.removeValueAtPath(pathToElement);
|
|
90
|
-
foundMatch = true;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
if (foundMatch) {
|
|
94
|
-
batch.commit();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
public forEach(
|
|
99
|
-
callback:(idx:number, value:T) => void
|
|
100
|
-
):void {
|
|
101
|
-
this.content.checkDisposed("ArrayView.forEach");
|
|
102
|
-
const array:T[] = JsonPathSelect.getValueAtPath(this.content.doc, this.path);
|
|
103
|
-
for (let i:number = 0; i < array.length; i++) {
|
|
104
|
-
callback(i, array[i]);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
public unshift(value:T):void {
|
|
109
|
-
this.content.checkDisposed("ArrayView.unshift");
|
|
110
|
-
const batch = new BatchOperation(this.content);
|
|
111
|
-
batch.unshiftIntoArray(this.path, value);
|
|
112
|
-
batch.commit();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
public push(value:T):void {
|
|
116
|
-
this.content.checkDisposed("ArrayView.push");
|
|
117
|
-
const batch = new BatchOperation(this.content);
|
|
118
|
-
batch.pushIntoArray(this.path, value);
|
|
119
|
-
batch.commit();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
public insert(idx:number, value:T):void {
|
|
123
|
-
this.content.checkDisposed("ArrayView.insert");
|
|
124
|
-
if (idx == this.length) {
|
|
125
|
-
this.push(value);
|
|
126
|
-
} else {
|
|
127
|
-
const batch = new BatchOperation(this.content);
|
|
128
|
-
batch.insertIntoArray(this.path, idx, value);
|
|
129
|
-
batch.commit();
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
public remove(value:T):void {
|
|
134
|
-
this.content.checkDisposed("ArrayView.remove");
|
|
135
|
-
const index:number = this.indexOf(value);
|
|
136
|
-
if (index >= 0) {
|
|
137
|
-
this.removeAt(index);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
public removeAt(index:number):void {
|
|
142
|
-
this.content.checkDisposed("ArrayView.removeAt");
|
|
143
|
-
const pathToElement:JsonPath = Struct.clone(this.path);
|
|
144
|
-
pathToElement.push(index);
|
|
145
|
-
const batch = new BatchOperation(this.content);
|
|
146
|
-
batch.removeValueAtPath(pathToElement);
|
|
147
|
-
batch.commit();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
public move(originIndex:number, destinationIndex:number):void {
|
|
151
|
-
this.content.checkDisposed("ArrayView.move");
|
|
152
|
-
if (originIndex != destinationIndex) {
|
|
153
|
-
const originPath:JsonPath = Struct.clone(this.path);
|
|
154
|
-
const destinationPath:JsonPath = Struct.clone(this.path);
|
|
155
|
-
originPath.push(originIndex);
|
|
156
|
-
destinationPath.push(destinationIndex);
|
|
157
|
-
const batch = new BatchOperation(this.content);
|
|
158
|
-
batch.move(originPath, destinationPath);
|
|
159
|
-
batch.commit();
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
public removeObjectPropertyAtIndex(index:number, fieldName:string):void {
|
|
164
|
-
this.content.checkDisposed("ArrayView.setObjectValueAtIndex");
|
|
165
|
-
const pathToElement:JsonPath = Struct.clone(this.path);
|
|
166
|
-
pathToElement.push(index);
|
|
167
|
-
const element:any = JsonPathSelect.getValueAtPath(this.content.doc, pathToElement);
|
|
168
|
-
if (element.hasOwnProperty(fieldName)) {
|
|
169
|
-
const pathToProperty:JsonPath = Struct.clone(this.path);
|
|
170
|
-
pathToProperty.push(fieldName);
|
|
171
|
-
const batch = new BatchOperation(this.content);
|
|
172
|
-
batch.removeValueAtPath(pathToProperty)
|
|
173
|
-
batch.commit();
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
public setObjectValueAtIndex(index:number, fieldName:string, newValue:any):void {
|
|
178
|
-
this.content.checkDisposed("ArrayView.setObjectValueAtIndex");
|
|
179
|
-
const pathToElement:JsonPath = Struct.clone(this.path);
|
|
180
|
-
pathToElement.push(index);
|
|
181
|
-
pathToElement.push(fieldName);
|
|
182
|
-
const prevValue:any = JsonPathSelect.getValueAtPath(this.content.doc, pathToElement);
|
|
183
|
-
if (!Struct.equals(prevValue, newValue)) {
|
|
184
|
-
const batch = new BatchOperation(this.content);
|
|
185
|
-
batch.setPathValue(pathToElement, newValue);
|
|
186
|
-
batch.commit();
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
public editObjectTextValueAtIndex(index:number, fieldName:string, newValue:string):void {
|
|
191
|
-
this.content.checkDisposed("ArrayView.editObjectTextValueAtIndex");
|
|
192
|
-
const pathToElement:JsonPath = Struct.clone(this.path);
|
|
193
|
-
pathToElement.push(index);
|
|
194
|
-
pathToElement.push(fieldName);
|
|
195
|
-
const prevValue:any = JsonPathSelect.getValueAtPath(this.content.doc, pathToElement);
|
|
196
|
-
if (!Struct.equals(prevValue, newValue)) {
|
|
197
|
-
const batch = new BatchOperation(this.content);
|
|
198
|
-
batch.editPathText(pathToElement, newValue);
|
|
199
|
-
batch.commit();
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Struct } from "@shaxpir/shaxpir-common";
|
|
2
|
-
import { ReviewResult } from "./Review";
|
|
3
|
-
|
|
4
|
-
export interface BayesianScore {
|
|
5
|
-
alpha:number;
|
|
6
|
-
beta:number;
|
|
7
|
-
theta:number;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export class BayesianScoreModel {
|
|
11
|
-
public static apply(
|
|
12
|
-
prevScore:BayesianScore,
|
|
13
|
-
result:ReviewResult,
|
|
14
|
-
weight:number
|
|
15
|
-
):BayesianScore {
|
|
16
|
-
if (isNaN(weight) || !isFinite(weight) || weight < 0 || weight > 1) {
|
|
17
|
-
throw new Error(`illegal weight value: ${weight}`);
|
|
18
|
-
}
|
|
19
|
-
const nextScore = Struct.clone(prevScore) as BayesianScore;
|
|
20
|
-
if (result == 'EASY') {
|
|
21
|
-
nextScore.alpha += (weight * 1.0);
|
|
22
|
-
} else if (result == 'GOOD') {
|
|
23
|
-
nextScore.alpha += (weight * 0.7);
|
|
24
|
-
} else if (result == 'HARD') {
|
|
25
|
-
nextScore.beta += (weight * 0.3);
|
|
26
|
-
} else if (result == 'FAIL') {
|
|
27
|
-
nextScore.beta += (weight * 1.0);
|
|
28
|
-
}
|
|
29
|
-
nextScore.theta = nextScore.alpha / (nextScore.alpha + nextScore.beta);
|
|
30
|
-
return nextScore;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { Tuples } from "@shaxpir/shaxpir-common";
|
|
2
|
-
import * as Changesets from 'json-diff-ts';
|
|
3
|
-
import { Operation } from "json-diff-ts";
|
|
4
|
-
import { Model } from "./Model";
|
|
5
|
-
|
|
6
|
-
export interface ChangeItem {
|
|
7
|
-
type:Operation;
|
|
8
|
-
path:string;
|
|
9
|
-
value?:any;
|
|
10
|
-
oldValue?:any;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface ModelChange {
|
|
14
|
-
local:boolean;
|
|
15
|
-
model:Model;
|
|
16
|
-
items:ChangeItem[];
|
|
17
|
-
op:any[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class Changes {
|
|
21
|
-
public static withPathPrefix(change:ModelChange, prefix:string):boolean {
|
|
22
|
-
let matchingItems:ChangeItem[] = Changes.havingPathPrefix(change, prefix);
|
|
23
|
-
return matchingItems.length > 0;
|
|
24
|
-
}
|
|
25
|
-
public static havingPathPrefix(change:ModelChange, prefix:string):ChangeItem[] {
|
|
26
|
-
let matchingItems:ChangeItem[] = [];
|
|
27
|
-
const items = change.items;
|
|
28
|
-
for (let i = 0, len = items.length; i < len; i++) {
|
|
29
|
-
const item = items[i];
|
|
30
|
-
if (item.path.startsWith(prefix)) {
|
|
31
|
-
matchingItems.push(item);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return matchingItems;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// We have our own ChangeModel logic for performaning a diff between two objects. The main difference
|
|
39
|
-
// between our model and the json-diff implementation is that we care about enumerating the full-path
|
|
40
|
-
// to all modified model data elements, so that various GUI mediators can match against those paths
|
|
41
|
-
// and decide whether or not to re-render a view. So, when a deeply-nested object is added into
|
|
42
|
-
// another deeply nested object, the change-model should include the full path to all new R-Values
|
|
43
|
-
// added in the change, rather than just the path to the root of the new tree branches.
|
|
44
|
-
export class ChangeModel {
|
|
45
|
-
public static between(before:any, after:any):ChangeItem[] {
|
|
46
|
-
let changeItems:ChangeItem[] = [];
|
|
47
|
-
const diff = Changesets.flattenChangeset(
|
|
48
|
-
Changesets.diff(before, after)
|
|
49
|
-
);
|
|
50
|
-
for (let i = 0; i < diff.length; i++) {
|
|
51
|
-
let diffItem = diff[i];
|
|
52
|
-
let type:Operation = diffItem.type;
|
|
53
|
-
let path:string = diffItem.path;
|
|
54
|
-
let value:any = diffItem.value;
|
|
55
|
-
let oldValue:any = diffItem.oldValue;
|
|
56
|
-
let valueType:string = diffItem.valueType;
|
|
57
|
-
let key:string = diffItem.key;
|
|
58
|
-
if (valueType === 'Object' || valueType == 'Array') {
|
|
59
|
-
let tuples = Tuples.of(value);
|
|
60
|
-
let fullPath = path;
|
|
61
|
-
if (/^\d+$/.test(key) && !path.endsWith('[' + key + ']')) {
|
|
62
|
-
fullPath = path + '[' + key + ']';
|
|
63
|
-
}
|
|
64
|
-
if (!/^\d+$/.test(key) && !path.endsWith('.' + key)) {
|
|
65
|
-
fullPath = path + '.' + key;
|
|
66
|
-
}
|
|
67
|
-
if (tuples.length == 0) {
|
|
68
|
-
if (type == 'REMOVE') {
|
|
69
|
-
changeItems.push({ type : type, path : fullPath, oldValue : value });
|
|
70
|
-
} else {
|
|
71
|
-
changeItems.push({ type : type, path : fullPath, value : value, oldValue : oldValue });
|
|
72
|
-
}
|
|
73
|
-
} else {
|
|
74
|
-
for (let j = 0; j < tuples.length; j++) {
|
|
75
|
-
let tuple = tuples[j];
|
|
76
|
-
let fullTuplePath = Tuples.stringifyPath(fullPath, tuple.path);
|
|
77
|
-
if (type == 'REMOVE') {
|
|
78
|
-
changeItems.push({ type : type, path : fullTuplePath, oldValue : tuple.val });
|
|
79
|
-
} else {
|
|
80
|
-
changeItems.push({ type : type, path : fullTuplePath, value : tuple.val });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
if (type == 'REMOVE') {
|
|
86
|
-
changeItems.push({ type : type, path : path, oldValue : value });
|
|
87
|
-
} else {
|
|
88
|
-
changeItems.push({ type : type, path : path, value : value, oldValue : oldValue });
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return changeItems;
|
|
93
|
-
}
|
|
94
|
-
}
|
package/lib/models/Content.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { Doc } from '@shaxpir/sharedb/lib/client';
|
|
2
|
-
import { CompactDateTime, MultiTime, Struct } from '@shaxpir/shaxpir-common';
|
|
3
|
-
import { ShareSync } from '../repo';
|
|
4
|
-
import { ContentKind } from './ContentKind';
|
|
5
|
-
import { DevicePayload } from './Device';
|
|
6
|
-
import { MediaPayload } from './Media';
|
|
7
|
-
import { MetricPayload } from './Metric';
|
|
8
|
-
import { Model } from './Model';
|
|
9
|
-
import { ProfilePayload } from "./Profile";
|
|
10
|
-
import { ProgressPayload } from './Progress';
|
|
11
|
-
import { SessionPayload } from './Session';
|
|
12
|
-
import { TermPayload } from './Term';
|
|
13
|
-
import { UserPayload } from './User';
|
|
14
|
-
import { WorkspacePayload } from './Workspace';
|
|
15
|
-
|
|
16
|
-
enum ContentIdBrand {}
|
|
17
|
-
enum ContentRefBrand {}
|
|
18
|
-
|
|
19
|
-
export type ContentId = string & ContentIdBrand;
|
|
20
|
-
export type ContentRef = (string & ContentRefBrand) | ContentId;
|
|
21
|
-
|
|
22
|
-
export interface ParsedContentRef {
|
|
23
|
-
id:ContentId;
|
|
24
|
-
kind?:ContentKind;
|
|
25
|
-
timestamp?:CompactDateTime;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface ContentBody {
|
|
29
|
-
meta:ContentMeta;
|
|
30
|
-
payload:ContentPayload;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface ContentMeta {
|
|
34
|
-
ref:ContentRef;
|
|
35
|
-
kind:ContentKind;
|
|
36
|
-
id:ContentId;
|
|
37
|
-
owner:ContentId;
|
|
38
|
-
created_at:MultiTime;
|
|
39
|
-
updated_at:MultiTime;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type ContentPayload =
|
|
43
|
-
DevicePayload
|
|
44
|
-
| MediaPayload
|
|
45
|
-
| MetricPayload
|
|
46
|
-
| ProfilePayload
|
|
47
|
-
| ProgressPayload
|
|
48
|
-
| SessionPayload
|
|
49
|
-
| TermPayload
|
|
50
|
-
| UserPayload
|
|
51
|
-
| WorkspacePayload;
|
|
52
|
-
|
|
53
|
-
export abstract class Content extends Model {
|
|
54
|
-
|
|
55
|
-
public static ID_LENGTH:number = 16;
|
|
56
|
-
|
|
57
|
-
constructor(doc:Doc, shouldAcquire:boolean, shareSync:ShareSync) {
|
|
58
|
-
super(doc, shouldAcquire, shareSync);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
public get meta():ContentMeta {
|
|
62
|
-
this.checkDisposed("Content.meta");
|
|
63
|
-
return this.doc.data.meta as ContentMeta;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
public get payload():ContentPayload {
|
|
67
|
-
this.checkDisposed("Content.payload");
|
|
68
|
-
return this.doc.data.payload as ContentPayload;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
public cloneContentBody():ContentBody {
|
|
72
|
-
this.checkDisposed("Content.cloneContentBody");
|
|
73
|
-
if (this.exists()) {
|
|
74
|
-
return Struct.clone(this.doc.data);
|
|
75
|
-
} else {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
public get id():ContentId {
|
|
81
|
-
this.checkDisposed("Content.id");
|
|
82
|
-
return this.meta.id as ContentId;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
public get updatedAt():MultiTime {
|
|
86
|
-
this.checkDisposed("Content.updatedAt");
|
|
87
|
-
return this.meta.updated_at as MultiTime;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
public get createdAt():MultiTime {
|
|
91
|
-
this.checkDisposed("Content.createdAt");
|
|
92
|
-
return this.meta.created_at as MultiTime;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
public get owner():ContentId {
|
|
96
|
-
this.checkDisposed("Content.owner");
|
|
97
|
-
return this.meta.owner as ContentId;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public async modelUpdated():Promise<void> {
|
|
101
|
-
this.checkDisposed("Content.modelUpdated");
|
|
102
|
-
this.acquire();
|
|
103
|
-
await this.shareSync.updateManifestForContent(this);
|
|
104
|
-
this.release();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export enum ContentKind {
|
|
2
|
-
|
|
3
|
-
// No models yet for these, but they're definitely coming
|
|
4
|
-
BILLING = "billing",
|
|
5
|
-
|
|
6
|
-
// These are all the current Content subclasses
|
|
7
|
-
DEVICE = "device",
|
|
8
|
-
METRIC = "metric",
|
|
9
|
-
PROFILE = "profile",
|
|
10
|
-
PROGRESS = "progress",
|
|
11
|
-
SESSION = "session",
|
|
12
|
-
TERM = "term",
|
|
13
|
-
USER = "user",
|
|
14
|
-
MEDIA = "media",
|
|
15
|
-
WORKSPACE = "workspace",
|
|
16
|
-
|
|
17
|
-
// These are used in the ShareDB system, but for internal bookkeeping, not for Content subclasses.
|
|
18
|
-
MANIFEST = "manifest",
|
|
19
|
-
}
|