1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-02 12:47:41 +02:00

Chore: Convert CLI app class to TS

This commit is contained in:
Laurent Cozic 2024-01-20 14:29:21 +00:00
parent 6720fd1f0e
commit a8f6676fb3
34 changed files with 961 additions and 494 deletions

View File

@ -86,6 +86,7 @@ packages/lib/countable/Countable.js
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD # AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
packages/app-cli/app/LinkSelector.js packages/app-cli/app/LinkSelector.js
packages/app-cli/app/app.js
packages/app-cli/app/base-command.js packages/app-cli/app/base-command.js
packages/app-cli/app/command-apidoc.js packages/app-cli/app/command-apidoc.js
packages/app-cli/app/command-attach.js packages/app-cli/app/command-attach.js

1
.gitignore vendored
View File

@ -66,6 +66,7 @@ docs/**/*.mustache
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD # AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
packages/app-cli/app/LinkSelector.js packages/app-cli/app/LinkSelector.js
packages/app-cli/app/app.js
packages/app-cli/app/base-command.js packages/app-cli/app/base-command.js
packages/app-cli/app/command-apidoc.js packages/app-cli/app/command-apidoc.js
packages/app-cli/app/command-attach.js packages/app-cli/app/command-attach.js

View File

@ -1,469 +1,461 @@
const BaseApplication = require('@joplin/lib/BaseApplication').default; "use strict";
const { refreshFolders } = require('@joplin/lib/folders-screen-utils.js'); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
const ResourceService = require('@joplin/lib/services/ResourceService').default; function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
const BaseModel = require('@joplin/lib/BaseModel').default; return new (P || (P = Promise))(function (resolve, reject) {
const Folder = require('@joplin/lib/models/Folder').default; function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
const BaseItem = require('@joplin/lib/models/BaseItem').default; function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
const Note = require('@joplin/lib/models/Note').default; function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
const Tag = require('@joplin/lib/models/Tag').default; step((generator = generator.apply(thisArg, _arguments || [])).next());
const Setting = require('@joplin/lib/models/Setting').default; });
const { reg } = require('@joplin/lib/registry.js'); };
const { fileExtension } = require('@joplin/lib/path-utils'); Object.defineProperty(exports, "__esModule", { value: true });
const { splitCommandString } = require('@joplin/utils'); const BaseApplication_1 = require("@joplin/lib/BaseApplication");
const { splitCommandBatch } = require('@joplin/lib/string-utils'); const folders_screen_utils_js_1 = require("@joplin/lib/folders-screen-utils.js");
const { _ } = require('@joplin/lib/locale'); const ResourceService_1 = require("@joplin/lib/services/ResourceService");
const fs = require('fs-extra'); const BaseModel_1 = require("@joplin/lib/BaseModel");
const Folder_1 = require("@joplin/lib/models/Folder");
const BaseItem_1 = require("@joplin/lib/models/BaseItem");
const Note_1 = require("@joplin/lib/models/Note");
const Tag_1 = require("@joplin/lib/models/Tag");
const Setting_1 = require("@joplin/lib/models/Setting");
const registry_js_1 = require("@joplin/lib/registry.js");
const path_utils_1 = require("@joplin/lib/path-utils");
const utils_1 = require("@joplin/utils");
const locale_1 = require("@joplin/lib/locale");
const fs_extra_1 = require("fs-extra");
const RevisionService_1 = require("@joplin/lib/services/RevisionService");
const shim_1 = require("@joplin/lib/shim");
const setupCommand_1 = require("./setupCommand");
const { cliUtils } = require('./cli-utils.js'); const { cliUtils } = require('./cli-utils.js');
const Cache = require('@joplin/lib/Cache'); const Cache = require('@joplin/lib/Cache');
const RevisionService = require('@joplin/lib/services/RevisionService').default; const { splitCommandBatch } = require('@joplin/lib/string-utils');
const shim = require('@joplin/lib/shim').default; class Application extends BaseApplication_1.default {
const setupCommand = require('./setupCommand').default; constructor() {
super(...arguments);
class Application extends BaseApplication { this.commands_ = {};
constructor() { this.commandMetadata_ = null;
super(); this.activeCommand_ = null;
this.allCommandsLoaded_ = false;
this.showPromptString_ = true; this.gui_ = null;
this.commands_ = {}; this.cache_ = new Cache();
this.commandMetadata_ = null; }
this.activeCommand_ = null; gui() {
this.allCommandsLoaded_ = false; return this.gui_;
this.showStackTraces_ = false; }
this.gui_ = null; commandStdoutMaxWidth() {
this.cache_ = new Cache(); return this.gui().stdoutMaxWidth();
} }
guessTypeAndLoadItem(pattern, options = null) {
gui() { return __awaiter(this, void 0, void 0, function* () {
return this.gui_; let type = BaseModel_1.default.TYPE_NOTE;
} if (pattern.indexOf('/') === 0) {
type = BaseModel_1.default.TYPE_FOLDER;
commandStdoutMaxWidth() { pattern = pattern.substr(1);
return this.gui().stdoutMaxWidth(); }
} return this.loadItem(type, pattern, options);
});
async guessTypeAndLoadItem(pattern, options = null) { }
let type = BaseModel.TYPE_NOTE; loadItem(type, pattern, options = null) {
if (pattern.indexOf('/') === 0) { return __awaiter(this, void 0, void 0, function* () {
type = BaseModel.TYPE_FOLDER; const output = yield this.loadItems(type, pattern, options);
pattern = pattern.substr(1); if (output.length > 1) {
} // output.sort((a, b) => { return a.user_updated_time < b.user_updated_time ? +1 : -1; });
return this.loadItem(type, pattern, options); // let answers = { 0: _('[Cancel]') };
} // for (let i = 0; i < output.length; i++) {
// answers[i + 1] = output[i].title;
async loadItem(type, pattern, options = null) { // }
const output = await this.loadItems(type, pattern, options); // Not really useful with new UI?
throw new Error((0, locale_1._)('More than one item match "%s". Please narrow down your query.', pattern));
if (output.length > 1) { // let msg = _('More than one item match "%s". Please select one:', pattern);
// output.sort((a, b) => { return a.user_updated_time < b.user_updated_time ? +1 : -1; }); // const response = await cliUtils.promptMcq(msg, answers);
// if (!response) return null;
// let answers = { 0: _('[Cancel]') }; // return output[response - 1];
// for (let i = 0; i < output.length; i++) { }
// answers[i + 1] = output[i].title; else {
// } return output.length ? output[0] : null;
}
// Not really useful with new UI? });
throw new Error(_('More than one item match "%s". Please narrow down your query.', pattern)); }
loadItems(type, pattern, options = null) {
// let msg = _('More than one item match "%s". Please select one:', pattern); return __awaiter(this, void 0, void 0, function* () {
// const response = await cliUtils.promptMcq(msg, answers); if (type === 'folderOrNote') {
// if (!response) return null; const folders = yield this.loadItems(BaseModel_1.default.TYPE_FOLDER, pattern, options);
if (folders.length)
// return output[response - 1]; return folders;
} else { return yield this.loadItems(BaseModel_1.default.TYPE_NOTE, pattern, options);
return output.length ? output[0] : null; }
} pattern = pattern ? pattern.toString() : '';
} if (type === BaseModel_1.default.TYPE_FOLDER && (pattern === Folder_1.default.conflictFolderTitle() || pattern === Folder_1.default.conflictFolderId()))
return [Folder_1.default.conflictFolder()];
async loadItems(type, pattern, options = null) { if (!options)
if (type === 'folderOrNote') { options = {};
const folders = await this.loadItems(BaseModel.TYPE_FOLDER, pattern, options); const parent = options.parent ? options.parent : app().currentFolder();
if (folders.length) return folders; const ItemClass = BaseItem_1.default.itemClass(type);
return await this.loadItems(BaseModel.TYPE_NOTE, pattern, options); if (type === BaseModel_1.default.TYPE_NOTE && pattern.indexOf('*') >= 0) {
} // Handle it as pattern
if (!parent)
pattern = pattern ? pattern.toString() : ''; throw new Error((0, locale_1._)('No notebook selected.'));
return yield Note_1.default.previews(parent.id, { titlePattern: pattern });
if (type === BaseModel.TYPE_FOLDER && (pattern === Folder.conflictFolderTitle() || pattern === Folder.conflictFolderId())) return [Folder.conflictFolder()]; }
else {
if (!options) options = {}; // Single item
let item = null;
const parent = options.parent ? options.parent : app().currentFolder(); if (type === BaseModel_1.default.TYPE_NOTE) {
const ItemClass = BaseItem.itemClass(type); if (!parent)
throw new Error((0, locale_1._)('No notebook has been specified.'));
if (type === BaseModel.TYPE_NOTE && pattern.indexOf('*') >= 0) { item = yield ItemClass.loadFolderNoteByField(parent.id, 'title', pattern);
// Handle it as pattern }
if (!parent) throw new Error(_('No notebook selected.')); else {
return await Note.previews(parent.id, { titlePattern: pattern }); item = yield ItemClass.loadByTitle(pattern);
} else { }
// Single item if (item)
let item = null; return [item];
if (type === BaseModel.TYPE_NOTE) { item = yield ItemClass.load(pattern); // Load by id
if (!parent) throw new Error(_('No notebook has been specified.')); if (item)
item = await ItemClass.loadFolderNoteByField(parent.id, 'title', pattern); return [item];
} else { if (pattern.length >= 2) {
item = await ItemClass.loadByTitle(pattern); return yield ItemClass.loadByPartialId(pattern);
} }
if (item) return [item]; }
return [];
item = await ItemClass.load(pattern); // Load by id });
if (item) return [item]; }
setupCommand(cmd) {
if (pattern.length >= 2) { return (0, setupCommand_1.default)(cmd, (t) => this.stdout(t), () => this.store(), () => this.gui());
return await ItemClass.loadByPartialId(pattern); }
} stdout(text) {
} return this.gui().stdout(text);
}
return []; exit(code = 0) {
} const _super = Object.create(null, {
exit: { get: () => super.exit }
setupCommand(cmd) { });
return setupCommand(cmd, t => this.stdout(t), () => this.store(), () => this.gui()); return __awaiter(this, void 0, void 0, function* () {
} const doExit = () => __awaiter(this, void 0, void 0, function* () {
this.gui().exit();
stdout(text) { yield _super.exit.call(this, code);
return this.gui().stdout(text); });
} // Give it a few seconds to cancel otherwise exit anyway
shim_1.default.setTimeout(() => __awaiter(this, void 0, void 0, function* () {
async exit(code = 0) { yield doExit();
const doExit = async () => { }), 5000);
this.gui().exit(); if (yield registry_js_1.reg.syncTarget().syncStarted()) {
await super.exit(code); this.stdout((0, locale_1._)('Cancelling background synchronisation... Please wait.'));
}; const sync = yield registry_js_1.reg.syncTarget().synchronizer();
yield sync.cancel();
// Give it a few seconds to cancel otherwise exit anyway }
shim.setTimeout(async () => { yield doExit();
await doExit(); });
}, 5000); }
commands(uiType = null) {
if (await reg.syncTarget().syncStarted()) { if (!this.allCommandsLoaded_) {
this.stdout(_('Cancelling background synchronisation... Please wait.')); // eslint-disable-next-line github/array-foreach -- Old code before rule was applied
const sync = await reg.syncTarget().synchronizer(); (0, fs_extra_1.readdirSync)(__dirname).forEach(path => {
await sync.cancel(); if (path.indexOf('command-') !== 0)
} return;
if (path.endsWith('.test.js'))
await doExit(); return;
} const ext = (0, path_utils_1.fileExtension)(path);
if (ext !== 'js')
commands(uiType = null) { return;
if (!this.allCommandsLoaded_) { const CommandClass = require(`./${path}`);
// eslint-disable-next-line github/array-foreach -- Old code before rule was applied let cmd = new CommandClass();
fs.readdirSync(__dirname).forEach(path => { if (!cmd.enabled())
if (path.indexOf('command-') !== 0) return; return;
if (path.endsWith('.test.js')) return; cmd = this.setupCommand(cmd);
const ext = fileExtension(path); this.commands_[cmd.name()] = cmd;
if (ext !== 'js') return; });
this.allCommandsLoaded_ = true;
const CommandClass = require(`./${path}`); }
let cmd = new CommandClass(); if (uiType !== null) {
if (!cmd.enabled()) return; const temp = {};
cmd = this.setupCommand(cmd); for (const n in this.commands_) {
this.commands_[cmd.name()] = cmd; if (!this.commands_.hasOwnProperty(n))
}); continue;
const c = this.commands_[n];
this.allCommandsLoaded_ = true; if (!c.supportsUi(uiType))
} continue;
temp[n] = c;
if (uiType !== null) { }
const temp = []; return temp;
for (const n in this.commands_) { }
if (!this.commands_.hasOwnProperty(n)) continue; return this.commands_;
const c = this.commands_[n]; }
if (!c.supportsUi(uiType)) continue; commandNames() {
temp[n] = c; return __awaiter(this, void 0, void 0, function* () {
} const metadata = yield this.commandMetadata();
return temp; const output = [];
} for (const n in metadata) {
if (!metadata.hasOwnProperty(n))
return this.commands_; continue;
} output.push(n);
}
async commandNames() { return output;
const metadata = await this.commandMetadata(); });
const output = []; }
for (const n in metadata) { commandMetadata() {
if (!metadata.hasOwnProperty(n)) continue; return __awaiter(this, void 0, void 0, function* () {
output.push(n); if (this.commandMetadata_)
} return this.commandMetadata_;
return output; let output = yield this.cache_.getItem('metadata');
} if (output) {
this.commandMetadata_ = output;
async commandMetadata() { return Object.assign({}, this.commandMetadata_);
if (this.commandMetadata_) return this.commandMetadata_; }
const commands = this.commands();
let output = await this.cache_.getItem('metadata'); output = {};
if (output) { for (const n in commands) {
this.commandMetadata_ = output; if (!commands.hasOwnProperty(n))
return { ...this.commandMetadata_ }; continue;
} const cmd = commands[n];
output[n] = cmd.metadata();
const commands = this.commands(); }
yield this.cache_.setItem('metadata', output, 1000 * 60 * 60 * 24);
output = {}; this.commandMetadata_ = output;
for (const n in commands) { return Object.assign({}, this.commandMetadata_);
if (!commands.hasOwnProperty(n)) continue; });
const cmd = commands[n]; }
output[n] = cmd.metadata(); hasGui() {
} return this.gui() && !this.gui().isDummy();
}
await this.cache_.setItem('metadata', output, 1000 * 60 * 60 * 24); findCommandByName(name) {
if (this.commands_[name])
this.commandMetadata_ = output; return this.commands_[name];
return { ...this.commandMetadata_ }; let CommandClass = null;
} try {
CommandClass = require(`${__dirname}/command-${name}.js`);
hasGui() { }
return this.gui() && !this.gui().isDummy(); catch (error) {
} if (error.message && error.message.indexOf('Cannot find module') >= 0) {
const e = new Error((0, locale_1._)('No such command: %s', name));
findCommandByName(name) { e.type = 'notFound';
if (this.commands_[name]) return this.commands_[name]; throw e;
}
let CommandClass = null; else {
try { throw error;
CommandClass = require(`${__dirname}/command-${name}.js`); }
} catch (error) { }
if (error.message && error.message.indexOf('Cannot find module') >= 0) { let cmd = new CommandClass();
const e = new Error(_('No such command: %s', name)); cmd = this.setupCommand(cmd);
e.type = 'notFound'; this.commands_[name] = cmd;
throw e; return this.commands_[name];
} else { }
throw error; dummyGui() {
} return {
} isDummy: () => {
return true;
let cmd = new CommandClass(); },
cmd = this.setupCommand(cmd); prompt: (initialText = '', promptString = '', options = null) => {
this.commands_[name] = cmd; return cliUtils.prompt(initialText, promptString, options);
return this.commands_[name]; },
} showConsole: () => { },
maximizeConsole: () => { },
dummyGui() { stdout: (text) => {
return { // eslint-disable-next-line no-console
isDummy: () => { console.info(text);
return true; },
}, fullScreen: () => { },
prompt: (initialText = '', promptString = '', options = null) => { exit: () => { },
return cliUtils.prompt(initialText, promptString, options); showModalOverlay: () => { },
}, hideModalOverlay: () => { },
showConsole: () => {}, stdoutMaxWidth: () => {
maximizeConsole: () => {}, return 100;
stdout: text => { },
// eslint-disable-next-line no-console forceRender: () => { },
console.info(text); termSaveState: () => { },
}, termRestoreState: () => { },
fullScreen: () => {}, };
exit: () => {}, }
showModalOverlay: () => {}, execCommand(argv) {
hideModalOverlay: () => {}, return __awaiter(this, void 0, void 0, function* () {
stdoutMaxWidth: () => { if (!argv.length)
return 100; return this.execCommand(['help']);
}, // reg.logger().debug('execCommand()', argv);
forceRender: () => {}, const commandName = argv[0];
termSaveState: () => {}, this.activeCommand_ = this.findCommandByName(commandName);
termRestoreState: () => {}, let outException = null;
}; try {
} if (this.gui().isDummy() && !this.activeCommand_.supportsUi('cli'))
throw new Error((0, locale_1._)('The command "%s" is only available in GUI mode', this.activeCommand_.name()));
async execCommand(argv) { const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv);
if (!argv.length) return this.execCommand(['help']); yield this.activeCommand_.action(cmdArgs);
// reg.logger().debug('execCommand()', argv); }
const commandName = argv[0]; catch (error) {
this.activeCommand_ = this.findCommandByName(commandName); outException = error;
}
let outException = null; this.activeCommand_ = null;
try { if (outException)
if (this.gui().isDummy() && !this.activeCommand_.supportsUi('cli')) throw new Error(_('The command "%s" is only available in GUI mode', this.activeCommand_.name())); throw outException;
const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv); });
await this.activeCommand_.action(cmdArgs); }
} catch (error) { currentCommand() {
outException = error; return this.activeCommand_;
} }
this.activeCommand_ = null; loadKeymaps() {
if (outException) throw outException; return __awaiter(this, void 0, void 0, function* () {
} const defaultKeyMap = [
{ keys: [':'], type: 'function', command: 'enter_command_line_mode' },
currentCommand() { { keys: ['TAB'], type: 'function', command: 'focus_next' },
return this.activeCommand_; { keys: ['SHIFT_TAB'], type: 'function', command: 'focus_previous' },
} { keys: ['UP'], type: 'function', command: 'move_up' },
{ keys: ['DOWN'], type: 'function', command: 'move_down' },
async loadKeymaps() { { keys: ['PAGE_UP'], type: 'function', command: 'page_up' },
const defaultKeyMap = [ { keys: ['PAGE_DOWN'], type: 'function', command: 'page_down' },
{ keys: [':'], type: 'function', command: 'enter_command_line_mode' }, { keys: ['ENTER'], type: 'function', command: 'activate' },
{ keys: ['TAB'], type: 'function', command: 'focus_next' }, { keys: ['DELETE', 'BACKSPACE'], type: 'function', command: 'delete' },
{ keys: ['SHIFT_TAB'], type: 'function', command: 'focus_previous' }, { keys: ['n'], type: 'function', command: 'next_link' },
{ keys: ['UP'], type: 'function', command: 'move_up' }, { keys: ['b'], type: 'function', command: 'previous_link' },
{ keys: ['DOWN'], type: 'function', command: 'move_down' }, { keys: ['o'], type: 'function', command: 'open_link' },
{ keys: ['PAGE_UP'], type: 'function', command: 'page_up' }, { keys: [' '], type: 'prompt', command: 'todo toggle $n' },
{ keys: ['PAGE_DOWN'], type: 'function', command: 'page_down' }, { keys: ['tc'], type: 'function', command: 'toggle_console' },
{ keys: ['ENTER'], type: 'function', command: 'activate' }, { keys: ['tm'], type: 'function', command: 'toggle_metadata' },
{ keys: ['DELETE', 'BACKSPACE'], type: 'function', command: 'delete' }, { keys: ['ti'], type: 'function', command: 'toggle_ids' },
{ keys: ['n'], type: 'function', command: 'next_link' }, { keys: ['/'], type: 'prompt', command: 'search ""', cursorPosition: -2 },
{ keys: ['b'], type: 'function', command: 'previous_link' }, { keys: ['mn'], type: 'prompt', command: 'mknote ""', cursorPosition: -2 },
{ keys: ['o'], type: 'function', command: 'open_link' }, { keys: ['mt'], type: 'prompt', command: 'mktodo ""', cursorPosition: -2 },
{ keys: [' '], command: 'todo toggle $n' }, { keys: ['mb'], type: 'prompt', command: 'mkbook ""', cursorPosition: -2 },
{ keys: ['tc'], type: 'function', command: 'toggle_console' }, { keys: ['yn'], type: 'prompt', command: 'cp $n ""', cursorPosition: -2 },
{ keys: ['tm'], type: 'function', command: 'toggle_metadata' }, { keys: ['dn'], type: 'prompt', command: 'mv $n ""', cursorPosition: -2 },
{ keys: ['ti'], type: 'function', command: 'toggle_ids' }, ];
{ keys: ['/'], type: 'prompt', command: 'search ""', cursorPosition: -2 }, // Filter the keymap item by command so that items in keymap.json can override
{ keys: ['mn'], type: 'prompt', command: 'mknote ""', cursorPosition: -2 }, // the default ones.
{ keys: ['mt'], type: 'prompt', command: 'mktodo ""', cursorPosition: -2 }, const itemsByCommand = {};
{ keys: ['mb'], type: 'prompt', command: 'mkbook ""', cursorPosition: -2 }, for (let i = 0; i < defaultKeyMap.length; i++) {
{ keys: ['yn'], type: 'prompt', command: 'cp $n ""', cursorPosition: -2 }, itemsByCommand[defaultKeyMap[i].command] = defaultKeyMap[i];
{ keys: ['dn'], type: 'prompt', command: 'mv $n ""', cursorPosition: -2 }, }
]; const filePath = `${Setting_1.default.value('profileDir')}/keymap.json`;
if (yield (0, fs_extra_1.pathExists)(filePath)) {
// Filter the keymap item by command so that items in keymap.json can override try {
// the default ones. let configString = yield (0, fs_extra_1.readFile)(filePath, 'utf-8');
const itemsByCommand = {}; configString = configString.replace(/^\s*\/\/.*/, ''); // Strip off comments
const keymap = JSON.parse(configString);
for (let i = 0; i < defaultKeyMap.length; i++) { for (let keymapIndex = 0; keymapIndex < keymap.length; keymapIndex++) {
itemsByCommand[defaultKeyMap[i].command] = defaultKeyMap[i]; const item = keymap[keymapIndex];
} itemsByCommand[item.command] = item;
}
const filePath = `${Setting.value('profileDir')}/keymap.json`; }
if (await fs.pathExists(filePath)) { catch (error) {
try { let msg = error.message ? error.message : '';
let configString = await fs.readFile(filePath, 'utf-8'); msg = `Could not load keymap ${filePath}\n${msg}`;
configString = configString.replace(/^\s*\/\/.*/, ''); // Strip off comments error.message = msg;
const keymap = JSON.parse(configString); throw error;
for (let keymapIndex = 0; keymapIndex < keymap.length; keymapIndex++) { }
const item = keymap[keymapIndex]; }
itemsByCommand[item.command] = item; const output = [];
} for (const n in itemsByCommand) {
} catch (error) { if (!itemsByCommand.hasOwnProperty(n))
let msg = error.message ? error.message : ''; continue;
msg = `Could not load keymap ${filePath}\n${msg}`; output.push(itemsByCommand[n]);
error.message = msg; }
throw error; // Map reserved shortcuts to their equivalent key
} // https://github.com/cronvel/terminal-kit/issues/101
} for (let i = 0; i < output.length; i++) {
const newKeys = output[i].keys.map(k => {
const output = []; k = k.replace(/CTRL_H/g, 'BACKSPACE');
for (const n in itemsByCommand) { k = k.replace(/CTRL_I/g, 'TAB');
if (!itemsByCommand.hasOwnProperty(n)) continue; k = k.replace(/CTRL_M/g, 'ENTER');
output.push(itemsByCommand[n]); return k;
} });
output[i].keys = newKeys;
// Map reserved shortcuts to their equivalent key }
// https://github.com/cronvel/terminal-kit/issues/101 return output;
for (let i = 0; i < output.length; i++) { });
const newKeys = output[i].keys.map(k => { }
k = k.replace(/CTRL_H/g, 'BACKSPACE'); commandList(argv) {
k = k.replace(/CTRL_I/g, 'TAB'); return __awaiter(this, void 0, void 0, function* () {
k = k.replace(/CTRL_M/g, 'ENTER'); if (argv.length && argv[0] === 'batch') {
return k; const commands = [];
}); const commandLines = splitCommandBatch(yield (0, fs_extra_1.readFile)(argv[1], 'utf-8'));
output[i].keys = newKeys; for (const commandLine of commandLines) {
} if (!commandLine.trim())
continue;
return output; const splitted = (0, utils_1.splitCommandString)(commandLine.trim());
} commands.push(splitted);
}
async commandList(argv) { return commands;
if (argv.length && argv[0] === 'batch') { }
const commands = []; else {
const commandLines = splitCommandBatch(await fs.readFile(argv[1], 'utf-8')); return [argv];
}
for (const commandLine of commandLines) { });
if (!commandLine.trim()) continue; }
const splitted = splitCommandString(commandLine.trim()); // We need this special case here because by the time the `version` command
commands.push(splitted); // runs, the keychain has already been setup.
} checkIfKeychainEnabled(argv) {
return commands; return argv.indexOf('version') < 0;
} else { }
return [argv]; start(argv) {
} const _super = Object.create(null, {
} start: { get: () => super.start }
});
// We need this special case here because by the time the `version` command return __awaiter(this, void 0, void 0, function* () {
// runs, the keychain has already been setup. const keychainEnabled = this.checkIfKeychainEnabled(argv);
checkIfKeychainEnabled(argv) { argv = yield _super.start.call(this, argv, { keychainEnabled });
return argv.indexOf('version') < 0; cliUtils.setStdout((object) => {
} return this.stdout(object);
});
async start(argv) { this.initRedux();
const keychainEnabled = this.checkIfKeychainEnabled(argv); // If we have some arguments left at this point, it's a command
// so execute it.
argv = await super.start(argv, { keychainEnabled }); if (argv.length) {
this.gui_ = this.dummyGui();
cliUtils.setStdout(object => { this.currentFolder_ = yield Folder_1.default.load(Setting_1.default.value('activeFolderId'));
return this.stdout(object); yield this.applySettingsSideEffects();
}); try {
const commands = yield this.commandList(argv);
this.initRedux(); for (const command of commands) {
yield this.execCommand(command);
// If we have some arguments left at this point, it's a command }
// so execute it. }
if (argv.length) { catch (error) {
this.gui_ = this.dummyGui(); if (this.showStackTraces_) {
console.error(error);
this.currentFolder_ = await Folder.load(Setting.value('activeFolderId')); }
else {
await this.applySettingsSideEffects(); // eslint-disable-next-line no-console
console.info(error.message);
try { }
const commands = await this.commandList(argv); process.exit(1);
for (const command of commands) { }
await this.execCommand(command); yield Setting_1.default.saveAll();
} // Need to call exit() explicitly, otherwise Node wait for any timeout to complete
} catch (error) { // https://stackoverflow.com/questions/18050095
if (this.showStackTraces_) { process.exit(0);
console.error(error); }
} else { else {
// eslint-disable-next-line no-console // Otherwise open the GUI
console.info(error.message); const keymap = yield this.loadKeymaps();
} const AppGui = require('./app-gui.js');
process.exit(1); this.gui_ = new AppGui(this, this.store(), keymap);
} this.gui_.setLogger(this.logger());
yield this.gui_.start();
await Setting.saveAll(); // Since the settings need to be loaded before the store is created, it will never
// receive the SETTING_UPDATE_ALL even, which mean state.settings will not be
// Need to call exit() explicitly, otherwise Node wait for any timeout to complete // initialised. So we manually call dispatchUpdateAll() to force an update.
// https://stackoverflow.com/questions/18050095 Setting_1.default.dispatchUpdateAll();
process.exit(0); yield (0, folders_screen_utils_js_1.refreshFolders)((action) => this.store().dispatch(action));
} else { const tags = yield Tag_1.default.allWithNotes();
// Otherwise open the GUI ResourceService_1.default.runInBackground();
const keymap = await this.loadKeymaps(); RevisionService_1.default.instance().runInBackground();
this.dispatch({
const AppGui = require('./app-gui.js'); type: 'TAG_UPDATE_ALL',
this.gui_ = new AppGui(this, this.store(), keymap); items: tags,
this.gui_.setLogger(this.logger()); });
await this.gui_.start(); this.store().dispatch({
type: 'FOLDER_SELECT',
// Since the settings need to be loaded before the store is created, it will never id: Setting_1.default.value('activeFolderId'),
// receive the SETTING_UPDATE_ALL even, which mean state.settings will not be });
// initialised. So we manually call dispatchUpdateAll() to force an update. this.startRotatingLogMaintenance(Setting_1.default.value('profileDir'));
Setting.dispatchUpdateAll(); }
});
await refreshFolders((action) => { this.store().dispatch(action); }); }
const tags = await Tag.allWithNotes();
ResourceService.runInBackground();
RevisionService.instance().runInBackground();
this.dispatch({
type: 'TAG_UPDATE_ALL',
items: tags,
});
this.store().dispatch({
type: 'FOLDER_SELECT',
id: Setting.value('activeFolderId'),
});
this.startRotatingLogMaintenance(Setting.value('profileDir'));
}
}
} }
let application_ = null; let application_ = null;
function app() { function app() {
if (application_) return application_; if (application_)
application_ = new Application(); return application_;
return application_; application_ = new Application();
return application_;
} }
exports.default = app;
module.exports = { app }; //# sourceMappingURL=app.js.map

472
packages/app-cli/app/app.ts Normal file
View File

@ -0,0 +1,472 @@
import BaseApplication from '@joplin/lib/BaseApplication';
import { refreshFolders } from '@joplin/lib/folders-screen-utils.js';
import ResourceService from '@joplin/lib/services/ResourceService';
import BaseModel, { ModelType } from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder';
import BaseItem from '@joplin/lib/models/BaseItem';
import Note from '@joplin/lib/models/Note';
import Tag from '@joplin/lib/models/Tag';
import Setting from '@joplin/lib/models/Setting';
import { reg } from '@joplin/lib/registry.js';
import { fileExtension } from '@joplin/lib/path-utils';
import { splitCommandString } from '@joplin/utils';
import { _ } from '@joplin/lib/locale';
import { pathExists, readFile, readdirSync } from 'fs-extra';
import RevisionService from '@joplin/lib/services/RevisionService';
import shim from '@joplin/lib/shim';
import setupCommand from './setupCommand';
import { FolderEntity, NoteEntity } from '@joplin/lib/services/database/types';
const { cliUtils } = require('./cli-utils.js');
const Cache = require('@joplin/lib/Cache');
const { splitCommandBatch } = require('@joplin/lib/string-utils');
class Application extends BaseApplication {
private commands_: Record<string, any> = {};
private commandMetadata_: any = null;
private activeCommand_: any = null;
private allCommandsLoaded_ = false;
private gui_: any = null;
private cache_ = new Cache();
public gui() {
return this.gui_;
}
public commandStdoutMaxWidth() {
return this.gui().stdoutMaxWidth();
}
public async guessTypeAndLoadItem(pattern: string, options: any = null) {
let type = BaseModel.TYPE_NOTE;
if (pattern.indexOf('/') === 0) {
type = BaseModel.TYPE_FOLDER;
pattern = pattern.substr(1);
}
return this.loadItem(type, pattern, options);
}
public async loadItem(type: ModelType | 'folderOrNote', pattern: string, options: any = null) {
const output = await this.loadItems(type, pattern, options);
if (output.length > 1) {
// output.sort((a, b) => { return a.user_updated_time < b.user_updated_time ? +1 : -1; });
// let answers = { 0: _('[Cancel]') };
// for (let i = 0; i < output.length; i++) {
// answers[i + 1] = output[i].title;
// }
// Not really useful with new UI?
throw new Error(_('More than one item match "%s". Please narrow down your query.', pattern));
// let msg = _('More than one item match "%s". Please select one:', pattern);
// const response = await cliUtils.promptMcq(msg, answers);
// if (!response) return null;
// return output[response - 1];
} else {
return output.length ? output[0] : null;
}
}
public async loadItems(type: ModelType | 'folderOrNote', pattern: string, options: any = null): Promise<(FolderEntity | NoteEntity)[]> {
if (type === 'folderOrNote') {
const folders: FolderEntity[] = await this.loadItems(BaseModel.TYPE_FOLDER, pattern, options);
if (folders.length) return folders;
return await this.loadItems(BaseModel.TYPE_NOTE, pattern, options);
}
pattern = pattern ? pattern.toString() : '';
if (type === BaseModel.TYPE_FOLDER && (pattern === Folder.conflictFolderTitle() || pattern === Folder.conflictFolderId())) return [Folder.conflictFolder()];
if (!options) options = {};
const parent = options.parent ? options.parent : app().currentFolder();
const ItemClass = BaseItem.itemClass(type);
if (type === BaseModel.TYPE_NOTE && pattern.indexOf('*') >= 0) {
// Handle it as pattern
if (!parent) throw new Error(_('No notebook selected.'));
return await Note.previews(parent.id, { titlePattern: pattern });
} else {
// Single item
let item = null;
if (type === BaseModel.TYPE_NOTE) {
if (!parent) throw new Error(_('No notebook has been specified.'));
item = await ItemClass.loadFolderNoteByField(parent.id, 'title', pattern);
} else {
item = await ItemClass.loadByTitle(pattern);
}
if (item) return [item];
item = await ItemClass.load(pattern); // Load by id
if (item) return [item];
if (pattern.length >= 2) {
return await ItemClass.loadByPartialId(pattern);
}
}
return [];
}
public setupCommand(cmd: string) {
return setupCommand(cmd, (t: string) => this.stdout(t), () => this.store(), () => this.gui());
}
public stdout(text: string) {
return this.gui().stdout(text);
}
public async exit(code = 0) {
const doExit = async () => {
this.gui().exit();
await super.exit(code);
};
// Give it a few seconds to cancel otherwise exit anyway
shim.setTimeout(async () => {
await doExit();
}, 5000);
if (await reg.syncTarget().syncStarted()) {
this.stdout(_('Cancelling background synchronisation... Please wait.'));
const sync = await reg.syncTarget().synchronizer();
await sync.cancel();
}
await doExit();
}
public commands(uiType: string = null) {
if (!this.allCommandsLoaded_) {
// eslint-disable-next-line github/array-foreach -- Old code before rule was applied
readdirSync(__dirname).forEach(path => {
if (path.indexOf('command-') !== 0) return;
if (path.endsWith('.test.js')) return;
const ext = fileExtension(path);
if (ext !== 'js') return;
const CommandClass = require(`./${path}`);
let cmd = new CommandClass();
if (!cmd.enabled()) return;
cmd = this.setupCommand(cmd);
this.commands_[cmd.name()] = cmd;
});
this.allCommandsLoaded_ = true;
}
if (uiType !== null) {
const temp: Record<string, any> = {};
for (const n in this.commands_) {
if (!this.commands_.hasOwnProperty(n)) continue;
const c = this.commands_[n];
if (!c.supportsUi(uiType)) continue;
temp[n] = c;
}
return temp;
}
return this.commands_;
}
public async commandNames() {
const metadata = await this.commandMetadata();
const output = [];
for (const n in metadata) {
if (!metadata.hasOwnProperty(n)) continue;
output.push(n);
}
return output;
}
public async commandMetadata() {
if (this.commandMetadata_) return this.commandMetadata_;
let output = await this.cache_.getItem('metadata');
if (output) {
this.commandMetadata_ = output;
return { ...this.commandMetadata_ };
}
const commands = this.commands();
output = {};
for (const n in commands) {
if (!commands.hasOwnProperty(n)) continue;
const cmd = commands[n];
output[n] = cmd.metadata();
}
await this.cache_.setItem('metadata', output, 1000 * 60 * 60 * 24);
this.commandMetadata_ = output;
return { ...this.commandMetadata_ };
}
public hasGui() {
return this.gui() && !this.gui().isDummy();
}
public findCommandByName(name: string) {
if (this.commands_[name]) return this.commands_[name];
let CommandClass = null;
try {
CommandClass = require(`${__dirname}/command-${name}.js`);
} catch (error) {
if (error.message && error.message.indexOf('Cannot find module') >= 0) {
const e: any = new Error(_('No such command: %s', name));
e.type = 'notFound';
throw e;
} else {
throw error;
}
}
let cmd = new CommandClass();
cmd = this.setupCommand(cmd);
this.commands_[name] = cmd;
return this.commands_[name];
}
public dummyGui() {
return {
isDummy: () => {
return true;
},
prompt: (initialText = '', promptString = '', options: any = null) => {
return cliUtils.prompt(initialText, promptString, options);
},
showConsole: () => {},
maximizeConsole: () => {},
stdout: (text: string) => {
// eslint-disable-next-line no-console
console.info(text);
},
fullScreen: () => {},
exit: () => {},
showModalOverlay: () => {},
hideModalOverlay: () => {},
stdoutMaxWidth: () => {
return 100;
},
forceRender: () => {},
termSaveState: () => {},
termRestoreState: () => {},
};
}
public async execCommand(argv: string[]): Promise<any> {
if (!argv.length) return this.execCommand(['help']);
// reg.logger().debug('execCommand()', argv);
const commandName = argv[0];
this.activeCommand_ = this.findCommandByName(commandName);
let outException = null;
try {
if (this.gui().isDummy() && !this.activeCommand_.supportsUi('cli')) throw new Error(_('The command "%s" is only available in GUI mode', this.activeCommand_.name()));
const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv);
await this.activeCommand_.action(cmdArgs);
} catch (error) {
outException = error;
}
this.activeCommand_ = null;
if (outException) throw outException;
}
public currentCommand() {
return this.activeCommand_;
}
public async loadKeymaps() {
interface KeyMapItem {
keys: string[];
type: 'function' | 'prompt';
command: string;
cursorPosition?: number;
}
const defaultKeyMap: KeyMapItem[] = [
{ keys: [':'], type: 'function', command: 'enter_command_line_mode' },
{ keys: ['TAB'], type: 'function', command: 'focus_next' },
{ keys: ['SHIFT_TAB'], type: 'function', command: 'focus_previous' },
{ keys: ['UP'], type: 'function', command: 'move_up' },
{ keys: ['DOWN'], type: 'function', command: 'move_down' },
{ keys: ['PAGE_UP'], type: 'function', command: 'page_up' },
{ keys: ['PAGE_DOWN'], type: 'function', command: 'page_down' },
{ keys: ['ENTER'], type: 'function', command: 'activate' },
{ keys: ['DELETE', 'BACKSPACE'], type: 'function', command: 'delete' },
{ keys: ['n'], type: 'function', command: 'next_link' },
{ keys: ['b'], type: 'function', command: 'previous_link' },
{ keys: ['o'], type: 'function', command: 'open_link' },
{ keys: [' '], type: 'prompt', command: 'todo toggle $n' },
{ keys: ['tc'], type: 'function', command: 'toggle_console' },
{ keys: ['tm'], type: 'function', command: 'toggle_metadata' },
{ keys: ['ti'], type: 'function', command: 'toggle_ids' },
{ keys: ['/'], type: 'prompt', command: 'search ""', cursorPosition: -2 },
{ keys: ['mn'], type: 'prompt', command: 'mknote ""', cursorPosition: -2 },
{ keys: ['mt'], type: 'prompt', command: 'mktodo ""', cursorPosition: -2 },
{ keys: ['mb'], type: 'prompt', command: 'mkbook ""', cursorPosition: -2 },
{ keys: ['yn'], type: 'prompt', command: 'cp $n ""', cursorPosition: -2 },
{ keys: ['dn'], type: 'prompt', command: 'mv $n ""', cursorPosition: -2 },
];
// Filter the keymap item by command so that items in keymap.json can override
// the default ones.
const itemsByCommand: Record<string, KeyMapItem> = {};
for (let i = 0; i < defaultKeyMap.length; i++) {
itemsByCommand[defaultKeyMap[i].command] = defaultKeyMap[i];
}
const filePath = `${Setting.value('profileDir')}/keymap.json`;
if (await pathExists(filePath)) {
try {
let configString = await readFile(filePath, 'utf-8');
configString = configString.replace(/^\s*\/\/.*/, ''); // Strip off comments
const keymap = JSON.parse(configString);
for (let keymapIndex = 0; keymapIndex < keymap.length; keymapIndex++) {
const item = keymap[keymapIndex];
itemsByCommand[item.command] = item;
}
} catch (error) {
let msg = error.message ? error.message : '';
msg = `Could not load keymap ${filePath}\n${msg}`;
error.message = msg;
throw error;
}
}
const output = [];
for (const n in itemsByCommand) {
if (!itemsByCommand.hasOwnProperty(n)) continue;
output.push(itemsByCommand[n]);
}
// Map reserved shortcuts to their equivalent key
// https://github.com/cronvel/terminal-kit/issues/101
for (let i = 0; i < output.length; i++) {
const newKeys = output[i].keys.map(k => {
k = k.replace(/CTRL_H/g, 'BACKSPACE');
k = k.replace(/CTRL_I/g, 'TAB');
k = k.replace(/CTRL_M/g, 'ENTER');
return k;
});
output[i].keys = newKeys;
}
return output;
}
public async commandList(argv: string[]) {
if (argv.length && argv[0] === 'batch') {
const commands = [];
const commandLines = splitCommandBatch(await readFile(argv[1], 'utf-8'));
for (const commandLine of commandLines) {
if (!commandLine.trim()) continue;
const splitted = splitCommandString(commandLine.trim());
commands.push(splitted);
}
return commands;
} else {
return [argv];
}
}
// We need this special case here because by the time the `version` command
// runs, the keychain has already been setup.
public checkIfKeychainEnabled(argv: string[]) {
return argv.indexOf('version') < 0;
}
public async start(argv: string[]) {
const keychainEnabled = this.checkIfKeychainEnabled(argv);
argv = await super.start(argv, { keychainEnabled });
cliUtils.setStdout((object: any) => {
return this.stdout(object);
});
this.initRedux();
// If we have some arguments left at this point, it's a command
// so execute it.
if (argv.length) {
this.gui_ = this.dummyGui();
this.currentFolder_ = await Folder.load(Setting.value('activeFolderId'));
await this.applySettingsSideEffects();
try {
const commands = await this.commandList(argv);
for (const command of commands) {
await this.execCommand(command);
}
} catch (error) {
if (this.showStackTraces_) {
console.error(error);
} else {
// eslint-disable-next-line no-console
console.info(error.message);
}
process.exit(1);
}
await Setting.saveAll();
// Need to call exit() explicitly, otherwise Node wait for any timeout to complete
// https://stackoverflow.com/questions/18050095
process.exit(0);
} else {
// Otherwise open the GUI
const keymap = await this.loadKeymaps();
const AppGui = require('./app-gui.js');
this.gui_ = new AppGui(this, this.store(), keymap);
this.gui_.setLogger(this.logger());
await this.gui_.start();
// Since the settings need to be loaded before the store is created, it will never
// receive the SETTING_UPDATE_ALL even, which mean state.settings will not be
// initialised. So we manually call dispatchUpdateAll() to force an update.
Setting.dispatchUpdateAll();
await refreshFolders((action: any) => this.store().dispatch(action));
const tags = await Tag.allWithNotes();
ResourceService.runInBackground();
RevisionService.instance().runInBackground();
this.dispatch({
type: 'TAG_UPDATE_ALL',
items: tags,
});
this.store().dispatch({
type: 'FOLDER_SELECT',
id: Setting.value('activeFolderId'),
});
this.startRotatingLogMaintenance(Setting.value('profileDir'));
}
}
}
let application_: Application = null;
function app() {
if (application_) return application_;
application_ = new Application();
return application_;
}
export default app;

View File

@ -1,4 +1,4 @@
const { app } = require('./app.js'); const app = require('./app').default;
const Note = require('@joplin/lib/models/Note').default; const Note = require('@joplin/lib/models/Note').default;
const Folder = require('@joplin/lib/models/Folder').default; const Folder = require('@joplin/lib/models/Folder').default;
const Tag = require('@joplin/lib/models/Tag').default; const Tag = require('@joplin/lib/models/Tag').default;

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import shim from '@joplin/lib/shim'; import shim from '@joplin/lib/shim';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import BaseItem from '@joplin/lib/models/BaseItem'; import BaseItem from '@joplin/lib/models/BaseItem';

View File

@ -1,6 +1,6 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
import { _, setLocale } from '@joplin/lib/locale'; import { _, setLocale } from '@joplin/lib/locale';
const { app } = require('./app.js'); import app from './app';
import * as fs from 'fs-extra'; import * as fs from 'fs-extra';
import Setting, { AppType } from '@joplin/lib/models/Setting'; import Setting, { AppType } from '@joplin/lib/models/Setting';
import { ReadStream } from 'tty'; import { ReadStream } from 'tty';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import Note from '@joplin/lib/models/Note'; import Note from '@joplin/lib/models/Note';

View File

@ -1,9 +1,10 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import Note from '@joplin/lib/models/Note'; import Note from '@joplin/lib/models/Note';
import time from '@joplin/lib/time'; import time from '@joplin/lib/time';
import { NoteEntity } from '@joplin/lib/services/database/types';
class Command extends BaseCommand { class Command extends BaseCommand {
public override usage() { public override usage() {
@ -15,7 +16,7 @@ class Command extends BaseCommand {
} }
public static async handleAction(commandInstance: BaseCommand, args: any, isCompleted: boolean) { public static async handleAction(commandInstance: BaseCommand, args: any, isCompleted: boolean) {
const note = await app().loadItem(BaseModel.TYPE_NOTE, args.note); const note: NoteEntity = await app().loadItem(BaseModel.TYPE_NOTE, args.note);
commandInstance.encryptionCheck(note); commandInstance.encryptionCheck(note);
if (!note) throw new Error(_('Cannot find "%s".', args.note)); if (!note) throw new Error(_('Cannot find "%s".', args.note));
if (!note.is_todo) throw new Error(_('Note is not a to-do: "%s"', args.note)); if (!note.is_todo) throw new Error(_('Note is not a to-do: "%s"', args.note));

View File

@ -2,7 +2,7 @@ import * as fs from 'fs-extra';
import BaseCommand from './base-command'; import BaseCommand from './base-command';
import { splitCommandString } from '@joplin/utils'; import { splitCommandString } from '@joplin/utils';
import uuid from '@joplin/lib/uuid'; import uuid from '@joplin/lib/uuid';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import Note from '@joplin/lib/models/Note'; import Note from '@joplin/lib/models/Note';
import Setting from '@joplin/lib/models/Setting'; import Setting from '@joplin/lib/models/Setting';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
class Command extends BaseCommand { class Command extends BaseCommand {

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import Setting from '@joplin/lib/models/Setting'; import Setting from '@joplin/lib/models/Setting';
import ReportService from '@joplin/lib/services/ReportService'; import ReportService from '@joplin/lib/services/ReportService';
import * as fs from 'fs-extra'; import * as fs from 'fs-extra';

View File

@ -1,7 +1,7 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
import InteropService from '@joplin/lib/services/interop/InteropService'; import InteropService from '@joplin/lib/services/interop/InteropService';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import { ExportOptions } from '@joplin/lib/services/interop/types'; import { ExportOptions } from '@joplin/lib/services/interop/types';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import Note from '@joplin/lib/models/Note'; import Note from '@joplin/lib/models/Note';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
const { renderCommandHelp } = require('./help-utils.js'); const { renderCommandHelp } = require('./help-utils.js');
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
const { cliUtils } = require('./cli-utils.js'); const { cliUtils } = require('./cli-utils.js');

View File

@ -2,7 +2,7 @@ import BaseCommand from './base-command';
import InteropService from '@joplin/lib/services/interop/InteropService'; import InteropService from '@joplin/lib/services/interop/InteropService';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
const { cliUtils } = require('./cli-utils.js'); const { cliUtils } = require('./cli-utils.js');
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import { ImportOptions } from '@joplin/lib/services/interop/types'; import { ImportOptions } from '@joplin/lib/services/interop/types';
import { unique } from '@joplin/lib/array'; import { unique } from '@joplin/lib/array';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder'; import Folder from '@joplin/lib/models/Folder';

View File

@ -1,5 +1,5 @@
const BaseCommand = require('./base-command').default; const BaseCommand = require('./base-command').default;
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder'; import Folder from '@joplin/lib/models/Folder';

View File

@ -1,5 +1,5 @@
const BaseCommand = require('./base-command').default; const BaseCommand = require('./base-command').default;
const { app } = require('./app.js'); const app = require('./app').default;
const { _ } = require('@joplin/lib/locale'); const { _ } = require('@joplin/lib/locale');
const Note = require('@joplin/lib/models/Note').default; const Note = require('@joplin/lib/models/Note').default;

View File

@ -1,5 +1,5 @@
const BaseCommand = require('./base-command').default; const BaseCommand = require('./base-command').default;
const { app } = require('./app.js'); const app = require('./app').default;
const { _ } = require('@joplin/lib/locale'); const { _ } = require('@joplin/lib/locale');
const Note = require('@joplin/lib/models/Note').default; const Note = require('@joplin/lib/models/Note').default;

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder'; import Folder from '@joplin/lib/models/Folder';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder'; import Folder from '@joplin/lib/models/Folder';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import Folder from '@joplin/lib/models/Folder'; import Folder from '@joplin/lib/models/Folder';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import Note from '@joplin/lib/models/Note'; import Note from '@joplin/lib/models/Note';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';
import Database from '@joplin/lib/database'; import Database from '@joplin/lib/database';

View File

@ -1,5 +1,5 @@
const BaseCommand = require('./base-command').default; const BaseCommand = require('./base-command').default;
const { app } = require('./app.js'); const app = require('./app').default;
const Setting = require('@joplin/lib/models/Setting').default; const Setting = require('@joplin/lib/models/Setting').default;
const { _ } = require('@joplin/lib/locale'); const { _ } = require('@joplin/lib/locale');
const ReportService = require('@joplin/lib/services/ReportService').default; const ReportService = require('@joplin/lib/services/ReportService').default;

View File

@ -7,7 +7,7 @@ import Synchronizer from '@joplin/lib/Synchronizer';
import { masterKeysWithoutPassword } from '@joplin/lib/services/e2ee/utils'; import { masterKeysWithoutPassword } from '@joplin/lib/services/e2ee/utils';
import { appTypeToLockType } from '@joplin/lib/services/synchronizer/LockHandler'; import { appTypeToLockType } from '@joplin/lib/services/synchronizer/LockHandler';
const BaseCommand = require('./base-command').default; const BaseCommand = require('./base-command').default;
const { app } = require('./app.js'); import app from './app';
const { OneDriveApiNodeUtils } = require('@joplin/lib/onedrive-api-node-utils.js'); const { OneDriveApiNodeUtils } = require('@joplin/lib/onedrive-api-node-utils.js');
import { reg } from '@joplin/lib/registry'; import { reg } from '@joplin/lib/registry';
const { cliUtils } = require('./cli-utils.js'); const { cliUtils } = require('./cli-utils.js');

View File

@ -1,5 +1,5 @@
const BaseCommand = require('./base-command').default; const BaseCommand = require('./base-command').default;
const { app } = require('./app.js'); const app = require('./app').default;
const { _ } = require('@joplin/lib/locale'); const { _ } = require('@joplin/lib/locale');
const Tag = require('@joplin/lib/models/Tag').default; const Tag = require('@joplin/lib/models/Tag').default;
const BaseModel = require('@joplin/lib/BaseModel').default; const BaseModel = require('@joplin/lib/BaseModel').default;

View File

@ -1,5 +1,5 @@
const BaseCommand = require('./base-command').default; const BaseCommand = require('./base-command').default;
const { app } = require('./app.js'); const app = require('./app').default;
const { _ } = require('@joplin/lib/locale'); const { _ } = require('@joplin/lib/locale');
const BaseModel = require('@joplin/lib/BaseModel').default; const BaseModel = require('@joplin/lib/BaseModel').default;
const Note = require('@joplin/lib/models/Note').default; const Note = require('@joplin/lib/models/Note').default;

View File

@ -1,5 +1,5 @@
import BaseCommand from './base-command'; import BaseCommand from './base-command';
const { app } = require('./app.js'); import app from './app';
import { _ } from '@joplin/lib/locale'; import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel'; import BaseModel from '@joplin/lib/BaseModel';

View File

@ -10,7 +10,7 @@ if (compareVersion(nodeVersion, '10.0.0') < 0) {
process.exit(1); process.exit(1);
} }
const { app } = require('./app.js'); const app = require('./app').default;
const Folder = require('@joplin/lib/models/Folder').default; const Folder = require('@joplin/lib/models/Folder').default;
const Resource = require('@joplin/lib/models/Resource').default; const Resource = require('@joplin/lib/models/Resource').default;
const BaseItem = require('@joplin/lib/models/BaseItem').default; const BaseItem = require('@joplin/lib/models/BaseItem').default;

View File

@ -1,4 +1,4 @@
const { app } = require('../app'); import app from '../app';
import Folder from '@joplin/lib/models/Folder'; import Folder from '@joplin/lib/models/Folder';
import BaseCommand from '../base-command'; import BaseCommand from '../base-command';
import setupCommand from '../setupCommand'; import setupCommand from '../setupCommand';

View File

@ -88,7 +88,7 @@ export default class BaseApplication {
// Note: this is basically a cache of state.selectedFolderId. It should *only* // Note: this is basically a cache of state.selectedFolderId. It should *only*
// be derived from the state and not set directly since that would make the // be derived from the state and not set directly since that would make the
// state and UI out of sync. // state and UI out of sync.
private currentFolder_: any = null; protected currentFolder_: any = null;
protected store_: Store<any> = null; protected store_: Store<any> = null;