@plttn/mkd 0.1.6 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -101,10 +101,9 @@ function makeNewCommand({ config, pfs }) {
101
101
  }
102
102
  async function generateFrontmatter(title, config) {
103
103
  const description = await makeDescription(title);
104
- const now = /* @__PURE__ */ new Date();
105
104
  const data = {
106
105
  [config.titleKey]: title,
107
- [config.publishedAtKey]: now,
106
+ [config.publishedAtKey]: /* @__PURE__ */ new Date("3000-01-01T00:00:00Z"),
108
107
  [config.authorKey]: config.author,
109
108
  [config.draftKey]: true,
110
109
  [config.descriptionKey]: description,
@@ -198,8 +197,8 @@ function makePublishCommand({ config, pfs }) {
198
197
  async function getPostsToPublish(drafts, config) {
199
198
  const options = postsToOptions(drafts, config);
200
199
  (0, import_prompts2.intro)("Publishing posts");
201
- const selected = await (0, import_prompts2.autocompleteMultiselect)({
202
- message: "Select posts to publish",
200
+ const selected = await (0, import_prompts2.autocomplete)({
201
+ message: "Select post to publish",
203
202
  options
204
203
  });
205
204
  if ((0, import_prompts2.isCancel)(selected)) {
@@ -207,12 +206,17 @@ async function getPostsToPublish(drafts, config) {
207
206
  return [];
208
207
  }
209
208
  (0, import_prompts2.outro)("Posts undrafted...");
210
- return selectedValuesToPosts(selected, drafts);
209
+ return selectedValuesToPosts(
210
+ Array.isArray(selected) ? selected : [selected],
211
+ drafts
212
+ );
211
213
  }
212
214
  async function updateDraftFrontMatter(draft, deps) {
215
+ const now = /* @__PURE__ */ new Date();
213
216
  const parsed = (0, import_gray_matter3.default)(draft.content);
214
217
  const fm = parsed.data;
215
218
  fm[deps.config.draftKey] = false;
219
+ fm[deps.config.publishedAtKey] = now;
216
220
  const updatedContent = import_gray_matter3.default.stringify(parsed.content, fm);
217
221
  await deps.pfs.write(`${deps.config.blogDir}/${draft.file}`, updatedContent);
218
222
  return { ...draft, content: updatedContent };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/lib/deps.ts","../src/commands/new.ts","../src/commands/publish.ts","../src/lib/commands.ts","../src/commands/update.ts","../src/commands/unpublish.ts","../src/commands/init.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { run, subcommands } from \"cmd-ts\";\nimport { PoweredFileSystem } from \"pwd-fs\";\nimport { loadConfig } from \"./lib/deps\";\nimport { makeNewCommand } from \"./commands/new\";\nimport { makePublishCommand } from \"./commands/publish\";\nimport { makeUpdateCommand } from \"./commands/update\";\nimport { makeUnPublishCommand } from \"./commands/unpublish\";\nimport { makeInitCommand } from \"./commands/init\";\n\nasync function main() {\n const pfs = new PoweredFileSystem();\n const config = await loadConfig(pfs);\n const deps = { config, pfs };\n\n const app = subcommands({\n name: \"mkd\",\n cmds: {\n new: makeNewCommand(deps),\n publish: makePublishCommand(deps),\n update: makeUpdateCommand(deps),\n unpublish: makeUnPublishCommand(deps),\n init: makeInitCommand(deps),\n },\n });\n\n await run(app, process.argv.slice(2));\n}\n\nmain().catch((error) => {\n console.error(error);\n process.exit(1);\n});\n","import type { PoweredFileSystem } from \"pwd-fs\";\n\nexport type Config = {\n blogDir: string;\n titleKey: string;\n author: string;\n publishedAtKey: string;\n modifiedAtKey: string;\n authorKey: string;\n draftKey: string;\n descriptionKey: string;\n tagsKey: string;\n};\n\nexport type Deps = {\n config: Config;\n pfs: PoweredFileSystem;\n};\n\nconst defaultConfig: Config = {\n blogDir: \"./src/blog\",\n titleKey: \"title\",\n author: \"\",\n publishedAtKey: \"publishedAt\",\n modifiedAtKey: \"updatedAt\",\n authorKey: \"author\",\n draftKey: \"draft\",\n descriptionKey: \"description\",\n tagsKey: \"tags\",\n};\n\nexport async function loadConfig(pfs: PoweredFileSystem): Promise<Config> {\n try {\n const raw = await pfs.read(\"./mkd.json\");\n\n if (!raw.trim()) {\n return defaultConfig;\n }\n\n const parsed = JSON.parse(raw);\n\n if (!isRecord(parsed)) {\n return defaultConfig;\n }\n\n const { $schema: _schema, ...config } = parsed;\n\n return {\n ...defaultConfig,\n ...config,\n };\n } catch {\n return defaultConfig;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { command, restPositionals, string } from \"cmd-ts\";\nimport path from \"node:path\";\nimport slugify from \"@sindresorhus/slugify\";\nimport filenamify from \"filenamify\";\nimport matter from \"gray-matter\";\nimport { isCancel, text, intro, outro } from \"@clack/prompts\";\nimport type { Config, Deps } from \"../lib/deps\";\n\nexport function makeNewCommand({ config, pfs }: Deps) {\n return command({\n name: \"new\",\n description: \"Create a new post\",\n args: {\n new: restPositionals({\n type: string,\n displayName: \"file\",\n description: \"name of the new post\",\n }),\n },\n handler: async ({ new: titleArray }) => {\n intro(\"Create a new post\");\n let title: string;\n if (titleArray.length === 0) {\n title = await generateTitle();\n if (title === \"\") {\n return;\n }\n } else {\n title = titleArray.join(\" \");\n }\n const slug = slugify(title);\n const fileName = filenamify(slug);\n const frontmatter = await generateFrontmatter(title, config);\n const filePath = path.join(config.blogDir, `${fileName}.md`);\n\n await pfs.write(filePath, frontmatter);\n },\n });\n}\n\nasync function generateFrontmatter(\n title: string,\n config: Config,\n): Promise<string> {\n const description = await makeDescription(title);\n const now = new Date();\n\n const data = {\n [config.titleKey]: title,\n [config.publishedAtKey]: now,\n [config.authorKey]: config.author,\n [config.draftKey]: true,\n [config.descriptionKey]: description,\n [config.tagsKey]: [],\n };\n\n return matter.stringify(\"\", data);\n}\n\nasync function makeDescription(title: string): Promise<string> {\n const description = await text({\n message: \"Enter a description for the post:\",\n defaultValue: title,\n });\n\n if (isCancel(description)) {\n return \"\";\n }\n\n return description;\n}\n\nasync function generateTitle(): Promise<string> {\n const title = await text({\n message: \"Enter a title for the post:\",\n validate: (value) => {\n if (!value) {\n return \"Title required\";\n }\n return undefined;\n },\n });\n\n if (isCancel(title)) {\n return \"\";\n }\n\n return title;\n}\n","import { command } from \"cmd-ts\";\nimport {\n autocompleteMultiselect,\n isCancel,\n intro,\n outro,\n} from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n parseFrontmatter,\n postsToOptions,\n selectedValuesToPosts,\n Post,\n} from \"../lib/commands\";\n\nexport function makePublishCommand({ config, pfs }: Deps) {\n return command({\n name: \"publish\",\n description: \"Undraft a post\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const drafts = posts.filter(\n (post) => parseFrontmatter(post)[config.draftKey] === true,\n );\n const selected = await getPostsToPublish(drafts, config);\n\n for (const draft of selected) {\n await updateDraftFrontMatter(draft, { config, pfs });\n }\n },\n });\n}\n\nasync function getPostsToPublish(\n drafts: Post[],\n config: Config,\n): Promise<Post[]> {\n const options = postsToOptions(drafts, config);\n intro(\"Publishing posts\");\n\n const selected = await autocompleteMultiselect({\n message: \"Select posts to publish\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Publishing cancelled.\");\n return [];\n }\n\n outro(\"Posts undrafted...\");\n\n return selectedValuesToPosts(selected, drafts);\n}\n\nasync function updateDraftFrontMatter(draft: Post, deps: Deps) {\n const parsed = matter(draft.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.draftKey] = false;\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${draft.file}`, updatedContent);\n return { ...draft, content: updatedContent };\n}\n","import matter from \"gray-matter\";\nimport type { Config, Deps } from \"./deps\";\n\nexport type Post = {\n file: string;\n content: string;\n};\n\nexport type Frontmatter = Record<string, unknown>;\n\n/** Read all files from the blog directory and return them as Post objects */\nexport async function readPosts(pfs: Deps[\"pfs\"], config: Config): Promise<Post[]> {\n const files = (await pfs.readdir(config.blogDir)) as string[];\n const posts: Post[] = [];\n\n for (const file of files) {\n const content = await pfs.read(`${config.blogDir}/${file}`);\n posts.push({ file, content });\n }\n\n return posts;\n}\n\n/** Parse frontmatter from a Post */\nexport function parseFrontmatter(post: Post): Frontmatter {\n const { data } = matter(post.content);\n return data as Frontmatter;\n}\n\n/** Convert Posts to prompt option objects (value/label/hint) */\nexport function postsToOptions(posts: Post[], config: Config) {\n return posts.map((post) => {\n const fm = parseFrontmatter(post);\n const title = String(fm[config.titleKey] ?? post.file);\n\n return {\n value: post.file,\n label: title,\n hint: post.file,\n };\n });\n}\n\n/** Take the raw selected values returned by the prompt and return matching Post[] */\nexport function selectedValuesToPosts(selected: string[] | symbol, posts: Post[]): Post[] {\n if (typeof selected === \"symbol\") return [];\n return posts.filter((p) => selected.includes(p.file));\n}\n\nexport function findPostByFile(posts: Post[], fileName: string): Post | undefined {\n return posts.find((p) => p.file === fileName);\n}\n","import { command } from \"cmd-ts\";\nimport { autocomplete, isCancel, intro, outro } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n postsToOptions,\n findPostByFile,\n Post,\n} from \"../lib/commands\";\n\ntype Frontmatter = Record<string, unknown>;\n\nexport function makeUpdateCommand({ config, pfs }: Deps) {\n return command({\n name: \"update\",\n description: \"Update a post's modified date\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const post = await getPostToUpdate(posts, config);\n if (!post) return;\n\n await updatePostDate(post, { config, pfs });\n },\n });\n}\n\nasync function getPostToUpdate(\n posts: Post[],\n config: Config,\n): Promise<Post | null> {\n const options = postsToOptions(posts, config);\n\n intro(\"Update a post\");\n\n const selected = await autocomplete({\n message: \"Select post to update\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Update cancelled.\");\n return null;\n }\n outro(\"Post updated.\");\n\n const found = findPostByFile(posts, selected as string);\n return found ?? null;\n}\n\nasync function updatePostDate(post: Post, deps: Deps) {\n const parsed = matter(post.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.modifiedAtKey] = new Date();\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${post.file}`, updatedContent);\n return { ...post, content: updatedContent };\n}\n","import { command } from \"cmd-ts\";\nimport { autocomplete, isCancel, intro, outro } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n postsToOptions,\n findPostByFile,\n Post,\n} from \"../lib/commands\";\n\ntype Frontmatter = Record<string, unknown>;\n\nexport function makeUnPublishCommand({ config, pfs }: Deps) {\n return command({\n name: \"unpublish\",\n description: \"Unpublish a post\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const post = await getPostToUnpub(posts, config);\n if (!post) return;\n\n await unpubPost(post, { config, pfs });\n },\n });\n}\n\nasync function getPostToUnpub(\n posts: Post[],\n config: Config,\n): Promise<Post | null> {\n const options = postsToOptions(posts, config);\n\n intro(\"Unpublish a post\");\n\n const selected = await autocomplete({\n message: \"Select post to unpublish\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Unpublish cancelled.\");\n return null;\n }\n outro(\"Post unpublished.\");\n\n const found = findPostByFile(posts, selected as string);\n return found ?? null;\n}\n\nasync function unpubPost(post: Post, deps: Deps) {\n const parsed = matter(post.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.draftKey] = true;\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${post.file}`, updatedContent);\n return { ...post, content: updatedContent };\n}\n","import { command } from \"cmd-ts\";\nimport { text, isCancel, intro, outro } from \"@clack/prompts\";\nimport type { Deps } from \"../lib/deps\";\n\nexport function makeInitCommand({ config, pfs }: Deps) {\n return command({\n name: \"init\",\n description: \"Create or update mkd.json configuration\",\n args: {},\n handler: async () => {\n intro(\"Initialize mkd configuration\");\n\n const blogDir = await text({\n message: \"Directory where generated posts are written\",\n defaultValue: String(config.blogDir ?? \"./src/blog\"),\n });\n if (isCancel(blogDir)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const author = await text({\n message: \"Default author\",\n defaultValue: String(config.author ?? \"\"),\n });\n if (isCancel(author)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const titleKey = await text({\n message: \"Title frontmatter key\",\n defaultValue: String(config.titleKey ?? \"title\"),\n });\n if (isCancel(titleKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const publishedAtKey = await text({\n message: \"Published date frontmatter key\",\n defaultValue: String(config.publishedAtKey ?? \"publishedAt\"),\n });\n if (isCancel(publishedAtKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const modifiedAtKey = await text({\n message: \"Modified date frontmatter key\",\n defaultValue: String(config.modifiedAtKey ?? \"updatedAt\"),\n });\n if (isCancel(modifiedAtKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const authorKey = await text({\n message: \"Author frontmatter key\",\n defaultValue: String(config.authorKey ?? \"author\"),\n });\n if (isCancel(authorKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const draftKey = await text({\n message: \"Draft frontmatter key\",\n defaultValue: String(config.draftKey ?? \"draft\"),\n });\n if (isCancel(draftKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const descriptionKey = await text({\n message: \"Description frontmatter key\",\n defaultValue: String(config.descriptionKey ?? \"description\"),\n });\n if (isCancel(descriptionKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const tagsKey = await text({\n message: \"Tags frontmatter key\",\n defaultValue: String(config.tagsKey ?? \"tags\"),\n });\n if (isCancel(tagsKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const newConfig = {\n blogDir: String(blogDir),\n author: String(author),\n publishedAtKey: String(publishedAtKey),\n modifiedAtKey: String(modifiedAtKey),\n authorKey: String(authorKey),\n draftKey: String(draftKey),\n descriptionKey: String(descriptionKey),\n tagsKey: String(tagsKey),\n titleKey: String(titleKey),\n };\n\n await pfs.write(\"./mkd.json\", JSON.stringify(newConfig, null, 2) + \"\\n\");\n\n outro(\"Configuration saved to mkd.json\");\n },\n });\n}\n"],"mappings":"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","names":["import_cmd_ts","slugify","filenamify","path","matter","import_cmd_ts","import_prompts","import_gray_matter","import_gray_matter","matter","matter","import_cmd_ts","import_prompts","import_gray_matter","matter","import_cmd_ts","import_prompts","import_gray_matter","matter","import_cmd_ts","import_prompts"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/lib/deps.ts","../src/commands/new.ts","../src/commands/publish.ts","../src/lib/commands.ts","../src/commands/update.ts","../src/commands/unpublish.ts","../src/commands/init.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { run, subcommands } from \"cmd-ts\";\nimport { PoweredFileSystem } from \"pwd-fs\";\nimport { loadConfig } from \"./lib/deps\";\nimport { makeNewCommand } from \"./commands/new\";\nimport { makePublishCommand } from \"./commands/publish\";\nimport { makeUpdateCommand } from \"./commands/update\";\nimport { makeUnPublishCommand } from \"./commands/unpublish\";\nimport { makeInitCommand } from \"./commands/init\";\n\nasync function main() {\n const pfs = new PoweredFileSystem();\n const config = await loadConfig(pfs);\n const deps = { config, pfs };\n\n const app = subcommands({\n name: \"mkd\",\n cmds: {\n new: makeNewCommand(deps),\n publish: makePublishCommand(deps),\n update: makeUpdateCommand(deps),\n unpublish: makeUnPublishCommand(deps),\n init: makeInitCommand(deps),\n },\n });\n\n await run(app, process.argv.slice(2));\n}\n\nmain().catch((error) => {\n console.error(error);\n process.exit(1);\n});\n","import type { PoweredFileSystem } from \"pwd-fs\";\n\nexport type Config = {\n blogDir: string;\n titleKey: string;\n author: string;\n publishedAtKey: string;\n modifiedAtKey: string;\n authorKey: string;\n draftKey: string;\n descriptionKey: string;\n tagsKey: string;\n};\n\nexport type Deps = {\n config: Config;\n pfs: PoweredFileSystem;\n};\n\nconst defaultConfig: Config = {\n blogDir: \"./src/blog\",\n titleKey: \"title\",\n author: \"\",\n publishedAtKey: \"publishedAt\",\n modifiedAtKey: \"updatedAt\",\n authorKey: \"author\",\n draftKey: \"draft\",\n descriptionKey: \"description\",\n tagsKey: \"tags\",\n};\n\nexport async function loadConfig(pfs: PoweredFileSystem): Promise<Config> {\n try {\n const raw = await pfs.read(\"./mkd.json\");\n\n if (!raw.trim()) {\n return defaultConfig;\n }\n\n const parsed = JSON.parse(raw);\n\n if (!isRecord(parsed)) {\n return defaultConfig;\n }\n\n const { $schema: _schema, ...config } = parsed;\n\n return {\n ...defaultConfig,\n ...config,\n };\n } catch {\n return defaultConfig;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { command, restPositionals, string } from \"cmd-ts\";\nimport path from \"node:path\";\nimport slugify from \"@sindresorhus/slugify\";\nimport filenamify from \"filenamify\";\nimport matter from \"gray-matter\";\nimport { isCancel, text, intro, outro } from \"@clack/prompts\";\nimport type { Config, Deps } from \"../lib/deps\";\n\nexport function makeNewCommand({ config, pfs }: Deps) {\n return command({\n name: \"new\",\n description: \"Create a new post\",\n args: {\n new: restPositionals({\n type: string,\n displayName: \"file\",\n description: \"name of the new post\",\n }),\n },\n handler: async ({ new: titleArray }) => {\n intro(\"Create a new post\");\n let title: string;\n if (titleArray.length === 0) {\n title = await generateTitle();\n if (title === \"\") {\n return;\n }\n } else {\n title = titleArray.join(\" \");\n }\n const slug = slugify(title);\n const fileName = filenamify(slug);\n const frontmatter = await generateFrontmatter(title, config);\n const filePath = path.join(config.blogDir, `${fileName}.md`);\n\n await pfs.write(filePath, frontmatter);\n },\n });\n}\n\nasync function generateFrontmatter(\n title: string,\n config: Config,\n): Promise<string> {\n const description = await makeDescription(title);\n // const now = new Date();\n\n const data = {\n [config.titleKey]: title,\n [config.publishedAtKey]: new Date(\"3000-01-01T00:00:00Z\"),\n [config.authorKey]: config.author,\n [config.draftKey]: true,\n [config.descriptionKey]: description,\n [config.tagsKey]: [],\n };\n\n return matter.stringify(\"\", data);\n}\n\nasync function makeDescription(title: string): Promise<string> {\n const description = await text({\n message: \"Enter a description for the post:\",\n defaultValue: title,\n });\n\n if (isCancel(description)) {\n return \"\";\n }\n\n return description;\n}\n\nasync function generateTitle(): Promise<string> {\n const title = await text({\n message: \"Enter a title for the post:\",\n validate: (value) => {\n if (!value) {\n return \"Title required\";\n }\n return undefined;\n },\n });\n\n if (isCancel(title)) {\n return \"\";\n }\n\n return title;\n}\n","import { command } from \"cmd-ts\";\nimport { isCancel, intro, outro, autocomplete } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n parseFrontmatter,\n postsToOptions,\n selectedValuesToPosts,\n Post,\n} from \"../lib/commands\";\n\nexport function makePublishCommand({ config, pfs }: Deps) {\n return command({\n name: \"publish\",\n description: \"Undraft a post\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const drafts = posts.filter(\n (post) => parseFrontmatter(post)[config.draftKey] === true,\n );\n const selected = await getPostsToPublish(drafts, config);\n\n for (const draft of selected) {\n await updateDraftFrontMatter(draft, { config, pfs });\n }\n },\n });\n}\n\nasync function getPostsToPublish(\n drafts: Post[],\n config: Config,\n): Promise<Post[]> {\n const options = postsToOptions(drafts, config);\n intro(\"Publishing posts\");\n\n const selected = await autocomplete({\n message: \"Select post to publish\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Publishing cancelled.\");\n return [];\n }\n\n outro(\"Posts undrafted...\");\n\n return selectedValuesToPosts(\n Array.isArray(selected) ? selected : [selected],\n drafts,\n );\n}\n\nasync function updateDraftFrontMatter(draft: Post, deps: Deps) {\n const now = new Date();\n const parsed = matter(draft.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.draftKey] = false;\n fm[deps.config.publishedAtKey] = now;\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${draft.file}`, updatedContent);\n return { ...draft, content: updatedContent };\n}\n","import matter from \"gray-matter\";\nimport type { Config, Deps } from \"./deps\";\n\nexport type Post = {\n file: string;\n content: string;\n};\n\nexport type Frontmatter = Record<string, unknown>;\n\n/** Read all files from the blog directory and return them as Post objects */\nexport async function readPosts(pfs: Deps[\"pfs\"], config: Config): Promise<Post[]> {\n const files = (await pfs.readdir(config.blogDir)) as string[];\n const posts: Post[] = [];\n\n for (const file of files) {\n const content = await pfs.read(`${config.blogDir}/${file}`);\n posts.push({ file, content });\n }\n\n return posts;\n}\n\n/** Parse frontmatter from a Post */\nexport function parseFrontmatter(post: Post): Frontmatter {\n const { data } = matter(post.content);\n return data as Frontmatter;\n}\n\n/** Convert Posts to prompt option objects (value/label/hint) */\nexport function postsToOptions(posts: Post[], config: Config) {\n return posts.map((post) => {\n const fm = parseFrontmatter(post);\n const title = String(fm[config.titleKey] ?? post.file);\n\n return {\n value: post.file,\n label: title,\n hint: post.file,\n };\n });\n}\n\n/** Take the raw selected values returned by the prompt and return matching Post[] */\nexport function selectedValuesToPosts(selected: string[] | symbol, posts: Post[]): Post[] {\n if (typeof selected === \"symbol\") return [];\n return posts.filter((p) => selected.includes(p.file));\n}\n\nexport function findPostByFile(posts: Post[], fileName: string): Post | undefined {\n return posts.find((p) => p.file === fileName);\n}\n","import { command } from \"cmd-ts\";\nimport { autocomplete, isCancel, intro, outro } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n postsToOptions,\n findPostByFile,\n Post,\n} from \"../lib/commands\";\n\ntype Frontmatter = Record<string, unknown>;\n\nexport function makeUpdateCommand({ config, pfs }: Deps) {\n return command({\n name: \"update\",\n description: \"Update a post's modified date\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const post = await getPostToUpdate(posts, config);\n if (!post) return;\n\n await updatePostDate(post, { config, pfs });\n },\n });\n}\n\nasync function getPostToUpdate(\n posts: Post[],\n config: Config,\n): Promise<Post | null> {\n const options = postsToOptions(posts, config);\n\n intro(\"Update a post\");\n\n const selected = await autocomplete({\n message: \"Select post to update\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Update cancelled.\");\n return null;\n }\n outro(\"Post updated.\");\n\n const found = findPostByFile(posts, selected as string);\n return found ?? null;\n}\n\nasync function updatePostDate(post: Post, deps: Deps) {\n const parsed = matter(post.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.modifiedAtKey] = new Date();\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${post.file}`, updatedContent);\n return { ...post, content: updatedContent };\n}\n","import { command } from \"cmd-ts\";\nimport { autocomplete, isCancel, intro, outro } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n postsToOptions,\n findPostByFile,\n Post,\n} from \"../lib/commands\";\n\ntype Frontmatter = Record<string, unknown>;\n\nexport function makeUnPublishCommand({ config, pfs }: Deps) {\n return command({\n name: \"unpublish\",\n description: \"Unpublish a post\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const post = await getPostToUnpub(posts, config);\n if (!post) return;\n\n await unpubPost(post, { config, pfs });\n },\n });\n}\n\nasync function getPostToUnpub(\n posts: Post[],\n config: Config,\n): Promise<Post | null> {\n const options = postsToOptions(posts, config);\n\n intro(\"Unpublish a post\");\n\n const selected = await autocomplete({\n message: \"Select post to unpublish\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Unpublish cancelled.\");\n return null;\n }\n outro(\"Post unpublished.\");\n\n const found = findPostByFile(posts, selected as string);\n return found ?? null;\n}\n\nasync function unpubPost(post: Post, deps: Deps) {\n const parsed = matter(post.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.draftKey] = true;\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${post.file}`, updatedContent);\n return { ...post, content: updatedContent };\n}\n","import { command } from \"cmd-ts\";\nimport { text, isCancel, intro, outro } from \"@clack/prompts\";\nimport type { Deps } from \"../lib/deps\";\n\nexport function makeInitCommand({ config, pfs }: Deps) {\n return command({\n name: \"init\",\n description: \"Create or update mkd.json configuration\",\n args: {},\n handler: async () => {\n intro(\"Initialize mkd configuration\");\n\n const blogDir = await text({\n message: \"Directory where generated posts are written\",\n defaultValue: String(config.blogDir ?? \"./src/blog\"),\n });\n if (isCancel(blogDir)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const author = await text({\n message: \"Default author\",\n defaultValue: String(config.author ?? \"\"),\n });\n if (isCancel(author)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const titleKey = await text({\n message: \"Title frontmatter key\",\n defaultValue: String(config.titleKey ?? \"title\"),\n });\n if (isCancel(titleKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const publishedAtKey = await text({\n message: \"Published date frontmatter key\",\n defaultValue: String(config.publishedAtKey ?? \"publishedAt\"),\n });\n if (isCancel(publishedAtKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const modifiedAtKey = await text({\n message: \"Modified date frontmatter key\",\n defaultValue: String(config.modifiedAtKey ?? \"updatedAt\"),\n });\n if (isCancel(modifiedAtKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const authorKey = await text({\n message: \"Author frontmatter key\",\n defaultValue: String(config.authorKey ?? \"author\"),\n });\n if (isCancel(authorKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const draftKey = await text({\n message: \"Draft frontmatter key\",\n defaultValue: String(config.draftKey ?? \"draft\"),\n });\n if (isCancel(draftKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const descriptionKey = await text({\n message: \"Description frontmatter key\",\n defaultValue: String(config.descriptionKey ?? \"description\"),\n });\n if (isCancel(descriptionKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const tagsKey = await text({\n message: \"Tags frontmatter key\",\n defaultValue: String(config.tagsKey ?? \"tags\"),\n });\n if (isCancel(tagsKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const newConfig = {\n blogDir: String(blogDir),\n author: String(author),\n publishedAtKey: String(publishedAtKey),\n modifiedAtKey: String(modifiedAtKey),\n authorKey: String(authorKey),\n draftKey: String(draftKey),\n descriptionKey: String(descriptionKey),\n tagsKey: String(tagsKey),\n titleKey: String(titleKey),\n };\n\n await pfs.write(\"./mkd.json\", JSON.stringify(newConfig, null, 2) + \"\\n\");\n\n outro(\"Configuration saved to mkd.json\");\n },\n });\n}\n"],"mappings":"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","names":["import_cmd_ts","slugify","filenamify","path","matter","import_cmd_ts","import_prompts","import_gray_matter","import_gray_matter","matter","matter","import_cmd_ts","import_prompts","import_gray_matter","matter","import_cmd_ts","import_prompts","import_gray_matter","matter","import_cmd_ts","import_prompts"]}
package/dist/index.js CHANGED
@@ -78,10 +78,9 @@ function makeNewCommand({ config, pfs }) {
78
78
  }
79
79
  async function generateFrontmatter(title, config) {
80
80
  const description = await makeDescription(title);
81
- const now = /* @__PURE__ */ new Date();
82
81
  const data = {
83
82
  [config.titleKey]: title,
84
- [config.publishedAtKey]: now,
83
+ [config.publishedAtKey]: /* @__PURE__ */ new Date("3000-01-01T00:00:00Z"),
85
84
  [config.authorKey]: config.author,
86
85
  [config.draftKey]: true,
87
86
  [config.descriptionKey]: description,
@@ -117,12 +116,7 @@ async function generateTitle() {
117
116
 
118
117
  // src/commands/publish.ts
119
118
  import { command as command2 } from "cmd-ts";
120
- import {
121
- autocompleteMultiselect,
122
- isCancel as isCancel2,
123
- intro as intro2,
124
- outro as outro2
125
- } from "@clack/prompts";
119
+ import { isCancel as isCancel2, intro as intro2, outro as outro2, autocomplete } from "@clack/prompts";
126
120
  import matter3 from "gray-matter";
127
121
 
128
122
  // src/lib/commands.ts
@@ -180,8 +174,8 @@ function makePublishCommand({ config, pfs }) {
180
174
  async function getPostsToPublish(drafts, config) {
181
175
  const options = postsToOptions(drafts, config);
182
176
  intro2("Publishing posts");
183
- const selected = await autocompleteMultiselect({
184
- message: "Select posts to publish",
177
+ const selected = await autocomplete({
178
+ message: "Select post to publish",
185
179
  options
186
180
  });
187
181
  if (isCancel2(selected)) {
@@ -189,12 +183,17 @@ async function getPostsToPublish(drafts, config) {
189
183
  return [];
190
184
  }
191
185
  outro2("Posts undrafted...");
192
- return selectedValuesToPosts(selected, drafts);
186
+ return selectedValuesToPosts(
187
+ Array.isArray(selected) ? selected : [selected],
188
+ drafts
189
+ );
193
190
  }
194
191
  async function updateDraftFrontMatter(draft, deps) {
192
+ const now = /* @__PURE__ */ new Date();
195
193
  const parsed = matter3(draft.content);
196
194
  const fm = parsed.data;
197
195
  fm[deps.config.draftKey] = false;
196
+ fm[deps.config.publishedAtKey] = now;
198
197
  const updatedContent = matter3.stringify(parsed.content, fm);
199
198
  await deps.pfs.write(`${deps.config.blogDir}/${draft.file}`, updatedContent);
200
199
  return { ...draft, content: updatedContent };
@@ -202,7 +201,7 @@ async function updateDraftFrontMatter(draft, deps) {
202
201
 
203
202
  // src/commands/update.ts
204
203
  import { command as command3 } from "cmd-ts";
205
- import { autocomplete, isCancel as isCancel3, intro as intro3, outro as outro3 } from "@clack/prompts";
204
+ import { autocomplete as autocomplete2, isCancel as isCancel3, intro as intro3, outro as outro3 } from "@clack/prompts";
206
205
  import matter4 from "gray-matter";
207
206
  function makeUpdateCommand({ config, pfs }) {
208
207
  return command3({
@@ -220,7 +219,7 @@ function makeUpdateCommand({ config, pfs }) {
220
219
  async function getPostToUpdate(posts, config) {
221
220
  const options = postsToOptions(posts, config);
222
221
  intro3("Update a post");
223
- const selected = await autocomplete({
222
+ const selected = await autocomplete2({
224
223
  message: "Select post to update",
225
224
  options
226
225
  });
@@ -243,7 +242,7 @@ async function updatePostDate(post, deps) {
243
242
 
244
243
  // src/commands/unpublish.ts
245
244
  import { command as command4 } from "cmd-ts";
246
- import { autocomplete as autocomplete2, isCancel as isCancel4, intro as intro4, outro as outro4 } from "@clack/prompts";
245
+ import { autocomplete as autocomplete3, isCancel as isCancel4, intro as intro4, outro as outro4 } from "@clack/prompts";
247
246
  import matter5 from "gray-matter";
248
247
  function makeUnPublishCommand({ config, pfs }) {
249
248
  return command4({
@@ -261,7 +260,7 @@ function makeUnPublishCommand({ config, pfs }) {
261
260
  async function getPostToUnpub(posts, config) {
262
261
  const options = postsToOptions(posts, config);
263
262
  intro4("Unpublish a post");
264
- const selected = await autocomplete2({
263
+ const selected = await autocomplete3({
265
264
  message: "Select post to unpublish",
266
265
  options
267
266
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/lib/deps.ts","../src/commands/new.ts","../src/commands/publish.ts","../src/lib/commands.ts","../src/commands/update.ts","../src/commands/unpublish.ts","../src/commands/init.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { run, subcommands } from \"cmd-ts\";\nimport { PoweredFileSystem } from \"pwd-fs\";\nimport { loadConfig } from \"./lib/deps\";\nimport { makeNewCommand } from \"./commands/new\";\nimport { makePublishCommand } from \"./commands/publish\";\nimport { makeUpdateCommand } from \"./commands/update\";\nimport { makeUnPublishCommand } from \"./commands/unpublish\";\nimport { makeInitCommand } from \"./commands/init\";\n\nasync function main() {\n const pfs = new PoweredFileSystem();\n const config = await loadConfig(pfs);\n const deps = { config, pfs };\n\n const app = subcommands({\n name: \"mkd\",\n cmds: {\n new: makeNewCommand(deps),\n publish: makePublishCommand(deps),\n update: makeUpdateCommand(deps),\n unpublish: makeUnPublishCommand(deps),\n init: makeInitCommand(deps),\n },\n });\n\n await run(app, process.argv.slice(2));\n}\n\nmain().catch((error) => {\n console.error(error);\n process.exit(1);\n});\n","import type { PoweredFileSystem } from \"pwd-fs\";\n\nexport type Config = {\n blogDir: string;\n titleKey: string;\n author: string;\n publishedAtKey: string;\n modifiedAtKey: string;\n authorKey: string;\n draftKey: string;\n descriptionKey: string;\n tagsKey: string;\n};\n\nexport type Deps = {\n config: Config;\n pfs: PoweredFileSystem;\n};\n\nconst defaultConfig: Config = {\n blogDir: \"./src/blog\",\n titleKey: \"title\",\n author: \"\",\n publishedAtKey: \"publishedAt\",\n modifiedAtKey: \"updatedAt\",\n authorKey: \"author\",\n draftKey: \"draft\",\n descriptionKey: \"description\",\n tagsKey: \"tags\",\n};\n\nexport async function loadConfig(pfs: PoweredFileSystem): Promise<Config> {\n try {\n const raw = await pfs.read(\"./mkd.json\");\n\n if (!raw.trim()) {\n return defaultConfig;\n }\n\n const parsed = JSON.parse(raw);\n\n if (!isRecord(parsed)) {\n return defaultConfig;\n }\n\n const { $schema: _schema, ...config } = parsed;\n\n return {\n ...defaultConfig,\n ...config,\n };\n } catch {\n return defaultConfig;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { command, restPositionals, string } from \"cmd-ts\";\nimport path from \"node:path\";\nimport slugify from \"@sindresorhus/slugify\";\nimport filenamify from \"filenamify\";\nimport matter from \"gray-matter\";\nimport { isCancel, text, intro, outro } from \"@clack/prompts\";\nimport type { Config, Deps } from \"../lib/deps\";\n\nexport function makeNewCommand({ config, pfs }: Deps) {\n return command({\n name: \"new\",\n description: \"Create a new post\",\n args: {\n new: restPositionals({\n type: string,\n displayName: \"file\",\n description: \"name of the new post\",\n }),\n },\n handler: async ({ new: titleArray }) => {\n intro(\"Create a new post\");\n let title: string;\n if (titleArray.length === 0) {\n title = await generateTitle();\n if (title === \"\") {\n return;\n }\n } else {\n title = titleArray.join(\" \");\n }\n const slug = slugify(title);\n const fileName = filenamify(slug);\n const frontmatter = await generateFrontmatter(title, config);\n const filePath = path.join(config.blogDir, `${fileName}.md`);\n\n await pfs.write(filePath, frontmatter);\n },\n });\n}\n\nasync function generateFrontmatter(\n title: string,\n config: Config,\n): Promise<string> {\n const description = await makeDescription(title);\n const now = new Date();\n\n const data = {\n [config.titleKey]: title,\n [config.publishedAtKey]: now,\n [config.authorKey]: config.author,\n [config.draftKey]: true,\n [config.descriptionKey]: description,\n [config.tagsKey]: [],\n };\n\n return matter.stringify(\"\", data);\n}\n\nasync function makeDescription(title: string): Promise<string> {\n const description = await text({\n message: \"Enter a description for the post:\",\n defaultValue: title,\n });\n\n if (isCancel(description)) {\n return \"\";\n }\n\n return description;\n}\n\nasync function generateTitle(): Promise<string> {\n const title = await text({\n message: \"Enter a title for the post:\",\n validate: (value) => {\n if (!value) {\n return \"Title required\";\n }\n return undefined;\n },\n });\n\n if (isCancel(title)) {\n return \"\";\n }\n\n return title;\n}\n","import { command } from \"cmd-ts\";\nimport {\n autocompleteMultiselect,\n isCancel,\n intro,\n outro,\n} from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n parseFrontmatter,\n postsToOptions,\n selectedValuesToPosts,\n Post,\n} from \"../lib/commands\";\n\nexport function makePublishCommand({ config, pfs }: Deps) {\n return command({\n name: \"publish\",\n description: \"Undraft a post\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const drafts = posts.filter(\n (post) => parseFrontmatter(post)[config.draftKey] === true,\n );\n const selected = await getPostsToPublish(drafts, config);\n\n for (const draft of selected) {\n await updateDraftFrontMatter(draft, { config, pfs });\n }\n },\n });\n}\n\nasync function getPostsToPublish(\n drafts: Post[],\n config: Config,\n): Promise<Post[]> {\n const options = postsToOptions(drafts, config);\n intro(\"Publishing posts\");\n\n const selected = await autocompleteMultiselect({\n message: \"Select posts to publish\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Publishing cancelled.\");\n return [];\n }\n\n outro(\"Posts undrafted...\");\n\n return selectedValuesToPosts(selected, drafts);\n}\n\nasync function updateDraftFrontMatter(draft: Post, deps: Deps) {\n const parsed = matter(draft.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.draftKey] = false;\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${draft.file}`, updatedContent);\n return { ...draft, content: updatedContent };\n}\n","import matter from \"gray-matter\";\nimport type { Config, Deps } from \"./deps\";\n\nexport type Post = {\n file: string;\n content: string;\n};\n\nexport type Frontmatter = Record<string, unknown>;\n\n/** Read all files from the blog directory and return them as Post objects */\nexport async function readPosts(pfs: Deps[\"pfs\"], config: Config): Promise<Post[]> {\n const files = (await pfs.readdir(config.blogDir)) as string[];\n const posts: Post[] = [];\n\n for (const file of files) {\n const content = await pfs.read(`${config.blogDir}/${file}`);\n posts.push({ file, content });\n }\n\n return posts;\n}\n\n/** Parse frontmatter from a Post */\nexport function parseFrontmatter(post: Post): Frontmatter {\n const { data } = matter(post.content);\n return data as Frontmatter;\n}\n\n/** Convert Posts to prompt option objects (value/label/hint) */\nexport function postsToOptions(posts: Post[], config: Config) {\n return posts.map((post) => {\n const fm = parseFrontmatter(post);\n const title = String(fm[config.titleKey] ?? post.file);\n\n return {\n value: post.file,\n label: title,\n hint: post.file,\n };\n });\n}\n\n/** Take the raw selected values returned by the prompt and return matching Post[] */\nexport function selectedValuesToPosts(selected: string[] | symbol, posts: Post[]): Post[] {\n if (typeof selected === \"symbol\") return [];\n return posts.filter((p) => selected.includes(p.file));\n}\n\nexport function findPostByFile(posts: Post[], fileName: string): Post | undefined {\n return posts.find((p) => p.file === fileName);\n}\n","import { command } from \"cmd-ts\";\nimport { autocomplete, isCancel, intro, outro } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n postsToOptions,\n findPostByFile,\n Post,\n} from \"../lib/commands\";\n\ntype Frontmatter = Record<string, unknown>;\n\nexport function makeUpdateCommand({ config, pfs }: Deps) {\n return command({\n name: \"update\",\n description: \"Update a post's modified date\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const post = await getPostToUpdate(posts, config);\n if (!post) return;\n\n await updatePostDate(post, { config, pfs });\n },\n });\n}\n\nasync function getPostToUpdate(\n posts: Post[],\n config: Config,\n): Promise<Post | null> {\n const options = postsToOptions(posts, config);\n\n intro(\"Update a post\");\n\n const selected = await autocomplete({\n message: \"Select post to update\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Update cancelled.\");\n return null;\n }\n outro(\"Post updated.\");\n\n const found = findPostByFile(posts, selected as string);\n return found ?? null;\n}\n\nasync function updatePostDate(post: Post, deps: Deps) {\n const parsed = matter(post.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.modifiedAtKey] = new Date();\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${post.file}`, updatedContent);\n return { ...post, content: updatedContent };\n}\n","import { command } from \"cmd-ts\";\nimport { autocomplete, isCancel, intro, outro } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n postsToOptions,\n findPostByFile,\n Post,\n} from \"../lib/commands\";\n\ntype Frontmatter = Record<string, unknown>;\n\nexport function makeUnPublishCommand({ config, pfs }: Deps) {\n return command({\n name: \"unpublish\",\n description: \"Unpublish a post\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const post = await getPostToUnpub(posts, config);\n if (!post) return;\n\n await unpubPost(post, { config, pfs });\n },\n });\n}\n\nasync function getPostToUnpub(\n posts: Post[],\n config: Config,\n): Promise<Post | null> {\n const options = postsToOptions(posts, config);\n\n intro(\"Unpublish a post\");\n\n const selected = await autocomplete({\n message: \"Select post to unpublish\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Unpublish cancelled.\");\n return null;\n }\n outro(\"Post unpublished.\");\n\n const found = findPostByFile(posts, selected as string);\n return found ?? null;\n}\n\nasync function unpubPost(post: Post, deps: Deps) {\n const parsed = matter(post.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.draftKey] = true;\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${post.file}`, updatedContent);\n return { ...post, content: updatedContent };\n}\n","import { command } from \"cmd-ts\";\nimport { text, isCancel, intro, outro } from \"@clack/prompts\";\nimport type { Deps } from \"../lib/deps\";\n\nexport function makeInitCommand({ config, pfs }: Deps) {\n return command({\n name: \"init\",\n description: \"Create or update mkd.json configuration\",\n args: {},\n handler: async () => {\n intro(\"Initialize mkd configuration\");\n\n const blogDir = await text({\n message: \"Directory where generated posts are written\",\n defaultValue: String(config.blogDir ?? \"./src/blog\"),\n });\n if (isCancel(blogDir)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const author = await text({\n message: \"Default author\",\n defaultValue: String(config.author ?? \"\"),\n });\n if (isCancel(author)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const titleKey = await text({\n message: \"Title frontmatter key\",\n defaultValue: String(config.titleKey ?? \"title\"),\n });\n if (isCancel(titleKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const publishedAtKey = await text({\n message: \"Published date frontmatter key\",\n defaultValue: String(config.publishedAtKey ?? \"publishedAt\"),\n });\n if (isCancel(publishedAtKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const modifiedAtKey = await text({\n message: \"Modified date frontmatter key\",\n defaultValue: String(config.modifiedAtKey ?? \"updatedAt\"),\n });\n if (isCancel(modifiedAtKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const authorKey = await text({\n message: \"Author frontmatter key\",\n defaultValue: String(config.authorKey ?? \"author\"),\n });\n if (isCancel(authorKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const draftKey = await text({\n message: \"Draft frontmatter key\",\n defaultValue: String(config.draftKey ?? \"draft\"),\n });\n if (isCancel(draftKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const descriptionKey = await text({\n message: \"Description frontmatter key\",\n defaultValue: String(config.descriptionKey ?? \"description\"),\n });\n if (isCancel(descriptionKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const tagsKey = await text({\n message: \"Tags frontmatter key\",\n defaultValue: String(config.tagsKey ?? \"tags\"),\n });\n if (isCancel(tagsKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const newConfig = {\n blogDir: String(blogDir),\n author: String(author),\n publishedAtKey: String(publishedAtKey),\n modifiedAtKey: String(modifiedAtKey),\n authorKey: String(authorKey),\n draftKey: String(draftKey),\n descriptionKey: String(descriptionKey),\n tagsKey: String(tagsKey),\n titleKey: String(titleKey),\n };\n\n await pfs.write(\"./mkd.json\", JSON.stringify(newConfig, null, 2) + \"\\n\");\n\n outro(\"Configuration saved to mkd.json\");\n },\n });\n}\n"],"mappings":"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","names":["command","isCancel","intro","outro","matter","matter","command","intro","isCancel","outro","matter","command","isCancel","intro","outro","matter","command","intro","isCancel","outro","matter","command","autocomplete","isCancel","intro","outro","matter","command","intro","autocomplete","isCancel","outro","matter","command","text","isCancel","intro","outro"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/lib/deps.ts","../src/commands/new.ts","../src/commands/publish.ts","../src/lib/commands.ts","../src/commands/update.ts","../src/commands/unpublish.ts","../src/commands/init.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { run, subcommands } from \"cmd-ts\";\nimport { PoweredFileSystem } from \"pwd-fs\";\nimport { loadConfig } from \"./lib/deps\";\nimport { makeNewCommand } from \"./commands/new\";\nimport { makePublishCommand } from \"./commands/publish\";\nimport { makeUpdateCommand } from \"./commands/update\";\nimport { makeUnPublishCommand } from \"./commands/unpublish\";\nimport { makeInitCommand } from \"./commands/init\";\n\nasync function main() {\n const pfs = new PoweredFileSystem();\n const config = await loadConfig(pfs);\n const deps = { config, pfs };\n\n const app = subcommands({\n name: \"mkd\",\n cmds: {\n new: makeNewCommand(deps),\n publish: makePublishCommand(deps),\n update: makeUpdateCommand(deps),\n unpublish: makeUnPublishCommand(deps),\n init: makeInitCommand(deps),\n },\n });\n\n await run(app, process.argv.slice(2));\n}\n\nmain().catch((error) => {\n console.error(error);\n process.exit(1);\n});\n","import type { PoweredFileSystem } from \"pwd-fs\";\n\nexport type Config = {\n blogDir: string;\n titleKey: string;\n author: string;\n publishedAtKey: string;\n modifiedAtKey: string;\n authorKey: string;\n draftKey: string;\n descriptionKey: string;\n tagsKey: string;\n};\n\nexport type Deps = {\n config: Config;\n pfs: PoweredFileSystem;\n};\n\nconst defaultConfig: Config = {\n blogDir: \"./src/blog\",\n titleKey: \"title\",\n author: \"\",\n publishedAtKey: \"publishedAt\",\n modifiedAtKey: \"updatedAt\",\n authorKey: \"author\",\n draftKey: \"draft\",\n descriptionKey: \"description\",\n tagsKey: \"tags\",\n};\n\nexport async function loadConfig(pfs: PoweredFileSystem): Promise<Config> {\n try {\n const raw = await pfs.read(\"./mkd.json\");\n\n if (!raw.trim()) {\n return defaultConfig;\n }\n\n const parsed = JSON.parse(raw);\n\n if (!isRecord(parsed)) {\n return defaultConfig;\n }\n\n const { $schema: _schema, ...config } = parsed;\n\n return {\n ...defaultConfig,\n ...config,\n };\n } catch {\n return defaultConfig;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { command, restPositionals, string } from \"cmd-ts\";\nimport path from \"node:path\";\nimport slugify from \"@sindresorhus/slugify\";\nimport filenamify from \"filenamify\";\nimport matter from \"gray-matter\";\nimport { isCancel, text, intro, outro } from \"@clack/prompts\";\nimport type { Config, Deps } from \"../lib/deps\";\n\nexport function makeNewCommand({ config, pfs }: Deps) {\n return command({\n name: \"new\",\n description: \"Create a new post\",\n args: {\n new: restPositionals({\n type: string,\n displayName: \"file\",\n description: \"name of the new post\",\n }),\n },\n handler: async ({ new: titleArray }) => {\n intro(\"Create a new post\");\n let title: string;\n if (titleArray.length === 0) {\n title = await generateTitle();\n if (title === \"\") {\n return;\n }\n } else {\n title = titleArray.join(\" \");\n }\n const slug = slugify(title);\n const fileName = filenamify(slug);\n const frontmatter = await generateFrontmatter(title, config);\n const filePath = path.join(config.blogDir, `${fileName}.md`);\n\n await pfs.write(filePath, frontmatter);\n },\n });\n}\n\nasync function generateFrontmatter(\n title: string,\n config: Config,\n): Promise<string> {\n const description = await makeDescription(title);\n // const now = new Date();\n\n const data = {\n [config.titleKey]: title,\n [config.publishedAtKey]: new Date(\"3000-01-01T00:00:00Z\"),\n [config.authorKey]: config.author,\n [config.draftKey]: true,\n [config.descriptionKey]: description,\n [config.tagsKey]: [],\n };\n\n return matter.stringify(\"\", data);\n}\n\nasync function makeDescription(title: string): Promise<string> {\n const description = await text({\n message: \"Enter a description for the post:\",\n defaultValue: title,\n });\n\n if (isCancel(description)) {\n return \"\";\n }\n\n return description;\n}\n\nasync function generateTitle(): Promise<string> {\n const title = await text({\n message: \"Enter a title for the post:\",\n validate: (value) => {\n if (!value) {\n return \"Title required\";\n }\n return undefined;\n },\n });\n\n if (isCancel(title)) {\n return \"\";\n }\n\n return title;\n}\n","import { command } from \"cmd-ts\";\nimport { isCancel, intro, outro, autocomplete } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n parseFrontmatter,\n postsToOptions,\n selectedValuesToPosts,\n Post,\n} from \"../lib/commands\";\n\nexport function makePublishCommand({ config, pfs }: Deps) {\n return command({\n name: \"publish\",\n description: \"Undraft a post\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const drafts = posts.filter(\n (post) => parseFrontmatter(post)[config.draftKey] === true,\n );\n const selected = await getPostsToPublish(drafts, config);\n\n for (const draft of selected) {\n await updateDraftFrontMatter(draft, { config, pfs });\n }\n },\n });\n}\n\nasync function getPostsToPublish(\n drafts: Post[],\n config: Config,\n): Promise<Post[]> {\n const options = postsToOptions(drafts, config);\n intro(\"Publishing posts\");\n\n const selected = await autocomplete({\n message: \"Select post to publish\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Publishing cancelled.\");\n return [];\n }\n\n outro(\"Posts undrafted...\");\n\n return selectedValuesToPosts(\n Array.isArray(selected) ? selected : [selected],\n drafts,\n );\n}\n\nasync function updateDraftFrontMatter(draft: Post, deps: Deps) {\n const now = new Date();\n const parsed = matter(draft.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.draftKey] = false;\n fm[deps.config.publishedAtKey] = now;\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${draft.file}`, updatedContent);\n return { ...draft, content: updatedContent };\n}\n","import matter from \"gray-matter\";\nimport type { Config, Deps } from \"./deps\";\n\nexport type Post = {\n file: string;\n content: string;\n};\n\nexport type Frontmatter = Record<string, unknown>;\n\n/** Read all files from the blog directory and return them as Post objects */\nexport async function readPosts(pfs: Deps[\"pfs\"], config: Config): Promise<Post[]> {\n const files = (await pfs.readdir(config.blogDir)) as string[];\n const posts: Post[] = [];\n\n for (const file of files) {\n const content = await pfs.read(`${config.blogDir}/${file}`);\n posts.push({ file, content });\n }\n\n return posts;\n}\n\n/** Parse frontmatter from a Post */\nexport function parseFrontmatter(post: Post): Frontmatter {\n const { data } = matter(post.content);\n return data as Frontmatter;\n}\n\n/** Convert Posts to prompt option objects (value/label/hint) */\nexport function postsToOptions(posts: Post[], config: Config) {\n return posts.map((post) => {\n const fm = parseFrontmatter(post);\n const title = String(fm[config.titleKey] ?? post.file);\n\n return {\n value: post.file,\n label: title,\n hint: post.file,\n };\n });\n}\n\n/** Take the raw selected values returned by the prompt and return matching Post[] */\nexport function selectedValuesToPosts(selected: string[] | symbol, posts: Post[]): Post[] {\n if (typeof selected === \"symbol\") return [];\n return posts.filter((p) => selected.includes(p.file));\n}\n\nexport function findPostByFile(posts: Post[], fileName: string): Post | undefined {\n return posts.find((p) => p.file === fileName);\n}\n","import { command } from \"cmd-ts\";\nimport { autocomplete, isCancel, intro, outro } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n postsToOptions,\n findPostByFile,\n Post,\n} from \"../lib/commands\";\n\ntype Frontmatter = Record<string, unknown>;\n\nexport function makeUpdateCommand({ config, pfs }: Deps) {\n return command({\n name: \"update\",\n description: \"Update a post's modified date\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const post = await getPostToUpdate(posts, config);\n if (!post) return;\n\n await updatePostDate(post, { config, pfs });\n },\n });\n}\n\nasync function getPostToUpdate(\n posts: Post[],\n config: Config,\n): Promise<Post | null> {\n const options = postsToOptions(posts, config);\n\n intro(\"Update a post\");\n\n const selected = await autocomplete({\n message: \"Select post to update\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Update cancelled.\");\n return null;\n }\n outro(\"Post updated.\");\n\n const found = findPostByFile(posts, selected as string);\n return found ?? null;\n}\n\nasync function updatePostDate(post: Post, deps: Deps) {\n const parsed = matter(post.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.modifiedAtKey] = new Date();\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${post.file}`, updatedContent);\n return { ...post, content: updatedContent };\n}\n","import { command } from \"cmd-ts\";\nimport { autocomplete, isCancel, intro, outro } from \"@clack/prompts\";\nimport matter from \"gray-matter\";\nimport type { Config, Deps } from \"../lib/deps\";\nimport {\n readPosts,\n postsToOptions,\n findPostByFile,\n Post,\n} from \"../lib/commands\";\n\ntype Frontmatter = Record<string, unknown>;\n\nexport function makeUnPublishCommand({ config, pfs }: Deps) {\n return command({\n name: \"unpublish\",\n description: \"Unpublish a post\",\n args: {},\n handler: async () => {\n const posts = await readPosts(pfs, config);\n const post = await getPostToUnpub(posts, config);\n if (!post) return;\n\n await unpubPost(post, { config, pfs });\n },\n });\n}\n\nasync function getPostToUnpub(\n posts: Post[],\n config: Config,\n): Promise<Post | null> {\n const options = postsToOptions(posts, config);\n\n intro(\"Unpublish a post\");\n\n const selected = await autocomplete({\n message: \"Select post to unpublish\",\n options,\n });\n\n if (isCancel(selected)) {\n outro(\"Unpublish cancelled.\");\n return null;\n }\n outro(\"Post unpublished.\");\n\n const found = findPostByFile(posts, selected as string);\n return found ?? null;\n}\n\nasync function unpubPost(post: Post, deps: Deps) {\n const parsed = matter(post.content);\n const fm = parsed.data as Record<string, unknown>;\n fm[deps.config.draftKey] = true;\n const updatedContent = matter.stringify(parsed.content, fm);\n await deps.pfs.write(`${deps.config.blogDir}/${post.file}`, updatedContent);\n return { ...post, content: updatedContent };\n}\n","import { command } from \"cmd-ts\";\nimport { text, isCancel, intro, outro } from \"@clack/prompts\";\nimport type { Deps } from \"../lib/deps\";\n\nexport function makeInitCommand({ config, pfs }: Deps) {\n return command({\n name: \"init\",\n description: \"Create or update mkd.json configuration\",\n args: {},\n handler: async () => {\n intro(\"Initialize mkd configuration\");\n\n const blogDir = await text({\n message: \"Directory where generated posts are written\",\n defaultValue: String(config.blogDir ?? \"./src/blog\"),\n });\n if (isCancel(blogDir)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const author = await text({\n message: \"Default author\",\n defaultValue: String(config.author ?? \"\"),\n });\n if (isCancel(author)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const titleKey = await text({\n message: \"Title frontmatter key\",\n defaultValue: String(config.titleKey ?? \"title\"),\n });\n if (isCancel(titleKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const publishedAtKey = await text({\n message: \"Published date frontmatter key\",\n defaultValue: String(config.publishedAtKey ?? \"publishedAt\"),\n });\n if (isCancel(publishedAtKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const modifiedAtKey = await text({\n message: \"Modified date frontmatter key\",\n defaultValue: String(config.modifiedAtKey ?? \"updatedAt\"),\n });\n if (isCancel(modifiedAtKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const authorKey = await text({\n message: \"Author frontmatter key\",\n defaultValue: String(config.authorKey ?? \"author\"),\n });\n if (isCancel(authorKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const draftKey = await text({\n message: \"Draft frontmatter key\",\n defaultValue: String(config.draftKey ?? \"draft\"),\n });\n if (isCancel(draftKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const descriptionKey = await text({\n message: \"Description frontmatter key\",\n defaultValue: String(config.descriptionKey ?? \"description\"),\n });\n if (isCancel(descriptionKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const tagsKey = await text({\n message: \"Tags frontmatter key\",\n defaultValue: String(config.tagsKey ?? \"tags\"),\n });\n if (isCancel(tagsKey)) {\n outro(\"Init cancelled\");\n return;\n }\n\n const newConfig = {\n blogDir: String(blogDir),\n author: String(author),\n publishedAtKey: String(publishedAtKey),\n modifiedAtKey: String(modifiedAtKey),\n authorKey: String(authorKey),\n draftKey: String(draftKey),\n descriptionKey: String(descriptionKey),\n tagsKey: String(tagsKey),\n titleKey: String(titleKey),\n };\n\n await pfs.write(\"./mkd.json\", JSON.stringify(newConfig, null, 2) + \"\\n\");\n\n outro(\"Configuration saved to mkd.json\");\n },\n });\n}\n"],"mappings":"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","names":["command","isCancel","intro","outro","matter","matter","command","intro","isCancel","outro","matter","command","autocomplete","isCancel","intro","outro","matter","command","intro","autocomplete","isCancel","outro","matter","command","autocomplete","isCancel","intro","outro","matter","command","intro","autocomplete","isCancel","outro","matter","command","text","isCancel","intro","outro"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plttn/mkd",
3
- "version": "0.1.6",
3
+ "version": "0.2.1",
4
4
  "description": "A tool for managing markdown blog posts",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,6 +23,7 @@
23
23
  "author": "",
24
24
  "license": "MIT",
25
25
  "devDependencies": {
26
+ "@changesets/cli": "^2.31.0",
26
27
  "@types/node": "^25.9.1",
27
28
  "prettier": "3.8.3",
28
29
  "tsup": "^8.5.1",
@@ -41,8 +42,13 @@
41
42
  "type": "git",
42
43
  "url": "https://github.com/plttn/mkd.git"
43
44
  },
45
+ "publishConfig": {
46
+ "access": "public",
47
+ "provenance": true
48
+ },
44
49
  "scripts": {
45
50
  "dev": "tsx ./src/index.ts",
46
- "build": "tsup"
51
+ "build": "tsup",
52
+ "ci:publish": "pnpm build && changeset publish"
47
53
  }
48
54
  }