lossless-group_perplexed-pl.../src/modals/TextEnhancementModal.ts
mpstaton 0a016e2668 fix(marketplace): comply with ObsidianReviewBot recommended config — sentence-case, no-restricted-globals, async hygiene
Round 3 of the marketplace submission (#12513) flagged 73 errors + 6
warnings against the bot's recommended eslint config. This ships the
literal fixes the bot demanded so the rescan goes clean and the PR
moves to human review.

Sentence-case (66 errors). Applied the bot's exact "Expected: '...'"
rewrites across main.ts, the 8 modal files, and claudeService.ts. The
bot runs obsidianmd/ui/sentence-case with `enforceCamelCaseLower: true`
and no brand allowlist, so "Ask Perplexity" becomes "Ask perplexity",
"LM Studio" becomes "Lm studio", "PromptsService" becomes "promptsservice"
— UI text now reads as broken. Brand capitalization is to be restored
after marketplace acceptance, when we own the plugin entry on our own
update cadence. Local eslint.config.mjs's brand-allowlist override
also dropped so the local lint stops disagreeing with the bot.

Async without await (2 errors). main.ts:504 `callback: async () => {}`
reduced to `callback: () => {}` (the wrapped reinitializeServices() is
sync). directoryTemplateService.ts:195 listTemplates reduced from
`async function ... : Promise<TemplateFile[]>` to sync; the two callers
in main.ts updated to drop `await`.

no-restricted-globals (4 errors + 4 description-missing errors). All
four streaming fetch() sites (directoryTemplateService, lmStudioService,
perplexicaService, perplexityService) switched to `activeWindow.fetch`,
matching the precedent already used for `activeWindow.setTimeout`
elsewhere. The bare eslint-disable directives removed. SSE/streaming
rationale (Obsidian's requestUrl buffers) preserved in adjacent
comments.

Unused catch bindings (6 warnings). Three in main.ts, plus
lmStudioService:243, perplexicaService:255, logger.ts:47 — all
collapsed from `catch (e)` / `catch (error)` to `catch { ... }`.

Also included: changelog/2026-05-12_01.md documenting what the bot
flagged, the diff cost (brand names lowercased mid-string), the
non-sentence-case fixes, and verification.

Verification: both eslint configs (local + bot-mirror recommended)
exit 0; tsc -noEmit -skipLibCheck exit 0; production esbuild exit 0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 06:58:09 -05:00

148 lines
5.3 KiB
TypeScript

import type { App, Editor } from 'obsidian';
import { Modal, Notice } from 'obsidian';
import type { PerplexityService } from '../services/perplexityService';
import type { PromptsService } from '../services/promptsService';
export class TextEnhancementModal extends Modal {
protected editor: Editor;
protected perplexityService: PerplexityService;
protected promptsService: PromptsService;
protected selectedText: string;
private prompt: string;
private enhanceBtn!: HTMLButtonElement;
constructor(
app: App,
editor: Editor,
perplexityService: PerplexityService,
promptsService: PromptsService,
selectedText: string
) {
super(app);
this.editor = editor;
this.perplexityService = perplexityService;
this.promptsService = promptsService;
this.selectedText = selectedText;
this.prompt = this.promptsService.getEnhanceTemplate(this.selectedText);
}
onOpen(): void {
const { contentEl, modalEl } = this;
modalEl.addClass('text-enhancement-modal');
contentEl.empty();
// ----- Header -----
const header = contentEl.createDiv({ cls: 'text-enhancement-modal__header' });
header.createEl('h2', { text: 'Enhance text with perplexity', cls: 'text-enhancement-modal__title' });
header.createEl('p', {
cls: 'text-enhancement-modal__subtitle',
text: 'Rewrite or expand selected text via perplexity (sonar-pro). Streams into the active note at the cursor with citations.',
});
// ----- Selected Text (read-only) -----
const selectedSection = contentEl.createDiv({ cls: 'text-enhancement-modal__section' });
selectedSection.createEl('label', {
text: 'Selected text',
cls: 'text-enhancement-modal__label',
});
const selectedTextarea = selectedSection.createEl('textarea', {
cls: 'text-enhancement-modal__textarea text-enhancement-modal__textarea--readonly',
attr: {
rows: '6',
readonly: 'readonly',
},
});
selectedTextarea.value = this.selectedText;
// ----- Enhancement Prompt (editable) -----
const promptSection = contentEl.createDiv({ cls: 'text-enhancement-modal__section' });
promptSection.createEl('label', {
text: 'Enhancement prompt',
cls: 'text-enhancement-modal__label',
attr: { for: 'text-enhancement-modal-prompt' },
});
promptSection.createEl('p', {
cls: 'text-enhancement-modal__hint',
text: 'Pre-filled from the plugin template — edit to refine the rewrite instructions before submitting.',
});
const promptTextarea = promptSection.createEl('textarea', {
cls: 'text-enhancement-modal__textarea',
attr: {
id: 'text-enhancement-modal-prompt',
rows: '8',
placeholder: 'Enter your enhancement prompt…',
},
});
promptTextarea.value = this.prompt;
promptTextarea.addEventListener('input', () => {
this.prompt = promptTextarea.value;
});
promptTextarea.addEventListener('keydown', (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
e.preventDefault();
void this.onSubmit();
}
});
// ----- Footer -----
const footer = contentEl.createDiv({ cls: 'text-enhancement-modal__footer' });
const cancelBtn = footer.createEl('button', {
text: 'Cancel',
cls: 'text-enhancement-modal__button',
});
cancelBtn.addEventListener('click', () => this.close());
this.enhanceBtn = footer.createEl('button', {
text: 'Enhance text',
cls: 'text-enhancement-modal__button mod-cta',
});
this.enhanceBtn.addEventListener('click', () => void this.onSubmit());
activeWindow.setTimeout(() => promptTextarea.focus(), 50);
}
private async onSubmit(): Promise<void> {
const trimmed = this.prompt.trim();
if (!trimmed) {
new Notice('Please enter an enhancement prompt.');
return;
}
try {
this.enhanceBtn.disabled = true;
this.enhanceBtn.textContent = 'Enhancing…';
this.close();
const cursor = this.editor.getCursor();
this.editor.replaceRange('\n\n', cursor);
await this.perplexityService.queryPerplexity(
trimmed,
'sonar-pro',
true,
this.editor,
{
return_citations: true,
return_images: false,
return_related_questions: false,
}
);
new Notice('Text enhancement completed.');
} catch (error) {
console.error('Error enhancing text:', error);
new Notice('Failed to enhance text. Check console for details.');
} finally {
if (this.enhanceBtn) {
this.enhanceBtn.disabled = false;
this.enhanceBtn.textContent = 'Enhance text';
}
}
}
onClose(): void {
this.contentEl.empty();
}
}