mirror of
https://github.com/sbuffkin/hexmaker.git
synced 2026-07-22 06:14:01 +00:00
fix Obsidian reviewer lint errors; add lint to rebuild flow; bump to 1.0.28
- Remove unnecessary type assertions in IconPickerModal (createEl("input") already returns HTMLInputElement)
- Fix sentence-case violation: "Remove GM icon" → "Remove icon" in HexEditorModal tooltip
- Annotate frontmatter["region"] accesses as unknown to satisfy no-unsafe-assignment
- Wire npm run lint into /rebuild command so issues are caught locally before submission
- Document no-unnecessary-type-assertion and mid-sentence acronym patterns in /lint guidance
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e7019aaca4
commit
96eef77ffa
10 changed files with 35 additions and 14 deletions
|
|
@ -35,6 +35,15 @@ this.registerEvent(
|
|||
```
|
||||
This removes `any` entirely; `unknown as SomeInterface` is fully type-safe.
|
||||
|
||||
### `@typescript-eslint/no-unnecessary-type-assertion`
|
||||
A cast (`as T`) where TypeScript already knows the value has type `T`.
|
||||
|
||||
**Common cause — `createEl` with a specific tag**: Obsidian's `createEl<K>(tag: K, ...)` returns `HTMLElementTagNameMap[K]`, so `createEl("input", ...)` already returns `HTMLInputElement`. Any subsequent `as HTMLInputElement` cast is redundant.
|
||||
|
||||
**Common cause — ambient types not imported**: Using `as DomElementInfo` inline causes ESLint's `no-undef` to fire because the ambient type isn't an explicit import. Drop the cast entirely — `{ type: "checkbox" }` is assignable to `DomElementInfo` without a cast.
|
||||
|
||||
**Fix**: Delete the redundant cast. If the type isn't narrow enough, use `as unknown as T` (two-step) rather than a direct `as T` — but prefer removing the cast entirely.
|
||||
|
||||
### `obsidianmd/ui/sentence-case`
|
||||
UI text must use sentence case: only the first word and proper nouns are capitalised.
|
||||
|
||||
|
|
@ -43,6 +52,7 @@ UI text must use sentence case: only the first word and proper nouns are capital
|
|||
- `"← Pick icons"` → `"← pick icons"`
|
||||
- `"↩ Map mode"` → `"↩ map mode"`
|
||||
- Parenthetical range notation: `"(A → Z)"` → `"(a → z)"`
|
||||
- Mid-sentence acronyms (e.g. "Remove GM icon"): the rule flags consecutive capitals that are not the first word. Reword to move the acronym to the front, avoid it, or use the full term in lowercase: `"Remove icon"` or `"GM icon: remove"`.
|
||||
|
||||
**Fix B — eslint-disable** for intentional special-case UI text that would look wrong if sentence-cased:
|
||||
- Short abbreviation labels: `"wt ↑"`, `"a→z"`, `"z→a"` — these are symbols/abbreviations, not sentences
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
description: Build the duckmage plugin (type-check + bundle)
|
||||
description: Build the duckmage plugin (type-check + bundle + lint + tests)
|
||||
allowed-tools: Bash(npm:*)
|
||||
---
|
||||
|
||||
|
|
@ -15,7 +15,17 @@ Report the build result clearly:
|
|||
- If it succeeded, confirm that `main.js` was updated.
|
||||
- If it failed, show the full error output and identify the likely cause (TypeScript type error, missing import, syntax error, etc.).
|
||||
|
||||
Then, regardless of build result, run the test suite:
|
||||
Then run the linter:
|
||||
|
||||
```
|
||||
cd /mnt/c/Users/markr/Documents/KB/journal/.obsidian/plugins/duckmage-plugin && npm run lint 2>&1
|
||||
```
|
||||
|
||||
Report the lint result clearly:
|
||||
- If there are no issues, confirm it is lint-clean.
|
||||
- If there are errors or warnings, list each one with file, line, rule name, and a brief description. Errors from the Obsidian reviewer are **required** fixes; address them before marking the task done.
|
||||
|
||||
Then, regardless of build/lint result, run the test suite:
|
||||
|
||||
```
|
||||
cd /mnt/c/Users/markr/Documents/KB/journal/.obsidian/plugins/duckmage-plugin && npm test
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "hexmaker",
|
||||
"name": "Hexmap World Creator",
|
||||
"version": "1.0.27",
|
||||
"version": "1.0.28",
|
||||
"minAppVersion": "1.12.0",
|
||||
"description": "Create a hex map and a guidebook level wiki for your setting with minimal fuss. Hex crawl worldbuilding toolbox. System agnostic, ready for any TRPG you care to run in it.",
|
||||
"author": "morkdev",
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "hexmaker-plugin",
|
||||
"version": "1.0.27",
|
||||
"version": "1.0.28",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "hexmaker-plugin",
|
||||
"version": "1.0.27",
|
||||
"version": "1.0.28",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minisearch": "^7.2.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hexmaker-plugin",
|
||||
"version": "1.0.27",
|
||||
"version": "1.0.28",
|
||||
"description": "A plugin to power hex crawl worldbuilding and running.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -736,7 +736,7 @@ export default class HexmakerPlugin extends Plugin {
|
|||
let linked = 0;
|
||||
for (const file of hexFiles) {
|
||||
const cache = this.app.metadataCache.getFileCache(file);
|
||||
const region = cache?.frontmatter?.["region"];
|
||||
const region: unknown = cache?.frontmatter?.["region"];
|
||||
if (typeof region !== "string" || !region) continue;
|
||||
await this.syncHexRegionTableLink(file.path, region);
|
||||
linked++;
|
||||
|
|
|
|||
|
|
@ -512,7 +512,7 @@ export class HexEditorModal extends HexmakerModal {
|
|||
const clearGmBtn = gmRow.createEl("button", {
|
||||
text: "Clear",
|
||||
cls: "duckmage-clear-btn",
|
||||
title: "Remove GM icon",
|
||||
title: "Remove icon",
|
||||
});
|
||||
clearGmBtn.setCssProps({
|
||||
visibility: currentGmIcon ? "visible" : "hidden",
|
||||
|
|
|
|||
|
|
@ -2777,7 +2777,7 @@ export class HexMapView extends ItemView {
|
|||
const file = this.app.vault.getAbstractFileByPath(hexFilePath);
|
||||
if (!(file instanceof TFile)) return null;
|
||||
const cache = this.app.metadataCache.getFileCache(file);
|
||||
const region = cache?.frontmatter?.["region"];
|
||||
const region: unknown = cache?.frontmatter?.["region"];
|
||||
return typeof region === "string" ? region : null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,15 +39,15 @@ export class IconPickerModal extends HexmakerModal {
|
|||
|
||||
// GM layer only toggle
|
||||
const gmRow = headerRight.createDiv({ cls: "duckmage-icon-gm-toggle-row" });
|
||||
const gmCb = gmRow.createEl("input", { type: "checkbox" } as DomElementInfo);
|
||||
(gmCb as HTMLInputElement).checked = this.gmOnly;
|
||||
const gmCb = gmRow.createEl("input", { type: "checkbox" });
|
||||
gmCb.checked = this.gmOnly;
|
||||
const gmLabel = gmRow.createSpan({ text: "GM layer only", cls: "duckmage-icon-gm-toggle-label" });
|
||||
const applyGm = () => {
|
||||
this.gmOnly = (gmCb as HTMLInputElement).checked;
|
||||
this.gmOnly = gmCb.checked;
|
||||
};
|
||||
gmCb.addEventListener("change", applyGm);
|
||||
gmLabel.addEventListener("click", () => {
|
||||
(gmCb as HTMLInputElement).checked = !(gmCb as HTMLInputElement).checked;
|
||||
gmCb.checked = !gmCb.checked;
|
||||
applyGm();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -16,5 +16,6 @@
|
|||
"1.0.24": "1.12.0",
|
||||
"1.0.25": "1.12.0",
|
||||
"1.0.26": "1.12.0",
|
||||
"1.0.27": "1.12.0"
|
||||
"1.0.27": "1.12.0",
|
||||
"1.0.28": "1.12.0"
|
||||
}
|
||||
Loading…
Reference in a new issue