94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import { promises, type Stats } from "node:fs";
|
|
import path, { extname } from "node:path";
|
|
import type { DocumentBody } from "dbtype";
|
|
import { oshash } from "src/util/oshash.ts";
|
|
/**
|
|
* content file or directory referrer
|
|
*/
|
|
export interface ContentFile {
|
|
getHash(): Promise<string>;
|
|
createDocumentBody(): Promise<DocumentBody>;
|
|
readonly path: string;
|
|
readonly type: string;
|
|
}
|
|
|
|
export type ContentConstructOption = {
|
|
hash: string;
|
|
};
|
|
type ContentFileConstructor = (new (
|
|
path: string,
|
|
option?: ContentConstructOption,
|
|
) => ContentFile) & {
|
|
content_type: string;
|
|
};
|
|
export const createDefaultClass = (type: string): ContentFileConstructor => {
|
|
const cons = class implements ContentFile {
|
|
readonly path: string;
|
|
// type = type;
|
|
static content_type = type;
|
|
protected hash: string | undefined;
|
|
protected stat: Stats | undefined;
|
|
|
|
protected getStat(){
|
|
return this.stat;
|
|
}
|
|
|
|
constructor(path: string, option?: ContentConstructOption) {
|
|
this.path = path;
|
|
this.hash = option?.hash;
|
|
this.stat = undefined;
|
|
}
|
|
async createDocumentBody(): Promise<DocumentBody> {
|
|
console.log(`createDocumentBody: ${this.path}`);
|
|
const { base, dir, name } = path.parse(this.path);
|
|
|
|
const ret = {
|
|
title: name,
|
|
basepath: dir,
|
|
additional: {},
|
|
content_type: cons.content_type,
|
|
filename: base,
|
|
tags: [],
|
|
content_hash: await this.getHash(),
|
|
modified_at: await this.getMtime(),
|
|
pagenum: 0,
|
|
} as DocumentBody;
|
|
return ret;
|
|
}
|
|
get type(): string {
|
|
return cons.content_type;
|
|
}
|
|
async getHash(): Promise<string> {
|
|
if (this.hash !== undefined) return this.hash;
|
|
const hash = await oshash(this.path);
|
|
this.hash = hash.toString();
|
|
return this.hash;
|
|
}
|
|
async getMtime(): Promise<number> {
|
|
const oldStat = this.getStat();
|
|
if (oldStat !== undefined) return oldStat.mtimeMs;
|
|
const stat = await promises.stat(this.path);
|
|
this.stat = stat;
|
|
return stat.mtimeMs;
|
|
}
|
|
};
|
|
return cons;
|
|
};
|
|
const ContstructorTable: { [k: string]: ContentFileConstructor } = {};
|
|
export function registerContentReferrer(s: ContentFileConstructor) {
|
|
console.log(`registered content type: ${s.content_type}`);
|
|
ContstructorTable[s.content_type] = s;
|
|
}
|
|
export function createContentFile(type: string, path: string, option?: ContentConstructOption) {
|
|
const constructorMethod = ContstructorTable[type];
|
|
if (constructorMethod === undefined) {
|
|
console.log(`${type} are not in ${JSON.stringify(ContstructorTable)}`);
|
|
throw new Error("construction method of the content type is undefined");
|
|
}
|
|
return new constructorMethod(path, option);
|
|
}
|
|
export function getContentFileConstructor(type: string): ContentFileConstructor | undefined {
|
|
const ret = ContstructorTable[type];
|
|
return ret;
|
|
}
|