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