diff --git a/package.json b/package.json index 1b1592e9..1e76debb 100644 --- a/package.json +++ b/package.json @@ -1206,6 +1206,11 @@ "title": "Authenticate", "category": "Front matter" }, + { + "command": "frontMatter.generate.contenttype", + "title": "Generate content type from current file", + "category": "Front matter" + }, { "command": "frontMatter.markup.blockquote", "title": "Blockquote", @@ -1681,6 +1686,10 @@ { "command": "frontMatter.generateSlug", "when": "frontMatter:file:isValid == true" + }, + { + "command": "frontMatter.generate.contenttype", + "when": "frontMatter:file:isValid == true" } ], "view/title": [ diff --git a/src/commands/Article.ts b/src/commands/Article.ts index 4015443b..90f41f24 100644 --- a/src/commands/Article.ts +++ b/src/commands/Article.ts @@ -30,7 +30,7 @@ export class Article { return; } - const article = Article.getCurrent(); + const article = ArticleHelper.getCurrent(); if (!article) { return; @@ -375,23 +375,6 @@ export class Article { } as DashboardData); } - /** - * Get the current article - */ - private static getCurrent(): ParsedFrontMatter | undefined { - const editor = vscode.window.activeTextEditor; - if (!editor) { - return; - } - - const article = ArticleHelper.getFrontMatter(editor); - if (!article) { - return; - } - - return article; - } - /** * Update the article date and return it * @param article diff --git a/src/constants/Extension.ts b/src/constants/Extension.ts index c3331a7f..a55eb954 100644 --- a/src/constants/Extension.ts +++ b/src/constants/Extension.ts @@ -53,4 +53,7 @@ export const COMMAND_NAME = { orderedlist: getCommandName("markup.orderedlist"), taskList: getCommandName("markup.tasklist"), options: getCommandName("markup.options"), + + // Content types + generateContentType: getCommandName("generate.contenttype"), }; \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 25cc9ccb..b761dfba 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -154,6 +154,10 @@ export async function activate(context: vscode.ExtensionContext) { const createByTemplate = vscode.commands.registerCommand(COMMAND_NAME.createByTemplate, Folders.create); const createContent = vscode.commands.registerCommand(COMMAND_NAME.createContent, Content.create); + subscriptions.push( + vscode.commands.registerCommand(COMMAND_NAME.generateContentType, ContentType.generate) + ); + // Initialize command Template.init(); const projectInit = vscode.commands.registerCommand(COMMAND_NAME.init, async (cb: Function) => { diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index 1418bf48..b998df62 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -44,6 +44,23 @@ export class ArticleHelper { return ArticleHelper.parseFile(fileContents, document.fileName); } + /** + * Get the current article + */ + public static getCurrent(): ParsedFrontMatter | undefined { + const editor = vscode.window.activeTextEditor; + if (!editor) { + return; + } + + const article = ArticleHelper.getFrontMatter(editor); + if (!article) { + return; + } + + return article; + } + /** * Retrieve the file's front matter by its path * @param filePath diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index db032352..e089a240 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -2,7 +2,7 @@ import { PagesListener } from './../listeners/dashboard'; import { ArticleHelper, Settings } from "."; import { SETTING_CONTENT_DRAFT_FIELD, SETTING_DATE_FORMAT, SETTING_TAXONOMY_CONTENT_TYPES, TelemetryEvent } from "../constants"; import { ContentType as IContentType, DraftField, Field } from '../models'; -import { Uri, commands } from 'vscode'; +import { Uri, commands, window } from 'vscode'; import { Folders } from "../commands/Folders"; import { Questions } from "./Questions"; import { writeFileSync } from "fs"; @@ -92,6 +92,128 @@ export class ContentType { return Settings.get(SETTING_TAXONOMY_CONTENT_TYPES); } + /** + * Generate a content type + */ + public static async generate() { + const content = ArticleHelper.getCurrent(); + + if (!content || !content.data) { + Notifications.warning(`No front matter data found to generate a content type.`); + return; + } + + const answer = await window.showInputBox({ + ignoreFocusOut: true, + placeHolder: "Enter the name of the content type to generate", + prompt: "Enter the name of the content type to generate", + title: "Generate Content Type", + validateInput: (value: string) => { + if (!value) { + return "Please enter a name for the content type"; + } + + const contentTypes = ContentType.getAll(); + if (contentTypes && contentTypes.find(ct => ct.name.toLowerCase() === value.toLowerCase())) { + return "A content type with this name already exists"; + } + + return null; + } + }); + + if (!answer) { + Notifications.warning(`You didn't specify a name for the content type.`); + return; + } + + const fields = ContentType.generateFields(content.data); + + const newContentType: IContentType = { + name: answer, + fields + }; + + const contentTypes = ContentType.getAll() || []; + contentTypes.push(newContentType); + + Settings.update(SETTING_TAXONOMY_CONTENT_TYPES, contentTypes, true); + Notifications.info(`Content type ${answer} has been generated.`); + } + + /** + * Generate the fields from the data + * @param data + * @param fields + * @returns + */ + private static generateFields(data: any, fields: any[] = []) { + for (const field in data) { + const fieldData = data[field]; + + if (fieldData && fieldData instanceof Array && fieldData.length > 0 && typeof fieldData[0] === "string") { + if (field.toLowerCase() === "tag" || field.toLowerCase() === "tags") { + fields.push({ + title: field, + name: field, + type: "tags", + } as Field); + } else if (field.toLowerCase() === "category" || field.toLowerCase() === "categories") { + fields.push({ + title: field, + name: field, + type: "categories", + } as Field); + } else { + fields.push({ + title: field, + name: field, + type: "choice", + choices: fieldData + } as Field); + } + } else if (fieldData && fieldData instanceof Array && fieldData.length > 0 && typeof fieldData[0] === "object") { + const newFields = ContentType.generateFields(fieldData); + fields.push({ + title: field, + name: field, + type: "block", + fields: newFields + } as Field); + } else if (fieldData && fieldData instanceof Object) { + const newFields = ContentType.generateFields(fieldData); + fields.push({ + title: field, + name: field, + type: "fields", + fields: newFields + } as Field); + } else { + if (!isNaN(new Date(fieldData).getDate())) { + fields.push({ + title: field, + name: field, + type: "datetime" + } as Field); + } else if (field.toLowerCase() === "draft") { + fields.push({ + title: field, + name: field, + type: "draft" + } as Field); + } else { + fields.push({ + title: field, + name: field, + type: typeof fieldData + } as Field); + } + } + } + + return fields; + } + /** * Create a new file with the specified content type * @param contentType