From 8dd9db2141856dffbe8666e10208e8920bf907e8 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Mon, 19 Feb 2024 23:00:39 +0800 Subject: [PATCH] fix linting issue (#197) * fix linting issue * fix end of line error * fix lint --- .eslintrc | 6 +- .prettierrc | 3 +- package.json | 4 +- src/__tests__/formatDate.spec.ts | 18 +- src/__tests__/path_validation.spec.ts | 14 +- src/api.ts | 4 +- src/main.ts | 160 ++++---- src/settings/index.ts | 2 +- src/settings/suggest.ts | 6 +- src/settings/template.ts | 523 +++++++++++++------------- src/util.ts | 56 ++- yarn.lock | 51 ++- 12 files changed, 446 insertions(+), 401 deletions(-) diff --git a/.eslintrc b/.eslintrc index 734c3f3..bab550a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,11 +5,11 @@ "plugins": ["@typescript-eslint"], "extends": [ "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended" + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" ], "parserOptions": { - "sourceType": "module" + "project": "./tsconfig.json" }, "rules": { "no-unused-vars": "off", diff --git a/.prettierrc b/.prettierrc index 1ccc975..6467b11 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,5 @@ { "semi": false, - "singleQuote": true + "singleQuote": true, + "endOfLine": "auto" } diff --git a/package.json b/package.json index 8497187..fea74bc 100644 --- a/package.json +++ b/package.json @@ -37,11 +37,13 @@ "builtin-modules": "3.3.0", "esbuild": "0.14.47", "eslint": "^8.53.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "jest": "^29.4.3", "jest-cli": "^29.4.3", "jest-junit-reporter": "^1.1.0", "obsidian": "^1.2.8", - "prettier": "^2.8.1", + "prettier": "^3.2.5", "semantic-release": "^19.0.5", "ts-jest": "^29.0.5", "tslib": "2.4.0", diff --git a/src/__tests__/formatDate.spec.ts b/src/__tests__/formatDate.spec.ts index 22525aa..10e6978 100644 --- a/src/__tests__/formatDate.spec.ts +++ b/src/__tests__/formatDate.spec.ts @@ -75,8 +75,8 @@ function generateRandomISODateStrings(quantity: number): string[] { Math.floor(Math.random() * 24), Math.floor(Math.random() * 60), Math.floor(Math.random() * 60), - Math.floor(Math.random() * 1000) - ) + Math.floor(Math.random() * 1000), + ), ) // Randomly select a timezone from the available time zones @@ -86,7 +86,7 @@ function generateRandomISODateStrings(quantity: number): string[] { // Convert the generated date to the randomly selected timezone // const dateTimeWithZone = DateTime.fromJSDate(date, { zone: randomTimeZone }).toUTC(); const jsDateTimeWithZone = new Date( - date.toLocaleString('en-US', { timeZone: randomTimeZone }) + date.toLocaleString('en-US', { timeZone: randomTimeZone }), ) const luxonDate = DateTime.fromJSDate(jsDateTimeWithZone) randomISODateStrings.push(luxonDate.toISO() as string) @@ -102,13 +102,13 @@ describe('formatDate on random dates', () => { const result = formatDate(date, 'yyyy-MM-dd HH:mm:ss') // test with regex to ensure the format is correct expect(result).toMatch(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/) - } + }, ) }) function getCasesWithRandomDates( testFormats: string[], - quantity = 10 + quantity = 10, ): { date: string luxonFormat: string @@ -117,7 +117,7 @@ function getCasesWithRandomDates( generateRandomISODateStrings(quantity).map((date) => ({ date, luxonFormat, - })) + })), ) } @@ -135,7 +135,7 @@ describe('round trip on random dates', () => { const result = formatDate(testCase.date, testCase.luxonFormat) const result2 = formatDate(result, testCase.luxonFormat) expect(result2).toBe(result) - } + }, ) const atypicalFormats = [ @@ -148,9 +148,9 @@ describe('round trip on random dates', () => { const formattedDate = formatDate(testCase.date, testCase.luxonFormat) const parsedDate = DateTime.fromFormat( formattedDate, - testCase.luxonFormat + testCase.luxonFormat, ) expect(parsedDate.isValid).toBe(true) - } + }, ) }) diff --git a/src/__tests__/path_validation.spec.ts b/src/__tests__/path_validation.spec.ts index 1454553..d5a3067 100644 --- a/src/__tests__/path_validation.spec.ts +++ b/src/__tests__/path_validation.spec.ts @@ -29,7 +29,7 @@ describe('replaceIllegalChars() removes all expected characters', () => { const input = `this${character}string` const output = replaceIllegalChars(input) expect(output).not.toContain(character) - } + }, ) }) @@ -41,7 +41,7 @@ describe('replaceIllegalChars() function replaces illegal characters with replac const expectedOutput = `this${REPLACEMENT_CHAR}string` const output = replaceIllegalChars(input) expect(output).toEqual(expectedOutput) - } + }, ) }) @@ -51,7 +51,7 @@ describe('replaceIllegalChars() function does not modify string without illegal (input) => { const output = replaceIllegalChars(input) expect(output).toEqual(input) - } + }, ) }) @@ -72,14 +72,14 @@ describe('replaceIllegalChars() function replaces all occurrences of illegal cha const output = replaceIllegalChars(input) expect(output).toEqual(expectedOutput) expect(output.match(ILLEGAL_CHAR_REGEX)).toBeNull() - } + }, ) }) describe('file system behavior with non-alphanumeric characters not in the illegal character list', () => { const nonAlphanumericCharactersWithoutIllegal: string[] = Array.from( { length: 127 - 32 }, - (_, i) => String.fromCharCode(i + 32) + (_, i) => String.fromCharCode(i + 32), ) .filter((char) => !/^[a-zA-Z0-9]+$/.test(char)) .map(replaceIllegalChars) @@ -97,7 +97,7 @@ describe('file system behavior with non-alphanumeric characters not in the illeg fs.unlinkSync(input) // verify the file has been deleted expect(fs.existsSync(input)).toBe(false) - } + }, ) }) @@ -110,6 +110,6 @@ describe('replaceIllegalChars() function removes all occurrences of invisible ch const output = replaceIllegalChars(input) expect(output).toEqual(expectedOutput) expect(output.match(ILLEGAL_CHAR_REGEX)).toBeNull() - } + }, ) }) diff --git a/src/api.ts b/src/api.ts index 9669ed6..894b938 100644 --- a/src/api.ts +++ b/src/api.ts @@ -95,7 +95,7 @@ export const loadArticles = async ( updatedAt = '', query = '', includeContent = false, - format = 'html' + format = 'html', ): Promise<[Article[], boolean]> => { const res = await requestUrl({ url: endpoint, @@ -177,7 +177,7 @@ export const loadArticles = async ( export const deleteArticleById = async ( endpoint: string, apiKey: string, - articleId: string + articleId: string, ) => { const res = await requestUrl({ url: endpoint, diff --git a/src/main.ts b/src/main.ts index 7b7b9e0..c3f1e38 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import { DateTime } from "luxon" +import { DateTime } from 'luxon' import { addIcon, App, @@ -11,16 +11,16 @@ import { stringifyYaml, TFile, TFolder, -} from "obsidian" -import { Article, deleteArticleById, loadArticles, PageType } from "./api" +} from 'obsidian' +import { Article, deleteArticleById, loadArticles, PageType } from './api' import { DEFAULT_SETTINGS, Filter, FRONT_MATTER_VARIABLES, HighlightOrder, OmnivoreSettings, -} from "./settings" -import { FolderSuggest } from "./settings/file-suggest" +} from './settings' +import { FolderSuggest } from './settings/file-suggest' import { preParseTemplate, render, @@ -49,7 +49,7 @@ export default class OmnivorePlugin extends Plugin { const currentVersion = this.settings.version if (latestVersion !== currentVersion) { this.settings.version = latestVersion - this.saveSettings() + await this.saveSettings() // show release notes const releaseNotes = `Omnivore plugin is upgraded to ${latestVersion}. @@ -61,27 +61,27 @@ export default class OmnivorePlugin extends Plugin { this.addCommand({ id: 'sync', name: 'Sync new changes', - callback: () => { - this.fetchOmnivore() + callback: async () => { + await this.fetchOmnivore() }, }) this.addCommand({ id: 'deleteArticle', name: 'Delete Current Article from Omnivore', - callback: () => { - this.deleteCurrentArticle(this.app.workspace.getActiveFile()) + callback: async () => { + await this.deleteCurrentArticle(this.app.workspace.getActiveFile()) }, }) this.addCommand({ id: 'resync', name: 'Resync all articles', - callback: () => { + callback: async () => { this.settings.syncAt = '' - this.saveSettings() + await this.saveSettings() new Notice('Omnivore Last Sync reset') - this.fetchOmnivore() + await this.fetchOmnivore() }, }) @@ -89,7 +89,7 @@ export default class OmnivorePlugin extends Plugin { // add icon addIcon( iconId, - `` + ``, ) // This creates an icon in the left ribbon. @@ -118,14 +118,14 @@ export default class OmnivorePlugin extends Plugin { if (this.settings.filter === 'ADVANCED') { this.settings.filter = 'ALL' console.log( - 'obsidian-omnivore: advanced filter is replaced with all filter' + 'obsidian-omnivore: advanced filter is replaced with all filter', ) const customQuery = this.settings.customQuery this.settings.customQuery = `in:all ${ customQuery ? `(${customQuery})` : '' }` console.log( - `obsidian-omnivore: custom query is set to ${this.settings.customQuery}` + `obsidian-omnivore: custom query is set to ${this.settings.customQuery}`, ) this.saveSettings() } @@ -134,7 +134,7 @@ export default class OmnivorePlugin extends Plugin { if (!this.settings.customQuery) { this.settings.customQuery = getQueryFromFilter(this.settings.filter) console.log( - `obsidian-omnivore: custom query is set to ${this.settings.customQuery}` + `obsidian-omnivore: custom query is set to ${this.settings.customQuery}`, ) this.saveSettings() } @@ -144,7 +144,7 @@ export default class OmnivorePlugin extends Plugin { await this.saveData(this.settings) } - scheduleSync() { + async scheduleSync() { // clear previous interval if (this.settings.intervalId > 0) { window.clearInterval(this.settings.intervalId) @@ -152,12 +152,15 @@ export default class OmnivorePlugin extends Plugin { const frequency = this.settings.frequency if (frequency > 0) { // schedule new interval - const intervalId = window.setInterval(async () => { - await this.fetchOmnivore(false) - }, frequency * 60 * 1000) + const intervalId = window.setInterval( + async () => { + await this.fetchOmnivore(false) + }, + frequency * 60 * 1000, + ) // save new interval id this.settings.intervalId = intervalId - this.saveSettings() + await this.saveSettings() // clear interval when plugin is unloaded this.registerInterval(intervalId) } @@ -174,8 +177,8 @@ export default class OmnivorePlugin extends Plugin { render( article, this.settings.attachmentFolder, - this.settings.folderDateFormat - ) + this.settings.folderDateFormat, + ), ) const folder = app.vault.getAbstractFileByPath(folderName) if (!(folder instanceof TFolder)) { @@ -186,7 +189,7 @@ export default class OmnivorePlugin extends Plugin { if (!(file instanceof TFile)) { const newFile = await app.vault.createBinary( fileName, - response.arrayBuffer + response.arrayBuffer, ) return newFile.path } @@ -231,10 +234,10 @@ export default class OmnivorePlugin extends Plugin { const templateSpans = preParseTemplate(template) // check if we need to include content or file attachment const includeContent = templateSpans.some( - (templateSpan) => templateSpan[1] === 'content' + (templateSpan) => templateSpan[1] === 'content', ) const includeFileAttachment = templateSpans.some( - (templateSpan) => templateSpan[1] === 'fileAttachment' + (templateSpan) => templateSpan[1] === 'fileAttachment', ) const size = 50 @@ -243,7 +246,7 @@ export default class OmnivorePlugin extends Plugin { hasNextPage; after += size ) { - ;;[articles, hasNextPage] = await loadArticles( + ;[articles, hasNextPage] = await loadArticles( this.settings.endpoint, apiKey, after, @@ -251,12 +254,12 @@ export default class OmnivorePlugin extends Plugin { parseDateTime(syncAt).toISO() || undefined, customQuery, includeContent, - 'highlightedMarkdown' + 'highlightedMarkdown', ) for (const article of articles) { const folderName = normalizePath( - render(article, folder, this.settings.folderDateFormat) + render(article, folder, this.settings.folderDateFormat), ) const omnivoreFolder = this.app.vault.getAbstractFileByPath(folderName) @@ -276,11 +279,11 @@ export default class OmnivorePlugin extends Plugin { isSingleFile, frontMatterVariables, frontMatterTemplate, - fileAttachment + fileAttachment, ) // use the custom filename const customFilename = replaceIllegalChars( - renderFilename(article, filename, this.settings.filenameDateFormat) + renderFilename(article, filename, this.settings.filenameDateFormat), ) const pageName = `${folderName}/${customFilename}.md` const normalizedPath = normalizePath(pageName) @@ -316,7 +319,7 @@ export default class OmnivorePlugin extends Plugin { // find the front matter with the same id const frontMatterIdx = findFrontMatterIndex( existingFrontMatter, - article.id + article.id, ) if (frontMatterIdx >= 0) { // this article already exists in the file @@ -326,12 +329,12 @@ export default class OmnivorePlugin extends Plugin { const sectionEnd = `%%${article.id}_end%%` const existingContentRegex = new RegExp( `${sectionStart}.*?${sectionEnd}`, - 's' + 's', ) newContentWithoutFrontMatter = existingContentWithoutFrontmatter.replace( existingContentRegex, - contentWithoutFrontmatter + contentWithoutFrontmatter, ) existingFrontMatter[frontMatterIdx] = newFrontMatter[0] @@ -344,12 +347,12 @@ export default class OmnivorePlugin extends Plugin { } const newFrontMatterStr = `---\n${stringifyYaml( - existingFrontMatter + existingFrontMatter, )}---` await this.app.vault.modify( omnivoreFile, - `${newFrontMatterStr}\n\n${newContentWithoutFrontMatter}` + `${newFrontMatterStr}\n\n${newContentWithoutFrontMatter}`, ) continue } @@ -366,9 +369,8 @@ export default class OmnivorePlugin extends Plugin { this.app.vault.getAbstractFileByPath(newNormalizedPath) if (newOmnivoreFile instanceof TFile) { // a file with the same name and id already exists, so we need to update it - const existingContent = await this.app.vault.read( - newOmnivoreFile - ) + const existingContent = + await this.app.vault.read(newOmnivoreFile) if (existingContent !== content) { await this.app.vault.modify(newOmnivoreFile, content) } @@ -383,7 +385,7 @@ export default class OmnivorePlugin extends Plugin { if (existingContent !== content) { await this.app.vault.modify(omnivoreFile, content) } - } + }, ) continue } @@ -393,7 +395,7 @@ export default class OmnivorePlugin extends Plugin { } catch (error) { if (error.toString().includes('File already exists')) { new Notice( - `Skipping file creation: ${normalizedPath}. Please check if you have duplicated article titles and delete the file if needed.` + `Skipping file creation: ${normalizedPath}. Please check if you have duplicated article titles and delete the file if needed.`, ) } else { throw error @@ -427,7 +429,7 @@ export default class OmnivorePlugin extends Plugin { const isDeleted = deleteArticleById( this.settings.endpoint, this.settings.apiKey, - articleId + articleId, ) if (!isDeleted) { new Notice('Failed to delete article in Omnivore') @@ -471,9 +473,9 @@ class OmnivoreSettingTab extends PluginSettingTab { fragment.createEl('a', { text: 'https://omnivore.app/settings/api', href: 'https://omnivore.app/settings/api', - }) + }), ) - }) + }), ) .addText((text) => text @@ -482,13 +484,13 @@ class OmnivoreSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.apiKey = value await this.plugin.saveSettings() - }) + }), ) new Setting(containerEl) .setName('Filter') .setDesc( - "Select an Omnivore search filter type. Changing this would update the 'Custom Query' accordingly and reset the 'Last sync' timestamp" + "Select an Omnivore search filter type. Changing this would update the 'Custom Query' accordingly and reset the 'Last sync' timestamp", ) .addDropdown((dropdown) => { dropdown.addOptions(Filter) @@ -513,14 +515,14 @@ class OmnivoreSettingTab extends PluginSettingTab { text: 'https://docs.omnivore.app/using/search', href: 'https://docs.omnivore.app/using/search', }), - " for more info on search query syntax. Changing this would reset the 'Last Sync' timestamp" + " for more info on search query syntax. Changing this would reset the 'Last Sync' timestamp", ) - }) + }), ) .addText((text) => text .setPlaceholder( - 'Enter an Omnivore custom search query if advanced filter is selected' + 'Enter an Omnivore custom search query if advanced filter is selected', ) .setValue(this.plugin.settings.customQuery) .onChange(async (value) => { @@ -528,13 +530,13 @@ class OmnivoreSettingTab extends PluginSettingTab { this.plugin.settings.syncAt = '' await this.plugin.saveSettings() this.display() - }) + }), ) new Setting(containerEl) .setName('Last Sync') .setDesc( - "Last time the plugin synced with Omnivore. The 'Sync' command fetches articles updated after this timestamp" + "Last time the plugin synced with Omnivore. The 'Sync' command fetches articles updated after this timestamp", ) .addMomentFormat((momentFormat) => momentFormat @@ -544,7 +546,7 @@ class OmnivoreSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.syncAt = value await this.plugin.saveSettings() - }) + }), ) new Setting(containerEl) @@ -575,9 +577,9 @@ class OmnivoreSettingTab extends PluginSettingTab { }), fragment.createEl('br'), fragment.createEl('br'), - 'If you want to use a custom front matter template, you can enter it below under the advanced settings' + 'If you want to use a custom front matter template, you can enter it below under the advanced settings', ) - }) + }), ) .addTextArea((text) => { text @@ -591,7 +593,7 @@ class OmnivoreSettingTab extends PluginSettingTab { .filter( (v, i, a) => FRONT_MATTER_VARIABLES.includes(v.split('::')[0]) && - a.indexOf(v) === i + a.indexOf(v) === i, ) await this.plugin.saveSettings() }) @@ -611,9 +613,9 @@ class OmnivoreSettingTab extends PluginSettingTab { }), fragment.createEl('br'), fragment.createEl('br'), - 'If you want to use a custom front matter template, you can enter it below under the advanced settings' + 'If you want to use a custom front matter template, you can enter it below under the advanced settings', ) - }) + }), ) .addTextArea((text) => { text @@ -645,7 +647,7 @@ class OmnivoreSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Frequency') .setDesc( - 'Enter the frequency in minutes to sync with Omnivore automatically. 0 means manual sync' + 'Enter the frequency in minutes to sync with Omnivore automatically. 0 means manual sync', ) .addText((text) => text @@ -663,13 +665,13 @@ class OmnivoreSettingTab extends PluginSettingTab { await this.plugin.saveSettings() this.plugin.scheduleSync() - }) + }), ) new Setting(containerEl) .setName('Folder') .setDesc( - 'Enter the folder where the data will be stored. {{{title}}}, {{{dateSaved}}} and {{{datePublished}}} could be used in the folder name' + 'Enter the folder where the data will be stored. {{{title}}}, {{{dateSaved}}} and {{{datePublished}}} could be used in the folder name', ) .addSearch((search) => { new FolderSuggest(this.app, search.inputEl) @@ -684,7 +686,7 @@ class OmnivoreSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Attachment Folder') .setDesc( - 'Enter the folder where the attachment will be downloaded to. {{{title}}}, {{{dateSaved}}} and {{{datePublished}}} could be used in the folder name' + 'Enter the folder where the attachment will be downloaded to. {{{title}}}, {{{dateSaved}}} and {{{datePublished}}} could be used in the folder name', ) .addSearch((search) => { new FolderSuggest(this.app, search.inputEl) @@ -700,7 +702,7 @@ class OmnivoreSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Is Single File') .setDesc( - 'Check this box if you want to save all articles in a single file' + 'Check this box if you want to save all articles in a single file', ) .addToggle((toggle) => toggle @@ -708,13 +710,13 @@ class OmnivoreSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.isSingleFile = value await this.plugin.saveSettings() - }) + }), ) new Setting(containerEl) .setName('Filename') .setDesc( - 'Enter the filename where the data will be stored. {{id}}, {{{title}}}, {{{dateSaved}}} and {{{datePublished}}} could be used in the filename' + 'Enter the filename where the data will be stored. {{id}}, {{{title}}}, {{{dateSaved}}} and {{{datePublished}}} could be used in the filename', ) .addText((text) => text @@ -723,7 +725,7 @@ class OmnivoreSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.filename = value await this.plugin.saveSettings() - }) + }), ) new Setting(containerEl) @@ -735,9 +737,9 @@ class OmnivoreSettingTab extends PluginSettingTab { fragment.createEl('a', { text: 'reference', href: 'https://moment.github.io/luxon/#/formatting?id=table-of-tokens', - }) + }), ) - }) + }), ) .addText((text) => text @@ -746,7 +748,7 @@ class OmnivoreSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.filenameDateFormat = value await this.plugin.saveSettings() - }) + }), ) new Setting(containerEl) @@ -758,9 +760,9 @@ class OmnivoreSettingTab extends PluginSettingTab { fragment.createEl('a', { text: 'reference', href: 'https://moment.github.io/luxon/#/formatting?id=table-of-tokens', - }) + }), ) - }) + }), ) .addText((text) => text @@ -769,12 +771,12 @@ class OmnivoreSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.folderDateFormat = value await this.plugin.saveSettings() - }) + }), ) new Setting(containerEl) .setName('Date Saved Format') .setDesc( - 'Enter the date format for dateSaved variable in rendered template' + 'Enter the date format for dateSaved variable in rendered template', ) .addText((text) => text @@ -783,12 +785,12 @@ class OmnivoreSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.dateSavedFormat = value await this.plugin.saveSettings() - }) + }), ) new Setting(containerEl) .setName('Date Highlighted Format') .setDesc( - 'Enter the date format for dateHighlighted variable in rendered template' + 'Enter the date format for dateHighlighted variable in rendered template', ) .addText((text) => text @@ -797,7 +799,7 @@ class OmnivoreSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.dateHighlightedFormat = value await this.plugin.saveSettings() - }) + }), ) containerEl.createEl('h5', { @@ -819,7 +821,7 @@ class OmnivoreSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.endpoint = value await this.plugin.saveSettings() - }) + }), ) new Setting(advancedSettings) @@ -837,9 +839,9 @@ class OmnivoreSettingTab extends PluginSettingTab { 'We recommend you to use Front Matter section under the basic settings to define the metadata.', fragment.createEl('br'), fragment.createEl('br'), - 'If this template is set, it will override the Front Matter so please make sure your template is a valid YAML.' + 'If this template is set, it will override the Front Matter so please make sure your template is a valid YAML.', ) - }) + }), ) .addTextArea((text) => { text diff --git a/src/settings/index.ts b/src/settings/index.ts index 5dd40c1..d72c167 100644 --- a/src/settings/index.ts +++ b/src/settings/index.ts @@ -17,7 +17,7 @@ export const FRONT_MATTER_VARIABLES = [ 'read_length', 'state', 'date_archived', - 'image' + 'image', ] export const DEFAULT_SETTINGS: OmnivoreSettings = { diff --git a/src/settings/suggest.ts b/src/settings/suggest.ts index d2def24..430bce6 100644 --- a/src/settings/suggest.ts +++ b/src/settings/suggest.ts @@ -18,12 +18,12 @@ class Suggest { containerEl.on( 'click', '.suggestion-item', - this.onSuggestionClick.bind(this) + this.onSuggestionClick.bind(this), ) containerEl.on( 'mousemove', '.suggestion-item', - this.onSuggestionMouseover.bind(this) + this.onSuggestionMouseover.bind(this), ) scope.register([], 'ArrowUp', (event) => { @@ -127,7 +127,7 @@ export abstract class TextInputSuggest implements ISuggestOwner { '.suggestion-container', (event: MouseEvent) => { event.preventDefault() - } + }, ) } diff --git a/src/settings/template.ts b/src/settings/template.ts index 04dd135..156a4b9 100644 --- a/src/settings/template.ts +++ b/src/settings/template.ts @@ -15,7 +15,7 @@ import { type FunctionMap = { [key: string]: () => ( text: string, - render: (text: string) => string + render: (text: string) => string, ) => string } @@ -81,301 +81,300 @@ export type ArticleView = } | FunctionMap - export type View = - | { - id: string - title: string - omnivoreUrl: string - siteName: string - originalUrl: string - author: string - date: string - dateSaved: string - datePublished?: string - type: PageType - dateRead?: string - state: string - dateArchived?: string - } - | FunctionMap - - enum ArticleState { - Inbox = 'INBOX', - Reading = 'READING', - Completed = 'COMPLETED', - Archived = 'ARCHIVED', - } - - const getArticleState = (article: Article): string => { - if (article.isArchived) { - return ArticleState.Archived - } - if (article.readingProgressPercent > 0) { - return article.readingProgressPercent === 100 - ? ArticleState.Completed - : ArticleState.Reading +export type View = + | { + id: string + title: string + omnivoreUrl: string + siteName: string + originalUrl: string + author: string + date: string + dateSaved: string + datePublished?: string + type: PageType + dateRead?: string + state: string + dateArchived?: string } + | FunctionMap - return ArticleState.Inbox - } +enum ArticleState { + Inbox = 'INBOX', + Reading = 'READING', + Completed = 'COMPLETED', + Archived = 'ARCHIVED', +} - function lowerCase() { - return function (text: string, render: (text: string) => string) { - return render(text).toLowerCase() - } +const getArticleState = (article: Article): string => { + if (article.isArchived) { + return ArticleState.Archived } - - function upperCase() { - return function (text: string, render: (text: string) => string) { - return render(text).toUpperCase() - } + if (article.readingProgressPercent > 0) { + return article.readingProgressPercent === 100 + ? ArticleState.Completed + : ArticleState.Reading } - function upperCaseFirst() { - return function (text: string, render: (text: string) => string) { - const str = render(text) - return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase() - } + return ArticleState.Inbox +} + +function lowerCase() { + return function (text: string, render: (text: string) => string) { + return render(text).toLowerCase() } +} - function formatDateFunc() { - return function (text: string, render: (text: string) => string) { - // get the date and format from the text - const [dateVariable, format] = text.split(',', 2) - const date = render(dateVariable) - if (!date) { - return '' - } - // format the date - return formatDate(date, format) - } +function upperCase() { + return function (text: string, render: (text: string) => string) { + return render(text).toUpperCase() } +} - const functionMap: FunctionMap = { - lowerCase, - upperCase, - upperCaseFirst, - formatDate: formatDateFunc, +function upperCaseFirst() { + return function (text: string, render: (text: string) => string) { + const str = render(text) + return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase() } +} - const getOmnivoreUrl = (article: Article) => { - return `https://omnivore.app/me/${article.slug}` +function formatDateFunc() { + return function (text: string, render: (text: string) => string) { + // get the date and format from the text + const [dateVariable, format] = text.split(',', 2) + const date = render(dateVariable) + if (!date) { + return '' + } + // format the date + return formatDate(date, format) } +} - export const renderFilename = ( - article: Article, - filename: string, - dateFormat: string - ) => { - const renderedFilename = render(article, filename, dateFormat) +const functionMap: FunctionMap = { + lowerCase, + upperCase, + upperCaseFirst, + formatDate: formatDateFunc, +} - // truncate the filename to 100 characters - return truncate(renderedFilename, { - length: 100, - }) - } +const getOmnivoreUrl = (article: Article) => { + return `https://omnivore.app/me/${article.slug}` +} - export const renderLabels = (labels?: LabelView[]) => { - return labels?.map((l) => ({ - // replace spaces with underscores because Obsidian doesn't allow spaces in tags - name: l.name.replaceAll(' ', '_'), - })) - } +export const renderFilename = ( + article: Article, + filename: string, + dateFormat: string, +) => { + const renderedFilename = render(article, filename, dateFormat) + + // truncate the filename to 100 characters + return truncate(renderedFilename, { + length: 100, + }) +} + +export const renderLabels = (labels?: LabelView[]) => { + return labels?.map((l) => ({ + // replace spaces with underscores because Obsidian doesn't allow spaces in tags + name: l.name.replaceAll(' ', '_'), + })) +} - export const renderArticleContnet = async ( - article: Article, - template: string, - highlightOrder: string, - dateHighlightedFormat: string, - dateSavedFormat: string, - isSingleFile: boolean, - frontMatterVariables: string[], - frontMatterTemplate: string, - fileAttachment?: string - ) => { - // filter out notes and redactions - const articleHighlights = - article.highlights?.filter((h) => h.type === HighlightType.Highlight) || - [] - // sort highlights by location if selected in options - if (highlightOrder === 'LOCATION') { - articleHighlights.sort((a, b) => { - try { - if (article.pageType === PageType.File) { - // sort by location in file - return compareHighlightsInFile(a, b) - } - // for web page, sort by location in the page - return getHighlightLocation(a.patch) - getHighlightLocation(b.patch) - } catch (e) { - console.error(e) +export const renderArticleContnet = async ( + article: Article, + template: string, + highlightOrder: string, + dateHighlightedFormat: string, + dateSavedFormat: string, + isSingleFile: boolean, + frontMatterVariables: string[], + frontMatterTemplate: string, + fileAttachment?: string, +) => { + // filter out notes and redactions + const articleHighlights = + article.highlights?.filter((h) => h.type === HighlightType.Highlight) || [] + // sort highlights by location if selected in options + if (highlightOrder === 'LOCATION') { + articleHighlights.sort((a, b) => { + try { + if (article.pageType === PageType.File) { + // sort by location in file return compareHighlightsInFile(a, b) } - }) - } - const highlights: HighlightView[] = articleHighlights.map((highlight) => { - return { - text: formatHighlightQuote(highlight.quote, template), - highlightUrl: `https://omnivore.app/me/${article.slug}#${highlight.id}`, - highlightID: highlight.id.slice(0, 8), - dateHighlighted: formatDate(highlight.updatedAt, dateHighlightedFormat), - note: highlight.annotation ?? undefined, - labels: renderLabels(highlight.labels), - color: highlight.color ?? 'yellow', - positionPercent: highlight.highlightPositionPercent, - positionAnchorIndex: highlight.highlightPositionAnchorIndex + 1, // PDF page numbers start at 1 + // for web page, sort by location in the page + return getHighlightLocation(a.patch) - getHighlightLocation(b.patch) + } catch (e) { + console.error(e) + return compareHighlightsInFile(a, b) } }) - const dateSaved = formatDate(article.savedAt, dateSavedFormat) - const siteName = - article.siteName || siteNameFromUrl(article.originalArticleUrl) - const publishedAt = article.publishedAt - const datePublished = publishedAt - ? formatDate(publishedAt, dateSavedFormat).trim() - : undefined - const articleNote = article.highlights?.find( - (h) => h.type === HighlightType.Note - ) - const dateRead = article.readAt - ? formatDate(article.readAt, dateSavedFormat).trim() - : undefined - const wordsCount = article.wordsCount - const readLength = wordsCount - ? Math.round(Math.max(1, wordsCount / 235)) - : undefined - const articleView: ArticleView = { - id: article.id, - title: article.title, - omnivoreUrl: `https://omnivore.app/me/${article.slug}`, - siteName, - originalUrl: article.originalArticleUrl, - author: article.author, - labels: renderLabels(article.labels), - dateSaved, - highlights, - content: article.contentReader === 'WEB' ? article.content : undefined, - datePublished, - fileAttachment, - description: article.description, - note: articleNote?.annotation ?? undefined, - type: article.pageType, - dateRead, - wordsCount, - readLength, - state: getArticleState(article), - dateArchived: article.archivedAt, - image: article.image, - updatedAt: article.updatedAt, - ...functionMap, + } + const highlights: HighlightView[] = articleHighlights.map((highlight) => { + return { + text: formatHighlightQuote(highlight.quote, template), + highlightUrl: `https://omnivore.app/me/${article.slug}#${highlight.id}`, + highlightID: highlight.id.slice(0, 8), + dateHighlighted: formatDate(highlight.updatedAt, dateHighlightedFormat), + note: highlight.annotation ?? undefined, + labels: renderLabels(highlight.labels), + color: highlight.color ?? 'yellow', + positionPercent: highlight.highlightPositionPercent, + positionAnchorIndex: highlight.highlightPositionAnchorIndex + 1, // PDF page numbers start at 1 } + }) + const dateSaved = formatDate(article.savedAt, dateSavedFormat) + const siteName = + article.siteName || siteNameFromUrl(article.originalArticleUrl) + const publishedAt = article.publishedAt + const datePublished = publishedAt + ? formatDate(publishedAt, dateSavedFormat).trim() + : undefined + const articleNote = article.highlights?.find( + (h) => h.type === HighlightType.Note, + ) + const dateRead = article.readAt + ? formatDate(article.readAt, dateSavedFormat).trim() + : undefined + const wordsCount = article.wordsCount + const readLength = wordsCount + ? Math.round(Math.max(1, wordsCount / 235)) + : undefined + const articleView: ArticleView = { + id: article.id, + title: article.title, + omnivoreUrl: `https://omnivore.app/me/${article.slug}`, + siteName, + originalUrl: article.originalArticleUrl, + author: article.author, + labels: renderLabels(article.labels), + dateSaved, + highlights, + content: article.contentReader === 'WEB' ? article.content : undefined, + datePublished, + fileAttachment, + description: article.description, + note: articleNote?.annotation ?? undefined, + type: article.pageType, + dateRead, + wordsCount, + readLength, + state: getArticleState(article), + dateArchived: article.archivedAt, + image: article.image, + updatedAt: article.updatedAt, + ...functionMap, + } - let frontMatter: { [id: string]: unknown } = { - id: article.id, // id is required for deduplication - } + let frontMatter: { [id: string]: unknown } = { + id: article.id, // id is required for deduplication + } - // if the front matter template is set, use it - if (frontMatterTemplate) { - const frontMatterTemplateRendered = Mustache.render( - frontMatterTemplate, - articleView - ) - try { - // parse the front matter template as yaml - const frontMatterParsed = parseYaml(frontMatterTemplateRendered) + // if the front matter template is set, use it + if (frontMatterTemplate) { + const frontMatterTemplateRendered = Mustache.render( + frontMatterTemplate, + articleView, + ) + try { + // parse the front matter template as yaml + const frontMatterParsed = parseYaml(frontMatterTemplateRendered) - frontMatter = { - ...frontMatterParsed, - ...frontMatter, - } - } catch (error) { - // if there's an error parsing the front matter template, log it - console.error('Error parsing front matter template', error) - // and add the error to the front matter - frontMatter = { - ...frontMatter, - omnivore_error: - 'There was an error parsing the front matter template. See console for details.', - } + frontMatter = { + ...frontMatterParsed, + ...frontMatter, } - } else { - // otherwise, use the front matter variables - for (const item of frontMatterVariables) { - // split the item into variable and alias - const aliasedVariables = item.split('::') - const variable = aliasedVariables[0] - // we use snake case for variables in the front matter - const articleVariable = snakeToCamelCase(variable) - // use alias if available, otherwise use variable - const key = aliasedVariables[1] || variable - if ( - variable === 'tags' && - articleView.labels && - articleView.labels.length > 0 - ) { - // tags are handled separately - // use label names as tags - frontMatter[key] = articleView.labels.map((l) => l.name) - continue - } - - const value = (articleView as any)[articleVariable] - if (value) { - // if variable is in article, use it - frontMatter[key] = value - } + } catch (error) { + // if there's an error parsing the front matter template, log it + console.error('Error parsing front matter template', error) + // and add the error to the front matter + frontMatter = { + ...frontMatter, + omnivore_error: + 'There was an error parsing the front matter template. See console for details.', } } + } else { + // otherwise, use the front matter variables + for (const item of frontMatterVariables) { + // split the item into variable and alias + const aliasedVariables = item.split('::') + const variable = aliasedVariables[0] + // we use snake case for variables in the front matter + const articleVariable = snakeToCamelCase(variable) + // use alias if available, otherwise use variable + const key = aliasedVariables[1] || variable + if ( + variable === 'tags' && + articleView.labels && + articleView.labels.length > 0 + ) { + // tags are handled separately + // use label names as tags + frontMatter[key] = articleView.labels.map((l) => l.name) + continue + } - // Build content string based on template - const content = Mustache.render(template, articleView) - let contentWithoutFrontMatter = removeFrontMatterFromContent(content) - let frontMatterYaml = stringifyYaml(frontMatter) - if (isSingleFile) { - // wrap the content without front matter in comments - const sectionStart = `%%${article.id}_start%%` - const sectionEnd = `%%${article.id}_end%%` - contentWithoutFrontMatter = `${sectionStart}\n${contentWithoutFrontMatter}\n${sectionEnd}` - - // if single file, wrap the front matter in an array - frontMatterYaml = stringifyYaml([frontMatter]) + const value = (articleView as any)[articleVariable] + if (value) { + // if variable is in article, use it + frontMatter[key] = value + } } + } - const frontMatterStr = `---\n${frontMatterYaml}---` - - return `${frontMatterStr}\n\n${contentWithoutFrontMatter}` + // Build content string based on template + const content = Mustache.render(template, articleView) + let contentWithoutFrontMatter = removeFrontMatterFromContent(content) + let frontMatterYaml = stringifyYaml(frontMatter) + if (isSingleFile) { + // wrap the content without front matter in comments + const sectionStart = `%%${article.id}_start%%` + const sectionEnd = `%%${article.id}_end%%` + contentWithoutFrontMatter = `${sectionStart}\n${contentWithoutFrontMatter}\n${sectionEnd}` + + // if single file, wrap the front matter in an array + frontMatterYaml = stringifyYaml([frontMatter]) } - export const render = ( - article: Article, - template: string, - dateFormat: string - ) => { - const dateSaved = formatDate(article.savedAt, dateFormat) - const datePublished = article.publishedAt - ? formatDate(article.publishedAt, dateFormat).trim() - : undefined - const dateArchived = article.archivedAt - ? formatDate(article.archivedAt, dateFormat).trim() - : undefined - const dateRead = article.readAt - ? formatDate(article.readAt, dateFormat).trim() - : undefined - const view: View = { - ...article, - author: article.author || 'unknown-author', - omnivoreUrl: getOmnivoreUrl(article), - originalUrl: article.originalArticleUrl, - date: dateSaved, - dateSaved, - datePublished, - dateArchived, - dateRead, - type: article.pageType, - state: getArticleState(article), - ...functionMap, - } - return Mustache.render(template, view) + const frontMatterStr = `---\n${frontMatterYaml}---` + + return `${frontMatterStr}\n\n${contentWithoutFrontMatter}` +} + +export const render = ( + article: Article, + template: string, + dateFormat: string, +) => { + const dateSaved = formatDate(article.savedAt, dateFormat) + const datePublished = article.publishedAt + ? formatDate(article.publishedAt, dateFormat).trim() + : undefined + const dateArchived = article.archivedAt + ? formatDate(article.archivedAt, dateFormat).trim() + : undefined + const dateRead = article.readAt + ? formatDate(article.readAt, dateFormat).trim() + : undefined + const view: View = { + ...article, + author: article.author || 'unknown-author', + omnivoreUrl: getOmnivoreUrl(article), + originalUrl: article.originalArticleUrl, + date: dateSaved, + dateSaved, + datePublished, + dateArchived, + dateRead, + type: article.pageType, + state: getArticleState(article), + ...functionMap, } + return Mustache.render(template, view) +} export const preParseTemplate = (template: string) => { return Mustache.parse(template) diff --git a/src/util.ts b/src/util.ts index 2cd27d7..1b762e9 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,21 +1,21 @@ -import { diff_match_patch } from "diff-match-patch" -import { DateTime } from "luxon" -import escape from "markdown-escape" -import { parseYaml } from "obsidian" -import outOfCharacter from "out-of-character" -import { Highlight } from "./api" +import { diff_match_patch } from 'diff-match-patch' +import { DateTime } from 'luxon' +import escape from 'markdown-escape' +import { parseYaml } from 'obsidian' +import outOfCharacter from 'out-of-character' +import { Highlight } from './api' export const DATE_FORMAT_W_OUT_SECONDS = "yyyy-MM-dd'T'HH:mm" export const DATE_FORMAT = `${DATE_FORMAT_W_OUT_SECONDS}:ss` -export const REPLACEMENT_CHAR = "-" +export const REPLACEMENT_CHAR = '-' // On Unix-like systems / is reserved and <>:"/\|?* as well as non-printable characters \u0000-\u001F on Windows // credit: https://github.com/sindresorhus/filename-reserved-regex // eslint-disable-next-line no-control-regex export const ILLEGAL_CHAR_REGEX = /[<>:"/\\|?*\u0000-\u001F]/g export interface HighlightPoint { - left: number; - top: number; + left: number + top: number } export const getHighlightLocation = (patch: string | null): number => { @@ -54,7 +54,7 @@ export const markdownEscape = (text: string): string => { try { return escape(text) } catch (e) { - console.error("markdownEscape error", e) + console.error('markdownEscape error', e) return text } } @@ -78,29 +78,27 @@ export const wrapAround = (value: number, size: number): number => { export const unicodeSlug = (str: string, savedAt: string) => { return ( str - .normalize("NFKD") // using NFKD method returns the Unicode Normalization Form of a given string. - .replace(/[\u0300-\u036f]/g, "") // remove all previously split accents + .normalize('NFKD') // using NFKD method returns the Unicode Normalization Form of a given string. + .replace(/[\u0300-\u036f]/g, '') // remove all previously split accents .trim() .toLowerCase() .replace( /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, - "" + '', ) // replace all the symbols with - - .replace(/\s+/g, "-") // collapse whitespace and replace by - - .replace(/_/g, "-") // replace _ with - - .replace(/-+/g, "-") // collapse dashes + .replace(/\s+/g, '-') // collapse whitespace and replace by - + .replace(/_/g, '-') // replace _ with - + .replace(/-+/g, '-') // collapse dashes // remove trailing - - .replace(/-$/g, "") + .replace(/-$/g, '') .substring(0, 64) + - "-" + + '-' + new Date(savedAt).getTime().toString(16) ) } export const replaceIllegalChars = (str: string): string => { - return removeInvisibleChars( - str.replace(ILLEGAL_CHAR_REGEX, REPLACEMENT_CHAR) - ) + return removeInvisibleChars(str.replace(ILLEGAL_CHAR_REGEX, REPLACEMENT_CHAR)) } export function formatDate(date: string, format: string): string { @@ -127,24 +125,24 @@ export const getQueryFromFilter = (filter: string): string => { export const siteNameFromUrl = (originalArticleUrl: string): string => { try { - return new URL(originalArticleUrl).hostname.replace(/^www\./, "") + return new URL(originalArticleUrl).hostname.replace(/^www\./, '') } catch { - return "" + return '' } } export const formatHighlightQuote = ( quote: string | null, - template: string + template: string, ): string => { if (!quote) { - return "" + return '' } // if the template has highlights, we need to preserve paragraphs const regex = /{{#highlights}}(\n)*>/gm if (regex.test(template)) { // replace all empty lines with blockquote '>' to preserve paragraphs - quote = quote.replaceAll(">", ">").replaceAll(/\n/gm, "\n> ") + quote = quote.replaceAll('>', '>').replaceAll(/\n/gm, '\n> ') } return quote @@ -152,7 +150,7 @@ export const formatHighlightQuote = ( export const findFrontMatterIndex = ( frontMatter: any[], - id: string + id: string, ): number => { // find index of front matter with matching id return frontMatter.findIndex((fm) => fm.id == id) @@ -171,11 +169,11 @@ export const parseFrontMatterFromContent = (content: string) => { export const removeFrontMatterFromContent = (content: string): string => { const frontMatterRegex = /^---.*?---\n*/s - return content.replace(frontMatterRegex, "") + return content.replace(frontMatterRegex, '') } export const snakeToCamelCase = (str: string) => - str.replace(/(_[a-z])/g, (group) => group.toUpperCase().replace("_", "")) + str.replace(/(_[a-z])/g, (group) => group.toUpperCase().replace('_', '')) const removeInvisibleChars = (str: string): string => { return outOfCharacter.replace(str) diff --git a/yarn.lock b/yarn.lock index f21bbc0..d2427dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -997,6 +997,11 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== + "@pnpm/config.env-replace@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c" @@ -2439,6 +2444,19 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== + +eslint-plugin-prettier@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz#17cfade9e732cef32b5f5be53bd4e07afd8e67e1" + integrity sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.8.6" + eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -2605,6 +2623,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + fast-glob@^3.2.9: version "3.2.12" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" @@ -4913,10 +4936,17 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@^2.8.1: - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== pretty-format@^29.0.0, pretty-format@^29.5.0: version "29.5.0" @@ -5563,6 +5593,14 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +synckit@^0.8.6: + version "0.8.8" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7" + integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + tar@^6.1.0, tar@^6.1.11, tar@^6.1.2: version "6.1.15" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.15.tgz#c9738b0b98845a3b344d334b8fa3041aaba53a69" @@ -5696,6 +5734,11 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"