notu 0.12.2 → 0.14.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 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
  }
@@ -205,9 +47,6 @@ class Notu {
205
47
  async getNoteCount(query, spaceId) {
206
48
  return await this.client.getNoteCount(query, spaceId);
207
49
  }
208
- async getRelatedNotes(tag) {
209
- return (await this.client.getRelatedNotes(tag)).map((n) => this.cache.noteFromJSON(n));
210
- }
211
50
  async saveNotes(notes) {
212
51
  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);
213
52
  for (const noteData of notesData.filter((x) => !!x.ownTag && !x.ownTag.isDeleted))
@@ -220,71 +59,214 @@ class Notu {
220
59
  return await this.client.customJob(name, data);
221
60
  }
222
61
  }
223
- class NoteAttr extends ModelWithState {
224
- constructor(attr, tag, value) {
62
+ class ModelWithState {
63
+ constructor() {
64
+ __publicField(this, "state", "NEW");
65
+ }
66
+ new() {
67
+ return this.state = "NEW", this;
68
+ }
69
+ clean() {
70
+ return this.state = "CLEAN", this;
71
+ }
72
+ dirty() {
73
+ return this.state = "DIRTY", this;
74
+ }
75
+ delete() {
76
+ return this.state = "DELETED", this;
77
+ }
78
+ get isNew() {
79
+ return this.state == "NEW";
80
+ }
81
+ get isClean() {
82
+ return this.state == "CLEAN";
83
+ }
84
+ get isDirty() {
85
+ return this.state == "DIRTY";
86
+ }
87
+ get isDeleted() {
88
+ return this.state == "DELETED";
89
+ }
90
+ validate(throwError = !1) {
91
+ return !0;
92
+ }
93
+ }
94
+ class Space extends ModelWithState {
95
+ constructor(name = "") {
225
96
  super();
226
- __publicField(this, "_tag", null);
227
- __publicField(this, "_attr", null);
228
- __publicField(this, "_value", null);
229
- if (!attr)
230
- throw Error("Cannot instanciate new NoteAttr without a passed in attr.");
231
- if (attr.isNew)
232
- throw Error("Cannot create a NoteAttr object for an attr that hasn't been saved yet.");
233
- if (attr.isDeleted)
234
- throw Error("Cannot create a NoteAttr object for an attr marked as deleted.");
235
- if (this._attr = attr, tag) {
236
- if (tag.isNew)
237
- throw Error("Cannot create a NoteAttr object linked to a tag that hasn't been saved yet.");
238
- if (tag.isDeleted)
239
- throw Error("Cannot create a NoteAttr object linked to a tag marked as deleted.");
240
- this._tag = tag;
241
- }
242
- value != null && value != null ? this.value = value : this.value = attr.defaultValue;
97
+ __publicField(this, "_id", 0);
98
+ __publicField(this, "_name", "");
99
+ __publicField(this, "_version", "0.0.1");
100
+ __publicField(this, "_useCommonSpace", !1);
101
+ this._name = name;
243
102
  }
244
- get tag() {
245
- return this._tag;
103
+ get id() {
104
+ return this._id;
246
105
  }
247
- get attr() {
248
- return this._attr;
106
+ set id(value) {
107
+ if (!this.isNew)
108
+ throw Error("Cannot change the id of a Space once it has already been created.");
109
+ this._id = value;
249
110
  }
250
- get value() {
251
- return this._value;
111
+ get name() {
112
+ return this._name;
252
113
  }
253
- set value(newVal) {
254
- 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());
114
+ set name(value) {
115
+ value !== this._name && (this._name = value, this.isClean && this.dirty());
255
116
  }
256
- withValue(value) {
257
- return this.value = value, this;
117
+ get version() {
118
+ return this._version;
119
+ }
120
+ set version(value) {
121
+ value !== this._version && (this._version = value, this.isClean && this.dirty());
122
+ }
123
+ v(version) {
124
+ return this.version = version, this;
125
+ }
126
+ get useCommonSpace() {
127
+ return this._useCommonSpace;
128
+ }
129
+ set useCommonSpace(value) {
130
+ value !== this._useCommonSpace && (this._useCommonSpace = value, this.isClean && this.dirty());
258
131
  }
259
132
  duplicate() {
260
133
  const output = this.duplicateAsNew();
261
- return output.state = this.state, output;
134
+ return output.id = this.id, output.state = this.state, output;
262
135
  }
263
136
  duplicateAsNew() {
264
- return new NoteAttr(this.attr, this.tag, this.value);
137
+ const output = new Space();
138
+ return output.name = this.name, output.version = this.version, output;
265
139
  }
266
140
  validate(throwError = !1) {
267
141
  let output = null;
268
- if (throwError && output != null)
142
+ if (!this.isNew && this.id <= 0 && (output = "Space id must be greater than zero if in non-new state."), throwError && output != null)
269
143
  throw Error(output);
270
144
  return output == null;
271
145
  }
272
146
  toJSON() {
273
- var _a;
274
147
  return {
275
148
  state: this.state,
276
- attrId: this.attr.id,
277
- tagId: (_a = this.tag) == null ? void 0 : _a.id,
278
- value: this.value
149
+ id: this.id,
150
+ name: this.name,
151
+ version: this.version,
152
+ useCommonSpace: this.useCommonSpace
279
153
  };
280
154
  }
281
155
  }
156
+ class NotuHttpClient {
157
+ constructor(url, fetchMethod = null) {
158
+ __publicField(this, "_url", null);
159
+ __publicField(this, "_token", null);
160
+ //Added for testing support
161
+ __publicField(this, "_fetch");
162
+ //Used to handle error responses that come in and take some custom action on them
163
+ //Returns true if the response was handled, otherwise returns in which case an error will be thrown
164
+ __publicField(this, "errorHandler", null);
165
+ if (!url)
166
+ throw Error("Endpoint URL must be passed in to NotuClient constructor");
167
+ url.endsWith("/") && (url = url.substring(0, url.length - 1)), this._url = url, this._fetch = fetchMethod ?? window.fetch.bind(window);
168
+ }
169
+ get url() {
170
+ return this._url;
171
+ }
172
+ get token() {
173
+ return this._token;
174
+ }
175
+ set token(value) {
176
+ this._token = value;
177
+ }
178
+ _validateResponseStatus(response) {
179
+ if (response.status >= 400 && response.status < 600) {
180
+ if (this.errorHandler && this.errorHandler(response))
181
+ return;
182
+ throw Error(response.statusText);
183
+ }
184
+ }
185
+ async login(username, password) {
186
+ const response = await this._fetch(
187
+ this.url + "/login",
188
+ {
189
+ method: "POST",
190
+ body: JSON.stringify({ username, password })
191
+ }
192
+ );
193
+ if (this._validateResponseStatus(response), response.body != null) {
194
+ const result = await response.json();
195
+ return result && (this._token = result), result;
196
+ }
197
+ throw Error("Unknown error occurred on the server");
198
+ }
199
+ async setup() {
200
+ const response = await this._fetch(
201
+ this.url + "/setup",
202
+ {
203
+ method: "POST",
204
+ headers: { Authorization: "Bearer " + this.token }
205
+ }
206
+ );
207
+ this._validateResponseStatus(response), await response.json();
208
+ }
209
+ async saveSpace(space) {
210
+ const response = await this._fetch(
211
+ this.url + "/spaces",
212
+ {
213
+ method: "POST",
214
+ body: JSON.stringify(space),
215
+ headers: { Authorization: "Bearer " + this.token }
216
+ }
217
+ );
218
+ return this._validateResponseStatus(response), await response.json();
219
+ }
220
+ async getNotes(query, space) {
221
+ space && space instanceof Space && (space = space.id);
222
+ const response = await this._fetch(
223
+ this.url + `/notes?${space ? `space=${space}&` : ""}query=${encodeURIComponent(query)}`,
224
+ {
225
+ method: "GET",
226
+ headers: { Authorization: "Bearer " + this.token }
227
+ }
228
+ );
229
+ return this._validateResponseStatus(response), await response.json();
230
+ }
231
+ async getNoteCount(query, space) {
232
+ space instanceof Space && (space = space.id);
233
+ const response = await this._fetch(
234
+ this.url + `/notes?count=true&space=${space}&query=${encodeURIComponent(query)}`,
235
+ {
236
+ method: "GET",
237
+ headers: { Authorization: "Bearer " + this.token }
238
+ }
239
+ );
240
+ return this._validateResponseStatus(response), (await response.json()).count;
241
+ }
242
+ async saveNotes(notes) {
243
+ const response = await this._fetch(
244
+ this.url + "/notes",
245
+ {
246
+ method: "POST",
247
+ body: JSON.stringify(notes),
248
+ headers: { Authorization: "Bearer " + this.token }
249
+ }
250
+ );
251
+ return this._validateResponseStatus(response), await response.json();
252
+ }
253
+ async customJob(name, data) {
254
+ const response = await this._fetch(
255
+ this.url + "/customJob",
256
+ {
257
+ method: "POST",
258
+ body: JSON.stringify({ name, data, clientTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone }),
259
+ headers: { Authorization: "Bearer " + this.token }
260
+ }
261
+ );
262
+ return this._validateResponseStatus(response), await response.json();
263
+ }
264
+ }
282
265
  class NoteTag extends ModelWithState {
283
266
  constructor(tag) {
284
267
  super();
285
268
  __publicField(this, "_tag");
286
269
  __publicField(this, "_data");
287
- __publicField(this, "_attrs", []);
288
270
  if (!tag)
289
271
  throw Error("Cannot instanciate new NoteTag without a passed in tag.");
290
272
  if (tag.isNew)
@@ -305,38 +287,13 @@ class NoteTag extends ModelWithState {
305
287
  withData(data) {
306
288
  return this.data = data, this;
307
289
  }
308
- get attrs() {
309
- return this._attrs.filter((x) => !x.isDeleted);
310
- }
311
- get attrsPendingDeletion() {
312
- return this._attrs.filter((x) => x.isDeleted);
313
- }
314
- addAttr(attr, value) {
315
- if (attr.isDeleted)
316
- throw Error("Cannot add an attribute marked as deleted.");
317
- if (attr.isNew)
318
- throw Error("Cannot add an attribute that hasn't yet been saved.");
319
- let na = this.attrs.find((x) => x.attr.id == attr.id);
320
- return na ? (na.isDeleted && na.dirty(), value != null && (na.value = value), this) : (na = new NoteAttr(attr, this.tag, value), this._attrs.push(na), this);
321
- }
322
- removeAttr(attr) {
323
- const na = this._attrs.find((x) => x.attr.id == attr.id);
324
- return na ? (na.isNew ? this._attrs = this._attrs.filter((x) => x !== na) : na.delete(), this) : this;
325
- }
326
- getAttr(attr) {
327
- return attr instanceof Attr && (attr = attr.name), this.attrs.find((x) => x.attr.name == attr);
328
- }
329
- getValue(attr) {
330
- var _a;
331
- return (_a = this.getAttr(attr)) == null ? void 0 : _a.value;
332
- }
333
290
  duplicate() {
334
291
  const output = this.duplicateAsNew();
335
292
  return output.state = this.state, output;
336
293
  }
337
294
  duplicateAsNew() {
338
295
  const output = new NoteTag(this.tag);
339
- return this.data && (output._data = JSON.parse(JSON.stringify(this.data))), output._attrs = this.attrs.map((x) => x.duplicateAsNew()), output;
296
+ return this.data && (output._data = JSON.parse(JSON.stringify(this.data))), output;
340
297
  }
341
298
  validate(throwError = !1) {
342
299
  function exit(message) {
@@ -344,81 +301,13 @@ class NoteTag extends ModelWithState {
344
301
  throw Error(message);
345
302
  return message == null;
346
303
  }
347
- if (!this.tag)
348
- return exit("NoteTag must have a tag set.");
349
- for (const na of this._attrs)
350
- if (!na.validate(throwError))
351
- return !1;
352
- return !0;
304
+ return this.tag ? !0 : exit("NoteTag must have a tag set.");
353
305
  }
354
306
  toJSON() {
355
307
  return {
356
308
  state: this.state,
357
309
  tagId: this.tag.id,
358
- data: this.data,
359
- attrs: this._attrs.map((x) => x.toJSON())
360
- };
361
- }
362
- }
363
- class Space extends ModelWithState {
364
- constructor(name = "") {
365
- super();
366
- __publicField(this, "_id", 0);
367
- __publicField(this, "_name", "");
368
- __publicField(this, "_version", "0.0.1");
369
- __publicField(this, "_useCommonSpace", !1);
370
- this._name = name;
371
- }
372
- get id() {
373
- return this._id;
374
- }
375
- set id(value) {
376
- if (!this.isNew)
377
- throw Error("Cannot change the id of a Space once it has already been created.");
378
- this._id = value;
379
- }
380
- get name() {
381
- return this._name;
382
- }
383
- set name(value) {
384
- value !== this._name && (this._name = value, this.isClean && this.dirty());
385
- }
386
- get version() {
387
- return this._version;
388
- }
389
- set version(value) {
390
- value !== this._version && (this._version = value, this.isClean && this.dirty());
391
- }
392
- v(version) {
393
- return this.version = version, this;
394
- }
395
- get useCommonSpace() {
396
- return this._useCommonSpace;
397
- }
398
- set useCommonSpace(value) {
399
- value !== this._useCommonSpace && (this._useCommonSpace = value, this.isClean && this.dirty());
400
- }
401
- duplicate() {
402
- const output = this.duplicateAsNew();
403
- return output.id = this.id, output.state = this.state, output;
404
- }
405
- duplicateAsNew() {
406
- const output = new Space();
407
- return output.name = this.name, output.version = this.version, output;
408
- }
409
- validate(throwError = !1) {
410
- let output = null;
411
- if (!this.isNew && this.id <= 0 && (output = "Space id must be greater than zero if in non-new state."), throwError && output != null)
412
- throw Error(output);
413
- return output == null;
414
- }
415
- toJSON() {
416
- return {
417
- state: this.state,
418
- id: this.id,
419
- name: this.name,
420
- version: this.version,
421
- useCommonSpace: this.useCommonSpace
310
+ data: this.data
422
311
  };
423
312
  }
424
313
  }
@@ -532,7 +421,6 @@ class Note extends ModelWithState {
532
421
  __publicField(this, "_space", null);
533
422
  __publicField(this, "_ownTag", null);
534
423
  __publicField(this, "_tags", []);
535
- __publicField(this, "_attrs", []);
536
424
  text && (this.text = text), this._ownTag = ownTag;
537
425
  }
538
426
  get id() {
@@ -603,46 +491,11 @@ class Note extends ModelWithState {
603
491
  }
604
492
  removeTag(tag) {
605
493
  const nt = this._tags.find((x) => x.tag.id == tag.id);
606
- if (!nt)
607
- return this;
608
- if (nt.isNew)
609
- this._tags = this._tags.filter((x) => x !== nt);
610
- else {
611
- nt.delete();
612
- const attrs = nt.attrs.map((x) => x.attr);
613
- for (const attr of attrs)
614
- nt.removeAttr(attr);
615
- }
616
- return this;
494
+ return nt ? (nt.isNew ? this._tags = this._tags.filter((x) => x !== nt) : nt.delete(), this) : this;
617
495
  }
618
496
  getTag(tag, space = null) {
619
497
  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));
620
498
  }
621
- get attrs() {
622
- return this._attrs.filter((x) => !x.isDeleted);
623
- }
624
- get attrsPendingDeletion() {
625
- return this._attrs.filter((x) => x.isDeleted);
626
- }
627
- addAttr(attr, value) {
628
- if (attr.isDeleted)
629
- throw Error("Cannot add an attribute marked as deleted to a note");
630
- if (attr.isNew)
631
- throw Error("Cannot add an attribute that hasn't yet been saved to a note");
632
- let na = this.attrs.find((x) => x.attr.id == attr.id);
633
- return na ? (na.isDeleted && na.dirty(), value != null && (na.value = value), this) : (na = new NoteAttr(attr, null, value), this._attrs.push(na), this);
634
- }
635
- removeAttr(attr) {
636
- const na = this._attrs.find((x) => x.attr.id == attr.id);
637
- return na ? (na.isNew ? this._attrs = this._attrs.filter((x) => x !== na) : na.delete(), this) : this;
638
- }
639
- getAttr(attr) {
640
- return attr instanceof Attr && (attr = attr.name), this.attrs.find((x) => x.attr.name == attr);
641
- }
642
- getValue(attr) {
643
- var _a;
644
- return (_a = this.getAttr(attr)) == null ? void 0 : _a.value;
645
- }
646
499
  getTagData(tag, type) {
647
500
  const nt = this.getTag(tag);
648
501
  return nt ? new type(nt) : null;
@@ -650,11 +503,11 @@ class Note extends ModelWithState {
650
503
  duplicate() {
651
504
  var _a;
652
505
  const output = new Note(this.text, (_a = this.ownTag) == null ? void 0 : _a.duplicate()).at(this.date).in(this.space);
653
- 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;
506
+ return output._tags = this.tags.map((x) => x.duplicate()), output.id = this.id, output.state = this.state, output;
654
507
  }
655
508
  duplicateAsNew() {
656
509
  const output = new Note(this.text).at(this.date).in(this.space);
657
- return output._attrs = this.attrs.map((x) => x.duplicateAsNew()), output._tags = this.tags.map((x) => x.duplicateAsNew()), output;
510
+ return output._tags = this.tags.map((x) => x.duplicateAsNew()), output;
658
511
  }
659
512
  toJSON() {
660
513
  var _a;
@@ -665,8 +518,7 @@ class Note extends ModelWithState {
665
518
  text: this.text,
666
519
  spaceId: this.space.id,
667
520
  ownTag: (_a = this.ownTag) == null ? void 0 : _a.toJSON(),
668
- tags: this._tags.map((x) => x.toJSON()),
669
- attrs: this._attrs.map((x) => x.toJSON())
521
+ tags: this._tags.map((x) => x.toJSON())
670
522
  };
671
523
  }
672
524
  validate(throwError = !1) {
@@ -682,172 +534,26 @@ class Note extends ModelWithState {
682
534
  return exit("Note cannot belong to a different space than its own tag");
683
535
  } else
684
536
  return exit("Note must belong to a space.");
685
- const survivingAttrs = this.attrs;
686
- for (let i = 0; i < survivingAttrs.length; i++) {
687
- const na = survivingAttrs[i];
688
- for (let j = i + 1; j < survivingAttrs.length; j++) {
689
- const na2 = survivingAttrs[j];
690
- if (na.attr.id == na2.attr.id)
691
- return exit(`Attr '${na.attr.name}' is duplicated.`);
692
- }
693
- }
694
537
  if (this.ownTag && !this.ownTag.validate(throwError))
695
538
  return !1;
696
539
  for (const nt of this._tags)
697
540
  if (!nt.validate(throwError))
698
541
  return !1;
699
- for (const na of this._attrs)
700
- if (!na.validate(throwError))
701
- return !1;
702
542
  return !0;
703
543
  }
704
544
  }
705
- class NotuHttpClient {
706
- constructor(url, fetchMethod = null) {
707
- __publicField(this, "_url", null);
708
- __publicField(this, "_token", null);
709
- //Added for testing support
710
- __publicField(this, "_fetch");
711
- //Used to handle error responses that come in and take some custom action on them
712
- //Returns true if the response was handled, otherwise returns in which case an error will be thrown
713
- __publicField(this, "errorHandler", null);
714
- if (!url)
715
- throw Error("Endpoint URL must be passed in to NotuClient constructor");
716
- url.endsWith("/") && (url = url.substring(0, url.length - 1)), this._url = url, this._fetch = fetchMethod ?? window.fetch.bind(window);
717
- }
718
- get url() {
719
- return this._url;
720
- }
721
- get token() {
722
- return this._token;
723
- }
724
- set token(value) {
725
- this._token = value;
726
- }
727
- _validateResponseStatus(response) {
728
- if (response.status >= 400 && response.status < 600) {
729
- if (this.errorHandler && this.errorHandler(response))
730
- return;
731
- throw Error(response.statusText);
732
- }
733
- }
734
- async login(username, password) {
735
- const response = await this._fetch(
736
- this.url + "/login",
737
- {
738
- method: "POST",
739
- body: JSON.stringify({ username, password })
740
- }
741
- );
742
- if (this._validateResponseStatus(response), response.body != null) {
743
- const result = await response.json();
744
- return result && (this._token = result), result;
745
- }
746
- throw Error("Unknown error occurred on the server");
747
- }
748
- async setup() {
749
- const response = await this._fetch(
750
- this.url + "/setup",
751
- {
752
- method: "POST",
753
- headers: { Authorization: "Bearer " + this.token }
754
- }
755
- );
756
- this._validateResponseStatus(response), await response.json();
757
- }
758
- async saveSpace(space) {
759
- const response = await this._fetch(
760
- this.url + "/spaces",
761
- {
762
- method: "POST",
763
- body: JSON.stringify(space),
764
- headers: { Authorization: "Bearer " + this.token }
765
- }
766
- );
767
- return this._validateResponseStatus(response), await response.json();
768
- }
769
- async saveAttr(attr) {
770
- const response = await this._fetch(
771
- this.url + "/attrs",
772
- {
773
- method: "POST",
774
- body: JSON.stringify(attr),
775
- headers: { Authorization: "Bearer " + this.token }
776
- }
777
- );
778
- return this._validateResponseStatus(response), await response.json();
779
- }
780
- async getNotes(query, space) {
781
- space instanceof Space && (space = space.id);
782
- const response = await this._fetch(
783
- this.url + `/notes?space=${space}&query=${encodeURIComponent(query)}`,
784
- {
785
- method: "GET",
786
- headers: { Authorization: "Bearer " + this.token }
787
- }
788
- );
789
- return this._validateResponseStatus(response), await response.json();
790
- }
791
- async getNoteCount(query, space) {
792
- space instanceof Space && (space = space.id);
793
- const response = await this._fetch(
794
- this.url + `/notes?count=true&space=${space}&query=${encodeURIComponent(query)}`,
795
- {
796
- method: "GET",
797
- headers: { Authorization: "Bearer " + this.token }
798
- }
799
- );
800
- return this._validateResponseStatus(response), (await response.json()).count;
801
- }
802
- async getRelatedNotes(tag) {
803
- tag instanceof Tag && (tag = tag.id), tag instanceof Note && (tag = tag.id);
804
- const response = await this._fetch(
805
- this.url + `/notes?tag=${tag}`,
806
- {
807
- method: "GET",
808
- headers: { Authorization: "Bearer " + this.token }
809
- }
810
- );
811
- return this._validateResponseStatus(response), await response.json();
812
- }
813
- async saveNotes(notes) {
814
- const response = await this._fetch(
815
- this.url + "/notes",
816
- {
817
- method: "POST",
818
- body: JSON.stringify(notes),
819
- headers: { Authorization: "Bearer " + this.token }
820
- }
821
- );
822
- return this._validateResponseStatus(response), await response.json();
823
- }
824
- async customJob(name, data) {
825
- const response = await this._fetch(
826
- this.url + "/customJob",
827
- {
828
- method: "POST",
829
- body: JSON.stringify({ name, data, clientTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone }),
830
- headers: { Authorization: "Bearer " + this.token }
831
- }
832
- );
833
- return this._validateResponseStatus(response), await response.json();
834
- }
835
- }
836
545
  class NotuCache {
837
546
  constructor(fetcher) {
838
547
  __publicField(this, "_fetcher");
839
548
  __publicField(this, "_spaces", null);
840
549
  __publicField(this, "_tags", null);
841
550
  __publicField(this, "_tagNames", null);
842
- __publicField(this, "_attrs", null);
843
551
  if (!fetcher)
844
552
  throw Error("NotuCache constructor must have a fetcher argument supplied.");
845
553
  this._fetcher = fetcher;
846
554
  }
847
555
  async populate() {
848
- await this._populateSpaces();
849
- const tagsPromise = this._populateTags(), attrsPromise = this._populateAttrs();
850
- await Promise.all([tagsPromise, attrsPromise]), this._populateTagNames();
556
+ await this._populateSpaces(), await this._populateTags(), this._populateTagNames();
851
557
  }
852
558
  async _populateSpaces() {
853
559
  const spacesData = await this._fetcher.getSpacesData();
@@ -884,32 +590,12 @@ class NotuCache {
884
590
  _populateTagLinks(tag, tagData) {
885
591
  tag.links = tagData.links.map((x) => this._tags.get(x));
886
592
  }
887
- async _populateAttrs() {
888
- const attrsData = await this._fetcher.getAttrsData();
889
- this._attrs = /* @__PURE__ */ new Map();
890
- for (const attrData of attrsData) {
891
- const attr = this.attrFromJSON(attrData);
892
- this._attrs.set(attr.id, attr);
893
- }
894
- }
895
- attrFromJSON(attrData) {
896
- const attr = new Attr(attrData.name, attrData.description);
897
- return attr.id = attrData.id, attr.type = attrData.type, attr.space = this._spaces.get(attrData.spaceId), attr.state = attrData.state, attr;
898
- }
899
593
  noteFromJSON(noteData) {
900
594
  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));
901
595
  note.id = noteData.id, note.state = noteData.state;
902
- for (const naData of noteData.attrs) {
903
- const attr = this.getAttr(naData.attrId);
904
- note.addAttr(attr, naData.value), note.getAttr(attr).state = naData.state;
905
- }
906
596
  for (const ntData of noteData.tags) {
907
597
  const nt = note.addTag(this.getTag(ntData.tagId));
908
598
  nt.data = ntData.data, nt.state = ntData.state;
909
- for (const ntaData of ntData.attrs) {
910
- const attr = this.getAttr(ntaData.attrId);
911
- nt.addAttr(attr, ntaData.value), nt.getAttr(attr).state = ntaData.state;
912
- }
913
599
  }
914
600
  return note;
915
601
  }
@@ -947,22 +633,6 @@ class NotuCache {
947
633
  const tag = this.tagFromJSON(tagData);
948
634
  return tag.state == "DELETED" ? this._tags.delete(tag.id) : this._tags.set(tag.id, tag), this._populateTagNames(), tag;
949
635
  }
950
- getAttrs(space = null) {
951
- 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));
952
- }
953
- getAttr(id) {
954
- return this._attrs.get(id);
955
- }
956
- getAttrByName(name, space) {
957
- space instanceof Space && (space = space.id);
958
- for (const attr of this._attrs.values())
959
- if (attr.name == name && attr.space.id == space)
960
- return attr;
961
- }
962
- attrSaved(attrData) {
963
- const attr = this.attrFromJSON(attrData);
964
- return attr.state == "DELETED" ? this._attrs.delete(attr.id) : this._attrs.set(attr.id, attr), attr;
965
- }
966
636
  }
967
637
  class NotuHttpCacheFetcher {
968
638
  constructor(url, token, fetchMethod = null) {
@@ -988,9 +658,6 @@ class NotuHttpCacheFetcher {
988
658
  async getTagsData() {
989
659
  return await this._getX("/tags");
990
660
  }
991
- async getAttrsData() {
992
- return await this._getX("/attrs");
993
- }
994
661
  async _getX(endpoint) {
995
662
  return await (await this._fetch(
996
663
  this.url + endpoint,
@@ -1049,89 +716,9 @@ class ParsedQuery {
1049
716
  __publicField(this, "where", null);
1050
717
  __publicField(this, "order", null);
1051
718
  __publicField(this, "tags", []);
1052
- __publicField(this, "attrs", []);
1053
719
  }
1054
720
  }
1055
721
  class ParsedTag {
1056
- constructor() {
1057
- __publicField(this, "space", null);
1058
- __publicField(this, "name", null);
1059
- __publicField(this, "searchDepth", 0);
1060
- __publicField(this, "strictSearchDepth", !0);
1061
- __publicField(this, "includeOwner", !1);
1062
- }
1063
- }
1064
- class ParsedAttr {
1065
- constructor() {
1066
- __publicField(this, "name", null);
1067
- __publicField(this, "exists", !1);
1068
- __publicField(this, "tagNameFilters", null);
1069
- }
1070
- }
1071
- function parseQuery(query) {
1072
- const output = splitQuery$1(query);
1073
- 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;
1074
- }
1075
- function splitQuery$1(query) {
1076
- query = " " + query + " ";
1077
- const output = new ParsedQuery(), orderByIndex = query.toUpperCase().indexOf(" ORDER BY ");
1078
- 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;
1079
- }
1080
- function identifyTags$1(query, parsedQuery) {
1081
- const regexes = [
1082
- /(#+\??~?|~)([\w\d]+\.)?([\w\d]+)/,
1083
- //Single word tags and space names
1084
- /(#+\??~?|~)\[([\w\d\s]+\.)?([\w\d\s]+)\]/
1085
- //Multi-word tags and space names wrapped in []
1086
- ];
1087
- for (const regex of regexes)
1088
- for (; ; ) {
1089
- const match = regex.exec(query);
1090
- if (!match)
1091
- break;
1092
- const hashPrefix = match[1], parsedTag = new ParsedTag();
1093
- 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("?");
1094
- const fullMatch = match[0], matchStart = query.indexOf(fullMatch), matchEnd = matchStart + fullMatch.length;
1095
- query = query.substring(0, matchStart) + `{tag${parsedQuery.tags.length}}` + query.substring(matchEnd), parsedQuery.tags.push(parsedTag);
1096
- }
1097
- return query;
1098
- }
1099
- function identifyAttrs(query, parsedQuery) {
1100
- const regexes = [
1101
- /@([\w\d]+)/,
1102
- /@\[([\w\d\s]+)\]/
1103
- ];
1104
- for (const regex of regexes)
1105
- for (; ; ) {
1106
- const match = regex.exec(query);
1107
- if (!match)
1108
- break;
1109
- const parsedAttr = new ParsedAttr();
1110
- parsedAttr.name = match[1];
1111
- const matchStart = query.indexOf(match[0]);
1112
- let matchEnd = matchStart + match[0].length;
1113
- if (query.substring(matchEnd, matchEnd + 9) == ".Exists()" && (parsedAttr.exists = !0, matchEnd += 9), query.substring(matchEnd, matchEnd + 4) == ".On(") {
1114
- let tagFilterStart = matchEnd + 4;
1115
- if (matchEnd = query.indexOf(")", tagFilterStart), matchEnd < 0)
1116
- throw Error("Unclosed bracket detected");
1117
- let tagNameFilters = query.substring(tagFilterStart, matchEnd).split("|");
1118
- const dummyParsedQuery = new ParsedQuery();
1119
- for (let tagNameFilter of tagNameFilters)
1120
- tagNameFilter.startsWith("~") || (tagNameFilter = "~" + tagNameFilter), identifyTags$1(tagNameFilter, dummyParsedQuery);
1121
- parsedAttr.tagNameFilters = dummyParsedQuery.tags, matchEnd++;
1122
- }
1123
- query = query.substring(0, matchStart) + `{attr${parsedQuery.attrs.length}}` + query.substring(matchEnd), parsedQuery.attrs.push(parsedAttr);
1124
- }
1125
- return query;
1126
- }
1127
- class NewParsedQuery {
1128
- constructor() {
1129
- __publicField(this, "where", null);
1130
- __publicField(this, "order", null);
1131
- __publicField(this, "tags", []);
1132
- }
1133
- }
1134
- class NewParsedTag {
1135
722
  constructor() {
1136
723
  __publicField(this, "space", null);
1137
724
  __publicField(this, "name", null);
@@ -1139,19 +726,19 @@ class NewParsedTag {
1139
726
  __publicField(this, "filter", null);
1140
727
  }
1141
728
  }
1142
- class NewParsedTagFilter {
729
+ class ParsedTagFilter {
1143
730
  constructor() {
1144
731
  __publicField(this, "pattern", null);
1145
732
  __publicField(this, "exps", []);
1146
733
  }
1147
734
  }
1148
- function newParseQuery(query) {
735
+ function parseQuery(query) {
1149
736
  const output = splitQuery(query);
1150
737
  return output.where = identifyTags(output.where, output), output.order = identifyTags(output.order, output), output;
1151
738
  }
1152
739
  function splitQuery(query) {
1153
740
  query = " " + query + " ";
1154
- const output = new NewParsedQuery(), orderByIndex = query.toUpperCase().indexOf(" ORDER BY ");
741
+ const output = new ParsedQuery(), orderByIndex = query.toUpperCase().indexOf(" ORDER BY ");
1155
742
  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;
1156
743
  }
1157
744
  function identifyTags(query, parsedQuery) {
@@ -1167,7 +754,7 @@ function identifyTags(query, parsedQuery) {
1167
754
  if (!match)
1168
755
  break;
1169
756
  let hashPrefix = match[1];
1170
- const parsedTag = new NewParsedTag();
757
+ const parsedTag = new ParsedTag();
1171
758
  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));
1172
759
  for (let i = 0; i < hashPrefix.length; i++)
1173
760
  hashPrefix[i] == "#" && parsedTag.searchDepths.push(i + 1);
@@ -1193,7 +780,7 @@ function getTagDataFilterText(query, tagEndIndex) {
1193
780
  return query.substring(tagEndIndex + 1, i);
1194
781
  }
1195
782
  function processTagDataFilter(parsedTag, filterText) {
1196
- filterText = ` ${filterText}`, parsedTag.filter = new NewParsedTagFilter(), parsedTag.filter.pattern = filterText;
783
+ filterText = ` ${filterText}`, parsedTag.filter = new ParsedTagFilter(), parsedTag.filter.pattern = filterText;
1197
784
  const expressionRegex = /[\s\(]\.([\w\d\[\]\.]+)/;
1198
785
  for (; ; ) {
1199
786
  const match = expressionRegex.exec(parsedTag.filter.pattern);
@@ -1205,24 +792,18 @@ function processTagDataFilter(parsedTag, filterText) {
1205
792
  parsedTag.filter.pattern = parsedTag.filter.pattern.trim();
1206
793
  }
1207
794
  export {
1208
- Attr,
1209
- NewParsedQuery,
1210
- NewParsedTag,
1211
- NewParsedTagFilter,
1212
795
  Note,
1213
- NoteAttr,
1214
796
  NoteComponentInfo,
1215
797
  NoteTag,
1216
798
  Notu,
1217
799
  NotuCache,
1218
800
  NotuHttpCacheFetcher,
1219
801
  NotuHttpClient,
1220
- ParsedAttr,
1221
802
  ParsedQuery,
1222
803
  ParsedTag,
804
+ ParsedTagFilter,
1223
805
  Space,
1224
806
  Tag,
1225
- newParseQuery,
1226
807
  parseQuery,
1227
808
  splitNoteTextIntoComponents
1228
809
  };