feature: First build

This commit is contained in:
Keith Solomon
2026-01-26 08:24:46 -06:00
parent 27511d8ec0
commit d6df4c18a2
6 changed files with 240 additions and 10 deletions

156
src/extension.ts Normal file
View File

@@ -0,0 +1,156 @@
import * as path from "path";
import { promises as fs } from "fs";
import * as vscode from "vscode";
const OUTPUT_CHANNEL = vscode.window.createOutputChannel("VDI ACF Block Scaffold");
export function activate(context: vscode.ExtensionContext): void {
const command = vscode.commands.registerCommand(
"vdi-acf-block-scaffold.createBlock",
async () => {
try {
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
if (!workspaceFolder) {
vscode.window.showErrorMessage("Open a workspace folder first.");
return;
}
const blockNameInput = await vscode.window.showInputBox({
prompt: "Enter the new block name",
placeHolder: "Testimonial",
validateInput: (value) => {
if (!value || !value.trim()) {
return "Block name is required.";
}
return null;
}
});
if (!blockNameInput) {
return;
}
const blockName = blockNameInput.trim();
const blockSlug = toSlug(blockName);
if (!blockSlug) {
vscode.window.showErrorMessage(
"Block name must include at least one letter or number."
);
return;
}
const config = vscode.workspace.getConfiguration("vdiAcfBlockScaffold");
const parentSetting = config.get<string>(
"parentDirectory",
"views/blocks"
);
const parentDir = path.isAbsolute(parentSetting)
? parentSetting
: path.join(workspaceFolder.uri.fsPath, parentSetting);
const targetDir = path.join(parentDir, blockSlug);
if (await pathExists(targetDir)) {
vscode.window.showErrorMessage(
`A block named "${blockSlug}" already exists.`
);
return;
}
const templateDir = path.join(context.extensionPath, "block-template");
if (!(await pathExists(templateDir))) {
vscode.window.showErrorMessage(
"Block template folder is missing from the extension."
);
return;
}
await fs.mkdir(targetDir, { recursive: true });
const templateEntries = await fs.readdir(templateDir, {
withFileTypes: true
});
for (const entry of templateEntries) {
if (!entry.isFile()) {
continue;
}
const sourcePath = path.join(templateDir, entry.name);
const content = await fs.readFile(sourcePath, "utf8");
const replaced = content
.replace(/{{BLOCK_NAME}}/g, blockName)
.replace(/{{BLOCK_SLUG}}/g, blockSlug);
const destinationName = mapTemplateFileName(entry.name, blockSlug);
const destinationPath = path.join(targetDir, destinationName);
if (await pathExists(destinationPath)) {
vscode.window.showErrorMessage(
`File already exists: ${destinationName}`
);
return;
}
await fs.writeFile(destinationPath, replaced, "utf8");
}
await openCreatedFiles(targetDir, blockSlug);
vscode.window.showInformationMessage(
`Created ACF block: ${blockName}`
);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
OUTPUT_CHANNEL.appendLine(message);
vscode.window.showErrorMessage(
"Failed to create ACF block. See output for details."
);
}
}
);
context.subscriptions.push(command, OUTPUT_CHANNEL);
}
export function deactivate(): void {
OUTPUT_CHANNEL.dispose();
}
function toSlug(value: string): string {
return value
.toLowerCase()
.trim()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
function mapTemplateFileName(filename: string, slug: string): string {
if (filename === "block-template.php") {
return `${slug}.php`;
}
if (filename === "block-template.css") {
return `${slug}.css`;
}
return filename;
}
async function openCreatedFiles(dir: string, slug: string): Promise<void> {
const filesToOpen = ["block.json", `${slug}.php`, `${slug}.css`];
for (const filename of filesToOpen) {
const filePath = path.join(dir, filename);
if (!(await pathExists(filePath))) {
continue;
}
const doc = await vscode.workspace.openTextDocument(filePath);
await vscode.window.showTextDocument(doc, { preview: false });
}
}
async function pathExists(targetPath: string): Promise<boolean> {
try {
await fs.access(targetPath);
return true;
} catch {
return false;
}
}