chore: address Obsidian review findings

This commit is contained in:
黄鸿峰 2026-05-18 11:37:14 +08:00
parent 2086948b97
commit 73f0b08592
11 changed files with 50 additions and 32 deletions

View file

@ -16,7 +16,9 @@ on:
type: string
permissions:
attestations: write
contents: write
id-token: write
jobs:
release:
@ -59,6 +61,13 @@ jobs:
exit 1
fi
- name: Attest release assets
uses: actions/attest-build-provenance@v2
with:
subject-path: |
main.js
styles.css
- name: Create or update GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,6 +1,6 @@
import esbuild from "esbuild";
import { builtinModules } from "module";
import process from "process";
import builtins from "builtin-modules";
const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
@ -28,7 +28,7 @@ const context = await esbuild.context({
"@lezer/common",
"@lezer/highlight",
"@lezer/lr",
...builtins,
...builtinModules,
],
format: "cjs",
target: "es2022",

View file

@ -1,7 +1,7 @@
{
"id": "table-master",
"name": "Table Master",
"version": "0.2.0",
"version": "0.2.1",
"minAppVersion": "1.4.0",
"description": "All-in-one Markdown table workflow: floating toolbar, visual grid editor, and merged-cell support with MultiMarkdown ^^ / || syntax.",
"author": "moranrs",

14
package-lock.json generated
View file

@ -15,7 +15,6 @@
"@types/node": "^20.10.0",
"@typescript-eslint/eslint-plugin": "^8.59.0",
"@typescript-eslint/parser": "^8.59.0",
"builtin-modules": "^3.3.0",
"esbuild": "^0.20.0",
"eslint": "^9.39.4",
"eslint-plugin-obsidianmd": "^0.2.4",
@ -1947,19 +1946,6 @@
"node": ">=8"
}
},
"node_modules/builtin-modules": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cac": {
"version": "6.7.14",
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",

View file

@ -1,6 +1,6 @@
{
"name": "obsidian-table-master",
"version": "0.2.0",
"version": "0.2.1",
"description": "Unified Markdown table plugin for Obsidian: GUI toolbar, visual grid editor, merged cells.",
"main": "main.js",
"scripts": {
@ -23,7 +23,6 @@
"@types/node": "^20.10.0",
"@typescript-eslint/eslint-plugin": "^8.59.0",
"@typescript-eslint/parser": "^8.59.0",
"builtin-modules": "^3.3.0",
"esbuild": "^0.20.0",
"eslint": "^9.39.4",
"eslint-plugin-obsidianmd": "^0.2.4",

View file

@ -24,6 +24,30 @@ const CONFLICT_PLUGIN_IDS = [
"table-extended",
];
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null;
}
function readSettings(data: unknown): Partial<TableMasterSettings> {
if (!isRecord(data)) return {};
const settings: Partial<TableMasterSettings> = {};
if (data.outputFormat === "extended" || data.outputFormat === "html") settings.outputFormat = data.outputFormat;
if (typeof data.showFloatingToolbar === "boolean") settings.showFloatingToolbar = data.showFloatingToolbar;
if (
data.floatingToolbarPosition === "on-click" ||
data.floatingToolbarPosition === "follow-mouse" ||
data.floatingToolbarPosition === "top-left"
) {
settings.floatingToolbarPosition = data.floatingToolbarPosition;
}
if (typeof data.enableTabNavigation === "boolean") settings.enableTabNavigation = data.enableTabNavigation;
if (data.defaultAlign === "left" || data.defaultAlign === "center" || data.defaultAlign === "right" || data.defaultAlign === "none") {
settings.defaultAlign = data.defaultAlign;
}
if (data.language === "auto" || data.language === "en" || data.language === "zh") settings.language = data.language;
return settings;
}
export default class TableMasterPlugin extends Plugin {
settings: TableMasterSettings = DEFAULT_SETTINGS;
@ -151,7 +175,8 @@ export default class TableMasterPlugin extends Plugin {
}
async loadSettings(): Promise<void> {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
const data: unknown = await this.loadData();
this.settings = Object.assign({}, DEFAULT_SETTINGS, readSettings(data));
}
async saveSettings(): Promise<void> {

View file

@ -9,6 +9,7 @@
// `^^` / `||` or HTML, depending on the user's setting.
import {
Align,
Cell,
TableModel,
makeAnchor,
@ -81,6 +82,7 @@ function tableElementToModel(table: HTMLTableElement): TableModel | null {
// Second pass: write actual content into the right anchor slot.
const written: boolean[][] = Array.from({ length: rows }, () => []);
const aligns: Array<Align> = Array.from({ length: cols }, (): Align => "none");
let headerRows = 0;
for (let r = 0; r < trs.length; r++) {
const cells = Array.from(trs[r].children).filter(
@ -124,7 +126,7 @@ function tableElementToModel(table: HTMLTableElement): TableModel | null {
const model: TableModel = {
rows: grid,
aligns: new Array(cols).fill("none"),
aligns,
headerRows,
cols,
tbodyBreaks: [],

View file

@ -82,7 +82,7 @@ function splitCellLines(cell: Cell): string[] {
export function serializeExtended(model: TableModel): string {
recomputeSpans(model);
const cols = model.cols;
const widths: number[] = new Array(cols).fill(3);
const widths = Array.from({ length: cols }, (): number => 3);
for (const row of model.rows) {
for (let c = 0; c < cols; c++) {
const cell = row[c];

View file

@ -4,7 +4,7 @@
// Cells may contain embedded newlines wrapped in double quotes (`"line 1\nline
// 2"`); we honour that quoting per RFC 4180 with tab as the delimiter.
import { Cell, TableModel, makeAnchor } from "./model";
import { Align, Cell, TableModel, makeAnchor } from "./model";
/** Try to parse a TSV string into a TableModel. Returns null when it doesn't
* look tabular (no tabs anywhere, no useful row separation). */
@ -28,7 +28,7 @@ export function importTsvTable(tsv: string): TableModel | null {
}
return {
rows: grid,
aligns: new Array(cols).fill("none"),
aligns: Array.from({ length: cols }, (): Align => "none"),
headerRows: 1,
cols,
tbodyBreaks: [],

View file

@ -26,11 +26,7 @@
}
.tm-floating-toolbar.is-hidden {
/* Toggled by the view plugin via classList instead of inline display
* styles. `!important` is used so a theme that bumps `display` on
* `.tm-floating-toolbar` cannot accidentally re-show the toolbar while
* the plugin considers it hidden. */
display: none !important;
display: none;
}
/* Inner wrapper that stacks functional groups vertically.
@ -57,7 +53,7 @@
}
.tm-floating-toolbar.is-collapsed .tm-toolbar-content {
width: 0 !important;
width: 0;
opacity: 0;
padding: 0;
gap: 0;
@ -108,7 +104,7 @@
* classList instead of writing element.style.display directly. */
table td.tm-merge-placeholder,
table th.tm-merge-placeholder {
display: none !important;
display: none;
}
.tm-floating-toolbar .tm-group {

View file

@ -1,4 +1,5 @@
{
"0.1.0": "1.4.0",
"0.2.0": "1.4.0"
"0.2.0": "1.4.0",
"0.2.1": "1.4.0"
}