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

Feature/add prompt library and fix typescript #874

Merged
merged 8 commits into from
Jul 1, 2020
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ node_modules
# Errors
npm-debug.log
php_errors.log
lerna-debug.log

# Typescript
dist
# Typescript outdir
packages/*/lib
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ TBD
1. Clone the repo
1. Run `npm install`, This will install all dev dependencies and run the postinstall script `lerna:install` which runs `lerna bootstrap --nohoist` and installs all package dependencies.
1. If you update subdependencies, simply run `npm install` or `npm run lerna:install` to re-install lerna package dependencies. This is especially helpful when you are pulling in new code (with sub dependency additionas) from another branch.
1. `npm run build:watch` build the project in the dist folder
1. `npm run build:watch` build the project in the `packages/<PACKAGE_NAME>/lib` folder, packages that do not contain a .tsconfig and do not have a `tsc` and `tsc:build` script will be ignored lerna executes packages that contain only these scripts.
1. For all packages, simply execute the target file such as `node packages/particle-cli/lib/bin/particle-cli.js init` to run things, typescript must be compiled for typescript packages to execute
1. `npm run test:watch` to start jest in watch mode (recommended)

### Installing A Dependency

1. Run `npm run build`, build will fire off the `tsc` build script and also copy the package.json and README.md files from the `packages/*` directories directly into the dist folder. Alternatively have the compiler in watch mode `npm run build:watch` and run `npm run postbuild` to copy the files in.
1. Cd into `dist/<REPO_NAME>` and run `npm link`, this will link the **bin** alias as an alias in your terminal. Example the bin is named `@phase2/particle-cli` therefore running `npx @phase2/particle-cli -v` will invoke the binary file `particle-cli`.
1. Cd into `package/<PACKAGE_NAME>` and run `npm link`, this will link the **lib/bin** or `main/index.js` alias as an alias in your terminal. Example the bin is named (or aliased) `@phase2/particle-cli` therefore running `npx @phase2/particle-cli -v` will invoke the binary file `particle-cli`.

#### Example

Expand All @@ -41,7 +42,7 @@ particle-cli -V; // works

### Clean the repo

To remove package-lock.json from all levels of the repo simply run this command. PS is used to prevent grep from exiting as this throws an error with `lerna exec` even with the `--no-bail` flag.
To remove package-lock.json from all levels of the repo simply run this command. `ps` is used to prevent grep from exiting as this throws an error with `lerna exec` even with the `--no-bail` flag.

```bash
ps -ef | (grep -q -s -R ^$1 package-lock.json && rm -rf package-lock.json) | { grep -v grep || true; }; lerna exec -- ps -ef | (grep -q -s -R ^$1 package-lock.json && rm -rf package-lock.json) | { grep -v grep || true; }
Expand Down
20 changes: 0 additions & 20 deletions babel.config.js

This file was deleted.

15 changes: 6 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
},
"private": true,
"keywords:": [
"Particle",
"Storybook",
"Pattern Lab",
"Drupal"
Expand All @@ -27,17 +28,16 @@
"pretty-check": "prettier --check packages/**/*.js",
"test": "jest",
"test:watch": "jest --watch",
"build": "tsc -p tsconfig.json && npm run postbuild",
"build": "lerna run --parallel --scope='@phase2/*' tsc && npm run postbuild",
"build:watch": "lerna run --parallel --scope='@phase2/*' tsc:watch",
"postbuild": "ts-node ./src/scripts/build.ts",
"build:watch": "tsc -p tsconfig.json --watch",
"update:check": "npx ncu && npx lerna exec --concurrency 1 --no-bail -- npx ncu",
"update:start": "npm-upgrade && lerna exec --concurrency 1 -- npm-upgrade; npm run lerna:install"
},
"devDependencies": {
"@babel/core": "^7.10.2",
"@babel/preset-env": "^7.10.2",
"@lerna/link": "^3.21.0",
"@types/jest": "^26.0.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"@types/node": "^14.0.14",
"eslint": "^7.2.0",
"jest": "^26.0.1",
"jest-watch-typeahead": "^0.6.0",
Expand All @@ -48,8 +48,5 @@
"ts-jest": "^26.1.0",
"ts-node": "^8.10.2",
"typescript": "^3.9.5"
},
"files": [
"dist/**/*"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ module.exports = {
rules: {
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
},
};
}
9 changes: 5 additions & 4 deletions packages/particle-cli/bin/particle-cli.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/usr/bin/env node

const program = require('commander')
// const pkg = require('../package'); // can't do since this is not copied over into dist unless its an import
import program from 'commander'

import pkg from '../package.json'
const create = require('../lib/create')
import { generatePromptOptions } from '../src/generatePromptOptions'
import create from '../src/create'

/**
* Initialize Commander program with version.
Expand All @@ -16,7 +17,7 @@ program
.description('Scaffold your project from a set of prompts.')
.action(function () {
// @TODO Implement Create Function.
create()
generatePromptOptions().then(create)
})

// allow commander to parse `process.argv`
Expand Down
14 changes: 10 additions & 4 deletions packages/particle-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"init"
],
"bin": {
"@phase2/particle-cli": "bin/particle-cli.js",
"particle-cli": "bin/particle-cli.js"
"@phase2/particle-cli": "lib/bin/particle-cli.js",
"particle-cli": "lib/bin/particle-cli.js"
},
"homepage": "https://github.com/phase2/particle#readme",
"repository": {
Expand All @@ -27,10 +27,16 @@
},
"license": "GPL-2.0",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"tsc": "tsc",
"tsc:watch": "tsc --watch"
},
"dependencies": {
"commander": "^5.1.0",
"esm": "^3.2.25"
"esm": "^3.2.25",
"inquirer": "^7.2.0"
},
"devDependencies": {
"@types/inquirer": "^6.5.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
*
*/

const create = () => {
console.log('Create Particle Project')
const create = (data: any) => {
console.log('Create Particle Project with the data:', data)
return true
}

Expand Down
197 changes: 197 additions & 0 deletions packages/particle-cli/src/generatePromptOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import {
CustomAnswers,
ConfigOptions,
ConfigurationAnswers,
CSSLibraryOptions,
DesignSystemPatternLibraryOptions,
FrontendFrameworkOptions,
TestingLibraryOptions,
} from './types'
import inquirer from 'inquirer'

const prompt = inquirer.createPromptModule()

const minMaxOptionsValidate = ({ min, max }: { min: number; max?: number }) => (
answer: Record<string, string>[]
) => {
if (answer.length < min || (!max ? false : answer.length > max)) {
return `You must choose a minimum of ${min} option(s)${
max ? ` and a maximum of ${max} option(s)` : ''
}`
}
return true
}

const configurationPrompt = (): Promise<ConfigurationAnswers> =>
prompt([
{
type: 'input',
message: 'choose a project name using kebab case, example: "my-project"',
name: 'projectName',
validate: (name: string) => {
if (!name || name.length < 4) {
return 'Please enter a project name of more than 4 characters length'
}
if (name.indexOf(' ') > 0) {
return 'Please enter a project name with no spaces'
}
return true
},
},
{
type: 'input',
message: 'choose a design system name',
name: 'designSystemName',
default: 'default',
validate: (name: string) => {
if (!name || name.length < 4) {
return 'Please enter a repo name of more than 4 characters length'
}
return true
},
},
{
type: 'list',
message: 'Choose a configuration',
name: 'config',
choices: [
{
name:
'modern react (storybook, tailwind, react, typescript, jest | cypress, svgs)',
value: 'modern-react',
},
{ name: 'drupal only (Pattern Lab, Tailwind, Svgs)', value: 'drupal' },
{ name: 'custom', value: 'custom' },
],
},
])

const customPromptOptions = (): Promise<CustomAnswers> => {
return prompt([
{
type: 'checkbox',
message: 'choose a Component/Pattern Library or a Design System',
name: 'designSystem',
choices: [
new inquirer.Separator('-- Design System choose(1 or both)--'),
{
name: 'Storybook',
value: DesignSystemPatternLibraryOptions.STORYBOOK,
checked: true,
},
{
name: 'Pattern Lab',
value: DesignSystemPatternLibraryOptions.PATTERN_LAB,
},
],
validate: minMaxOptionsValidate({ min: 1 }),
},
{
type: 'checkbox',
message: 'What frontend framework are you using with Storybook?',
name: 'frontendFramework',
choices: [
{
name: 'React',
checked: true,
value: FrontendFrameworkOptions.REACT,
},
{
name: 'Webcomponents',
value: FrontendFrameworkOptions.WEBCOMPONENTS,
},
],
// PR up for docs on inquirer to annotate second param answers https://github.com/SBoudrias/Inquirer.js/pull/936
filter: (value: FrontendFrameworkOptions[], answers: CustomAnswers) => {
if (
answers.designSystem.includes(
DesignSystemPatternLibraryOptions.PATTERN_LAB
)
) {
return [FrontendFrameworkOptions.TWIG, ...value]
}
return value
// throw new Error(answers.designSystem)
// input will { answers, values } as we are modifying the return value in the choices section
},
when: (answers: CustomAnswers) => {
// Checks to see if we enabled typescript previously then asks the prompt
if (
new Set(answers.designSystem).has(
DesignSystemPatternLibraryOptions.STORYBOOK
)
) {
return true
}

// Mutates answers object adds twig to selected choice (does not prompt user)
answers.frontendFramework = [FrontendFrameworkOptions.TWIG]

return false
},
},
{
type: 'list',
message: 'Choose a CSS library',
name: 'cssLibrary',
choices: [
{ name: 'Tailwind', checked: true, value: CSSLibraryOptions.TAILWIND },
{ name: 'Sass', value: CSSLibraryOptions.SASS },
{
name: 'Bootstrap',
disabled: true,
value: CSSLibraryOptions.BOOTSTRAP,
},
],
},
{
type: 'confirm',
message: 'Do you want to use typescript?',
name: 'hasTypescript',
},
{
type: 'confirm',
message: 'Do you want ESModule support for typescript?',
name: 'typescriptEsm',
when: (answer: CustomAnswers) => {
// Checks to see if we enabled typescript previously then asks the prompt
if (answer.hasTypescript) {
return true
}
return false
},
},
{
type: 'confirm',
name: 'Are you using SVGs?',
},
{
type: 'checkbox',
message: 'What testing libraries do you want to use?',
name: 'testingLibraries',
choices: [
{ name: 'Jest', value: TestingLibraryOptions.JEST },
{ name: 'Cypress', value: TestingLibraryOptions.CYPRESS },
{ name: 'Selenium', value: TestingLibraryOptions.SELENIUM },
{
name: 'Loki (Storybook only VRT)',
value: TestingLibraryOptions.LOKI,
},
],
validate: minMaxOptionsValidate({ min: 1 }),
},
])
}

/**
* Returns a promise with a json schema
* The JSON schema will be used for the create method to generate files based off of the options selected in the prompt
*/
export const generatePromptOptions = async () => {
const results = await configurationPrompt()
if (results.config === ConfigOptions.CUSTOM) {
return customPromptOptions()
}

return Promise.resolve(results)
}
Loading