Skip to content

Commit

Permalink
file: abstract file
Browse files Browse the repository at this point in the history
  • Loading branch information
julesvirallinen committed Sep 26, 2023
1 parent 79ccb15 commit 89ec12f
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 63 deletions.
16 changes: 14 additions & 2 deletions main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { DigitalGardenSettingTab } from "./src/ui/DigitalGardenSettingTab";
import { generateGardenSnapshot } from "./src/test/snapshot/generateGardenSnapshot";
import { FRONTMATTER_KEYS } from "./src/models/frontMatter";
import dotenv from "dotenv";
import { PublishFile } from "./src/publisher/PublishFile";
dotenv.config();

const DEFAULT_SETTINGS: DigitalGardenSettings = {
Expand Down Expand Up @@ -159,6 +160,7 @@ export default class DigitalGarden extends Plugin {
this.addCommand({
id: "publish-multiple-notes",
name: "Publish Multiple Notes",
// TODO: move to publisher?
callback: async () => {
const statusBarItem = this.addStatusBarItem();

Expand Down Expand Up @@ -215,7 +217,7 @@ export default class DigitalGarden extends Plugin {
errorFiles++;

new Notice(
`Unable to publish note ${file.name}, skipping it.`,
`Unable to publish note ${file.file.name}, skipping it.`,
);
}
}
Expand Down Expand Up @@ -362,6 +364,7 @@ export default class DigitalGarden extends Plugin {
}
}

// TODO: move to publisher?
async publishSingleNote() {
try {
const { vault, workspace, metadataCache } = this.app;
Expand All @@ -387,7 +390,16 @@ export default class DigitalGarden extends Plugin {
metadataCache,
this.settings,
);
const publishSuccessful = await publisher.publish(activeFile);

const publishFile = await new PublishFile({
file: activeFile,
vault: vault,
compiler: publisher.compiler,
metadataCache: metadataCache,
settings: this.settings,
}).compile();

const publishSuccessful = await publisher.publish(publishFile);

if (publishSuccessful) {
new Notice(`Successfully published note to your garden.`);
Expand Down
5 changes: 2 additions & 3 deletions src/compiler/FrontmatterCompiler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DateTime } from "luxon";
import { FrontMatterCache, MetadataCache, TFile, Vault } from "obsidian";
import { FrontMatterCache, MetadataCache, TFile } from "obsidian";
import {
getGardenPathForNote,
sanitizePermalink,
Expand Down Expand Up @@ -33,8 +33,7 @@ export class FrontmatterCompiler {
private readonly settings: DigitalGardenSettings;
private readonly rewriteRules: PathRewriteRules;

constructor(vault: Vault, settings: DigitalGardenSettings) {
// this.vault = vault;
constructor(settings: DigitalGardenSettings) {
this.settings = settings;
this.rewriteRules = getRewriteRules(settings.pathRewriteRules);
}
Expand Down
8 changes: 5 additions & 3 deletions src/compiler/GardenPageCompiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export interface Assets {
images: Array<Asset>;
}

export type TCompiledFile = [string, Assets];

export class GardenPageCompiler {
private readonly vault: Vault;
private readonly settings: DigitalGardenSettings;
Expand All @@ -59,12 +61,12 @@ export class GardenPageCompiler {
this.settings = settings;
this.metadataCache = metadataCache;
this.getFilesMarkedForPublishing = getFilesMarkedForPublishing;
this.frontMatterCompiler = new FrontmatterCompiler(vault, settings);
this.frontMatterCompiler = new FrontmatterCompiler(settings);
this.excalidrawCompiler = new ExcalidrawCompiler(vault);
this.rewriteRules = getRewriteRules(this.settings.pathRewriteRules);
}

async generateMarkdown(file: TFile): Promise<[string, Assets]> {
async generateMarkdown(file: TFile): Promise<TCompiledFile> {
const assets: Assets = { images: [] };

const processedFrontmatter =
Expand Down Expand Up @@ -557,7 +559,7 @@ export class GardenPageCompiler {

const publishedFilesContainsLinkedFile =
publishedFiles.find(
(f) => f.path == linkedFile.path,
(f) => f.getPath() == linkedFile.path,
);

if (publishedFilesContainsLinkedFile) {
Expand Down
101 changes: 101 additions & 0 deletions src/publisher/PublishFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { MetadataCache, TFile, Vault } from "obsidian";
import {
GardenPageCompiler,
TCompiledFile,
} from "../compiler/GardenPageCompiler";
import {
FrontmatterCompiler,
TFrontmatter,
} from "../compiler/FrontmatterCompiler";
import DigitalGardenSettings from "../models/settings";
import { isPublishFrontmatterValid } from "./Validator";

interface IPublishFileProps {
file: TFile;
vault: Vault;
compiler: GardenPageCompiler;
metadataCache: MetadataCache;
settings: DigitalGardenSettings;
}

export class PublishFile {
file: TFile;
compiler: GardenPageCompiler;
vault: Vault;
compiledFile?: TCompiledFile;
metadataCache: MetadataCache;
frontmatter: TFrontmatter;
settings: DigitalGardenSettings;

constructor({
file,
compiler,
metadataCache,
vault,
settings,
}: IPublishFileProps) {
this.compiler = compiler;
this.metadataCache = metadataCache;
this.file = file;
this.settings = settings;
this.vault = vault;
this.frontmatter = this.getFrontmatter();
}

async compile(): Promise<CompiledPublishFile> {
const compiledFile = await this.compiler.generateMarkdown(this.file);

return new CompiledPublishFile(
{
file: this.file,
compiler: this.compiler,
metadataCache: this.metadataCache,
vault: this.vault,
settings: this.settings,
},
compiledFile,
);
}

shouldPublish(): boolean {
return isPublishFrontmatterValid(this.frontmatter);
}

async getImageLinks() {
const content = await this.cachedRead();

return this.compiler.extractImageLinks(content, this.file.path);
}

async cachedRead() {
return this.vault.cachedRead(this.file);
}

getFrontmatter() {
return this.metadataCache.getCache(this.file.path)?.frontmatter ?? {};
}

getPath = () => this.file.path;
getProcessedFrontmatter() {
const frontmatterCompiler = new FrontmatterCompiler(this.settings);

const metadata =
this.metadataCache.getCache(this.file.path)?.frontmatter ?? {};

return frontmatterCompiler.getProcessedFrontMatter(this.file, metadata);
}
}

export class CompiledPublishFile extends PublishFile {
compiledFile: TCompiledFile;

constructor(props: IPublishFileProps, compiledFile: TCompiledFile) {
super(props);

this.compiledFile = compiledFile;
}

getCompiledFile() {
return this.compiledFile;
}
}
36 changes: 18 additions & 18 deletions src/publisher/PublishStatusManager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import DigitalGardenSiteManager from "./DigitalGardenSiteManager";
import { TFile } from "obsidian";
import Publisher from "./Publisher";
import { generateBlobHash } from "../utils/utils";
import { CompiledPublishFile } from "./PublishFile";

/**
* Manages the publishing status of notes and images for a digital garden.
Expand All @@ -20,7 +20,7 @@ export default class PublishStatusManager implements IPublishStatusManager {

return this.generateDeletedContentPaths(
remoteNoteHashes,
marked.notes.map((f) => f.path),
marked.notes.map((f) => f.getPath()),
);
}

Expand Down Expand Up @@ -49,42 +49,42 @@ export default class PublishStatusManager implements IPublishStatusManager {
return deletedContentPaths;
}
async getPublishStatus(): Promise<PublishStatus> {
const unpublishedNotes: Array<TFile> = [];
const publishedNotes: Array<TFile> = [];
const changedNotes: Array<TFile> = [];
const unpublishedNotes: Array<CompiledPublishFile> = [];
const publishedNotes: Array<CompiledPublishFile> = [];
const changedNotes: Array<CompiledPublishFile> = [];

const remoteNoteHashes = await this.siteManager.getNoteHashes();
const remoteImageHashes = await this.siteManager.getImageHashes();
const marked = await this.publisher.getFilesMarkedForPublishing();

for (const file of marked.notes) {
const [content, _] =
await this.publisher.compiler.generateMarkdown(file);
const compiledFile = await file.compile();
const [content, _] = await compiledFile.getCompiledFile();

const localHash = generateBlobHash(content);
const remoteHash = remoteNoteHashes[file.path];
const remoteHash = remoteNoteHashes[file.getPath()];

if (!remoteHash) {
unpublishedNotes.push(file);
unpublishedNotes.push(compiledFile);
} else if (remoteHash === localHash) {
publishedNotes.push(file);
publishedNotes.push(compiledFile);
} else {
changedNotes.push(file);
changedNotes.push(compiledFile);
}
}

const deletedNotePaths = this.generateDeletedContentPaths(
remoteNoteHashes,
marked.notes.map((f) => f.path),
marked.notes.map((f) => f.getPath()),
);

const deletedImagePaths = this.generateDeletedContentPaths(
remoteImageHashes,
marked.images,
);
unpublishedNotes.sort((a, b) => (a.path > b.path ? 1 : -1));
publishedNotes.sort((a, b) => (a.path > b.path ? 1 : -1));
changedNotes.sort((a, b) => (a.path > b.path ? 1 : -1));
unpublishedNotes.sort((a, b) => (a.getPath() > b.getPath() ? 1 : -1));
publishedNotes.sort((a, b) => (a.getPath() > b.getPath() ? 1 : -1));
changedNotes.sort((a, b) => (a.getPath() > b.getPath() ? 1 : -1));
deletedNotePaths.sort((a, b) => (a > b ? 1 : -1));

return {
Expand All @@ -98,9 +98,9 @@ export default class PublishStatusManager implements IPublishStatusManager {
}

export interface PublishStatus {
unpublishedNotes: Array<TFile>;
publishedNotes: Array<TFile>;
changedNotes: Array<TFile>;
unpublishedNotes: Array<CompiledPublishFile>;
publishedNotes: Array<CompiledPublishFile>;
changedNotes: Array<CompiledPublishFile>;
deletedNotePaths: Array<string>;
deletedImagePaths: Array<string>;
}
Expand Down
42 changes: 24 additions & 18 deletions src/publisher/Publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { isPublishFrontmatterValid } from "./Validator";
import { PathRewriteRules } from "./DigitalGardenSiteManager";
import DigitalGardenSettings from "../models/settings";
import { Assets, GardenPageCompiler } from "../compiler/GardenPageCompiler";
import { CompiledPublishFile, PublishFile } from "./PublishFile";

export interface MarkedForPublishing {
notes: TFile[];
notes: PublishFile[];
images: string[];
}
/**
Expand Down Expand Up @@ -39,23 +40,32 @@ export default class Publisher {
);
}

shouldPublish(file: TFile): boolean {
const frontMatter = this.metadataCache.getCache(file.path)?.frontmatter;

return isPublishFrontmatterValid(frontMatter);
}

async getFilesMarkedForPublishing(): Promise<MarkedForPublishing> {
const files = this.vault.getMarkdownFiles();
const notesToPublish: TFile[] = [];
const notesToPublish: PublishFile[] = [];
const imagesToPublish: Set<string> = new Set();

for (const file of files) {
try {
const frontMatter = this.metadataCache.getCache(file.path)
?.frontmatter;
if (this.shouldPublish(file)) {
const publishFile = new PublishFile({
file,
vault: this.vault,
compiler: this.compiler,
metadataCache: this.metadataCache,
settings: this.settings,
});

notesToPublish.push(publishFile);

if (frontMatter && frontMatter["dg-publish"] === true) {
notesToPublish.push(file);
const images = await publishFile.getImageLinks();

const images = await this.compiler.extractImageLinks(
await this.vault.cachedRead(file),
file.path,
);
images.forEach((i) => imagesToPublish.add(i));
}
} catch {
Expand Down Expand Up @@ -148,18 +158,14 @@ export default class Publisher {
return true;
}

async publish(file: TFile): Promise<boolean> {
if (
!isPublishFrontmatterValid(
this.metadataCache.getCache(file.path)?.frontmatter,
)
) {
async publish(file: CompiledPublishFile): Promise<boolean> {
if (file.shouldPublish()) {
return false;
}

try {
const [text, assets] = await this.compiler.generateMarkdown(file);
await this.uploadText(file.path, text);
const [text, assets] = await file.compiledFile;
await this.uploadText(file.getPath(), text);
await this.uploadAssets(assets);

return true;
Expand Down
4 changes: 2 additions & 2 deletions src/test/snapshot/generateGardenSnapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ export const generateGardenSnapshot = async (
let fileString = "---\n";

const notesSortedByCreationDate = marked.notes.sort(
(note) => note.stat.ctime,
(note) => note.file.stat.ctime,
);

for (const file of notesSortedByCreationDate) {
const [content, _] = await publisher.compiler.generateMarkdown(file);
const [content, _] = await (await file.compile()).getCompiledFile();
// TODO: add assets

fileString += `${content}\n`;
Expand Down
Loading

0 comments on commit 89ec12f

Please sign in to comment.