From c1a51f45bfc489a7e4e2acb60e05abbc401e2bd4 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 8 Oct 2025 11:35:05 +1100 Subject: [PATCH] Fixing some bugs in the update script --- README.collections.md | 2 +- update-readme.js | 124 +++++++++++++++++++++++++++++------------- 2 files changed, 88 insertions(+), 38 deletions(-) diff --git a/README.collections.md b/README.collections.md index 40f94bb..4b2df4e 100644 --- a/README.collections.md +++ b/README.collections.md @@ -20,11 +20,11 @@ Curated collections of related prompts, instructions, and chat modes organized a | [Clojure Interactive Programming](collections/clojure-interactive-programming.md) | Tools for REPL-first Clojure workflows featuring Clojure instructions, the interactive programming chat mode and supporting guidance. | 3 items | clojure, repl, interactive-programming | | [Database & Data Management](collections/database-data-management.md) | Database administration, SQL optimization, and data management tools for PostgreSQL, SQL Server, and general database development best practices. | 8 items | database, sql, postgresql, sql-server, dba, optimization, queries, data-management | | [DevOps On-Call](collections/devops-oncall.md) | A focused set of prompts, instructions, and a chat mode to help triage incidents and respond quickly with DevOps tools and Azure resources. | 5 items | devops, incident-response, oncall, azure | -| [Tasks by microsoft/edge-ai](collections/edge-ai-tasks.md) | Task Researcher and Task Planner for intermediate to expert users and large codebases - Brought to you by microsoft/edge-ai | 3 items | architecture, planning, research, tasks, implementation | | [Frontend Web Development](collections/frontend-web-dev.md) | Essential prompts, instructions, and chat modes for modern frontend web development including React, Angular, Vue, TypeScript, and CSS frameworks. | 11 items | frontend, web, react, typescript, javascript, css, html, angular, vue | | [Java Development](collections/java-development.md) | Comprehensive collection of prompts and instructions for Java development including Spring Boot, Quarkus, testing, documentation, and best practices. | 12 items | java, springboot, quarkus, jpa, junit, javadoc | | [Power Apps Code Apps Development](collections/power-apps-code-apps.md) | Complete toolkit for Power Apps Code Apps development including project scaffolding, development standards, and expert guidance for building code-first applications with Power Platform integration. | 3 items | power-apps, power-platform, typescript, react, code-apps, dataverse, connectors | | [Project Planning & Management](collections/project-planning.md) | Tools and guidance for software project planning, feature breakdown, epic management, implementation planning, and task organization for development teams. | 17 items | planning, project-management, epic, feature, implementation, task, architecture, technical-spike | | [Security & Code Quality](collections/security-best-practices.md) | Security frameworks, accessibility guidelines, performance optimization, and code quality best practices for building secure, maintainable, and high-performance applications. | 6 items | security, accessibility, performance, code-quality, owasp, a11y, optimization, best-practices | +| [Tasks by microsoft/edge-ai](collections/edge-ai-tasks.md) | Task Researcher and Task Planner for intermediate to expert users and large codebases - Brought to you by microsoft/edge-ai | 3 items | architecture, planning, research, tasks, implementation | | [Technical Spike](collections/technical-spike.md) | Tools for creation, management and research of technical spikes to reduce unknowns and assumptions before proceeding to specification and implementation of solutions. | 2 items | technical-spike, assumption-testing, validation, research | | [Testing & Test Automation](collections/testing-automation.md) | Comprehensive collection for writing tests, test automation, and test-driven development including unit tests, integration tests, and end-to-end testing strategies. | 11 items | testing, tdd, automation, unit-tests, integration, playwright, jest, nunit | diff --git a/update-readme.js b/update-readme.js index 8e9475e..d6ce2da 100755 --- a/update-readme.js +++ b/update-readme.js @@ -142,7 +142,10 @@ function extractTitle(filePath) { // Track code blocks to ignore headings inside them if (frontmatterEnded2) { - if (line.trim().startsWith("```") || line.trim().startsWith("````")) { + if ( + line.trim().startsWith("```") || + line.trim().startsWith("````") + ) { inCodeBlock = !inCodeBlock; continue; } @@ -156,7 +159,10 @@ function extractTitle(filePath) { // No frontmatter, look for first heading (but not in code blocks) let inCodeBlock = false; for (const line of lines) { - if (line.trim().startsWith("```") || line.trim().startsWith("````")) { + if ( + line.trim().startsWith("```") || + line.trim().startsWith("````") + ) { inCodeBlock = !inCodeBlock; continue; } @@ -260,7 +266,9 @@ function extractDescription(filePath) { let description = descriptionMatch[1]; // Check if the description is wrapped in single quotes and handle escaped quotes - const singleQuoteMatch = line.match(/^description:\s*'(.+?)'\s*$/); + const singleQuoteMatch = line.match( + /^description:\s*'(.+?)'\s*$/ + ); if (singleQuoteMatch) { // Replace escaped single quotes ('') with single quotes (') description = singleQuoteMatch[1].replace(/''/g, "'"); @@ -308,8 +316,12 @@ const AKA_INSTALL_URLS = { function makeBadges(link, type) { const aka = AKA_INSTALL_URLS[type] || AKA_INSTALL_URLS.instructions; - const vscodeUrl = `${aka}?url=${encodeURIComponent(`vscode:chat-${type}/install?url=${repoBaseUrl}/${link}`)}`; - const insidersUrl = `${aka}?url=${encodeURIComponent(`vscode-insiders:chat-${type}/install?url=${repoBaseUrl}/${link}`)}`; + const vscodeUrl = `${aka}?url=${encodeURIComponent( + `vscode:chat-${type}/install?url=${repoBaseUrl}/${link}` + )}`; + const insidersUrl = `${aka}?url=${encodeURIComponent( + `vscode-insiders:chat-${type}/install?url=${repoBaseUrl}/${link}` + )}`; return `[![Install in VS Code](${vscodeInstallImage})](${vscodeUrl})
[![Install in VS Code Insiders](${vscodeInsidersInstallImage})](${insidersUrl})`; } @@ -405,8 +417,7 @@ function generatePromptsSection(promptsDir) { } // Create table header - let promptsContent = - "| Title | Description |\n| ----- | ----------- |\n"; + let promptsContent = "| Title | Description |\n| ----- | ----------- |\n"; // Generate table rows for each prompt file for (const entry of promptEntries) { @@ -462,8 +473,7 @@ function generateChatModesSection(chatmodesDir) { } // Create table header - let chatmodesContent = - "| Title | Description |\n| ----- | ----------- |\n"; + let chatmodesContent = "| Title | Description |\n| ----- | ----------- |\n"; // Generate table rows for each chat mode file for (const entry of chatmodeEntries) { @@ -502,19 +512,22 @@ function generateCollectionsSection(collectionsDir) { .filter((file) => file.endsWith(".collection.yml")); // Map collection files to objects with name for sorting - const collectionEntries = collectionFiles.map((file) => { - const filePath = path.join(collectionsDir, file); - const collection = parseCollectionYaml(filePath); + const collectionEntries = collectionFiles + .map((file) => { + const filePath = path.join(collectionsDir, file); + const collection = parseCollectionYaml(filePath); - if (!collection) { - console.warn(`Failed to parse collection: ${file}`); - return null; - } + if (!collection) { + console.warn(`Failed to parse collection: ${file}`); + return null; + } - const collectionId = collection.id || path.basename(file, ".collection.yml"); - const name = collection.name || collectionId; - return { file, filePath, collection, collectionId, name }; - }).filter(entry => entry !== null); // Remove failed parses + const collectionId = + collection.id || path.basename(file, ".collection.yml"); + const name = collection.name || collectionId; + return { file, filePath, collection, collectionId, name }; + }) + .filter((entry) => entry !== null); // Remove failed parses // Sort by name alphabetically collectionEntries.sort((a, b) => a.name.localeCompare(b.name)); @@ -584,14 +597,24 @@ function generateCollectionReadme(collection, collectionId) { const title = extractTitle(filePath); const description = extractDescription(filePath) || "No description"; - const typeDisplay = item.kind === "chat-mode" ? "Chat Mode" : - item.kind === "instruction" ? "Instruction" : "Prompt"; + const typeDisplay = + item.kind === "chat-mode" + ? "Chat Mode" + : item.kind === "instruction" + ? "Instruction" + : "Prompt"; const link = `../${item.path}`; // Create install badges for each item - const badges = makeBadges(item.path, item.kind === "instruction" ? "instructions" : - item.kind === "chat-mode" ? "mode" : "prompt"); - + const badges = makeBadges( + item.path, + item.kind === "instruction" + ? "instructions" + : item.kind === "chat-mode" + ? "mode" + : "prompt" + ); + const usageDescription = item.usage ? `${description} [see usage](#${title .replace(/\s+/g, "-") @@ -601,8 +624,11 @@ function generateCollectionReadme(collection, collectionId) { content += `| [${title}](${link})
${badges} | ${typeDisplay} | ${usageDescription} |\n`; // Generate Usage section for each collection if (item.usage && item.usage.trim()) { - collectionUsageContent.push(`### ${title}\n\n${item.usage.trim()}\n\n---\n\n`); + collectionUsageContent.push( + `### ${title}\n\n${item.usage.trim()}\n\n---\n\n` + ); } + } // Append the usage section if any items had usage defined if (collectionUsageContent.length > 0) { @@ -611,10 +637,11 @@ function generateCollectionReadme(collection, collectionId) { content += "\n---\n"; } - // Optional badge note at the end if show_badge is true if (collection.display?.show_badge) { - content += `*This collection includes ${items.length} curated items for ${name.toLowerCase()}.*`; + content += `*This collection includes ${ + items.length + } curated items for ${name.toLowerCase()}.*`; } return content; @@ -626,12 +653,16 @@ function writeFileIfChanged(filePath, content) { if (exists) { const original = fs.readFileSync(filePath, "utf8"); if (original === content) { - console.log(`${path.basename(filePath)} is already up to date. No changes needed.`); + console.log( + `${path.basename(filePath)} is already up to date. No changes needed.` + ); return; } } fs.writeFileSync(filePath, content); - console.log(`${path.basename(filePath)} ${exists ? "updated" : "created"} successfully!`); + console.log( + `${path.basename(filePath)} ${exists ? "updated" : "created"} successfully!` + ); } // Build per-category README content using existing generators, upgrading headings to H1 @@ -655,10 +686,16 @@ try { const collectionsDir = path.join(__dirname, "collections"); // Compose headers for standalone files by converting section headers to H1 - const instructionsHeader = TEMPLATES.instructionsSection.replace(/^##\s/m, "# "); + const instructionsHeader = TEMPLATES.instructionsSection.replace( + /^##\s/m, + "# " + ); const promptsHeader = TEMPLATES.promptsSection.replace(/^##\s/m, "# "); const chatmodesHeader = TEMPLATES.chatmodesSection.replace(/^##\s/m, "# "); - const collectionsHeader = TEMPLATES.collectionsSection.replace(/^##\s/m, "# "); + const collectionsHeader = TEMPLATES.collectionsSection.replace( + /^##\s/m, + "# " + ); const instructionsReadme = buildCategoryReadme( generateInstructionsSection, @@ -688,10 +725,19 @@ try { ); // Write category outputs - writeFileIfChanged(path.join(__dirname, "README.instructions.md"), instructionsReadme); + writeFileIfChanged( + path.join(__dirname, "README.instructions.md"), + instructionsReadme + ); writeFileIfChanged(path.join(__dirname, "README.prompts.md"), promptsReadme); - writeFileIfChanged(path.join(__dirname, "README.chatmodes.md"), chatmodesReadme); - writeFileIfChanged(path.join(__dirname, "README.collections.md"), collectionsReadme); + writeFileIfChanged( + path.join(__dirname, "README.chatmodes.md"), + chatmodesReadme + ); + writeFileIfChanged( + path.join(__dirname, "README.collections.md"), + collectionsReadme + ); // Generate individual collection README files if (fs.existsSync(collectionsDir)) { @@ -706,8 +752,12 @@ try { const collection = parseCollectionYaml(filePath); if (collection) { - const collectionId = collection.id || path.basename(file, ".collection.yml"); - const readmeContent = generateCollectionReadme(collection, collectionId); + const collectionId = + collection.id || path.basename(file, ".collection.yml"); + const readmeContent = generateCollectionReadme( + collection, + collectionId + ); const readmeFile = path.join(collectionsDir, `${collectionId}.md`); writeFileIfChanged(readmeFile, readmeContent); }