The .kenvs/snippets
directory is now deprecated in favor of Scriptlets.
This script migrates your previous txt-based snippets to the new syntax.
USE AT YOUR OWN RISK! Best create a backup of the snippets directory before running it!
Open migrate-snippets-to-scriptlets in Script Kit
import "@johnlindquist/kit"import { parseMetadata } from "@johnlindquist/kit"metadata = {name: "Migrate Snippets to Scriptlets",description: "Reads your legacy snippets folder and migrates them to the new markdown-based scriptlets syntax",author: "JosXa",}const snippetsDir = kenvPath("snippets")const snippetFiles = await readdir(snippetsDir, { encoding: "utf8", recursive: false })const scriptletParts = ["# Migrated Snippets"]const skippedFiles = [] as { fileName: string; reason: string }[]const filesToDelete = [] as string[]for (const fileName of snippetFiles) {try {if (!fileName.endsWith(".txt")) {skippedFiles.push({ fileName, reason: "it is not a .txt file" })continue}const fileContent = await readFile(path.join(snippetsDir, fileName), { encoding: "utf8" })const contentRegex = /(?:\/\/.*\r?\n)*([\s\S]+)$/const text = fileContent.match(contentRegex)?.[1]?.trim()if (!text) {skippedFiles.push({ fileName, reason: "no expand text was found" })continue}// @ts-expect-error Typings bugconst { name: metadataName, snippet, expand, type: _, ...rest } = parseMetadata(fileContent)const name = metadataName ?? path.parse(fileName).nameconst expandMetadata = expand ?? snippetif (!expandMetadata) {skippedFiles.push({ fileName, reason: `no "// Expand" or "// Snippet" metadata was found` })continue}scriptletParts.push(`## ${name}`)const metadataStr = [] as string[]metadataStr.push(`Expand: ${expandMetadata}`)for (const [key, value] of Object.entries(rest)) {metadataStr.push(`${titleCase(key)}: ${value}`)}scriptletParts.push(`<!--\n${metadataStr.join("\n")}\n-->`)const sanitizedText = text.replaceAll("~~~", "```")scriptletParts.push(`~~~paste\n${sanitizedText}\n\~~~\n`)filesToDelete.push(path.join(snippetsDir, fileName))} catch (err) {skippedFiles.push({ fileName, reason: `an error occurred: ${err}` })}}const finalScriptlet = scriptletParts.join("\n\n")const outFile = kenvPath("scriptlets", "migrated-snippets.md")if (await pathExists(outFile)) {const choice = await select<"Abort" | "Yes">({ hint: `File at ${outFile} already exists! Overwrite it?`, strict: true, multiple: false },["[A]bort", "[Y]es"],)if (choice === "Abort") {exit()}await unlink(outFile)}await writeFile(outFile, finalScriptlet)await edit(outFile)await rm(filesToDelete)function titleCase(str: string) {return str.slice(0, 1).toUpperCase() + str.slice(1)}if (skippedFiles.length > 0) {await div(md(`Skipped ${skippedFiles.length} files:\n\n${skippedFiles.map((x) => `- <b>${x.fileName}</b> because ${x.reason}`).join("\n")}`,),)} else if (skippedFiles.length === 0) {await div(md("All files migrated successfully, yay!"))try {await rmdir(snippetsDir, { recursive: true })} catch (err) {console.error(err)}}