mirror of
https://github.com/edems-dev/md-discord-syntax.git
synced 2026-07-22 08:37:37 +00:00
fix(obsidian): warning+id
- Changed plugin ID to md-discord-syntax across manifests, validation, package metadata, and release instructions. - Resolved TypeScript unsafe-value warnings through correct typed ESLint configuration and source typing. - Replaced flagged document.createElement usage with Obsidian createEl. - Addressed text-decoration compatibility warnings. - Optimized spoiler detection to inspect only relevant document lines instead of allocating the full document text. - Updated tests for strict type safety and promise handling.
This commit is contained in:
parent
a23dbf13b3
commit
b3294030f8
15 changed files with 53 additions and 57 deletions
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
|
|
@ -43,9 +43,9 @@ jobs:
|
|||
body: |
|
||||
Obsidian plugin release for Discord Syntax.
|
||||
|
||||
Plugin ID: discord-syntax
|
||||
Plugin ID: md-discord-syntax
|
||||
|
||||
Install by copying main.js, manifest.json, and styles.css into .obsidian/plugins/discord-syntax/.
|
||||
Install by copying main.js, manifest.json, and styles.css into .obsidian/plugins/md-discord-syntax/.
|
||||
files: |
|
||||
packages/obsidian/main.js
|
||||
packages/obsidian/manifest.json
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ export default tseslint.config(
|
|||
"**/dist/**",
|
||||
"packages/obsidian/main.js",
|
||||
"packages/obsidian/styles.css",
|
||||
"**/*.mjs",
|
||||
"**/*.js",
|
||||
],
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "discord-syntax",
|
||||
"id": "md-discord-syntax",
|
||||
"name": "Discord Syntax",
|
||||
"version": "1.0.21",
|
||||
"version": "1.0.22",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Discord-style `||spoiler||` and `-# subtext` markdown formatting extension.",
|
||||
"author": "Edems-DEV",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"build": "npm run build --workspaces --if-present",
|
||||
"pretest": "npm run build -w @edems-dev/md-discord-syntax-core",
|
||||
"test": "npm run test --workspaces --if-present",
|
||||
"lint": "eslint \"packages/**/src/**/*.ts\"",
|
||||
"lint": "eslint .",
|
||||
"pretypecheck": "npm run build -w @edems-dev/md-discord-syntax-core",
|
||||
"typecheck": "npm run typecheck --workspaces --if-present",
|
||||
"validate": "node scripts/validate.js",
|
||||
|
|
|
|||
|
|
@ -2,14 +2,12 @@ import test from "node:test";
|
|||
import assert from "node:assert";
|
||||
import {
|
||||
findSpoilerRanges,
|
||||
findCodeRanges,
|
||||
isPosInCode,
|
||||
isSubtextLine,
|
||||
stripSubtextPrefix,
|
||||
hasSubtextMarker,
|
||||
} from "../src/index.js";
|
||||
|
||||
test("Core Spoiler & Subtext Syntax Rules", async (t) => {
|
||||
void test("Core Spoiler & Subtext Syntax Rules", async (t) => {
|
||||
await t.test("detects basic spoiler range", () => {
|
||||
const text = "Hello ||secret|| world";
|
||||
const spoilers = findSpoilerRanges(text);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "discord-syntax",
|
||||
"id": "md-discord-syntax",
|
||||
"name": "Discord Syntax",
|
||||
"version": "1.0.21",
|
||||
"version": "1.0.22",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Discord-style `||spoiler||` and `-# subtext` markdown formatting extension.",
|
||||
"author": "Edems-DEV",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "discord-syntax",
|
||||
"version": "1.0.21",
|
||||
"name": "md-discord-syntax",
|
||||
"version": "1.0.22",
|
||||
"description": "Discord Syntax Obsidian plugin adapter",
|
||||
"private": true,
|
||||
"main": "main.js",
|
||||
|
|
|
|||
|
|
@ -14,10 +14,6 @@ interface ObsidianEditor {
|
|||
cm?: EditorView;
|
||||
}
|
||||
|
||||
interface MarkdownPreviewView {
|
||||
containerEl?: HTMLElement;
|
||||
}
|
||||
|
||||
export default class DiscordSyntaxPlugin extends Plugin {
|
||||
onload() {
|
||||
// ── Reading View Post Processor ──────────────────────────────────────
|
||||
|
|
@ -42,9 +38,7 @@ export default class DiscordSyntaxPlugin extends Plugin {
|
|||
|
||||
const mode = activeView.getMode();
|
||||
if (mode === "preview") {
|
||||
const preview =
|
||||
activeView.previewMode as unknown as MarkdownPreviewView;
|
||||
const container = preview?.containerEl;
|
||||
const container = activeView.previewMode?.containerEl;
|
||||
if (!container) return;
|
||||
const spoilers = container.querySelectorAll(
|
||||
".note-flow-spoiler, .discord-syntax-spoiler",
|
||||
|
|
@ -76,7 +70,7 @@ export default class DiscordSyntaxPlugin extends Plugin {
|
|||
}
|
||||
}
|
||||
} else if (mode === "source") {
|
||||
const editor = activeView.editor as unknown as ObsidianEditor;
|
||||
const editor = activeView.editor as ObsidianEditor;
|
||||
const cm = editor.cm;
|
||||
if (
|
||||
!cm ||
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ export function getSpoilerAtSelection(state: EditorState): SpoilerRange | null {
|
|||
if (!selection.main.empty) return null;
|
||||
const pos = selection.main.head;
|
||||
|
||||
const text = state.doc.toString();
|
||||
const spoilers = findSpoilerRanges(text);
|
||||
const line = state.doc.lineAt(pos);
|
||||
const spoilers = findSpoilerRanges(line.text, line.from);
|
||||
for (const s of spoilers) {
|
||||
if (pos >= s.from && pos <= s.to) {
|
||||
return s;
|
||||
|
|
@ -356,8 +356,8 @@ export const spoilerLivePreviewPlugin = ViewPlugin.fromClass(
|
|||
|
||||
const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
|
||||
if (pos !== null) {
|
||||
const text = view.state.doc.toString();
|
||||
const spoilers = findSpoilerRanges(text);
|
||||
const line = view.state.doc.lineAt(pos);
|
||||
const spoilers = findSpoilerRanges(line.text, line.from);
|
||||
const spoiler = spoilers.find((s) => pos >= s.from && pos <= s.to);
|
||||
|
||||
if (spoiler) {
|
||||
|
|
@ -414,9 +414,9 @@ export const spoilerLivePreviewPlugin = ViewPlugin.fromClass(
|
|||
if (spoilerId) {
|
||||
const fromStr = spoilerId.replace("spoiler-", "");
|
||||
const from = parseInt(fromStr, 10);
|
||||
if (!isNaN(from)) {
|
||||
const text = view.state.doc.toString();
|
||||
const spoilers = findSpoilerRanges(text);
|
||||
if (!isNaN(from) && from >= 0 && from <= view.state.doc.length) {
|
||||
const line = view.state.doc.lineAt(from);
|
||||
const spoilers = findSpoilerRanges(line.text, line.from);
|
||||
const spoiler = spoilers.find((s) => s.from === from);
|
||||
if (spoiler) {
|
||||
const currentState = getSpoilerState(
|
||||
|
|
|
|||
|
|
@ -1,29 +1,26 @@
|
|||
function createDetachedElement<K extends keyof HTMLElementTagNameMap>(
|
||||
doc: Document,
|
||||
tag: K,
|
||||
): HTMLElementTagNameMap[K] {
|
||||
const fragment = doc.createDocumentFragment();
|
||||
if (typeof fragment.createEl === "function") {
|
||||
return fragment.createEl(tag);
|
||||
}
|
||||
return doc.createElement(tag);
|
||||
}
|
||||
|
||||
export function processSpoilers(
|
||||
element: HTMLElement,
|
||||
doc: Document = element.ownerDocument,
|
||||
): void {
|
||||
function createSpoilerSpan(): HTMLSpanElement {
|
||||
const spoilerSpan = createDetachedElement(doc, "span");
|
||||
spoilerSpan.classList.add("note-flow-spoiler", "discord-syntax-spoiler");
|
||||
spoilerSpan.setAttribute("role", "button");
|
||||
spoilerSpan.setAttribute("tabindex", "0");
|
||||
spoilerSpan.setAttribute("aria-expanded", "false");
|
||||
spoilerSpan.setAttribute("aria-label", "Spoiler, click to reveal");
|
||||
const spoilerSpan = element.createEl("span", {
|
||||
cls: "note-flow-spoiler discord-syntax-spoiler",
|
||||
attr: {
|
||||
role: "button",
|
||||
tabindex: "0",
|
||||
"aria-expanded": "false",
|
||||
"aria-label": "Spoiler, click to reveal",
|
||||
},
|
||||
});
|
||||
if (spoilerSpan.parentNode) {
|
||||
spoilerSpan.parentNode.removeChild(spoilerSpan);
|
||||
}
|
||||
|
||||
const innerSpan = createDetachedElement(doc, "span");
|
||||
innerSpan.setAttribute("aria-hidden", "true");
|
||||
spoilerSpan.appendChild(innerSpan);
|
||||
const innerSpan = spoilerSpan.createEl("span", {
|
||||
attr: {
|
||||
"aria-hidden": "true",
|
||||
},
|
||||
});
|
||||
|
||||
function toggleSpoiler() {
|
||||
const isRevealed = spoilerSpan.classList.contains("is-revealed");
|
||||
|
|
@ -66,8 +63,12 @@ export function processSpoilers(
|
|||
if (beforeStr) {
|
||||
parent.insertBefore(doc.createTextNode(beforeStr), node);
|
||||
}
|
||||
const marker = createDetachedElement(doc, "span");
|
||||
marker.setAttribute("data-spoiler-marker", "true");
|
||||
const marker = element.createEl("span", {
|
||||
attr: { "data-spoiler-marker": "true" },
|
||||
});
|
||||
if (marker.parentNode) {
|
||||
marker.parentNode.removeChild(marker);
|
||||
}
|
||||
parent.insertBefore(marker, node);
|
||||
markers.push(marker);
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
* {
|
||||
color: transparent;
|
||||
-webkit-text-fill-color: transparent;
|
||||
text-decoration: none;
|
||||
text-decoration-line: none;
|
||||
text-decoration-color: transparent;
|
||||
text-shadow: none;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
findSpoilerRanges,
|
||||
} from "../src/spoiler-detector.js";
|
||||
|
||||
test("Spoiler Detection & Live Preview", async (t) => {
|
||||
void test("Spoiler Detection & Live Preview", async (t) => {
|
||||
await t.test("detects basic spoiler range", () => {
|
||||
const text = "Hello ||secret|| world";
|
||||
const ranges = findSpoilerRanges(text);
|
||||
|
|
@ -102,7 +102,7 @@ test("Spoiler Detection & Live Preview", async (t) => {
|
|||
items.push({
|
||||
from: iter.from,
|
||||
to: iter.to,
|
||||
value: iter.value as unknown as DecoItem["value"],
|
||||
value: iter.value,
|
||||
});
|
||||
iter.next();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import test from "node:test";
|
|||
import assert from "node:assert";
|
||||
import { processSubtextParagraph } from "../src/subtext-post-processor.js";
|
||||
|
||||
test("Subtext Reading View Post Processor", async (t) => {
|
||||
void test("Subtext Reading View Post Processor", async (t) => {
|
||||
await t.test(
|
||||
"wraps paragraph starting with -# into discord-subtext span",
|
||||
() => {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ interface TestNode {
|
|||
data?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
test("Remark Discord Syntax Plugin", async (t) => {
|
||||
void test("Remark Discord Syntax Plugin", async (t) => {
|
||||
const processor = remark().use(remarkMdDiscordSyntax);
|
||||
|
||||
await t.test("transforms discord-style spoilers (plain)", async () => {
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ try {
|
|||
}
|
||||
|
||||
// Ensure Obsidian plugin details
|
||||
if (manifest.id !== "discord-syntax") {
|
||||
if (manifest.id !== "md-discord-syntax") {
|
||||
exitWithError(
|
||||
`manifest.json id must be "discord-syntax", got "${manifest.id}"`,
|
||||
`manifest.json id must be "md-discord-syntax", got "${manifest.id}"`,
|
||||
);
|
||||
}
|
||||
if (manifest.name !== "Discord Syntax") {
|
||||
|
|
@ -110,9 +110,9 @@ try {
|
|||
);
|
||||
}
|
||||
|
||||
if (obsidianPkg.name !== "discord-syntax") {
|
||||
if (obsidianPkg.name !== "md-discord-syntax") {
|
||||
exitWithError(
|
||||
`packages/obsidian/package.json name must be "discord-syntax", got "${obsidianPkg.name}"`,
|
||||
`packages/obsidian/package.json name must be "md-discord-syntax", got "${obsidianPkg.name}"`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue