1.1.0: fix Live Preview crash, add Reading View inline support, birthday labels
- Fix RangeSetBuilder ordering crash: inline and fenced-block decorations
are now merged and sorted before being added, instead of two unsorted
passes (crashed whenever a fenced block preceded inline code in a note).
- Add explicit @codemirror/state and @codemirror/view devDependencies
(previously only transitive via @codemirror/language).
- Add Reading View support for inline `date-calc:` spans via
registerMarkdownPostProcessor (previously Live Preview only), mirroring
the approach used by Dataview's inline queries.
- Fix verbose=false being silently truthy (non-empty string) in inline
key=value config, which meant it never actually disabled verbose output.
- Fix diff type auto-inference: from/to was dead code (countdown's check
always matched first); reordered so from+to or start+end infer diff.
- Implement documented but missing birthday label support: cfg.label,
falling back to frontmatter name ("Jane's age:"), then "Age:".
- Split main.ts (777 lines) into src/ modules per AGENTS.md conventions.
- Fix duplicated command-palette prefixes, move inline JS styles to
styles.css, fix package.json author, drop orphaned showArrow setting.
Verified: unit tests against the real bundled logic (mocked obsidian
module), a reproduction of the RangeSetBuilder crash against the real
@codemirror/state package, and live end-to-end testing in Obsidian via
CDP/Playwright (Tchernobyl vault).
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { moment } from "obsidian";
|
||||
import type { M } from "./types";
|
||||
|
||||
/**
|
||||
* Parse a date-ish input (frontmatter Date object, "YYYY-MM-DD" string, or any
|
||||
* moment-parseable string) into a moment. Returns null if unparseable.
|
||||
*/
|
||||
export function parseMoment(input: unknown): M | null {
|
||||
if (input == null || input === "") return null;
|
||||
|
||||
if (input instanceof Date) {
|
||||
if (Number.isNaN(input.getTime())) return null;
|
||||
|
||||
const isUtcMidnight =
|
||||
input.getUTCHours() === 0 &&
|
||||
input.getUTCMinutes() === 0 &&
|
||||
input.getUTCSeconds() === 0 &&
|
||||
input.getUTCMilliseconds() === 0;
|
||||
|
||||
if (isUtcMidnight) {
|
||||
return moment({
|
||||
year: input.getUTCFullYear(),
|
||||
month: input.getUTCMonth(),
|
||||
day: input.getUTCDate(),
|
||||
}).startOf("day");
|
||||
}
|
||||
|
||||
return moment(input);
|
||||
}
|
||||
|
||||
const s = String(input).trim();
|
||||
const dateOnly = moment(s, "YYYY-MM-DD", true);
|
||||
if (dateOnly.isValid()) return dateOnly.startOf("day");
|
||||
|
||||
const any = moment(s);
|
||||
return any.isValid() ? any : null;
|
||||
}
|
||||
|
||||
/** Break the span between two moments into years/months/days/hours/minutes. */
|
||||
export function formatSpan(
|
||||
from: M,
|
||||
to: M,
|
||||
verbose: boolean
|
||||
): { text: string; isNegative: boolean } {
|
||||
let a = from.clone();
|
||||
let b = to.clone();
|
||||
|
||||
const isNegative = b.isBefore(a);
|
||||
if (isNegative) [a, b] = [b, a];
|
||||
|
||||
const years = b.diff(a, "years"); a.add(years, "years");
|
||||
const months = b.diff(a, "months"); a.add(months, "months");
|
||||
const days = b.diff(a, "days"); a.add(days, "days");
|
||||
const hours = b.diff(a, "hours"); a.add(hours, "hours");
|
||||
const minutes = b.diff(a, "minutes");
|
||||
|
||||
if (verbose) {
|
||||
const parts: string[] = [];
|
||||
if (years) parts.push(`${years} year${years === 1 ? "" : "s"}`);
|
||||
if (months) parts.push(`${months} month${months === 1 ? "" : "s"}`);
|
||||
if (days) parts.push(`${days} day${days === 1 ? "" : "s"}`);
|
||||
if (hours && parts.length < 3) parts.push(`${hours} hour${hours === 1 ? "" : "s"}`);
|
||||
if (minutes && parts.length < 3) parts.push(`${minutes} minute${minutes === 1 ? "" : "s"}`);
|
||||
return { text: parts.join(", ") || "0 minutes", isNegative };
|
||||
} else {
|
||||
const parts: string[] = [];
|
||||
if (years) parts.push(`${years}y`);
|
||||
if (months) parts.push(`${months}mo`);
|
||||
if (days) parts.push(`${days}d`);
|
||||
if (hours && parts.length < 3) parts.push(`${hours}h`);
|
||||
if (minutes && parts.length < 3) parts.push(`${minutes}m`);
|
||||
return { text: parts.join(" ") || "0m", isNegative };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user