refactor: new template

This commit is contained in:
Michael Naumov 2026-06-21 02:33:30 -06:00
parent 6b39ce6cfe
commit 3e6a6b5456
8 changed files with 356 additions and 359 deletions

607
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -36,6 +36,8 @@
},
"overrides": {
"eslint": "$eslint",
"js-yaml": "^4.2.0",
"markdown-it": "^14.2.0",
"type-fest": "^5.6.0",
"typescript": "^6.0.3"
},
@ -46,19 +48,19 @@
"@obsidian-typings/obsidian-public-latest": "^6.15.0",
"@total-typescript/ts-reset": "^0.6.1",
"@tsconfig/strictest": "^2.0.8",
"@types/node": "^25.9.3",
"@vitest/coverage-v8": "^4.1.8",
"@types/node": "^26.0.0",
"@vitest/coverage-v8": "^4.1.9",
"better-typescript-lib": "^2.12.0",
"czg": "^1.13.1",
"eslint": "^10.4.1",
"eslint": "^10.5.0",
"husky": "^9.1.7",
"jiti": "^2.7.0",
"jsdom": "^29.1.1",
"nano-staged": "^1.0.2",
"obsidian": "^1.13.1",
"obsidian-dev-utils": "^70.2.2",
"obsidian-integration-testing": "^4.2.4",
"obsidian-test-mocks": "^3.1.1",
"vitest": "^4.1.8"
"obsidian-dev-utils": "^74.1.0",
"obsidian-integration-testing": "^4.3.0",
"obsidian-test-mocks": "^3.2.0",
"vitest": "^4.1.9"
}
}

View file

@ -11,23 +11,11 @@ import type { PluginSettings } from '../plugin-settings.ts';
import { InsertAttachmentsControl } from '../insert-attachments-control.ts';
/**
* Params for creating an {@link InvokeCommandHandler}.
*/
export interface InvokeCommandHandlerConstructorParams {
/**
* The Obsidian app instance.
*/
readonly app: App;
/**
* A function that returns the current plugin settings.
*/
getPluginSettings(): ReadonlyDeep<PluginSettings>;
/**
* The name of the plugin.
*/
readonly pluginName: string;
}

View file

@ -12,23 +12,11 @@ import {
import type { PluginSettings } from './plugin-settings.ts';
/**
* Params for creating an {@link InsertAttachmentsControl}.
*/
export interface InsertAttachmentsControlConstructorParams {
/**
* The Obsidian app instance.
*/
readonly app: App;
/**
* The editor to insert attachment links into.
*/
readonly editor: Editor;
/**
* The plugin settings.
*/
readonly pluginSettings: ReadonlyDeep<PluginSettings>;
}

View file

@ -105,7 +105,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const EXPECTED_SETTING_COUNT = 3;
expect(mockContainerEl.children.length).toBe(EXPECTED_SETTING_COUNT);
@ -115,7 +115,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
expect(capturedBinds.map((b) => b.key)).toContain('attachmentLinksPrefix');
});
@ -124,7 +124,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
expect(capturedBinds.map((b) => b.key)).toContain('attachmentLinksDelimiter');
});
@ -133,7 +133,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
expect(capturedBinds.map((b) => b.key)).toContain('attachmentLinksSuffix');
});
@ -142,7 +142,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const prefixBind = capturedBinds.find((b) => b.key === 'attachmentLinksPrefix');
const converter = prefixBind?.options?.pluginSettingsToComponentValueConverter;
@ -155,7 +155,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const prefixBind = capturedBinds.find((b) => b.key === 'attachmentLinksPrefix');
const converter = prefixBind?.options?.pluginSettingsToComponentValueConverter;
@ -168,7 +168,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const prefixBind = capturedBinds.find((b) => b.key === 'attachmentLinksPrefix');
const converter = prefixBind?.options?.componentToPluginSettingsValueConverter;
@ -181,7 +181,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const prefixBind = capturedBinds.find((b) => b.key === 'attachmentLinksPrefix');
const converter = prefixBind?.options?.componentToPluginSettingsValueConverter;
@ -194,7 +194,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const prefixBind = capturedBinds.find((b) => b.key === 'attachmentLinksPrefix');
const inputEl = prefixBind?.component.inputEl;
@ -211,7 +211,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const prefixBind = capturedBinds.find((b) => b.key === 'attachmentLinksPrefix');
const inputEl = prefixBind?.component.inputEl;
@ -234,7 +234,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const prefixBind = capturedBinds.find((b) => b.key === 'attachmentLinksPrefix');
const inputEl = prefixBind?.component.inputEl;
@ -254,7 +254,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const prefixBind = capturedBinds.find((b) => b.key === 'attachmentLinksPrefix');
const inputEl = prefixBind?.component.inputEl;
@ -274,7 +274,7 @@ describe('PluginSettingsTab', () => {
const tab = createSettingsTab();
// eslint-disable-next-line @typescript-eslint/no-deprecated -- display() is the entry point for PluginSettingsTabBase; calling it in tests is intentional.
tab.display();
tab.displayLegacy();
const prefixBind = capturedBinds.find((b) => b.key === 'attachmentLinksPrefix');
const inputEl = prefixBind?.component.inputEl;

View file

@ -11,9 +11,8 @@ const VISIBLE_SPACE_CHARACTER = '␣';
const VISIBLE_ENTER_CHARACTER = '↵';
export class PluginSettingsTab extends PluginSettingsTabBase<PluginSettings> {
public override display(): void {
// eslint-disable-next-line @typescript-eslint/no-deprecated -- super.display() calls the PluginSettingsTabBase override; the inherited @deprecated tag on Obsidian's SettingTab.display propagates via TS getJsDocTags.
super.display();
public override displayLegacy(): void {
super.displayLegacy();
new Setting(this.containerEl)
.setName('Attachment links prefix')

View file

@ -1,13 +1,6 @@
import type {
App,
PluginManifest
} from 'obsidian';
import { noopAsync } from 'obsidian-dev-utils/function';
import { AppActiveFileProvider } from 'obsidian-dev-utils/obsidian/active-file-provider';
import { CommandHandlerComponent } from 'obsidian-dev-utils/obsidian/command-handlers/command-handler-component';
import { PluginCommandRegistrar } from 'obsidian-dev-utils/obsidian/command-registrar';
import { CallbackLayoutReadyComponent } from 'obsidian-dev-utils/obsidian/components/layout-ready-component';
import { MenuEventRegistrarComponent } from 'obsidian-dev-utils/obsidian/components/menu-event-registrar-component';
import { PluginSettingsTabComponent } from 'obsidian-dev-utils/obsidian/components/plugin-settings-tab-component';
import { PluginDataHandler } from 'obsidian-dev-utils/obsidian/data-handler';
@ -21,10 +14,9 @@ import { PluginSettingsComponent } from './plugin-settings-component.ts';
import { PluginSettingsTab } from './plugin-settings-tab.ts';
export class Plugin extends PluginBase {
private readonly pluginSettingsComponent: PluginSettingsComponent;
private pluginSettingsComponent!: PluginSettingsComponent;
public constructor(app: App, manifest: PluginManifest) {
super(app, manifest);
protected override onloadImpl(): void {
this.pluginSettingsComponent = this.addChild(
new PluginSettingsComponent({
dataHandler: new PluginDataHandler(this),
@ -40,26 +32,21 @@ export class Plugin extends PluginBase {
})
})
);
const menuEventRegistrar = this.addChild(new MenuEventRegistrarComponent(app));
const menuEventRegistrar = this.addChild(new MenuEventRegistrarComponent(this.app));
this.addChild(
new CommandHandlerComponent({
activeFileProvider: new AppActiveFileProvider(app),
activeFileProvider: new AppActiveFileProvider(this.app),
commandHandlers: [
new InvokeCommandHandler({
app,
app: this.app,
getPluginSettings: (): PluginSettings => this.pluginSettingsComponent.settings as PluginSettings,
pluginName: manifest.name
pluginName: this.manifest.name
})
],
commandRegistrar: new PluginCommandRegistrar(this),
menuEventRegistrar,
pluginName: manifest.name
pluginName: this.manifest.name
})
);
this.addChild(new CallbackLayoutReadyComponent(app, this.onLayoutReady.bind(this)));
}
protected async onLayoutReady(): Promise<void> {
await noopAsync();
}
}

View file

@ -11,14 +11,14 @@
"lib": [
"DOM",
"DOM.Iterable",
"ESNext"
"ES2022"
],
"libReplacement": true,
"module": "NodeNext",
"moduleResolution": "NodeNext",
"module": "node16",
"moduleResolution": "node16",
"noEmit": true,
"skipLibCheck": false,
"target": "ESNext",
"skipLibCheck": true,
"target": "es2022",
"types": [
"@total-typescript/ts-reset",
"node",