diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..b7876de --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,22 @@ +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + plugins: [ + '@typescript-eslint' + ], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended' + ], + env: { + node: true, + jest: true + }, + rules: { + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-explicit-any': 'warn', + 'no-console': ['warn', { allow: ['warn', 'error'] }], + 'semi': ['error', 'always'], + 'quotes': ['error', 'single'] + } +}; \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c722951..91cc29c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,4 +26,7 @@ jobs: run: npm ci - name: Run tests - run: npm test \ No newline at end of file + run: npm test + + - name: Run linting + run: npm run lint \ No newline at end of file diff --git a/.gitignore b/.gitignore index 837762e..36a04ec 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ node_modules main.js main.test.js +obsidian.js diff --git a/__mocks__/obsidian.ts b/__mocks__/obsidian.ts index 03874c9..a5e4883 100644 --- a/__mocks__/obsidian.ts +++ b/__mocks__/obsidian.ts @@ -1,7 +1,5 @@ export class Plugin { - app: any; - registerEvent(_: any) {} - addCommand(_: any) {} + app: unknown; } export class TFile { @@ -25,7 +23,7 @@ export interface HeadingCache { export interface FrontMatterCache { title?: string; - [key: string]: any; + [key: string]: unknown; } export interface CachedMetadata { @@ -41,12 +39,17 @@ export interface CachedMetadata { frontmatter?: FrontMatterCache; } -export function debounce(func: Function, timeout: number, immediate?: boolean) { +export function debounce( + func: (...args: unknown[]) => unknown, + _timeout: number, + _immediate?: boolean +) { return func; } export class Notice { constructor(message: string) { + // eslint-disable-next-line no-console console.log(message); } } diff --git a/changelog.md b/changelog.md index 70e9e77..175ae5f 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,10 @@ All notable changes to the Title As Link Text plugin will be documented in this file. +## [1.1.4] - 🚀 Release version + +- Mainly just a code cleanup, and ensuring the all platforms are supported. + ## [1.1.3] - 🐛 Bug Fix ### Fixed diff --git a/main.test.ts b/main.test.ts index 066f08e..0558ac7 100644 --- a/main.test.ts +++ b/main.test.ts @@ -1,53 +1,32 @@ import { TFile, CachedMetadata, HeadingCache } from 'obsidian'; import { LinkUpdater, VaultLike, MetadataCacheLike } from './main'; -class MockApp { - vault: any; - metadataCache: any; - constructor() { - this.vault = {}; - this.metadataCache = {}; - } -} - -class MockPluginSettingTab { - app: any; - plugin: any; - constructor(app: any, plugin: any) { - this.app = app; - this.plugin = plugin; - } -} - -class MockPlugin { - app: any; - constructor() { - this.app = new MockApp(); - } - registerEvent() { } - addCommand() { } - addSettingTab() { } - loadData() { return Promise.resolve({}); } - saveData() { return Promise.resolve(); } +// Define proper types for App +interface MockAppInterface { + vault: VaultLike; + metadataCache: MetadataCacheLike; } // Mock the required Obsidian imports jest.mock('obsidian', () => ({ Plugin: class MockPlugin { - app: any; + app: MockAppInterface; constructor() { - this.app = { vault: {}, metadataCache: {} }; + this.app = { + vault: {} as VaultLike, + metadataCache: {} as MetadataCacheLike + }; } - registerEvent() { } - addCommand() { } - addSettingTab() { } - loadData() { return Promise.resolve({}); } - saveData() { return Promise.resolve(); } + registerEvent(): void { /* Mock implementation */ } + addCommand(): void { /* Mock implementation */ } + addSettingTab(): void { /* Mock implementation */ } + loadData(): Promise> { return Promise.resolve({}); } + saveData(): Promise { return Promise.resolve(); } }, PluginSettingTab: class MockPluginSettingTab { - app: any; - plugin: any; - constructor(app: any, plugin: any) { + app: MockAppInterface; + plugin: unknown; + constructor(app: MockAppInterface, plugin: unknown) { this.app = app; this.plugin = plugin; } @@ -58,12 +37,12 @@ jest.mock('obsidian', () => ({ addText: jest.fn().mockReturnThis(), })), Notice: jest.fn(), - debounce: (fn: any) => fn, + debounce: (fn: () => void) => fn, TFile: class { }, })); function basename(path: string): string { - let base = new String(path).substring(path.lastIndexOf("/") + 1); + const base = new String(path).substring(path.lastIndexOf('/') + 1); return base; } @@ -78,10 +57,15 @@ class MockVault implements VaultLike { } getMarkdownFiles(): TFile[] { - return Array.from(this.files.keys()).map(path => ({ - path, - name: basename(path), - }) as TFile); + return Array.from(this.files.keys()).map(path => { + const file = new TFile(); + file.path = path; + file.name = basename(path); + if (!(file instanceof TFile)) { + throw new Error('Failed to create TFile instance'); + } + return file; + }); } async read(file: TFile): Promise { @@ -92,7 +76,9 @@ class MockVault implements VaultLike { this.files.set(file.path, content); } - on() { } // No-op for testing + on(): void { + // Intentionally empty for testing + } } // Mock implementation of MetadataCache @@ -107,19 +93,24 @@ class MockMetadataCache implements MetadataCacheLike { return this.fileCache[path] || null; } - getFirstLinkpathDest(linkpath: string, sourcePath: string): TFile | null { + getFirstLinkpathDest(linkpath: string, _sourcePath: string): TFile | null { + // Prefix unused parameter with underscore const normalizedLinkpath = linkpath.endsWith('.md') ? linkpath : `${linkpath}.md`; if (this.fileCache[normalizedLinkpath]) { - const result = { - path: normalizedLinkpath, - name: basename(normalizedLinkpath) - } as TFile; - return result; + const file = new TFile(); + file.path = normalizedLinkpath; + file.name = basename(normalizedLinkpath); + if (!(file instanceof TFile)) { + throw new Error('Failed to create TFile instance'); + } + return file; } return null; } - on() { } + on(): void { + // Intentionally empty for testing + } } describe('LinkUpdater', () => { @@ -133,10 +124,15 @@ describe('LinkUpdater', () => { similarityThreshold: 0.65 }; - const createSourceFile = (path: string = 'note1.md'): TFile => ({ - path, - name: path - } as TFile); + const createSourceFile = (path = 'note1.md'): TFile => { + const file = new TFile(); + file.path = path; + file.name = path; + if (!(file instanceof TFile)) { + throw new Error('Failed to create TFile instance'); + } + return file; + }; const setupTest = ( files: { [path: string]: string }, @@ -161,12 +157,12 @@ describe('LinkUpdater', () => { link: 'note2.md', original: '[link](note2.md)', }], - headings: [{ heading: "New Title" }] as HeadingCache[], + headings: [{ heading: 'New Title' }] as HeadingCache[], frontmatter: undefined } as CachedMetadata, 'note2.md': { frontmatter: { title: 'Front Matter Title' }, - headings: [{ heading: "New Title" }] as HeadingCache[], + headings: [{ heading: 'New Title' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -189,12 +185,12 @@ describe('LinkUpdater', () => { link: 'note2.md', original: '[link](note2.md)', }], - headings: [{ heading: "New Title" }] as HeadingCache[], + headings: [{ heading: 'New Title' }] as HeadingCache[], frontmatter: undefined } as CachedMetadata, 'note2.md': { frontmatter: undefined, - headings: [{ heading: "Heading Title" }] as HeadingCache[], + headings: [{ heading: 'Heading Title' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -224,7 +220,7 @@ describe('LinkUpdater', () => { title: 'Dogs 1', aliases: ['Hello', 'World'] }, - headings: [{ heading: "Different Title" }] as HeadingCache[], + headings: [{ heading: 'Different Title' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -333,12 +329,12 @@ describe('LinkUpdater', () => { link: 'note2', original: '[[note2|link]]', }], - headings: [{ heading: "New Title" }] as HeadingCache[], + headings: [{ heading: 'New Title' }] as HeadingCache[], frontmatter: undefined } as CachedMetadata, 'note2.md': { frontmatter: { title: 'Front Matter Title' }, - headings: [{ heading: "New Title" }] as HeadingCache[], + headings: [{ heading: 'New Title' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -368,7 +364,7 @@ describe('LinkUpdater', () => { title: 'Dogs 1', aliases: ['Hello', 'World'] }, - headings: [{ heading: "Different Title" }] as HeadingCache[], + headings: [{ heading: 'Different Title' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -391,12 +387,12 @@ describe('LinkUpdater', () => { link: 'note2#Subheading', original: '[[note2#Subheading|link]]', }], - headings: [{ heading: "New Title" }] as HeadingCache[], + headings: [{ heading: 'New Title' }] as HeadingCache[], frontmatter: undefined } as CachedMetadata, 'note2.md': { frontmatter: { title: 'Front Matter Title' }, - headings: [{ heading: "New Title" }] as HeadingCache[], + headings: [{ heading: 'New Title' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -558,7 +554,7 @@ describe('LinkUpdater', () => { } as CachedMetadata, 'dogs.md': { frontmatter: undefined, - headings: [{ heading: "dogs" }] as HeadingCache[], + headings: [{ heading: 'dogs' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -648,14 +644,14 @@ describe('LinkUpdater', () => { } ], frontmatter: undefined, - headings: [{ heading: "Heading" }] as HeadingCache[] + headings: [{ heading: 'Heading' }] as HeadingCache[] } as CachedMetadata, 'note2.md': { frontmatter: { title: 'Note 2 Title', aliases: [] // Similar to "Hello" }, - headings: [{ heading: "Heading" }] as HeadingCache[], + headings: [{ heading: 'Heading' }] as HeadingCache[], links: [] } as CachedMetadata, 'note3.md': { @@ -663,7 +659,7 @@ describe('LinkUpdater', () => { title: 'Another Title', aliases: ['Project Z'] // Similar to "Project X" }, - headings: [{ heading: "Heading" }] as HeadingCache[], + headings: [{ heading: 'Heading' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -694,14 +690,14 @@ describe('LinkUpdater', () => { } ], frontmatter: undefined, - headings: [{ heading: "Heading" }] as HeadingCache[] + headings: [{ heading: 'Heading' }] as HeadingCache[] } as CachedMetadata, 'note2.md': { frontmatter: { title: 'Note 2 Title', aliases: [] // Similar to "Hello" }, - headings: [{ heading: "Heading" }] as HeadingCache[], + headings: [{ heading: 'Heading' }] as HeadingCache[], links: [] } as CachedMetadata, 'note3.md': { @@ -709,7 +705,7 @@ describe('LinkUpdater', () => { title: 'Another Title', aliases: ['Project Z'] // Similar to "Project X" }, - headings: [{ heading: "Heading" }] as HeadingCache[], + headings: [{ heading: 'Heading' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -740,14 +736,14 @@ describe('LinkUpdater', () => { } ], frontmatter: undefined, - headings: [{ heading: "Heading" }] as HeadingCache[] + headings: [{ heading: 'Heading' }] as HeadingCache[] } as CachedMetadata, 'note2.md': { frontmatter: { title: 'Note 2 Title', aliases: ['Hello 2'] // Contains "Hello" }, - headings: [{ heading: "Heading" }] as HeadingCache[], + headings: [{ heading: 'Heading' }] as HeadingCache[], links: [] } as CachedMetadata, 'note3.md': { @@ -755,7 +751,7 @@ describe('LinkUpdater', () => { title: 'Another Title', aliases: ['My Project Name'] // Contains "Project" }, - headings: [{ heading: "Heading" }] as HeadingCache[], + headings: [{ heading: 'Heading' }] as HeadingCache[], links: [] } as CachedMetadata } @@ -790,7 +786,6 @@ describe('LinkUpdater', () => { } ); - const updatedCount = await linkUpdater.updateLinksInNote(sourceFile); expect(await vault.read(sourceFile)).toBe('[[ \n\n[Doggos](dogs.md)'); }); }); diff --git a/main.ts b/main.ts index dbae88b..d99b698 100644 --- a/main.ts +++ b/main.ts @@ -1,7 +1,5 @@ import { Plugin, - HeadingCache, - FrontMatterCache, CachedMetadata, TFile, Notice, @@ -10,10 +8,10 @@ import { App, PluginSettingTab, Setting, -} from "obsidian"; +} from 'obsidian'; function basename(path: string): string { - let base = new String(path).substring(path.lastIndexOf("/") + 1); + const base = new String(path).substring(path.lastIndexOf('/') + 1); return base; } @@ -21,14 +19,14 @@ export interface VaultLike { getMarkdownFiles(): TFile[]; read(file: TFile): Promise; modify(file: TFile, content: string): Promise; - on(name: string, callback: (...args: any[]) => any): void; + on(name: string, callback: (file: TFile | TAbstractFile, oldPath?: string) => void): void; } export interface MetadataCacheLike { getFileCache(file: TFile): CachedMetadata | null; getCache(path: string): CachedMetadata | null; getFirstLinkpathDest(linkpath: string, sourcePath: string): TFile | null; - on(name: string, callback: (...args: any[]) => any): void; + on(name: string, callback: (file: TFile) => void): void; } export interface TitleAsLinkTextSettings { @@ -55,7 +53,7 @@ export class LinkUpdater { async updateAllLinks() { const markdownFiles = this.vault.getMarkdownFiles(); - var updatedBacklinksCount = 0; + let updatedBacklinksCount = 0; for (const file of markdownFiles) { const oldPath = file.path; const backLinks = await this.updateBackLinks(file, oldPath, false); @@ -76,19 +74,18 @@ export class LinkUpdater { let updatedCount = 0; - // Markdown link regex breakdown: - // (? { + (match, linkText, linkUrl) => { + // Skip if this is a checkbox pattern + if (match.startsWith('[ ]') || match.startsWith('[x]')) { + return match; + } + const linkUrlDecoded = decodeURIComponent(linkUrl); // Remove any #subheading from the link before looking up the file const baseLinkUrl = linkUrlDecoded.split('#')[0]; @@ -119,15 +116,16 @@ export class LinkUpdater { // Wikilinks regex breakdown: // \[\[ - Match literal opening double brackets - // ([^\]\[\n]+?) - Group 1: Capture chars that aren't brackets or newline, non-greedy - // (?: - Start non-capturing group - // #([^\]\[\n]+?) - Group 2: Optional subheading after #, no brackets/newline, non-greedy - // )? - End optional non-capturing group - // (?: - Start non-capturing group - // \|([^\]\[\n]+?) - Group 3: Optional display text after |, no brackets/newline, non-greedy - // )? - End optional non-capturing group + // ([^\]\[\n]+?) - Group 1: Match one or more chars that aren't brackets or newline (non-greedy) + // This captures the main link path + // (?: - Start non-capturing group for optional subheading + // #([^\]\[\n]+?) - Group 2: Match # followed by one or more non-bracket/newline chars (non-greedy) + // )? - End optional subheading group + // (?: - Start non-capturing group for optional alias + // \|([^\]\[\n]+?) - Group 3: Match | followed by one or more non-bracket/newline chars (non-greedy) + // )? - End optional alias group // \]\] - Match literal closing double brackets - const wikilinkRegex = /\[\[([^\]\[\n]+?)(?:#([^\]\[\n]+?))?(?:\|([^\]\[\n]+?))?\]\]/g + const wikilinkRegex = /\[\[([^\][\n]+?)(?:#([^\][\n]+?))?(?:\|([^\][\n]+?))?]]/g; newFileContent = newFileContent.replace( wikilinkRegex, @@ -179,7 +177,7 @@ export class LinkUpdater { async updateBackLinks(file: TFile, oldPath: string, notify: boolean) { if ( !oldPath || - !file.path.toLocaleLowerCase().endsWith(".md") || + !file.path.toLocaleLowerCase().endsWith('.md') || !(file instanceof TFile) ) { return; @@ -189,7 +187,7 @@ export class LinkUpdater { let updatedBacklinksCount = 0; // Update backlinks in other notes - for (let note of notes) { + for (const note of notes) { const count = await this.updateLinksInNote(note); updatedBacklinksCount += count; } @@ -208,12 +206,12 @@ export class LinkUpdater { } private getCachedNotesThatHaveLinkToFile(filePath: string): TFile[] { - let notesWithBacklinks: TFile[] = []; - let allNotes = this.vault.getMarkdownFiles(); + const notesWithBacklinks: TFile[] = []; + const allNotes = this.vault.getMarkdownFiles(); if (allNotes) { - for (let note of allNotes) { - let notePath = note.path; + for (const note of allNotes) { + const notePath = note.path; if (note.path == filePath) { continue; @@ -225,7 +223,7 @@ export class LinkUpdater { ...(noteCache?.links || []), ]; if (embedsAndLinks) { - for (let link_data of embedsAndLinks) { + for (const link_data of embedsAndLinks) { // getFirstLinkpathDest = Get the best match for a linkpath. // https://marcus.se.net/obsidian-plugin-docs/reference/typescript/classes/MetadataCache const firstLinkPath = this.metadataCache.getFirstLinkpathDest( @@ -245,11 +243,11 @@ export class LinkUpdater { private getPageTitle(cache: CachedMetadata, filePath: string): string { const frontMatterTitle = - cache.frontmatter && (cache.frontmatter as FrontMatterCache).title; + cache.frontmatter && cache.frontmatter.title; const firstHeading = - cache.headings && cache.headings.length > 0 && (cache.headings[0] as HeadingCache).heading; + cache.headings && cache.headings.length > 0 && cache.headings[0].heading; return ( - frontMatterTitle || firstHeading || basename(filePath).replace(".md", "") + frontMatterTitle || firstHeading || basename(filePath).replace('.md', '') ); } @@ -342,7 +340,7 @@ export default class TitleAsLinkTextPlugin extends Plugin { ); this.registerEvent( - this.app.vault.on("rename", async (file: TAbstractFile, oldPath: string) => { + this.app.vault.on('rename', async (file: TAbstractFile, oldPath: string) => { if (file instanceof TFile) { this.debouncedUpdateBackLinks(file, oldPath, true); } @@ -350,14 +348,14 @@ export default class TitleAsLinkTextPlugin extends Plugin { ); this.registerEvent( - this.app.metadataCache.on("changed", async (file: TFile) => { + this.app.metadataCache.on('changed', async (file: TFile) => { this.debouncedUpdateBackLinks(file, file.path, true); }) ); this.addCommand({ - id: "update-all-links", - name: "Update All Links", + id: 'update-all-links', + name: 'Update All Links', callback: async () => { const count = await this.linkUpdater.updateAllLinks(); new Notice(`Updated the link text of ${count} Markdown link(s).`); diff --git a/package-lock.json b/package-lock.json index b77e438..33c05e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@typescript-eslint/parser": "5.29.0", "builtin-modules": "3.3.0", "esbuild": "0.17.3", + "eslint": "^8.57.0", "jest": "^29.7.0", "obsidian": "latest", "ts-jest": "^29.2.5", @@ -955,7 +956,6 @@ "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -975,7 +975,6 @@ "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -986,7 +985,6 @@ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1011,7 +1009,6 @@ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -1023,7 +1020,6 @@ "deprecated": "Use @eslint/config-array instead", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -1039,7 +1035,6 @@ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=12.22" }, @@ -1054,8 +1049,7 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -1946,8 +1940,7 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/acorn": { "version": "8.14.0", @@ -1955,7 +1948,6 @@ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1969,7 +1961,6 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -1980,7 +1971,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2066,8 +2056,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "Python-2.0", - "peer": true + "license": "Python-2.0" }, "node_modules/array-union": { "version": "2.1.0", @@ -2552,8 +2541,7 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", @@ -2604,7 +2592,6 @@ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -2719,7 +2706,6 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -2734,7 +2720,6 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -2847,7 +2832,6 @@ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -2865,7 +2849,6 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=4.0" } @@ -2876,7 +2859,6 @@ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -2909,7 +2891,6 @@ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -2923,7 +2904,6 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=4.0" } @@ -2967,7 +2947,6 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -3027,8 +3006,7 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", @@ -3072,8 +3050,7 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fastq": { "version": "1.18.0", @@ -3101,7 +3078,6 @@ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -3161,7 +3137,6 @@ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -3179,7 +3154,6 @@ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -3194,8 +3168,7 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/fs.realpath": { "version": "1.0.0", @@ -3307,7 +3280,6 @@ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -3321,7 +3293,6 @@ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -3365,8 +3336,7 @@ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/has-flag": { "version": "4.0.0", @@ -3424,7 +3394,6 @@ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -3567,7 +3536,6 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -4278,7 +4246,6 @@ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "argparse": "^2.0.1" }, @@ -4304,8 +4271,7 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -4319,16 +4285,14 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", @@ -4349,7 +4313,6 @@ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "json-buffer": "3.0.1" } @@ -4380,7 +4343,6 @@ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -4402,7 +4364,6 @@ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -4425,8 +4386,7 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lru-cache": { "version": "5.1.1", @@ -4643,7 +4603,6 @@ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -4678,7 +4637,6 @@ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -4705,7 +4663,6 @@ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "callsites": "^3.0.0" }, @@ -4884,7 +4841,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8.0" } @@ -4937,7 +4893,6 @@ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -5060,7 +5015,6 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -5093,7 +5047,6 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -5367,8 +5320,7 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tmpl": { "version": "1.0.5", @@ -5475,7 +5427,6 @@ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -5499,7 +5450,6 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", - "peer": true, "engines": { "node": ">=10" }, @@ -5558,7 +5508,6 @@ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "punycode": "^2.1.0" } @@ -5617,7 +5566,6 @@ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } diff --git a/package.json b/package.json index 84bf6ad..8af5d69 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", "version": "node version-bump.mjs && git add manifest.json versions.json", "test": "jest", - "test:watch": "jest --watch" + "test:watch": "jest --watch", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix" }, "keywords": [], "author": "Lex Toumbourou", @@ -22,6 +24,7 @@ "@typescript-eslint/parser": "5.29.0", "builtin-modules": "3.3.0", "esbuild": "0.17.3", + "eslint": "^8.57.0", "jest": "^29.7.0", "obsidian": "latest", "ts-jest": "^29.2.5",