Skip to content

Commit

Permalink
feat: the bookshop/init command can now create new Bookshop projects
Browse files Browse the repository at this point in the history
  • Loading branch information
bglw committed Apr 5, 2022
1 parent 853bd11 commit 824de51
Show file tree
Hide file tree
Showing 16 changed files with 269 additions and 29 deletions.
5 changes: 5 additions & 0 deletions javascript-modules/init/lib/templates/bookshop-config.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
engines: {
"@bookshop/<%= ssg %>-engine": {}
}
}
6 changes: 4 additions & 2 deletions javascript-modules/init/lib/templates/bookshop-js.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ module.exports = () => {
structures: [
"content_blocks"
],
label: "",
label: "<%= componentLabel %>",
description: "",
icon: "",
tags: []
};

// <%= blueprintComment %>
const blueprint = {};
const blueprint = {
text = "Hello World!"
};

// <%= previewComment %>
const preview = {};
Expand Down
6 changes: 4 additions & 2 deletions javascript-modules/init/lib/templates/bookshop-json.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
"structures": [
"content_blocks"
],
"label": "",
"label": "<%= componentLabel %>",
"description": "",
"icon": "",
"tags": []
},
"blueprint": {},
"blueprint": {
"text": "Hello World!"
},
"preview": {},
"_inputs": {}
}
3 changes: 2 additions & 1 deletion javascript-modules/init/lib/templates/bookshop-toml.ejs.t
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# <%= specComment %>
[spec]
structures = [ "content_blocks" ]
label = ""
label = "<%= componentLabel %>"
description = ""
icon = ""
tags = []

# <%= blueprintComment %>
[blueprint]
text = "Hello World!"

# <%= previewComment %>
[preview]
Expand Down
3 changes: 2 additions & 1 deletion javascript-modules/init/lib/templates/bookshop-yml.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
spec:
structures:
- content_blocks
label:
label: "<%= componentLabel %>"
description:
icon:
tags: []

# <%= blueprintComment %>
blueprint:
text: "Hello World!"

# <%= previewComment %>
preview:
Expand Down
1 change: 1 addition & 0 deletions javascript-modules/init/lib/templates/eleventy.ejs.t
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<div class="c-<%= componentName %>">
<p>{{ text }}</p>
</div>
6 changes: 6 additions & 0 deletions javascript-modules/init/lib/templates/global-style.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Files in shared/styles will be used as global stylesheets on your site,
// as well as in the component browser and screenshots.

html, body {

}
11 changes: 11 additions & 0 deletions javascript-modules/init/lib/templates/hugo-config.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[module]
hugoVersion.extended = true
hugoVersion.min = "0.86.1"

[[module.mounts]]
source = "."
target = "layouts/partials/bookshop"

[[module.mounts]]
source = "."
target = "assets/bookshop"
1 change: 1 addition & 0 deletions javascript-modules/init/lib/templates/hugo.ejs.t
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<div class="c-<%= componentName %>">
<p>{{ .text }}</p>
</div>
1 change: 1 addition & 0 deletions javascript-modules/init/lib/templates/jekyll.ejs.t
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<div class="c-<%= componentName %>">
<p>{{ include.text }}</p>
</div>
9 changes: 9 additions & 0 deletions javascript-modules/init/lib/templates/page-eleventy.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div>
{% for block in content_blocks %}
{% comment %}
# The bind parameter here passes the inner fields of block to the component.
# Imagine it like the ...spread operator in JavaScript.
{% endcomment %}
{% bookshop "{{block._bookshop_name}}" bind: block %}
{% endfor %}
</div>
5 changes: 5 additions & 0 deletions javascript-modules/init/lib/templates/page-hugo.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div>
{{ range . }}
{{ partial "bookshop" . }}
{{ end }}
</div>
9 changes: 9 additions & 0 deletions javascript-modules/init/lib/templates/page-jekyll.ejs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div>
{% for block in include.content_blocks %}
{% comment %}
# The bind parameter here passes the inner fields of block to the component.
# Imagine it like the ...spread operator in JavaScript.
{% endcomment %}
{% bookshop {{block._bookshop_name}} bind=block %}
{% endfor %}
</div>
27 changes: 27 additions & 0 deletions javascript-modules/init/lib/templates/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ export const eleventy = {
extension: 'eleventy.liquid'
};

export const jekyll_page = {
render: ejs.compile(readFileSync(join(__dirname, "page-jekyll.ejs.t"), 'utf8')),
extension: 'jekyll.html'
};

export const hugo_page = {
render: ejs.compile(readFileSync(join(__dirname, "page-hugo.ejs.t"), 'utf8')),
extension: 'hugo.html'
};

export const eleventy_page = {
render: ejs.compile(readFileSync(join(__dirname, "page-eleventy.ejs.t"), 'utf8')),
extension: 'eleventy.liquid'
};

export const svelte = {
render: ejs.compile(readFileSync(join(__dirname, "svelte.ejs.t"), 'utf8')),
extension: 'svelte'
Expand Down Expand Up @@ -47,4 +62,16 @@ export const bookshop_js = {
export const bookshop_json = {
render: ejs.compile(readFileSync(join(__dirname, "bookshop-json.ejs.t"), 'utf8')),
extension: 'bookshop.json'
};

export const bookshop_config = {
render: ejs.compile(readFileSync(join(__dirname, "bookshop-config.ejs.t"), 'utf8')),
};

export const hugo_config = {
render: ejs.compile(readFileSync(join(__dirname, "hugo-config.ejs.t"), 'utf8')),
};

export const global_style = {
render: ejs.compile(readFileSync(join(__dirname, "global-style.ejs.t"), 'utf8')),
};
161 changes: 138 additions & 23 deletions javascript-modules/init/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const getComponentName = (path) => {
return path.replace(/\//g, "-");
}

const getComponentLabel = (path) => {
return path.split('/').map(s => s[0].toUpperCase() + s.substr(1)).join(' ');
}

const getComponentFileName = (path) => {
return path.split("/").reverse()[0];
}
Expand Down Expand Up @@ -103,7 +107,7 @@ const initComponent = async (options) => {
const resp = await inquirer.prompt([{
type: 'list',
name: 'format',
message: 'What configuration format would you like to use?',
message: 'What configuration format would you like to use for components?',
choices: ['YAML (Recommended)', 'TOML', 'JS', 'JSON'],
filter(val) {
return val.split(' ')[0].toLowerCase().replace(/yaml/, 'yml');
Expand All @@ -117,18 +121,19 @@ const initComponent = async (options) => {
mkdirSync(componentDirPath, { recursive: true });

const componentName = getComponentName(options.component);
const componentLabel = getComponentLabel(options.component);
const componentFileName = getComponentFileName(options.component);

for (const framework of frameworks) {
const template = templates[framework];
if (!template) {
const allowed = Object.keys(templates).filter(f => !/scss|bookshop/.test(f));
const allowed = ['hugo', 'eleventy', 'jekyll'];
console.error(chalk.red(`Unrecognized framework ${chalk.cyan(framework)}, expected one of: ${chalk.cyan(allowed.join(', '))}`));
process.exit(1);
}
renderFile(
template,
{ componentName },
{ componentName, componentLabel },
join(componentDirPath, `${componentFileName}.${template.extension}`)
);
}
Expand All @@ -142,41 +147,151 @@ const initComponent = async (options) => {
const bookshopTemplate = templates[`bookshop_${targetFormat}`];
renderFile(
bookshopTemplate,
{ componentName },
{ componentName, componentLabel },
join(componentDirPath, `${componentFileName}.${bookshopTemplate.extension}`)
);
}

const initBookshop = async (options) => {
console.log(chalk.magenta(`Creating a Bookshop project at ${options.new}`));

mkdirSync(options.new, { recursive: true });
mkdirSync(join(options.new, 'bookshop'), { recursive: true });
mkdirSync(join(options.new, 'components'), { recursive: true });
mkdirSync(join(options.new, 'shared', options.framework[0]), { recursive: true });
mkdirSync(join(options.new, 'shared', 'styles'), { recursive: true });

renderFile(
templates["bookshop_config"],
{ ssg: options.framework[0] },
join(options.new, `bookshop`, `bookshop.config.js`)
);

const pageComponent = `${options.framework[0]}_page`;
renderFile(
templates[pageComponent],
{},
join(options.new, `shared`, options.framework[0], `page.${templates[pageComponent].extension}`)
);

renderFile(
templates["global_style"],
{},
join(options.new, `shared`, `styles`, `global.scss`)
);

if (options.framework[0] === "hugo") {
renderFile(
templates["hugo_config"],
{},
join(options.new, `config.toml`)
);
}

options.component = "sample";
await initComponent(options);
}

async function run() {
program.option("-c, --component <component>", "The name of a component to create");
program.option("-n, --new <project name>", "Create a new Bookshop in the given directory");
program.option("-c, --component <component>", "Create a new component with the given name");
program.option("-f, --framework <frameworks...>", "Optional: Space separated list of frameworks to use. Will be aut-detected if not supplied");
program.addOption(new Option('--format <filetype>', 'Convert Bookshop files to another format').choices(['yml', 'toml', 'json', 'js']));
program.option("-d, --dot", "Look for Bookshops inside . directories");
program.parse(process.argv);
const options = program.opts();

if (!options.component) {
console.log(chalk.magenta("What is the name of your new component?"));
console.log(chalk.magenta(`You can use a path here, i.e. ${chalk.cyan(`blocks/hero/large`)}`));
if (options.component && options.new) {
console.error(chalk.red("--component and --new cannot be passed together"));
process.exit(1);
}

let action;
if (options.component) action = 'component';
if (options.new) action = 'new';
if (!options.component && !options.new) {
const resp = await inquirer.prompt([{
type: 'input',
name: 'component',
message: 'Component name:',
validate: c => {
if (/[^a-z0-9-_\/]/.test(c)) {
return `Component name must only contain alphanumeric, hyphen, underscore, and forward-slash`;
} else {
return true;
}
}
type: 'list',
name: 'action',
message: 'What do you want to create?',
choices: ['A new Bookshop project', 'A new component'],
}]);
options.component = resp.component;
switch (resp.action) {
case "A new Bookshop project":
action = 'new';
break;
case "A new component":
action = 'component';
break
default:
process.exit(1);
}
}

if (options.component) {
await initComponent(options);
console.log(chalk.bold.green(`\nAll done.`));
return;
if (action === 'component') {
if (!options.component) {
console.log(chalk.magenta("What is the name of your new component?"));
console.log(chalk.magenta(`You can use a path here, i.e. ${chalk.cyan(`blocks/hero/large`)}`));
const resp = await inquirer.prompt([{
type: 'input',
name: 'component',
message: 'Component name:',
validate: c => {
if (/[^a-z0-9-_\/]/.test(c)) {
return `Component name must only contain alphanumeric, hyphen, underscore, and forward-slash`;
} else {
return true;
}
}
}]);
options.component = resp.component;
}

if (options.component) {
await initComponent(options);
console.log(chalk.bold.green(`\nAll done.`));
return;
}
} else if (action === 'new') {
if (!options.new) {
console.log(chalk.magenta("What directory would you like to create your Bookshop in?"));
console.log(chalk.magenta("This will be relative to to the directory you're running this command in"));
const resp = await inquirer.prompt([{
type: 'input',
name: 'newdir',
message: 'Directory name:',
validate: c => {
if (/[^a-z0-9-_\/]/.test(c)) {
return `Directory name must only contain alphanumeric, hyphen, underscore, and forward-slash`;
} else {
return true;
}
}
}]);
options.new = resp.newdir;
}

if (!options.framework || !options.framework.length) {
const resp = await inquirer.prompt([{
type: 'list',
name: 'ssg',
message: 'What framework do you want to create a new Bookshop project for?',
choices: ['Hugo', 'Eleventy', 'Jekyll'],
filter(val) { return val.toLowerCase(); },
}]);
options.framework = [resp.ssg];
}

if (options.framework.length > 1) {
console.error(chalk.red("Only one framework can be supplied for creating a new Bookshop"));
process.exit(1);
}

if (options.new && options.framework) {
await initBookshop(options);
console.log(chalk.bold.green(`\nAll done.`));
return;
}
}
}

Expand Down
Loading

0 comments on commit 824de51

Please sign in to comment.