diff --git a/src/entities/routine/repository/group-repository.ts b/src/entities/routine/repository/group-repository.ts index c8587df..3aba4e7 100644 --- a/src/entities/routine/repository/group-repository.ts +++ b/src/entities/routine/repository/group-repository.ts @@ -8,8 +8,9 @@ import { RoutineGroupEntity } from "../domain/routine-group"; const parse = async (file: TFile): Promise => { + const fm = await fileAccessor.loadFrontMatter(file); const name = file.basename.startsWith(GROUP_PREFIX) ? file.basename.slice(GROUP_PREFIX.length) : file.basename; - const properties = RoutineGroupEntity.validateGroupProperties(fileAccessor.loadFrontMatter(file)); + const properties = RoutineGroupEntity.validateGroupProperties(fm); if(properties.isErr()) throw new Error(`[RoutineGroup '${name}' Parse Error] ${properties.error}`); return { diff --git a/src/entities/routine/repository/routine-repository.ts b/src/entities/routine/repository/routine-repository.ts index 1b781e0..9c4e3ba 100644 --- a/src/entities/routine/repository/routine-repository.ts +++ b/src/entities/routine/repository/routine-repository.ts @@ -8,8 +8,16 @@ import dedent from "dedent"; import { Routine } from "../domain/routine-type"; +/** + * File을 받아서 Routine 객체로 변환한다. + * + * 루틴을 저장소에서 읽어와 변환하는 로직은 모두 해당 함수를 사용한다. + * @param file + * @returns + */ const parse = async (file: TFile): Promise => { - const result = RoutineEntity.validateRoutineProperties(fileAccessor.loadFrontMatter(file)); + const fm = await fileAccessor.loadFrontMatter(file); + const result = RoutineEntity.validateRoutineProperties(fm); if(result.isErr()){ new Notice(`Routine '${file.basename}' frontmatter error: ${result.error}`); throw new Error(`[Routine '${file.basename}' Parse Error] ${result.error}`); @@ -32,7 +40,7 @@ export interface RoutineQuery { load(routineName: string): Promise; } export interface RoutineRepository extends RoutineQuery { - persist(entity: Routine): Promise; + create(entity: Routine): Promise; delete(routineName: string): Promise; changeName(originalName: string, newName: string): Promise; update(routine: Routine): Promise; @@ -62,7 +70,7 @@ export const routineRepository: RoutineRepository = { return await parse(file); }, - async persist(routine: Routine){ + async create(routine: Routine){ const path = ROUTINE_PATH(routine.name); const file = fileAccessor.loadFile(path); if(!file){ diff --git a/src/shared/components/modal/styled.tsx b/src/shared/components/modal/styled.tsx index 69ffb0a..8727fe6 100644 --- a/src/shared/components/modal/styled.tsx +++ b/src/shared/components/modal/styled.tsx @@ -8,6 +8,7 @@ import { useCallback, useEffect, useMemo } from 'react'; import { ModalApi } from './create-modal'; import { TextEditComponent } from "@shared/components/TextEditComponent" import { Button } from "@shared/components/Button" +import { plugin } from "@shared/utils/plugin-service-locator"; type ModalProps = { @@ -173,14 +174,22 @@ export const SaveBtn = ({ name, }: SaveBtnProps) => { - const handleEnterKeyDown = useCallback((e: KeyboardEvent) => { - if(e.key === "Enter" && !disabled) onSaveBtnClick?.(); - }, [disabled, onSaveBtnClick]); - + /** + * Enter Key로 Save Button을 트리거하는 이벤트를 등록 + */ useEffect(() => { + + const handleEnterKeyDown = ({ key, isComposing}: KeyboardEvent) => { + if(isComposing) return; + + if(key === "Enter" && !disabled){ + onSaveBtnClick?.(); + } + } + document.addEventListener('keydown', handleEnterKeyDown); return () => document.removeEventListener('keydown', handleEnterKeyDown); - }, [handleEnterKeyDown]); + }, [disabled, onSaveBtnClick]); return (
any) => Promise; - loadFrontMatter: (file: TFile) => object | null; + loadFrontMatter: (file: TFile) => Promise; } export const fileAccessor: FileAccessor = { @@ -116,8 +115,30 @@ export const fileAccessor: FileAccessor = { }); }, - loadFrontMatter: (file: TFile) => { + /** + * 1차 시도는 metadataCache에서 frontmatter를 가져오고, + * 실패하면 파일을 직접 읽어서 frontmatter를 파싱한다. + * 그래도 안되면 에러를 발생시킨다. + * @param file + * @returns + */ + loadFrontMatter: async (file: TFile): Promise => { const metadataCache = plugin().app.metadataCache.getFileCache(file); - return metadataCache?.frontmatter ?? null; + if(metadataCache && metadataCache.frontmatter){ + return metadataCache.frontmatter; + } else { + const content = await fileAccessor.readFileAsReadonly(file); + return parseFrontmatterFromContent(content); + } } +} + + +export const parseFrontmatterFromContent = (fileContent: string): object => { + const fmInfo = getFrontMatterInfo(fileContent); + if(!fmInfo.exists){ + return {}; + } + const yaml = fmInfo.frontmatter.replace('---', '').trim() + return parseYaml(yaml); } \ No newline at end of file diff --git a/src/widgets/routine/ui/start-routine.tsx b/src/widgets/routine/ui/start-routine.tsx index cce9bb8..5145807 100644 --- a/src/widgets/routine/ui/start-routine.tsx +++ b/src/widgets/routine/ui/start-routine.tsx @@ -21,7 +21,7 @@ export const useStartRoutineModal = createModal(({ modal }: StartRoutineModalPro const [routine, dispatch] = useReducer(routineReducer, createNewRoutine()); const onSaveBtnClick = useCallback(async () => { - await routineRepository.persist(routine); + await routineRepository.create(routine); mergeNotes(); modal.close(); new Notice(`Routine '${routine.name}' started! 🎉`);