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

CLI command for initializing component boilerplate #109

Merged
merged 8 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Feature: GitHub source links for components via [@etchteam/storybook-addon-github-link](https://storybook.js.org/addons/@etchteam/storybook-addon-github-link) in storybook docs
- Patch: Update method of declaring Storybook component descriptions and add import instructions to components
- Patch: Remove description field from top level `meta` object in component `.stories.svelte` files (do not render)
- Feature: CLI command to generate new component boilerplate (`npm run create-component`)

## v0.10.2

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ To build your library:
npm run package
```

### CLI-based command for creating new component boilerplate

To create three boilerplate files for a new component (`ComponentName.svelte`, `ComponentName.stories.svelte`, and `ComponentName.docs.md`), run the following command:

```bash
npm run create-component
```

## Contributing to this library

When contributing to this library, keep the following guidelines in mind. The [pull request template](https://github.com/UrbanInstitute/dataviz-components/blob/main/.github/pull_request_template.md) requires explanation of changes and provides a checklist of tasks to ensure clean code and documentation. Please name all branches in `kebab-case`, beginning with "patch", "feature", or "bugfix", and provide insightful commit messages.
72 changes: 72 additions & 0 deletions bin/createComponent/createComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env node
import { input } from "@inquirer/prompts";
import fs from "fs";
import path from "path";
import process from "process";
import { createStory } from "./createStory.js";
import { createDocs } from "./createDocs.js";

// check if PascalCase https://www.w3resource.com/javascript-exercises/javascript-string-exercise-56.php
function isPascalCase(str) {
return /^[A-Z][A-Za-z]*$/.test(str);
}

// check if name is valid
function validateName(componentName) {
if (!componentName) {
return "Please enter a component name";
} else if (!isPascalCase(componentName)) {
return "Component name must be in PascalCase";
} else {
return true;
}
}

function createFiles(componentName) {
// validate file name
const validated = validateName(componentName);
if (validated !== true) {
return console.error(validated);
}

// declare dir
const dir = path.join(process.cwd(), "src", "lib", componentName);

// if directory exists show error, else create files
if (fs.existsSync(dir)) {
console.error("Directory already exists");
} else {
// create directory
fs.mkdirSync(dir, { recursive: true });

// create Component.svelte (blank)
const svelteFilePath = path.join(dir, `${componentName}.svelte`);
fs.writeFileSync(svelteFilePath, "", "utf8");

// create Component.docs.md
const docsFilePath = path.join(dir, `${componentName}.docs.md`);
fs.writeFileSync(docsFilePath, createDocs(componentName), "utf8");

// create Component.stories.svelte
const storyFilePath = path.join(dir, `${componentName}.stories.svelte`);
fs.writeFileSync(storyFilePath, createStory(componentName), "utf8");

// Confirmation text
console.log(`Boilerplate files created in ${dir}`);
}
}

async function main() {
// if there's an argument in the command, use it (but no more)
if (process.argv[2] && !process.argv[3]) {
createFiles(process.argv[2]);
} else {
// show input
await input({
message: "What is the name of your component? (ie: MyComponent)",
validate: validateName
}).then(createFiles);
}
}

main().catch(console.error);
8 changes: 8 additions & 0 deletions bin/createComponent/createDocs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function createDocs(componentName) {
return `Esse ipsum deserunt dolor minim dolore sunt cillum.

\`\`\`js
import { ${componentName} } from "@urbaninstitute/dataviz-components";
\`\`\`
`;
}
32 changes: 32 additions & 0 deletions bin/createComponent/createStory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export function createStory(componentName) {
return `<script context="module">
import TestingTree from "./TestingTree.svelte";
import docs from "./TestingTree.docs.md?raw";

export const meta = {
title: "Components/TestingTree",
component: TestingTree,
tags: ["autodocs"],
parameters: {
docs: {
description: {
component: docs
}
},
githubLink: {
url: "/TestingTree/TestingTree.svelte"
}
}
};
</script>

<script>
import { Story, Template } from "@storybook/addon-svelte-csf";
</script>

<Template let:args>
<TestingTree {...args} />
</Template>

<Story name="Default" />`;
}
Loading