notu 0.12.1 → 0.13.0
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/notu.mjs +39 -442
- package/dist/notu.umd.js +1 -1
- package/dist/types/TestHelpers.d.ts +1 -2
- package/dist/types/index.d.ts +2 -5
- package/dist/types/models/Note.d.ts +0 -21
- package/dist/types/models/NoteTag.d.ts +0 -15
- package/dist/types/services/HttpCacheFetcher.d.ts +0 -2
- package/dist/types/services/HttpClient.d.ts +0 -3
- package/dist/types/services/Notu.d.ts +1 -5
- package/dist/types/services/NotuCache.d.ts +0 -8
- package/dist/types/services/QueryParser.d.ts +5 -9
- package/package.json +1 -1
- package/dist/types/models/Attr.d.ts +0 -51
- package/dist/types/models/NoteAttr.d.ts +0 -23
- package/dist/types/services/NewQueryParser.d.ts +0 -18
package/dist/notu.mjs
CHANGED
|
@@ -1,151 +1,6 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => (__defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value), value);
|
|
4
|
-
class ModelWithState {
|
|
5
|
-
constructor() {
|
|
6
|
-
__publicField(this, "state", "NEW");
|
|
7
|
-
}
|
|
8
|
-
new() {
|
|
9
|
-
return this.state = "NEW", this;
|
|
10
|
-
}
|
|
11
|
-
clean() {
|
|
12
|
-
return this.state = "CLEAN", this;
|
|
13
|
-
}
|
|
14
|
-
dirty() {
|
|
15
|
-
return this.state = "DIRTY", this;
|
|
16
|
-
}
|
|
17
|
-
delete() {
|
|
18
|
-
return this.state = "DELETED", this;
|
|
19
|
-
}
|
|
20
|
-
get isNew() {
|
|
21
|
-
return this.state == "NEW";
|
|
22
|
-
}
|
|
23
|
-
get isClean() {
|
|
24
|
-
return this.state == "CLEAN";
|
|
25
|
-
}
|
|
26
|
-
get isDirty() {
|
|
27
|
-
return this.state == "DIRTY";
|
|
28
|
-
}
|
|
29
|
-
get isDeleted() {
|
|
30
|
-
return this.state == "DELETED";
|
|
31
|
-
}
|
|
32
|
-
validate(throwError = !1) {
|
|
33
|
-
return !0;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
class Attr extends ModelWithState {
|
|
37
|
-
constructor(name, description) {
|
|
38
|
-
super();
|
|
39
|
-
__publicField(this, "id", 0);
|
|
40
|
-
__publicField(this, "_name", "");
|
|
41
|
-
__publicField(this, "_description", "");
|
|
42
|
-
__publicField(this, "_type", "TEXT");
|
|
43
|
-
__publicField(this, "_space", null);
|
|
44
|
-
__publicField(this, "_color", null);
|
|
45
|
-
name && (this.name = name), description && (this.description = description);
|
|
46
|
-
}
|
|
47
|
-
get name() {
|
|
48
|
-
return this._name;
|
|
49
|
-
}
|
|
50
|
-
set name(value) {
|
|
51
|
-
value !== this._name && (this._name = value, this.isClean && this.dirty());
|
|
52
|
-
}
|
|
53
|
-
get description() {
|
|
54
|
-
return this._description;
|
|
55
|
-
}
|
|
56
|
-
set description(value) {
|
|
57
|
-
value !== this._description && (this._description = value, this.isClean && this.dirty());
|
|
58
|
-
}
|
|
59
|
-
get type() {
|
|
60
|
-
return this._type;
|
|
61
|
-
}
|
|
62
|
-
set type(value) {
|
|
63
|
-
if (!this.isNew)
|
|
64
|
-
throw Error("Cannot change an attribute's type once it has been created.");
|
|
65
|
-
this._type = value;
|
|
66
|
-
}
|
|
67
|
-
get isText() {
|
|
68
|
-
return this.type == "TEXT";
|
|
69
|
-
}
|
|
70
|
-
get isNumber() {
|
|
71
|
-
return this.type == "NUMBER";
|
|
72
|
-
}
|
|
73
|
-
get isBoolean() {
|
|
74
|
-
return this.type == "BOOLEAN";
|
|
75
|
-
}
|
|
76
|
-
get isDate() {
|
|
77
|
-
return this.type == "DATE";
|
|
78
|
-
}
|
|
79
|
-
asText() {
|
|
80
|
-
return this.type = "TEXT", this;
|
|
81
|
-
}
|
|
82
|
-
asNumber() {
|
|
83
|
-
return this.type = "NUMBER", this;
|
|
84
|
-
}
|
|
85
|
-
asBoolean() {
|
|
86
|
-
return this.type = "BOOLEAN", this;
|
|
87
|
-
}
|
|
88
|
-
asDate() {
|
|
89
|
-
return this.type = "DATE", this;
|
|
90
|
-
}
|
|
91
|
-
get space() {
|
|
92
|
-
return this._space;
|
|
93
|
-
}
|
|
94
|
-
set space(value) {
|
|
95
|
-
var _a;
|
|
96
|
-
if (value !== this._space) {
|
|
97
|
-
const idChanged = (value == null ? void 0 : value.id) != ((_a = this._space) == null ? void 0 : _a.id);
|
|
98
|
-
this._space = value, this.isClean && idChanged && this.dirty();
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
in(space) {
|
|
102
|
-
return this.space = space, this;
|
|
103
|
-
}
|
|
104
|
-
get color() {
|
|
105
|
-
return this._color;
|
|
106
|
-
}
|
|
107
|
-
set color(value) {
|
|
108
|
-
value !== this._color && (this._color = value, this.isClean && this.dirty());
|
|
109
|
-
}
|
|
110
|
-
duplicate() {
|
|
111
|
-
const output = this.duplicateAsNew();
|
|
112
|
-
return output.id = this.id, output.state = this.state, output;
|
|
113
|
-
}
|
|
114
|
-
duplicateAsNew() {
|
|
115
|
-
const output = new Attr();
|
|
116
|
-
return output.name = this.name, output.description = this.description, output.type = this.type, output.space = this.space, output.color = this.color, output;
|
|
117
|
-
}
|
|
118
|
-
validate(throwError = !1) {
|
|
119
|
-
let output = null;
|
|
120
|
-
if (this.space ? !this.isNew && this.id <= 0 ? output = "Attr id must be greater than zero if in non-new state." : this.color && !/^#?[A-z0-9]{6}$/.test(this.color) && (output = "Tag color is invalid, must be a 6 character hexadecimal.") : output = "Attr must belong to a space.", throwError && output != null)
|
|
121
|
-
throw Error(output);
|
|
122
|
-
return output == null;
|
|
123
|
-
}
|
|
124
|
-
get defaultValue() {
|
|
125
|
-
switch (this.type) {
|
|
126
|
-
case "TEXT":
|
|
127
|
-
return "";
|
|
128
|
-
case "NUMBER":
|
|
129
|
-
return 0;
|
|
130
|
-
case "BOOLEAN":
|
|
131
|
-
return !1;
|
|
132
|
-
case "DATE":
|
|
133
|
-
return /* @__PURE__ */ new Date();
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
toJSON() {
|
|
137
|
-
var _a;
|
|
138
|
-
return {
|
|
139
|
-
state: this.state,
|
|
140
|
-
id: this.id,
|
|
141
|
-
name: this.name,
|
|
142
|
-
description: this.description,
|
|
143
|
-
type: this.type,
|
|
144
|
-
spaceId: (_a = this.space) == null ? void 0 : _a.id,
|
|
145
|
-
color: this.color
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
4
|
class Notu {
|
|
150
5
|
constructor(client, cache) {
|
|
151
6
|
__publicField(this, "_client");
|
|
@@ -177,19 +32,6 @@ class Notu {
|
|
|
177
32
|
const spaceData = await this.client.saveSpace(space);
|
|
178
33
|
return this.cache.spaceSaved(spaceData);
|
|
179
34
|
}
|
|
180
|
-
getAttrs(space = null) {
|
|
181
|
-
return this.cache.getAttrs(space);
|
|
182
|
-
}
|
|
183
|
-
getAttr(id) {
|
|
184
|
-
return this.cache.getAttr(id);
|
|
185
|
-
}
|
|
186
|
-
getAttrByName(name, space) {
|
|
187
|
-
return this.cache.getAttrByName(name, space);
|
|
188
|
-
}
|
|
189
|
-
async saveAttr(attr) {
|
|
190
|
-
const attrData = await this.client.saveAttr(attr);
|
|
191
|
-
return this.cache.attrSaved(attrData);
|
|
192
|
-
}
|
|
193
35
|
getTags(space = null, includeOtherSpacePublics = !1) {
|
|
194
36
|
return this.cache.getTags(space, includeOtherSpacePublics);
|
|
195
37
|
}
|
|
@@ -209,72 +51,47 @@ class Notu {
|
|
|
209
51
|
return (await this.client.getRelatedNotes(tag)).map((n) => this.cache.noteFromJSON(n));
|
|
210
52
|
}
|
|
211
53
|
async saveNotes(notes) {
|
|
212
|
-
const notesData = await this.client.saveNotes(notes);
|
|
213
|
-
for (const noteData of notesData.filter((x) => !!x.ownTag))
|
|
54
|
+
const tagsBeingDeletedData = notes.filter((x) => !!x.ownTag).filter((x) => x.isDeleted || x.ownTag.isDeleted).map((x) => x.ownTag.toJSON()), notesData = await this.client.saveNotes(notes);
|
|
55
|
+
for (const noteData of notesData.filter((x) => !!x.ownTag && !x.ownTag.isDeleted))
|
|
214
56
|
noteData.ownTag.links = noteData.tags.map((x) => x.tagId), this.cache.tagSaved(noteData.ownTag);
|
|
57
|
+
for (const tagData of tagsBeingDeletedData)
|
|
58
|
+
tagData.state = "DELETED", this.cache.tagSaved(tagData);
|
|
215
59
|
return notes = notesData.map((n) => this.cache.noteFromJSON(n)), notes;
|
|
216
60
|
}
|
|
217
61
|
async customJob(name, data) {
|
|
218
62
|
return await this.client.customJob(name, data);
|
|
219
63
|
}
|
|
220
64
|
}
|
|
221
|
-
class
|
|
222
|
-
constructor(
|
|
223
|
-
|
|
224
|
-
__publicField(this, "_tag", null);
|
|
225
|
-
__publicField(this, "_attr", null);
|
|
226
|
-
__publicField(this, "_value", null);
|
|
227
|
-
if (!attr)
|
|
228
|
-
throw Error("Cannot instanciate new NoteAttr without a passed in attr.");
|
|
229
|
-
if (attr.isNew)
|
|
230
|
-
throw Error("Cannot create a NoteAttr object for an attr that hasn't been saved yet.");
|
|
231
|
-
if (attr.isDeleted)
|
|
232
|
-
throw Error("Cannot create a NoteAttr object for an attr marked as deleted.");
|
|
233
|
-
if (this._attr = attr, tag) {
|
|
234
|
-
if (tag.isNew)
|
|
235
|
-
throw Error("Cannot create a NoteAttr object linked to a tag that hasn't been saved yet.");
|
|
236
|
-
if (tag.isDeleted)
|
|
237
|
-
throw Error("Cannot create a NoteAttr object linked to a tag marked as deleted.");
|
|
238
|
-
this._tag = tag;
|
|
239
|
-
}
|
|
240
|
-
value != null && value != null ? this.value = value : this.value = attr.defaultValue;
|
|
65
|
+
class ModelWithState {
|
|
66
|
+
constructor() {
|
|
67
|
+
__publicField(this, "state", "NEW");
|
|
241
68
|
}
|
|
242
|
-
|
|
243
|
-
return this.
|
|
69
|
+
new() {
|
|
70
|
+
return this.state = "NEW", this;
|
|
71
|
+
}
|
|
72
|
+
clean() {
|
|
73
|
+
return this.state = "CLEAN", this;
|
|
244
74
|
}
|
|
245
|
-
|
|
246
|
-
return this.
|
|
75
|
+
dirty() {
|
|
76
|
+
return this.state = "DIRTY", this;
|
|
247
77
|
}
|
|
248
|
-
|
|
249
|
-
return this.
|
|
78
|
+
delete() {
|
|
79
|
+
return this.state = "DELETED", this;
|
|
250
80
|
}
|
|
251
|
-
|
|
252
|
-
|
|
81
|
+
get isNew() {
|
|
82
|
+
return this.state == "NEW";
|
|
253
83
|
}
|
|
254
|
-
|
|
255
|
-
return this.
|
|
84
|
+
get isClean() {
|
|
85
|
+
return this.state == "CLEAN";
|
|
256
86
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
return output.state = this.state, output;
|
|
87
|
+
get isDirty() {
|
|
88
|
+
return this.state == "DIRTY";
|
|
260
89
|
}
|
|
261
|
-
|
|
262
|
-
return
|
|
90
|
+
get isDeleted() {
|
|
91
|
+
return this.state == "DELETED";
|
|
263
92
|
}
|
|
264
93
|
validate(throwError = !1) {
|
|
265
|
-
|
|
266
|
-
if (throwError && output != null)
|
|
267
|
-
throw Error(output);
|
|
268
|
-
return output == null;
|
|
269
|
-
}
|
|
270
|
-
toJSON() {
|
|
271
|
-
var _a;
|
|
272
|
-
return {
|
|
273
|
-
state: this.state,
|
|
274
|
-
attrId: this.attr.id,
|
|
275
|
-
tagId: (_a = this.tag) == null ? void 0 : _a.id,
|
|
276
|
-
value: this.value
|
|
277
|
-
};
|
|
94
|
+
return !0;
|
|
278
95
|
}
|
|
279
96
|
}
|
|
280
97
|
class NoteTag extends ModelWithState {
|
|
@@ -282,7 +99,6 @@ class NoteTag extends ModelWithState {
|
|
|
282
99
|
super();
|
|
283
100
|
__publicField(this, "_tag");
|
|
284
101
|
__publicField(this, "_data");
|
|
285
|
-
__publicField(this, "_attrs", []);
|
|
286
102
|
if (!tag)
|
|
287
103
|
throw Error("Cannot instanciate new NoteTag without a passed in tag.");
|
|
288
104
|
if (tag.isNew)
|
|
@@ -303,38 +119,13 @@ class NoteTag extends ModelWithState {
|
|
|
303
119
|
withData(data) {
|
|
304
120
|
return this.data = data, this;
|
|
305
121
|
}
|
|
306
|
-
get attrs() {
|
|
307
|
-
return this._attrs.filter((x) => !x.isDeleted);
|
|
308
|
-
}
|
|
309
|
-
get attrsPendingDeletion() {
|
|
310
|
-
return this._attrs.filter((x) => x.isDeleted);
|
|
311
|
-
}
|
|
312
|
-
addAttr(attr, value) {
|
|
313
|
-
if (attr.isDeleted)
|
|
314
|
-
throw Error("Cannot add an attribute marked as deleted.");
|
|
315
|
-
if (attr.isNew)
|
|
316
|
-
throw Error("Cannot add an attribute that hasn't yet been saved.");
|
|
317
|
-
let na = this.attrs.find((x) => x.attr.id == attr.id);
|
|
318
|
-
return na ? (na.isDeleted && na.dirty(), value != null && (na.value = value), this) : (na = new NoteAttr(attr, this.tag, value), this._attrs.push(na), this);
|
|
319
|
-
}
|
|
320
|
-
removeAttr(attr) {
|
|
321
|
-
const na = this._attrs.find((x) => x.attr.id == attr.id);
|
|
322
|
-
return na ? (na.isNew ? this._attrs = this._attrs.filter((x) => x !== na) : na.delete(), this) : this;
|
|
323
|
-
}
|
|
324
|
-
getAttr(attr) {
|
|
325
|
-
return attr instanceof Attr && (attr = attr.name), this.attrs.find((x) => x.attr.name == attr);
|
|
326
|
-
}
|
|
327
|
-
getValue(attr) {
|
|
328
|
-
var _a;
|
|
329
|
-
return (_a = this.getAttr(attr)) == null ? void 0 : _a.value;
|
|
330
|
-
}
|
|
331
122
|
duplicate() {
|
|
332
123
|
const output = this.duplicateAsNew();
|
|
333
124
|
return output.state = this.state, output;
|
|
334
125
|
}
|
|
335
126
|
duplicateAsNew() {
|
|
336
127
|
const output = new NoteTag(this.tag);
|
|
337
|
-
return this.data && (output._data = JSON.parse(JSON.stringify(this.data))), output
|
|
128
|
+
return this.data && (output._data = JSON.parse(JSON.stringify(this.data))), output;
|
|
338
129
|
}
|
|
339
130
|
validate(throwError = !1) {
|
|
340
131
|
function exit(message) {
|
|
@@ -342,19 +133,13 @@ class NoteTag extends ModelWithState {
|
|
|
342
133
|
throw Error(message);
|
|
343
134
|
return message == null;
|
|
344
135
|
}
|
|
345
|
-
|
|
346
|
-
return exit("NoteTag must have a tag set.");
|
|
347
|
-
for (const na of this._attrs)
|
|
348
|
-
if (!na.validate(throwError))
|
|
349
|
-
return !1;
|
|
350
|
-
return !0;
|
|
136
|
+
return this.tag ? !0 : exit("NoteTag must have a tag set.");
|
|
351
137
|
}
|
|
352
138
|
toJSON() {
|
|
353
139
|
return {
|
|
354
140
|
state: this.state,
|
|
355
141
|
tagId: this.tag.id,
|
|
356
|
-
data: this.data
|
|
357
|
-
attrs: this._attrs.map((x) => x.toJSON())
|
|
142
|
+
data: this.data
|
|
358
143
|
};
|
|
359
144
|
}
|
|
360
145
|
}
|
|
@@ -530,7 +315,6 @@ class Note extends ModelWithState {
|
|
|
530
315
|
__publicField(this, "_space", null);
|
|
531
316
|
__publicField(this, "_ownTag", null);
|
|
532
317
|
__publicField(this, "_tags", []);
|
|
533
|
-
__publicField(this, "_attrs", []);
|
|
534
318
|
text && (this.text = text), this._ownTag = ownTag;
|
|
535
319
|
}
|
|
536
320
|
get id() {
|
|
@@ -601,46 +385,11 @@ class Note extends ModelWithState {
|
|
|
601
385
|
}
|
|
602
386
|
removeTag(tag) {
|
|
603
387
|
const nt = this._tags.find((x) => x.tag.id == tag.id);
|
|
604
|
-
|
|
605
|
-
return this;
|
|
606
|
-
if (nt.isNew)
|
|
607
|
-
this._tags = this._tags.filter((x) => x !== nt);
|
|
608
|
-
else {
|
|
609
|
-
nt.delete();
|
|
610
|
-
const attrs = nt.attrs.map((x) => x.attr);
|
|
611
|
-
for (const attr of attrs)
|
|
612
|
-
nt.removeAttr(attr);
|
|
613
|
-
}
|
|
614
|
-
return this;
|
|
388
|
+
return nt ? (nt.isNew ? this._tags = this._tags.filter((x) => x !== nt) : nt.delete(), this) : this;
|
|
615
389
|
}
|
|
616
390
|
getTag(tag, space = null) {
|
|
617
391
|
return tag instanceof Tag ? this.tags.find((x) => x.tag === tag) : (space && space instanceof Space && (space = space.id), space != null ? this.tags.find((x) => x.tag.name == tag && x.tag.space.id == space) : this.tags.find((x) => x.tag.name == tag && x.tag.space.id == this.space.id));
|
|
618
392
|
}
|
|
619
|
-
get attrs() {
|
|
620
|
-
return this._attrs.filter((x) => !x.isDeleted);
|
|
621
|
-
}
|
|
622
|
-
get attrsPendingDeletion() {
|
|
623
|
-
return this._attrs.filter((x) => x.isDeleted);
|
|
624
|
-
}
|
|
625
|
-
addAttr(attr, value) {
|
|
626
|
-
if (attr.isDeleted)
|
|
627
|
-
throw Error("Cannot add an attribute marked as deleted to a note");
|
|
628
|
-
if (attr.isNew)
|
|
629
|
-
throw Error("Cannot add an attribute that hasn't yet been saved to a note");
|
|
630
|
-
let na = this.attrs.find((x) => x.attr.id == attr.id);
|
|
631
|
-
return na ? (na.isDeleted && na.dirty(), value != null && (na.value = value), this) : (na = new NoteAttr(attr, null, value), this._attrs.push(na), this);
|
|
632
|
-
}
|
|
633
|
-
removeAttr(attr) {
|
|
634
|
-
const na = this._attrs.find((x) => x.attr.id == attr.id);
|
|
635
|
-
return na ? (na.isNew ? this._attrs = this._attrs.filter((x) => x !== na) : na.delete(), this) : this;
|
|
636
|
-
}
|
|
637
|
-
getAttr(attr) {
|
|
638
|
-
return attr instanceof Attr && (attr = attr.name), this.attrs.find((x) => x.attr.name == attr);
|
|
639
|
-
}
|
|
640
|
-
getValue(attr) {
|
|
641
|
-
var _a;
|
|
642
|
-
return (_a = this.getAttr(attr)) == null ? void 0 : _a.value;
|
|
643
|
-
}
|
|
644
393
|
getTagData(tag, type) {
|
|
645
394
|
const nt = this.getTag(tag);
|
|
646
395
|
return nt ? new type(nt) : null;
|
|
@@ -648,11 +397,11 @@ class Note extends ModelWithState {
|
|
|
648
397
|
duplicate() {
|
|
649
398
|
var _a;
|
|
650
399
|
const output = new Note(this.text, (_a = this.ownTag) == null ? void 0 : _a.duplicate()).at(this.date).in(this.space);
|
|
651
|
-
return output.
|
|
400
|
+
return output._tags = this.tags.map((x) => x.duplicate()), output.id = this.id, output.state = this.state, output;
|
|
652
401
|
}
|
|
653
402
|
duplicateAsNew() {
|
|
654
403
|
const output = new Note(this.text).at(this.date).in(this.space);
|
|
655
|
-
return output.
|
|
404
|
+
return output._tags = this.tags.map((x) => x.duplicateAsNew()), output;
|
|
656
405
|
}
|
|
657
406
|
toJSON() {
|
|
658
407
|
var _a;
|
|
@@ -663,8 +412,7 @@ class Note extends ModelWithState {
|
|
|
663
412
|
text: this.text,
|
|
664
413
|
spaceId: this.space.id,
|
|
665
414
|
ownTag: (_a = this.ownTag) == null ? void 0 : _a.toJSON(),
|
|
666
|
-
tags: this._tags.map((x) => x.toJSON())
|
|
667
|
-
attrs: this._attrs.map((x) => x.toJSON())
|
|
415
|
+
tags: this._tags.map((x) => x.toJSON())
|
|
668
416
|
};
|
|
669
417
|
}
|
|
670
418
|
validate(throwError = !1) {
|
|
@@ -680,23 +428,11 @@ class Note extends ModelWithState {
|
|
|
680
428
|
return exit("Note cannot belong to a different space than its own tag");
|
|
681
429
|
} else
|
|
682
430
|
return exit("Note must belong to a space.");
|
|
683
|
-
const survivingAttrs = this.attrs;
|
|
684
|
-
for (let i = 0; i < survivingAttrs.length; i++) {
|
|
685
|
-
const na = survivingAttrs[i];
|
|
686
|
-
for (let j = i + 1; j < survivingAttrs.length; j++) {
|
|
687
|
-
const na2 = survivingAttrs[j];
|
|
688
|
-
if (na.attr.id == na2.attr.id)
|
|
689
|
-
return exit(`Attr '${na.attr.name}' is duplicated.`);
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
431
|
if (this.ownTag && !this.ownTag.validate(throwError))
|
|
693
432
|
return !1;
|
|
694
433
|
for (const nt of this._tags)
|
|
695
434
|
if (!nt.validate(throwError))
|
|
696
435
|
return !1;
|
|
697
|
-
for (const na of this._attrs)
|
|
698
|
-
if (!na.validate(throwError))
|
|
699
|
-
return !1;
|
|
700
436
|
return !0;
|
|
701
437
|
}
|
|
702
438
|
}
|
|
@@ -764,17 +500,6 @@ class NotuHttpClient {
|
|
|
764
500
|
);
|
|
765
501
|
return this._validateResponseStatus(response), await response.json();
|
|
766
502
|
}
|
|
767
|
-
async saveAttr(attr) {
|
|
768
|
-
const response = await this._fetch(
|
|
769
|
-
this.url + "/attrs",
|
|
770
|
-
{
|
|
771
|
-
method: "POST",
|
|
772
|
-
body: JSON.stringify(attr),
|
|
773
|
-
headers: { Authorization: "Bearer " + this.token }
|
|
774
|
-
}
|
|
775
|
-
);
|
|
776
|
-
return this._validateResponseStatus(response), await response.json();
|
|
777
|
-
}
|
|
778
503
|
async getNotes(query, space) {
|
|
779
504
|
space instanceof Space && (space = space.id);
|
|
780
505
|
const response = await this._fetch(
|
|
@@ -837,15 +562,12 @@ class NotuCache {
|
|
|
837
562
|
__publicField(this, "_spaces", null);
|
|
838
563
|
__publicField(this, "_tags", null);
|
|
839
564
|
__publicField(this, "_tagNames", null);
|
|
840
|
-
__publicField(this, "_attrs", null);
|
|
841
565
|
if (!fetcher)
|
|
842
566
|
throw Error("NotuCache constructor must have a fetcher argument supplied.");
|
|
843
567
|
this._fetcher = fetcher;
|
|
844
568
|
}
|
|
845
569
|
async populate() {
|
|
846
|
-
await this._populateSpaces();
|
|
847
|
-
const tagsPromise = this._populateTags(), attrsPromise = this._populateAttrs();
|
|
848
|
-
await Promise.all([tagsPromise, attrsPromise]), this._populateTagNames();
|
|
570
|
+
await this._populateSpaces(), await this._populateTags(), this._populateTagNames();
|
|
849
571
|
}
|
|
850
572
|
async _populateSpaces() {
|
|
851
573
|
const spacesData = await this._fetcher.getSpacesData();
|
|
@@ -882,32 +604,12 @@ class NotuCache {
|
|
|
882
604
|
_populateTagLinks(tag, tagData) {
|
|
883
605
|
tag.links = tagData.links.map((x) => this._tags.get(x));
|
|
884
606
|
}
|
|
885
|
-
async _populateAttrs() {
|
|
886
|
-
const attrsData = await this._fetcher.getAttrsData();
|
|
887
|
-
this._attrs = /* @__PURE__ */ new Map();
|
|
888
|
-
for (const attrData of attrsData) {
|
|
889
|
-
const attr = this.attrFromJSON(attrData);
|
|
890
|
-
this._attrs.set(attr.id, attr);
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
attrFromJSON(attrData) {
|
|
894
|
-
const attr = new Attr(attrData.name, attrData.description);
|
|
895
|
-
return attr.id = attrData.id, attr.type = attrData.type, attr.space = this._spaces.get(attrData.spaceId), attr.state = attrData.state, attr;
|
|
896
|
-
}
|
|
897
607
|
noteFromJSON(noteData) {
|
|
898
608
|
const ownTag = !noteData.ownTag || noteData.ownTag.state == "CLEAN" ? this.getTag(noteData.id) : this.tagFromJSON(noteData.ownTag), note = new Note(noteData.text, ownTag).at(new Date(noteData.date)).in(this.getSpace(noteData.spaceId));
|
|
899
609
|
note.id = noteData.id, note.state = noteData.state;
|
|
900
|
-
for (const naData of noteData.attrs) {
|
|
901
|
-
const attr = this.getAttr(naData.attrId);
|
|
902
|
-
note.addAttr(attr, naData.value), note.getAttr(attr).state = naData.state;
|
|
903
|
-
}
|
|
904
610
|
for (const ntData of noteData.tags) {
|
|
905
611
|
const nt = note.addTag(this.getTag(ntData.tagId));
|
|
906
612
|
nt.data = ntData.data, nt.state = ntData.state;
|
|
907
|
-
for (const ntaData of ntData.attrs) {
|
|
908
|
-
const attr = this.getAttr(ntaData.attrId);
|
|
909
|
-
nt.addAttr(attr, ntaData.value), nt.getAttr(attr).state = ntaData.state;
|
|
910
|
-
}
|
|
911
613
|
}
|
|
912
614
|
return note;
|
|
913
615
|
}
|
|
@@ -945,22 +647,6 @@ class NotuCache {
|
|
|
945
647
|
const tag = this.tagFromJSON(tagData);
|
|
946
648
|
return tag.state == "DELETED" ? this._tags.delete(tag.id) : this._tags.set(tag.id, tag), this._populateTagNames(), tag;
|
|
947
649
|
}
|
|
948
|
-
getAttrs(space = null) {
|
|
949
|
-
return space == null ? Array.from(this._attrs.values()) : (space instanceof Space && (space = space.id), Array.from(this._attrs.values()).filter((x) => x.space.id == space));
|
|
950
|
-
}
|
|
951
|
-
getAttr(id) {
|
|
952
|
-
return this._attrs.get(id);
|
|
953
|
-
}
|
|
954
|
-
getAttrByName(name, space) {
|
|
955
|
-
space instanceof Space && (space = space.id);
|
|
956
|
-
for (const attr of this._attrs.values())
|
|
957
|
-
if (attr.name == name && attr.space.id == space)
|
|
958
|
-
return attr;
|
|
959
|
-
}
|
|
960
|
-
attrSaved(attrData) {
|
|
961
|
-
const attr = this.attrFromJSON(attrData);
|
|
962
|
-
return attr.state == "DELETED" ? this._attrs.delete(attr.id) : this._attrs.set(attr.id, attr), attr;
|
|
963
|
-
}
|
|
964
650
|
}
|
|
965
651
|
class NotuHttpCacheFetcher {
|
|
966
652
|
constructor(url, token, fetchMethod = null) {
|
|
@@ -986,9 +672,6 @@ class NotuHttpCacheFetcher {
|
|
|
986
672
|
async getTagsData() {
|
|
987
673
|
return await this._getX("/tags");
|
|
988
674
|
}
|
|
989
|
-
async getAttrsData() {
|
|
990
|
-
return await this._getX("/attrs");
|
|
991
|
-
}
|
|
992
675
|
async _getX(endpoint) {
|
|
993
676
|
return await (await this._fetch(
|
|
994
677
|
this.url + endpoint,
|
|
@@ -1047,89 +730,9 @@ class ParsedQuery {
|
|
|
1047
730
|
__publicField(this, "where", null);
|
|
1048
731
|
__publicField(this, "order", null);
|
|
1049
732
|
__publicField(this, "tags", []);
|
|
1050
|
-
__publicField(this, "attrs", []);
|
|
1051
733
|
}
|
|
1052
734
|
}
|
|
1053
735
|
class ParsedTag {
|
|
1054
|
-
constructor() {
|
|
1055
|
-
__publicField(this, "space", null);
|
|
1056
|
-
__publicField(this, "name", null);
|
|
1057
|
-
__publicField(this, "searchDepth", 0);
|
|
1058
|
-
__publicField(this, "strictSearchDepth", !0);
|
|
1059
|
-
__publicField(this, "includeOwner", !1);
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
class ParsedAttr {
|
|
1063
|
-
constructor() {
|
|
1064
|
-
__publicField(this, "name", null);
|
|
1065
|
-
__publicField(this, "exists", !1);
|
|
1066
|
-
__publicField(this, "tagNameFilters", null);
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
function parseQuery(query) {
|
|
1070
|
-
const output = splitQuery$1(query);
|
|
1071
|
-
return output.where = identifyTags$1(output.where, output), output.order = identifyTags$1(output.order, output), output.where = identifyAttrs(output.where, output), output.order = identifyAttrs(output.order, output), output;
|
|
1072
|
-
}
|
|
1073
|
-
function splitQuery$1(query) {
|
|
1074
|
-
query = " " + query + " ";
|
|
1075
|
-
const output = new ParsedQuery(), orderByIndex = query.toUpperCase().indexOf(" ORDER BY ");
|
|
1076
|
-
return orderByIndex < 0 ? output.where = query.trim() : (output.where = query.substring(0, orderByIndex).trim(), output.order = query.substring(orderByIndex + 10).trim()), output.where == "" && (output.where = null), output;
|
|
1077
|
-
}
|
|
1078
|
-
function identifyTags$1(query, parsedQuery) {
|
|
1079
|
-
const regexes = [
|
|
1080
|
-
/(#+\??~?|~)([\w\d]+\.)?([\w\d]+)/,
|
|
1081
|
-
//Single word tags and space names
|
|
1082
|
-
/(#+\??~?|~)\[([\w\d\s]+\.)?([\w\d\s]+)\]/
|
|
1083
|
-
//Multi-word tags and space names wrapped in []
|
|
1084
|
-
];
|
|
1085
|
-
for (const regex of regexes)
|
|
1086
|
-
for (; ; ) {
|
|
1087
|
-
const match = regex.exec(query);
|
|
1088
|
-
if (!match)
|
|
1089
|
-
break;
|
|
1090
|
-
const hashPrefix = match[1], parsedTag = new ParsedTag();
|
|
1091
|
-
parsedTag.space = match[2] ? match[2].substring(0, match[2].length - 1) : null, parsedTag.name = match[3], parsedTag.includeOwner = hashPrefix.includes("~"), parsedTag.searchDepth = (hashPrefix.match(/#/g) || []).length, parsedTag.strictSearchDepth = !hashPrefix.includes("?");
|
|
1092
|
-
const fullMatch = match[0], matchStart = query.indexOf(fullMatch), matchEnd = matchStart + fullMatch.length;
|
|
1093
|
-
query = query.substring(0, matchStart) + `{tag${parsedQuery.tags.length}}` + query.substring(matchEnd), parsedQuery.tags.push(parsedTag);
|
|
1094
|
-
}
|
|
1095
|
-
return query;
|
|
1096
|
-
}
|
|
1097
|
-
function identifyAttrs(query, parsedQuery) {
|
|
1098
|
-
const regexes = [
|
|
1099
|
-
/@([\w\d]+)/,
|
|
1100
|
-
/@\[([\w\d\s]+)\]/
|
|
1101
|
-
];
|
|
1102
|
-
for (const regex of regexes)
|
|
1103
|
-
for (; ; ) {
|
|
1104
|
-
const match = regex.exec(query);
|
|
1105
|
-
if (!match)
|
|
1106
|
-
break;
|
|
1107
|
-
const parsedAttr = new ParsedAttr();
|
|
1108
|
-
parsedAttr.name = match[1];
|
|
1109
|
-
const matchStart = query.indexOf(match[0]);
|
|
1110
|
-
let matchEnd = matchStart + match[0].length;
|
|
1111
|
-
if (query.substring(matchEnd, matchEnd + 9) == ".Exists()" && (parsedAttr.exists = !0, matchEnd += 9), query.substring(matchEnd, matchEnd + 4) == ".On(") {
|
|
1112
|
-
let tagFilterStart = matchEnd + 4;
|
|
1113
|
-
if (matchEnd = query.indexOf(")", tagFilterStart), matchEnd < 0)
|
|
1114
|
-
throw Error("Unclosed bracket detected");
|
|
1115
|
-
let tagNameFilters = query.substring(tagFilterStart, matchEnd).split("|");
|
|
1116
|
-
const dummyParsedQuery = new ParsedQuery();
|
|
1117
|
-
for (let tagNameFilter of tagNameFilters)
|
|
1118
|
-
tagNameFilter.startsWith("~") || (tagNameFilter = "~" + tagNameFilter), identifyTags$1(tagNameFilter, dummyParsedQuery);
|
|
1119
|
-
parsedAttr.tagNameFilters = dummyParsedQuery.tags, matchEnd++;
|
|
1120
|
-
}
|
|
1121
|
-
query = query.substring(0, matchStart) + `{attr${parsedQuery.attrs.length}}` + query.substring(matchEnd), parsedQuery.attrs.push(parsedAttr);
|
|
1122
|
-
}
|
|
1123
|
-
return query;
|
|
1124
|
-
}
|
|
1125
|
-
class NewParsedQuery {
|
|
1126
|
-
constructor() {
|
|
1127
|
-
__publicField(this, "where", null);
|
|
1128
|
-
__publicField(this, "order", null);
|
|
1129
|
-
__publicField(this, "tags", []);
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
class NewParsedTag {
|
|
1133
736
|
constructor() {
|
|
1134
737
|
__publicField(this, "space", null);
|
|
1135
738
|
__publicField(this, "name", null);
|
|
@@ -1137,19 +740,19 @@ class NewParsedTag {
|
|
|
1137
740
|
__publicField(this, "filter", null);
|
|
1138
741
|
}
|
|
1139
742
|
}
|
|
1140
|
-
class
|
|
743
|
+
class ParsedTagFilter {
|
|
1141
744
|
constructor() {
|
|
1142
745
|
__publicField(this, "pattern", null);
|
|
1143
746
|
__publicField(this, "exps", []);
|
|
1144
747
|
}
|
|
1145
748
|
}
|
|
1146
|
-
function
|
|
749
|
+
function parseQuery(query) {
|
|
1147
750
|
const output = splitQuery(query);
|
|
1148
751
|
return output.where = identifyTags(output.where, output), output.order = identifyTags(output.order, output), output;
|
|
1149
752
|
}
|
|
1150
753
|
function splitQuery(query) {
|
|
1151
754
|
query = " " + query + " ";
|
|
1152
|
-
const output = new
|
|
755
|
+
const output = new ParsedQuery(), orderByIndex = query.toUpperCase().indexOf(" ORDER BY ");
|
|
1153
756
|
return orderByIndex < 0 ? output.where = query.trim() : (output.where = query.substring(0, orderByIndex).trim(), output.order = query.substring(orderByIndex + 10).trim()), output.where == "" && (output.where = null), output;
|
|
1154
757
|
}
|
|
1155
758
|
function identifyTags(query, parsedQuery) {
|
|
@@ -1165,7 +768,7 @@ function identifyTags(query, parsedQuery) {
|
|
|
1165
768
|
if (!match)
|
|
1166
769
|
break;
|
|
1167
770
|
let hashPrefix = match[1];
|
|
1168
|
-
const parsedTag = new
|
|
771
|
+
const parsedTag = new ParsedTag();
|
|
1169
772
|
parsedTag.space = match[2] ? match[2].substring(0, match[2].length - 1) : null, parsedTag.name = match[3], hashPrefix.startsWith("@") && (parsedTag.searchDepths.push(0), hashPrefix = hashPrefix.substring(1));
|
|
1170
773
|
for (let i = 0; i < hashPrefix.length; i++)
|
|
1171
774
|
hashPrefix[i] == "#" && parsedTag.searchDepths.push(i + 1);
|
|
@@ -1191,7 +794,7 @@ function getTagDataFilterText(query, tagEndIndex) {
|
|
|
1191
794
|
return query.substring(tagEndIndex + 1, i);
|
|
1192
795
|
}
|
|
1193
796
|
function processTagDataFilter(parsedTag, filterText) {
|
|
1194
|
-
filterText = ` ${filterText}`, parsedTag.filter = new
|
|
797
|
+
filterText = ` ${filterText}`, parsedTag.filter = new ParsedTagFilter(), parsedTag.filter.pattern = filterText;
|
|
1195
798
|
const expressionRegex = /[\s\(]\.([\w\d\[\]\.]+)/;
|
|
1196
799
|
for (; ; ) {
|
|
1197
800
|
const match = expressionRegex.exec(parsedTag.filter.pattern);
|
|
@@ -1203,24 +806,18 @@ function processTagDataFilter(parsedTag, filterText) {
|
|
|
1203
806
|
parsedTag.filter.pattern = parsedTag.filter.pattern.trim();
|
|
1204
807
|
}
|
|
1205
808
|
export {
|
|
1206
|
-
Attr,
|
|
1207
|
-
NewParsedQuery,
|
|
1208
|
-
NewParsedTag,
|
|
1209
|
-
NewParsedTagFilter,
|
|
1210
809
|
Note,
|
|
1211
|
-
NoteAttr,
|
|
1212
810
|
NoteComponentInfo,
|
|
1213
811
|
NoteTag,
|
|
1214
812
|
Notu,
|
|
1215
813
|
NotuCache,
|
|
1216
814
|
NotuHttpCacheFetcher,
|
|
1217
815
|
NotuHttpClient,
|
|
1218
|
-
ParsedAttr,
|
|
1219
816
|
ParsedQuery,
|
|
1220
817
|
ParsedTag,
|
|
818
|
+
ParsedTagFilter,
|
|
1221
819
|
Space,
|
|
1222
820
|
Tag,
|
|
1223
|
-
newParseQuery,
|
|
1224
821
|
parseQuery,
|
|
1225
822
|
splitNoteTextIntoComponents
|
|
1226
823
|
};
|
package/dist/notu.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(global,factory){typeof exports=="object"&&typeof module<"u"?factory(exports):typeof define=="function"&&define.amd?define(["exports"],factory):(global=typeof globalThis<"u"?globalThis:global||self,factory(global.notu={}))})(this,function(exports2){"use strict";var __defProp=Object.defineProperty;var __defNormalProp=(obj,key,value)=>key in obj?__defProp(obj,key,{enumerable:!0,configurable:!0,writable:!0,value}):obj[key]=value;var __publicField=(obj,key,value)=>(__defNormalProp(obj,typeof key!="symbol"?key+"":key,value),value);class ModelWithState{constructor(){__publicField(this,"state","NEW")}new(){return this.state="NEW",this}clean(){return this.state="CLEAN",this}dirty(){return this.state="DIRTY",this}delete(){return this.state="DELETED",this}get isNew(){return this.state=="NEW"}get isClean(){return this.state=="CLEAN"}get isDirty(){return this.state=="DIRTY"}get isDeleted(){return this.state=="DELETED"}validate(throwError=!1){return!0}}class Attr extends ModelWithState{constructor(name,description){super();__publicField(this,"id",0);__publicField(this,"_name","");__publicField(this,"_description","");__publicField(this,"_type","TEXT");__publicField(this,"_space",null);__publicField(this,"_color",null);name&&(this.name=name),description&&(this.description=description)}get name(){return this._name}set name(value){value!==this._name&&(this._name=value,this.isClean&&this.dirty())}get description(){return this._description}set description(value){value!==this._description&&(this._description=value,this.isClean&&this.dirty())}get type(){return this._type}set type(value){if(!this.isNew)throw Error("Cannot change an attribute's type once it has been created.");this._type=value}get isText(){return this.type=="TEXT"}get isNumber(){return this.type=="NUMBER"}get isBoolean(){return this.type=="BOOLEAN"}get isDate(){return this.type=="DATE"}asText(){return this.type="TEXT",this}asNumber(){return this.type="NUMBER",this}asBoolean(){return this.type="BOOLEAN",this}asDate(){return this.type="DATE",this}get space(){return this._space}set space(value){var _a;if(value!==this._space){const idChanged=(value==null?void 0:value.id)!=((_a=this._space)==null?void 0:_a.id);this._space=value,this.isClean&&idChanged&&this.dirty()}}in(space){return this.space=space,this}get color(){return this._color}set color(value){value!==this._color&&(this._color=value,this.isClean&&this.dirty())}duplicate(){const output=this.duplicateAsNew();return output.id=this.id,output.state=this.state,output}duplicateAsNew(){const output=new Attr;return output.name=this.name,output.description=this.description,output.type=this.type,output.space=this.space,output.color=this.color,output}validate(throwError=!1){let output=null;if(this.space?!this.isNew&&this.id<=0?output="Attr id must be greater than zero if in non-new state.":this.color&&!/^#?[A-z0-9]{6}$/.test(this.color)&&(output="Tag color is invalid, must be a 6 character hexadecimal."):output="Attr must belong to a space.",throwError&&output!=null)throw Error(output);return output==null}get defaultValue(){switch(this.type){case"TEXT":return"";case"NUMBER":return 0;case"BOOLEAN":return!1;case"DATE":return new Date}}toJSON(){var _a;return{state:this.state,id:this.id,name:this.name,description:this.description,type:this.type,spaceId:(_a=this.space)==null?void 0:_a.id,color:this.color}}}class Notu{constructor(client,cache){__publicField(this,"_client");__publicField(this,"_cache");this._client=client,this._cache=cache}get client(){return this._client}get cache(){return this._cache}async login(username,password){return await this.client.login(username,password)}async setup(){return await this.client.setup()}getSpaces(){return this.cache.getSpaces()}getSpace(id){return this.cache.getSpace(id)}getSpaceByName(name){return this.cache.getSpaceByName(name)}async saveSpace(space){const spaceData=await this.client.saveSpace(space);return this.cache.spaceSaved(spaceData)}getAttrs(space=null){return this.cache.getAttrs(space)}getAttr(id){return this.cache.getAttr(id)}getAttrByName(name,space){return this.cache.getAttrByName(name,space)}async saveAttr(attr){const attrData=await this.client.saveAttr(attr);return this.cache.attrSaved(attrData)}getTags(space=null,includeOtherSpacePublics=!1){return this.cache.getTags(space,includeOtherSpacePublics)}getTag(id){return this.cache.getTag(id)}getTagByName(name,space){return this.cache.getTagByName(name,space)}async getNotes(query,spaceId){return(await this.client.getNotes(query,spaceId)).map(n=>this.cache.noteFromJSON(n))}async getNoteCount(query,spaceId){return await this.client.getNoteCount(query,spaceId)}async getRelatedNotes(tag){return(await this.client.getRelatedNotes(tag)).map(n=>this.cache.noteFromJSON(n))}async saveNotes(notes){const notesData=await this.client.saveNotes(notes);for(const noteData of notesData.filter(x=>!!x.ownTag))noteData.ownTag.links=noteData.tags.map(x=>x.tagId),this.cache.tagSaved(noteData.ownTag);return notes=notesData.map(n=>this.cache.noteFromJSON(n)),notes}async customJob(name,data){return await this.client.customJob(name,data)}}class NoteAttr extends ModelWithState{constructor(attr,tag,value){super();__publicField(this,"_tag",null);__publicField(this,"_attr",null);__publicField(this,"_value",null);if(!attr)throw Error("Cannot instanciate new NoteAttr without a passed in attr.");if(attr.isNew)throw Error("Cannot create a NoteAttr object for an attr that hasn't been saved yet.");if(attr.isDeleted)throw Error("Cannot create a NoteAttr object for an attr marked as deleted.");if(this._attr=attr,tag){if(tag.isNew)throw Error("Cannot create a NoteAttr object linked to a tag that hasn't been saved yet.");if(tag.isDeleted)throw Error("Cannot create a NoteAttr object linked to a tag marked as deleted.");this._tag=tag}value!=null&&value!=null?this.value=value:this.value=attr.defaultValue}get tag(){return this._tag}get attr(){return this._attr}get value(){return this._value}set value(newVal){this.attr.isText&&typeof newVal!="string"?newVal=String(newVal):this.attr.isDate&&!(newVal instanceof Date)?newVal=new Date(newVal):this.attr.isNumber&&typeof newVal!="number"?newVal=Number(newVal):this.attr.isBoolean&&typeof newVal!="boolean"&&(newVal=!!newVal),newVal!=this._value&&(this._value=newVal,this.isClean&&this.dirty())}withValue(value){return this.value=value,this}duplicate(){const output=this.duplicateAsNew();return output.state=this.state,output}duplicateAsNew(){return new NoteAttr(this.attr,this.tag,this.value)}validate(throwError=!1){let output=null;if(throwError&&output!=null)throw Error(output);return output==null}toJSON(){var _a;return{state:this.state,attrId:this.attr.id,tagId:(_a=this.tag)==null?void 0:_a.id,value:this.value}}}class NoteTag extends ModelWithState{constructor(tag){super();__publicField(this,"_tag");__publicField(this,"_data");__publicField(this,"_attrs",[]);if(!tag)throw Error("Cannot instanciate new NoteTag without a passed in tag.");if(tag.isNew)throw Error("Cannot create a NoteTag object for a tag that hasn't been saved yet.");if(tag.isDeleted)throw Error("Cannot create a NoteTag object for a tag marked as deleted.");this._tag=tag}get tag(){return this._tag}get data(){return this._data}set data(value){this._data=value,this.isClean&&this.dirty()}withData(data){return this.data=data,this}get attrs(){return this._attrs.filter(x=>!x.isDeleted)}get attrsPendingDeletion(){return this._attrs.filter(x=>x.isDeleted)}addAttr(attr,value){if(attr.isDeleted)throw Error("Cannot add an attribute marked as deleted.");if(attr.isNew)throw Error("Cannot add an attribute that hasn't yet been saved.");let na=this.attrs.find(x=>x.attr.id==attr.id);return na?(na.isDeleted&&na.dirty(),value!=null&&(na.value=value),this):(na=new NoteAttr(attr,this.tag,value),this._attrs.push(na),this)}removeAttr(attr){const na=this._attrs.find(x=>x.attr.id==attr.id);return na?(na.isNew?this._attrs=this._attrs.filter(x=>x!==na):na.delete(),this):this}getAttr(attr){return attr instanceof Attr&&(attr=attr.name),this.attrs.find(x=>x.attr.name==attr)}getValue(attr){var _a;return(_a=this.getAttr(attr))==null?void 0:_a.value}duplicate(){const output=this.duplicateAsNew();return output.state=this.state,output}duplicateAsNew(){const output=new NoteTag(this.tag);return this.data&&(output._data=JSON.parse(JSON.stringify(this.data))),output._attrs=this.attrs.map(x=>x.duplicateAsNew()),output}validate(throwError=!1){function exit(message){if(throwError&&message!=null)throw Error(message);return message==null}if(!this.tag)return exit("NoteTag must have a tag set.");for(const na of this._attrs)if(!na.validate(throwError))return!1;return!0}toJSON(){return{state:this.state,tagId:this.tag.id,data:this.data,attrs:this._attrs.map(x=>x.toJSON())}}}class Space extends ModelWithState{constructor(name=""){super();__publicField(this,"_id",0);__publicField(this,"_name","");__publicField(this,"_version","0.0.1");__publicField(this,"_useCommonSpace",!1);this._name=name}get id(){return this._id}set id(value){if(!this.isNew)throw Error("Cannot change the id of a Space once it has already been created.");this._id=value}get name(){return this._name}set name(value){value!==this._name&&(this._name=value,this.isClean&&this.dirty())}get version(){return this._version}set version(value){value!==this._version&&(this._version=value,this.isClean&&this.dirty())}v(version){return this.version=version,this}get useCommonSpace(){return this._useCommonSpace}set useCommonSpace(value){value!==this._useCommonSpace&&(this._useCommonSpace=value,this.isClean&&this.dirty())}duplicate(){const output=this.duplicateAsNew();return output.id=this.id,output.state=this.state,output}duplicateAsNew(){const output=new Space;return output.name=this.name,output.version=this.version,output}validate(throwError=!1){let output=null;if(!this.isNew&&this.id<=0&&(output="Space id must be greater than zero if in non-new state."),throwError&&output!=null)throw Error(output);return output==null}toJSON(){return{state:this.state,id:this.id,name:this.name,version:this.version,useCommonSpace:this.useCommonSpace}}}class Tag extends ModelWithState{constructor(name=""){super();__publicField(this,"_id",0);__publicField(this,"_space",null);__publicField(this,"_name","");__publicField(this,"_color",null);__publicField(this,"_isPublic",!1);__publicField(this,"links",[]);this._name=name}get id(){return this._id}set id(value){if(!this.isNew)throw Error("Cannot change the id of a Tag once it has already been created.");this._id=value}get space(){return this._space}set space(value){var _a;if(value!==this._space){const idChanged=(value==null?void 0:value.id)!=((_a=this._space)==null?void 0:_a.id);this._space=value,this.isClean&&idChanged&&this.dirty()}}in(space){return this.space=space,this}get name(){return this._name}set name(value){value!==this._name&&(this._name=value,this.isClean&&this.dirty())}getFullName(){return`${this.space.name}.${this.name}`}getQualifiedName(contextSpaceId){var _a;return contextSpaceId==((_a=this.space)==null?void 0:_a.id)?this.name:this.getFullName()}getUniqueName(cache){return cache.getTagsByName(this.name).length==1?this.name:this.getFullName()}get color(){return this._color}set color(value){value!==this._color&&(this._color=value,this.isClean&&this.dirty())}get isPublic(){return this._isPublic}set isPublic(value){if(!this.isNew&&this.isPublic&&!value)throw Error("Cannot change a tag from public to private once its already been saved.");value!==this._isPublic&&(this._isPublic=value,this.isClean&&this.dirty())}asPublic(){return this.isPublic=!0,this}asPrivate(){return this.isPublic=!1,this}linksTo(tag){return!!this.links.find(x=>x==tag)}duplicate(){const output=this.duplicateAsNew();return output.id=this.id,output.state=this.state,output}duplicateAsNew(){const output=new Tag(this.name);return output.color=this.color,output.space=this.space,output.isPublic=this.isPublic,output.links=this.links.slice(),output}validate(throwError=!1){let output=null;if(!this.isNew&&this.id<=0?output="Tag id must be greater than zero if in non-new state.":!this.name||!/^[a-zA-Z][a-zA-Z0-9 ]*[a-zA-Z0-9]?$/.test(this.name)?output="Tag name is invalid, must only contain letters, numbers, and spaces, starting with a letter":this.color&&!/^#?[A-z0-9]{6}$/.test(this.color)&&(output="Tag color is invalid, must be a 6 character hexadecimal."),throwError&&output!=null)throw Error(output);return output==null}toJSON(){var _a;return{state:this.state,id:this.id,name:this.name,spaceId:(_a=this.space)==null?void 0:_a.id,color:this.color,isPublic:this.isPublic,links:this.links.map(x=>x.id)}}}class Note extends ModelWithState{constructor(text,ownTag){super();__publicField(this,"_id",0);__publicField(this,"_date",new Date);__publicField(this,"_text","");__publicField(this,"_space",null);__publicField(this,"_ownTag",null);__publicField(this,"_tags",[]);__publicField(this,"_attrs",[]);text&&(this.text=text),this._ownTag=ownTag}get id(){return this._id}set id(value){if(!this.isNew)throw Error("Cannot change the id of a Note once it has already been created.");this._id=value,this.ownTag&&this.ownTag.id!=value&&(this.ownTag.id=value)}get date(){return this._date}set date(value){value!==this._date&&(this._date=value,this.isClean&&this.dirty())}at(value){return this.date=value,this}get text(){return this._text}set text(value){value!==this._text&&(this._text=value,this.isClean&&this.dirty())}get space(){return this._space}set space(value){var _a;if(value!==this._space){const idChanged=(value==null?void 0:value.id)!=((_a=this._space)==null?void 0:_a.id);this._space=value,this.isClean&&idChanged&&this.dirty(),this._setOwnTagSpace()}}in(space){return this.space=space,this}get ownTag(){return this._ownTag}setOwnTag(tagName){return this.ownTag==null?(this._ownTag=new Tag(tagName),this.ownTag.id=this.id):this.ownTag.isDeleted&&this.ownTag.dirty(),this.ownTag.name=tagName,this._setOwnTagSpace(),this}removeOwnTag(){return this.ownTag?(this.ownTag.isNew?this._ownTag=null:this.ownTag.delete(),this):this}_setOwnTagSpace(){this.ownTag&&this.space&&(this.ownTag.space=this.space)}get tags(){return this._tags.filter(x=>!x.isDeleted)}get tagsPendingDeletion(){return this._tags.filter(x=>x.isDeleted)}addTag(tag){if(tag.isDeleted)throw Error("Cannot add a tag marked as deleted to a note");if(tag.isNew)throw Error("Cannot add a tag that hasn't yet been saved to a note");if(tag.id==this.id)throw Error("Note cannot add its own tag as a linked tag");if(!tag.isPublic&&tag.space.id!=this.space.id)throw Error("Cannot add a private tag from another space");let nt=this._tags.find(x=>x.tag.id==tag.id);return nt?(nt.isDeleted&&nt.dirty(),nt):(nt=new NoteTag(tag),this._tags.push(nt),nt)}removeTag(tag){const nt=this._tags.find(x=>x.tag.id==tag.id);if(!nt)return this;if(nt.isNew)this._tags=this._tags.filter(x=>x!==nt);else{nt.delete();const attrs=nt.attrs.map(x=>x.attr);for(const attr of attrs)nt.removeAttr(attr)}return this}getTag(tag,space=null){return tag instanceof Tag?this.tags.find(x=>x.tag===tag):(space&&space instanceof Space&&(space=space.id),space!=null?this.tags.find(x=>x.tag.name==tag&&x.tag.space.id==space):this.tags.find(x=>x.tag.name==tag&&x.tag.space.id==this.space.id))}get attrs(){return this._attrs.filter(x=>!x.isDeleted)}get attrsPendingDeletion(){return this._attrs.filter(x=>x.isDeleted)}addAttr(attr,value){if(attr.isDeleted)throw Error("Cannot add an attribute marked as deleted to a note");if(attr.isNew)throw Error("Cannot add an attribute that hasn't yet been saved to a note");let na=this.attrs.find(x=>x.attr.id==attr.id);return na?(na.isDeleted&&na.dirty(),value!=null&&(na.value=value),this):(na=new NoteAttr(attr,null,value),this._attrs.push(na),this)}removeAttr(attr){const na=this._attrs.find(x=>x.attr.id==attr.id);return na?(na.isNew?this._attrs=this._attrs.filter(x=>x!==na):na.delete(),this):this}getAttr(attr){return attr instanceof Attr&&(attr=attr.name),this.attrs.find(x=>x.attr.name==attr)}getValue(attr){var _a;return(_a=this.getAttr(attr))==null?void 0:_a.value}getTagData(tag,type){const nt=this.getTag(tag);return nt?new type(nt):null}duplicate(){var _a;const output=new Note(this.text,(_a=this.ownTag)==null?void 0:_a.duplicate()).at(this.date).in(this.space);return output._attrs=this.attrs.map(x=>x.duplicate()),output._tags=this.tags.map(x=>x.duplicate()),output.id=this.id,output.state=this.state,output}duplicateAsNew(){const output=new Note(this.text).at(this.date).in(this.space);return output._attrs=this.attrs.map(x=>x.duplicateAsNew()),output._tags=this.tags.map(x=>x.duplicateAsNew()),output}toJSON(){var _a;return{state:this.state,id:this.id,date:this.date,text:this.text,spaceId:this.space.id,ownTag:(_a=this.ownTag)==null?void 0:_a.toJSON(),tags:this._tags.map(x=>x.toJSON()),attrs:this._attrs.map(x=>x.toJSON())}}validate(throwError=!1){function exit(message){if(throwError&&message!=null)throw Error(message);return message==null}if(this.space){if(!this.isNew&&this.id<=0)return exit("Note id must be greater than zero if in non-new state.");if(this.ownTag&&this.ownTag.space.id!=this.space.id)return exit("Note cannot belong to a different space than its own tag")}else return exit("Note must belong to a space.");const survivingAttrs=this.attrs;for(let i=0;i<survivingAttrs.length;i++){const na=survivingAttrs[i];for(let j=i+1;j<survivingAttrs.length;j++){const na2=survivingAttrs[j];if(na.attr.id==na2.attr.id)return exit(`Attr '${na.attr.name}' is duplicated.`)}}if(this.ownTag&&!this.ownTag.validate(throwError))return!1;for(const nt of this._tags)if(!nt.validate(throwError))return!1;for(const na of this._attrs)if(!na.validate(throwError))return!1;return!0}}class NotuHttpClient{constructor(url,fetchMethod=null){__publicField(this,"_url",null);__publicField(this,"_token",null);__publicField(this,"_fetch");__publicField(this,"errorHandler",null);if(!url)throw Error("Endpoint URL must be passed in to NotuClient constructor");url.endsWith("/")&&(url=url.substring(0,url.length-1)),this._url=url,this._fetch=fetchMethod??window.fetch.bind(window)}get url(){return this._url}get token(){return this._token}set token(value){this._token=value}_validateResponseStatus(response){if(response.status>=400&&response.status<600){if(this.errorHandler&&this.errorHandler(response))return;throw Error(response.statusText)}}async login(username,password){const response=await this._fetch(this.url+"/login",{method:"POST",body:JSON.stringify({username,password})});if(this._validateResponseStatus(response),response.body!=null){const result=await response.json();return result&&(this._token=result),result}throw Error("Unknown error occurred on the server")}async setup(){const response=await this._fetch(this.url+"/setup",{method:"POST",headers:{Authorization:"Bearer "+this.token}});this._validateResponseStatus(response),await response.json()}async saveSpace(space){const response=await this._fetch(this.url+"/spaces",{method:"POST",body:JSON.stringify(space),headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}async saveAttr(attr){const response=await this._fetch(this.url+"/attrs",{method:"POST",body:JSON.stringify(attr),headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}async getNotes(query,space){space instanceof Space&&(space=space.id);const response=await this._fetch(this.url+`/notes?space=${space}&query=${encodeURIComponent(query)}`,{method:"GET",headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}async getNoteCount(query,space){space instanceof Space&&(space=space.id);const response=await this._fetch(this.url+`/notes?count=true&space=${space}&query=${encodeURIComponent(query)}`,{method:"GET",headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),(await response.json()).count}async getRelatedNotes(tag){tag instanceof Tag&&(tag=tag.id),tag instanceof Note&&(tag=tag.id);const response=await this._fetch(this.url+`/notes?tag=${tag}`,{method:"GET",headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}async saveNotes(notes){const response=await this._fetch(this.url+"/notes",{method:"POST",body:JSON.stringify(notes),headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}async customJob(name,data){const response=await this._fetch(this.url+"/customJob",{method:"POST",body:JSON.stringify({name,data,clientTimezone:Intl.DateTimeFormat().resolvedOptions().timeZone}),headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}}class NotuCache{constructor(fetcher){__publicField(this,"_fetcher");__publicField(this,"_spaces",null);__publicField(this,"_tags",null);__publicField(this,"_tagNames",null);__publicField(this,"_attrs",null);if(!fetcher)throw Error("NotuCache constructor must have a fetcher argument supplied.");this._fetcher=fetcher}async populate(){await this._populateSpaces();const tagsPromise=this._populateTags(),attrsPromise=this._populateAttrs();await Promise.all([tagsPromise,attrsPromise]),this._populateTagNames()}async _populateSpaces(){const spacesData=await this._fetcher.getSpacesData();this._spaces=new Map;for(const spaceData of spacesData){const space=this.spaceFromJSON(spaceData);this._spaces.set(space.id,space)}}spaceFromJSON(spaceData){const space=new Space(spaceData.name);return space.id=spaceData.id,space.version=spaceData.version,space.state=spaceData.state,space}async _populateTags(){const tagsData=await this._fetcher.getTagsData(),allTags=new Map;for(const tagData of tagsData){const tag=this.tagFromJSON(tagData);allTags.set(tag.id,tag),tagData.tag=tag}this._tags=allTags;for(const tagData of tagsData)this._populateTagLinks(tagData.tag,tagData)}_populateTagNames(){const result=new Map;for(const tag of this._tags.values())result.has(tag.name)?result.get(tag.name).push(tag):result.set(tag.name,[tag]);this._tagNames=result}tagFromJSON(tagData){const tag=new Tag(tagData.name);return tag.id=tagData.id,tag.space=this._spaces.get(tagData.spaceId),tag.color=tagData.color,tag.isPublic=tagData.isPublic,tag.state=tagData.state,this._tags&&this._populateTagLinks(tag,tagData),tag}_populateTagLinks(tag,tagData){tag.links=tagData.links.map(x=>this._tags.get(x))}async _populateAttrs(){const attrsData=await this._fetcher.getAttrsData();this._attrs=new Map;for(const attrData of attrsData){const attr=this.attrFromJSON(attrData);this._attrs.set(attr.id,attr)}}attrFromJSON(attrData){const attr=new Attr(attrData.name,attrData.description);return attr.id=attrData.id,attr.type=attrData.type,attr.space=this._spaces.get(attrData.spaceId),attr.state=attrData.state,attr}noteFromJSON(noteData){const ownTag=!noteData.ownTag||noteData.ownTag.state=="CLEAN"?this.getTag(noteData.id):this.tagFromJSON(noteData.ownTag),note=new Note(noteData.text,ownTag).at(new Date(noteData.date)).in(this.getSpace(noteData.spaceId));note.id=noteData.id,note.state=noteData.state;for(const naData of noteData.attrs){const attr=this.getAttr(naData.attrId);note.addAttr(attr,naData.value),note.getAttr(attr).state=naData.state}for(const ntData of noteData.tags){const nt=note.addTag(this.getTag(ntData.tagId));nt.data=ntData.data,nt.state=ntData.state;for(const ntaData of ntData.attrs){const attr=this.getAttr(ntaData.attrId);nt.addAttr(attr,ntaData.value),nt.getAttr(attr).state=ntaData.state}}return note}getSpaces(){return Array.from(this._spaces.values())}getSpace(id){return this._spaces.get(id)}getSpaceByName(name){for(const space of this._spaces.values())if(space.name==name)return space}spaceSaved(spaceData){const space=this.spaceFromJSON(spaceData);return space.state=="DELETED"?this._spaces.delete(space.id):this._spaces.set(space.id,space),space}getTags(space=null,includeOtherSpacePublics=!1){return space==null?Array.from(this._tags.values()):(space instanceof Space&&(space=space.id),Array.from(this._tags.values()).filter(x=>x.isPublic&&includeOtherSpacePublics||x.space.id==space))}getTag(id){return this._tags.get(id)}getTagByName(name,space){space instanceof Space&&(space=space.id);for(const tag of this._tagNames.get(name)??[])if(tag.name==name&&tag.space.id==space)return tag}getTagsByName(name){return this._tagNames.get(name)??[]}tagSaved(tagData){const tag=this.tagFromJSON(tagData);return tag.state=="DELETED"?this._tags.delete(tag.id):this._tags.set(tag.id,tag),this._populateTagNames(),tag}getAttrs(space=null){return space==null?Array.from(this._attrs.values()):(space instanceof Space&&(space=space.id),Array.from(this._attrs.values()).filter(x=>x.space.id==space))}getAttr(id){return this._attrs.get(id)}getAttrByName(name,space){space instanceof Space&&(space=space.id);for(const attr of this._attrs.values())if(attr.name==name&&attr.space.id==space)return attr}attrSaved(attrData){const attr=this.attrFromJSON(attrData);return attr.state=="DELETED"?this._attrs.delete(attr.id):this._attrs.set(attr.id,attr),attr}}class NotuHttpCacheFetcher{constructor(url,token,fetchMethod=null){__publicField(this,"_url",null);__publicField(this,"_token",null);__publicField(this,"_fetch");if(!url)throw Error("Endpoint URL must be passed into NotuHttpCacheFetcher constructor");if(!token)throw Error("Security token must be passed into NotuHttpCacheFetcher constructor");url.endsWith("/")&&(url=url.substring(0,url.length-1)),this._url=url,this._token=token,this._fetch=fetchMethod??window.fetch.bind(window)}get url(){return this._url}get token(){return this._token}async getSpacesData(){return await this._getX("/spaces")}async getTagsData(){return await this._getX("/tags")}async getAttrsData(){return await this._getX("/attrs")}async _getX(endpoint){return await(await this._fetch(this.url+endpoint,{method:"GET",headers:{Authorization:"Bearer "+this.token}})).json()}}class NoteComponentInfo{constructor(text,start,processor){__publicField(this,"text");__publicField(this,"start");__publicField(this,"processor");this.text=text,this.start=start,this.processor=processor}get end(){return this.start+this.text.length}}function splitNoteTextIntoComponents(note,notu,componentProcessors,defaultProcessor,groupIntoParagraph){const componentInfos=recursiveSplitNoteText(note.text,note,componentProcessors,defaultProcessor),components=[];async function save(){note.text=components.map(x=>x.getText()).join(""),await notu.saveNotes([note])}for(let groupStart=0;groupStart<componentInfos.length;groupStart++){const startInfo=componentInfos[groupStart];if(!startInfo.processor.componentShowsInlineInParagraph){components.push(startInfo.processor.create(startInfo,note,save));continue}for(let groupEnd=groupStart;groupEnd<=componentInfos.length;groupEnd++){const endInfo=componentInfos[groupEnd];if(!endInfo||!endInfo.processor.componentShowsInlineInParagraph){const groupedComponents=componentInfos.slice(groupStart,groupEnd).map(x=>x.processor.create(x,note,save));components.push(groupIntoParagraph(groupedComponents)),groupStart=groupEnd-1;break}}}return components}function recursiveSplitNoteText(text,note,componentProcessors,defaultProcessor){let componentInfo=null;for(const processor of componentProcessors)if(componentInfo=processor.identify(text),componentInfo)break;if(!componentInfo)return[new NoteComponentInfo(text,0,defaultProcessor)];const output=[];return componentInfo.start>0&&output.push(...recursiveSplitNoteText(text.substring(0,componentInfo.start),note,componentProcessors,defaultProcessor)),output.push(componentInfo),componentInfo.end<text.length&&output.push(...recursiveSplitNoteText(text.substring(componentInfo.end),note,componentProcessors,defaultProcessor)),output}class ParsedQuery{constructor(){__publicField(this,"where",null);__publicField(this,"order",null);__publicField(this,"tags",[]);__publicField(this,"attrs",[])}}class ParsedTag{constructor(){__publicField(this,"space",null);__publicField(this,"name",null);__publicField(this,"searchDepth",0);__publicField(this,"strictSearchDepth",!0);__publicField(this,"includeOwner",!1)}}class ParsedAttr{constructor(){__publicField(this,"name",null);__publicField(this,"exists",!1);__publicField(this,"tagNameFilters",null)}}function parseQuery(query){const output=splitQuery$1(query);return output.where=identifyTags$1(output.where,output),output.order=identifyTags$1(output.order,output),output.where=identifyAttrs(output.where,output),output.order=identifyAttrs(output.order,output),output}function splitQuery$1(query){query=" "+query+" ";const output=new ParsedQuery,orderByIndex=query.toUpperCase().indexOf(" ORDER BY ");return orderByIndex<0?output.where=query.trim():(output.where=query.substring(0,orderByIndex).trim(),output.order=query.substring(orderByIndex+10).trim()),output.where==""&&(output.where=null),output}function identifyTags$1(query,parsedQuery){const regexes=[/(#+\??~?|~)([\w\d]+\.)?([\w\d]+)/,/(#+\??~?|~)\[([\w\d\s]+\.)?([\w\d\s]+)\]/];for(const regex of regexes)for(;;){const match=regex.exec(query);if(!match)break;const hashPrefix=match[1],parsedTag=new ParsedTag;parsedTag.space=match[2]?match[2].substring(0,match[2].length-1):null,parsedTag.name=match[3],parsedTag.includeOwner=hashPrefix.includes("~"),parsedTag.searchDepth=(hashPrefix.match(/#/g)||[]).length,parsedTag.strictSearchDepth=!hashPrefix.includes("?");const fullMatch=match[0],matchStart=query.indexOf(fullMatch),matchEnd=matchStart+fullMatch.length;query=query.substring(0,matchStart)+`{tag${parsedQuery.tags.length}}`+query.substring(matchEnd),parsedQuery.tags.push(parsedTag)}return query}function identifyAttrs(query,parsedQuery){const regexes=[/@([\w\d]+)/,/@\[([\w\d\s]+)\]/];for(const regex of regexes)for(;;){const match=regex.exec(query);if(!match)break;const parsedAttr=new ParsedAttr;parsedAttr.name=match[1];const matchStart=query.indexOf(match[0]);let matchEnd=matchStart+match[0].length;if(query.substring(matchEnd,matchEnd+9)==".Exists()"&&(parsedAttr.exists=!0,matchEnd+=9),query.substring(matchEnd,matchEnd+4)==".On("){let tagFilterStart=matchEnd+4;if(matchEnd=query.indexOf(")",tagFilterStart),matchEnd<0)throw Error("Unclosed bracket detected");let tagNameFilters=query.substring(tagFilterStart,matchEnd).split("|");const dummyParsedQuery=new ParsedQuery;for(let tagNameFilter of tagNameFilters)tagNameFilter.startsWith("~")||(tagNameFilter="~"+tagNameFilter),identifyTags$1(tagNameFilter,dummyParsedQuery);parsedAttr.tagNameFilters=dummyParsedQuery.tags,matchEnd++}query=query.substring(0,matchStart)+`{attr${parsedQuery.attrs.length}}`+query.substring(matchEnd),parsedQuery.attrs.push(parsedAttr)}return query}class NewParsedQuery{constructor(){__publicField(this,"where",null);__publicField(this,"order",null);__publicField(this,"tags",[])}}class NewParsedTag{constructor(){__publicField(this,"space",null);__publicField(this,"name",null);__publicField(this,"searchDepths",[]);__publicField(this,"filter",null)}}class NewParsedTagFilter{constructor(){__publicField(this,"pattern",null);__publicField(this,"exps",[])}}function newParseQuery(query){const output=splitQuery(query);return output.where=identifyTags(output.where,output),output.order=identifyTags(output.order,output),output}function splitQuery(query){query=" "+query+" ";const output=new NewParsedQuery,orderByIndex=query.toUpperCase().indexOf(" ORDER BY ");return orderByIndex<0?output.where=query.trim():(output.where=query.substring(0,orderByIndex).trim(),output.order=query.substring(orderByIndex+10).trim()),output.where==""&&(output.where=null),output}function identifyTags(query,parsedQuery){const regexes=[/([#@_]+)([\w\d]+\.)?([\w\d]+)/,/([#@_]+)\[([\w\d\s]+\.)?([\w\d\s]+)\]/];for(const regex of regexes)for(;;){const match=regex.exec(query);if(!match)break;let hashPrefix=match[1];const parsedTag=new NewParsedTag;parsedTag.space=match[2]?match[2].substring(0,match[2].length-1):null,parsedTag.name=match[3],hashPrefix.startsWith("@")&&(parsedTag.searchDepths.push(0),hashPrefix=hashPrefix.substring(1));for(let i=0;i<hashPrefix.length;i++)hashPrefix[i]=="#"&&parsedTag.searchDepths.push(i+1);const fullMatch=match[0],matchStart=query.indexOf(fullMatch),matchEnd=matchStart+fullMatch.length,tagDataFilter=getTagDataFilterText(query,matchEnd);tagDataFilter&&(query=query.substring(0,matchEnd)+query.substring(matchEnd+tagDataFilter.length+2),processTagDataFilter(parsedTag,tagDataFilter)),query=query.substring(0,matchStart)+`{tag${parsedQuery.tags.length}}`+query.substring(matchEnd),parsedQuery.tags.push(parsedTag)}return query}function getTagDataFilterText(query,tagEndIndex){if(query.charAt(tagEndIndex)!="{")return null;let i=tagEndIndex+1,braceDepth=1;for(;;){if(i>=query.length)throw Error("Invalid query syntax, expected closing '}' symbol.");const char=query.charAt(i);if(char=="{")braceDepth++;else if(char=="}"&&(braceDepth--,braceDepth==0))break;i++}return query.substring(tagEndIndex+1,i)}function processTagDataFilter(parsedTag,filterText){filterText=` ${filterText}`,parsedTag.filter=new NewParsedTagFilter,parsedTag.filter.pattern=filterText;const expressionRegex=/[\s\(]\.([\w\d\[\]\.]+)/;for(;;){const match=expressionRegex.exec(parsedTag.filter.pattern);if(!match)break;const expression=match[1];parsedTag.filter.pattern=parsedTag.filter.pattern.replace(`.${expression}`,`{exp${parsedTag.filter.exps.length}}`),parsedTag.filter.exps.push(expression)}parsedTag.filter.pattern=parsedTag.filter.pattern.trim()}exports2.Attr=Attr,exports2.NewParsedQuery=NewParsedQuery,exports2.NewParsedTag=NewParsedTag,exports2.NewParsedTagFilter=NewParsedTagFilter,exports2.Note=Note,exports2.NoteAttr=NoteAttr,exports2.NoteComponentInfo=NoteComponentInfo,exports2.NoteTag=NoteTag,exports2.Notu=Notu,exports2.NotuCache=NotuCache,exports2.NotuHttpCacheFetcher=NotuHttpCacheFetcher,exports2.NotuHttpClient=NotuHttpClient,exports2.ParsedAttr=ParsedAttr,exports2.ParsedQuery=ParsedQuery,exports2.ParsedTag=ParsedTag,exports2.Space=Space,exports2.Tag=Tag,exports2.newParseQuery=newParseQuery,exports2.parseQuery=parseQuery,exports2.splitNoteTextIntoComponents=splitNoteTextIntoComponents,Object.defineProperty(exports2,Symbol.toStringTag,{value:"Module"})});
|
|
1
|
+
(function(global,factory){typeof exports=="object"&&typeof module<"u"?factory(exports):typeof define=="function"&&define.amd?define(["exports"],factory):(global=typeof globalThis<"u"?globalThis:global||self,factory(global.notu={}))})(this,function(exports2){"use strict";var __defProp=Object.defineProperty;var __defNormalProp=(obj,key,value)=>key in obj?__defProp(obj,key,{enumerable:!0,configurable:!0,writable:!0,value}):obj[key]=value;var __publicField=(obj,key,value)=>(__defNormalProp(obj,typeof key!="symbol"?key+"":key,value),value);class Notu{constructor(client,cache){__publicField(this,"_client");__publicField(this,"_cache");this._client=client,this._cache=cache}get client(){return this._client}get cache(){return this._cache}async login(username,password){return await this.client.login(username,password)}async setup(){return await this.client.setup()}getSpaces(){return this.cache.getSpaces()}getSpace(id){return this.cache.getSpace(id)}getSpaceByName(name){return this.cache.getSpaceByName(name)}async saveSpace(space){const spaceData=await this.client.saveSpace(space);return this.cache.spaceSaved(spaceData)}getTags(space=null,includeOtherSpacePublics=!1){return this.cache.getTags(space,includeOtherSpacePublics)}getTag(id){return this.cache.getTag(id)}getTagByName(name,space){return this.cache.getTagByName(name,space)}async getNotes(query,spaceId){return(await this.client.getNotes(query,spaceId)).map(n=>this.cache.noteFromJSON(n))}async getNoteCount(query,spaceId){return await this.client.getNoteCount(query,spaceId)}async getRelatedNotes(tag){return(await this.client.getRelatedNotes(tag)).map(n=>this.cache.noteFromJSON(n))}async saveNotes(notes){const tagsBeingDeletedData=notes.filter(x=>!!x.ownTag).filter(x=>x.isDeleted||x.ownTag.isDeleted).map(x=>x.ownTag.toJSON()),notesData=await this.client.saveNotes(notes);for(const noteData of notesData.filter(x=>!!x.ownTag&&!x.ownTag.isDeleted))noteData.ownTag.links=noteData.tags.map(x=>x.tagId),this.cache.tagSaved(noteData.ownTag);for(const tagData of tagsBeingDeletedData)tagData.state="DELETED",this.cache.tagSaved(tagData);return notes=notesData.map(n=>this.cache.noteFromJSON(n)),notes}async customJob(name,data){return await this.client.customJob(name,data)}}class ModelWithState{constructor(){__publicField(this,"state","NEW")}new(){return this.state="NEW",this}clean(){return this.state="CLEAN",this}dirty(){return this.state="DIRTY",this}delete(){return this.state="DELETED",this}get isNew(){return this.state=="NEW"}get isClean(){return this.state=="CLEAN"}get isDirty(){return this.state=="DIRTY"}get isDeleted(){return this.state=="DELETED"}validate(throwError=!1){return!0}}class NoteTag extends ModelWithState{constructor(tag){super();__publicField(this,"_tag");__publicField(this,"_data");if(!tag)throw Error("Cannot instanciate new NoteTag without a passed in tag.");if(tag.isNew)throw Error("Cannot create a NoteTag object for a tag that hasn't been saved yet.");if(tag.isDeleted)throw Error("Cannot create a NoteTag object for a tag marked as deleted.");this._tag=tag}get tag(){return this._tag}get data(){return this._data}set data(value){this._data=value,this.isClean&&this.dirty()}withData(data){return this.data=data,this}duplicate(){const output=this.duplicateAsNew();return output.state=this.state,output}duplicateAsNew(){const output=new NoteTag(this.tag);return this.data&&(output._data=JSON.parse(JSON.stringify(this.data))),output}validate(throwError=!1){function exit(message){if(throwError&&message!=null)throw Error(message);return message==null}return this.tag?!0:exit("NoteTag must have a tag set.")}toJSON(){return{state:this.state,tagId:this.tag.id,data:this.data}}}class Space extends ModelWithState{constructor(name=""){super();__publicField(this,"_id",0);__publicField(this,"_name","");__publicField(this,"_version","0.0.1");__publicField(this,"_useCommonSpace",!1);this._name=name}get id(){return this._id}set id(value){if(!this.isNew)throw Error("Cannot change the id of a Space once it has already been created.");this._id=value}get name(){return this._name}set name(value){value!==this._name&&(this._name=value,this.isClean&&this.dirty())}get version(){return this._version}set version(value){value!==this._version&&(this._version=value,this.isClean&&this.dirty())}v(version){return this.version=version,this}get useCommonSpace(){return this._useCommonSpace}set useCommonSpace(value){value!==this._useCommonSpace&&(this._useCommonSpace=value,this.isClean&&this.dirty())}duplicate(){const output=this.duplicateAsNew();return output.id=this.id,output.state=this.state,output}duplicateAsNew(){const output=new Space;return output.name=this.name,output.version=this.version,output}validate(throwError=!1){let output=null;if(!this.isNew&&this.id<=0&&(output="Space id must be greater than zero if in non-new state."),throwError&&output!=null)throw Error(output);return output==null}toJSON(){return{state:this.state,id:this.id,name:this.name,version:this.version,useCommonSpace:this.useCommonSpace}}}class Tag extends ModelWithState{constructor(name=""){super();__publicField(this,"_id",0);__publicField(this,"_space",null);__publicField(this,"_name","");__publicField(this,"_color",null);__publicField(this,"_isPublic",!1);__publicField(this,"links",[]);this._name=name}get id(){return this._id}set id(value){if(!this.isNew)throw Error("Cannot change the id of a Tag once it has already been created.");this._id=value}get space(){return this._space}set space(value){var _a;if(value!==this._space){const idChanged=(value==null?void 0:value.id)!=((_a=this._space)==null?void 0:_a.id);this._space=value,this.isClean&&idChanged&&this.dirty()}}in(space){return this.space=space,this}get name(){return this._name}set name(value){value!==this._name&&(this._name=value,this.isClean&&this.dirty())}getFullName(){return`${this.space.name}.${this.name}`}getQualifiedName(contextSpaceId){var _a;return contextSpaceId==((_a=this.space)==null?void 0:_a.id)?this.name:this.getFullName()}getUniqueName(cache){return cache.getTagsByName(this.name).length==1?this.name:this.getFullName()}get color(){return this._color}set color(value){value!==this._color&&(this._color=value,this.isClean&&this.dirty())}get isPublic(){return this._isPublic}set isPublic(value){if(!this.isNew&&this.isPublic&&!value)throw Error("Cannot change a tag from public to private once its already been saved.");value!==this._isPublic&&(this._isPublic=value,this.isClean&&this.dirty())}asPublic(){return this.isPublic=!0,this}asPrivate(){return this.isPublic=!1,this}linksTo(tag){return!!this.links.find(x=>x==tag)}duplicate(){const output=this.duplicateAsNew();return output.id=this.id,output.state=this.state,output}duplicateAsNew(){const output=new Tag(this.name);return output.color=this.color,output.space=this.space,output.isPublic=this.isPublic,output.links=this.links.slice(),output}validate(throwError=!1){let output=null;if(!this.isNew&&this.id<=0?output="Tag id must be greater than zero if in non-new state.":!this.name||!/^[a-zA-Z][a-zA-Z0-9 ]*[a-zA-Z0-9]?$/.test(this.name)?output="Tag name is invalid, must only contain letters, numbers, and spaces, starting with a letter":this.color&&!/^#?[A-z0-9]{6}$/.test(this.color)&&(output="Tag color is invalid, must be a 6 character hexadecimal."),throwError&&output!=null)throw Error(output);return output==null}toJSON(){var _a;return{state:this.state,id:this.id,name:this.name,spaceId:(_a=this.space)==null?void 0:_a.id,color:this.color,isPublic:this.isPublic,links:this.links.map(x=>x.id)}}}class Note extends ModelWithState{constructor(text,ownTag){super();__publicField(this,"_id",0);__publicField(this,"_date",new Date);__publicField(this,"_text","");__publicField(this,"_space",null);__publicField(this,"_ownTag",null);__publicField(this,"_tags",[]);text&&(this.text=text),this._ownTag=ownTag}get id(){return this._id}set id(value){if(!this.isNew)throw Error("Cannot change the id of a Note once it has already been created.");this._id=value,this.ownTag&&this.ownTag.id!=value&&(this.ownTag.id=value)}get date(){return this._date}set date(value){value!==this._date&&(this._date=value,this.isClean&&this.dirty())}at(value){return this.date=value,this}get text(){return this._text}set text(value){value!==this._text&&(this._text=value,this.isClean&&this.dirty())}get space(){return this._space}set space(value){var _a;if(value!==this._space){const idChanged=(value==null?void 0:value.id)!=((_a=this._space)==null?void 0:_a.id);this._space=value,this.isClean&&idChanged&&this.dirty(),this._setOwnTagSpace()}}in(space){return this.space=space,this}get ownTag(){return this._ownTag}setOwnTag(tagName){return this.ownTag==null?(this._ownTag=new Tag(tagName),this.ownTag.id=this.id):this.ownTag.isDeleted&&this.ownTag.dirty(),this.ownTag.name=tagName,this._setOwnTagSpace(),this}removeOwnTag(){return this.ownTag?(this.ownTag.isNew?this._ownTag=null:this.ownTag.delete(),this):this}_setOwnTagSpace(){this.ownTag&&this.space&&(this.ownTag.space=this.space)}get tags(){return this._tags.filter(x=>!x.isDeleted)}get tagsPendingDeletion(){return this._tags.filter(x=>x.isDeleted)}addTag(tag){if(tag.isDeleted)throw Error("Cannot add a tag marked as deleted to a note");if(tag.isNew)throw Error("Cannot add a tag that hasn't yet been saved to a note");if(tag.id==this.id)throw Error("Note cannot add its own tag as a linked tag");if(!tag.isPublic&&tag.space.id!=this.space.id)throw Error("Cannot add a private tag from another space");let nt=this._tags.find(x=>x.tag.id==tag.id);return nt?(nt.isDeleted&&nt.dirty(),nt):(nt=new NoteTag(tag),this._tags.push(nt),nt)}removeTag(tag){const nt=this._tags.find(x=>x.tag.id==tag.id);return nt?(nt.isNew?this._tags=this._tags.filter(x=>x!==nt):nt.delete(),this):this}getTag(tag,space=null){return tag instanceof Tag?this.tags.find(x=>x.tag===tag):(space&&space instanceof Space&&(space=space.id),space!=null?this.tags.find(x=>x.tag.name==tag&&x.tag.space.id==space):this.tags.find(x=>x.tag.name==tag&&x.tag.space.id==this.space.id))}getTagData(tag,type){const nt=this.getTag(tag);return nt?new type(nt):null}duplicate(){var _a;const output=new Note(this.text,(_a=this.ownTag)==null?void 0:_a.duplicate()).at(this.date).in(this.space);return output._tags=this.tags.map(x=>x.duplicate()),output.id=this.id,output.state=this.state,output}duplicateAsNew(){const output=new Note(this.text).at(this.date).in(this.space);return output._tags=this.tags.map(x=>x.duplicateAsNew()),output}toJSON(){var _a;return{state:this.state,id:this.id,date:this.date,text:this.text,spaceId:this.space.id,ownTag:(_a=this.ownTag)==null?void 0:_a.toJSON(),tags:this._tags.map(x=>x.toJSON())}}validate(throwError=!1){function exit(message){if(throwError&&message!=null)throw Error(message);return message==null}if(this.space){if(!this.isNew&&this.id<=0)return exit("Note id must be greater than zero if in non-new state.");if(this.ownTag&&this.ownTag.space.id!=this.space.id)return exit("Note cannot belong to a different space than its own tag")}else return exit("Note must belong to a space.");if(this.ownTag&&!this.ownTag.validate(throwError))return!1;for(const nt of this._tags)if(!nt.validate(throwError))return!1;return!0}}class NotuHttpClient{constructor(url,fetchMethod=null){__publicField(this,"_url",null);__publicField(this,"_token",null);__publicField(this,"_fetch");__publicField(this,"errorHandler",null);if(!url)throw Error("Endpoint URL must be passed in to NotuClient constructor");url.endsWith("/")&&(url=url.substring(0,url.length-1)),this._url=url,this._fetch=fetchMethod??window.fetch.bind(window)}get url(){return this._url}get token(){return this._token}set token(value){this._token=value}_validateResponseStatus(response){if(response.status>=400&&response.status<600){if(this.errorHandler&&this.errorHandler(response))return;throw Error(response.statusText)}}async login(username,password){const response=await this._fetch(this.url+"/login",{method:"POST",body:JSON.stringify({username,password})});if(this._validateResponseStatus(response),response.body!=null){const result=await response.json();return result&&(this._token=result),result}throw Error("Unknown error occurred on the server")}async setup(){const response=await this._fetch(this.url+"/setup",{method:"POST",headers:{Authorization:"Bearer "+this.token}});this._validateResponseStatus(response),await response.json()}async saveSpace(space){const response=await this._fetch(this.url+"/spaces",{method:"POST",body:JSON.stringify(space),headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}async getNotes(query,space){space instanceof Space&&(space=space.id);const response=await this._fetch(this.url+`/notes?space=${space}&query=${encodeURIComponent(query)}`,{method:"GET",headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}async getNoteCount(query,space){space instanceof Space&&(space=space.id);const response=await this._fetch(this.url+`/notes?count=true&space=${space}&query=${encodeURIComponent(query)}`,{method:"GET",headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),(await response.json()).count}async getRelatedNotes(tag){tag instanceof Tag&&(tag=tag.id),tag instanceof Note&&(tag=tag.id);const response=await this._fetch(this.url+`/notes?tag=${tag}`,{method:"GET",headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}async saveNotes(notes){const response=await this._fetch(this.url+"/notes",{method:"POST",body:JSON.stringify(notes),headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}async customJob(name,data){const response=await this._fetch(this.url+"/customJob",{method:"POST",body:JSON.stringify({name,data,clientTimezone:Intl.DateTimeFormat().resolvedOptions().timeZone}),headers:{Authorization:"Bearer "+this.token}});return this._validateResponseStatus(response),await response.json()}}class NotuCache{constructor(fetcher){__publicField(this,"_fetcher");__publicField(this,"_spaces",null);__publicField(this,"_tags",null);__publicField(this,"_tagNames",null);if(!fetcher)throw Error("NotuCache constructor must have a fetcher argument supplied.");this._fetcher=fetcher}async populate(){await this._populateSpaces(),await this._populateTags(),this._populateTagNames()}async _populateSpaces(){const spacesData=await this._fetcher.getSpacesData();this._spaces=new Map;for(const spaceData of spacesData){const space=this.spaceFromJSON(spaceData);this._spaces.set(space.id,space)}}spaceFromJSON(spaceData){const space=new Space(spaceData.name);return space.id=spaceData.id,space.version=spaceData.version,space.state=spaceData.state,space}async _populateTags(){const tagsData=await this._fetcher.getTagsData(),allTags=new Map;for(const tagData of tagsData){const tag=this.tagFromJSON(tagData);allTags.set(tag.id,tag),tagData.tag=tag}this._tags=allTags;for(const tagData of tagsData)this._populateTagLinks(tagData.tag,tagData)}_populateTagNames(){const result=new Map;for(const tag of this._tags.values())result.has(tag.name)?result.get(tag.name).push(tag):result.set(tag.name,[tag]);this._tagNames=result}tagFromJSON(tagData){const tag=new Tag(tagData.name);return tag.id=tagData.id,tag.space=this._spaces.get(tagData.spaceId),tag.color=tagData.color,tag.isPublic=tagData.isPublic,tag.state=tagData.state,this._tags&&this._populateTagLinks(tag,tagData),tag}_populateTagLinks(tag,tagData){tag.links=tagData.links.map(x=>this._tags.get(x))}noteFromJSON(noteData){const ownTag=!noteData.ownTag||noteData.ownTag.state=="CLEAN"?this.getTag(noteData.id):this.tagFromJSON(noteData.ownTag),note=new Note(noteData.text,ownTag).at(new Date(noteData.date)).in(this.getSpace(noteData.spaceId));note.id=noteData.id,note.state=noteData.state;for(const ntData of noteData.tags){const nt=note.addTag(this.getTag(ntData.tagId));nt.data=ntData.data,nt.state=ntData.state}return note}getSpaces(){return Array.from(this._spaces.values())}getSpace(id){return this._spaces.get(id)}getSpaceByName(name){for(const space of this._spaces.values())if(space.name==name)return space}spaceSaved(spaceData){const space=this.spaceFromJSON(spaceData);return space.state=="DELETED"?this._spaces.delete(space.id):this._spaces.set(space.id,space),space}getTags(space=null,includeOtherSpacePublics=!1){return space==null?Array.from(this._tags.values()):(space instanceof Space&&(space=space.id),Array.from(this._tags.values()).filter(x=>x.isPublic&&includeOtherSpacePublics||x.space.id==space))}getTag(id){return this._tags.get(id)}getTagByName(name,space){space instanceof Space&&(space=space.id);for(const tag of this._tagNames.get(name)??[])if(tag.name==name&&tag.space.id==space)return tag}getTagsByName(name){return this._tagNames.get(name)??[]}tagSaved(tagData){const tag=this.tagFromJSON(tagData);return tag.state=="DELETED"?this._tags.delete(tag.id):this._tags.set(tag.id,tag),this._populateTagNames(),tag}}class NotuHttpCacheFetcher{constructor(url,token,fetchMethod=null){__publicField(this,"_url",null);__publicField(this,"_token",null);__publicField(this,"_fetch");if(!url)throw Error("Endpoint URL must be passed into NotuHttpCacheFetcher constructor");if(!token)throw Error("Security token must be passed into NotuHttpCacheFetcher constructor");url.endsWith("/")&&(url=url.substring(0,url.length-1)),this._url=url,this._token=token,this._fetch=fetchMethod??window.fetch.bind(window)}get url(){return this._url}get token(){return this._token}async getSpacesData(){return await this._getX("/spaces")}async getTagsData(){return await this._getX("/tags")}async _getX(endpoint){return await(await this._fetch(this.url+endpoint,{method:"GET",headers:{Authorization:"Bearer "+this.token}})).json()}}class NoteComponentInfo{constructor(text,start,processor){__publicField(this,"text");__publicField(this,"start");__publicField(this,"processor");this.text=text,this.start=start,this.processor=processor}get end(){return this.start+this.text.length}}function splitNoteTextIntoComponents(note,notu,componentProcessors,defaultProcessor,groupIntoParagraph){const componentInfos=recursiveSplitNoteText(note.text,note,componentProcessors,defaultProcessor),components=[];async function save(){note.text=components.map(x=>x.getText()).join(""),await notu.saveNotes([note])}for(let groupStart=0;groupStart<componentInfos.length;groupStart++){const startInfo=componentInfos[groupStart];if(!startInfo.processor.componentShowsInlineInParagraph){components.push(startInfo.processor.create(startInfo,note,save));continue}for(let groupEnd=groupStart;groupEnd<=componentInfos.length;groupEnd++){const endInfo=componentInfos[groupEnd];if(!endInfo||!endInfo.processor.componentShowsInlineInParagraph){const groupedComponents=componentInfos.slice(groupStart,groupEnd).map(x=>x.processor.create(x,note,save));components.push(groupIntoParagraph(groupedComponents)),groupStart=groupEnd-1;break}}}return components}function recursiveSplitNoteText(text,note,componentProcessors,defaultProcessor){let componentInfo=null;for(const processor of componentProcessors)if(componentInfo=processor.identify(text),componentInfo)break;if(!componentInfo)return[new NoteComponentInfo(text,0,defaultProcessor)];const output=[];return componentInfo.start>0&&output.push(...recursiveSplitNoteText(text.substring(0,componentInfo.start),note,componentProcessors,defaultProcessor)),output.push(componentInfo),componentInfo.end<text.length&&output.push(...recursiveSplitNoteText(text.substring(componentInfo.end),note,componentProcessors,defaultProcessor)),output}class ParsedQuery{constructor(){__publicField(this,"where",null);__publicField(this,"order",null);__publicField(this,"tags",[])}}class ParsedTag{constructor(){__publicField(this,"space",null);__publicField(this,"name",null);__publicField(this,"searchDepths",[]);__publicField(this,"filter",null)}}class ParsedTagFilter{constructor(){__publicField(this,"pattern",null);__publicField(this,"exps",[])}}function parseQuery(query){const output=splitQuery(query);return output.where=identifyTags(output.where,output),output.order=identifyTags(output.order,output),output}function splitQuery(query){query=" "+query+" ";const output=new ParsedQuery,orderByIndex=query.toUpperCase().indexOf(" ORDER BY ");return orderByIndex<0?output.where=query.trim():(output.where=query.substring(0,orderByIndex).trim(),output.order=query.substring(orderByIndex+10).trim()),output.where==""&&(output.where=null),output}function identifyTags(query,parsedQuery){const regexes=[/([#@_]+)([\w\d]+\.)?([\w\d]+)/,/([#@_]+)\[([\w\d\s]+\.)?([\w\d\s]+)\]/];for(const regex of regexes)for(;;){const match=regex.exec(query);if(!match)break;let hashPrefix=match[1];const parsedTag=new ParsedTag;parsedTag.space=match[2]?match[2].substring(0,match[2].length-1):null,parsedTag.name=match[3],hashPrefix.startsWith("@")&&(parsedTag.searchDepths.push(0),hashPrefix=hashPrefix.substring(1));for(let i=0;i<hashPrefix.length;i++)hashPrefix[i]=="#"&&parsedTag.searchDepths.push(i+1);const fullMatch=match[0],matchStart=query.indexOf(fullMatch),matchEnd=matchStart+fullMatch.length,tagDataFilter=getTagDataFilterText(query,matchEnd);tagDataFilter&&(query=query.substring(0,matchEnd)+query.substring(matchEnd+tagDataFilter.length+2),processTagDataFilter(parsedTag,tagDataFilter)),query=query.substring(0,matchStart)+`{tag${parsedQuery.tags.length}}`+query.substring(matchEnd),parsedQuery.tags.push(parsedTag)}return query}function getTagDataFilterText(query,tagEndIndex){if(query.charAt(tagEndIndex)!="{")return null;let i=tagEndIndex+1,braceDepth=1;for(;;){if(i>=query.length)throw Error("Invalid query syntax, expected closing '}' symbol.");const char=query.charAt(i);if(char=="{")braceDepth++;else if(char=="}"&&(braceDepth--,braceDepth==0))break;i++}return query.substring(tagEndIndex+1,i)}function processTagDataFilter(parsedTag,filterText){filterText=` ${filterText}`,parsedTag.filter=new ParsedTagFilter,parsedTag.filter.pattern=filterText;const expressionRegex=/[\s\(]\.([\w\d\[\]\.]+)/;for(;;){const match=expressionRegex.exec(parsedTag.filter.pattern);if(!match)break;const expression=match[1];parsedTag.filter.pattern=parsedTag.filter.pattern.replace(`.${expression}`,`{exp${parsedTag.filter.exps.length}}`),parsedTag.filter.exps.push(expression)}parsedTag.filter.pattern=parsedTag.filter.pattern.trim()}exports2.Note=Note,exports2.NoteComponentInfo=NoteComponentInfo,exports2.NoteTag=NoteTag,exports2.Notu=Notu,exports2.NotuCache=NotuCache,exports2.NotuHttpCacheFetcher=NotuHttpCacheFetcher,exports2.NotuHttpClient=NotuHttpClient,exports2.ParsedQuery=ParsedQuery,exports2.ParsedTag=ParsedTag,exports2.ParsedTagFilter=ParsedTagFilter,exports2.Space=Space,exports2.Tag=Tag,exports2.parseQuery=parseQuery,exports2.splitNoteTextIntoComponents=splitNoteTextIntoComponents,Object.defineProperty(exports2,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Note, Space, Tag } from ".";
|
|
2
2
|
import { NotuCacheFetcher } from "./services/HttpCacheFetcher";
|
|
3
3
|
export declare function newNote(text?: string, id?: number): Note;
|
|
4
4
|
export declare function newSpace(name?: string, id?: number): Space;
|
|
5
|
-
export declare function newAttr(name?: string, id?: number): Attr;
|
|
6
5
|
export declare function newTag(name?: string, id?: number): Tag;
|
|
7
6
|
export declare function testCacheFetcher(): NotuCacheFetcher;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import Attr from './models/Attr';
|
|
2
1
|
import { Notu } from './services/Notu';
|
|
3
2
|
import NotuHttpClient from './services/HttpClient';
|
|
4
3
|
import { NotuCache } from './services/NotuCache';
|
|
5
4
|
import { NotuHttpCacheFetcher } from './services/HttpCacheFetcher';
|
|
6
5
|
import Note from './models/Note';
|
|
7
|
-
import NoteAttr from './models/NoteAttr';
|
|
8
6
|
import { NoteComponentInfo, splitNoteTextIntoComponents } from './notecomponents/NoteComponent';
|
|
9
7
|
import NoteTag from './models/NoteTag';
|
|
10
|
-
import parseQuery, { ParsedQuery, ParsedTag,
|
|
11
|
-
import newParseQuery, { NewParsedQuery, NewParsedTag, NewParsedTagFilter } from './services/NewQueryParser';
|
|
8
|
+
import parseQuery, { ParsedQuery, ParsedTag, ParsedTagFilter } from './services/QueryParser';
|
|
12
9
|
import Space from './models/Space';
|
|
13
10
|
import Tag from './models/Tag';
|
|
14
|
-
export {
|
|
11
|
+
export { Notu, NotuHttpClient, NotuCache, NotuHttpCacheFetcher, Note, NoteComponentInfo, splitNoteTextIntoComponents, NoteTag, parseQuery, ParsedQuery, ParsedTag, ParsedTagFilter, Space, Tag };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import ModelWithState from './ModelWithState';
|
|
2
|
-
import NoteAttr from './NoteAttr';
|
|
3
2
|
import NoteTag from './NoteTag';
|
|
4
3
|
import Space from './Space';
|
|
5
4
|
import Tag from './Tag';
|
|
6
|
-
import Attr from './Attr';
|
|
7
5
|
export default class Note extends ModelWithState<Note> {
|
|
8
6
|
constructor(text?: string, ownTag?: Tag);
|
|
9
7
|
private _id;
|
|
@@ -31,13 +29,6 @@ export default class Note extends ModelWithState<Note> {
|
|
|
31
29
|
addTag(tag: Tag): NoteTag;
|
|
32
30
|
removeTag(tag: Tag): Note;
|
|
33
31
|
getTag(tag: string | Tag, space?: number | Space): NoteTag;
|
|
34
|
-
private _attrs;
|
|
35
|
-
get attrs(): Array<NoteAttr>;
|
|
36
|
-
get attrsPendingDeletion(): Array<NoteAttr>;
|
|
37
|
-
addAttr(attr: Attr, value?: any): Note;
|
|
38
|
-
removeAttr(attr: Attr): Note;
|
|
39
|
-
getAttr(attr: string | Attr): NoteAttr;
|
|
40
|
-
getValue(attr: string | Attr): any;
|
|
41
32
|
getTagData<T>(tag: Tag, type: {
|
|
42
33
|
new (noteTag: NoteTag): T;
|
|
43
34
|
}): T;
|
|
@@ -62,18 +53,6 @@ export default class Note extends ModelWithState<Note> {
|
|
|
62
53
|
state: "NEW" | "CLEAN" | "DIRTY" | "DELETED";
|
|
63
54
|
tagId: number;
|
|
64
55
|
data: any;
|
|
65
|
-
attrs: {
|
|
66
|
-
state: "NEW" | "CLEAN" | "DIRTY" | "DELETED";
|
|
67
|
-
attrId: number;
|
|
68
|
-
tagId: number;
|
|
69
|
-
value: any;
|
|
70
|
-
}[];
|
|
71
|
-
}[];
|
|
72
|
-
attrs: {
|
|
73
|
-
state: "NEW" | "CLEAN" | "DIRTY" | "DELETED";
|
|
74
|
-
attrId: number;
|
|
75
|
-
tagId: number;
|
|
76
|
-
value: any;
|
|
77
56
|
}[];
|
|
78
57
|
};
|
|
79
58
|
validate(throwError?: boolean): boolean;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import ModelWithState from './ModelWithState';
|
|
2
2
|
import Tag from './Tag';
|
|
3
|
-
import Attr from './Attr';
|
|
4
|
-
import NoteAttr from './NoteAttr';
|
|
5
3
|
export default class NoteTag extends ModelWithState<NoteTag> {
|
|
6
4
|
constructor(tag: Tag);
|
|
7
5
|
private _tag;
|
|
@@ -10,13 +8,6 @@ export default class NoteTag extends ModelWithState<NoteTag> {
|
|
|
10
8
|
get data(): any;
|
|
11
9
|
set data(value: any);
|
|
12
10
|
withData(data: any): NoteTag;
|
|
13
|
-
private _attrs;
|
|
14
|
-
get attrs(): Array<NoteAttr>;
|
|
15
|
-
get attrsPendingDeletion(): Array<NoteAttr>;
|
|
16
|
-
addAttr(attr: Attr, value?: any): NoteTag;
|
|
17
|
-
removeAttr(attr: Attr): NoteTag;
|
|
18
|
-
getAttr(attr: string | Attr): NoteAttr;
|
|
19
|
-
getValue(attr: string | Attr): any;
|
|
20
11
|
duplicate(): NoteTag;
|
|
21
12
|
duplicateAsNew(): NoteTag;
|
|
22
13
|
validate(throwError?: boolean): boolean;
|
|
@@ -24,11 +15,5 @@ export default class NoteTag extends ModelWithState<NoteTag> {
|
|
|
24
15
|
state: "NEW" | "CLEAN" | "DIRTY" | "DELETED";
|
|
25
16
|
tagId: number;
|
|
26
17
|
data: any;
|
|
27
|
-
attrs: {
|
|
28
|
-
state: "NEW" | "CLEAN" | "DIRTY" | "DELETED";
|
|
29
|
-
attrId: number;
|
|
30
|
-
tagId: number;
|
|
31
|
-
value: any;
|
|
32
|
-
}[];
|
|
33
18
|
};
|
|
34
19
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export interface NotuCacheFetcher {
|
|
2
2
|
getSpacesData(): Promise<Array<any>>;
|
|
3
3
|
getTagsData(): Promise<Array<any>>;
|
|
4
|
-
getAttrsData(): Promise<Array<any>>;
|
|
5
4
|
}
|
|
6
5
|
export declare class NotuHttpCacheFetcher implements NotuCacheFetcher {
|
|
7
6
|
private _url;
|
|
@@ -12,6 +11,5 @@ export declare class NotuHttpCacheFetcher implements NotuCacheFetcher {
|
|
|
12
11
|
constructor(url: string, token: string, fetchMethod?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>);
|
|
13
12
|
getSpacesData(): Promise<Array<any>>;
|
|
14
13
|
getTagsData(): Promise<Array<any>>;
|
|
15
|
-
getAttrsData(): Promise<Array<any>>;
|
|
16
14
|
private _getX;
|
|
17
15
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import Attr from '../models/Attr';
|
|
2
1
|
import Note from '../models/Note';
|
|
3
2
|
import Space from '../models/Space';
|
|
4
3
|
import Tag from '../models/Tag';
|
|
@@ -6,7 +5,6 @@ export interface NotuClient {
|
|
|
6
5
|
login(username: string, password: string): Promise<string>;
|
|
7
6
|
setup(): Promise<void>;
|
|
8
7
|
saveSpace(space: Space): Promise<any>;
|
|
9
|
-
saveAttr(attr: Attr): Promise<any>;
|
|
10
8
|
getNotes(query: string, space: number | Space): Promise<Array<any>>;
|
|
11
9
|
getNoteCount(query: string, space: number | Space): Promise<number>;
|
|
12
10
|
getRelatedNotes(tag: Tag | Note | number): Promise<Array<any>>;
|
|
@@ -26,7 +24,6 @@ export default class NotuHttpClient implements NotuClient {
|
|
|
26
24
|
login(username: string, password: string): Promise<string>;
|
|
27
25
|
setup(): Promise<void>;
|
|
28
26
|
saveSpace(space: Space): Promise<any>;
|
|
29
|
-
saveAttr(attr: Attr): Promise<any>;
|
|
30
27
|
getNotes(query: string, space: number | Space): Promise<Array<any>>;
|
|
31
28
|
getNoteCount(query: string, space: number | Space): Promise<number>;
|
|
32
29
|
getRelatedNotes(tag: Tag | Note | number): Promise<Array<any>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Note, Space, Tag } from '..';
|
|
2
2
|
import { NotuClient } from './HttpClient';
|
|
3
3
|
import { NotuCache } from './NotuCache';
|
|
4
4
|
export declare class Notu {
|
|
@@ -13,10 +13,6 @@ export declare class Notu {
|
|
|
13
13
|
getSpace(id: number): Space;
|
|
14
14
|
getSpaceByName(name: string): Space;
|
|
15
15
|
saveSpace(space: Space): Promise<Space>;
|
|
16
|
-
getAttrs(space?: number | Space): Array<Attr>;
|
|
17
|
-
getAttr(id: number): Attr;
|
|
18
|
-
getAttrByName(name: string, space: number | Space): Attr;
|
|
19
|
-
saveAttr(attr: Attr): Promise<Attr>;
|
|
20
16
|
getTags(space?: number | Space, includeOtherSpacePublics?: boolean): Array<Tag>;
|
|
21
17
|
getTag(id: number): Tag;
|
|
22
18
|
getTagByName(name: string, space: number | Space): Tag;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import Attr from '../models/Attr';
|
|
2
1
|
import Note from '../models/Note';
|
|
3
2
|
import Space from '../models/Space';
|
|
4
3
|
import Tag from '../models/Tag';
|
|
@@ -9,7 +8,6 @@ export declare class NotuCache {
|
|
|
9
8
|
private _spaces;
|
|
10
9
|
private _tags;
|
|
11
10
|
private _tagNames;
|
|
12
|
-
private _attrs;
|
|
13
11
|
populate(): Promise<void>;
|
|
14
12
|
private _populateSpaces;
|
|
15
13
|
spaceFromJSON(spaceData: any): Space;
|
|
@@ -17,8 +15,6 @@ export declare class NotuCache {
|
|
|
17
15
|
private _populateTagNames;
|
|
18
16
|
tagFromJSON(tagData: any): Tag;
|
|
19
17
|
private _populateTagLinks;
|
|
20
|
-
private _populateAttrs;
|
|
21
|
-
attrFromJSON(attrData: any): Attr;
|
|
22
18
|
noteFromJSON(noteData: any): Note;
|
|
23
19
|
getSpaces(): Array<Space>;
|
|
24
20
|
getSpace(id: number): Space;
|
|
@@ -29,8 +25,4 @@ export declare class NotuCache {
|
|
|
29
25
|
getTagByName(name: string, space: number | Space): Tag;
|
|
30
26
|
getTagsByName(name: string): Array<Tag>;
|
|
31
27
|
tagSaved(tagData: any): Tag;
|
|
32
|
-
getAttrs(space?: number | Space): Array<Attr>;
|
|
33
|
-
getAttr(id: number): Attr;
|
|
34
|
-
getAttrByName(name: string, space: number | Space): Attr;
|
|
35
|
-
attrSaved(attrData: any): Attr;
|
|
36
28
|
}
|
|
@@ -2,21 +2,17 @@ export declare class ParsedQuery {
|
|
|
2
2
|
where: string;
|
|
3
3
|
order: string;
|
|
4
4
|
tags: Array<ParsedTag>;
|
|
5
|
-
attrs: Array<ParsedAttr>;
|
|
6
5
|
}
|
|
7
6
|
export declare class ParsedTag {
|
|
8
7
|
space: string;
|
|
9
8
|
name: string;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
includeOwner: boolean;
|
|
9
|
+
searchDepths: Array<number>;
|
|
10
|
+
filter: ParsedTagFilter;
|
|
13
11
|
}
|
|
14
|
-
export declare class
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
tagNameFilters: Array<ParsedTag>;
|
|
12
|
+
export declare class ParsedTagFilter {
|
|
13
|
+
pattern: string;
|
|
14
|
+
exps: Array<string>;
|
|
18
15
|
}
|
|
19
16
|
export default function parseQuery(query: string): ParsedQuery;
|
|
20
17
|
export declare function splitQuery(query: string): ParsedQuery;
|
|
21
18
|
export declare function identifyTags(query: string, parsedQuery: ParsedQuery): string;
|
|
22
|
-
export declare function identifyAttrs(query: string, parsedQuery: ParsedQuery): string;
|
package/package.json
CHANGED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import ModelWithState from './ModelWithState';
|
|
2
|
-
import Space from './Space';
|
|
3
|
-
declare const ATTR_TYPE: {
|
|
4
|
-
TEXT: string;
|
|
5
|
-
NUMBER: string;
|
|
6
|
-
BOOLEAN: string;
|
|
7
|
-
DATE: string;
|
|
8
|
-
};
|
|
9
|
-
export type AttrType = keyof typeof ATTR_TYPE;
|
|
10
|
-
export default class Attr extends ModelWithState<Attr> {
|
|
11
|
-
constructor(name?: string, description?: string);
|
|
12
|
-
id: number;
|
|
13
|
-
private _name;
|
|
14
|
-
get name(): string;
|
|
15
|
-
set name(value: string);
|
|
16
|
-
private _description;
|
|
17
|
-
get description(): string;
|
|
18
|
-
set description(value: string);
|
|
19
|
-
private _type;
|
|
20
|
-
get type(): AttrType;
|
|
21
|
-
set type(value: AttrType);
|
|
22
|
-
get isText(): boolean;
|
|
23
|
-
get isNumber(): boolean;
|
|
24
|
-
get isBoolean(): boolean;
|
|
25
|
-
get isDate(): boolean;
|
|
26
|
-
asText(): Attr;
|
|
27
|
-
asNumber(): Attr;
|
|
28
|
-
asBoolean(): Attr;
|
|
29
|
-
asDate(): Attr;
|
|
30
|
-
private _space;
|
|
31
|
-
get space(): Space;
|
|
32
|
-
set space(value: Space);
|
|
33
|
-
in(space: Space): Attr;
|
|
34
|
-
private _color;
|
|
35
|
-
get color(): string;
|
|
36
|
-
set color(value: string);
|
|
37
|
-
duplicate(): Attr;
|
|
38
|
-
duplicateAsNew(): Attr;
|
|
39
|
-
validate(throwError?: boolean): boolean;
|
|
40
|
-
get defaultValue(): any;
|
|
41
|
-
toJSON(): {
|
|
42
|
-
state: "NEW" | "CLEAN" | "DIRTY" | "DELETED";
|
|
43
|
-
id: number;
|
|
44
|
-
name: string;
|
|
45
|
-
description: string;
|
|
46
|
-
type: "TEXT" | "NUMBER" | "BOOLEAN" | "DATE";
|
|
47
|
-
spaceId: number;
|
|
48
|
-
color: string;
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
export {};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import ModelWithState from './ModelWithState';
|
|
2
|
-
import Attr from './Attr';
|
|
3
|
-
import Tag from './Tag';
|
|
4
|
-
export default class NoteAttr extends ModelWithState<NoteAttr> {
|
|
5
|
-
constructor(attr: Attr, tag?: Tag, value?: any);
|
|
6
|
-
private _tag;
|
|
7
|
-
get tag(): Tag;
|
|
8
|
-
private _attr;
|
|
9
|
-
get attr(): Attr;
|
|
10
|
-
private _value;
|
|
11
|
-
get value(): any;
|
|
12
|
-
set value(newVal: any);
|
|
13
|
-
withValue(value: any): NoteAttr;
|
|
14
|
-
duplicate(): NoteAttr;
|
|
15
|
-
duplicateAsNew(): NoteAttr;
|
|
16
|
-
validate(throwError?: boolean): boolean;
|
|
17
|
-
toJSON(): {
|
|
18
|
-
state: "NEW" | "CLEAN" | "DIRTY" | "DELETED";
|
|
19
|
-
attrId: number;
|
|
20
|
-
tagId: number;
|
|
21
|
-
value: any;
|
|
22
|
-
};
|
|
23
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export declare class NewParsedQuery {
|
|
2
|
-
where: string;
|
|
3
|
-
order: string;
|
|
4
|
-
tags: Array<NewParsedTag>;
|
|
5
|
-
}
|
|
6
|
-
export declare class NewParsedTag {
|
|
7
|
-
space: string;
|
|
8
|
-
name: string;
|
|
9
|
-
searchDepths: Array<number>;
|
|
10
|
-
filter: NewParsedTagFilter;
|
|
11
|
-
}
|
|
12
|
-
export declare class NewParsedTagFilter {
|
|
13
|
-
pattern: string;
|
|
14
|
-
exps: Array<string>;
|
|
15
|
-
}
|
|
16
|
-
export default function newParseQuery(query: string): NewParsedQuery;
|
|
17
|
-
export declare function splitQuery(query: string): NewParsedQuery;
|
|
18
|
-
export declare function identifyTags(query: string, parsedQuery: NewParsedQuery): string;
|