Something went wrong. Try again.
Fork of github.com/ccmdi/propsec
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147import { App, TFile } from "obsidian";import { FieldType, SchemaField } from "../types";import "../obsidian-ex.d.ts";import { EXCLUDE_FIELDS, ISO_DATE_REGEX } from "../utils/constant";
/** * Map Obsidian's metadata type names to our FieldType */function mapObsidianType(obsidianType: string | null): FieldType | null { if (!obsidianType) return null;
switch (obsidianType) { case "text": return "string"; case "number": return "number"; case "checkbox": return "boolean"; case "date": case "datetime": return "date"; case "tags": case "aliases": case "multitext": return "array"; default: return null; }}
/** * Infer the FieldType from a frontmatter value */export function inferFieldType(value: unknown): FieldType { if (value === null || value === undefined) { return "unknown"; }
if (typeof value === "string") { if (ISO_DATE_REGEX.test(value)) { return "date"; } return "string"; }
if (typeof value === "number") { return "number"; }
if (typeof value === "boolean") { return "boolean"; }
if (Array.isArray(value)) { return "array"; }
if (typeof value === "object") { return "object"; }
return "unknown";}
/** * Infer FieldType with Obsidian metadata fallback for empty values */export function inferFieldTypeWithObsidian(app: App, key: string, value: unknown): FieldType { // First try to infer from actual value const inferredType = inferFieldType(value);
if (inferredType !== "unknown") { return inferredType; }
// Fall back to Obsidian's registered type for this property const obsidianType = app.metadataTypeManager?.properties?.[key]?.widget; const mappedType = mapObsidianType(obsidianType ?? null);
return mappedType ?? "unknown";}
/** * Extract schema fields from a template file's frontmatter * All fields default to required=true * Uses Obsidian's metadata type system as fallback for empty values */export async function extractSchemaFromTemplate( app: App, templateFile: TFile): Promise<SchemaField[]> { const frontmatter = app.metadataCache.getFileCache(templateFile)?.frontmatter;
if (!frontmatter) { return []; }
const fields: SchemaField[] = [];
for (const [key, value] of Object.entries(frontmatter)) { if (EXCLUDE_FIELDS.includes(key)) continue;
fields.push({ name: key, type: inferFieldTypeWithObsidian(app, key, value), required: true, // Default to required }); }
return fields;}
/** * Get a human-readable type name for display * For custom types, returns the type name as-is */export function getTypeDisplayName(type: FieldType): string { switch (type) { case "string": return "String"; case "number": return "Number"; case "boolean": return "Boolean"; case "date": return "Date"; case "array": return "Array"; case "object": return "Object"; case "null": return "Null"; case "unknown": return "Unknown"; default: // Custom type - return the name as-is return type; }}
/** * Get all available field types for dropdown selection */export function getAllFieldTypes(): FieldType[] { return ["string", "number", "boolean", "date", "array", "object", "null", "unknown"];}