diff --git a/spec/search/search.spec.ts b/spec/search/search.spec.ts index 45c0f3acd..f13da498a 100644 --- a/spec/search/search.spec.ts +++ b/spec/search/search.spec.ts @@ -4,7 +4,6 @@ import BBranch from "../../src/becca/entities/bbranch.js"; import SearchContext from "../../src/services/search/search_context.js"; import dateUtils from "../../src/services/date_utils.js"; import becca from "../../src/becca/becca.js"; -// const { NoteBuilder, findNoteByTitle, note } = require('./becca_mocking'); import becca_mocking from "./becca_mocking.js"; describe('Search', () => { diff --git a/src/becca/becca_loader.ts b/src/becca/becca_loader.ts index dd751bf9a..1bfab31da 100644 --- a/src/becca/becca_loader.ts +++ b/src/becca/becca_loader.ts @@ -14,13 +14,15 @@ import cls from "../services/cls.js"; import entityConstructor from "../becca/entity_constructor.js"; import { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow } from './entities/rows'; import AbstractBeccaEntity from "./entities/abstract_becca_entity.js"; +import options_init from "../services/options_init.js"; +import ws from "../services/ws.js"; const beccaLoaded = new Promise((res, rej) => { sqlInit.dbReady.then(() => { cls.init(() => { load(); - require('../services/options_init').initStartupOptions(); + options_init.initStartupOptions(); res(); }); @@ -73,7 +75,7 @@ function load() { function reload(reason: string) { load(); - require('../services/ws').reloadFrontend(reason || "becca reloaded"); + ws.reloadFrontend(reason || "becca reloaded"); } eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED], ({ entityName, entityRow }) => { diff --git a/src/becca/entities/battachment.ts b/src/becca/entities/battachment.ts index 1fdbd1cb4..bef20acea 100644 --- a/src/becca/entities/battachment.ts +++ b/src/becca/entities/battachment.ts @@ -9,6 +9,7 @@ import log from "../../services/log.js"; import { AttachmentRow } from './rows'; import BNote from "./bnote.js"; import BBranch from "./bbranch.js"; +import noteService from "../../services/notes.js"; const attachmentRoleToNoteTypeMapping = { 'image': 'image', @@ -157,8 +158,6 @@ class BAttachment extends AbstractBeccaEntity { throw new Error(`Cannot convert protected attachment outside of protected session`); } - const noteService = require('../../services/notes'); - const { note, branch } = noteService.createNewNote({ parentNoteId: this.ownerId, title: this.title, diff --git a/src/becca/entities/bnote.ts b/src/becca/entities/bnote.ts index d0fcac1b6..e7cfc2a46 100644 --- a/src/becca/entities/bnote.ts +++ b/src/becca/entities/bnote.ts @@ -12,10 +12,14 @@ import TaskContext from "../../services/task_context.js"; import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; import eventService from "../../services/events.js"; -import { AttachmentRow, NoteRow, NoteType, RevisionRow } from './rows'; +import { AttachmentRow, AttributeType, NoteRow, NoteType, RevisionRow } from './rows'; import BBranch from "./bbranch.js"; import BAttribute from "./battribute.js"; import { NotePojo } from '../becca-interface'; +import searchService from "../../services/search/services/search.js"; +import cloningService, { CloneResponse } from "../../services/cloning.js"; +import noteService from "../../services/notes.js"; +import handlers from "../../services/handlers.js"; dayjs.extend(utc); const LABEL = 'label'; @@ -890,11 +894,9 @@ class BNote extends AbstractBeccaEntity { } try { - const searchService = require('../../services/search/services/search'); - const {searchResultNoteIds} = searchService.searchFromNote(this); - + const result = searchService.searchFromNote(this); const becca = this.becca; - return (searchResultNoteIds as string[]) // TODO: remove cast once search is converted + return (result.searchResultNoteIds) .map(resultNoteId => becca.notes[resultNoteId]) .filter(note => !!note); } @@ -1261,7 +1263,7 @@ class BNote extends AbstractBeccaEntity { * @param name - attribute name * @param value - attribute value (optional) */ - setAttribute(type: string, name: string, value?: string) { + setAttribute(type: AttributeType, name: string, value?: string) { const attributes = this.getOwnedAttributes(); const attr = attributes.find(attr => attr.type === type && attr.name === name); @@ -1274,8 +1276,6 @@ class BNote extends AbstractBeccaEntity { } } else { - const BAttribute = require('./battribute'); - new BAttribute({ noteId: this.noteId, type: type, @@ -1310,9 +1310,7 @@ class BNote extends AbstractBeccaEntity { * @param name - name of the attribute, not including the leading ~/# * @param value - value of the attribute - text for labels, target note ID for relations; optional. */ - addAttribute(type: string, name: string, value: string = "", isInheritable: boolean = false, position: number | null = null): BAttribute { - const BAttribute = require('./battribute'); - + addAttribute(type: AttributeType, name: string, value: string = "", isInheritable: boolean = false, position: number | null = null): BAttribute { return new BAttribute({ noteId: this.noteId, type: type, @@ -1351,7 +1349,7 @@ class BNote extends AbstractBeccaEntity { * @param name - attribute name * @param value - attribute value (optional) */ - toggleAttribute(type: string, enabled: boolean, name: string, value?: string) { + toggleAttribute(type: AttributeType, enabled: boolean, name: string, value?: string) { if (enabled) { this.setAttribute(type, name, value); } @@ -1423,8 +1421,6 @@ class BNote extends AbstractBeccaEntity { } searchNotesInSubtree(searchString: string) { - const searchService = require('../../services/search/services/search'); - return searchService.searchNotes(searchString) as BNote[]; } @@ -1432,12 +1428,16 @@ class BNote extends AbstractBeccaEntity { return this.searchNotesInSubtree(searchString)[0]; } - cloneTo(parentNoteId: string) { - const cloningService = require('../../services/cloning'); - + cloneTo(parentNoteId: string): CloneResponse { const branch = this.becca.getNote(parentNoteId)?.getParentBranches()[0]; + if (!branch?.branchId) { + return { + success: false, + message: "Unable to find the branch ID to clone." + }; + } - return cloningService.cloneNoteToBranch(this.noteId, branch?.branchId); + return cloningService.cloneNoteToBranch(this.noteId, branch.branchId); } isEligibleForConversionToAttachment(opts: ConvertOpts = { autoConversion: false }) { @@ -1508,7 +1508,6 @@ class BNote extends AbstractBeccaEntity { parentNote.setContent(fixedContent); - const noteService = require('../../services/notes'); noteService.asyncPostProcessContent(parentNote, fixedContent); // to mark an unused attachment for deletion this.deleteNote(); @@ -1535,7 +1534,6 @@ class BNote extends AbstractBeccaEntity { } // needs to be run before branches and attributes are deleted and thus attached relations disappear - const handlers = require('../../services/handlers'); handlers.runAttachedRelations(this, 'runOnNoteDeletion', this); taskContext.noteDeletionHandlerTriggered = true; diff --git a/src/becca/entities/rows.ts b/src/becca/entities/rows.ts index bb4c70a78..6c46bf301 100644 --- a/src/becca/entities/rows.ts +++ b/src/becca/entities/rows.ts @@ -69,7 +69,7 @@ export interface AttributeRow { noteId?: string; type: AttributeType; name: string; - position?: number; + position?: number | null; value?: string; isInheritable?: boolean; utcDateModified?: string; diff --git a/src/routes/api/search.ts b/src/routes/api/search.ts index 0c2966dad..fbfe74766 100644 --- a/src/routes/api/search.ts +++ b/src/routes/api/search.ts @@ -4,19 +4,19 @@ import { Request } from "express"; import becca from "../../becca/becca.js"; import SearchContext from "../../services/search/search_context.js"; -import searchService from "../../services/search/services/search.js"; +import searchService, { EMPTY_RESULT, SearchNoteResult } from "../../services/search/services/search.js"; import bulkActionService from "../../services/bulk_actions.js"; import cls from "../../services/cls.js"; import attributeFormatter from "../../services/attribute_formatter.js"; import ValidationError from "../../errors/validation_error.js"; import SearchResult from "../../services/search/search_result.js"; -function searchFromNote(req: Request) { +function searchFromNote(req: Request): SearchNoteResult { const note = becca.getNoteOrThrow(req.params.noteId); if (!note) { // this can be triggered from recent changes, and it's harmless to return an empty list rather than fail - return []; + return EMPTY_RESULT; } if (note.type !== 'search') { diff --git a/src/services/cloning.ts b/src/services/cloning.ts index 4e81b2666..1176ff37a 100644 --- a/src/services/cloning.ts +++ b/src/services/cloning.ts @@ -7,7 +7,7 @@ import BBranch from '../becca/entities/bbranch'; import becca from '../becca/becca'; import log from './log'; -interface CloneResponse { +export interface CloneResponse { success: boolean; message?: string; branchId?: string; @@ -53,7 +53,7 @@ function cloneNoteToParentNote(noteId: string, parentNoteId: string, prefix: str }; } -function cloneNoteToBranch(noteId: string, parentBranchId: string, prefix: string) { +function cloneNoteToBranch(noteId: string, parentBranchId: string, prefix?: string) { const parentBranch = becca.getBranch(parentBranchId); if (!parentBranch) { diff --git a/src/services/import/enex.ts b/src/services/import/enex.ts index e2ccaa78a..739b418c3 100644 --- a/src/services/import/enex.ts +++ b/src/services/import/enex.ts @@ -12,6 +12,7 @@ import sanitizeAttributeName from "../sanitize_attribute_name.js"; import TaskContext from "../task_context.js"; import BNote from "../../becca/entities/bnote.js"; import { File } from "./common"; +import { AttributeType } from "../../becca/entities/rows.js"; /** * date format is e.g. 20181121T193703Z or 2013-04-14T16:19:00.000Z (Mac evernote, see #3496) @@ -29,7 +30,7 @@ function parseDate(text: string) { } interface Attribute { - type: string; + type: AttributeType; name: string; value: string; } diff --git a/src/services/log.ts b/src/services/log.ts index 414dc27e1..9bd97a2a7 100644 --- a/src/services/log.ts +++ b/src/services/log.ts @@ -50,7 +50,7 @@ function checkDate(millisSinceMidnight: number) { return millisSinceMidnight; } -function log(str: string) { +function log(str: string | Error) { const bundleNoteId = cls.get("bundleNoteId"); if (bundleNoteId) { @@ -66,11 +66,11 @@ function log(str: string) { console.log(str); } -function info(message: string) { +function info(message: string | Error) { log(message); } -function error(message: string) { +function error(message: string | Error) { log(`ERROR: ${message}`); } diff --git a/src/services/search/services/search.ts b/src/services/search/services/search.ts index 5b289ff9d..18d70be34 100644 --- a/src/services/search/services/search.ts +++ b/src/services/search/services/search.ts @@ -18,7 +18,19 @@ import Expression from "../expressions/expression.js"; import sql from "../../sql.js"; import scriptService from "../../script.js"; -function searchFromNote(note: BNote) { +export interface SearchNoteResult { + searchResultNoteIds: string[]; + highlightedTokens: string[]; + error: string | null; +} + +export const EMPTY_RESULT: SearchNoteResult = { + searchResultNoteIds: [], + highlightedTokens: [], + error: null +}; + +function searchFromNote(note: BNote): SearchNoteResult { let searchResultNoteIds; let highlightedTokens: string[]; diff --git a/src/www.ts b/src/www.ts index c1ec2f0f3..7f0b14aa5 100644 --- a/src/www.ts +++ b/src/www.ts @@ -1,23 +1,4 @@ #!/usr/bin/env node - -// setup basic error handling even before requiring dependencies, since those can produce errors as well - -process.on('unhandledRejection', error => { - // this makes sure that stacktrace of failed promise is printed out - console.log(error); - - // but also try to log it into file - require('./services/log').info(error); -}); - -function exit() { - console.log("Caught interrupt/termination signal. Exiting."); - process.exit(0); -} - -process.on('SIGINT', exit); -process.on('SIGTERM', exit); - import app from "./app.js"; import sessionParser from "./routes/session_parser.js"; import fs from "fs"; @@ -32,6 +13,25 @@ import port from "./services/port.js"; import host from "./services/host.js"; import semver from "semver"; +// setup basic error handling even before requiring dependencies, since those can produce errors as well + +process.on('unhandledRejection', (error: Error) => { + // this makes sure that stacktrace of failed promise is printed out + console.log(error); + + // but also try to log it into file + log.info(error); +}); + +function exit() { + console.log("Caught interrupt/termination signal. Exiting."); + process.exit(0); +} + +process.on('SIGINT', exit); +process.on('SIGTERM', exit); + + if (!semver.satisfies(process.version, ">=10.5.0")) { console.error("Trilium only supports node.js 10.5 and later"); process.exit(1);