Skip to content

Commit f6f9f58

Browse files
authored
Merge pull request #6 from winstonwumbo/main
cli: Input validation and Commander.js scripting with themes
2 parents 1cdf645 + 69e11b8 commit f6f9f58

File tree

5 files changed

+78
-36
lines changed

5 files changed

+78
-36
lines changed

src/create.js

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ async function main() {
6161
.option('--content-scrape <char>', 'CSS Selector for `body` in resource')
6262
.option('--items-import <char>', 'import items from a file / site')
6363
.option('--recipe <char>', 'path to recipe file')
64+
.option('--custom-theme-name <char>', 'custom theme name')
65+
.option('--custom-theme-template <char>', 'custom theme template; (options: base, polaris-flex, polaris-sidebar)')
6466
.version(await HAXCMS.getHAXCMSVersion())
6567
.helpCommand(true);
6668

@@ -119,6 +121,8 @@ async function main() {
119121
.option('--content-scrape <char>', 'CSS Selector for `body` in resource')
120122
.option('--item-import <char>', 'import items from a file / site')
121123
.option('--recipe <char>', 'path to recipe file')
124+
.option('--custom-theme-name <char>', 'custom theme name')
125+
.option('--custom-theme-template <char>', 'custom theme template (options: base, polaris-flex, polaris-sidebar)')
122126
.version(await HAXCMS.getHAXCMSVersion());
123127
let siteNodeOps = siteNodeOperations();
124128
for (var i in siteNodeOps) {
@@ -203,6 +207,11 @@ async function main() {
203207
commandRun.options.author = author;
204208
}
205209
}
210+
// validate theme cli commands
211+
if (commandRun.options.theme !== 'custom-theme' && (commandRun.options.customThemeName || commandRun.options.customThemeTemplate)) {
212+
program.error(color.red('ERROR: You can only use the --custom-theme-name option with --theme custom-theme'));
213+
}
214+
206215
let packageData = {};
207216
let testPackages = [
208217
path.join(process.cwd(), 'package.json'),
@@ -332,6 +341,15 @@ async function main() {
332341
activeProject = project.type;
333342
// silly but this way we don't have to take options for quitting
334343
if (project.type !== 'quit') {
344+
// also silly temp spot
345+
let themes = await siteThemeList();
346+
const custom = {
347+
value: 'custom-theme',
348+
label: 'Create Custom Theme',
349+
}
350+
// Append custom option to list of core themes
351+
themes.push(custom);
352+
335353
project = await p.group(
336354
{
337355
type: ({ results }) => {
@@ -422,13 +440,6 @@ async function main() {
422440
}
423441
},
424442
theme: async({ results }) => {
425-
let themes = await siteThemeList();
426-
let custom = {
427-
value: 'custom-theme',
428-
label: 'Create Custom Theme',
429-
}
430-
themes.push(custom);
431-
432443
if (results.type === "site" && !commandRun.options.theme) {
433444
// support having no theme but autoselecting
434445
if (commandRun.options.auto && commandRun.options.skip) {
@@ -444,30 +455,34 @@ async function main() {
444455
}
445456
}
446457
},
447-
customName({ results }) {
458+
customThemeName: async ({ results }) => {
448459
if (results.theme === "custom-theme") {
449-
return p.text({
460+
let tmpCustomName = await p.text({
450461
message: 'Theme Name:',
451-
placeholder: results.theme,
462+
placeholder: `${results.name}`,
452463
required: false,
453464
validate: (value) => {
454465
if (!value) {
455-
return "Name is required (tab writes default)";
466+
return "Theme name is required (tab writes default)";
467+
}
468+
if(themes.some(theme => theme.value === value)) {
469+
return "Theme name is already in use";
456470
}
457471
if (/^\d/.test(value)) {
458-
return "Name cannot start with a number";
472+
return "Theme name cannot start with a number";
459473
}
460-
if (value.indexOf(' ') !== -1) {
461-
return "No spaces allowed in project name";
474+
if (/[A-Z]/.test(value)) {
475+
return "No uppercase letters allowed in theme name";
462476
}
463-
if (value.indexOf('-') === -1 && value.indexOf('-') !== 0 && value.indexOf('-') !== value.length - 1) {
464-
return "Name must include at least one `-` and must not start or end name.";
477+
if (value.indexOf(' ') !== -1) {
478+
return "No spaces allowed in theme name";
465479
}
466480
}
467481
})
482+
return tmpCustomName;
468483
}
469484
},
470-
customTemplate({ results }) {
485+
customThemeTemplate: ({ results }) => {
471486
if (results.theme === "custom-theme") {
472487
const options = [
473488
{ value: 'base', label: 'Vanilla Theme with Hearty Documentation' },

src/lib/programs/site.js

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,12 +1174,12 @@ export async function siteProcess(commandRun, project, port = '3000') { // au
11741174
}
11751175

11761176
// Write theme template to site/custom
1177-
if(project.customName && project.customTemplate) {
1178-
s.start(merlinSays(`Creating new theme: ${project.customName}`));
1177+
if(commandRun.options.theme === 'custom-theme' && commandRun.options.customThemeName && commandRun.options.customThemeTemplate || project.customThemeName && project.customThemeTemplate) {
1178+
s.start(merlinSays(`Creating new theme: ${commandRun.options.customThemeName ? commandRun.options.customThemeName : project.customThemeName}`));
11791179

11801180
await customSiteTheme(commandRun, project);
11811181

1182-
s.stop(merlinSays(`${project.customName} theme created!`));
1182+
s.stop(merlinSays(`${commandRun.options.customThemeName ? commandRun.options.customThemeName : project.customThemeName} theme created!`));
11831183
}
11841184

11851185
if (project.gitRepo && !commandRun.options.isMonorepo) {
@@ -1253,19 +1253,43 @@ export async function siteThemeList() {
12531253
}
12541254

12551255
async function customSiteTheme(commandRun, project) {
1256-
project.className = dashToCamel(project.customName);
1257-
var sitePath = `${project.path}/${project.name}`;
1256+
// pass theme name for twig templates
1257+
project.customThemeName = commandRun.options.customThemeName ? commandRun.options.customThemeName : project.customThemeName;
12581258

1259-
const filePath = `${sitePath}/custom/src/${project.customName}.js`;
1260-
if(project.customTemplate === "base"){
1261-
await fs.copyFileSync(`${process.mainModule.path}/templates/sitetheme/base-theme.js`, `${sitePath}/custom/src/base-theme.js`)
1262-
await fs.renameSync(`${sitePath}/custom/src/base-theme.js`, filePath)
1263-
} else if(project.customTemplate === "polaris-flex") {
1259+
// validate start and end tags for theme name
1260+
if(/^custom/.test(project.customThemeName) && !/^custom-/.test(project.customThemeName)){
1261+
project.customThemeName = project.customThemeName.replace(/^custom/, "custom-");
1262+
} else if (!/^custom-/.test(project.className)) {
1263+
project.customThemeName = `custom-${project.customThemeName}`;
1264+
}
1265+
1266+
if(/theme$/.test(project.customThemeName) && !/-theme$/.test(project.customThemeName)){
1267+
project.customThemeName = project.customThemeName.replace(/theme$/, "-theme");
1268+
} else if (!/-theme$/.test(project.customThemeName)) {
1269+
project.customThemeName = `${project.customThemeName}-theme`;
1270+
}
1271+
1272+
// set camel case class name
1273+
project.className = dashToCamel(project.customThemeName);
1274+
1275+
// path to hax site
1276+
var sitePath = `${project.path}/${commandRun.options.name ? commandRun.options.name : project.name}`;
1277+
1278+
// path to new theme file
1279+
const filePath = `${sitePath}/custom/src/${project.customThemeName}.js`;
1280+
1281+
// theme template to use
1282+
const themeTemplate = commandRun.options.customThemeTemplate ? commandRun.options.customThemeTemplate : project.customThemeTemplate;
1283+
if(themeTemplate === "polaris-flex") {
12641284
await fs.copyFileSync(`${process.mainModule.path}/templates/sitetheme/flex-theme.js`, `${sitePath}/custom/src/flex-theme.js`)
12651285
await fs.renameSync(`${sitePath}/custom/src/flex-theme.js`, filePath)
1266-
} else if(project.customTemplate === "polaris-sidebar") {
1286+
} else if(themeTemplate === "polaris-sidebar") {
12671287
await fs.copyFileSync(`${process.mainModule.path}/templates/sitetheme/sidebar-theme.js`, `${sitePath}/custom/src/sidebar-theme.js`)
12681288
await fs.renameSync(`${sitePath}/custom/src/sidebar-theme.js`, filePath)
1289+
} else {
1290+
// vanilla theme is default
1291+
await fs.copyFileSync(`${process.mainModule.path}/templates/sitetheme/base-theme.js`, `${sitePath}/custom/src/base-theme.js`)
1292+
await fs.renameSync(`${sitePath}/custom/src/base-theme.js`, filePath)
12691293
}
12701294

12711295
try {
@@ -1281,18 +1305,21 @@ async function customSiteTheme(commandRun, project) {
12811305
console.error(err);
12821306
}
12831307

1284-
await fs.appendFileSync(`${sitePath}/custom/src/custom.js`, `\n import "./${project.customName}.js"`);
1308+
// import theme to custom.js
1309+
await fs.appendFileSync(`${sitePath}/custom/src/custom.js`, `\n import "./${project.customThemeName}.js"`);
12851310
var activeHaxsite = await hax.systemStructureContext(sitePath);
12861311

1312+
// add theme to site.json
12871313
let themeObj = {
1288-
element: project.customName,
1314+
element: project.customThemeName,
12891315
path: filePath,
12901316
name: project.className,
12911317
}
12921318

12931319
activeHaxsite.manifest.metadata.theme = themeObj;
12941320
activeHaxsite.manifest.save(false);
12951321

1322+
// install and build theme dependencies
12961323
await exec(`cd ${sitePath}/custom/ && ${commandRun.options.npmClient} install && ${commandRun.options.npmClient} run build && cd ${sitePath}`);
12971324
}
12981325

src/templates/sitetheme/base-theme.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { html, css, HAXCMSLitElementTheme } from "@haxtheweb/haxcms-elements/lib
1414
* - HAXCMSTheme - A super class that provides correct baseline wiring to build a new theme
1515
*
1616
* @demo demo/index.html
17-
* @element <%= customName %>
17+
* @element <%= customThemeName %>
1818
*/
1919
class <%= className %> extends HAXCMSLitElementTheme {
2020
//styles function
@@ -34,7 +34,7 @@ class <%= className %> extends HAXCMSLitElementTheme {
3434
* @notice function name must be here for tooling to operate correctly
3535
*/
3636
static get tag() {
37-
return "<%= customName %>";
37+
return "<%= customThemeName %>";
3838
}
3939

4040
constructor() {

src/templates/sitetheme/flex-theme.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import "@haxtheweb/haxcms-elements/lib/ui-components/blocks/site-children-block.
1616
* - HAXCMSTheme - A super class that provides correct baseline wiring to build a new theme
1717
*
1818
* @demo demo/index.html
19-
* @element <%= customName %>
19+
* @element <%= customThemeName %>
2020
*/
2121
class <%= className %> extends PolarisFlexTheme {
2222
//styles function
@@ -55,7 +55,7 @@ class <%= className %> extends PolarisFlexTheme {
5555
* @notice function name must be here for tooling to operate correctly
5656
*/
5757
static get tag() {
58-
return "<%= customName %>";
58+
return "<%= customThemeName %>";
5959
}
6060

6161
constructor() {

src/templates/sitetheme/sidebar-theme.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import "@haxtheweb/haxcms-elements/lib/ui-components/blocks/site-children-block.
1616
* - HAXCMSTheme - A super class that provides correct baseline wiring to build a new theme
1717
*
1818
* @demo demo/index.html
19-
* @element <%= customName %>
19+
* @element <%= customThemeName %>
2020
*/
2121
class <%= className %> extends PolarisFlexTheme {
2222
//styles function
@@ -101,7 +101,7 @@ class <%= className %> extends PolarisFlexTheme {
101101
* @notice function name must be here for tooling to operate correctly
102102
*/
103103
static get tag() {
104-
return "<%= customName %>";
104+
return "<%= customThemeName %>";
105105
}
106106

107107
constructor() {

0 commit comments

Comments
 (0)