Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(scaffold): add prompts for scaffold template #529

Merged
merged 5 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/pages/src/scaffold/scaffold.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Command } from "commander";
import { modulesCommand } from "./modules/modules.js";
import { templateCommand } from "./template/template.js";

export const scaffoldCommand = (program: Command) => {
const scaffold = program
Expand All @@ -16,4 +17,5 @@ export const scaffoldCommand = (program: Command) => {
console.log('Must provide a subcommand of "scaffold".');
});
modulesCommand(scaffold);
templateCommand(scaffold);
};
117 changes: 117 additions & 0 deletions packages/pages/src/scaffold/template/generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import prompts, { PromptObject } from "prompts";
import { ProjectStructure } from "../../common/src/project/structure.js";
import path from "node:path";
import fs from "node:fs";

/* eslint-disable @typescript-eslint/no-unused-vars */
// TODO: Remove after using adding generation code for templates

export const generateTemplate = async (
projectStructure: ProjectStructure
): Promise<void> => {
const questions: PromptObject[] = [
{
type: "text",
name: "templateName",
message: "What would you like to name your Template?",
validate: (templateName) =>
validateTemplateName(templateName, projectStructure) ||
"Please ensure the name provided isn't already used and is valid.",
},
{
type: "confirm",
name: "isVisualEditor",
message: "Is this a Visual Editor template?",
initial: true,
},
{
type: (prev) => (prev ? null : "toggle"),
name: "isDynamic",
message: "Is this a static or dynamic template?",
initial: true,
active: "Dynamic",
inactive: "Static",
},
{
type: (prev) => (prev ? "select" : null),
name: "entityScope",
message:
"How would you like you to define the entity scope for your template?",
choices: [
{ title: "Entity Type", value: "entityTypes" },
{ title: "Static", value: "static" },
asanehisa marked this conversation as resolved.
Show resolved Hide resolved
{ title: "Filter", value: "savedFilterIds" },
{ title: "Entity Id", value: "entityIds" },
],
},
{
type: (prev, values) =>
values.entityScope === "entityTypes" ? "list" : null,
name: "filter",
message: "Enter the entity type(s):",
initial: "",
separator: ",",
},
{
type: (prev, values) =>
values.entityScope === "savedFilterIds" ? "list" : null,
name: "filter",
message: "Enter the saved filter ID(s):",
initial: "",
separator: ",",
},
{
type: (prev, values) =>
values.entityScope === "entityIds" ? "list" : null,
name: "filter",
message: "Enter the entity ID(s):",
initial: "",
separator: ",",
},
];

const response = await prompts(questions);

// TODO (SUMO-5251): handle generating VE templates
// TODO (SUMO-5252): handle generating non-VE templates
};

// Returns true if templateName can be formatted into valid filename and that filename isn't being used.
const validateTemplateName = (
asanehisa marked this conversation as resolved.
Show resolved Hide resolved
templateName: string,
projectStructure: ProjectStructure
): boolean => {
const formattedFileName = formatFileName(templateName);

// Must start with an alphabetic char
if (/^[^a-zA-Z]/.test(formattedFileName)) {
return false;
}

const templatePath = path.join(
projectStructure.getTemplatePaths()[0].path,
formattedFileName
);
if (fs.existsSync(templatePath)) {
return false;
}

return true;
};

const formatFileName = (templateName: string): string => {
asanehisa marked this conversation as resolved.
Show resolved Hide resolved
const specialCharsRemoved = templateName.replace(/[^a-zA-Z0-9\s]+/g, "");

const words = specialCharsRemoved.split(" ");
if (words.length === 0) {
return "";
}

let fileName = words[0].toLowerCase();
for (let i = 1; i < words.length; i++) {
fileName +=
words[i].charAt(0).toUpperCase() + words[i].slice(1).toLowerCase();
}

return fileName;
};
24 changes: 24 additions & 0 deletions packages/pages/src/scaffold/template/template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Command } from "commander";
import { logErrorAndExit } from "../../util/logError.js";
import { ProjectStructure } from "../../common/src/project/structure.js";
import { generateTemplate } from "./generate.js";

const handler = async () => {
const scope = process.env.YEXT_PAGES_SCOPE;
const projectStructure = await ProjectStructure.init({ scope });
try {
await generateTemplate(projectStructure);
} catch (error) {
logErrorAndExit(error);
}
process.exit(0);
};

export const templateCommand = (program: Command) => {
program
.command("template")
.description(
"Adds the required files and folder structure for a new Pages template."
)
.action(handler);
};
Loading