diff --git a/src/@types/i18next.d.ts b/src/@types/i18next.d.ts index 0d486ffa..b7b6cc6f 100644 --- a/src/@types/i18next.d.ts +++ b/src/@types/i18next.d.ts @@ -1,4 +1,4 @@ -import { resources } from "../i18n/i18next"; +import { resources } from "src/i18n/i18next"; declare module "i18next" { interface CustomTypeOptions { diff --git a/src/GitHub/branch.ts b/src/GitHub/branch.ts index ddbbcbd8..5dcb0e58 100644 --- a/src/GitHub/branch.ts +++ b/src/GitHub/branch.ts @@ -1,13 +1,12 @@ +import { + Properties, +} from "@interfaces/main"; import { Octokit } from "@octokit/core"; import i18next from "i18next"; import {Notice } from "obsidian"; - -import { - Properties, -} from "../interfaces/main"; -import GithubPublisher from "../main"; -import { logs, notif } from "../utils"; -import { FilesManagement } from "./files"; +import { FilesManagement } from "src/GitHub/files"; +import GithubPublisher from "src/main"; +import { logs, notif } from "src/utils"; export class GithubBranch extends FilesManagement { diff --git a/src/GitHub/delete.ts b/src/GitHub/delete.ts index 624a05c9..5ffd4b6d 100644 --- a/src/GitHub/delete.ts +++ b/src/GitHub/delete.ts @@ -1,8 +1,3 @@ -import { Octokit } from "@octokit/core"; -import i18next from "i18next"; -import { Base64 } from "js-base64"; -import { MetadataCache, normalizePath, Notice, parseYaml, TAbstractFile, TFile, TFolder, Vault } from "obsidian"; - import { Deleted, FIND_REGEX, @@ -11,11 +6,15 @@ import { GithubRepo, MonoRepoProperties, Properties, -} from "../interfaces"; -import { logs, notif, trimObject} from "../utils"; -import {isAttachment, verifyRateLimitAPI} from "../utils/data_validation_test"; -import { frontmatterSettingsRepository } from "../utils/parse_frontmatter"; -import { FilesManagement } from "./files"; +} from "@interfaces"; +import { Octokit } from "@octokit/core"; +import i18next from "i18next"; +import { Base64 } from "js-base64"; +import { MetadataCache, normalizePath, Notice, parseYaml, TAbstractFile, TFile, TFolder, Vault } from "obsidian"; +import { FilesManagement } from "src/GitHub/files"; +import { logs, notif, trimObject} from "src/utils"; +import {isAttachment, verifyRateLimitAPI} from "src/utils/data_validation_test"; +import { frontmatterSettingsRepository } from "src/utils/parse_frontmatter"; /** * Delete file from github, based on a list of file in the original vault diff --git a/src/GitHub/files.ts b/src/GitHub/files.ts index e52ffab0..1e3bde0f 100644 --- a/src/GitHub/files.ts +++ b/src/GitHub/files.ts @@ -1,11 +1,3 @@ -import { Octokit } from "@octokit/core"; -import { EmbedCache, LinkCache, TFile, TFolder} from "obsidian"; -import { getAPI, Link } from "obsidian-dataview"; - -import { - getImagePath, - getReceiptFolder, -} from "../conversion/file_path"; import { ConvertedLink, GithubRepo, @@ -13,12 +5,19 @@ import { Properties, PropertiesConversion, Repository, -} from "../interfaces/main"; -import GithubPublisher from "../main"; -import {logs} from "../utils"; -import { isAttachment, isShared } from "../utils/data_validation_test"; -import { frontmatterFromFile, getFrontmatterSettings, getProperties } from "../utils/parse_frontmatter"; -import Publisher from "./upload"; +} from "@interfaces/main"; +import { Octokit } from "@octokit/core"; +import { EmbedCache, LinkCache, TFile, TFolder} from "obsidian"; +import { getAPI, Link } from "obsidian-dataview"; +import { + getImagePath, + getReceiptFolder, +} from "src/conversion/file_path"; +import Publisher from "src/GitHub/upload"; +import GithubPublisher from "src/main"; +import {logs} from "src/utils"; +import { isAttachment, isShared } from "src/utils/data_validation_test"; +import { frontmatterFromFile, getFrontmatterSettings, getProperties } from "src/utils/parse_frontmatter"; export class FilesManagement extends Publisher { diff --git a/src/GitHub/upload.ts b/src/GitHub/upload.ts index e27d6486..e9d1b770 100644 --- a/src/GitHub/upload.ts +++ b/src/GitHub/upload.ts @@ -1,3 +1,13 @@ +import { + Deleted, + GitHubPublisherSettings, + MetadataExtractor, MonoProperties, + MonoRepoProperties, + MultiProperties, + MultiRepoProperties, + Properties, UploadedFiles, +} from "@interfaces"; +import { LOADING_ICON } from "@interfaces/icons"; import { Octokit } from "@octokit/core"; import i18next from "i18next"; import { Base64 } from "js-base64"; @@ -11,42 +21,31 @@ import { TFolder, Vault, } from "obsidian"; -import merge from "ts-deepmerge"; - -import { mainConverting } from "../conversion"; -import { convertToHTMLSVG } from "../conversion/compiler/excalidraw"; +import { mainConverting } from "src/conversion"; +import { convertToHTMLSVG } from "src/conversion/compiler/excalidraw"; import { getImagePath, getReceiptFolder, -} from "../conversion/file_path"; -import { - Deleted, - GitHubPublisherSettings, - MetadataExtractor, MonoProperties, - MonoRepoProperties, - MultiProperties, - MultiRepoProperties, - Properties, UploadedFiles, -} from "../interfaces"; -import GithubPublisher from "../main"; +} from "src/conversion/file_path"; +import { deleteFromGithub } from "src/GitHub/delete"; +import { FilesManagement } from "src/GitHub/files"; +import GithubPublisher from "src/main"; import { logs, noticeMobile, notif, notifError, -} from "../utils"; +} from "src/utils"; import { checkEmptyConfiguration, checkIfRepoIsInAnother, forcePushAttachment, isAttachment, isShared, -} from "../utils/data_validation_test"; -import { LOADING_ICON } from "../utils/icons"; -import { frontmatterFromFile, frontmatterSettingsRepository, getFrontmatterSettings, getProperties } from "../utils/parse_frontmatter"; -import { ShareStatusBar } from "../utils/status_bar"; -import { deleteFromGithub } from "./delete"; -import { FilesManagement } from "./files"; +} from "src/utils/data_validation_test"; +import { frontmatterFromFile, frontmatterSettingsRepository, getFrontmatterSettings, getProperties } from "src/utils/parse_frontmatter"; +import { ShareStatusBar } from "src/utils/status_bar"; +import merge from "ts-deepmerge"; /** Class to manage the branch * @extends FilesManagement diff --git a/src/commands/callback.ts b/src/commands/callback.ts deleted file mode 100644 index a7239a7a..00000000 --- a/src/commands/callback.ts +++ /dev/null @@ -1,297 +0,0 @@ -/** - * @file callback.ts - * @description Return the commands based on the fact it's for a specific repo or the default one - * The id is different if a repo is set, and the smartkey is used as a name, prepended by a K - */ - -import i18next from "i18next"; -import {Command, Notice, TFile } from "obsidian"; - -import {MonoRepoProperties,MultiRepoProperties,Repository} from "../interfaces"; -import GithubPublisher from "../main"; -import {createLink} from "../utils"; -import {checkRepositoryValidity, isShared} from "../utils/data_validation_test"; -import { frontmatterFromFile, frontmatterSettingsRepository, getProperties } from "../utils/parse_frontmatter"; -import {purgeNotesRemote, shareOneNote} from "."; -import {shareEditedOnly, uploadAllEditedNotes, uploadAllNotes, uploadNewNotes} from "./plugin_commands"; - -/** - * Create the command to create a link to the note in the repo - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {GithubPublisher} plugin - * @return {Promise} - */ -export async function createLinkCallback(repo: Repository | null, plugin: GithubPublisher): Promise { - const id = repo ? `copy-link-K${repo.smartKey}` : "copy-link"; - const common = i18next.t("common.repository"); - let name = i18next.t("commands.copyLink.title"); - name = repo ? `${name} (${common} : ${repo.smartKey})` : name; - return { - id, - name, - hotkeys: [], - checkCallback: (checking) => { - const file = plugin.app.workspace.getActiveFile(); - const frontmatter = frontmatterFromFile(file, plugin, repo); - if ( - file && frontmatter && isShared(frontmatter, plugin.settings, file, repo) - ) { - if (!checking) { - const multiRepo: MultiRepoProperties = { - frontmatter: getProperties(plugin, repo, frontmatter, true), - repository: repo, - }; - createLink( - file, - multiRepo, - plugin - ); - new Notice(i18next.t("commands.copyLink.onActivation")); - } - return true; - } - return false; - }, - } as Command; -} - - -/** - * Command to delete file on the repo - * @call purgeNotesRemote - * @param {GithubPublisher} plugin - The plugin instance - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {string} branchName - The branch name to delete the file - * @return {Promise} - */ -export async function purgeNotesRemoteCallback(plugin: GithubPublisher, repo: Repository | null, branchName: string): Promise { - const id = repo ? `delete-clean-K${repo.smartKey}` : "delete-clean"; - let name = i18next.t("commands.publisherDeleteClean"); - const common = i18next.t("common.repository"); - name = repo ? `${name} (${common} : ${repo.smartKey})` : name; - return { - id, - name, - hotkeys: [], - callback: async () => { - const frontmatter = getProperties(plugin, repo, undefined, true); - const monoRepo: MonoRepoProperties = { - frontmatter: Array.isArray(frontmatter) ? frontmatter[0] : frontmatter, - repository: repo, - convert: frontmatterSettingsRepository(plugin, repo) - }; - const publisher = await plugin.reloadOctokit(repo?.smartKey); - await purgeNotesRemote( - publisher, - branchName, - monoRepo - ); - }, - } as Command; -} - -/** - * Command to upload the active file ; use checkCallback to check if the file is shared and if they are a active file - * @call shareOneNote - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {GithubPublisher} plugin - The plugin instance - * @return {Promise} - */ -export async function shareOneNoteCallback(repo: Repository|null, plugin: GithubPublisher): Promise { - const id = repo ? `share-one-K${repo.smartKey}` : "share-one"; - let name = i18next.t("commands.shareActiveFile"); - const common = i18next.t("common.repository"); - name = repo ? `${name} (${common} : ${repo.smartKey})` : name; - const octokit = await plugin.reloadOctokit(repo?.smartKey); - return { - id, - name, - hotkeys: [], - checkCallback: (checking) => { - const file = plugin.app.workspace.getActiveFile(); - const frontmatter = frontmatterFromFile(file, plugin, repo); - if ( - file && frontmatter && isShared(frontmatter, plugin.settings, file, repo) - ) { - if (!checking) { - shareOneNote( - octokit, - file, - repo, - frontmatter, - file.basename, - ); - } - return true; - } - return false; - }, - } as Command; -} - -/** - * Upload all note - * @call uploadAllNotes - * @param plugin {GithubPublisher} - The plugin instance - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {string} branchName - The branch name to upload the file - * @return {Promise} - */ -export async function uploadAllNotesCallback(plugin: GithubPublisher, repo: Repository|null, branchName: string): Promise { - const id = repo ? `publish-all-K${repo.smartKey}` : "publish-all"; - let name = i18next.t("commands.uploadAllNotes"); - const common = i18next.t("common.repository"); - name = repo ? `${name} (${common} : ${repo.smartKey})` : name; - return { - id, - name, - callback: async () => { - await uploadAllNotes(plugin,repo, branchName); - }, - } as Command; -} - -/** - * Upload all new notes only - * @param plugin {GithubPublisher} - The plugin instance - * @param repo {Repository | null} - Other repo if the command is called from the suggest_other_repo_command.ts - * @param branchName {string} - The branch name to upload the file - * @returns {Promise} - */ -export async function uploadNewNotesCallback(plugin: GithubPublisher, repo: Repository | null, branchName: string): Promise { - const id = repo ? `upload-new-K${repo.smartKey}` : "upload-new"; - let name = i18next.t("commands.uploadNewNotes"); - const common = i18next.t("common.repository"); - name = repo ? `${name} (${common} : ${repo.smartKey})` : name; - return { - id, - name, - callback: async () => { - await uploadNewNotes(plugin,branchName, repo); - }, - } as Command; -} - -/** - * Share all edited note - * @call uploadAllEditedNotes - * @param plugin - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {string} branchName - * @return {Promise} - */ -export async function uploadAllEditedNotesCallback(plugin: GithubPublisher, repo: Repository|null, branchName: string): Promise { - const id = repo ? `upload-all-edited-new-K${repo.smartKey}` : "upload-all-edited-new"; - let name = i18next.t("commands.uploadAllNewEditedNote"); - const common = i18next.t("common.repository"); - name = repo ? `${name} (${common} : ${repo.smartKey})` : name; - return { - id, - name, - callback: async () => { - await uploadAllEditedNotes(plugin, branchName, repo); - }, - } as Command; -} - -/** - * Share edited note only - * @call shareEditedOnly - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {string} branchName - * @param {GithubPublisher} plugin - * @return {Promise} - */ -export async function shareEditedOnlyCallback(repo: Repository|null, branchName: string, plugin: GithubPublisher): Promise { - const id = repo ? `upload-edited-K${repo.smartKey}` : "upload-edited"; - let name = i18next.t("commands.uploadAllEditedNote"); - const common = i18next.t("common.repository"); - name = repo ? `${name} (${common} : ${repo.smartKey})` : name; - return { - id, - name, - callback: async () => { - await shareEditedOnly(branchName, repo, plugin); - }, - } as Command; -} - -/** - * Check if the repository is valid - * @param {GithubPublisher} plugin - * @param {Repository} repo - * @return {Promise} - */ - -export async function checkRepositoryValidityCallback(plugin: GithubPublisher, repo: Repository | null): Promise { - const id = repo ? `check-plugin-repo-validy-K${repo.smartKey}` : "check-plugin-repo-validy"; - let name = i18next.t("commands.checkValidity.title"); - const common = i18next.t("common.repository"); - name = repo ? `${name} (${common} : ${repo.smartKey})` : name; - const octokit = await plugin.reloadOctokit(repo?.smartKey); - return { - id, - name, - checkCallback: (checking) => { - if (plugin.app.workspace.getActiveFile()) - { - if (!checking) { - checkRepositoryValidity( - octokit, - repo, - plugin.app.workspace.getActiveFile() - ); - } - return true; - } - return false; - }, - } as Command; -} - -export function refreshOpenedSet(plugin: GithubPublisher) { - const findRepo= (file: TFile | null) => { - if (!file) return []; - return plugin.settings.github.otherRepo.filter((repo) => repo.set === file.path); - }; - - return { - id: "reload-opened-set", - name: i18next.t("commands.refreshOpenedSet"), - checkCallback: (checking) => { - const file = plugin.app.workspace.getActiveFile(); - const repos = findRepo(file); - if (file && repos.length > 0) { - if (!checking) { - repos.forEach((repo) => { - plugin.repositoryFrontmatter[repo.smartKey] = plugin.app.metadataCache.getFileCache(file)?.frontmatter; - }); - } - return true; - } - return false; - }, - } as Command; -} - -export function refreshAllSets(plugin: GithubPublisher) { - return { - id: "reload-all-sets", - name: i18next.t("commands.refreshAllSets"), - checkCallback: (checking) => { - const allSets = plugin.settings.github.otherRepo.filter((repo) => repo.set !== "" || repo.set !== null); - if (allSets.length > 0) { - if (!checking) { - allSets.forEach((repo) => { - if (!repo.set) return; - const file = plugin.app.vault.getAbstractFileByPath(repo.set); - if (!file || !(file instanceof TFile)) return; - plugin.repositoryFrontmatter[repo.smartKey] = plugin.app.metadataCache.getFileCache(file)?.frontmatter; - }); - } - return true; - } - return false; - } - } as Command; -} diff --git a/src/commands/create_link.ts b/src/commands/create_link.ts new file mode 100644 index 00000000..e47a2c41 --- /dev/null +++ b/src/commands/create_link.ts @@ -0,0 +1,75 @@ +import { MultiRepoProperties, Repository } from "@interfaces"; +import i18next from "i18next"; +import { Command, Notice } from "obsidian"; +import GithubPublisher from "src/main"; +import { createLink } from "src/utils"; +import { isShared } from "src/utils/data_validation_test"; +import { frontmatterFromFile, getProperties } from "src/utils/parse_frontmatter"; + +/** + * Create the command to create a link to the note in the repo + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {GithubPublisher} plugin + * @return {Promise} + */ +export async function createLinkCallback(repo: Repository | null, plugin: GithubPublisher): Promise { + const id = repo ? `copy-link-K${repo.smartKey}` : "copy-link"; + const common = i18next.t("common.repository"); + let name = i18next.t("commands.copyLink.title"); + name = repo ? `${name} (${common} : ${repo.smartKey})` : name; + return { + id, + name, + hotkeys: [], + checkCallback: (checking) => { + const file = plugin.app.workspace.getActiveFile(); + const frontmatter = frontmatterFromFile(file, plugin, repo); + if (file && frontmatter && isShared(frontmatter, plugin.settings, file, repo)) { + if (!checking) { + const multiRepo: MultiRepoProperties = { + frontmatter: getProperties(plugin, repo, frontmatter, true), + repository: repo, + }; + createLink( + file, + multiRepo, + plugin + ); + new Notice(i18next.t("commands.copyLink.onActivation")); + } + return true; + } + return false; + }, + } as Command; +} + + +/** + * Create the command to create a link to the note in the repo if a file is active ; else do nothing + * @call createLink + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {GithubPublisher} plugin - The plugin instance + * @return {Promise} + */ +export async function createLinkOnActiveFile(repo: Repository | null, plugin: GithubPublisher): Promise { + const file = plugin.app.workspace.getActiveFile(); + const frontmatter = frontmatterFromFile(file, plugin, repo); + + if ( + file && frontmatter && isShared(frontmatter, plugin.settings, file, repo) + ) { + const multiRepo: MultiRepoProperties = { + frontmatter: getProperties(plugin, repo, frontmatter), + repository: repo + }; + await createLink( + file, + multiRepo, + plugin + ); + new Notice(i18next.t("commands.copyLink.onActivation")); + return; + } + new Notice(i18next.t("commands.runOtherRepo.noFile")); +} diff --git a/src/commands/file_menu.ts b/src/commands/file_menu/file.ts similarity index 52% rename from src/commands/file_menu.ts rename to src/commands/file_menu/file.ts index 91eef61b..12cf41d7 100644 --- a/src/commands/file_menu.ts +++ b/src/commands/file_menu/file.ts @@ -1,95 +1,11 @@ +import { Repository } from "@interfaces"; import i18next from "i18next"; -import { Menu, MenuItem, Platform, TFile, TFolder} from "obsidian"; - -import {MonoRepoProperties, Repository} from "../interfaces"; -import GithubPublisher from "../main"; -import {defaultRepo, getRepoSharedKey, isExcludedPath, isInDryRunFolder, isShared, multipleSharedKey} from "../utils/data_validation_test"; -import { frontmatterFromFile, frontmatterSettingsRepository, getProperties } from "../utils/parse_frontmatter"; -import {shareAllMarkedNotes, shareOneNote} from "."; -import {ChooseRepoToRun} from "./suggest_other_repo_commands_modal"; - -/** - * Share the shared file of a folder to a repository - * @param {GithubPublisher} plugin - The plugin instance - * @param {TFolder} folder - The folder to share - * @param {string} branchName - The branch name for the repository - * @param {Repository | null} repo - The data repository found in the file - */ -export async function shareFolderRepo(plugin: GithubPublisher, folder: TFolder, branchName: string, repo: Repository | null) { - const publisher = await plugin.reloadOctokit(repo?.smartKey); - const statusBarItems = plugin.addStatusBarItem(); - const prop = getProperties(plugin, repo, null, true); - const monoProperties: MonoRepoProperties = { - frontmatter: Array.isArray(prop) ? prop[0] : prop, - repository: repo, - convert: frontmatterSettingsRepository(plugin, repo) - }; - await shareAllMarkedNotes( - publisher, - statusBarItems, - branchName, - monoProperties, - publisher.getSharedFileOfFolder(folder, repo, true), - true, - ); -} - -/** - * Create a submenu if multiple repository are set up - * If Platform is Desktop, create a submenu - * If not, add the command to the original menu, in line - * @param {GithubPublisher} plugin - The plugin instance - * @param {MenuItem} item - The item to add the submenu to - * @param {TFolder} folder - The folder to share - * @param {string} branchName - The branch name for the repository - * @return {Menu} - The submenu created - */ -export function addSubMenuCommandsFolder(plugin: GithubPublisher, item: MenuItem, folder: TFolder, branchName: string, originalMenu: Menu): Menu { - const subMenu = Platform.isDesktop ? item.setSubmenu() as Menu : originalMenu; - if (!isExcludedPath(plugin.settings, folder, defaultRepo(plugin.settings))) { - subMenu.addItem((subItem) => { - subItem - .setTitle(i18next.t("commands.shareViewFiles.multiple.on", { - smartKey: i18next.t("common.default").toUpperCase(), - doc: folder.name - })) - .setIcon("folder-up") - .onClick(async () => { - const repo = getRepoSharedKey(plugin, undefined); - await shareFolderRepo(plugin, folder, branchName, repo); - }); - }); - } - const activatedRepoCommands = plugin.settings.github.otherRepo.filter((repo) => repo.createShortcuts); - if (activatedRepoCommands.length > 0) { - activatedRepoCommands.forEach((otherRepo) => { - if (isInDryRunFolder(plugin.settings, otherRepo, folder)) return; - subMenu.addItem((item) => { - item.setTitle( - i18next.t("commands.shareViewFiles.multiple.on", { - smartKey: otherRepo.smartKey.toUpperCase(), - doc: folder.name - })) - .setIcon("folder-up") - .onClick(async () => { - await shareFolderRepo(plugin, folder, branchName, otherRepo); - }); - }); - }); - } - subMenu.addItem((subItem) => { - subItem - .setTitle(i18next.t("commands.shareViewFiles.multiple.other")) - .setIcon("folder-symlink") - .onClick(async () => { - new ChooseRepoToRun(plugin.app, plugin, null, branchName, "folder", null, async (item: Repository) => { - await shareFolderRepo(plugin, folder, branchName, item); - }).open(); - - }); - }); - return subMenu; -} +import { Menu, MenuItem,Platform, TFile } from "obsidian"; +import { shareOneNote } from "src/commands"; +import { ChooseRepoToRun } from "src/commands/suggest_other_repo_commands_modal"; +import GithubPublisher from "src/main"; +import { defaultRepo,getRepoSharedKey, isShared, multipleSharedKey } from "src/utils/data_validation_test"; +import { frontmatterFromFile, getProperties } from "src/utils/parse_frontmatter"; /** * Create a menu for a shared file @@ -172,7 +88,7 @@ export function addMenuFile(plugin: GithubPublisher, file: TFile, branchName: st * @param {Repository} repo - The data repository found in the file * @return {Menu} - The submenu created */ -export function subMenuCommandsFile(plugin: GithubPublisher, item: MenuItem, file: TFile, branchName: string, repo: Repository | null, originalMenu: Menu): Menu { +function subMenuCommandsFile(plugin: GithubPublisher, item: MenuItem, file: TFile, branchName: string, repo: Repository | null, originalMenu: Menu): Menu { const frontmatter = frontmatterFromFile(file, plugin, repo); const fileName = plugin.getTitleFieldForCommand(file, frontmatter).replace(".md", ""); const subMenu = Platform.isDesktop ? item.setSubmenu() as Menu : originalMenu; @@ -266,49 +182,4 @@ export function subMenuCommandsFile(plugin: GithubPublisher, item: MenuItem, fil }); }); return subMenu; -} - -/** - * Create a menu with submenu for a folder in the explorer view - * @param menu {Menu} - The menu to add the item to - * @param folder {TFolder} - The folder to share - * @param branchName {string} - The branch name for the repository - * @param plugin {GithubPublisher} - The plugin instance - */ -export async function addMenuFolder(menu: Menu, folder: TFolder, branchName: string, plugin: GithubPublisher) { - menu.addItem((item) => { - /** - * Create a submenu if multiple repo exists in the settings - */ - const areTheyMultipleRepo = plugin.settings.github?.otherRepo?.length > 0; - if (areTheyMultipleRepo) { - if (Platform.isDesktop) { - item.setTitle("Github Publisher"); - item.setIcon("upload-cloud"); - } else { - //add the line to separate the commands - menu.addSeparator(); - item.setIsLabel(true); - } - addSubMenuCommandsFolder( - plugin, - item, - folder, - branchName, - menu - ); - return; - } - item.setSection("action"); - item.setTitle( - i18next.t("commands.shareViewFiles.multiple.on", { - smartKey: i18next.t("common.default").toUpperCase(), - doc: folder.name - })) - .setIcon("folder-up") - .onClick(async () => { - const repo = getRepoSharedKey(plugin); - await shareFolderRepo(plugin, folder, branchName, repo); - }); - }); -} +} \ No newline at end of file diff --git a/src/commands/file_menu/folder.ts b/src/commands/file_menu/folder.ts new file mode 100644 index 00000000..e5e64101 --- /dev/null +++ b/src/commands/file_menu/folder.ts @@ -0,0 +1,136 @@ +import { MonoRepoProperties,Repository } from "@interfaces"; +import i18next from "i18next"; +import { Menu, MenuItem, Platform, TFolder } from "obsidian"; +import { shareAllMarkedNotes } from "src/commands"; +import { ChooseRepoToRun } from "src/commands/suggest_other_repo_commands_modal"; +import GithubPublisher from "src/main"; +import { defaultRepo, getRepoSharedKey, isExcludedPath, isInDryRunFolder } from "src/utils/data_validation_test"; +import { frontmatterSettingsRepository,getProperties } from "src/utils/parse_frontmatter"; + +/** + * Share the shared file of a folder to a repository + * @param {GithubPublisher} plugin - The plugin instance + * @param {TFolder} folder - The folder to share + * @param {string} branchName - The branch name for the repository + * @param {Repository | null} repo - The data repository found in the file + */ +async function shareFolderRepo(plugin: GithubPublisher, folder: TFolder, branchName: string, repo: Repository | null) { + const publisher = await plugin.reloadOctokit(repo?.smartKey); + const statusBarItems = plugin.addStatusBarItem(); + const prop = getProperties(plugin, repo, null, true); + const monoProperties: MonoRepoProperties = { + frontmatter: Array.isArray(prop) ? prop[0] : prop, + repository: repo, + convert: frontmatterSettingsRepository(plugin, repo) + }; + await shareAllMarkedNotes( + publisher, + statusBarItems, + branchName, + monoProperties, + publisher.getSharedFileOfFolder(folder, repo, true), + true, + ); +} + +/** + * Create a submenu if multiple repository are set up + * If Platform is Desktop, create a submenu + * If not, add the command to the original menu, in line + * @param {GithubPublisher} plugin - The plugin instance + * @param {MenuItem} item - The item to add the submenu to + * @param {TFolder} folder - The folder to share + * @param {string} branchName - The branch name for the repository + * @return {Menu} - The submenu created + */ +function addSubMenuCommandsFolder(plugin: GithubPublisher, item: MenuItem, folder: TFolder, branchName: string, originalMenu: Menu): Menu { + const subMenu = Platform.isDesktop ? item.setSubmenu() as Menu : originalMenu; + if (!isExcludedPath(plugin.settings, folder, defaultRepo(plugin.settings))) { + subMenu.addItem((subItem) => { + subItem + .setTitle(i18next.t("commands.shareViewFiles.multiple.on", { + smartKey: i18next.t("common.default").toUpperCase(), + doc: folder.name + })) + .setIcon("folder-up") + .onClick(async () => { + const repo = getRepoSharedKey(plugin, undefined); + await shareFolderRepo(plugin, folder, branchName, repo); + }); + }); + } + const activatedRepoCommands = plugin.settings.github.otherRepo.filter((repo) => repo.createShortcuts); + if (activatedRepoCommands.length > 0) { + activatedRepoCommands.forEach((otherRepo) => { + if (isInDryRunFolder(plugin.settings, otherRepo, folder)) return; + subMenu.addItem((item) => { + item.setTitle( + i18next.t("commands.shareViewFiles.multiple.on", { + smartKey: otherRepo.smartKey.toUpperCase(), + doc: folder.name + })) + .setIcon("folder-up") + .onClick(async () => { + await shareFolderRepo(plugin, folder, branchName, otherRepo); + }); + }); + }); + } + subMenu.addItem((subItem) => { + subItem + .setTitle(i18next.t("commands.shareViewFiles.multiple.other")) + .setIcon("folder-symlink") + .onClick(async () => { + new ChooseRepoToRun(plugin.app, plugin, null, branchName, "folder", null, async (item: Repository) => { + await shareFolderRepo(plugin, folder, branchName, item); + }).open(); + + }); + }); + return subMenu; +} + +/** + * Create a menu with submenu for a folder in the explorer view + * @param menu {Menu} - The menu to add the item to + * @param folder {TFolder} - The folder to share + * @param branchName {string} - The branch name for the repository + * @param plugin {GithubPublisher} - The plugin instance + */ +export async function addMenuFolder(menu: Menu, folder: TFolder, branchName: string, plugin: GithubPublisher) { + menu.addItem((item) => { + /** + * Create a submenu if multiple repo exists in the settings + */ + const areTheyMultipleRepo = plugin.settings.github?.otherRepo?.length > 0; + if (areTheyMultipleRepo) { + if (Platform.isDesktop) { + item.setTitle("Github Publisher"); + item.setIcon("upload-cloud"); + } else { + //add the line to separate the commands + menu.addSeparator(); + item.setIsLabel(true); + } + addSubMenuCommandsFolder( + plugin, + item, + folder, + branchName, + menu + ); + return; + } + item.setSection("action"); + item.setTitle( + i18next.t("commands.shareViewFiles.multiple.on", { + smartKey: i18next.t("common.default").toUpperCase(), + doc: folder.name + })) + .setIcon("folder-up") + .onClick(async () => { + const repo = getRepoSharedKey(plugin); + await shareFolderRepo(plugin, folder, branchName, repo); + }); + }); +} \ No newline at end of file diff --git a/src/commands/file_menu/index.ts b/src/commands/file_menu/index.ts new file mode 100644 index 00000000..ae275467 --- /dev/null +++ b/src/commands/file_menu/index.ts @@ -0,0 +1,6 @@ +import { addMenuFile } from "src/commands/file_menu/file"; +import { addMenuFolder } from "src/commands/file_menu/folder"; + +export { + addMenuFile, addMenuFolder +}; \ No newline at end of file diff --git a/src/commands/index.ts b/src/commands/index.ts index 2ef4a135..a4e56e02 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,395 +1,29 @@ -import i18next from "i18next"; -import { FrontMatterCache, Notice, Platform, TFile } from "obsidian"; -import { ERROR_ICONS } from "src/utils/icons"; -import merge from "ts-deepmerge"; - -import { GithubBranch } from "../GitHub/branch"; -import { deleteFromGithub } from "../GitHub/delete"; -import { MonoRepoProperties, MultiRepoProperties, Repository, UploadedFiles} from "../interfaces"; -import { ListChangedFiles } from "../settings/modals/list_changed"; -import { - createLink, - createListEdited, - getSettingsOfMetadataExtractor, - logs, - notif, notifError, publisherNotification} from "../utils"; -import {checkRepositoryValidityWithProperties} from "../utils/data_validation_test"; -import { frontmatterFromFile, getProperties } from "../utils/parse_frontmatter"; -import { ShareStatusBar } from "../utils/status_bar"; - - -/** - * Share all marked note (share: true) from Obsidian to GitHub - * @param {GithubBranch} PublisherManager - * @param {HTMLElement} statusBarItems - The status bar element - * @param {string} branchName - The branch name created by the plugin - * @param {MonoRepoProperties} monoRepo - The repo where to share the files - * @param {TFile[]} sharedFiles - The files to share - * @param {boolean} createGithubBranch - If true, create the branch before sharing the files - */ -export async function shareAllMarkedNotes( - PublisherManager: GithubBranch, - statusBarItems: HTMLElement, - branchName: string, - monoRepo: MonoRepoProperties, - sharedFiles: TFile[], - createGithubBranch: boolean = true, - sourceFrontmatter: FrontMatterCache | undefined | null = null, -) { - const statusBar = new ShareStatusBar(statusBarItems, sharedFiles.length); - const prop = monoRepo.frontmatter; - try { - const fileError : string[] = []; - const listStateUploaded: UploadedFiles[] = []; - if (sharedFiles.length > 0) { - if (createGithubBranch) { - const isValid = await checkRepositoryValidityWithProperties(PublisherManager, prop, sharedFiles.length); - if (!isValid) return false; - await PublisherManager.newBranch(prop); - } - for (const sharedFile of sharedFiles) { - try { - statusBar.increment(); - const uploaded = await PublisherManager.publish( - sharedFile, - false, - monoRepo, - undefined, - undefined, - sourceFrontmatter, - ) ; - if (uploaded) { - listStateUploaded.push(...uploaded.uploaded); - } - } catch(e) { - fileError.push(sharedFile.name); - new Notice( - (i18next.t("error.unablePublishNote", {file: sharedFile.name}))); - logs({settings: PublisherManager.settings, e: true}, e); - } - } - statusBar.finish(8000); - const noticeValue = `${listStateUploaded.length} notes`; - const deleted = await deleteFromGithub( - true, - branchName, - PublisherManager, - monoRepo - ); - const settings = PublisherManager.settings; - if ( - settings.upload.metadataExtractorPath.length > 0 && - Platform.isDesktop - ) { - const metadataExtractor = await getSettingsOfMetadataExtractor( - PublisherManager.plugin.app, - settings - ); - if (metadataExtractor) { - await PublisherManager.uploadMetadataExtractorFiles( - metadataExtractor, - prop - ); - } - } - const update = await PublisherManager.updateRepository( - prop - ); - if (update) { - await publisherNotification( - PublisherManager, - noticeValue, - settings, - prop - ); - if (settings.plugin.displayModalRepoEditing) { - const listEdited = createListEdited(listStateUploaded, deleted, fileError); - new ListChangedFiles(PublisherManager.plugin.app, listEdited).open(); - } - } else { - notifError(prop); - } - } - } catch (error) { - logs({settings: PublisherManager.settings, e: true}, error); - const errorFrag = document.createDocumentFragment(); - errorFrag.createSpan({ cls: ["error", "obsidian-publisher", "icons", "notification"] }).innerHTML = ERROR_ICONS; - errorFrag.createSpan({ cls: ["error", "obsidian-publisher", "notification"], text: i18next.t("error.unablePublishMultiNotes") }); - statusBar.error(prop); - } -} - -/** - * Delete unshared/deleted in the repo - * @param {GithubBranch} PublisherManager - * @param {string} branchName - The branch name created by the plugin - * @param {MonoRepoProperties} monoRepo - The repo where to delete the files - * @returns {Promise} - */ -export async function purgeNotesRemote( - PublisherManager: GithubBranch, - branchName: string, - monoRepo: MonoRepoProperties, -): Promise { - try { - const noticeFragment = document.createDocumentFragment(); - noticeFragment.createSpan({ cls: ["obsidian-publisher", "notification"] }).innerHTML = i18next.t("informations.startingClean", { repo: monoRepo.frontmatter }); - new Notice( - noticeFragment - ); - const isValid = await checkRepositoryValidityWithProperties(PublisherManager, monoRepo.frontmatter); - if (!isValid) return false; - if (!PublisherManager.settings.github.dryRun.enable) - await PublisherManager.newBranch(monoRepo.frontmatter); - const deleted = await deleteFromGithub( - false, - branchName, - PublisherManager, - monoRepo - ); - if (!PublisherManager.settings.github.dryRun.enable) - await PublisherManager.updateRepository(monoRepo.frontmatter); - if (PublisherManager.settings.plugin.displayModalRepoEditing) new ListChangedFiles(PublisherManager.plugin.app, deleted).open(); - } catch (e) { - notif({settings: PublisherManager.settings, e: true}, e); - } -} - -/** - * Share only **one** note and their embedded contents, including note and attachments - * @param {string} branchName - The branch name created by the plugin - * @param {GithubBranch} PublisherManager - * @param {TFile} file - The file to share - * @param {Repository|null} repository - * @param {string} title The title from frontmatter + regex (if any) - * @returns {Promise} - */ -export async function shareOneNote( - PublisherManager: GithubBranch, - file: TFile, - repository: Repository | null = null, - sourceFrontmatter: FrontMatterCache | undefined | null, - title?: string, -): Promise { - const {settings, plugin} = PublisherManager; - const app = PublisherManager.plugin.app; - let frontmatter = frontmatterFromFile(file, PublisherManager.plugin, null); - if (sourceFrontmatter && frontmatter) frontmatter = merge(sourceFrontmatter, frontmatter); - try { - const prop = getProperties(plugin, repository, frontmatter); - let isValid: boolean; - if (prop instanceof Array) { - const isValidArray = []; - for (const repo of prop) { - isValidArray.push(await checkRepositoryValidityWithProperties(PublisherManager, repo)); - } - isValid = isValidArray.every((v) => v === true); - } else isValid = await checkRepositoryValidityWithProperties(PublisherManager, prop); - - const multiRepo: MultiRepoProperties = { - frontmatter: prop, - repository: repository - }; - if (!isValid) return false; - if (!settings.github.dryRun.enable) - await PublisherManager.newBranch(prop); - const publishSuccess = await PublisherManager.publish( - file, - true, - multiRepo, - [], - true, - sourceFrontmatter - ); - if (publishSuccess) { - if ( - settings.upload.metadataExtractorPath.length > 0 && - Platform.isDesktop - ) { - const metadataExtractor = await getSettingsOfMetadataExtractor( - app, - settings - ); - if (metadataExtractor) { - await PublisherManager.uploadMetadataExtractorFiles( - metadataExtractor, - prop - ); - } - } - const update = await PublisherManager.updateRepository( - prop, settings.github.dryRun.enable - ); - if (update) { - await publisherNotification( - PublisherManager, - title, - settings, - prop - ); - await createLink( - file, - multiRepo, - plugin - ); - if (settings.plugin.displayModalRepoEditing) { - const listEdited = createListEdited(publishSuccess.uploaded, publishSuccess.deleted, publishSuccess.error); - new ListChangedFiles(app, listEdited).open(); - } - - } else { - notifError(prop); - } - } - } catch (error) { - if (!(error instanceof DOMException)) { - logs({settings, e: true}, error); - notifError(getProperties(plugin, repository, frontmatter, true)); - } - } -} - -/** - * Deep scan the repository and send only the note that not exist in the repository - * @param {GithubBranch} PublisherManager - * @param {string} branchName - The branch name created by the plugin - * @param {MonoRepoProperties} monoRepo - The repo - * @returns {Promise} - */ -export async function shareNewNote( - PublisherManager: GithubBranch, - branchName: string, - monoRepo: MonoRepoProperties, -): Promise { - const plugin = PublisherManager.plugin; - new Notice(i18next.t("informations.scanningRepo") ); - const sharedFilesWithPaths = PublisherManager.getAllFileWithPath(monoRepo.repository, monoRepo.convert); - // Get all file in the repo before the creation of the branch - const githubSharedNotes = await PublisherManager.getAllFileFromRepo( - monoRepo.frontmatter.branch, // we need to take the master branch because the branch to create doesn't exist yet - monoRepo.frontmatter - ); - const newlySharedNotes = PublisherManager.getNewFiles( - sharedFilesWithPaths, - githubSharedNotes, - ); - if (newlySharedNotes.length > 0) { - new Notice( - (i18next.t("informations.foundNoteToSend", {nbNotes: newlySharedNotes.length}) - ) - ); - - const statusBarElement = plugin.addStatusBarItem(); - const isValid = await checkRepositoryValidityWithProperties(PublisherManager, monoRepo.frontmatter, newlySharedNotes.length); - if (!isValid) return false; - await PublisherManager.newBranch(monoRepo.frontmatter); - await shareAllMarkedNotes( - PublisherManager, - statusBarElement, - branchName, - monoRepo, - newlySharedNotes, - false, - ); - return; - } - new Notice(i18next.t("informations.noNewNote") ); -} - -/** - * Share edited notes : they exist on the repo, BUT the last edited time in Obsidian is after the last upload. Also share new notes. - * @param {GithubBranch} PublisherManager - * @param {string} branchName - The branch name created by the plugin - * @param {MonoRepoProperties} monoRepo - The repo - */ -export async function shareAllEditedNotes( - PublisherManager: GithubBranch, - branchName: string, - monoRepo: MonoRepoProperties, -) { - const plugin = PublisherManager.plugin; - new Notice(i18next.t("informations.scanningRepo") ); - const sharedFilesWithPaths = PublisherManager.getAllFileWithPath(monoRepo.repository, monoRepo.convert); - const githubSharedNotes = await PublisherManager.getAllFileFromRepo( - monoRepo.frontmatter.branch, - monoRepo.frontmatter - ); - const newSharedFiles = PublisherManager.getNewFiles( - sharedFilesWithPaths, - githubSharedNotes, - ); - const newlySharedNotes = await PublisherManager.getEditedFiles( - sharedFilesWithPaths, - githubSharedNotes, - newSharedFiles - ); - if (newlySharedNotes.length > 0) { - new Notice( - (i18next.t("informations.foundNoteToSend", {nbNotes: newlySharedNotes.length}) - ) - ); - - const statusBarElement = plugin.addStatusBarItem(); - const isValid = await checkRepositoryValidityWithProperties(PublisherManager, monoRepo.frontmatter, newlySharedNotes.length); - if (!isValid) return false; - await PublisherManager.newBranch(monoRepo.frontmatter); - await shareAllMarkedNotes( - PublisherManager, - statusBarElement, - branchName, - monoRepo, - newlySharedNotes, - false, - ); - return; - } - new Notice(i18next.t("informations.noNewNote") ); -} - -/** - * share **only** edited notes : they exist on the repo, but the last edited time is after the last upload. - * @param {GithubBranch} PublisherManager - * @param {string} branchName - The branch name created by the plugin - * @param {MonoRepoProperties} monoRepo - The repo - */ -export async function shareOnlyEdited( - PublisherManager: GithubBranch, - branchName: string, - monoRepo: MonoRepoProperties, -) { - const shortRepo = monoRepo.repository; - const prop = monoRepo.frontmatter; - new Notice(i18next.t("informations.scanningRepo") ); - const sharedFilesWithPaths = PublisherManager.getAllFileWithPath(shortRepo, monoRepo.convert); - const githubSharedNotes = await PublisherManager.getAllFileFromRepo( - prop.branch, - prop - ); - const newSharedFiles: TFile[] = []; - const newlySharedNotes = await PublisherManager.getEditedFiles( - sharedFilesWithPaths, - githubSharedNotes, - newSharedFiles - ); - if (newlySharedNotes.length > 0) { - new Notice( - (i18next.t("informations.foundNoteToSend", {nbNotes: newlySharedNotes.length})) - ); - const statusBarElement = PublisherManager.plugin.addStatusBarItem(); - const isValid = await checkRepositoryValidityWithProperties(PublisherManager, prop, newlySharedNotes.length); - if (!isValid) return false; - await PublisherManager.newBranch(prop); - await shareAllMarkedNotes( - PublisherManager, - statusBarElement, - branchName, - monoRepo, - newlySharedNotes, - false, - ); - return; - } - new Notice(i18next.t("informations.noNewNote") ); -} - - +import { createLinkCallback, createLinkOnActiveFile } from "./create_link"; +import { purgeCallback,purgeForRepo } from "./purge"; +import { checkRepositoryValidityCallback, repositoryValidityActiveFile } from "./repository_validity"; +import { refreshAllSets, refreshOpenedSet } from "./set"; +import { shareAllMarkedNotes, uploadAllNotes, uploadAllNotesCallback } from "./share/all_notes"; +import { shareEditedOnly, shareEditedOnlyCallback, uploadAllEditedNotes, uploadAllEditedNotesCallback } from "./share/edited_notes"; +import { uploadNewNotes, uploadNewNotesCallback } from "./share/new_notes"; +import { shareActiveFile, shareOneNote, shareOneNoteCallback } from "./share/unique_note"; + +export { + checkRepositoryValidityCallback, + createLinkCallback, + createLinkOnActiveFile, + purgeForRepo as deleteCommands, + purgeCallback as purgeNotesRemoteCallback, + refreshAllSets, + refreshOpenedSet, + repositoryValidityActiveFile, + shareActiveFile, + shareAllMarkedNotes, + shareEditedOnly, + shareEditedOnlyCallback, + shareOneNote, + shareOneNoteCallback, + uploadAllEditedNotes, + uploadAllEditedNotesCallback, + uploadAllNotes, + uploadAllNotesCallback, + uploadNewNotes,uploadNewNotesCallback}; \ No newline at end of file diff --git a/src/commands/plugin_commands.ts b/src/commands/plugin_commands.ts deleted file mode 100644 index 8407832c..00000000 --- a/src/commands/plugin_commands.ts +++ /dev/null @@ -1,215 +0,0 @@ -/** - * @file src/commands/plugin_commands.ts - * @description Contains all the commands that are used by the plugin ; used in suggest_other_repo_command.ts - */ - -import i18next from "i18next"; -import { Notice } from "obsidian"; - -import {MonoRepoProperties, MultiRepoProperties, Repository} from "../interfaces"; -import GithubPublisher from "../main"; -import {createLink} from "../utils"; -import {checkRepositoryValidity, isShared} from "../utils/data_validation_test"; -import { frontmatterFromFile, frontmatterSettingsRepository, getProperties } from "../utils/parse_frontmatter"; -import { - purgeNotesRemote, - shareAllEditedNotes, - shareAllMarkedNotes, - shareNewNote, - shareOneNote, shareOnlyEdited -} from "."; - -/** - * Create the command to create a link to the note in the repo if a file is active ; else do nothing - * @call createLink - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {GithubPublisher} plugin - The plugin instance - * @return {Promise} - */ -export async function createLinkOnActiveFile(repo: Repository | null, plugin: GithubPublisher): Promise { - const file = plugin.app.workspace.getActiveFile(); - const frontmatter = frontmatterFromFile(file, plugin, repo); - - if ( - file && frontmatter && isShared(frontmatter, plugin.settings, file, repo) - ) { - const multiRepo: MultiRepoProperties = { - frontmatter: getProperties(plugin, repo, frontmatter), - repository: repo - }; - await createLink( - file, - multiRepo, - plugin - ); - new Notice(i18next.t("commands.copyLink.onActivation")); - return; - } - new Notice(i18next.t("commands.runOtherRepo.noFile")); -} - -/** - * Command to shareTheActiveFile ; Return an error if no file is active - * @call shareOneNote - * @param {GithubPublisher} plugin - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {string} branchName - * @return {Promise} - */ -export async function shareActiveFile(plugin: GithubPublisher, repo: Repository | null): Promise { - const file = plugin.app.workspace.getActiveFile(); - const frontmatter = frontmatterFromFile(file, plugin, repo); - if (file && frontmatter && isShared(frontmatter, plugin.settings, file, repo)) { - await shareOneNote( - await plugin.reloadOctokit(repo?.smartKey), - file, - repo, - frontmatter, - ); - } else { - new Notice(i18next.t("commands.runOtherRepo.noFile")); - } -} - - -/** - * Command to delete the files - * @param {GithubPublisher} plugin - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {string} branchName - * @return {Promise} - */ -export async function deleteCommands(plugin : GithubPublisher, repo: Repository | null, branchName: string): Promise { - const prop = getProperties(plugin, repo, null, true); - const publisher = await plugin.reloadOctokit(repo?.smartKey); - const mono: MonoRepoProperties = { - frontmatter: Array.isArray(prop) ? prop[0] : prop, - repository: repo, - convert: frontmatterSettingsRepository(plugin, repo) - }; - await purgeNotesRemote( - publisher, - branchName, - mono - ); -} - -/** - * Command to share all the notes - * @call shareAllMarkedNotes - * @param {GithubPublisher} plugin - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {string} branchName - * @return {Promise} - */ - -export async function uploadAllNotes(plugin: GithubPublisher, repo: Repository | null, branchName: string): Promise { - const statusBarItems = plugin.addStatusBarItem(); - const publisher = await plugin.reloadOctokit(repo?.smartKey); - const sharedFiles = publisher.getSharedFiles(repo); - const prop = getProperties(plugin, repo, undefined, true); - const mono: MonoRepoProperties = { - frontmatter: Array.isArray(prop) ? prop[0] : prop, - repository: repo, - convert: frontmatterSettingsRepository( - plugin, - repo - ) - }; - await shareAllMarkedNotes( - publisher, - statusBarItems, - branchName, - mono, - sharedFiles, - true, - ); -} - -/** - * Command to share the new notes - * @call shareNewNote - * @param {GithubPublisher} plugin - * @param {string} branchName - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @return {Promise} - */ - -export async function uploadNewNotes(plugin: GithubPublisher, branchName: string, repo: Repository|null): Promise { - const publisher = await plugin.reloadOctokit(repo?.smartKey); - const prop = getProperties(plugin, repo, null, true); - await shareNewNote( - publisher, - branchName, - { - frontmatter: Array.isArray(prop) ? prop[0] : prop, - repository: repo, - convert: frontmatterSettingsRepository(plugin, repo) - }, - ); -} - -/** - * Command to check the validity of the repository - * @call checkRepositoryValidity - * @param {GithubPublisher} plugin - * @param {string} branchName - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @return {Promise} - */ -export async function repositoryValidityActiveFile(plugin:GithubPublisher, repo: Repository | null): Promise { - const file = plugin.app.workspace.getActiveFile(); - if (file) { - await checkRepositoryValidity( - await plugin.reloadOctokit(repo?.smartKey), - repo, - file, - ); - } else { - new Notice("No file is active"); - } -} - -/** - * Upload all the edited notes (including the new ones) - * @param {GithubPublisher} plugin - * @param {string} branchName - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @return {Promise} - */ -export async function uploadAllEditedNotes(plugin: GithubPublisher ,branchName: string, repo: Repository|null=null): Promise { - const publisher = await plugin.reloadOctokit(repo?.smartKey); - const prop = getProperties(plugin, repo, null, true); - - await shareAllEditedNotes( - publisher, - branchName, - { - frontmatter: Array.isArray(prop) ? prop[0] : prop, - repository: repo, - convert: frontmatterSettingsRepository(plugin, repo) - }, - ); -} - -/** - * Share only the edited notes - * @call shareOnlyEdited - * @param {string} branchName - * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts - * @param {GithubPublisher} plugin - * @return {Promise} - */ -export async function shareEditedOnly(branchName: string, repo: Repository|null, plugin: GithubPublisher): Promise { - const publisher = await plugin.reloadOctokit(repo?.smartKey); - const prop = getProperties(plugin, repo, null, true); - await shareOnlyEdited( - publisher, - branchName, - { - frontmatter: Array.isArray(prop) ? prop[0] : prop, - repository: repo, - convert: frontmatterSettingsRepository(plugin, repo) - }, - ); -} diff --git a/src/commands/purge.ts b/src/commands/purge.ts new file mode 100644 index 00000000..2e4d8bad --- /dev/null +++ b/src/commands/purge.ts @@ -0,0 +1,102 @@ +import { MonoRepoProperties,Repository } from "@interfaces"; +import i18next from "i18next"; +import { Command, Notice } from "obsidian"; +import { GithubBranch } from "src/GitHub/branch"; +import { deleteFromGithub } from "src/GitHub/delete"; +import GithubPublisher from "src/main"; +import { ListChangedFiles } from "src/settings/modals/list_changed"; +import { notif } from "src/utils"; +import { checkRepositoryValidityWithProperties } from "src/utils/data_validation_test"; +import { frontmatterSettingsRepository,getProperties } from "src/utils/parse_frontmatter"; + +/** + * Command to delete file on the repo + * @call purgeNotesRemote + * @param {GithubPublisher} plugin - The plugin instance + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {string} branchName - The branch name to delete the file + * @return {Promise} + */ +export async function purgeCallback(plugin: GithubPublisher, repo: Repository | null, branchName: string): Promise { + const id = repo ? `delete-clean-K${repo.smartKey}` : "delete-clean"; + let name = i18next.t("commands.publisherDeleteClean"); + const common = i18next.t("common.repository"); + name = repo ? `${name} (${common} : ${repo.smartKey})` : name; + return { + id, + name, + hotkeys: [], + callback: async () => { + const frontmatter = getProperties(plugin, repo, undefined, true); + const monoRepo: MonoRepoProperties = { + frontmatter: Array.isArray(frontmatter) ? frontmatter[0] : frontmatter, + repository: repo, + convert: frontmatterSettingsRepository(plugin, repo) + }; + const publisher = await plugin.reloadOctokit(repo?.smartKey); + await purge( + publisher, + branchName, + monoRepo + ); + }, + } as Command; +} + +/** + * Delete unshared/deleted in the repo + * @param {GithubBranch} PublisherManager + * @param {string} branchName - The branch name created by the plugin + * @param {MonoRepoProperties} monoRepo - The repo where to delete the files + * @returns {Promise} + */ +async function purge( + PublisherManager: GithubBranch, + branchName: string, + monoRepo: MonoRepoProperties, +): Promise { + try { + const noticeFragment = document.createDocumentFragment(); + noticeFragment.createSpan({ cls: ["obsidian-publisher", "notification"] }).innerHTML = i18next.t("informations.startingClean", { repo: monoRepo.frontmatter }); + new Notice( + noticeFragment + ); + const isValid = await checkRepositoryValidityWithProperties(PublisherManager, monoRepo.frontmatter); + if (!isValid) return false; + if (!PublisherManager.settings.github.dryRun.enable) + await PublisherManager.newBranch(monoRepo.frontmatter); + const deleted = await deleteFromGithub( + false, + branchName, + PublisherManager, + monoRepo + ); + if (!PublisherManager.settings.github.dryRun.enable) + await PublisherManager.updateRepository(monoRepo.frontmatter); + if (PublisherManager.settings.plugin.displayModalRepoEditing) new ListChangedFiles(PublisherManager.plugin.app, deleted).open(); + } catch (e) { + notif({settings: PublisherManager.settings, e: true}, e); + } +} + +/** + * Command to delete the files + * @param {GithubPublisher} plugin + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {string} branchName + * @return {Promise} + */ +export async function purgeForRepo(plugin : GithubPublisher, repo: Repository | null, branchName: string): Promise { + const prop = getProperties(plugin, repo, null, true); + const publisher = await plugin.reloadOctokit(repo?.smartKey); + const mono: MonoRepoProperties = { + frontmatter: Array.isArray(prop) ? prop[0] : prop, + repository: repo, + convert: frontmatterSettingsRepository(plugin, repo) + }; + await purge( + publisher, + branchName, + mono + ); +} diff --git a/src/commands/repository_validity.ts b/src/commands/repository_validity.ts new file mode 100644 index 00000000..22fc8fcb --- /dev/null +++ b/src/commands/repository_validity.ts @@ -0,0 +1,58 @@ +import { Repository } from "@interfaces"; +import i18next from "i18next"; +import { Command, Notice } from "obsidian"; +import GithubPublisher from "src/main"; +import { checkRepositoryValidity } from "src/utils/data_validation_test"; + +/** + * Command to check the validity of the repository + * @call checkRepositoryValidity + * @param {GithubPublisher} plugin + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @return {Promise} + */ +export async function repositoryValidityActiveFile(plugin:GithubPublisher, repo: Repository | null): Promise { + const file = plugin.app.workspace.getActiveFile(); + if (file) { + await checkRepositoryValidity( + await plugin.reloadOctokit(repo?.smartKey), + repo, + file, + ); + } else { + new Notice("No file is active"); + } +} + +/** + * Check if the repository is valid + * @param {GithubPublisher} plugin + * @param {Repository} repo + * @return {Promise} + */ + +export async function checkRepositoryValidityCallback(plugin: GithubPublisher, repo: Repository | null): Promise { + const id = repo ? `check-plugin-repo-validy-K${repo.smartKey}` : "check-plugin-repo-validy"; + let name = i18next.t("commands.checkValidity.title"); + const common = i18next.t("common.repository"); + name = repo ? `${name} (${common} : ${repo.smartKey})` : name; + const octokit = await plugin.reloadOctokit(repo?.smartKey); + return { + id, + name, + checkCallback: (checking) => { + if (plugin.app.workspace.getActiveFile()) + { + if (!checking) { + checkRepositoryValidity( + octokit, + repo, + plugin.app.workspace.getActiveFile() + ); + } + return true; + } + return false; + }, + } as Command; +} diff --git a/src/commands/set.ts b/src/commands/set.ts new file mode 100644 index 00000000..1df50d83 --- /dev/null +++ b/src/commands/set.ts @@ -0,0 +1,50 @@ +import i18next from "i18next"; +import { Command,TFile } from "obsidian"; +import GithubPublisher from "src/main"; + +export function refreshOpenedSet(plugin: GithubPublisher) { + const findRepo= (file: TFile | null) => { + if (!file) return []; + return plugin.settings.github.otherRepo.filter((repo) => repo.set === file.path); + }; + + return { + id: "reload-opened-set", + name: i18next.t("commands.refreshOpenedSet"), + checkCallback: (checking) => { + const file = plugin.app.workspace.getActiveFile(); + const repos = findRepo(file); + if (file && repos.length > 0) { + if (!checking) { + repos.forEach((repo) => { + plugin.repositoryFrontmatter[repo.smartKey] = plugin.app.metadataCache.getFileCache(file)?.frontmatter; + }); + } + return true; + } + return false; + }, + } as Command; +} + +export function refreshAllSets(plugin: GithubPublisher) { + return { + id: "reload-all-sets", + name: i18next.t("commands.refreshAllSets"), + checkCallback: (checking) => { + const allSets = plugin.settings.github.otherRepo.filter((repo) => repo.set !== "" || repo.set !== null); + if (allSets.length > 0) { + if (!checking) { + allSets.forEach((repo) => { + if (!repo.set) return; + const file = plugin.app.vault.getAbstractFileByPath(repo.set); + if (!file || !(file instanceof TFile)) return; + plugin.repositoryFrontmatter[repo.smartKey] = plugin.app.metadataCache.getFileCache(file)?.frontmatter; + }); + } + return true; + } + return false; + } + } as Command; +} diff --git a/src/commands/share/all_notes.ts b/src/commands/share/all_notes.ts new file mode 100644 index 00000000..aa22f357 --- /dev/null +++ b/src/commands/share/all_notes.ts @@ -0,0 +1,167 @@ +import { MonoRepoProperties, Repository, UploadedFiles } from "@interfaces"; +import { ERROR_ICONS } from "@interfaces/icons"; +import i18next from "i18next"; +import { Command, FrontMatterCache, Notice, Platform, TFile } from "obsidian"; +import { GithubBranch } from "src/GitHub/branch"; +import { deleteFromGithub } from "src/GitHub/delete"; +import GithubPublisher from "src/main"; +import { ListChangedFiles } from "src/settings/modals/list_changed"; +import { createListEdited, getSettingsOfMetadataExtractor, logs, notifError,publisherNotification } from "src/utils"; +import { checkRepositoryValidityWithProperties } from "src/utils/data_validation_test"; +import { frontmatterSettingsRepository,getProperties } from "src/utils/parse_frontmatter"; +import { ShareStatusBar } from "src/utils/status_bar"; + +/** + * Upload all note + * @call uploadAllNotes + * @param plugin {GithubPublisher} - The plugin instance + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {string} branchName - The branch name to upload the file + * @return {Promise} + */ +export async function uploadAllNotesCallback(plugin: GithubPublisher, repo: Repository|null, branchName: string): Promise { + const id = repo ? `publish-all-K${repo.smartKey}` : "publish-all"; + let name = i18next.t("commands.uploadAllNotes"); + const common = i18next.t("common.repository"); + name = repo ? `${name} (${common} : ${repo.smartKey})` : name; + return { + id, + name, + callback: async () => { + await uploadAllNotes(plugin,repo, branchName); + }, + } as Command; +} +/** + * Command to share all the notes + * @call shareAllMarkedNotes + * @param {GithubPublisher} plugin + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {string} branchName + * @return {Promise} + */ + +export async function uploadAllNotes(plugin: GithubPublisher, repo: Repository | null, branchName: string): Promise { + const statusBarItems = plugin.addStatusBarItem(); + const publisher = await plugin.reloadOctokit(repo?.smartKey); + const sharedFiles = publisher.getSharedFiles(repo); + const prop = getProperties(plugin, repo, undefined, true); + const mono: MonoRepoProperties = { + frontmatter: Array.isArray(prop) ? prop[0] : prop, + repository: repo, + convert: frontmatterSettingsRepository( + plugin, + repo + ) + }; + await shareAllMarkedNotes( + publisher, + statusBarItems, + branchName, + mono, + sharedFiles, + true, + ); +} + +/** + * Share all marked note (share: true) from Obsidian to GitHub + * @param {GithubBranch} PublisherManager + * @param {HTMLElement} statusBarItems - The status bar element + * @param {string} branchName - The branch name created by the plugin + * @param {MonoRepoProperties} monoRepo - The repo where to share the files + * @param {TFile[]} sharedFiles - The files to share + * @param {boolean} createGithubBranch - If true, create the branch before sharing the files + */ +export async function shareAllMarkedNotes( + PublisherManager: GithubBranch, + statusBarItems: HTMLElement, + branchName: string, + monoRepo: MonoRepoProperties, + sharedFiles: TFile[], + createGithubBranch: boolean = true, + sourceFrontmatter: FrontMatterCache | undefined | null = null, +) { + const statusBar = new ShareStatusBar(statusBarItems, sharedFiles.length); + const prop = monoRepo.frontmatter; + try { + const fileError : string[] = []; + const listStateUploaded: UploadedFiles[] = []; + if (sharedFiles.length > 0) { + if (createGithubBranch) { + const isValid = await checkRepositoryValidityWithProperties(PublisherManager, prop, sharedFiles.length); + if (!isValid) return false; + await PublisherManager.newBranch(prop); + } + for (const sharedFile of sharedFiles) { + try { + statusBar.increment(); + const uploaded = await PublisherManager.publish( + sharedFile, + false, + monoRepo, + undefined, + undefined, + sourceFrontmatter, + ) ; + if (uploaded) { + listStateUploaded.push(...uploaded.uploaded); + } + } catch(e) { + fileError.push(sharedFile.name); + new Notice( + (i18next.t("error.unablePublishNote", {file: sharedFile.name}))); + logs({settings: PublisherManager.settings, e: true}, e); + } + } + statusBar.finish(8000); + const noticeValue = `${listStateUploaded.length} notes`; + const deleted = await deleteFromGithub( + true, + branchName, + PublisherManager, + monoRepo + ); + const settings = PublisherManager.settings; + if ( + settings.upload.metadataExtractorPath.length > 0 && + Platform.isDesktop + ) { + const metadataExtractor = await getSettingsOfMetadataExtractor( + PublisherManager.plugin.app, + settings + ); + if (metadataExtractor) { + await PublisherManager.uploadMetadataExtractorFiles( + metadataExtractor, + prop + ); + } + } + const update = await PublisherManager.updateRepository( + prop + ); + if (update) { + await publisherNotification( + PublisherManager, + noticeValue, + settings, + prop + ); + if (settings.plugin.displayModalRepoEditing) { + const listEdited = createListEdited(listStateUploaded, deleted, fileError); + new ListChangedFiles(PublisherManager.plugin.app, listEdited).open(); + } + } else { + notifError(prop); + } + } + } catch (error) { + logs({settings: PublisherManager.settings, e: true}, error); + const errorFrag = document.createDocumentFragment(); + errorFrag.createSpan({ cls: ["error", "obsidian-publisher", "icons", "notification"] }).innerHTML = ERROR_ICONS; + errorFrag.createSpan({ cls: ["error", "obsidian-publisher", "notification"], text: i18next.t("error.unablePublishMultiNotes") }); + statusBar.error(prop); + } +} + diff --git a/src/commands/share/edited_notes.ts b/src/commands/share/edited_notes.ts new file mode 100644 index 00000000..64242076 --- /dev/null +++ b/src/commands/share/edited_notes.ts @@ -0,0 +1,195 @@ +import { MonoRepoProperties, Repository } from "@interfaces"; +import i18next from "i18next"; +import { Command, Notice, TFile } from "obsidian"; +import { GithubBranch } from "src/GitHub/branch"; +import GithubPublisher from "src/main"; +import { checkRepositoryValidityWithProperties } from "src/utils/data_validation_test"; +import { frontmatterSettingsRepository,getProperties } from "src/utils/parse_frontmatter"; + +import { shareAllMarkedNotes } from "./all_notes"; + +/** + * Share all edited note + * @call uploadAllEditedNotes + * @param plugin + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {string} branchName + * @return {Promise} + */ +export async function uploadAllEditedNotesCallback(plugin: GithubPublisher, repo: Repository|null, branchName: string): Promise { + const id = repo ? `upload-all-edited-new-K${repo.smartKey}` : "upload-all-edited-new"; + let name = i18next.t("commands.uploadAllNewEditedNote"); + const common = i18next.t("common.repository"); + name = repo ? `${name} (${common} : ${repo.smartKey})` : name; + return { + id, + name, + callback: async () => { + await uploadAllEditedNotes(plugin, branchName, repo); + }, + } as Command; +} + +/** + * Upload all the edited notes (including the new ones) + * @param {GithubPublisher} plugin + * @param {string} branchName + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @return {Promise} + */ +export async function uploadAllEditedNotes(plugin: GithubPublisher ,branchName: string, repo: Repository|null=null): Promise { + const publisher = await plugin.reloadOctokit(repo?.smartKey); + const prop = getProperties(plugin, repo, null, true); + + await shareAllEditedNotes( + publisher, + branchName, + { + frontmatter: Array.isArray(prop) ? prop[0] : prop, + repository: repo, + convert: frontmatterSettingsRepository(plugin, repo) + }, + ); +} + +/** + * Share edited notes : they exist on the repo, BUT the last edited time in Obsidian is after the last upload. Also share new notes. + * @param {GithubBranch} PublisherManager + * @param {string} branchName - The branch name created by the plugin + * @param {MonoRepoProperties} monoRepo - The repo + */ +async function shareAllEditedNotes( + PublisherManager: GithubBranch, + branchName: string, + monoRepo: MonoRepoProperties, +) { + const plugin = PublisherManager.plugin; + new Notice(i18next.t("informations.scanningRepo") ); + const sharedFilesWithPaths = PublisherManager.getAllFileWithPath(monoRepo.repository, monoRepo.convert); + const githubSharedNotes = await PublisherManager.getAllFileFromRepo( + monoRepo.frontmatter.branch, + monoRepo.frontmatter + ); + const newSharedFiles = PublisherManager.getNewFiles( + sharedFilesWithPaths, + githubSharedNotes, + ); + const newlySharedNotes = await PublisherManager.getEditedFiles( + sharedFilesWithPaths, + githubSharedNotes, + newSharedFiles + ); + if (newlySharedNotes.length > 0) { + new Notice( + (i18next.t("informations.foundNoteToSend", {nbNotes: newlySharedNotes.length}) + ) + ); + + const statusBarElement = plugin.addStatusBarItem(); + const isValid = await checkRepositoryValidityWithProperties(PublisherManager, monoRepo.frontmatter, newlySharedNotes.length); + if (!isValid) return false; + await PublisherManager.newBranch(monoRepo.frontmatter); + await shareAllMarkedNotes( + PublisherManager, + statusBarElement, + branchName, + monoRepo, + newlySharedNotes, + false, + ); + return; + } + new Notice(i18next.t("informations.noNewNote") ); +} + + +/** +* share **only** edited notes : they exist on the repo, but the last edited time is after the last upload. +* @param {GithubBranch} PublisherManager +* @param {string} branchName - The branch name created by the plugin +* @param {MonoRepoProperties} monoRepo - The repo +*/ +async function shareOnlyEdited( + PublisherManager: GithubBranch, + branchName: string, + monoRepo: MonoRepoProperties, +) { + const shortRepo = monoRepo.repository; + const prop = monoRepo.frontmatter; + new Notice(i18next.t("informations.scanningRepo") ); + const sharedFilesWithPaths = PublisherManager.getAllFileWithPath(shortRepo, monoRepo.convert); + const githubSharedNotes = await PublisherManager.getAllFileFromRepo( + prop.branch, + prop + ); + const newSharedFiles: TFile[] = []; + const newlySharedNotes = await PublisherManager.getEditedFiles( + sharedFilesWithPaths, + githubSharedNotes, + newSharedFiles + ); + if (newlySharedNotes.length > 0) { + new Notice( + (i18next.t("informations.foundNoteToSend", {nbNotes: newlySharedNotes.length})) + ); + const statusBarElement = PublisherManager.plugin.addStatusBarItem(); + const isValid = await checkRepositoryValidityWithProperties(PublisherManager, prop, newlySharedNotes.length); + if (!isValid) return false; + await PublisherManager.newBranch(prop); + await shareAllMarkedNotes( + PublisherManager, + statusBarElement, + branchName, + monoRepo, + newlySharedNotes, + false, + ); + return; + } + new Notice(i18next.t("informations.noNewNote") ); +} + +/** + * Share only the edited notes + * @call shareOnlyEdited + * @param {string} branchName + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {GithubPublisher} plugin + * @return {Promise} + */ +export async function shareEditedOnly(branchName: string, repo: Repository|null, plugin: GithubPublisher): Promise { + const publisher = await plugin.reloadOctokit(repo?.smartKey); + const prop = getProperties(plugin, repo, null, true); + await shareOnlyEdited( + publisher, + branchName, + { + frontmatter: Array.isArray(prop) ? prop[0] : prop, + repository: repo, + convert: frontmatterSettingsRepository(plugin, repo) + }, + ); +} + + +/** + * Share edited note only + * @call shareEditedOnly + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {string} branchName + * @param {GithubPublisher} plugin + * @return {Promise} + */ +export async function shareEditedOnlyCallback(repo: Repository|null, branchName: string, plugin: GithubPublisher): Promise { + const id = repo ? `upload-edited-K${repo.smartKey}` : "upload-edited"; + let name = i18next.t("commands.uploadAllEditedNote"); + const common = i18next.t("common.repository"); + name = repo ? `${name} (${common} : ${repo.smartKey})` : name; + return { + id, + name, + callback: async () => { + await shareEditedOnly(branchName, repo, plugin); + }, + } as Command; +} \ No newline at end of file diff --git a/src/commands/share/new_notes.ts b/src/commands/share/new_notes.ts new file mode 100644 index 00000000..dfed43c7 --- /dev/null +++ b/src/commands/share/new_notes.ts @@ -0,0 +1,100 @@ +import { MonoRepoProperties, Repository } from "@interfaces"; +import i18next from "i18next"; +import { Command, Notice } from "obsidian"; +import { shareAllMarkedNotes } from "src/commands"; +import { GithubBranch } from "src/GitHub/branch"; +import GithubPublisher from "src/main"; +import { checkRepositoryValidityWithProperties } from "src/utils/data_validation_test"; +import { frontmatterSettingsRepository,getProperties } from "src/utils/parse_frontmatter"; + +/** + * Upload all new notes only + * @param plugin {GithubPublisher} - The plugin instance + * @param repo {Repository | null} - Other repo if the command is called from the suggest_other_repo_command.ts + * @param branchName {string} - The branch name to upload the file + * @returns {Promise} + */ +export async function uploadNewNotesCallback(plugin: GithubPublisher, repo: Repository | null, branchName: string): Promise { + const id = repo ? `upload-new-K${repo.smartKey}` : "upload-new"; + let name = i18next.t("commands.uploadNewNotes"); + const common = i18next.t("common.repository"); + name = repo ? `${name} (${common} : ${repo.smartKey})` : name; + return { + id, + name, + callback: async () => { + await uploadNewNotes(plugin,branchName, repo); + }, + } as Command; +} + +/** + * Command to share the new notes + * @call shareNewNote + * @param {GithubPublisher} plugin + * @param {string} branchName + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @return {Promise} + */ + +export async function uploadNewNotes(plugin: GithubPublisher, branchName: string, repo: Repository|null): Promise { + const publisher = await plugin.reloadOctokit(repo?.smartKey); + const prop = getProperties(plugin, repo, null, true); + await shareNewNote( + publisher, + branchName, + { + frontmatter: Array.isArray(prop) ? prop[0] : prop, + repository: repo, + convert: frontmatterSettingsRepository(plugin, repo) + }, + ); +} + + +/** + * Deep scan the repository and send only the note that not exist in the repository + * @param {GithubBranch} PublisherManager + * @param {string} branchName - The branch name created by the plugin + * @param {MonoRepoProperties} monoRepo - The repo + * @returns {Promise} + */ +export async function shareNewNote( + PublisherManager: GithubBranch, + branchName: string, + monoRepo: MonoRepoProperties, +): Promise { + const plugin = PublisherManager.plugin; + new Notice(i18next.t("informations.scanningRepo") ); + const sharedFilesWithPaths = PublisherManager.getAllFileWithPath(monoRepo.repository, monoRepo.convert); + // Get all file in the repo before the creation of the branch + const githubSharedNotes = await PublisherManager.getAllFileFromRepo( + monoRepo.frontmatter.branch, // we need to take the master branch because the branch to create doesn't exist yet + monoRepo.frontmatter + ); + const newlySharedNotes = PublisherManager.getNewFiles( + sharedFilesWithPaths, + githubSharedNotes, + ); + if (newlySharedNotes.length > 0) { + new Notice( + (i18next.t("informations.foundNoteToSend", {nbNotes: newlySharedNotes.length}) + ) + ); + + const statusBarElement = plugin.addStatusBarItem(); + const isValid = await checkRepositoryValidityWithProperties(PublisherManager, monoRepo.frontmatter, newlySharedNotes.length); + if (!isValid) return false; + await PublisherManager.newBranch(monoRepo.frontmatter); + await shareAllMarkedNotes( + PublisherManager, + statusBarElement, + branchName, + monoRepo, + newlySharedNotes, + false, + ); + return; + } + new Notice(i18next.t("informations.noNewNote") ); +} \ No newline at end of file diff --git a/src/commands/share/unique_note.ts b/src/commands/share/unique_note.ts new file mode 100644 index 00000000..0e637353 --- /dev/null +++ b/src/commands/share/unique_note.ts @@ -0,0 +1,166 @@ +import { MultiRepoProperties, Repository } from "@interfaces"; +import i18next from "i18next"; +import { Command, FrontMatterCache, Notice, Platform, TFile } from "obsidian"; +import { GithubBranch } from "src/GitHub/branch"; +import GithubPublisher from "src/main"; +import { ListChangedFiles } from "src/settings/modals/list_changed"; +import { createLink, createListEdited, getSettingsOfMetadataExtractor, logs,notifError, publisherNotification } from "src/utils"; +import { checkRepositoryValidityWithProperties, isShared } from "src/utils/data_validation_test"; +import { frontmatterFromFile, getProperties } from "src/utils/parse_frontmatter"; +import merge from "ts-deepmerge"; + +/** + * Command to upload the active file ; use checkCallback to check if the file is shared and if they are a active file + * @call shareOneNote + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {GithubPublisher} plugin - The plugin instance + * @return {Promise} + */ +export async function shareOneNoteCallback(repo: Repository|null, plugin: GithubPublisher): Promise { + const id = repo ? `share-one-K${repo.smartKey}` : "share-one"; + let name = i18next.t("commands.shareActiveFile"); + const common = i18next.t("common.repository"); + name = repo ? `${name} (${common} : ${repo.smartKey})` : name; + const octokit = await plugin.reloadOctokit(repo?.smartKey); + return { + id, + name, + hotkeys: [], + checkCallback: (checking) => { + const file = plugin.app.workspace.getActiveFile(); + const frontmatter = frontmatterFromFile(file, plugin, repo); + if ( + file && frontmatter && isShared(frontmatter, plugin.settings, file, repo) + ) { + if (!checking) { + shareOneNote( + octokit, + file, + repo, + frontmatter, + file.basename, + ); + } + return true; + } + return false; + }, + } as Command; +} + + +/** + * Share only **one** note and their embedded contents, including note and attachments + * @param {GithubBranch} PublisherManager + * @param {TFile} file - The file to share + * @param {Repository|null} repository + * @param {string} title The title from frontmatter + regex (if any) + * @returns {Promise} + */ +export async function shareOneNote( + PublisherManager: GithubBranch, + file: TFile, + repository: Repository | null = null, + sourceFrontmatter: FrontMatterCache | undefined | null, + title?: string, +): Promise { + const {settings, plugin} = PublisherManager; + const app = PublisherManager.plugin.app; + let frontmatter = frontmatterFromFile(file, PublisherManager.plugin, null); + if (sourceFrontmatter && frontmatter) frontmatter = merge(sourceFrontmatter, frontmatter); + try { + const prop = getProperties(plugin, repository, frontmatter); + let isValid: boolean; + if (prop instanceof Array) { + const isValidArray = []; + for (const repo of prop) { + isValidArray.push(await checkRepositoryValidityWithProperties(PublisherManager, repo)); + } + isValid = isValidArray.every((v) => v === true); + } else isValid = await checkRepositoryValidityWithProperties(PublisherManager, prop); + + const multiRepo: MultiRepoProperties = { + frontmatter: prop, + repository: repository + }; + if (!isValid) return false; + if (!settings.github.dryRun.enable) + await PublisherManager.newBranch(prop); + const publishSuccess = await PublisherManager.publish( + file, + true, + multiRepo, + [], + true, + sourceFrontmatter + ); + if (publishSuccess) { + if ( + settings.upload.metadataExtractorPath.length > 0 && + Platform.isDesktop + ) { + const metadataExtractor = await getSettingsOfMetadataExtractor( + app, + settings + ); + if (metadataExtractor) { + await PublisherManager.uploadMetadataExtractorFiles( + metadataExtractor, + prop + ); + } + } + const update = await PublisherManager.updateRepository( + prop, settings.github.dryRun.enable + ); + if (update) { + await publisherNotification( + PublisherManager, + title, + settings, + prop + ); + await createLink( + file, + multiRepo, + plugin + ); + if (settings.plugin.displayModalRepoEditing) { + const listEdited = createListEdited(publishSuccess.uploaded, publishSuccess.deleted, publishSuccess.error); + new ListChangedFiles(app, listEdited).open(); + } + + } else { + notifError(prop); + } + } + } catch (error) { + if (!(error instanceof DOMException)) { + logs({settings, e: true}, error); + notifError(getProperties(plugin, repository, frontmatter, true)); + } + } +} + +/** + * Command to shareTheActiveFile ; Return an error if no file is active + * @call shareOneNote + * @param {GithubPublisher} plugin + * @param {Repository | null} repo - Other repo if the command is called from the suggest_other_repo_command.ts + * @param {string} branchName + * @return {Promise} + */ +export async function shareActiveFile(plugin: GithubPublisher, repo: Repository | null): Promise { + const file = plugin.app.workspace.getActiveFile(); + const frontmatter = frontmatterFromFile(file, plugin, repo); + if (file && frontmatter && isShared(frontmatter, plugin.settings, file, repo)) { + await shareOneNote( + await plugin.reloadOctokit(repo?.smartKey), + file, + repo, + frontmatter, + ); + } else { + new Notice(i18next.t("commands.runOtherRepo.noFile")); + } +} \ No newline at end of file diff --git a/src/commands/suggest_other_repo_commands_modal.ts b/src/commands/suggest_other_repo_commands_modal.ts index b6bd71fc..17024351 100644 --- a/src/commands/suggest_other_repo_commands_modal.ts +++ b/src/commands/suggest_other_repo_commands_modal.ts @@ -1,17 +1,10 @@ +import { FolderSettings, GitHubPublisherSettings, Repository } from "@interfaces"; import i18next from "i18next"; import { App, FuzzySuggestModal } from "obsidian"; +import {createLinkOnActiveFile, deleteCommands, repositoryValidityActiveFile, shareActiveFile, shareEditedOnly, uploadAllEditedNotes, uploadAllNotes, uploadNewNotes} from "src/commands"; +import GithubPublisher from "src/main"; import { defaultRepo } from "src/utils/data_validation_test"; -import { FolderSettings, GitHubPublisherSettings, Repository } from "../interfaces"; -import GithubPublisher from "../main"; -import { - createLinkOnActiveFile, - deleteCommands, repositoryValidityActiveFile, shareActiveFile, - shareEditedOnly, - uploadAllEditedNotes, - uploadAllNotes, - uploadNewNotes -} from "./plugin_commands"; interface GithubPublisherCommands { commands: string; diff --git a/src/conversion/compiler/dataview.ts b/src/conversion/compiler/dataview.ts index 495ad483..209bbaba 100644 --- a/src/conversion/compiler/dataview.ts +++ b/src/conversion/compiler/dataview.ts @@ -3,15 +3,14 @@ * @link https://github.com/oleeskild/obsidian-digital-garden/blob/main/src/compiler/DataviewCompiler.ts */ +import { LinkedNotes, MultiProperties,PropertiesConversion } from "@interfaces"; import i18next from "i18next"; import { Component, FrontMatterCache, htmlToMarkdown,TFile } from "obsidian"; import { getAPI, isPluginEnabled,Literal, Success } from "obsidian-dataview"; +import { convertToInternalGithub, convertWikilinks, escapeRegex } from "src/conversion/links"; import GithubPublisher from "src/main"; import { logs, notif } from "src/utils"; -import { FrontmatterConvert, LinkedNotes, MultiProperties } from "../../interfaces"; -import { convertToInternalGithub, convertWikilinks, escapeRegex } from "../links"; - /** * Convert dataview queries to markdown * Empty the block if settings.convertDataview is false or if the frontmatter key dataview is false @@ -170,11 +169,11 @@ export async function convertDataviewQueries( /** * Remove dataview queries from text - * @param dataviewMarkdown : string the dataview converted in markdown - * @param {@link FrontmatterConvert} frontmatterSettings the settings + * @param dataviewMarkdown string the dataview converted in markdown + * @param {PropertiesConversion} frontmatterSettings the settings * @return {string} the text without dataview queries or the dataview queries in markdown */ -function removeDataviewQueries(dataviewMarkdown: Literal, frontmatterSettings: FrontmatterConvert): string { +function removeDataviewQueries(dataviewMarkdown: Literal, frontmatterSettings: PropertiesConversion): string { const toString = dataviewMarkdown?.toString(); return frontmatterSettings.dataview && dataviewMarkdown && toString ? toString : ""; } @@ -271,10 +270,7 @@ function sanitizeQuery(query: string): {isInsideCallout: boolean, finalQuery: st sanitized.push(part); } } - let finalQuery = query; - if (isInsideCallout) { - finalQuery = sanitized.join("\n"); - } + const finalQuery = isInsideCallout ? sanitized.join("\n") : query; return {isInsideCallout, finalQuery}; } diff --git a/src/conversion/compiler/embeds.ts b/src/conversion/compiler/embeds.ts index c644e3cf..ff2adc23 100644 --- a/src/conversion/compiler/embeds.ts +++ b/src/conversion/compiler/embeds.ts @@ -6,6 +6,10 @@ * Each function is modified to fit the needs of this plugin, but citation are done in the code for each function */ +import { + GitHubPublisherSettings, + LinkedNotes, + MultiProperties} from "@interfaces"; import { App, BlockSubpathResult, @@ -15,15 +19,10 @@ import { resolveSubpath, TFile} from "obsidian"; import { getAPI, Link } from "obsidian-dataview"; +import { addToYaml } from "src/conversion"; +import { createRelativePath, getTitleField, regexOnFileName } from "src/conversion/file_path"; import GithubPublisher from "src/main"; - -import { - GitHubPublisherSettings, - LinkedNotes, - MultiProperties} from "../../interfaces"; -import {isShared} from "../../utils/data_validation_test"; -import { addToYaml } from ".."; -import { createRelativePath, getTitleField, regexOnFileName } from "../file_path"; +import {isShared} from "src/utils/data_validation_test"; /** diff --git a/src/conversion/file_path.ts b/src/conversion/file_path.ts index 39fd8afc..cba9ea21 100644 --- a/src/conversion/file_path.ts +++ b/src/conversion/file_path.ts @@ -1,29 +1,28 @@ -import { - FrontMatterCache, - normalizePath, - TFile, - TFolder, - Vault, -} from "obsidian"; -import GithubPublisher from "src/main"; -import merge from "ts-deepmerge"; - import { FIND_REGEX, FolderSettings, - FrontmatterConvert, GitHubPublisherSettings, LinkedNotes, MultiProperties, Properties, + PropertiesConversion, Repository, -} from "../interfaces"; +} from "@interfaces"; +import { + FrontMatterCache, + normalizePath, + TFile, + TFolder, + Vault, +} from "obsidian"; +import { createRegexFromText } from "src/conversion/find_and_replace_text"; +import GithubPublisher from "src/main"; import { logs, -} from "../utils"; -import {checkIfRepoIsInAnother, isInternalShared, isShared} from "../utils/data_validation_test"; -import { frontmatterFromFile, frontmatterSettingsRepository, getCategory, getFrontmatterSettings, getProperties } from "../utils/parse_frontmatter"; -import { createRegexFromText } from "./find_and_replace_text"; +} from "src/utils"; +import {checkIfRepoIsInAnother, isInternalShared, isShared} from "src/utils/data_validation_test"; +import { frontmatterFromFile, frontmatterSettingsRepository, getCategory, getFrontmatterSettings, getProperties } from "src/utils/parse_frontmatter"; +import merge from "ts-deepmerge"; /** Search a link in the entire frontmatter value */ @@ -408,13 +407,13 @@ export function getReceiptFolder( /** * Create filepath in github Repository based on settings and frontmatter for image * @param {TFile} file : Source file - * @param {FrontmatterConvert | null} sourceFrontmatter + * @param {PropertiesConversion | null} sourceFrontmatter * @return {string} the new filepath */ export function getImagePath( file: TFile, plugin: GithubPublisher, - sourceFrontmatter: FrontmatterConvert | null, + sourceFrontmatter: PropertiesConversion | null, repository: Properties | Properties[], ): string { const settings = plugin.settings; @@ -431,13 +430,13 @@ export function getImagePath( * Create filepath in github Repository based on settings and frontmatter for image * @param {TFile} file : Source file * @param {GitHubPublisherSettings} settings Settings - * @param {FrontmatterConvert | null} sourceFrontmatter + * @param {PropertiesConversion | null} sourceFrontmatter * @return {string} the new filepath */ function createImagePath(file: TFile, settings: GitHubPublisherSettings, - sourceFrontmatter: FrontmatterConvert | null, + sourceFrontmatter: PropertiesConversion | null, overridePath?: Properties, ): { path: string, name: string } { let fileName = file.name; diff --git a/src/conversion/find_and_replace_text.ts b/src/conversion/find_and_replace_text.ts index 7a850d2d..54a0b929 100644 --- a/src/conversion/find_and_replace_text.ts +++ b/src/conversion/find_and_replace_text.ts @@ -1,9 +1,8 @@ +import { FIND_REGEX, GitHubPublisherSettings } from "@interfaces"; +import { escapeRegex } from "src/conversion/links"; import { logs } from "src/utils"; -import { FIND_REGEX, GitHubPublisherSettings } from "../interfaces"; -import { escapeRegex } from "./links"; - /** * Convert a string to a regex object when the string is in the form of a regex (enclosed by /) * @param toReplace {string} The string to be converted to a regex object diff --git a/src/conversion/index.ts b/src/conversion/index.ts index 35fe8ea2..3b444d48 100644 --- a/src/conversion/index.ts +++ b/src/conversion/index.ts @@ -1,3 +1,9 @@ +import { + GitHubPublisherSettings, + LinkedNotes, + MultiProperties, + PropertiesConversion, +} from "@interfaces"; import i18next from "i18next"; import { FrontMatterCache, @@ -9,20 +15,14 @@ import { stringifyYaml, TFile, } from "obsidian"; +import { convertDataviewQueries } from "src/conversion/compiler/dataview"; +import { bakeEmbeds, convertInlineDataview } from "src/conversion/compiler/embeds"; +import { convertToInternalGithub, convertWikilinks } from "src/conversion/links"; +import GithubPublisher from "src/main"; +import { notif } from "src/utils"; import { isFolderNote } from "src/utils/data_validation_test"; -import { - FrontmatterConvert, - GitHubPublisherSettings, - LinkedNotes, - MultiProperties, -} from "../interfaces"; -import GithubPublisher from "../main"; -import { notif } from "../utils"; -import { convertDataviewQueries } from "./compiler/dataview"; -import { bakeEmbeds, convertInlineDataview } from "./compiler/embeds"; import findAndReplaceText from "./find_and_replace_text"; -import { convertToInternalGithub, convertWikilinks } from "./links"; /** * Convert soft line breaks to hard line breaks, adding two space at the end of the line. @@ -38,7 +38,7 @@ import { convertToInternalGithub, convertWikilinks } from "./links"; export function addHardLineBreak( text: string, settings: GitHubPublisherSettings, - frontmatter: FrontmatterConvert + frontmatter: PropertiesConversion ): string { try { text = text.replace(/^\s*\\\s*$/gim, "
"); diff --git a/src/conversion/links.ts b/src/conversion/links.ts index a7b1d01b..364e57ac 100644 --- a/src/conversion/links.ts +++ b/src/conversion/links.ts @@ -1,21 +1,21 @@ -import { FrontMatterCache, TFile } from "obsidian"; -import slugify from "slugify"; - import { - FrontmatterConvert, GitHubPublisherSettings, LinkedNotes, MultiProperties, -} from "../interfaces"; -import { isAttachment, noTextConversion } from "../utils/data_validation_test"; -import { createRelativePath, linkIsInFormatter, textIsInFrontmatter } from "./file_path"; -import { replaceText } from "./find_and_replace_text"; + PropertiesConversion, +} from "@interfaces"; +import { FrontMatterCache, TFile } from "obsidian"; +import slugify from "slugify"; +import { createRelativePath, linkIsInFormatter, textIsInFrontmatter } from "src/conversion/file_path"; +import { replaceText } from "src/conversion/find_and_replace_text"; +import { isAttachment, noTextConversion } from "src/utils/data_validation_test"; + /** - * Convert wikilinks to markdown + * Convert wikilinks to markdown links * Pretty cursed * @param {string} fileContent the text to convert - * @param {FrontmatterConvert} conditionConvert the frontmatter settings + * @param {PropertiesConversion} conditionConvert the frontmatter settings * @param {GitHubPublisherSettings} settings global settings * @param {LinkedNotes[]} linkedFiles the list of linked files * @return {string} the converted text @@ -23,7 +23,7 @@ import { replaceText } from "./find_and_replace_text"; export function convertWikilinks( fileContent: string, - conditionConvert: FrontmatterConvert, + conditionConvert: PropertiesConversion, linkedFiles: LinkedNotes[], settings: GitHubPublisherSettings, sourceFrontmatter: FrontMatterCache | undefined | null, @@ -42,132 +42,33 @@ export function convertWikilinks( const fileRegex = /(\[\[).*?([\]|])/; for (const wikiMatch of wikiMatches) { const fileMatch = wikiMatch.match(fileRegex); - let isEmbed = wikiMatch.startsWith("!") ? "!" : ""; + const isEmbed = wikiMatch.startsWith("!") ? "!" : ""; const isEmbedBool = wikiMatch.startsWith("!"); if (fileMatch) { - let linkCreator = wikiMatch; - /** - * In order to compare linked files with files that we have cached in - * memory, we have sanitize their link name to matching. - * - * For example, if we have a [[./wikilink.md|My Incredible Link Title]], - * we want to match `wikilink.md` with the cached files we have in - * memory. In this case, we'd strip [[, | and ./ to have wikilink.md as - * result. - */ - const fileName = fileMatch[0] - .replaceAll("[", "") - .replaceAll("|", "") - .replaceAll("]", "") - .replaceAll("\\", ""); - const StrictFileName = fileMatch[0] - .replaceAll("[", "") - .replaceAll("|", "") - .replaceAll("]", "") - .replaceAll("\\", "") - .replaceAll("../", "") - .replaceAll("./", "") - .replace(/#.*/, ""); - //get last from path + const fileName = sanitizeLinkFileName(fileMatch[0]); + const strictFileName = sanitizeStrictFileName(fileMatch[0]); const linkedFile = linkedFiles.find( - (item) => item.linkFrom.replace(/#.*/, "") === StrictFileName + (item) => item.linkFrom.replace(/#.*/, "") === strictFileName ); const isNotAttachment = !isAttachment(fileName.trim(), settings.embed.unHandledObsidianExt); if (linkedFile && !linkIsInFormatter(linkedFile, sourceFrontmatter)) { - let altText: string; - if (linkedFile.linked.extension !== "md") { - altText = - linkedFile.altText - ? linkedFile.altText - : ""; - } else { - altText = - linkedFile.altText - ? linkedFile.altText - : linkedFile.linked.basename; - altText = altText - .replace("#", " > ") - .replace(/ > \^\w*/, ""); - } - const removeEmbed = - (conditionConvert.removeEmbed === "remove" || conditionConvert.removeEmbed === "bake") && - isEmbedBool && - linkedFile.linked.extension === "md"; - if (isEmbedBool && linkedFile.linked.extension === "md" && conditionConvert.removeEmbed === "links") { - isEmbed = `${conditionConvert.charEmbedLinks} `; - linkCreator = linkCreator.replace("!", isEmbed); - } - if (convertWikilink) { - const altMatch = wikiMatch.match(/(\|).*(]])/); - const altCreator = fileName.split("/"); - let altLink = creatorAltLink( - altMatch as RegExpMatchArray, - altCreator, - fileName.split(".").at(-1) as string, - fileName - ); - - altLink = altLink - .replace("#", " > ") - .replace(/ > \^\w*/, ""); - linkCreator = createMarkdownLinks(fileName, isEmbed, altLink, settings); - } else { - const altMatch = wikiMatch.match(/(\|).*(]])/); - linkCreator = addAltForWikilinks(altMatch as RegExpMatchArray, linkCreator); - } - if ( - linkedFile.linked.extension === "md" && - !convertLinks && - !isEmbedBool - ) { - linkCreator = altText; - } - if ( - (!imageSettings && - !isNotAttachment) || - removeEmbed - ) { - linkCreator = ""; - } - fileContent = replaceText(fileContent, wikiMatch, linkCreator, settings, true); - + fileContent = isLinkedFile(linkedFile, conditionConvert, { + isEmbedBool, + isNotAttachment, + convertWikilink, + convertLinks, + imageSettings, + }, isEmbed, settings, fileContent, wikiMatch, fileName); } else if (!fileName.startsWith("http") && !textIsInFrontmatter(fileName, sourceFrontmatter)) { - const altMatch = wikiMatch.match(/(\|).*(]])/); - const altCreator = fileName.split("/"); - - let altLink = creatorAltLink( - altMatch as RegExpMatchArray, - altCreator, - fileName.split(".").at(-1) as string, - fileName + fileContent = strictStringConversion({ + convertWikilink, + isNotAttachment, + isEmbedBool, + convertLinks, + imageSettings, + }, wikiMatch, fileName, conditionConvert, isEmbed, settings, fileContent ); - altLink = altLink - .replace("#", " > ") - .replace(/ > \^\w*/, ""); - const removeEmbed = - isNotAttachment && - conditionConvert.removeEmbed === "remove" && - isEmbedBool; - if (isEmbedBool && conditionConvert.removeEmbed === "links" && isNotAttachment) { - isEmbed = `${conditionConvert.charEmbedLinks} `; - linkCreator = linkCreator.replace("!", isEmbed); - } - linkCreator = convertWikilink ? createMarkdownLinks(fileName, isEmbed, altLink, settings) : addAltForWikilinks(altMatch as RegExpMatchArray, linkCreator); - if ( - isNotAttachment && - !convertLinks && - !isEmbedBool - ) { - linkCreator = altLink; - } - if ( - (!imageSettings && !isNotAttachment) || - removeEmbed - ) { - linkCreator = ""; - } - fileContent = replaceText(fileContent, wikiMatch, linkCreator, settings, true); } } } @@ -175,6 +76,152 @@ export function convertWikilinks( return fileContent; } + +function sanitizeLinkFileName(link: string) { + return link + .replaceAll("[", "") + .replaceAll("|", "") + .replaceAll("]", "") + .replaceAll("\\", ""); +} +/** + * In order to compare linked files with files that we have cached in + * memory, we have sanitize their link name to matching. + * + * For example, if we have a [[./wikilink.md|My Incredible Link Title]], + * we want to match `wikilink.md` with the cached files we have in + * memory. In this case, we'd strip [[, | and ./ to have wikilink.md as + * result. + */ +function sanitizeStrictFileName(link: string) { + return link.replaceAll("[", "") + .replaceAll("|", "") + .replaceAll("]", "") + .replaceAll("\\", "") + .replaceAll("../", "") + .replaceAll("./", "") + .replace(/#.*/, ""); +} + +function isLinkedFile( + linkedFile: LinkedNotes, + conditionConvert: PropertiesConversion, + condition: { + isEmbedBool: boolean; + isNotAttachment: boolean; + convertWikilink: boolean; + convertLinks: boolean; + imageSettings: boolean; + }, + isEmbed: string, + settings: GitHubPublisherSettings, + fileContent: string, + wikiMatch: string, + fileName: string) { + let altText: string; + let linkCreator = wikiMatch; + const { isEmbedBool, isNotAttachment, convertWikilink, convertLinks, imageSettings } = condition; + if (linkedFile.linked.extension !== "md") { + altText = linkedFile.altText ? linkedFile.altText : ""; + } else { + altText = linkedFile.altText ? linkedFile.altText : linkedFile.linked.basename; + altText = altText .replace("#", " > ").replace(/ > \^\w*/, ""); + } + const removeEmbed = (conditionConvert.removeEmbed === "remove" || conditionConvert.removeEmbed === "bake") && + isEmbedBool && + linkedFile.linked.extension === "md"; + if (isEmbedBool && linkedFile.linked.extension === "md" && conditionConvert.removeEmbed === "links") { + isEmbed = `${conditionConvert.charEmbedLinks} `; + linkCreator = wikiMatch.replace("!", isEmbed); + } + if (convertWikilink) { + const altMatch = wikiMatch.match(/(\|).*(]])/); + const altCreator = fileName.split("/"); + let altLink = creatorAltLink( + altMatch as RegExpMatchArray, + altCreator, + fileName.split(".").at(-1) as string, + fileName + ); + + altLink = altLink + .replace("#", " > ") + .replace(/ > \^\w*/, ""); + linkCreator = createMarkdownLinks(fileName, isEmbed, altLink, settings); + } else { + const altMatch = wikiMatch.match(/(\|).*(]])/); + linkCreator = addAltForWikilinks(altMatch as RegExpMatchArray, linkCreator); + } + if ( + linkedFile.linked.extension === "md" && + !convertLinks && + !isEmbedBool + ) { + linkCreator = altText; + } + if ( + (!imageSettings && !isNotAttachment) || removeEmbed + ) { + linkCreator = ""; + } + return replaceText(fileContent, wikiMatch, linkCreator, settings, true); + + +} + +function strictStringConversion( + condition: { + convertWikilink: boolean; + isNotAttachment: boolean; + isEmbedBool: boolean; + convertLinks: boolean; + imageSettings: boolean; + }, + wikiMatch: string, + fileName: string, + conditionConvert: PropertiesConversion, + isEmbed: string, + settings: GitHubPublisherSettings, + fileContent: string) { + const { convertWikilink, isNotAttachment, isEmbedBool, convertLinks, imageSettings } = condition; + const altMatch = wikiMatch.match(/(\|).*(]])/); + const altCreator = fileName.split("/"); + + let altLink = creatorAltLink( + altMatch as RegExpMatchArray, + altCreator, + fileName.split(".").at(-1) as string, + fileName + ); + altLink = altLink + .replace("#", " > ") + .replace(/ > \^\w*/, ""); + const removeEmbed = + isNotAttachment && + conditionConvert.removeEmbed === "remove" && + isEmbedBool; + let linkCreator = wikiMatch; + if (isEmbedBool && conditionConvert.removeEmbed === "links" && isNotAttachment) { + isEmbed = `${conditionConvert.charEmbedLinks} `; + linkCreator = linkCreator.replace("!", isEmbed); + } + linkCreator = convertWikilink ? createMarkdownLinks(fileName, isEmbed, altLink, settings) : addAltForWikilinks(altMatch as RegExpMatchArray, linkCreator); + if ( + isNotAttachment && + !convertLinks && + !isEmbedBool + ) { + linkCreator = altLink; + } + if ( + (!imageSettings && !isNotAttachment) || + removeEmbed + ) { + linkCreator = ""; + } + return replaceText(fileContent, wikiMatch, linkCreator, settings, true); +} + /** * If there are no altText (aka (.*)|), we create one based on the content in [[.*]], but we replace the # with >. * @param {RegExpMatchArray} altMatch - The match for the altText if any diff --git a/src/i18n/i18next.ts b/src/i18n/i18next.ts index 099338ef..ece9722a 100644 --- a/src/i18n/i18next.ts +++ b/src/i18n/i18next.ts @@ -1,34 +1,33 @@ import { moment } from "obsidian"; - -import af from "./locales/af.json"; -import ar from "./locales/ar.json"; -import ca from "./locales/ca.json"; -import cs from "./locales/cs.json"; -import da from "./locales/da.json"; -import de from "./locales/de.json"; -import el from "./locales/el.json"; -import en from "./locales/en.json"; -import es from "./locales/es.json"; -import fi from "./locales/fi.json"; -import fr from "./locales/fr.json"; -import he from "./locales/he.json"; -import it from "./locales/it.json"; -import ja from "./locales/ja.json"; -import ko from "./locales/ko.json"; -import nl from "./locales/nl.json"; -import no from "./locales/no.json"; -import pl from "./locales/pl.json"; -import pt from "./locales/pt.json"; -import ptBR from "./locales/pt-BR.json"; -import ro from "./locales/ro.json"; -import ru from "./locales/ru.json"; -import sr from "./locales/sr.json"; -import sv from "./locales/sv.json"; -import tr from "./locales/tr.json"; -import uk from "./locales/uk.json"; -import vi from "./locales/vi.json"; -import zhCN from "./locales/zh-CN.json"; -import zhTW from "./locales/zh-TW.json"; +import af from "src/i18n/locales/af.json"; +import ar from "src/i18n/locales/ar.json"; +import ca from "src/i18n/locales/ca.json"; +import cs from "src/i18n/locales/cs.json"; +import da from "src/i18n/locales/da.json"; +import de from "src/i18n/locales/de.json"; +import el from "src/i18n/locales/el.json"; +import en from "src/i18n/locales/en.json"; +import es from "src/i18n/locales/es.json"; +import fi from "src/i18n/locales/fi.json"; +import fr from "src/i18n/locales/fr.json"; +import he from "src/i18n/locales/he.json"; +import it from "src/i18n/locales/it.json"; +import ja from "src/i18n/locales/ja.json"; +import ko from "src/i18n/locales/ko.json"; +import nl from "src/i18n/locales/nl.json"; +import no from "src/i18n/locales/no.json"; +import pl from "src/i18n/locales/pl.json"; +import pt from "src/i18n/locales/pt.json"; +import ptBR from "src/i18n/locales/pt-BR.json"; +import ro from "src/i18n/locales/ro.json"; +import ru from "src/i18n/locales/ru.json"; +import sr from "src/i18n/locales/sr.json"; +import sv from "src/i18n/locales/sv.json"; +import tr from "src/i18n/locales/tr.json"; +import uk from "src/i18n/locales/uk.json"; +import vi from "src/i18n/locales/vi.json"; +import zhCN from "src/i18n/locales/zh-CN.json"; +import zhTW from "src/i18n/locales/zh-TW.json"; export const resources = { en: { translation: en }, diff --git a/src/interfaces/constant.ts b/src/interfaces/constant.ts index a031164c..7d586e9f 100644 --- a/src/interfaces/constant.ts +++ b/src/interfaces/constant.ts @@ -1,5 +1,5 @@ -import { FolderSettings, GithubTiersVersion } from "./enum"; -import { GitHubPublisherSettings } from "./main"; +import { FolderSettings, GithubTiersVersion } from "src/interfaces/enum"; +import { GitHubPublisherSettings } from "src/interfaces/main"; /** Find a regex encapsuled in // */ export const FIND_REGEX = /^\/(.*)\/[igmsuy]*$/; diff --git a/src/utils/icons.ts b/src/interfaces/icons.ts similarity index 100% rename from src/utils/icons.ts rename to src/interfaces/icons.ts diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index cbe500a0..e826eb28 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -1,18 +1,26 @@ //export interface in a file to prevent breaking & allow to easily find the interface -import { DEFAULT_SETTINGS,FIND_REGEX, TOKEN_PATH } from "./constant"; -import {EnumbSettingsTabId,FolderSettings, GithubTiersVersion, TypeOfEditRegex } from "./enum"; -import { Deleted, ListEditedFiles, UploadedFiles } from "./list_edited_files"; -import { GitHubPublisherSettings,GithubRepo,LinkedNotes, OverrideAttachments, Path, Properties,PropertiesConversion, RegexReplace, Repository, SetRepositoryFrontmatter, TextCleaner } from "./main"; -import { MonoProperties,MonoRepoProperties,MultiProperties, MultiRepoProperties } from "./properties"; -import { MetadataExtractor } from "./settings"; +import { DEFAULT_SETTINGS,FIND_REGEX, TOKEN_PATH } from "src/interfaces/constant"; +import {EnumbSettingsTabId,FolderSettings, GithubTiersVersion, TypeOfEditRegex } from "src/interfaces/enum"; +import { Deleted, ListEditedFiles, UploadedFiles } from "src/interfaces/list_edited_files"; +import { GitHubPublisherSettings,GithubRepo,LinkedNotes, OverrideAttachments, Path, Properties,PropertiesConversion, RegexReplace, Repository, SetRepositoryFrontmatter, TextCleaner } from "src/interfaces/main"; +import { MonoProperties,MonoRepoProperties,MultiProperties, MultiRepoProperties } from "src/interfaces/properties"; +import { MetadataExtractor } from "src/interfaces/settings"; -export {DEFAULT_SETTINGS,EnumbSettingsTabId,FIND_REGEX,FolderSettings,GithubTiersVersion,TOKEN_PATH, TypeOfEditRegex, -}; +import { ERROR_ICONS, FOUND_ATTACHMENTS, HOURGLASS_ICON, SUCCESS_ICON } from "./icons"; + +export { + DEFAULT_SETTINGS, + EnumbSettingsTabId, + ERROR_ICONS, FIND_REGEX, + FolderSettings, + FOUND_ATTACHMENTS, GithubTiersVersion, + HOURGLASS_ICON, SUCCESS_ICON, + TOKEN_PATH, + TypeOfEditRegex}; export type { Deleted, - PropertiesConversion as FrontmatterConvert, GitHubPublisherSettings, GithubRepo, LinkedNotes, @@ -25,6 +33,7 @@ export type { OverrideAttachments, Path, Properties, + PropertiesConversion, RegexReplace, Repository, SetRepositoryFrontmatter, diff --git a/src/interfaces/properties.ts b/src/interfaces/properties.ts index f3cb2607..8e608a35 100644 --- a/src/interfaces/properties.ts +++ b/src/interfaces/properties.ts @@ -1,7 +1,6 @@ import { FrontMatterCache } from "obsidian"; - -import GithubPublisher from "../main"; -import { Properties, PropertiesConversion, Repository } from "./main"; +import { Properties, PropertiesConversion, Repository } from "src/interfaces/main"; +import GithubPublisher from "src/main"; /** * @interface MultiProperties diff --git a/src/interfaces/settings.ts b/src/interfaces/settings.ts index e23d0dcf..00dcff5e 100644 --- a/src/interfaces/settings.ts +++ b/src/interfaces/settings.ts @@ -1,5 +1,5 @@ -import { FolderSettings, GithubTiersVersion } from "./enum"; -import { OverrideAttachments,RegexReplace, Repository, TextCleaner } from "./main"; +import { FolderSettings, GithubTiersVersion } from "src/interfaces/enum"; +import { OverrideAttachments,RegexReplace, Repository, TextCleaner } from "src/interfaces/main"; export type Api = { /** diff --git a/src/main.ts b/src/main.ts index a57bdf6b..e0c3a4f3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,9 +1,14 @@ +import { + DEFAULT_SETTINGS, + GitHubPublisherSettings, + GithubTiersVersion, + Repository, + SetRepositoryFrontmatter, +} from "@interfaces"; import { Octokit } from "@octokit/core"; import dedent from "dedent"; import i18next from "i18next"; import { FrontMatterCache, Menu, Plugin, TAbstractFile, TFile, TFolder } from "obsidian"; -import merge from "ts-deepmerge"; - import { checkRepositoryValidityCallback, createLinkCallback, @@ -13,23 +18,17 @@ import { shareEditedOnlyCallback, shareOneNoteCallback, uploadAllEditedNotesCallback, uploadAllNotesCallback, uploadNewNotesCallback -} from "./commands/callback"; -import { addMenuFile, addMenuFolder } from "./commands/file_menu"; -import { ChooseWhichRepoToRun } from "./commands/suggest_other_repo_commands_modal"; -import { getTitleField, regexOnFileName } from "./conversion/file_path"; -import { GithubBranch } from "./GitHub/branch"; -import { resources, translationLanguage } from "./i18n/i18next"; -import { - DEFAULT_SETTINGS, - GitHubPublisherSettings, - GithubTiersVersion, - Repository, - SetRepositoryFrontmatter, -} from "./interfaces"; -import { GithubPublisherSettingsTab } from "./settings"; -import { migrateSettings, OldSettings } from "./settings/migrate"; -import { createTokenPath, monkeyPatchConsole, notif } from "./utils"; -import { checkRepositoryValidity, verifyRateLimitAPI } from "./utils/data_validation_test"; +} from "src/commands"; +import { addMenuFile, addMenuFolder } from "src/commands/file_menu"; +import { ChooseWhichRepoToRun } from "src/commands/suggest_other_repo_commands_modal"; +import { getTitleField, regexOnFileName } from "src/conversion/file_path"; +import { GithubBranch } from "src/GitHub/branch"; +import { resources, translationLanguage } from "src/i18n/i18next"; +import { GithubPublisherSettingsTab } from "src/settings"; +import { migrateSettings, OldSettings } from "src/settings/migrate"; +import { createTokenPath, monkeyPatchConsole, notif } from "src/utils"; +import { checkRepositoryValidity, verifyRateLimitAPI } from "src/utils/data_validation_test"; +import merge from "ts-deepmerge"; /** * Main class of the plugin diff --git a/src/settings.ts b/src/settings.ts index 401113b3..fd109d43 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,28 +1,27 @@ -import i18next from "i18next"; -import { App, Notice, PluginSettingTab, setIcon, Setting } from "obsidian"; - import { EnumbSettingsTabId, FolderSettings, GitHubPublisherSettings, GithubTiersVersion, Repository -} from "./interfaces"; -import GithubPublisherPlugin from "./main"; +} from "@interfaces"; +import i18next from "i18next"; +import { App, Notice, PluginSettingTab, setIcon, Setting } from "obsidian"; +import GithubPublisherPlugin from "src/main"; import { help, KeyBasedOnSettings, multipleRepoExplained, supportMe, usefulLinks -} from "./settings/help"; -import { migrateToken } from "./settings/migrate"; -import { ExportModal, ImportLoadPreset, ImportModal, loadAllPresets } from "./settings/modals/import_export"; -import { ModalAddingNewRepository } from "./settings/modals/manage_repo"; -import { AutoCleanPopup } from "./settings/modals/popup"; -import { ModalRegexFilePathName, ModalRegexOnContents, OverrideAttachmentsModal } from "./settings/modals/regex_edition"; -import { TokenEditPath } from "./settings/modals/token_path"; +} from "src/settings/help"; +import { migrateToken } from "src/settings/migrate"; +import { ExportModal, ImportLoadPreset, ImportModal, loadAllPresets } from "src/settings/modals/import_export"; +import { ModalAddingNewRepository } from "src/settings/modals/manage_repo"; +import { AutoCleanPopup } from "src/settings/modals/popup"; +import { ModalRegexFilePathName, ModalRegexOnContents, OverrideAttachmentsModal } from "src/settings/modals/regex_edition"; +import { TokenEditPath } from "src/settings/modals/token_path"; import { autoCleanCondition, folderHideShowSettings, showHideBasedOnFolder, -} from "./settings/style"; -import { checkRepositoryValidity, verifyRateLimitAPI } from "./utils/data_validation_test"; +} from "src/settings/style"; +import { checkRepositoryValidity, verifyRateLimitAPI } from "src/utils/data_validation_test"; export class GithubPublisherSettingsTab extends PluginSettingTab { diff --git a/src/settings/help.ts b/src/settings/help.ts index 8fb7790a..670b0cc2 100644 --- a/src/settings/help.ts +++ b/src/settings/help.ts @@ -1,8 +1,7 @@ +import { FolderSettings, GitHubPublisherSettings } from "@interfaces"; import i18next from "i18next"; import { normalizePath } from "obsidian"; - -import { regexOnPath } from "../conversion/file_path"; -import { FolderSettings, GitHubPublisherSettings } from "../interfaces"; +import { regexOnPath } from "src/conversion/file_path"; function spanAtRule(text: string, code: DocumentFragment, br: boolean = true): HTMLElement { if (br) code.createEl("br"); diff --git a/src/settings/migrate.ts b/src/settings/migrate.ts index af21bed7..b1e6d42b 100644 --- a/src/settings/migrate.ts +++ b/src/settings/migrate.ts @@ -1,9 +1,8 @@ +import { FolderSettings, GithubTiersVersion, TextCleaner, TOKEN_PATH, TypeOfEditRegex } from "@interfaces"; import i18next from "i18next"; import { normalizePath } from "obsidian"; - -import { FolderSettings, GithubTiersVersion, TextCleaner, TOKEN_PATH, TypeOfEditRegex } from "../interfaces"; -import GithubPublisher from "../main"; -import { createTokenPath, logs } from "../utils"; +import GithubPublisher from "src/main"; +import { createTokenPath, logs } from "src/utils"; export interface OldSettings { githubRepo: string; diff --git a/src/settings/modals/import_export.ts b/src/settings/modals/import_export.ts index 505072df..dfb31013 100644 --- a/src/settings/modals/import_export.ts +++ b/src/settings/modals/import_export.ts @@ -1,3 +1,4 @@ +import {GitHubPublisherSettings, Preset} from "@interfaces/main"; import {Octokit} from "@octokit/core"; import i18next from "i18next"; import { @@ -9,12 +10,10 @@ import { Platform, Setting, TextAreaComponent} from "obsidian"; - -import {GitHubPublisherSettings, Preset} from "../../interfaces/main"; -import GithubPublisher from "../../main"; -import {GithubPublisherSettingsTab} from "../../settings"; -import {logs, notif} from "../../utils"; -import { migrateSettings,OldSettings } from "../migrate"; +import GithubPublisher from "src/main"; +import {GithubPublisherSettingsTab} from "src/settings"; +import { migrateSettings,OldSettings } from "src/settings/migrate"; +import {logs, notif} from "src/utils"; export type SettingValue = number | string | boolean | unknown; diff --git a/src/settings/modals/list_changed.ts b/src/settings/modals/list_changed.ts index 5b5eaeb6..b7cc071b 100644 --- a/src/settings/modals/list_changed.ts +++ b/src/settings/modals/list_changed.ts @@ -1,8 +1,7 @@ +import { Deleted, ListEditedFiles } from "@interfaces"; import i18next from "i18next"; import { App,Modal } from "obsidian"; -import { Deleted, ListEditedFiles } from "../../interfaces"; - export class ListChangedFiles extends Modal { listChanged: ListEditedFiles | Deleted; diff --git a/src/settings/modals/manage_repo.ts b/src/settings/modals/manage_repo.ts index 3a365aa2..40b17852 100644 --- a/src/settings/modals/manage_repo.ts +++ b/src/settings/modals/manage_repo.ts @@ -1,10 +1,9 @@ +import {GitHubPublisherSettings, GithubTiersVersion, Repository} from "@interfaces"; import i18next from "i18next"; import {AbstractInputSuggest, App, Modal, Notice, Setting, TFile} from "obsidian"; - -import {GitHubPublisherSettings, GithubTiersVersion, Repository} from "../../interfaces"; -import GithubPublisher from "../../main"; -import {checkRepositoryValidity, verifyRateLimitAPI} from "../../utils/data_validation_test"; -import { migrateToken } from "../migrate"; +import GithubPublisher from "src/main"; +import { migrateToken } from "src/settings/migrate"; +import {checkRepositoryValidity, verifyRateLimitAPI} from "src/utils/data_validation_test"; class SetClassSuggester extends AbstractInputSuggest { diff --git a/src/settings/modals/popup.ts b/src/settings/modals/popup.ts index f849237c..def63f25 100644 --- a/src/settings/modals/popup.ts +++ b/src/settings/modals/popup.ts @@ -1,8 +1,7 @@ +import { GitHubPublisherSettings } from "@interfaces/main"; import i18next from "i18next"; import { App, Modal, Setting } from "obsidian"; -import { GitHubPublisherSettings } from "../../interfaces/main"; - export class AutoCleanPopup extends Modal { settings: GitHubPublisherSettings; diff --git a/src/settings/modals/regex_edition.ts b/src/settings/modals/regex_edition.ts index 75404abc..7f264fb1 100644 --- a/src/settings/modals/regex_edition.ts +++ b/src/settings/modals/regex_edition.ts @@ -1,9 +1,8 @@ +import {FolderSettings, GitHubPublisherSettings, OverrideAttachments, RegexReplace, TextCleaner, TypeOfEditRegex} from "@interfaces"; import i18next from "i18next"; import {App, Modal, Notice, Setting} from "obsidian"; import { escapeRegex } from "src/conversion/links"; -import {FolderSettings, GitHubPublisherSettings, OverrideAttachments, RegexReplace, TextCleaner, TypeOfEditRegex} from "../../interfaces"; - function isRegexValid(regexString: string) { try { new RegExp(regexString); diff --git a/src/settings/modals/token_path.ts b/src/settings/modals/token_path.ts index 490bd15d..05af47f5 100644 --- a/src/settings/modals/token_path.ts +++ b/src/settings/modals/token_path.ts @@ -1,11 +1,10 @@ +import { TOKEN_PATH } from "@interfaces"; import i18next from "i18next"; import { App, Modal, Notice,Setting } from "obsidian"; import GithubPublisher from "src/main"; +import { migrateToken } from "src/settings/migrate"; import { createTokenPath, logs } from "src/utils"; -import { TOKEN_PATH } from "../../interfaces"; -import { migrateToken } from "../migrate"; - export class TokenEditPath extends Modal { plugin: GithubPublisher; token: string; diff --git a/src/settings/style.ts b/src/settings/style.ts index d6ada973..0f87fdf8 100644 --- a/src/settings/style.ts +++ b/src/settings/style.ts @@ -1,9 +1,8 @@ +import {EnumbSettingsTabId, FolderSettings, GitHubPublisherSettings} from "@interfaces"; import i18next from "i18next"; import { Notice, Setting } from "obsidian"; +import GithubPublisher from "src/main"; import { GithubPublisherSettingsTab } from "src/settings"; - -import {EnumbSettingsTabId, FolderSettings, GitHubPublisherSettings} from "../interfaces"; -import GithubPublisher from "../main"; /** * show a settings * @param {Setting} containerEl setting to show diff --git a/src/utils/data_validation_test.ts b/src/utils/data_validation_test.ts index eaca1db0..022be170 100644 --- a/src/utils/data_validation_test.ts +++ b/src/utils/data_validation_test.ts @@ -1,15 +1,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import {FIND_REGEX, GitHubPublisherSettings, GithubTiersVersion, MultiProperties, Properties, PropertiesConversion, Repository} from "@interfaces"; import { Octokit } from "@octokit/core"; import i18next from "i18next"; import { FrontMatterCache, normalizePath,Notice, TFile, TFolder} from "obsidian"; +import {GithubBranch} from "src/GitHub/branch"; import GithubPublisher from "src/main"; +import { notif} from "src/utils"; +import { frontmatterFromFile, getLinkedFrontmatter, getProperties } from "src/utils/parse_frontmatter"; import merge from "ts-deepmerge"; -import {GithubBranch} from "../GitHub/branch"; -import {FIND_REGEX, FrontmatterConvert, GitHubPublisherSettings, GithubTiersVersion, MultiProperties, Properties, Repository} from "../interfaces"; -import { notif} from "."; -import { frontmatterFromFile, getLinkedFrontmatter, getProperties } from "./parse_frontmatter"; - /** * - Check if the file is a valid file to publish * - Check also the path from the excluded folder list @@ -84,7 +83,12 @@ export function isShared( const otherRepoWithShareAll = settings.github.otherRepo.filter((repo) => repo.shareAll?.enable); if (!settings.plugin.shareAll?.enable && !otherRepoWithShareAll.length) { const shareKey = otherRepo ? otherRepo.shareKey : settings.plugin.shareKey; - if ( meta == null || !meta[shareKey] || meta[shareKey] == null || isExcludedPath(settings, file, otherRepo) || meta[shareKey] === undefined || ["false", "0", "no"].includes(meta[shareKey].toString().toLowerCase())) { + if ( meta == null + || !meta[shareKey] + || meta[shareKey] == null + || isExcludedPath(settings, file, otherRepo) + || meta[shareKey] === undefined + || ["false", "0", "no"].includes(meta[shareKey].toString().toLowerCase())) { return false; } const shareKeyInFrontmatter:string = meta[shareKey].toString().toLowerCase(); @@ -92,7 +96,11 @@ export function isShared( } else if (settings.plugin.shareAll?.enable || otherRepoWithShareAll.length > 0) { const allExcludedFileName = otherRepoWithShareAll.map((repo) => repo.shareAll!.excludedFileName); allExcludedFileName.push(settings.plugin.shareAll!.excludedFileName); - if (allExcludedFileName.some(prefix => prefix.trim().length > 0 && !file.basename.startsWith(prefix) || prefix.trim().length === 0)) { + if ( + allExcludedFileName.some(prefix => prefix.trim().length > 0 + && !file.basename.startsWith(prefix) + || prefix.trim().length === 0) + ) { return !isExcludedPath(settings, file, otherRepo); } } @@ -289,10 +297,10 @@ export async function checkEmptyConfiguration(prop: Properties | Properties[], p /** * Verify if the text need to bee converted or not - * @param {FrontmatterConvert} conditionConvert The frontmatter option to check + * @param {PropertiesConversion} conditionConvert The frontmatter option to check * @return {boolean} if the text need to be converted */ -export function noTextConversion(conditionConvert: FrontmatterConvert): boolean { +export function noTextConversion(conditionConvert: PropertiesConversion): boolean { const convertWikilink = conditionConvert.convertWiki; const imageSettings = conditionConvert.attachment; const embedSettings = conditionConvert.embed; diff --git a/src/utils/index.ts b/src/utils/index.ts index 34a48794..1deef02b 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,11 +1,3 @@ -import i18next from "i18next"; -import {App, normalizePath, Notice, Platform, TFile} from "obsidian"; -import slugify from "slugify"; -import { createRegexFromText } from "src/conversion/find_and_replace_text"; -import GithubPublisher from "src/main"; - -import {getReceiptFolder} from "../conversion/file_path"; -import Publisher from "../GitHub/upload"; import { Deleted, FIND_REGEX, @@ -13,10 +5,18 @@ import { ListEditedFiles, MetadataExtractor, MultiRepoProperties, - Properties, TOKEN_PATH, - UploadedFiles} from "../interfaces"; -import { ERROR_ICONS, HOURGLASS_ICON, SUCCESS_ICON } from "./icons"; -import { frontmatterFromFile } from "./parse_frontmatter"; + Properties, + TOKEN_PATH, + UploadedFiles} from "@interfaces"; +import { ERROR_ICONS, HOURGLASS_ICON, SUCCESS_ICON } from "@interfaces/icons"; +import i18next from "i18next"; +import {App, normalizePath, Notice, Platform, TFile} from "obsidian"; +import slugify from "slugify"; +import {getReceiptFolder} from "src/conversion/file_path"; +import { createRegexFromText } from "src/conversion/find_and_replace_text"; +import Publisher from "src/GitHub/upload"; +import GithubPublisher from "src/main"; +import { frontmatterFromFile } from "src/utils/parse_frontmatter"; type LogsParameters = { settings: Partial, diff --git a/src/utils/parse_frontmatter.ts b/src/utils/parse_frontmatter.ts index 9602f1e3..2c1aae82 100644 --- a/src/utils/parse_frontmatter.ts +++ b/src/utils/parse_frontmatter.ts @@ -3,12 +3,11 @@ * See docs for all the condition */ +import { FolderSettings, GitHubPublisherSettings, Path, Properties, PropertiesConversion, Repository } from "@interfaces"; import { FrontMatterCache, normalizePath, TFile } from "obsidian"; import GithubPublisher from "src/main"; import merge from "ts-deepmerge"; -import { FolderSettings, FrontmatterConvert, GitHubPublisherSettings, Path, Properties, Repository } from "../interfaces"; - export function frontmatterSettingsRepository(plugin: GithubPublisher, repo: Repository | null) { const defaultConvert = getFrontmatterSettings(null, plugin.settings, repo); if (!repo?.set || !plugin.repositoryFrontmatter[repo.smartKey]) return defaultConvert; @@ -40,7 +39,7 @@ export function getFrontmatterSettings( repo: Repository | null ) { - let settingsConversion: FrontmatterConvert = { + let settingsConversion: PropertiesConversion = { convertWiki: settings.conversion.links.wiki, attachment: settings.embed.attachments, embed: settings.embed.notes, @@ -456,7 +455,7 @@ export function parsePath( function getFrontmatterSettingRepository( repository: Repository | null, frontmatter: FrontMatterCache | null | undefined, - frontConvert: FrontmatterConvert) { + frontConvert: PropertiesConversion) { if (!repository) return frontConvert; const smartKey = repository.smartKey; frontConvert = settingsLink(frontmatter, frontConvert, smartKey); @@ -513,7 +512,7 @@ export function frontmatterFromFile(file: TFile | null, plugin: GithubPublisher, return frontmatter; } -function settingsLink(frontmatter: FrontMatterCache | null | undefined, settingsConversion: FrontmatterConvert, smartKey?: string) { +function settingsLink(frontmatter: FrontMatterCache | null | undefined, settingsConversion: PropertiesConversion, smartKey?: string) { let key = "links"; if (smartKey) key = `${smartKey}.${key}`; if (!frontmatter) return settingsConversion; @@ -548,7 +547,7 @@ function settingsLink(frontmatter: FrontMatterCache | null | undefined, settings return settingsConversion; } -function settingsEmbed(frontmatter: FrontMatterCache | null | undefined, settingsConversion: FrontmatterConvert, smartkey?: string) { +function settingsEmbed(frontmatter: FrontMatterCache | null | undefined, settingsConversion: PropertiesConversion, smartkey?: string) { if (!frontmatter) return settingsConversion; const key = smartkey ? `${smartkey}.embed` : "embed"; if (frontmatter[key] != undefined) { @@ -575,7 +574,7 @@ function settingsEmbed(frontmatter: FrontMatterCache | null | undefined, setting return settingsConversion; } -function settingAttachment(frontmatter: FrontMatterCache | undefined | null, settingsConversion: FrontmatterConvert, smartKey?: string) { +function settingAttachment(frontmatter: FrontMatterCache | undefined | null, settingsConversion: PropertiesConversion, smartKey?: string) { if (!frontmatter) return settingsConversion; let key = "attachment"; if (smartKey) key = `${smartKey}.${key}`; diff --git a/src/utils/status_bar.ts b/src/utils/status_bar.ts index 1a699fe4..5d1bfa80 100644 --- a/src/utils/status_bar.ts +++ b/src/utils/status_bar.ts @@ -1,9 +1,7 @@ +import { ERROR_ICONS, FOUND_ATTACHMENTS, HOURGLASS_ICON, Properties, SUCCESS_ICON } from "@interfaces"; import i18next from "i18next"; import { Notice } from "obsidian"; - -import { Properties } from "../interfaces/main"; -import { noticeMobile } from "."; -import { ERROR_ICONS, FOUND_ATTACHMENTS, HOURGLASS_ICON, SUCCESS_ICON } from "./icons"; +import { noticeMobile } from "src/utils"; // Credit : https://github.com/oleeskild/obsidian-digital-garden/ @oleeskild diff --git a/tsconfig.json b/tsconfig.json index de084534..ebdcafd3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,25 +1,47 @@ { "compilerOptions": { "baseUrl": "./", - "paths" :{ - "data-model/*" : ["./node_modules/obsidian-dataview/lib/data-model/*"], - "api/*" : ["./node_modules/obsidian-dataview/lib/api/*"], - "data-index/*" : ["./node_modules/obsidian-dataview/lib/data-index/*"], - "query/*" : ["./node_modules/obsidian-dataview/lib/query/*"], - "expression/*" : ["./node_modules/obsidian-dataview/lib/expression/*"], - "settings" : ["./node_modules/obsidian-dataview/lib/settings"] + "paths": { + "data-model/*": [ + "./node_modules/obsidian-dataview/lib/data-model/*" + ], + "api/*": [ + "./node_modules/obsidian-dataview/lib/api/*" + ], + "data-index/*": [ + "./node_modules/obsidian-dataview/lib/data-index/*" + ], + "query/*": [ + "./node_modules/obsidian-dataview/lib/query/*" + ], + "expression/*": [ + "./node_modules/obsidian-dataview/lib/expression/*" + ], + "settings": [ + "./node_modules/obsidian-dataview/lib/settings" + ], + "@interfaces/*": [ + "./src/interfaces/*" + ], + "@interfaces": [ + "./src/interfaces/index.ts" + ], }, + "noEmit": true, "inlineSourceMap": true, "inlineSources": true, "module": "ESNext", - "target": "ES6", + "target": "ESNEXT", "allowJs": true, "noImplicitAny": true, + "skipLibCheck": true, + "removeComments": true, + "sourceMap": false, "moduleResolution": "node", "importHelpers": true, "isolatedModules": true, "resolveJsonModule": true, - "strict":true, + "strict": true, "allowSyntheticDefaultImports": true, "lib": [ "DOM", @@ -33,4 +55,4 @@ "include": [ "**/*.ts" ], -} +} \ No newline at end of file