refactor: update parameter names to improve clarity and consistency across the codebase

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Erik van der Boom 2026-05-06 09:24:57 +02:00
parent 2a691d248a
commit 00b34c9551
21 changed files with 194 additions and 87 deletions

View file

@ -35,7 +35,7 @@ export type { TemplateContext } from './templates/context';
interface TemplateModule {
meta: TemplateMeta;
render: (ctx: TemplateContext) => string;
render: (_ctx: TemplateContext) => string;
}
const TEMPLATES: Record<string, TemplateModule> = {

View file

@ -24,8 +24,8 @@ vi.mock('vscode', () => ({
},
Uri: { file: (p: string) => ({ fsPath: p }) },
ConfigurationTarget: { Global: 1, Workspace: 2 },
LanguageModelToolResult: class { constructor(public readonly content: unknown[]) {} },
LanguageModelTextPart: class { constructor(public readonly value: string) {} },
LanguageModelToolResult: class { constructor(public readonly _content: unknown[]) {} },
LanguageModelTextPart: class { constructor(public readonly _value: string) {} },
}));
import * as fs from 'node:fs';

View file

@ -12,7 +12,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
// ─── Mock child_process ───────────────────────────────────────────────────────
vi.mock('node:child_process', () => {
type ExecFileCallback = (err: Error | null, stdout: string, stderr: string) => void;
type ExecFileCallback = (_err: Error | null, _stdout: string, _stderr: string) => void;
return {
execFile: vi.fn((

View file

@ -1,10 +1,109 @@
import js from '@eslint/js';
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
export default [
{
ignores: ['**/node_modules/**', '**/dist/**', '**/out/**', '**/.vscode/**'],
ignores: ['**/node_modules/**', '**/dist/**', '**/out/**', '**/.vscode/**', '**/coverage/**'],
},
{
files: ['bindery-core/src/**/*.ts', 'bindery-merge/src/**/*.ts', 'mcp-ts/src/**/*.ts', 'vscode-ext/src/**/*.ts', 'obsidian-plugin/src/**/*.ts'],
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: [
`${__dirname}/bindery-core/tsconfig.json`,
`${__dirname}/bindery-merge/tsconfig.json`,
`${__dirname}/mcp-ts/tsconfig.json`,
`${__dirname}/vscode-ext/tsconfig.json`,
`${__dirname}/obsidian-plugin/tsconfig.json`,
],
tsconfigRootDir: __dirname,
},
globals: {
console: 'readonly',
process: 'readonly',
Buffer: 'readonly',
globalThis: 'readonly',
setTimeout: 'readonly',
clearTimeout: 'readonly',
fetch: 'readonly',
AbortSignal: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
require: 'readonly',
},
},
plugins: {
'@typescript-eslint': tsPlugin,
},
rules: {
...js.configs.recommended.rules,
...tsPlugin.configs.recommended.rules,
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': ['warn', {
args: 'all',
argsIgnorePattern: '^_',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_',
}],
'@typescript-eslint/no-require-imports': 'off',
'no-unused-vars': 'off',
'no-undef': 'off',
'no-empty': ['warn', { allowEmptyCatch: true }],
},
},
{
files: ['**/test/**/*.ts', '**/*.test.ts', '**/*.spec.ts'],
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
globals: {
console: 'readonly',
process: 'readonly',
Buffer: 'readonly',
globalThis: 'readonly',
setTimeout: 'readonly',
clearTimeout: 'readonly',
fetch: 'readonly',
AbortSignal: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
HTMLElement: 'readonly',
RequestInit: 'readonly',
require: 'readonly',
vi: 'readonly',
describe: 'readonly',
it: 'readonly',
expect: 'readonly',
beforeEach: 'readonly',
beforeAll: 'readonly',
afterEach: 'readonly',
afterAll: 'readonly',
},
},
plugins: {
'@typescript-eslint': tsPlugin,
},
rules: {
...js.configs.recommended.rules,
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-require-imports': 'off',
'no-undef': 'off',
'no-empty': ['warn', { allowEmptyCatch: true }],
},
},
{
files: ['**/*.ts', '**/*.js'],
@ -20,6 +119,12 @@ export default [
Buffer: 'readonly',
globalThis: 'readonly',
setTimeout: 'readonly',
clearTimeout: 'readonly',
fetch: 'readonly',
AbortSignal: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
HTMLElement: 'readonly',
},
},
plugins: {
@ -27,11 +132,13 @@ export default [
},
rules: {
...js.configs.recommended.rules,
...tsPlugin.configs.recommended.rules,
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-require-imports': 'off',
'no-empty': ['warn', { allowEmptyCatch: true }],
},
},
];

View file

@ -35,7 +35,7 @@ function parseBooksFromArgs(): Map<string, string> {
const args = process.argv;
for (let i = 0; i < args.length; i++) {
if (args[i] === '--book' && args[i + 1]) {
parseEntry(args[i + 1]!, books);
parseEntry(args[i + 1], books);
i++;
}
}

View file

@ -143,7 +143,7 @@ export interface BuildSemanticProgress {
export interface BuildSemanticOptions {
/** Called after each chunk finishes embedding. */
onProgress?: (p: BuildSemanticProgress) => void;
onProgress?: (_p: BuildSemanticProgress) => void;
}
export async function buildSemanticIndex(

View file

@ -109,7 +109,7 @@ function resolveOnPath(cmd: string): string | null {
}
}
function versionFlag(tool: ToolName): string {
function versionFlag(_tool: ToolName): string {
return '--version';
}

View file

@ -47,7 +47,7 @@ interface JsonRpcResponse {
*/
function spawnServer(bookName: string, bookRoot: string): {
proc: child_process.ChildProcessWithoutNullStreams;
send: (msg: JsonRpcRequest | JsonRpcNotification) => void;
send: (_msg: JsonRpcRequest | JsonRpcNotification) => void;
readOne: () => Promise<JsonRpcResponse>;
kill: () => void;
} {
@ -62,7 +62,7 @@ function spawnServer(bookName: string, bookRoot: string): {
);
let buffer = '';
const pending: Array<(line: string) => void> = [];
const pending: Array<(_line: string) => void> = [];
const lines: string[] = [];
proc.stdout.on('data', (chunk: Buffer) => {
@ -90,9 +90,9 @@ function spawnServer(bookName: string, bookRoot: string): {
reject(new Error(`Timed out waiting for MCP message after ${MSG_TIMEOUT_MS}ms`));
}, MSG_TIMEOUT_MS);
const handler = (line: string) => {
const handler = (_line: string) => {
clearTimeout(timer);
try { resolve(JSON.parse(line) as JsonRpcResponse); } catch (e) { reject(e); }
try { resolve(JSON.parse(_line) as JsonRpcResponse); } catch (e) { reject(e); }
};
pending.push(handler);
});
@ -110,7 +110,7 @@ function spawnServer(bookName: string, bookRoot: string): {
/** Perform the mandatory MCP initialize handshake and return the server's init result. */
async function handshake(
send: (msg: JsonRpcRequest | JsonRpcNotification) => void,
send: (_msg: JsonRpcRequest | JsonRpcNotification) => void,
readOne: () => Promise<JsonRpcResponse>,
): Promise<JsonRpcResponse> {
send({

View file

@ -40,9 +40,8 @@ export interface AiSetupResult {
/**
* Generate AI instruction files from vault settings.
*/
// eslint-disable-next-line @typescript-eslint/require-await -- Function is async for API consistency even though operations are synchronous
export async function setupAiFiles(
app: App,
_app: App,
bookRoot: string,
targets: AiTarget[] = ['claude', 'copilot'],
skills: SkillTemplate[] = ALL_SKILLS,

View file

@ -41,10 +41,10 @@ export default class BinderyPlugin extends Plugin {
private addContextMenuItems(menu: unknown, forEditor: boolean): void {
const m = menu as {
addSeparator?: () => void;
addItem: (cb: (item: {
setTitle: (title: string) => unknown;
setIcon?: (icon: string) => unknown;
onClick: (fn: () => void) => unknown;
addItem: (_cb: (_item: {
setTitle: (_title: string) => unknown;
setIcon?: (_icon: string) => unknown;
onClick: (_fn: () => void) => unknown;
}) => void) => void;
};

View file

@ -33,9 +33,9 @@ import { resolvePandocPath, resolveLibreOfficePath } from './exporter';
* @returns Merged book result with output paths and file count
*/
export async function mergeBook(
app: App,
vault: Vault,
vaultBasePath: string,
_app: App,
_vault: Vault,
_vaultBasePath: string,
bookRoot: string,
settings: BinderySettings,
outputTypes: OutputType[]

View file

@ -5,11 +5,11 @@ declare module 'obsidian' {
}
export interface Editor {
getCursor(which?: 'from' | 'to' | 'head' | 'anchor'): EditorPosition;
getLine(line: number): string;
getCursor(_which?: 'from' | 'to' | 'head' | 'anchor'): EditorPosition;
getLine(_line: number): string;
getSelection(): string;
replaceSelection(text: string): void;
replaceRange(text: string, from: EditorPosition, to?: EditorPosition): void;
replaceSelection(_text: string): void;
replaceRange(_text: string, _from: EditorPosition, _to?: EditorPosition): void;
}
export interface EventRef {
@ -24,10 +24,10 @@ declare module 'obsidian' {
}
export interface Vault {
read(file: TFile): Promise<string>;
modify(file: TFile, data: string): Promise<void>;
read(_file: TFile): Promise<string>;
modify(_file: TFile, _data: string): Promise<void>;
getName(): string;
on(event: string, callback: (...args: unknown[]) => unknown): EventRef;
on(_event: string, _callback: (..._args: unknown[]) => unknown): EventRef;
adapter?: { basePath: string; [key: string]: unknown };
}
@ -35,29 +35,29 @@ declare module 'obsidian' {
vault: Vault;
workspace?: {
getActiveFile(): TFile | null;
on(event: string, callback: (...args: unknown[]) => unknown): EventRef;
on(_event: string, _callback: (..._args: unknown[]) => unknown): EventRef;
};
}
export class Notice {
constructor(message: string, timeout?: number);
constructor(_message: string, _timeout?: number);
}
export interface Command {
id: string;
name: string;
callback?: () => void | Promise<void>;
editorCallback?: (editor: Editor) => void;
editorCallback?: (_editor: Editor) => void;
}
export class Plugin {
app: App;
constructor(app: App);
constructor(_app: App);
loadData(): Promise<unknown>;
saveData(data: unknown): Promise<void>;
addRibbonIcon(icon: string, title: string, callback: () => void): HTMLElement;
addCommand(command: Command): void;
addSettingTab(tab: unknown): void;
registerEvent(eventRef: EventRef): void;
saveData(_data: unknown): Promise<void>;
addRibbonIcon(_icon: string, _title: string, _callback: () => void): HTMLElement;
addCommand(_command: Command): void;
addSettingTab(_tab: unknown): void;
registerEvent(_eventRef: EventRef): void;
}
}

View file

@ -4,7 +4,7 @@
* Tests AI instruction file generation from vault settings
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as os from 'node:os';
@ -133,7 +133,7 @@ describe('AI Setup', () => {
bookTitle: 'Test Book',
}, null, 2), 'utf-8');
const result = await setupAiFiles(mockApp, tempRoot, ['claude'], ['review', 'brainstorm'], false);
await setupAiFiles(mockApp, tempRoot, ['claude'], ['review', 'brainstorm'], false);
const reviewSkillPath = path.join(tempRoot, '.claude', 'skills', 'review', 'SKILL.md');
const brainstormSkillPath = path.join(tempRoot, '.claude', 'skills', 'brainstorm', 'SKILL.md');
@ -158,7 +158,7 @@ describe('AI Setup', () => {
],
}, null, 2), 'utf-8');
const result = await setupAiFiles(mockApp, tempRoot, ['agents'], [], false);
await setupAiFiles(mockApp, tempRoot, ['agents'], [], false);
const agentsPath = path.join(tempRoot, 'AGENTS.md');
const content = fs.readFileSync(agentsPath, 'utf-8');

View file

@ -121,7 +121,7 @@ describe('buildPandocArgs', () => {
// ─── exportBook ──────────────────────────────────────────────────────────────
vi.mock('node:child_process', () => ({
execFile: vi.fn((_cmd: string, _args: string[], cb: (err: null, stdout: string, stderr: string) => void) => {
execFile: vi.fn((_cmd: string, _args: string[], cb: (_err: null, _stdout: string, _stderr: string) => void) => {
cb(null, '', '');
}),
}));
@ -295,7 +295,7 @@ describe('exportBook', () => {
it('rejects when execFile reports an error', async () => {
const { execFile } = await import('node:child_process');
const execMock = vi.mocked(execFile);
execMock.mockImplementationOnce((_cmd, _args, cb: (err: Error | null, stdout: string, stderr: string) => void) => {
execMock.mockImplementationOnce((_cmd, _args, cb: (_err: Error | null, _stdout: string, _stderr: string) => void) => {
cb(new Error('not found'), '', 'command not found');
return undefined as unknown as ReturnType<typeof execFile>;
});

View file

@ -1,4 +1,4 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { describe, it, expect, vi } from 'vitest';
import { formatFile, formatText } from '../src/formatter';
import type { TFile, Vault } from 'obsidian';

View file

@ -39,7 +39,7 @@ vi.mock('obsidian', () => {
id: string;
name: string;
callback?: () => void | Promise<void>;
editorCallback?: (editor: unknown) => void;
editorCallback?: (_editor: unknown) => void;
}): void { return; }
addRibbonIcon(_icon: string, _title: string, _callback: () => void): HTMLElement {
@ -202,9 +202,9 @@ describe('formatOnSave bookRoot scoping', () => {
const bp = new BinderyPlugin(app);
// Capture the vault.on callback before onload
let savedCallback: ((...args: unknown[]) => void) | undefined;
vi.spyOn(app.vault, 'on').mockImplementation((_event: string, cb: (...args: unknown[]) => unknown) => {
savedCallback = cb as (...args: unknown[]) => void;
let savedCallback: ((..._args: unknown[]) => void) | undefined;
vi.spyOn(app.vault, 'on').mockImplementation((_event: string, cb: (..._args: unknown[]) => unknown) => {
savedCallback = cb as (..._args: unknown[]) => void;
return {};
});
@ -226,9 +226,9 @@ describe('formatOnSave bookRoot scoping', () => {
const app = makeApp(vaultPath, 'MyVault');
const bp = new BinderyPlugin(app);
let savedCallback: ((...args: unknown[]) => void) | undefined;
vi.spyOn(app.vault, 'on').mockImplementation((_event: string, cb: (...args: unknown[]) => unknown) => {
savedCallback = cb as (...args: unknown[]) => void;
let savedCallback: ((..._args: unknown[]) => void) | undefined;
vi.spyOn(app.vault, 'on').mockImplementation((_event: string, cb: (..._args: unknown[]) => unknown) => {
savedCallback = cb as (..._args: unknown[]) => void;
return {};
});

View file

@ -8,7 +8,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as os from 'node:os';
import { readTranslations, upsertGlossaryRule, upsertSubstitutionRule } from '@bindery/core';
import { readTranslations, upsertGlossaryRule } from '@bindery/core';
import {
readSettings,
writeSettings,

View file

@ -1,5 +1,6 @@
{
"name": "bindery-monorepo",
"type": "module",
"private": true,
"workspaces": [
"bindery-core",
@ -11,6 +12,8 @@
"scripts": {
"build": "npm run build -ws --if-present",
"test": "npm run test -ws --if-present",
"lint": "npx eslint . --format=stylish",
"lint:fix": "npx eslint . --fix",
"build:core": "npm run build --workspace=bindery-core",
"obsidian:sync-version": "node ./scripts/sync-obsidian-version.mjs"
}

View file

@ -62,16 +62,15 @@ function getWorkspaceRoot(): string | undefined {
}
interface McpToolsForAi {
toolHealth: (root: string) => string;
toolSetupAiFiles: (root: string, args: { targets?: string[]; skills?: string[]; overwrite?: boolean }) => string;
writeBinderyCapabilitiesReadme: (root: string) => void;
toolHealth: (_root: string) => string;
toolSetupAiFiles: (_root: string, _args: { targets?: string[]; skills?: string[]; overwrite?: boolean }) => string;
writeBinderyCapabilitiesReadme: (_root: string) => void;
}
function loadMcpToolsForAi(extensionPath: string): McpToolsForAi {
const bundledPath = path.join(extensionPath, 'mcp-ts', 'out', 'tools');
const devPath = path.join(extensionPath, '..', 'mcp-ts', 'out', 'tools');
const modulePath = fs.existsSync(bundledPath + '.js') ? bundledPath : devPath;
// eslint-disable-next-line @typescript-eslint/no-require-imports -- Load bundled mcp-ts tools at runtime
return require(modulePath) as McpToolsForAi;
}

View file

@ -37,32 +37,32 @@ interface MemoryCompactInput { file: string; compacted_content: string }
interface ChapterStatusUpdateInput { chapters: Array<{ number: number; title: string; language: string; status: 'done' | 'in-progress' | 'draft' | 'planned' | 'needs-review'; wordCount?: number; notes?: string }> }
interface McpTools {
toolHealth: (root: string) => string;
toolIndexBuild: (root: string) => Promise<string>;
toolIndexStatus: (root: string) => string;
toolGetText: (root: string, args: GetTextInput) => string;
toolGetChapter: (root: string, args: GetChapterInput) => string;
toolGetBookUntil: (root: string, args: GetBookUntilInput) => string;
toolGetOverview: (root: string, args: GetOverviewInput) => string;
toolGetNotes: (root: string, args: GetNotesInput) => string;
toolSearch: (root: string, args: SearchInput) => Promise<string>;
toolFormat: (root: string, args: FormatInput) => string;
toolGetReviewText: (root: string, args: GetReviewTextInput) => string;
toolUpdateWorkspace: (root: string, args: UpdateWorkspaceInput) => string;
toolGitSnapshot: (root: string, args: GitSnapshotInput) => string;
toolAddTranslation: (root: string, args: AddTranslationInput) => string;
toolGetTranslation: (root: string, args: GetTranslationInput) => string;
toolAddDialect: (root: string, args: AddDialectInput) => string;
toolGetDialect: (root: string, args: GetDialectInput) => string;
toolAddLanguage: (root: string, args: AddLanguageInput) => string;
toolInitWorkspace: (root: string, args: InitWorkspaceInput) => string;
toolSettingsUpdate: (root: string, args: SettingsUpdateInput) => string;
toolSetupAiFiles: (root: string, args: SetupAiFilesInput) => string;
toolMemoryList: (root: string) => string;
toolMemoryAppend: (root: string, args: MemoryAppendInput) => string;
toolMemoryCompact: (root: string, args: MemoryCompactInput) => string;
toolChapterStatusGet: (root: string) => string;
toolChapterStatusUpdate: (root: string, args: ChapterStatusUpdateInput) => string;
toolHealth: (_root: string) => string;
toolIndexBuild: (_root: string) => Promise<string>;
toolIndexStatus: (_root: string) => string;
toolGetText: (_root: string, _args: GetTextInput) => string;
toolGetChapter: (_root: string, _args: GetChapterInput) => string;
toolGetBookUntil: (_root: string, _args: GetBookUntilInput) => string;
toolGetOverview: (_root: string, _args: GetOverviewInput) => string;
toolGetNotes: (_root: string, _args: GetNotesInput) => string;
toolSearch: (_root: string, _args: SearchInput) => Promise<string>;
toolFormat: (_root: string, _args: FormatInput) => string;
toolGetReviewText: (_root: string, _args: GetReviewTextInput) => string;
toolUpdateWorkspace: (_root: string, _args: UpdateWorkspaceInput) => string;
toolGitSnapshot: (_root: string, _args: GitSnapshotInput) => string;
toolAddTranslation: (_root: string, _args: AddTranslationInput) => string;
toolGetTranslation: (_root: string, _args: GetTranslationInput) => string;
toolAddDialect: (_root: string, _args: AddDialectInput) => string;
toolGetDialect: (_root: string, _args: GetDialectInput) => string;
toolAddLanguage: (_root: string, _args: AddLanguageInput) => string;
toolInitWorkspace: (_root: string, _args: InitWorkspaceInput) => string;
toolSettingsUpdate: (_root: string, _args: SettingsUpdateInput) => string;
toolSetupAiFiles: (_root: string, _args: SetupAiFilesInput) => string;
toolMemoryList: (_root: string) => string;
toolMemoryAppend: (_root: string, _args: MemoryAppendInput) => string;
toolMemoryCompact: (_root: string, _args: MemoryCompactInput) => string;
toolChapterStatusGet: (_root: string) => string;
toolChapterStatusUpdate: (_root: string, _args: ChapterStatusUpdateInput) => string;
}
/**
@ -77,7 +77,6 @@ function loadMcpTools(extensionPath: string): McpTools {
const bundledPath = path.join(extensionPath, 'mcp-ts', 'out', 'tools');
const devPath = path.join(extensionPath, '..', 'mcp-ts', 'out', 'tools');
const modulePath = fs.existsSync(bundledPath + '.js') ? bundledPath : devPath;
// eslint-disable-next-line @typescript-eslint/no-require-imports -- Load bundled mcp-ts tools at runtime
return require(modulePath) as McpTools;
}

View file

@ -38,10 +38,10 @@ vi.mock('vscode', () => ({
Uri: { file: (p: string) => ({ fsPath: p }) },
ConfigurationTarget: { Global: 1, Workspace: 2 },
LanguageModelToolResult: class {
constructor(public readonly content: unknown[]) {}
constructor(public readonly _content: unknown[]) {}
},
LanguageModelTextPart: class {
constructor(public readonly value: string) {}
constructor(public readonly _value: string) {}
},
}));