refactor: make all private methods/properties start with an underscore

This commit is contained in:
thecodrr
2020-02-22 21:53:56 +05:00
parent 4a96a0aae2
commit 8bf34553cc
11 changed files with 197 additions and 178 deletions

View File

@@ -213,6 +213,7 @@ test("pin note", () =>
noteTest().then(async ({ db, id }) => {
let note = db.notes.note(id);
await note.pin();
note = db.notes.note(id);
expect(note.data.pinned).toBe(true);
}));
@@ -220,6 +221,7 @@ test("favorite note", () =>
noteTest().then(async ({ db, id }) => {
let note = db.notes.note(id);
await note.favorite();
note = db.notes.note(id);
expect(note.data.favorite).toBe(true);
}));
@@ -232,6 +234,7 @@ test("lock and unlock note", () =>
}).then(async ({ db, id }) => {
let note = db.notes.note(id);
await note.lock("password123");
note = db.notes.note(id);
expect(note.data.locked).toBe(true);
expect(note.data.content.iv).toBeDefined();
expect((await note.delta()).iv).toBeDefined();
@@ -253,8 +256,9 @@ test("add note to topic", () =>
await topics.add("Home");
let topic = topics.topic("Home");
await topic.add(id);
topic = topics.topic("Home");
expect(topic.all.length).toBe(1);
expect(topic.topic.totalNotes).toBe(1);
expect(topic.totalNotes).toBe(1);
expect(db.notebooks.notebook(notebookId).data.totalNotes).toBe(1);
let note = db.notes.note(id);
expect(note.notebook.id).toBe(notebookId);

View File

@@ -47,7 +47,9 @@ test("get topic", () =>
let topic = topics.topic("Home");
let noteId = await db.notes.add({ content: { text: "Hello", delta: [] } });
await topic.add(noteId);
topic = topics.topic("Home");
expect(topic.all[0].content.text).toBe("Hello");
expect(topic.totalNotes).toBe(1);
}));
test("delete a topic", () =>

View File

@@ -17,10 +17,10 @@ test("delete a note", () =>
.add(id);
await db.notes.delete(id);
expect(db.trash.all.length).toBe(1);
expect(await db.trash.deltaStorage.read(id + "_delta")).toBeDefined();
expect(await db.trash._deltaStorage.read(id + "_delta")).toBeDefined();
await db.trash.delete(db.trash.all[0].id);
expect(db.trash.all.length).toBe(0);
expect(await db.trash.deltaStorage.read(id + "_delta")).toBeUndefined();
expect(await db.trash._deltaStorage.read(id + "_delta")).toBeUndefined();
}));
test("restore a deleted note", () =>

View File

@@ -9,9 +9,7 @@ if (!tfun) {
}
export default class Notebooks {
constructor(context) {
this.context = context;
this.collection = new CachedCollection(context, "notebooks");
this.notes = undefined;
this._collection = new CachedCollection(context, "notebooks");
}
/**
@@ -20,16 +18,16 @@ export default class Notebooks {
* @param {Trash} trash
*/
init(notes, trash) {
this.notes = notes;
this.trash = trash;
return this.collection.init();
this._trash = trash;
this._notes = notes;
return this._collection.init();
}
async add(notebookArg) {
if (!notebookArg) throw new Error("Notebook cannot be undefined or null.");
//TODO reliably and efficiently check for duplicates.
const id = notebookArg.id || Date.now().toString() + "_notebook";
let oldNotebook = this.collection.getItem(id);
let oldNotebook = this._collection.getItem(id);
if (!oldNotebook && !notebookArg.title)
throw new Error("Notebook must contain at least a title.");
@@ -54,7 +52,7 @@ export default class Notebooks {
notebook.topics.splice(0, 0, "General");
}
await this.collection.addItem(notebook);
await this._collection.addItem(notebook);
//if (!oldNotebook) {
await this.notebook(notebook.id).topics.add(...notebook.topics);
@@ -63,7 +61,7 @@ export default class Notebooks {
}
get all() {
return this.collection.getAllItems();
return this._collection.getAllItems();
}
/**
@@ -72,7 +70,7 @@ export default class Notebooks {
* @returns {Notebook} The notebook of the given id
*/
notebook(id) {
let notebook = this.collection.getItem(id);
let notebook = this._collection.getItem(id);
if (!notebook) return;
return new Notebook(this, notebook);
}
@@ -81,11 +79,11 @@ export default class Notebooks {
for (let id of ids) {
let notebook = this.notebook(id);
if (!notebook) continue;
await this.collection.transaction(() =>
notebook.topics.delete(...notebook.topics.all)
await this._collection.transaction(() =>
notebook.topics.delete(...notebook.data.topics)
);
await this.collection.removeItem(id);
await this.trash.add(notebook.data);
await this._collection.removeItem(id);
await this._trash.add(notebook.data);
}
}

View File

@@ -19,8 +19,8 @@ if (!tfun) {
export default class Notes {
constructor(context) {
this.collection = new CachedCollection(context, "notes");
this.deltaStorage = new Storage(context);
this._collection = new CachedCollection(context, "notes");
this._deltaStorage = new Storage(context);
}
/**
@@ -29,20 +29,18 @@ export default class Notes {
* @param {Trash} trash
*/
async init(notebooks, trash, tags, colors) {
await this.collection.init();
this.notebooks = notebooks;
this.trash = trash;
// await this.tagsCollection.init();
// await this.colorsCollection.init();
this.tagsCollection = tags;
this.colorsCollection = colors;
await this._collection.init();
this._notebooks = notebooks;
this._trash = trash;
this._tagsCollection = tags;
this._colorsCollection = colors;
}
async add(noteArg) {
if (!noteArg) return;
let id = noteArg.id || Date.now().toString() + "_note";
let oldNote = this.collection.getItem(id);
let oldNote = this._collection.getItem(id);
let note = {
...oldNote,
...noteArg
@@ -54,7 +52,7 @@ export default class Notes {
}
if (!(note.content.delta instanceof String)) {
await this.deltaStorage.write(id + "_delta", note.content.delta);
await this._deltaStorage.write(id + "_delta", note.content.delta);
}
note = {
@@ -74,15 +72,15 @@ export default class Notes {
if (!oldNote) {
for (let color of note.colors) {
await this.colorsCollection.add(color);
await this._colorsCollection.add(color);
}
for (let tag of note.tags) {
await this.tagsCollection.add(tag);
await this._tagsCollection.add(tag);
}
}
await this.collection.addItem(note);
await this._collection.addItem(note);
return note.id;
}
@@ -92,13 +90,13 @@ export default class Notes {
* @returns {Note} The note of the given id
*/
note(id) {
let note = this.collection.getItem(id);
let note = this._collection.getItem(id);
if (!note) return undefined;
return new Note(this, note);
}
get all() {
return this.collection.getAllItems();
return this._collection.getAllItems();
}
get pinned() {
@@ -121,9 +119,7 @@ export default class Notes {
if (!query) return [];
let queryFn = v => fuzzysearch(query, v.title + " " + v.content.text);
if (query instanceof Function) queryFn = query;
let c = tfun.filter(queryFn)(this.all);
return c;
return tfun.filter(queryFn)(this.all);
}
group(by, special = false) {
@@ -179,18 +175,18 @@ export default class Notes {
let item = this.note(id);
if (!item) continue;
if (item.notebook && item.notebook.id && item.notebook.topic) {
await this.collection.transaction(() =>
this.notebooks
await this._collection.transaction(() =>
this._notebooks
.notebook(item.notebook.id)
.topics.topic(item.notebook.topic)
.delete(id)
);
}
for (let tag of item.tags) {
await this.tagsCollection.remove(tag);
await this._tagsCollection.remove(tag);
}
await this.collection.removeItem(id);
await this.trash.add(item.data);
await this._collection.removeItem(id);
await this._trash.add(item.data);
}
}
@@ -200,7 +196,7 @@ export default class Notes {
throw new Error(
"The destination notebook must contain notebookId and topic."
);
let topic = this.notebooks.notebook(to.id).topics.topic(to.topic);
let topic = this._notebooks.notebook(to.id).topics.topic(to.topic);
if (!topic) throw new Error("No such topic exists.");
await topic.transaction(async () => {
await topic.add(...noteIds);

View File

@@ -2,37 +2,37 @@ import CachedCollection from "../database/cached-collection";
export default class Tags {
constructor(context, name) {
this.collection = new CachedCollection(context, name);
this._collection = new CachedCollection(context, name);
}
init() {
return this.collection.init();
return this._collection.init();
}
async add(id) {
if (!id || id.trim().length <= 0) return;
let tag = (await this.collection.getItem(id)) || {
let tag = (await this._collection.getItem(id)) || {
id,
title: id,
count: 0
};
tag.count++;
await this.collection.addItem(tag);
await this._collection.addItem(tag);
}
get all() {
return this.collection.getAllItems();
return this._collection.getAllItems();
}
async remove(id) {
if (!id || id.trim().length <= 0) return;
let tag = this.collection.getItem(id);
let tag = this._collection.getItem(id);
if (!tag) return;
tag.count--;
if (tag.count === 0) {
await this.collection.removeItem(id);
await this._collection.removeItem(id);
} else {
await this.collection.addItem(tag);
await this._collection.addItem(tag);
}
}
}

View File

@@ -7,43 +7,50 @@ export default class Topics {
/**
*
* @param {Notebooks} notebooks
* @param {Notes} notes
* @param {string} notebookId
*/
constructor(notebooks, notes, notebookId) {
this.notebooks = notebooks;
this.notebookId = notebookId;
this.notes = notes;
constructor(notebooks, notebookId) {
this._notebooks = notebooks;
this._notebookId = notebookId;
}
exists(topic) {
has(topic) {
return this.all.findIndex(v => v.title === (topic.title || topic)) > -1;
}
async add(...topics) {
let notebook = this.notebooks.notebook(this.notebookId);
let uniqueTopics = [...notebook.data.topics, ...topics];
uniqueTopics = uniqueTopics.filter(
(v, i) =>
v &&
(v.title || v).trim().length > 0 &&
uniqueTopics.findIndex(t => (v.title || v) === (t.title || t)) === i
);
notebook.data.topics = [];
notebook.data.totalNotes = 0;
for (let topic of uniqueTopics) {
let t = makeTopic(topic, this.notebookId);
notebook.data.topics.push(t);
notebook.data.totalNotes += t.totalNotes;
_dedupe(source) {
let length = source.length,
seen = new Map();
for (let index = 0; index < length; index++) {
let value = source[index];
let title = value.title || value;
if (title.trim().length <= 0) continue;
seen.set(title, value);
}
await this.notebooks.collection.addItem(notebook.data);
return seen;
}
async add(...topics) {
let notebook = { ...this._notebooks.notebook(this._notebookId).data };
let allTopics = [...notebook.topics, ...topics];
const unique = this._dedupe(allTopics);
notebook.topics = [];
notebook.totalNotes = 0;
unique.forEach(t => {
let topic = makeTopic(t, this._notebookId);
notebook.topics.push(topic);
notebook.totalNotes += topic.totalNotes;
});
return this._notebooks._collection.addItem(notebook);
}
/**
* @returns {Array} an array containing all the topics
*/
get all() {
return this.notebooks.notebook(this.notebookId).data.topics;
return this._notebooks.notebook(this._notebookId).data.topics;
}
/**
@@ -71,7 +78,7 @@ export default class Topics {
allTopics.splice(i, 1);
}
}
await this.notebooks.add({ id: this.notebookId, topics: allTopics });
await this._notebooks.add({ id: this._notebookId, topics: allTopics });
}
}

View File

@@ -4,8 +4,8 @@ import Notebooks from "./notebooks";
import Storage from "../database/storage";
export default class Trash {
constructor(context) {
this.collection = new CachedCollection(context, "trash");
this.deltaStorage = new Storage(context);
this._collection = new CachedCollection(context, "trash");
this._deltaStorage = new Storage(context);
}
/**
@@ -14,59 +14,59 @@ export default class Trash {
* @param {Notebooks} notebooks
*/
async init(notes, notebooks) {
this.notes = notes;
this.notebooks = notebooks;
await this.collection.init();
this._notes = notes;
this._notebooks = notebooks;
await this._collection.init();
}
get all() {
return this.collection.getAllItems();
return this._collection.getAllItems();
}
async add(item) {
if (this.collection.exists(item.id + "_deleted"))
if (this._collection.exists(item.id + "_deleted"))
throw new Error("This item has already been deleted.");
item.dateDeleted = Date.now();
item.id = item.id + "_deleted";
await this.collection.addItem(item);
await this._collection.addItem(item);
}
async delete(...ids) {
for (let id of ids) {
if (!this.collection.exists(id)) return;
if (!this._collection.exists(id)) return;
if (id.indexOf("note") > -1)
await this.deltaStorage.remove(id.replace("_deleted", "") + "_delta");
await this.collection.removeItem(id);
await this._deltaStorage.remove(id.replace("_deleted", "") + "_delta");
await this._collection.removeItem(id);
}
}
async restore(...ids) {
for (let id of ids) {
let item = this.collection.getItem(id);
let item = this._collection.getItem(id);
if (!item) continue;
delete item.dateDeleted;
item.id = item.id.replace("_deleted", "");
if (item.type === "note") {
let { notebook } = item;
item.notebook = {};
await this.notes.add(item);
await this._notes.add(item);
if (notebook && notebook.id && notebook.topic) {
const { id, topic } = notebook;
// if the notebook has been deleted
if (!this.notebooks.collection.exists(id)) {
if (!this._notebooks._collection.exists(id)) {
notebook = {};
} else {
// if the topic has been deleted
if (!this.notebooks.notebook(id).topics.exists(topic)) {
if (!this._notebooks.notebook(id).topics.has(topic)) {
notebook = {};
}
}
// restore the note to the topic it was in before deletion
if (notebook.id && notebook.topic) {
await this.notebooks
await this._notebooks
.notebook(id)
.topics.topic(topic)
.add(item.id);
@@ -75,8 +75,8 @@ export default class Trash {
} else {
const { topics } = item;
item.topics = [];
await this.notebooks.add(item);
let notebook = this.notebooks.notebook(item.id);
await this._notebooks.add(item);
let notebook = this._notebooks.notebook(item.id);
for (let topic of topics) {
await notebook.topics.add(topic.title || topic);
let t = notebook.topics.topic(topic.title || topic);
@@ -84,12 +84,12 @@ export default class Trash {
if (topic.notes) await t.add(...topic.notes);
}
}
await this.collection.removeItem(id);
await this._collection.removeItem(id);
}
}
async clear() {
let indices = await this.collection.indexer.getIndices();
let indices = await this._collection.indexer.getIndices();
return this.delete(...indices);
}
}

View File

@@ -7,127 +7,129 @@ export default class Note {
* @param {Object} note
*/
constructor(notes, note) {
this.note = note;
this.notes = notes;
this._note = note;
this._notes = notes;
}
get data() {
return this.note;
return this._note;
}
get headline() {
return this.note.headline;
return this._note.headline;
}
get title() {
return this.note.title;
return this._note.title;
}
get tags() {
return this.note.tags;
return this._note.tags;
}
get colors() {
return this.note.colors;
return this._note.colors;
}
get id() {
return this.note.id;
return this._note.id;
}
get notebook() {
return this.note.notebook;
return this._note.notebook;
}
get text() {
return this.note.content.text;
return this._note.content.text;
}
delta() {
return this.notes.deltaStorage.read(this.note.id + "_delta");
return this._notes._deltaStorage.read(this._note.id + "_delta");
}
color(color) {
return addTag.call(this, color, "colorsCollection", "colors");
return addTag.call(this, color, "_colorsCollection", "colors");
}
uncolor(color) {
return removeTag.call(this, color, "colorsCollection", "colors");
return removeTag.call(this, color, "_colorsCollection", "colors");
}
tag(tag) {
return addTag.call(this, tag, "tagsCollection", "tags");
return addTag.call(this, tag, "_tagsCollection", "tags");
}
untag(tag) {
return removeTag.call(this, tag, "tagsCollection", "tags");
return removeTag.call(this, tag, "_tagsCollection", "tags");
}
async save() {
await this.notes.add(this.note);
return this;
}
toggle(prop) {
this.note[prop] = !this.note[prop];
return this.save();
_toggle(prop) {
return this._notes.add({ id: this._note.id, [prop]: !this._note[prop] });
}
favorite() {
return this.toggle("favorite");
return this._toggle("favorite");
}
pin() {
return this.toggle("pinned");
return this._toggle("pinned");
}
async lock(password) {
let delta = await this.delta();
if (delta) {
delta = await this.notes.collection.indexer.encrypt(
delta = await this._notes._collection.indexer.encrypt(
password,
JSON.stringify(delta)
);
await this.notes.deltaStorage.write(this.note.content.delta, delta);
await this._notes._deltaStorage.write(this._note.content.delta, delta);
}
this.note.content = await this.notes.collection.indexer.encrypt(
const note = { ...this._note };
note.content = await this._notes._collection.indexer.encrypt(
password,
JSON.stringify(this.note.content)
JSON.stringify(this._note.content)
);
this.note.locked = true;
return await this.notes.collection.addItem(this.note);
note.locked = true;
return await this._notes._collection.addItem(note);
}
async unlock(password, perm = false) {
let decrypted = JSON.parse(
await this.notes.collection.indexer.decrypt(password, this.note.content)
await this._notes._collection.indexer.decrypt(
password,
this._note.content
)
);
let delta = JSON.parse(
await this.notes.collection.indexer.decrypt(password, await this.delta())
await this._notes._collection.indexer.decrypt(
password,
await this.delta()
)
);
if (perm) {
this.note.locked = false;
this.note.content = decrypted;
await this.notes.collection.addItem(this.note);
await this.notes.deltaStorage.write(this.note.content.delta, delta);
const note = { ...this._note, locked: false, content: decrypted };
note.locked = false;
note.content = decrypted;
await this._notes._collection.addItem(note);
await this._notes._deltaStorage.write(note.content.delta, delta);
}
return {
...this.note,
...this._note,
content: { ...decrypted, delta }
};
}
}
async function addTag(tag, collection, array) {
if (this.note[array].indexOf(tag) > -1)
if (this._note[array].indexOf(tag) > -1)
throw new Error("Cannot add a duplicate tag.");
this.note[array].push(tag);
await this.notes[collection].add(tag);
await this.notes.collection.addItem(this.note);
this._note[array].push(tag);
await this._notes[collection].add(tag);
await this._notes._collection.addItem(this._note);
}
async function removeTag(tag, collection, array) {
if (this.note[array].indexOf(tag) <= -1)
if (this._note[array].indexOf(tag) <= -1)
throw new Error("This note is not tagged by the specified tag.");
this.note[array].splice(this.note[array].indexOf(tag), 1);
await this.notes[collection].remove(tag);
await this.notes.collection.addItem(this.note);
this._note[array].splice(this._note[array].indexOf(tag), 1);
await this._notes[collection].remove(tag);
await this._notes._collection.addItem(this._note);
}

View File

@@ -8,34 +8,34 @@ export default class Notebook {
* @param {Object} notebook
*/
constructor(notebooks, notebook) {
this.notebook = notebook;
this.notebooks = notebooks;
this._notebook = notebook;
this._notebooks = notebooks;
}
get title() {
return this.notebook.title;
return this._notebook.title;
}
get data() {
return this.notebook;
return this._notebook;
}
get topics() {
return new Topics(this.notebooks, this.notebooks.notes, this.notebook.id);
return new Topics(this._notebooks, this._notebook.id);
}
toggle(prop) {
return this.notebooks.add({
id: this.notebook.id,
[prop]: !this.notebook[prop]
_toggle(prop) {
return this._notebooks.add({
id: this._notebook.id,
[prop]: !this._notebook[prop]
});
}
pin() {
return this.toggle("pinned");
return this._toggle("pinned");
}
favorite() {
return this.toggle("favorite");
return this._toggle("favorite");
}
}

View File

@@ -7,72 +7,82 @@ export default class Topic {
* @param {Object} topic
*/
constructor(topics, topic) {
this.topic = topic;
this.topics = topics;
this.transactionOpen = false;
this._topic = topic;
this._topics = topics;
this._transactionOpen = false;
}
get totalNotes() {
return this._topic.totalNotes;
}
transaction(ops, saveAfter = true) {
this.transactionOpen = true;
this._transactionOpen = true;
ops().then(() => {
this.transactionOpen = false;
this._transactionOpen = false;
});
if (!saveAfter) return this;
return this.save();
return this._save();
}
has(noteId) {
return this.topic.notes.findIndex(n => n === noteId) > -1;
return this._topic.notes.findIndex(n => n === noteId) > -1;
}
async add(...noteIds) {
const topic = { ...this._topic };
for (let noteId of noteIds) {
let note = this.topics.notes.note(noteId);
if (this.has(noteId) || !note) return this;
this.topic.notes.push(noteId);
let note = this._topics._notebooks._notes.note(noteId);
if (this.has(noteId) || !note) continue;
topic.notes.push(noteId);
if (note.notebook && note.notebook.id && note.notebook.topic) {
if (
note.notebook.id === this.topics.notebookId &&
note.notebook.topic === this.topic.title
note.notebook.id === this._topics.notebookId &&
note.notebook.topic === topic.title
)
return this;
await this.topics.notebooks
await this._topics._notebooks
.topics(note.notebook.id)
.topic(note.notebook.topic)
.delete(note.id);
}
await this.topics.notes.add({
await this._topics._notebooks._notes.add({
id: noteId,
notebook: { id: this.topics.notebookId, topic: this.topic.title }
notebook: { id: this._topics._notebookId, topic: topic.title }
});
topic.totalNotes++;
}
this.topic.totalNotes++;
return await this.save();
return await this._save(topic);
}
async delete(...noteIds) {
const topic = { ...this._topic };
for (let noteId of noteIds) {
if (!this.has(noteId)) return this;
let index = this.topic.notes.findIndex(n => n === noteId);
this.topic.notes.splice(index, 1);
await this.topics.notes.add({
let index = topic.notes.findIndex(n => n === noteId);
topic.notes.splice(index, 1);
await this._topics._notebooks._notes.add({
id: noteId,
notebook: {}
});
topic.totalNotes--;
}
this.topic.totalNotes--;
return await this.save();
return await this._save(topic);
}
async save() {
if (this.transactionOpen) return this;
await this.topics.add(this.topic);
async _save(topic) {
if (this._transactionOpen) return this;
await this._topics.add(topic);
return this;
}
get all() {
return this.topic.notes.map(note => this.topics.notes.note(note).note);
return this._topic.notes
.map(note => {
let fullNote = this._topics._notebooks._notes.note(note);
if (fullNote) return fullNote.data;
})
.filter(v => v);
}
}