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(cli): add functionality to existing projects #42

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
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 .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
2 changes: 1 addition & 1 deletion .github/workflows/pr_check.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Release
name: PR

on:
push:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

strategy:
matrix:
node-version: [14.x]
node-version: [14.x, 16.x]

steps:
- uses: actions/checkout@v2
Expand Down
451 changes: 264 additions & 187 deletions index.js

Large diffs are not rendered by default.

35 changes: 0 additions & 35 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,3 @@
// https://github.com/marvinhagemeister/kolorist/blob/main/src/index.ts
import { blue, yellow, red, green } from 'kolorist';

import * as types from './types';

export const TEMPLATES_DIRECTORY = `${__dirname}/templates`;
export const RENAMABLE_FILES_MAP: { [key: string]: string } = {
_gitignore: '.gitignore',
};

export const TEMPLATES: types.Template[] = [
{
name: 'react',
color: yellow,
variants: [
{
color: yellow,
name: 'react',
display: 'React JavaScript',
},
{
color: blue,
name: 'react-ts',
display: 'React TypeScript',
},
{
color: red,
name: 'vite-vanilla',
display: 'Vite JavaScript',
},
{
color: green,
name: 'koa-ts',
display: 'Koa Typescript',
},
],
},
];
22 changes: 0 additions & 22 deletions src/functions.ts

This file was deleted.

22 changes: 22 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import fs from 'fs';
import path from 'path';

export const copyDir = (srcDir: string, destDir: string) => {
fs.mkdirSync(destDir, { recursive: true });

const prepareAndCopy = (file: string) => {
const srcFile = path.resolve(srcDir, file);
const destFile = path.resolve(destDir, file);
copy(srcFile, destFile);
};

fs.readdirSync(srcDir).forEach(prepareAndCopy);
};

export const write = (to: string, content: string) =>
fs.writeFileSync(to, content);

export const copy = (src: string, dest: string) =>
fs.statSync(src).isDirectory()
? copyDir(src, dest)
: fs.copyFileSync(src, dest);
105 changes: 9 additions & 96 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,100 +1,13 @@
#!/usr/bin/env node
import * as types from './types';
import * as prompts from './prompts';
import * as utils from './utils';

import prompts from 'prompts'
import fs from 'fs'
import path from 'path'
import { green, reset } from 'kolorist'
const commandHandlers: Record<types.Command, () => Promise<void>> = {
add: prompts.add,
create: prompts.create,
};

import * as functions from './functions'
import * as utils from './utils'
import { TEMPLATES, TEMPLATES_DIRECTORY } from './constants'
const handleCommand = (command: types.Command) => commandHandlers[command]();

const cwd = process.cwd()

const init = async () => {
const state = {
targetDir: '',
}

const templates = TEMPLATES.flatMap((f) => f.variants)

let steps: prompts.PromptObject[] = [
{
type: 'text',
name: 'projectName',
message: 'Project name:',
initial: 'my-awesome-project',
onState: ({ value = '' }) => (state.targetDir = value.trim()),
},
{
type: () => {
if (fs.existsSync(state.targetDir) ? 'confirm' : null) {
throw new Error('Target directory is not empty. Please try again.')
}

return null
},
name: 'exitInvalidDir',
},
{
type: () => (utils.isValidPkgName(state.targetDir) ? null : 'text'),
name: 'packageName',
message: reset('Package name:'),
initial: () => utils.toValidPackageName(state.targetDir),
validate: (dir) =>
utils.isValidPkgName(dir) || 'Invalid package.json name',
},
{
type: 'select',
name: 'template',
message: reset('Select a template:'),
initial: 0,
choices: templates.map((template) => ({
title: template.color(template.name),
value: template,
})),
},
]

const result = await prompts(steps)

const root = path.join(cwd, state.targetDir)
console.log(`\nScaffolding project in ${root}...`)

fs.mkdirSync(root)
const templateDir = path.join(TEMPLATES_DIRECTORY, result.template.name)

fs.readdirSync(templateDir)
.filter(utils.isNotPackageJson)
.forEach((fileName) =>
functions.copy(
path.join(templateDir, fileName),
utils.getTargetPath(root, fileName)
)
)

const packageJson = Object.assign(
require(path.join(templateDir, 'package.json')),
{
name: result.packageName,
}
)

functions.write(
utils.getTargetPath(root, 'package.json'),
JSON.stringify(packageJson, null, 2)
)

const pkgManager =
utils.getPkgManagerFromUserAgent(process.env.npm_config_user_agent) ?? 'npm'

console.log(green(`\nFinished! Now run:\n`))

if (root !== cwd) {
console.log(` cd ${path.relative(cwd, root)}`)
}

console.log(utils.installInstructionsByPkgManager(pkgManager))
}

init().catch(({ message }) => console.error(message))
prompts.start().then(handleCommand).catch(utils.handleError);
63 changes: 63 additions & 0 deletions src/prompts/add/handlers/gh-actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import fs from 'fs';
import path from 'path';
import { lightGreen } from 'kolorist';

import * as helpers from '../../../helpers';
import * as utils from '../../../utils';

const cwd = process.cwd();

const createGithubDir = (path: string) => {
const hasGithubDir = fs.existsSync(`${path}/.github`);
if (!hasGithubDir) {
fs.mkdirSync(`${path}/.github`);
console.log(`\nNo .github exists, creating directory`);
}
};

export const ghActions = () => {
const root = path.join(cwd);

console.log(`\nAdding gh actions to ${root}...`);
console.log('this is root', root);

const hasGithubDir = fs.existsSync(`${root}/.github`);
console.log('has github dir: ', hasGithubDir);
const templateDir = path.join(
PROJECT_TEMPLATES_DIRECTORY,
result.template.name
);

fs.readdirSync(templateDir)
.filter(utils.isNotPackageJson)
.forEach((fileName) =>
helpers.copy(
path.join(templateDir, fileName),
utils.getTargetPath(root, fileName)
)
);

const packageJson = Object.assign(
require(path.join(templateDir, 'package.json')),
{
name: result.targetDir,
}
);

helpers.write(
utils.getTargetPath(root, 'package.json'),
JSON.stringify(packageJson, null, 2)
);

const pkgManager =
utils.getPkgManagerFromUserAgent(process.env.npm_config_user_agent) ??
'npm';

console.log(lightGreen(`\nFinished! Now run:\n`));

if (root !== cwd) {
console.log(` cd ${path.relative(cwd, root)}`);
}

console.log(utils.installInstructionsByPkgManager(pkgManager));
};
1 change: 1 addition & 0 deletions src/prompts/add/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './gh-actions';
26 changes: 26 additions & 0 deletions src/prompts/add/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { reset } from 'kolorist';
import p from 'prompts';
import * as types from './../../types';
import * as utils from '../../utils';
import { Util, UTIL_TEMPLATES } from '../create/constants';
import { ghActions } from './handlers';

const handlersMap: Record<Util, () => void> = {
'gh-actions': ghActions,
};

const handleTemplateChoice = (val: Util) => handlersMap[val]();

export const add = () =>
p(steps).then((val) => handleTemplateChoice(val.template));

const steps: p.PromptObject<'template'>[] = [
{
type: 'select',
name: 'template',
message: reset('Select a template:'),
initial: 0,
choices: UTIL_TEMPLATES.map(utils.templateAsSelectOption),
format: (x: types.Template) => x.name,
},
];
38 changes: 38 additions & 0 deletions src/prompts/create/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { blue, yellow, red, green } from 'kolorist';

import * as types from '../../types';

export const PROJECT_TEMPLATES_DIRECTORY = `${__dirname}/templates`;

export const PROJECT_TEMPLATES: Array<types.Template> = [
{
color: yellow,
name: 'react',
label: 'React JavaScript',
},
{
color: blue,
name: 'react-ts',
label: 'React TypeScript',
},
{
color: red,
name: 'vite-vanilla',
label: 'Vite JavaScript',
},
{
color: green,
name: 'koa-ts',
label: 'Koa Typescript',
},
];

export type Util = 'gh-actions';

export const UTIL_TEMPLATES: Array<types.Template<Util>> = [
{
color: yellow,
name: 'gh-actions',
label: 'Github Actions (on PR)',
},
];
Loading