many small fixes from Intellij analysis

This commit is contained in:
zadam 2023-05-05 23:17:23 +02:00
parent 0af6f91d21
commit 6dfc72c065
41 changed files with 73 additions and 83 deletions

View File

@ -92,6 +92,7 @@ module.exports = {
renderMathInElement: true, renderMathInElement: true,
// \src\public\app\widgets\type_widgets\editable_text.js // \src\public\app\widgets\type_widgets\editable_text.js
BalloonEditor: true, BalloonEditor: true,
FancytreeNode: true,
CKEditorInspector: true, CKEditorInspector: true,
// \src\public\app\widgets\type_widgets\editable_code.js // \src\public\app\widgets\type_widgets\editable_code.js
CodeMirror: true, CodeMirror: true,

View File

@ -189,7 +189,7 @@ class AbstractBeccaEntity {
* We're using the unencrypted blob for the hash calculation, because otherwise the random IV would * We're using the unencrypted blob for the hash calculation, because otherwise the random IV would
* cause every content blob to be unique which would balloon the database size (esp. with revisioning). * cause every content blob to be unique which would balloon the database size (esp. with revisioning).
* This has minor security implications (it's easy to infer that given content is shared between different * This has minor security implications (it's easy to infer that given content is shared between different
* notes/attachments, but the trade-off comes out clearly positive. * notes/attachments, but the trade-off comes out clearly positive).
*/ */
newBlobId = utils.hashedBlobId(unencryptedContentForHashCalculation); newBlobId = utils.hashedBlobId(unencryptedContentForHashCalculation);
blobNeedsInsert = !sql.getValue('SELECT 1 FROM blobs WHERE blobId = ?', [newBlobId]); blobNeedsInsert = !sql.getValue('SELECT 1 FROM blobs WHERE blobId = ?', [newBlobId]);
@ -228,7 +228,10 @@ class AbstractBeccaEntity {
return newBlobId; return newBlobId;
} }
/** @protected */ /**
* @protected
* @returns {string|Buffer}
*/
_getContent() { _getContent() {
const row = sql.getRow(`SELECT content FROM blobs WHERE blobId = ?`, [this.blobId]); const row = sql.getRow(`SELECT content FROM blobs WHERE blobId = ?`, [this.blobId]);

View File

@ -86,7 +86,7 @@ class BAttachment extends AbstractBeccaEntity {
|| protectedSessionService.isProtectedSessionAvailable() || protectedSessionService.isProtectedSessionAvailable()
} }
/** @returns {*} */ /** @returns {string|Buffer} */
getContent() { getContent() {
return this._getContent(); return this._getContent();
} }

View File

@ -207,7 +207,7 @@ class BNote extends AbstractBeccaEntity {
* - but to the user note content and title changes are one and the same - single dateModified (so all changes must go through Note and content is not a separate entity) * - but to the user note content and title changes are one and the same - single dateModified (so all changes must go through Note and content is not a separate entity)
*/ */
/** @returns {*} */ /** @returns {string|Buffer} */
getContent() { getContent() {
return this._getContent(); return this._getContent();
} }
@ -965,7 +965,7 @@ class BNote extends AbstractBeccaEntity {
}; };
} }
/** @returns {String[]} - includes the subtree root note as well */ /** @returns {string[]} - includes the subtree root note as well */
getSubtreeNoteIds({includeArchived = true, includeHidden = false, resolveSearch = false} = {}) { getSubtreeNoteIds({includeArchived = true, includeHidden = false, resolveSearch = false} = {}) {
return this.getSubtree({includeArchived, includeHidden, resolveSearch}) return this.getSubtree({includeArchived, includeHidden, resolveSearch})
.notes .notes
@ -1157,13 +1157,10 @@ class BNote extends AbstractBeccaEntity {
} }
const parentNotes = this.getParentNotes(); const parentNotes = this.getParentNotes();
let notePaths = [];
if (parentNotes.length === 1) { // optimization for most common case const notePaths = parentNotes.length === 1
notePaths = parentNotes[0].getAllNotePaths(); ? parentNotes[0].getAllNotePaths() // optimization for most common case
} else { : parentNotes.flatMap(parentNote => parentNote.getAllNotePaths());
notePaths = parentNotes.flatMap(parentNote => parentNote.getAllNotePaths());
}
for (const notePath of notePaths) { for (const notePath of notePaths) {
notePath.push(this.noteId); notePath.push(this.noteId);
@ -1514,10 +1511,10 @@ class BNote extends AbstractBeccaEntity {
/** /**
* (Soft) delete a note and all its descendants. * (Soft) delete a note and all its descendants.
* *
* @param {string} [deleteId] - optional delete identified * @param {string} [deleteId=null] - optional delete identified
* @param {TaskContext} [taskContext] * @param {TaskContext} [taskContext]
*/ */
deleteNote(deleteId, taskContext) { deleteNote(deleteId = null, taskContext = null) {
if (this.isDeleted) { if (this.isDeleted) {
return; return;
} }

View File

@ -80,7 +80,7 @@ class BNoteRevision extends AbstractBeccaEntity {
* This is the same approach as is used for Note's content. * This is the same approach as is used for Note's content.
*/ */
/** @returns {*} */ /** @returns {string|Buffer} */
getContent() { getContent() {
return this._getContent(); return this._getContent();
} }

View File

@ -47,7 +47,7 @@ export default class MainTreeExecutors extends Component {
} }
const parentNotePath = treeService.getNotePath(node.getParent()); const parentNotePath = treeService.getNotePath(node.getParent());
const isProtected = await treeService.getParentProtectedStatus(node); const isProtected = treeService.getParentProtectedStatus(node);
if (node.data.noteId === 'root' || node.data.noteId === hoistedNoteService.getHoistedNoteId()) { if (node.data.noteId === 'root' || node.data.noteId === hoistedNoteService.getHoistedNoteId()) {
return; return;

View File

@ -152,7 +152,7 @@ class NoteContext extends Component {
return resolvedNotePath; return resolvedNotePath;
} }
/** @property {FNote} */ /** @returns {FNote} */
get note() { get note() {
if (!this.noteId || !(this.noteId in froca.notes)) { if (!this.noteId || !(this.noteId in froca.notes)) {
return null; return null;
@ -161,7 +161,7 @@ class NoteContext extends Component {
return froca.notes[this.noteId]; return froca.notes[this.noteId];
} }
/** @property {string[]} */ /** @returns {string[]} */
get notePathArray() { get notePathArray() {
return this.notePath ? this.notePath.split('/') : []; return this.notePath ? this.notePath.split('/') : [];
} }

View File

@ -14,6 +14,8 @@ export default class TabManager extends Component {
constructor() { constructor() {
super(); super();
/** @property {NoteContext[]} */
this.children = [];
this.mutex = new Mutex(); this.mutex = new Mutex();
this.activeNtxId = null; this.activeNtxId = null;
@ -38,7 +40,7 @@ export default class TabManager extends Component {
appContext.addBeforeUnloadListener(this); appContext.addBeforeUnloadListener(this);
} }
/** @type {NoteContext[]} */ /** @returns {NoteContext[]} */
get noteContexts() { get noteContexts() {
return this.children; return this.children;
} }

View File

@ -358,13 +358,10 @@ class FNote {
} }
const parentNotes = this.getParentNotes(); const parentNotes = this.getParentNotes();
let notePaths = [];
if (parentNotes.length === 1) { // optimization for most common case const notePaths = parentNotes.length === 1
notePaths = parentNotes[0].getAllNotePaths(); ? parentNotes[0].getAllNotePaths() // optimization for most common case
} else { : parentNotes.flatMap(parentNote => parentNote.getAllNotePaths());
notePaths = parentNotes.flatMap(parentNote => parentNote.getAllNotePaths());
}
for (const notePath of notePaths) { for (const notePath of notePaths) {
notePath.push(this.noteId); notePath.push(this.noteId);

View File

@ -108,7 +108,7 @@ export default class TreeContextMenu {
} }
else if (command === "insertNoteAfter") { else if (command === "insertNoteAfter") {
const parentNotePath = treeService.getNotePath(this.node.getParent()); const parentNotePath = treeService.getNotePath(this.node.getParent());
const isProtected = await treeService.getParentProtectedStatus(this.node); const isProtected = treeService.getParentProtectedStatus(this.node);
noteCreateService.createNote(parentNotePath, { noteCreateService.createNote(parentNotePath, {
target: 'after', target: 'after',

View File

@ -41,7 +41,7 @@ class WidgetsByParent {
add(widget) { add(widget) {
if (!widget.parentWidget) { if (!widget.parentWidget) {
console.log(`Custom widget does not have mandatory 'getParent()' method defined`); console.log(`Custom widget does not have mandatory 'parentWidget' property defined`);
return; return;
} }

View File

@ -9,15 +9,15 @@
* @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ * @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
* @param {Function} func to wrap * @param {Function} func to wrap
* @param {Number} waitMs in ms (`100`) * @param {Number} waitMs in ms (`100`)
* @param {Boolean} immediate whether to execute at the beginning (`false`) * @param {Boolean} [immediate=false] whether to execute at the beginning (`false`)
* @api public * @api public
*/ */
function debounce(func, waitMs, immediate) { function debounce(func, waitMs, immediate = false) {
var timeout, args, context, timestamp, result; let timeout, args, context, timestamp, result;
if (null == waitMs) waitMs = 100; if (null == waitMs) waitMs = 100;
function later() { function later() {
var last = Date.now() - timestamp; const last = Date.now() - timestamp;
if (last < waitMs && last >= 0) { if (last < waitMs && last >= 0) {
timeout = setTimeout(later, waitMs - last); timeout = setTimeout(later, waitMs - last);
@ -30,11 +30,11 @@ function debounce(func, waitMs, immediate) {
} }
} }
var debounced = function(){ const debounced = function () {
context = this; context = this;
args = arguments; args = arguments;
timestamp = Date.now(); timestamp = Date.now();
var callNow = immediate && !timeout; const callNow = immediate && !timeout;
if (!timeout) timeout = setTimeout(later, waitMs); if (!timeout) timeout = setTimeout(later, waitMs);
if (callNow) { if (callNow) {
result = func.apply(context, args); result = func.apply(context, args);

View File

@ -5,6 +5,7 @@ import options from "./options.js";
import noteAttributeCache from "./note_attribute_cache.js"; import noteAttributeCache from "./note_attribute_cache.js";
import FBranch from "../entities/fbranch.js"; import FBranch from "../entities/fbranch.js";
import FAttribute from "../entities/fattribute.js"; import FAttribute from "../entities/fattribute.js";
import FAttachment from "../entities/fattachment.js";
async function processEntityChanges(entityChanges) { async function processEntityChanges(entityChanges) {
const loadResults = new LoadResults(entityChanges); const loadResults = new LoadResults(entityChanges);

View File

@ -322,7 +322,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance. * See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
* *
* @method * @method
* @returns {Promise<CKEditor>} instance of CKEditor * @returns {Promise<BalloonEditor>} instance of CKEditor
*/ */
this.getActiveContextTextEditor = () => appContext.tabManager.getActiveContext()?.getTextEditor(); this.getActiveContextTextEditor = () => appContext.tabManager.getActiveContext()?.getTextEditor();

View File

@ -79,7 +79,7 @@ async function openExternally(type, entityId, mime) {
if (res) { if (res) {
// fallback in case there's no default application for this file // fallback in case there's no default application for this file
window.open(getFileUrl(type, entityId), { url: true }); window.open(getFileUrl(type, entityId));
} }
} }
else { else {

View File

@ -18,7 +18,7 @@ async function resolveNotePath(notePath, hoistedNoteId = 'root') {
* notePath as possible. Part of the path might not be valid because of note moving (which causes * notePath as possible. Part of the path might not be valid because of note moving (which causes
* path change) or other corruption, in that case this will try to get some other valid path to the correct note. * path change) or other corruption, in that case this will try to get some other valid path to the correct note.
* *
* @returns {string[]} * @returns {Promise<string[]>}
*/ */
async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logErrors = true) { async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logErrors = true) {
utils.assertArguments(notePath); utils.assertArguments(notePath);
@ -129,7 +129,7 @@ ws.subscribeToMessages(message => {
}); });
function getParentProtectedStatus(node) { function getParentProtectedStatus(node) {
return hoistedNoteService.isHoistedNode(node) ? 0 : node.getParent().data.isProtected; return hoistedNoteService.isHoistedNode(node) ? false : node.getParent().data.isProtected;
} }
function getNoteIdFromNotePath(notePath) { function getNoteIdFromNotePath(notePath) {

View File

@ -399,10 +399,10 @@ function escapeRegExp(str) {
} }
function areObjectsEqual () { function areObjectsEqual () {
var i, l, leftChain, rightChain; let i, l, leftChain, rightChain;
function compare2Objects (x, y) { function compare2Objects (x, y) {
var p; let p;
// remember that NaN === NaN returns false // remember that NaN === NaN returns false
// and isNaN(undefined) returns true // and isNaN(undefined) returns true

View File

@ -321,9 +321,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget {
parseAttributes() { parseAttributes() {
try { try {
const attrs = attributesParser.lexAndParse(this.getPreprocessedData()); return attributesParser.lexAndParse(this.getPreprocessedData());
return attrs;
} }
catch (e) { catch (e) {
this.$errors.text(e.message).slideDown(); this.$errors.text(e.message).slideDown();

View File

@ -27,7 +27,7 @@ export default class BookmarkSwitchWidget extends SwitchWidget {
} }
} }
refreshWithNote(note) { async refreshWithNote(note) {
const isBookmarked = !!note.getParentBranches().find(b => b.parentNoteId === '_lbBookmarks'); const isBookmarked = !!note.getParentBranches().find(b => b.parentNoteId === '_lbBookmarks');
this.$switchOn.toggle(!isBookmarked); this.$switchOn.toggle(!isBookmarked);

View File

@ -90,7 +90,7 @@ export default class NoteActionsWidget extends NoteContextAwareWidget {
}); });
} }
refreshWithNote(note) { async refreshWithNote(note) {
this.$convertNoteIntoAttachmentButton.toggle(note.isEligibleForConversionToAttachment()); this.$convertNoteIntoAttachmentButton.toggle(note.isEligibleForConversionToAttachment());
this.toggleDisabled(this.$findInTextButton, ['text', 'code', 'book', 'search'].includes(note.type)); this.toggleDisabled(this.$findInTextButton, ['text', 'code', 'book', 'search'].includes(note.type));

View File

@ -34,7 +34,7 @@ export default class ConfirmDialog extends BasicWidget {
super(); super();
this.resolve = null; this.resolve = null;
this.$originallyFocused = null; // element focused before the dialog was opened, so we can return to it afterwards this.$originallyFocused = null; // element focused before the dialog was opened, so we can return to it afterward
} }
doRender() { doRender() {

View File

@ -27,7 +27,7 @@ export default class InfoDialog extends BasicWidget {
super(); super();
this.resolve = null; this.resolve = null;
this.$originallyFocused = null; // element focused before the dialog was opened, so we can return to it afterwards this.$originallyFocused = null; // element focused before the dialog was opened, so we can return to it afterward
} }
doRender() { doRender() {

View File

@ -46,7 +46,7 @@ export default class NoteTypeChooserDialog extends BasicWidget {
super(props); super(props);
this.resolve = null; this.resolve = null;
this.$originalFocused = null; // element focused before the dialog was opened, so we can return to it afterwards this.$originalFocused = null; // element focused before the dialog was opened, so we can return to it afterward
this.$originalDialog = null; this.$originalDialog = null;
} }

View File

@ -68,7 +68,7 @@ export default class CodeButtonsWidget extends NoteContextAwareWidget {
super.doRender(); super.doRender();
} }
refreshWithNote(note) { async refreshWithNote(note) {
this.$executeButton.toggle( this.$executeButton.toggle(
note.mime.startsWith('application/javascript') note.mime.startsWith('application/javascript')
|| note.mime === 'text/x-sqlite;schema=trilium' || note.mime === 'text/x-sqlite;schema=trilium'

View File

@ -1,6 +1,5 @@
import libraryLoader from "../services/library_loader.js"; import libraryLoader from "../services/library_loader.js";
import NoteContextAwareWidget from "./note_context_aware_widget.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js";
import froca from "../services/froca.js";
const TPL = `<div class="mermaid-widget"> const TPL = `<div class="mermaid-widget">
<style> <style>

View File

@ -78,7 +78,7 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
.width($parent.width()); .width($parent.width());
} }
async refreshWithNote() { async refreshWithNote(note) {
this.$widget.show(); this.$widget.show();
this.css = { this.css = {

View File

@ -1424,11 +1424,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
const parentNote = froca.getNoteFromCache(node.getParent().data.noteId); const parentNote = froca.getNoteFromCache(node.getParent().data.noteId);
if (parentNote && parentNote.hasLabel('sorted')) { return !parentNote?.hasLabel('sorted');
return false;
}
return true;
} }
moveNoteUpCommand({node}) { moveNoteUpCommand({node}) {

View File

@ -20,7 +20,7 @@ export default class ProtectedNoteSwitchWidget extends SwitchWidget {
protectedSessionService.protectNote(this.noteId, false, false) protectedSessionService.protectNote(this.noteId, false, false)
} }
refreshWithNote(note) { async refreshWithNote(note) {
this.$switchOn.toggle(!note.isProtected); this.$switchOn.toggle(!note.isProtected);
this.$switchOff.toggle(!!note.isProtected); this.$switchOff.toggle(!!note.isProtected);
} }

View File

@ -75,14 +75,6 @@ export default class OwnedAttributeListWidget extends NoteContextAwareWidget {
await this.attributeEditorWidget.updateAttributeList(attributes); await this.attributeEditorWidget.updateAttributeList(attributes);
} }
entitiesReloadedEvent({loadResults}) {
if (loadResults.getAttributes(this.componentId).find(attr => attributeService.isAffecting(attr, this.note))) {
this.refreshWithNote(this.note, true);
this.getTitle(this.note);
}
}
focus() { focus() {
this.attributeEditorWidget.focus(); this.attributeEditorWidget.focus();
} }

View File

@ -60,7 +60,7 @@ export default class SimilarNotesWidget extends NoteContextAwareWidget {
this.$similarNotesWrapper = this.$widget.find(".similar-notes-wrapper"); this.$similarNotesWrapper = this.$widget.find(".similar-notes-wrapper");
} }
async refreshWithNote() { async refreshWithNote(note) {
// remember which title was when we found the similar notes // remember which title was when we found the similar notes
this.title = this.note.title; this.title = this.note.title;

View File

@ -517,7 +517,7 @@ export default class TabRowWidget extends BasicWidget {
draggabilly.on('dragEnd', _ => { draggabilly.on('dragEnd', _ => {
this.isDragging = false; this.isDragging = false;
const finalTranslateX = parseFloat(tabEl.style.left, 10); const finalTranslateX = parseFloat(tabEl.style.left);
tabEl.style.transform = `translate3d(0, 0, 0)`; tabEl.style.transform = `translate3d(0, 0, 0)`;
// Animate dragged tab back into its place // Animate dragged tab back into its place
@ -617,7 +617,10 @@ export default class TabRowWidget extends BasicWidget {
this.updateTab($tab, noteContext); this.updateTab($tab, noteContext);
} }
/** @param {NoteContext} noteContext */ /**
* @param {jQuery} $tab
* @param {NoteContext} noteContext
*/
async updateTab($tab, noteContext) { async updateTab($tab, noteContext) {
if (!$tab.length) { if (!$tab.length) {
return; return;

View File

@ -106,7 +106,7 @@ export default class TocWidget extends RightPanelWidget {
/** /**
* Builds a jquery table of contents. * Builds a jquery table of contents.
* *
* @param {String} html Note's html content * @param {string} html Note's html content
* @returns {$toc: jQuery, headingCount: integer} ordered list table of headings, nested by heading level * @returns {$toc: jQuery, headingCount: integer} ordered list table of headings, nested by heading level
* with an onclick event that will cause the document to scroll to * with an onclick event that will cause the document to scroll to
* the desired position. * the desired position.

View File

@ -1,7 +1,6 @@
import libraryLoader from "../../services/library_loader.js"; import libraryLoader from "../../services/library_loader.js";
import TypeWidget from "./type_widget.js"; import TypeWidget from "./type_widget.js";
import utils from '../../services/utils.js'; import utils from '../../services/utils.js';
import froca from "../../services/froca.js";
import debounce from "../../services/debounce.js"; import debounce from "../../services/debounce.js";
const {sleep} = utils; const {sleep} = utils;

View File

@ -1,4 +1,3 @@
import froca from "../../services/froca.js";
import AbstractTextTypeWidget from "./abstract_text_type_widget.js"; import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
import treeService from "../../services/tree.js"; import treeService from "../../services/tree.js";
import libraryLoader from "../../services/library_loader.js"; import libraryLoader from "../../services/library_loader.js";

View File

@ -24,8 +24,6 @@ export default class WatchedFileUpdateStatusWidget extends NoteContextAwareWidge
isEnabled() { isEnabled() {
const { entityType, entityId } = this.getEntity(); const { entityType, entityId } = this.getEntity();
console.log(entityType, entityId);
return super.isEnabled() && !!fileWatcher.getFileModificationStatus(entityType, entityId); return super.isEnabled() && !!fileWatcher.getFileModificationStatus(entityType, entityId);
} }
@ -56,7 +54,7 @@ export default class WatchedFileUpdateStatusWidget extends NoteContextAwareWidge
}); });
} }
refreshWithNote(note) { async refreshWithNote(note) {
const { entityType, entityId } = this.getEntity(); const { entityType, entityId } = this.getEntity();
const status = fileWatcher.getFileModificationStatus(entityType, entityId); const status = fileWatcher.getFileModificationStatus(entityType, entityId);

View File

@ -26,7 +26,6 @@ function getNoteRevisions(req) {
} }
function getNoteRevision(req) { function getNoteRevision(req) {
// FIXME
const noteRevision = becca.getNoteRevision(req.params.noteRevisionId); const noteRevision = becca.getNoteRevision(req.params.noteRevisionId);
if (noteRevision.type === 'file') { if (noteRevision.type === 'file') {

View File

@ -51,13 +51,16 @@ function encrypt(key, plainText) {
return encryptedDataWithIv.toString('base64'); return encryptedDataWithIv.toString('base64');
} }
/**
* @returns {Buffer|false|null}
*/
function decrypt(key, cipherText) { function decrypt(key, cipherText) {
if (cipherText === null) { if (cipherText === null) {
return null; return null;
} }
if (!key) { if (!key) {
return "[protected]"; return Buffer.from("[protected]");
} }
try { try {
@ -103,17 +106,13 @@ function decryptString(dataKey, cipherText) {
if (buffer === null) { if (buffer === null) {
return null; return null;
} } else if (buffer === false) {
const str = buffer.toString('utf-8');
if (str === 'false') {
log.error(`Could not decrypt string. Buffer: ${buffer}`); log.error(`Could not decrypt string. Buffer: ${buffer}`);
throw new Error("Could not decrypt string."); throw new Error("Could not decrypt string.");
} }
return str; return buffer.toString('UTF-8');
} }
module.exports = { module.exports = {

View File

@ -65,7 +65,7 @@ function importCodeNote(taskContext, file, parentNote) {
const detectedMime = mimeService.getMime(file.originalname) || file.mimetype; const detectedMime = mimeService.getMime(file.originalname) || file.mimetype;
const mime = mimeService.normalizeMimeType(detectedMime); const mime = mimeService.normalizeMimeType(detectedMime);
const {note} = noteService.createNewNote({ const { note } = noteService.createNewNote({
parentNoteId: parentNote.noteId, parentNoteId: parentNote.noteId,
title, title,
content, content,

View File

@ -369,6 +369,10 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
return content; return content;
} }
/**
* @param {string} filePath
* @param {Buffer} content
*/
function saveNote(filePath, content) { function saveNote(filePath, content) {
const {parentNoteMeta, noteMeta, attachmentMeta} = getMeta(filePath); const {parentNoteMeta, noteMeta, attachmentMeta} = getMeta(filePath);
@ -566,6 +570,7 @@ function streamToBuffer(stream) {
return new Promise((res, rej) => stream.on('end', () => res(Buffer.concat(chunks)))); return new Promise((res, rej) => stream.on('end', () => res(Buffer.concat(chunks))));
} }
/** @returns {Buffer} */
function readContent(zipfile, entry) { function readContent(zipfile, entry) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
zipfile.openReadStream(entry, function(err, readStream) { zipfile.openReadStream(entry, function(err, readStream) {

View File

@ -1,6 +1,7 @@
const becca = require('../becca/becca'); const becca = require('../becca/becca');
const sql = require("./sql"); const sql = require("./sql");
/** @returns {string|null} */
function getOptionOrNull(name) { function getOptionOrNull(name) {
let option; let option;
@ -14,11 +15,12 @@ function getOptionOrNull(name) {
return option ? option.value : null; return option ? option.value : null;
} }
/** @returns {string} */
function getOption(name) { function getOption(name) {
const val = getOptionOrNull(name); const val = getOptionOrNull(name);
if (val === null) { if (val === null) {
throw new Error(`Option "${name}" doesn't exist`); throw new Error(`Option '${name}' doesn't exist`);
} }
return val; return val;

View File

@ -177,7 +177,7 @@ function register(router) {
res.send(note.getContent()); res.send(note.getContent());
}); });
// :filename is not used by trilium, but instead used for "save as" to assign a human readable filename // :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename
router.get('/share/api/images/:noteId/:filename', (req, res, next) => { router.get('/share/api/images/:noteId/:filename', (req, res, next) => {
shacaLoader.ensureLoad(); shacaLoader.ensureLoad();