From 14ddd8b53ce1f80e4ab6a02cca84dc3dd80ddea0 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Tue, 31 Oct 2023 11:44:02 +0100 Subject: [PATCH] Added the path to the parsed article --- src/commands/Article.ts | 6 +- src/commands/Preview.ts | 4 +- src/commands/Template.ts | 8 +- .../components/Header/Searchbox.tsx | 2 +- src/helpers/ArticleHelper.ts | 77 +++++++++++++++---- src/helpers/ContentType.ts | 18 ++--- src/helpers/CustomScript.ts | 4 +- src/helpers/MediaHelpers.ts | 2 +- src/helpers/TaxonomyHelper.ts | 4 +- src/listeners/dashboard/PagesListener.ts | 7 +- src/listeners/panel/DataListener.ts | 4 +- src/listeners/panel/FieldsListener.ts | 4 +- src/parsers/FrontMatterParser.ts | 1 + src/services/PagesParser.ts | 4 +- 14 files changed, 98 insertions(+), 47 deletions(-) diff --git a/src/commands/Article.ts b/src/commands/Article.ts index 567f1f83..44f8d004 100644 --- a/src/commands/Article.ts +++ b/src/commands/Article.ts @@ -127,7 +127,7 @@ export class Article { * @param article */ public static updateDate(article: ParsedFrontMatter) { - article.data = ArticleHelper.updateDates(article.data); + article.data = ArticleHelper.updateDates(article); return article; } @@ -227,7 +227,7 @@ export class Article { } let filePrefix = Settings.get(SETTING_TEMPLATES_PREFIX); - const contentType = ArticleHelper.getContentType(article.data); + const contentType = ArticleHelper.getContentType(article); filePrefix = ArticleHelper.getFilePrefix(filePrefix, editor.document.uri.fsPath, contentType); const titleField = 'title'; @@ -393,7 +393,7 @@ export class Article { const article = ArticleHelper.getFrontMatter(editor); const contentType = - article && article.data ? ArticleHelper.getContentType(article.data) : DEFAULT_CONTENT_TYPE; + article && article.data ? ArticleHelper.getContentType(article) : DEFAULT_CONTENT_TYPE; const position = editor.selection.active; const selectionText = editor.document.getText(editor.selection); diff --git a/src/commands/Preview.ts b/src/commands/Preview.ts index 17a512d8..5b0c3834 100644 --- a/src/commands/Preview.ts +++ b/src/commands/Preview.ts @@ -213,7 +213,7 @@ export class Preview { * @returns */ public static async getContentSlug( - article: ParsedFrontMatter | null, + article: ParsedFrontMatter | null | undefined, filePath?: string ): Promise { if (!filePath) { @@ -230,7 +230,7 @@ export class Preview { let contentType: ContentType | undefined = undefined; if (article?.data) { - contentType = ArticleHelper.getContentType(article.data); + contentType = ArticleHelper.getContentType(article); } // Check if there is a pathname defined on content folder level diff --git a/src/commands/Template.ts b/src/commands/Template.ts index cb1111f7..a39e56c7 100644 --- a/src/commands/Template.ts +++ b/src/commands/Template.ts @@ -165,11 +165,15 @@ export class Template { newFilePath ); - frontMatter = Article.updateDate(frontMatter); + const article = Article.updateDate(frontMatter); + + if (!article) { + return; + } await writeFileAsync( newFilePath, - ArticleHelper.stringifyFrontMatter(frontMatter.content, frontMatter.data), + ArticleHelper.stringifyFrontMatter(article.content, article.data), { encoding: 'utf8' } ); diff --git a/src/dashboardWebView/components/Header/Searchbox.tsx b/src/dashboardWebView/components/Header/Searchbox.tsx index 61b8efbe..d1490e9c 100644 --- a/src/dashboardWebView/components/Header/Searchbox.tsx +++ b/src/dashboardWebView/components/Header/Searchbox.tsx @@ -56,7 +56,7 @@ export const Searchbox: React.FunctionComponent = ({ name="search" className={`block w-full py-2 pl-10 pr-3 sm:text-sm appearance-none disabled:opacity-50 rounded ${getColors( 'bg-white dark:bg-vulcan-300 border border-gray-300 dark:border-vulcan-100 text-vulcan-500 dark:text-whisper-500 placeholder-gray-400 dark:placeholder-whisper-800 focus:outline-none', - 'bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] border-[var(--vscode-input-border)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent' + 'bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] border-[var(--vscode-input-border, --vscode-editorWidget-border)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent' ) }`} placeholder={placeholder || l10n.t(LocalizationKey.commonSearch)} diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index bd7b5075..e4764468 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -60,9 +60,19 @@ export class ArticleHelper { * * @param document The document to parse. */ - public static getFrontMatterFromDocument(document: vscode.TextDocument) { + public static getFrontMatterFromDocument( + document: vscode.TextDocument + ): ParsedFrontMatter | undefined { const fileContents = document.getText(); - return ArticleHelper.parseFile(fileContents, document.fileName); + const article = ArticleHelper.parseFile(fileContents, document.fileName); + if (!article) { + return undefined; + } + + return { + ...article, + path: document.uri.fsPath + }; } /** @@ -79,7 +89,10 @@ export class ArticleHelper { return; } - return article; + return { + ...article, + path: editor.document.uri.fsPath + }; } /** @@ -88,7 +101,15 @@ export class ArticleHelper { */ public static async getFrontMatterByPath(filePath: string) { const file = await readFileAsync(filePath, { encoding: 'utf-8' }); - return ArticleHelper.parseFile(file, filePath); + const article = ArticleHelper.parseFile(file, filePath); + if (!article) { + return undefined; + } + + return { + ...article, + path: filePath + }; } /** @@ -240,7 +261,7 @@ export class ArticleHelper { /** * Get date from front matter */ - public static getDate(article: ParsedFrontMatter | null) { + public static getDate(article: ParsedFrontMatter | null | undefined) { if (!article || !article.data) { return; } @@ -270,7 +291,7 @@ export class ArticleHelper { return; } - const articleCt = ArticleHelper.getContentType(article.data); + const articleCt = ArticleHelper.getContentType(article); const pubDateField = articleCt.fields.find((f) => f.isPublishDate); return ( @@ -290,7 +311,7 @@ export class ArticleHelper { return; } - const articleCt = ArticleHelper.getContentType(article.data); + const articleCt = ArticleHelper.getContentType(article); const modDateField = articleCt.fields.find((f) => f.isModifiedDate); return ( @@ -312,16 +333,38 @@ export class ArticleHelper { * Retrieve the content type of the current file * @param updatedMetadata */ - public static getContentType(metadata: { [field: string]: string }): IContentType { + public static getContentType(article: ParsedFrontMatter): IContentType { const contentTypes = ArticleHelper.getContentTypes(); - if (!contentTypes || !metadata) { + if (!contentTypes || !article.data) { return DEFAULT_CONTENT_TYPE; } - let contentType = contentTypes.find( - (ct) => ct.name === (metadata.type || DEFAULT_CONTENT_TYPE_NAME) - ); + let contentType: IContentType | undefined = undefined; + + // Get content type by type name in the front matter + if (article.data.type) { + contentType = contentTypes.find((ct) => ct.name === article.data.type); + } else if (!contentType && article.path) { + // Get the content type by the folder name + let folders = Folders.get(); + let parsedPath = parseWinPath(article.path); + let pageFolderMatches = folders.filter( + (folder) => parsedPath && folder.path && parsedPath.includes(folder.path) + ); + + // Sort by longest path + pageFolderMatches = pageFolderMatches.sort((a, b) => b.path.length - a.path.length); + if ( + pageFolderMatches.length > 0 && + pageFolderMatches[0].contentTypes && + pageFolderMatches[0].contentTypes.length === 1 + ) { + const contentTypeName = pageFolderMatches[0].contentTypes[0]; + contentType = contentTypes.find((ct) => ct.name === contentTypeName); + } + } + if (!contentType) { contentType = contentTypes.find((ct) => ct.name === DEFAULT_CONTENT_TYPE_NAME); } @@ -343,17 +386,17 @@ export class ArticleHelper { * Update all dates in the metadata * @param metadata */ - public static updateDates(metadata: { [field: string]: string }) { - const contentType = ArticleHelper.getContentType(metadata); + public static updateDates(article: ParsedFrontMatter) { + const contentType = ArticleHelper.getContentType(article); const dateFields = contentType.fields.filter((field) => field.type === 'datetime'); for (const dateField of dateFields) { - if (typeof metadata[dateField.name] !== 'undefined') { - metadata[dateField.name] = Article.formatDate(new Date(), dateField.dateFormat); + if (typeof article?.data[dateField.name] !== 'undefined') { + article.data[dateField.name] = Article.formatDate(new Date(), dateField.dateFormat); } } - return metadata; + return article.data; } /** diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index 504f2cef..7f08999a 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -49,18 +49,18 @@ export class ContentType { * @param data * @returns */ - public static getDraftStatus(data: { [field: string]: any }) { - const contentType = ArticleHelper.getContentType(data); + public static getDraftStatus(article: ParsedFrontMatter) { + const contentType = ArticleHelper.getContentType(article); const draftSetting = ContentType.getDraftField(); const draftField = contentType.fields.find((f) => f.type === 'draft'); let fieldValue = null; - if (draftField) { - fieldValue = data[draftField.name]; - } else if (draftSetting && data && data[draftSetting.name]) { - fieldValue = data[draftSetting.name]; + if (draftField && article?.data) { + fieldValue = article?.data[draftField.name]; + } else if (draftSetting && article?.data && article?.data[draftSetting.name]) { + fieldValue = article?.data[draftSetting.name]; } if (draftSetting && fieldValue !== null) { @@ -282,7 +282,7 @@ export class ContentType { return; } - const contentType = ArticleHelper.getContentType(content?.data); + const contentType = ArticleHelper.getContentType(content); const updatedFields = ContentType.generateFields(content.data, contentType.fields); const contentTypes = ContentType.getAll() || []; @@ -492,7 +492,7 @@ export class ContentType { * Find the required fields */ public static findEmptyRequiredFields(article: ParsedFrontMatter): Field[][] | undefined { - const contentType = ArticleHelper.getContentType(article.data); + const contentType = ArticleHelper.getContentType(article); if (!contentType) { return; } @@ -793,7 +793,7 @@ export class ContentType { } let templatePath = contentType.template; - let templateData: ParsedFrontMatter | null = null; + let templateData: ParsedFrontMatter | null | undefined = null; if (templatePath) { templatePath = Folders.getAbsFilePath(templatePath); templateData = await ArticleHelper.getFrontMatterByPath(templatePath); diff --git a/src/helpers/CustomScript.ts b/src/helpers/CustomScript.ts index 0cc4529b..c18566a1 100644 --- a/src/helpers/CustomScript.ts +++ b/src/helpers/CustomScript.ts @@ -71,7 +71,7 @@ export class CustomScript { path: string | null = null ): Promise { let articlePath: string | null = path; - let article: ParsedFrontMatter | null = null; + let article: ParsedFrontMatter | null | undefined = null; if (!path) { const editor = window.activeTextEditor; @@ -214,7 +214,7 @@ export class CustomScript { */ private static async runScript( wsPath: string, - article: ParsedFrontMatter | null, + article: ParsedFrontMatter | null | undefined, contentPath: string, script: ICustomScript ): Promise { diff --git a/src/helpers/MediaHelpers.ts b/src/helpers/MediaHelpers.ts index 427f3752..744c10b1 100644 --- a/src/helpers/MediaHelpers.ts +++ b/src/helpers/MediaHelpers.ts @@ -380,7 +380,7 @@ export class MediaHelpers { const article = editor ? ArticleHelper.getFrontMatter(editor) : null; const articleCt = - article && article.data ? ArticleHelper.getContentType(article.data) : DEFAULT_CONTENT_TYPE; + article && article.data ? ArticleHelper.getContentType(article) : DEFAULT_CONTENT_TYPE; const absImgPath = join(parseWinPath(wsFolder?.fsPath || ''), relPath); const fileDir = parseWinPath(dirname(filePath)); diff --git a/src/helpers/TaxonomyHelper.ts b/src/helpers/TaxonomyHelper.ts index 1c95d86a..69c2a918 100644 --- a/src/helpers/TaxonomyHelper.ts +++ b/src/helpers/TaxonomyHelper.ts @@ -305,7 +305,7 @@ export class TaxonomyHelper { if (mdFile) { try { const article = FrontMatterParser.fromFile(mdFile); - const contentType = ArticleHelper.getContentType(article.data); + const contentType = ArticleHelper.getContentType(article); let fieldNames: string[] = this.getFieldsHierarchy(taxonomyType, contentType); @@ -415,7 +415,7 @@ export class TaxonomyHelper { if (mdFile) { try { const article = FrontMatterParser.fromFile(mdFile); - const contentType = ArticleHelper.getContentType(article.data); + const contentType = ArticleHelper.getContentType(article); let oldFieldNames: string[] = this.getFieldsHierarchy(oldType, contentType); let newFieldNames: string[] = this.getFieldsHierarchy(newType, contentType, true); diff --git a/src/listeners/dashboard/PagesListener.ts b/src/listeners/dashboard/PagesListener.ts index c1c9a899..a2ba979b 100644 --- a/src/listeners/dashboard/PagesListener.ts +++ b/src/listeners/dashboard/PagesListener.ts @@ -119,7 +119,7 @@ export class PagesListener extends BaseListener { if (!article) { return; } - const contentType = ArticleHelper.getContentType(article.data); + const contentType = ArticleHelper.getContentType(article); Logger.info(`Deleting file: ${path}`); @@ -240,7 +240,10 @@ export class PagesListener extends BaseListener { * @param pages */ private static async createSearchIndex(pages: Page[]) { - const pagesIndex = Fuse.createIndex(['title', 'slug', 'description', 'fmBody', 'type'], pages); + const pagesIndex = Fuse.createIndex( + ['title', 'slug', 'description', 'fmBody', 'type', 'fmContentType'], + pages + ); await Extension.getInstance().setState( ExtensionState.Dashboard.Pages.Index, pagesIndex.toJSON(), diff --git a/src/listeners/panel/DataListener.ts b/src/listeners/panel/DataListener.ts index 71aa4422..9cde6738 100644 --- a/src/listeners/panel/DataListener.ts +++ b/src/listeners/panel/DataListener.ts @@ -254,7 +254,7 @@ export class DataListener extends BaseListener { return; } - const contentType = ArticleHelper.getContentType(article.data); + const contentType = ArticleHelper.getContentType(article); if (!value && field !== titleField && contentType.clearEmpty) { value = undefined; @@ -374,7 +374,7 @@ export class DataListener extends BaseListener { ) { let parentObj = data; let allParents = Object.assign([], parents); - const contentType = ArticleHelper.getContentType(article.data); + const contentType = ArticleHelper.getContentType(article); let selectedIndexes: number[] = []; if (blockData?.selectedIndex) { if (typeof blockData.selectedIndex === 'string') { diff --git a/src/listeners/panel/FieldsListener.ts b/src/listeners/panel/FieldsListener.ts index 5c4191d6..fcc8c8bc 100644 --- a/src/listeners/panel/FieldsListener.ts +++ b/src/listeners/panel/FieldsListener.ts @@ -36,7 +36,7 @@ export class FieldsListener extends BaseListener { PagesListener.getPagesData(false, async (pages) => { const fuseOptions: Fuse.IFuseOptions = { - keys: [{ name: 'type', weight: 1 }] + keys: [{ name: 'fmContentType', weight: 1 }] }; const pagesIndex = await Extension.getInstance().getState>( @@ -48,7 +48,7 @@ export class FieldsListener extends BaseListener { const results = fuse.search({ $and: [ { - type + fmContentType: type } ] }); diff --git a/src/parsers/FrontMatterParser.ts b/src/parsers/FrontMatterParser.ts index 8a5f9d78..2176bd7a 100644 --- a/src/parsers/FrontMatterParser.ts +++ b/src/parsers/FrontMatterParser.ts @@ -11,6 +11,7 @@ export interface Format { export interface ParsedFrontMatter { data: { [key: string]: any }; content: string; + path?: string; } export class FrontMatterParser { diff --git a/src/services/PagesParser.ts b/src/services/PagesParser.ts index 2d421c54..d3168a02 100644 --- a/src/services/PagesParser.ts +++ b/src/services/PagesParser.ts @@ -171,7 +171,7 @@ export class PagesParser { const dateField = ArticleHelper.getPublishDateField(article) || DefaultFields.PublishingDate; - const contentType = ArticleHelper.getContentType(article.data); + const contentType = ArticleHelper.getContentType(article); let dateFormat = Settings.get(SETTING_DATE_FORMAT) as string; const ctDateField = ContentType.findFieldByName(contentType.fields, dateField); if (ctDateField && ctDateField.dateFormat) { @@ -211,7 +211,7 @@ export class PagesParser { fmRelFileWsPath: FilesHelper.absToRelPath(filePath), fmRelFilePath: parseWinPath(filePath).replace(wsFolder?.fsPath || '', ''), fmFileName: fileName, - fmDraft: ContentType.getDraftStatus(article?.data), + fmDraft: ContentType.getDraftStatus(article), fmModified: modifiedFieldValue ? modifiedFieldValue : fileMtime, fmPublished: dateFieldValue ? dateFieldValue.getTime() : null, fmYear: dateFieldValue ? dateFieldValue.getFullYear() : null,