Skip to content

Commit 2f41a11

Browse files
committed
feat: rewrite the plugin to use a single cache that other plugins can fetch from via an exposed API rather than using daily-notes-interface
1 parent 6145639 commit 2f41a11

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+10270
-5330
lines changed

.DS_Store

6 KB
Binary file not shown.

.eslintrc.js

+26-5
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,33 @@ module.exports = {
22
root: true,
33
parser: "@typescript-eslint/parser",
44
plugins: ["@typescript-eslint"],
5-
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
5+
extends: [
6+
"eslint:recommended",
7+
"plugin:@typescript-eslint/recommended",
8+
"plugin:import/recommended",
9+
"plugin:import/typescript",
10+
],
611
rules: {
7-
"@typescript-eslint/no-unused-vars": [
8-
2,
9-
{ args: "all", argsIgnorePattern: "^_" },
12+
"@typescript-eslint/no-unused-vars": [2, { args: "all", argsIgnorePattern: "^_" }],
13+
"no-control-regex": 0,
14+
"import/no-unresolved": 0,
15+
"import/order": [
16+
"error",
17+
{
18+
groups: [
19+
"external", // Built-in types are first
20+
"internal",
21+
["sibling", "parent"], // Then sibling and parent types. They can be mingled together
22+
"index", // Then the index file
23+
"object",
24+
// Then the rest: internal and external type
25+
],
26+
"newlines-between": "always",
27+
alphabetize: {
28+
order: "asc",
29+
caseInsensitive: true,
30+
},
31+
},
1032
],
11-
"no-control-regex": 0
1233
},
1334
};

.yarnrc.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
nodeLinker: node-modules
2+
3+
yarnPath: .yarn/releases/yarn-berry.cjs

esbuild.config.mjs

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import esbuild from "esbuild";
2+
import process from "process";
3+
import builtins from "builtin-modules";
4+
import sveltePlugin from "esbuild-svelte";
5+
import sveltePreprocess from "svelte-preprocess";
6+
7+
const banner = `/*
8+
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
9+
if you want to view the source, please visit the github repository of this plugin
10+
*/
11+
`;
12+
13+
const prod = process.argv[2] === "production";
14+
15+
esbuild
16+
.build({
17+
banner: {
18+
js: banner,
19+
},
20+
minify: prod ? true : false,
21+
entryPoints: ["src/index.ts"],
22+
bundle: true,
23+
external: [
24+
"obsidian",
25+
"electron",
26+
"codemirror",
27+
"@codemirror/closebrackets",
28+
"@codemirror/commands",
29+
"@codemirror/fold",
30+
"@codemirror/gutter",
31+
"@codemirror/history",
32+
"@codemirror/language",
33+
"@codemirror/rangeset",
34+
"@codemirror/rectangular-selection",
35+
"@codemirror/search",
36+
"@codemirror/state",
37+
"@codemirror/stream-parser",
38+
"@codemirror/text",
39+
"@codemirror/view",
40+
...builtins,
41+
],
42+
format: "cjs",
43+
watch: !prod,
44+
target: "es2016",
45+
plugins: [
46+
sveltePlugin({
47+
compilerOptions: { css: true },
48+
preprocess: sveltePreprocess(),
49+
}),
50+
],
51+
logLevel: "info",
52+
sourcemap: prod ? false : "inline",
53+
treeShaking: true,
54+
outfile: "main.js",
55+
})
56+
.catch(() => process.exit(1));

main.css

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+26-23
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,44 @@
66
"main": "main.js",
77
"license": "MIT",
88
"scripts": {
9-
"lint": "eslint . --ext .ts",
10-
"build": "npm run lint && rollup -c",
9+
"lint": "svelte-check && eslint . --ext .ts",
10+
"lint:fix": "svelte-check && eslint . --ext .ts --fix",
11+
"dev": "node esbuild.config.mjs",
12+
"build": "yarn run lint && node esbuild.config.mjs production",
13+
"release": "standard-version",
1114
"test": "jest --passWithNoTests",
1215
"test:watch": "yarn test -- --watch"
1316
},
17+
"standard-version": {
18+
"t": ""
19+
},
1420
"dependencies": {
15-
"@popperjs/core": "2.9.1",
16-
"obsidian": "0.12.16",
17-
"obsidian-daily-notes-interface": "0.9.4",
18-
"svelte": "3.35.0",
19-
"tslib": "2.1.0"
21+
"lodash": "4.17.21",
22+
"obsidian": "0.13.30",
23+
"svelte": "3.46.4",
24+
"tslib": "2.3.1"
2025
},
2126
"devDependencies": {
22-
"@rollup/plugin-commonjs": "17.1.0",
23-
"@rollup/plugin-node-resolve": "11.2.0",
24-
"@rollup/plugin-typescript": "8.2.0",
2527
"@testing-library/jest-dom": "5.11.9",
26-
"@tsconfig/svelte": "1.0.10",
28+
"@tsconfig/svelte": "3.0.0",
2729
"@types/jest": "26.0.20",
30+
"@types/lodash": "4.14.179",
2831
"@types/moment": "2.13.0",
29-
"@types/node": "14.14.34",
30-
"@typescript-eslint/eslint-plugin": "4.17.0",
31-
"@typescript-eslint/parser": "4.17.0",
32-
"eslint": "7.22.0",
32+
"@types/node": "17.0.22",
33+
"@typescript-eslint/eslint-plugin": "^5.16.0",
34+
"@typescript-eslint/parser": "^5.16.0",
35+
"builtin-modules": "^3.2.0",
36+
"esbuild": "0.14.28",
37+
"esbuild-svelte": "0.6.3",
38+
"eslint": "8.11.0",
39+
"eslint-plugin-import": "^2.25.4",
3340
"jest": "26.6.3",
3441
"moment": "2.29.1",
35-
"rollup": "2.41.2",
36-
"rollup-plugin-svelte": "7.1.0",
37-
"svelte-check": "1.2.5",
38-
"svelte-preprocess": "4.6.9",
42+
"standard-version": "^9.3.2",
43+
"svelte-check": "2.4.6",
44+
"svelte-preprocess": "4.10.4",
3945
"ts-jest": "26.5.3",
40-
"typescript": "4.2.3"
41-
},
42-
"resolutions": {
43-
"obsidian": "0.12.16"
46+
"typescript": "^4.6.3"
4447
},
4548
"jest": {
4649
"moduleNameMapper": {

rollup.config.js

-28
This file was deleted.

src/cache.ts

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import type { Moment } from "moment";
2+
import { App, Component, TAbstractFile, TFile, TFolder, Vault } from "obsidian";
3+
4+
import { granularities, type Granularity, type PeriodicConfig } from "./types";
5+
6+
import type PeriodicNotesPlugin from "./index";
7+
8+
9+
type MatchType = "filename" | "frontmatter";
10+
11+
interface PeriodicNoteMatchMatchData {
12+
/* where was the date found */
13+
matchType: MatchType;
14+
/* XXX: keep ZK matches in the cache, should this be separate from formats with HH:mm in them? */
15+
/* just collect this for now, not 100% sure how it will be used. */
16+
exact: boolean;
17+
}
18+
19+
export interface PeriodicNoteCachedMetadata {
20+
calendarSet: string;
21+
22+
filePath: string;
23+
date: Moment;
24+
granularity: Granularity;
25+
canonicalDateStr: string;
26+
27+
/* "how" the match was made */
28+
matchData: PeriodicNoteMatchMatchData;
29+
}
30+
31+
function getCanonicalDateString(_granularity: Granularity, date: Moment): string {
32+
// TODO support all granularities
33+
return date.format("YYYY-MM-DD");
34+
}
35+
36+
export class PeriodicNotesCache extends Component {
37+
// Map the full filename to
38+
public cachedFiles: Map<string, PeriodicNoteCachedMetadata>;
39+
40+
constructor(readonly app: App, readonly plugin: PeriodicNotesPlugin) {
41+
super();
42+
this.cachedFiles = new Map();
43+
}
44+
45+
public initialize(): void {
46+
console.info("[PERIODIC NOTES] initializing cache");
47+
this.registerEvent(this.app.metadataCache.on("resolve", this.resolve, this));
48+
49+
for (const calendarSet of this.plugin.calendarSetManager.getCalendarSets()) {
50+
for (const granularity of granularities) {
51+
const config = calendarSet[granularity] as PeriodicConfig;
52+
const rootFolder = this.app.vault.getAbstractFileByPath(
53+
config.folder || "/"
54+
) as TFolder;
55+
// TODO: memoize this
56+
Vault.recurseChildren(rootFolder, (file: TAbstractFile) => {
57+
if (file instanceof TFile) {
58+
this.resolve(file);
59+
}
60+
});
61+
}
62+
}
63+
}
64+
65+
private resolve(file: TFile): void {
66+
// TODO: should I listen for create+rename instead? Rename would allow me to remove items from the cache
67+
const manager = this.plugin.calendarSetManager;
68+
69+
// Check if file matches any calendar set
70+
for (const calendarSet of manager.getCalendarSets()) {
71+
for (const granularity of granularities) {
72+
const format = manager.getFormat(granularity);
73+
const date = window.moment(file.basename, format, true);
74+
if (date.isValid()) {
75+
this.cachedFiles.set(file.path, {
76+
calendarSet: calendarSet.id,
77+
filePath: file.path,
78+
date,
79+
granularity,
80+
canonicalDateStr: getCanonicalDateString(granularity, date),
81+
matchData: {
82+
exact: true,
83+
matchType: "filename",
84+
},
85+
});
86+
return;
87+
}
88+
}
89+
}
90+
}
91+
92+
/**
93+
*
94+
* Get a periodic note from the cache
95+
*
96+
* @param calendarSet
97+
* @param granularity
98+
* @param date
99+
*/
100+
public getPeriodicNote(
101+
calendarSet: string,
102+
granularity: Granularity,
103+
date: Moment
104+
): TFile | null {
105+
for (const [filePath, cacheData] of this.cachedFiles) {
106+
if (cacheData.calendarSet !== calendarSet) continue;
107+
if (cacheData.granularity !== granularity) continue;
108+
if (!cacheData.date.isSame(date, granularity)) continue;
109+
110+
/**
111+
* TODO handle the non-unique case.
112+
*/
113+
114+
return this.app.vault.getAbstractFileByPath(filePath) as TFile;
115+
}
116+
117+
return null;
118+
}
119+
120+
// XXX: is this good to expose?
121+
public get(filePath: string): PeriodicNoteCachedMetadata | null {
122+
return this.cachedFiles.get(filePath) ?? null;
123+
}
124+
125+
public getCachedFiles(): Map<string, PeriodicNoteCachedMetadata> {
126+
return Object.freeze(this.cachedFiles);
127+
}
128+
}

0 commit comments

Comments
 (0)