obsidian#FrontMatterCache TypeScript Examples
The following examples show how to use
obsidian#FrontMatterCache.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: frontMatterParser.ts From obsidian-switcher-plus with GNU General Public License v3.0 | 6 votes |
static getAliases(frontMatter: FrontMatterCache): string[] {
let aliases: string[] = [];
if (frontMatter) {
aliases = FrontMatterParser.getValueForKey(frontMatter, /^alias(es)?$/i);
}
return aliases;
}
Example #2
Source File: frontMatterParser.ts From obsidian-switcher-plus with GNU General Public License v3.0 | 6 votes |
private static getValueForKey(
frontMatter: FrontMatterCache,
keyPattern: RegExp,
): string[] {
const retVal: string[] = [];
const fmKeys = Object.keys(frontMatter);
const key = fmKeys.find((val) => keyPattern.test(val));
if (key) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
let value = frontMatter[key];
if (typeof value === 'string') {
value = value.split(',');
}
if (Array.isArray(value)) {
value.forEach((val) => {
if (typeof val === 'string') {
retVal.push(val.trim());
}
});
}
}
return retVal;
}
Example #3
Source File: watcher.worker.ts From obsidian-fantasy-calendar with MIT License | 6 votes |
getDataFromFrontmatter(frontmatter: FrontMatterCache) {
let name: string, fcCategory: string, eventDisplayName: string;
if (frontmatter && "fc-ignore" in frontmatter) return {};
if (frontmatter) {
name = frontmatter?.["fc-calendar"];
fcCategory = frontmatter?.["fc-category"];
eventDisplayName = frontmatter?.["fc-display-name"];
}
if (this.addToDefaultIfMissing && (!name || !name.length)) {
name = this.defaultCalendar;
}
name = name?.toLowerCase();
const calendar = this.calendars.find(
(calendar) => name == calendar.name.toLowerCase()
);
return { calendar, fcCategory, eventDisplayName };
}
Example #4
Source File: watcher.worker.ts From obsidian-fantasy-calendar with MIT License | 6 votes |
getDates(frontmatter: Partial<FrontMatterCache> = {}, basename: string) {
const dateField = "fc-date" in frontmatter ? "fc-date" : "fc-start";
let startDate: string | CurrentCalendarData;
if (frontmatter && dateField in frontmatter) {
startDate = frontmatter[dateField];
}
if (!startDate) {
startDate = basename;
}
const date = this.parseDate(startDate);
const endDate =
"fc-end" in frontmatter
? (frontmatter["fc-end"] as string | CurrentCalendarData)
: null;
const end = this.parseDate(endDate);
return { date, end };
}
Example #5
Source File: markdown-file.ts From obsidian-dataview with MIT License | 5 votes |
/** Extract tags intelligently from frontmatter. Handles arrays, numbers, and strings. */
export function extractTags(metadata: FrontMatterCache): string[] {
let tagKeys = Object.keys(metadata).filter(t => t.toLowerCase() == "tags" || t.toLowerCase() == "tag");
return tagKeys.map(k => splitFrontmatterTagOrAlias(metadata[k])).reduce((p, c) => p.concat(c), []);
}
Example #6
Source File: markdown-file.ts From obsidian-dataview with MIT License | 5 votes |
/** Extract tags intelligently from frontmatter. Handles arrays, numbers, and strings. */
export function extractAliases(metadata: FrontMatterCache): string[] {
let aliasKeys = Object.keys(metadata).filter(t => t.toLowerCase() == "alias" || t.toLowerCase() == "aliases");
return aliasKeys.map(k => splitFrontmatterTagOrAlias(metadata[k])).reduce((p, c) => p.concat(c), []);
}
Example #7
Source File: watcher.worker.ts From obsidian-fantasy-calendar with MIT License | 5 votes |
parseFrontmatterEvents(
calendar: Calendar,
fcCategory: string,
frontmatter: FrontMatterCache,
file: { path: string; basename: string },
eventDisplayName?: string
): Event[] {
const { date, end } = this.getDates(
frontmatter,
this.parseTitle ? file.basename : ""
);
if (!date) {
return [];
}
if (date?.month && typeof date?.month == "string") {
let month = calendar.static.months.find(
(m) => m.name == (date.month as unknown as string)
);
if (!month) {
date.month = null;
} else {
date.month = calendar.static.months.indexOf(month);
}
} else if (date?.month && typeof date?.month == "number") {
date.month = wrap(date.month - 1, calendar.static.months.length);
}
if (end?.month && typeof end?.month == "string") {
let month = calendar.static.months.find(
(m) => m.name == (end.month as unknown as string)
);
if (!month) {
end.month = null;
} else {
end.month = calendar.static.months.indexOf(month);
}
} else if (end?.month && typeof end?.month == "number") {
end.month = wrap(end.month - 1, calendar.static.months.length);
}
const timestamp = Number(`${date.year}${date.month}${date.day}00`);
const category = calendar.categories.find(
(cat) => cat?.name == fcCategory
);
return [
{
id: nanoid(6),
name: eventDisplayName ?? file.basename,
note: file.path,
date,
end,
category: category?.id,
description: "",
auto: true
}
];
}
Example #8
Source File: frontMatterParser.test.ts From obsidian-switcher-plus with GNU General Public License v3.0 | 4 votes |
describe('FrontMatterParser', () => {
describe('getAliases', () => {
it('should return empty array with falsy input', () => {
const results = FrontMatterParser.getAliases(null);
expect(results).toBeInstanceOf(Array);
expect(results).toHaveLength(0);
});
it('should return empty array with missing key', () => {
const fm: FrontMatterCache = {
position: null,
};
const results = FrontMatterParser.getAliases(fm);
expect(results).toBeInstanceOf(Array);
expect(results).toHaveLength(0);
});
it('should parse alias key', () => {
const fm: FrontMatterCache = {
alias: 'foo',
position: null,
};
const results = FrontMatterParser.getAliases(fm);
expect(results).toBeInstanceOf(Array);
expect(results).toHaveLength(1);
expect(results[0]).toBe('foo');
});
it('should parse aliases key', () => {
const fm: FrontMatterCache = {
aliases: 'foo',
position: null,
};
const results = FrontMatterParser.getAliases(fm);
expect(results).toBeInstanceOf(Array);
expect(results).toHaveLength(1);
expect(results[0]).toBe('foo');
});
it('should parse string values', () => {
const fm: FrontMatterCache = {
aliases: 'one, two ,three',
position: null,
};
const results = FrontMatterParser.getAliases(fm);
expect(results).toBeInstanceOf(Array);
expect(results).toHaveLength(3);
expect(results).toEqual((fm.aliases as string).split(',').map((val) => val.trim()));
});
it('should parse array values', () => {
const fm: FrontMatterCache = {
aliases: ['one', 'two ', 'three'],
position: null,
};
const results = FrontMatterParser.getAliases(fm);
expect(results).toBeInstanceOf(Array);
expect(results).toHaveLength(3);
expect(results).toEqual((fm.aliases as string[]).map((val) => val.trim()));
});
it('should ignore non-string/non-array values', () => {
const fm: FrontMatterCache = {
aliases: {},
position: null,
};
const results = FrontMatterParser.getAliases(fm);
expect(results).toBeInstanceOf(Array);
expect(results).toHaveLength(0);
});
it('should ignore nested non-string values', () => {
const fm: FrontMatterCache = {
aliases: ['one', ['two'], 'three'],
position: null,
};
const results = FrontMatterParser.getAliases(fm);
expect(results).toBeInstanceOf(Array);
expect(results).toHaveLength(2);
expect(results).toEqual(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(fm.aliases as any[]).filter((val) => typeof val === 'string'),
);
});
});
});
Example #9
Source File: main.ts From obsidian-spaced-repetition with MIT License | 4 votes |
async sync(): Promise<void> {
if (this.syncLock) {
return;
}
this.syncLock = true;
// reset notes stuff
graph.reset();
this.easeByPath = {};
this.incomingLinks = {};
this.pageranks = {};
this.dueNotesCount = 0;
this.dueDatesNotes = {};
this.reviewDecks = {};
// reset flashcards stuff
this.deckTree = new Deck("root", null);
this.dueDatesFlashcards = {};
this.cardStats = {
eases: {},
intervals: {},
newCount: 0,
youngCount: 0,
matureCount: 0,
};
const now = window.moment(Date.now());
const todayDate: string = now.format("YYYY-MM-DD");
// clear bury list if we've changed dates
if (todayDate !== this.data.buryDate) {
this.data.buryDate = todayDate;
this.data.buryList = [];
}
const notes: TFile[] = this.app.vault.getMarkdownFiles();
for (const note of notes) {
if (
this.data.settings.noteFoldersToIgnore.some((folder) =>
note.path.startsWith(folder)
)
) {
continue;
}
if (this.incomingLinks[note.path] === undefined) {
this.incomingLinks[note.path] = [];
}
const links = this.app.metadataCache.resolvedLinks[note.path] || {};
for (const targetPath in links) {
if (this.incomingLinks[targetPath] === undefined)
this.incomingLinks[targetPath] = [];
// markdown files only
if (targetPath.split(".").pop().toLowerCase() === "md") {
this.incomingLinks[targetPath].push({
sourcePath: note.path,
linkCount: links[targetPath],
});
graph.link(note.path, targetPath, links[targetPath]);
}
}
const deckPath: string[] = this.findDeckPath(note);
if (deckPath.length !== 0) {
const flashcardsInNoteAvgEase: number = await this.findFlashcardsInNote(
note,
deckPath
);
if (flashcardsInNoteAvgEase > 0) {
this.easeByPath[note.path] = flashcardsInNoteAvgEase;
}
}
const fileCachedData = this.app.metadataCache.getFileCache(note) || {};
const frontmatter: FrontMatterCache | Record<string, unknown> =
fileCachedData.frontmatter || {};
const tags = getAllTags(fileCachedData) || [];
let shouldIgnore = true;
const matchedNoteTags = [];
for (const tagToReview of this.data.settings.tagsToReview) {
if (tags.some((tag) => tag === tagToReview || tag.startsWith(tagToReview + "/"))) {
if (!Object.prototype.hasOwnProperty.call(this.reviewDecks, tagToReview)) {
this.reviewDecks[tagToReview] = new ReviewDeck(tagToReview);
}
matchedNoteTags.push(tagToReview);
shouldIgnore = false;
break;
}
}
if (shouldIgnore) {
continue;
}
// file has no scheduling information
if (
!(
Object.prototype.hasOwnProperty.call(frontmatter, "sr-due") &&
Object.prototype.hasOwnProperty.call(frontmatter, "sr-interval") &&
Object.prototype.hasOwnProperty.call(frontmatter, "sr-ease")
)
) {
for (const matchedNoteTag of matchedNoteTags) {
this.reviewDecks[matchedNoteTag].newNotes.push(note);
}
continue;
}
const dueUnix: number = window
.moment(frontmatter["sr-due"], ["YYYY-MM-DD", "DD-MM-YYYY", "ddd MMM DD YYYY"])
.valueOf();
for (const matchedNoteTag of matchedNoteTags) {
this.reviewDecks[matchedNoteTag].scheduledNotes.push({ note, dueUnix });
if (dueUnix <= now.valueOf()) {
this.reviewDecks[matchedNoteTag].dueNotesCount++;
}
}
if (Object.prototype.hasOwnProperty.call(this.easeByPath, note.path)) {
this.easeByPath[note.path] =
(this.easeByPath[note.path] + frontmatter["sr-ease"]) / 2;
} else {
this.easeByPath[note.path] = frontmatter["sr-ease"];
}
if (dueUnix <= now.valueOf()) {
this.dueNotesCount++;
}
const nDays: number = Math.ceil((dueUnix - now.valueOf()) / (24 * 3600 * 1000));
if (!Object.prototype.hasOwnProperty.call(this.dueDatesNotes, nDays)) {
this.dueDatesNotes[nDays] = 0;
}
this.dueDatesNotes[nDays]++;
}
graph.rank(0.85, 0.000001, (node: string, rank: number) => {
this.pageranks[node] = rank * 10000;
});
// sort the deck names
this.deckTree.sortSubdecksList();
if (this.data.settings.showDebugMessages) {
console.log(`SR: ${t("EASES")}`, this.easeByPath);
console.log(`SR: ${t("DECKS")}`, this.deckTree);
}
for (const deckKey in this.reviewDecks) {
this.reviewDecks[deckKey].sortNotes(this.pageranks);
}
if (this.data.settings.showDebugMessages) {
console.log(
"SR: " +
t("SYNC_TIME_TAKEN", {
t: Date.now() - now.valueOf(),
})
);
}
this.statusBar.setText(
t("STATUS_BAR", {
dueNotesCount: this.dueNotesCount,
dueFlashcardsCount: this.deckTree.dueFlashcardsCount,
})
);
this.reviewQueueView.redraw();
this.syncLock = false;
}
Example #10
Source File: main.ts From obsidian-spaced-repetition with MIT License | 4 votes |
async saveReviewResponse(note: TFile, response: ReviewResponse): Promise<void> {
const fileCachedData = this.app.metadataCache.getFileCache(note) || {};
const frontmatter: FrontMatterCache | Record<string, unknown> =
fileCachedData.frontmatter || {};
const tags = getAllTags(fileCachedData) || [];
if (this.data.settings.noteFoldersToIgnore.some((folder) => note.path.startsWith(folder))) {
new Notice(t("NOTE_IN_IGNORED_FOLDER"));
return;
}
let shouldIgnore = true;
for (const tag of tags) {
if (
this.data.settings.tagsToReview.some(
(tagToReview) => tag === tagToReview || tag.startsWith(tagToReview + "/")
)
) {
shouldIgnore = false;
break;
}
}
if (shouldIgnore) {
new Notice(t("PLEASE_TAG_NOTE"));
return;
}
let fileText: string = await this.app.vault.read(note);
let ease: number, interval: number, delayBeforeReview: number;
const now: number = Date.now();
// new note
if (
!(
Object.prototype.hasOwnProperty.call(frontmatter, "sr-due") &&
Object.prototype.hasOwnProperty.call(frontmatter, "sr-interval") &&
Object.prototype.hasOwnProperty.call(frontmatter, "sr-ease")
)
) {
let linkTotal = 0,
linkPGTotal = 0,
totalLinkCount = 0;
for (const statObj of this.incomingLinks[note.path] || []) {
const ease: number = this.easeByPath[statObj.sourcePath];
if (ease) {
linkTotal += statObj.linkCount * this.pageranks[statObj.sourcePath] * ease;
linkPGTotal += this.pageranks[statObj.sourcePath] * statObj.linkCount;
totalLinkCount += statObj.linkCount;
}
}
const outgoingLinks = this.app.metadataCache.resolvedLinks[note.path] || {};
for (const linkedFilePath in outgoingLinks) {
const ease: number = this.easeByPath[linkedFilePath];
if (ease) {
linkTotal +=
outgoingLinks[linkedFilePath] * this.pageranks[linkedFilePath] * ease;
linkPGTotal += this.pageranks[linkedFilePath] * outgoingLinks[linkedFilePath];
totalLinkCount += outgoingLinks[linkedFilePath];
}
}
const linkContribution: number =
this.data.settings.maxLinkFactor *
Math.min(1.0, Math.log(totalLinkCount + 0.5) / Math.log(64));
ease =
(1.0 - linkContribution) * this.data.settings.baseEase +
(totalLinkCount > 0
? (linkContribution * linkTotal) / linkPGTotal
: linkContribution * this.data.settings.baseEase);
// add note's average flashcard ease if available
if (Object.prototype.hasOwnProperty.call(this.easeByPath, note.path)) {
ease = (ease + this.easeByPath[note.path]) / 2;
}
ease = Math.round(ease);
interval = 1.0;
delayBeforeReview = 0;
} else {
interval = frontmatter["sr-interval"];
ease = frontmatter["sr-ease"];
delayBeforeReview =
now -
window
.moment(frontmatter["sr-due"], ["YYYY-MM-DD", "DD-MM-YYYY", "ddd MMM DD YYYY"])
.valueOf();
}
const schedObj: Record<string, number> = schedule(
response,
interval,
ease,
delayBeforeReview,
this.data.settings,
this.dueDatesNotes
);
interval = schedObj.interval;
ease = schedObj.ease;
const due = window.moment(now + interval * 24 * 3600 * 1000);
const dueString: string = due.format("YYYY-MM-DD");
// check if scheduling info exists
if (SCHEDULING_INFO_REGEX.test(fileText)) {
const schedulingInfo = SCHEDULING_INFO_REGEX.exec(fileText);
fileText = fileText.replace(
SCHEDULING_INFO_REGEX,
`---\n${schedulingInfo[1]}sr-due: ${dueString}\n` +
`sr-interval: ${interval}\nsr-ease: ${ease}\n` +
`${schedulingInfo[5]}---`
);
} else if (YAML_FRONT_MATTER_REGEX.test(fileText)) {
// new note with existing YAML front matter
const existingYaml = YAML_FRONT_MATTER_REGEX.exec(fileText);
fileText = fileText.replace(
YAML_FRONT_MATTER_REGEX,
`---\n${existingYaml[1]}sr-due: ${dueString}\n` +
`sr-interval: ${interval}\nsr-ease: ${ease}\n---`
);
} else {
fileText =
`---\nsr-due: ${dueString}\nsr-interval: ${interval}\n` +
`sr-ease: ${ease}\n---\n\n${fileText}`;
}
if (this.data.settings.burySiblingCards) {
await this.findFlashcardsInNote(note, [], true); // bury all cards in current note
await this.savePluginData();
}
await this.app.vault.modify(note, fileText);
new Notice(t("RESPONSE_RECEIVED"));
await this.sync();
if (this.data.settings.autoNextNote) {
this.reviewNextNote(this.lastSelectedReviewDeck);
}
}
Example #11
Source File: main.ts From obsidian-initiative-tracker with GNU General Public License v3.0 | 4 votes |
async onload() {
registerIcons();
await this.loadSettings();
this.addSettingTab(new InitiativeTrackerSettings(this));
this.registerView(
INTIATIVE_TRACKER_VIEW,
(leaf: WorkspaceLeaf) => new TrackerView(leaf, this)
);
this.registerView(
CREATURE_TRACKER_VIEW,
(leaf: WorkspaceLeaf) => new CreatureView(leaf, this)
);
this.addCommands();
this.registerMarkdownCodeBlockProcessor("encounter", (src, el, ctx) => {
const handler = new EncounterBlock(this, src, el);
ctx.addChild(handler);
});
this.registerMarkdownCodeBlockProcessor(
"encounter-table",
(src, el, ctx) => {
const handler = new EncounterBlock(this, src, el, true);
ctx.addChild(handler);
}
);
this.registerMarkdownPostProcessor(async (el, ctx) => {
if (!el || !el.firstElementChild) return;
const codeEls = el.querySelectorAll<HTMLElement>("code");
if (!codeEls || !codeEls.length) return;
const codes = Array.from(codeEls).filter((code) =>
/^encounter:\s/.test(code.innerText)
);
if (!codes.length) return;
for (const code of codes) {
const creatures = code.innerText
.replace(`encounter:`, "")
.trim()
.split(",")
.map((s) => parseYaml(s.trim()));
const parser = new EncounterParser(this);
const parsed = await parser.parse({ creatures });
if (!parsed || !parsed.creatures || !parsed.creatures.size)
continue;
const target = createSpan("initiative-tracker-encounter-line");
new EncounterLine({
target,
props: {
...parsed,
plugin: this
}
});
code.replaceWith(target);
}
});
this.playerCreatures = new Map(
this.data.players.map((p) => [p.name, Creature.from(p)])
);
this.homebrewCreatures = new Map(
this.bestiary.map((p) => [p.name, Creature.from(p)])
);
this.app.workspace.onLayoutReady(async () => {
this.addTrackerView();
//Update players from < 7.2
for (const player of this.data.players) {
if (player.path) continue;
if (!player.note) continue;
const file = await this.app.metadataCache.getFirstLinkpathDest(
player.note,
""
);
if (
!file ||
!this.app.metadataCache.getFileCache(file)?.frontmatter
) {
new Notice(
`Initiative Tracker: There was an issue with the linked note for ${player.name}.\n\nPlease re-link it in settings.`
);
continue;
}
}
this.registerEvent(
this.app.metadataCache.on("changed", (file) => {
if (!(file instanceof TFile)) return;
const players = this.data.players.filter(
(p) => p.path == file.path
);
if (!players.length) return;
const frontmatter: FrontMatterCache =
this.app.metadataCache.getFileCache(file)?.frontmatter;
if (!frontmatter) return;
for (let player of players) {
const { ac, hp, modifier, level } = frontmatter;
player.ac = ac;
player.hp = hp;
player.modifier = modifier;
player.level = level;
this.playerCreatures.set(
player.name,
Creature.from(player)
);
if (this.view) {
const creature = this.view.ordered.find(
(c) => c.name == player.name
);
if (creature) {
this.view.updateCreature(creature, {
max: player.hp,
ac: player.ac
});
}
}
}
})
);
this.registerEvent(
this.app.vault.on("rename", (file, old) => {
if (!(file instanceof TFile)) return;
const players = this.data.players.filter(
(p) => p.path == old
);
if (!players.length) return;
for (const player of players) {
player.path = file.path;
player.note = file.basename;
}
})
);
this.registerEvent(
this.app.vault.on("delete", (file) => {
if (!(file instanceof TFile)) return;
const players = this.data.players.filter(
(p) => p.path == file.path
);
if (!players.length) return;
for (const player of players) {
player.path = null;
player.note = null;
}
})
);
});
console.log("Initiative Tracker v" + this.manifest.version + " loaded");
}