Skip to content

Commit

Permalink
refactor: refactor create handle.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaywcjlove committed Oct 6, 2021
1 parent 4aa33d4 commit 12658b6
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 137 deletions.
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"watch": "tsbb watch --disable-babel -f src/cli.ts",
"build": "tsbb build --disable-babel -f src/cli.ts",
"prettier": "prettier --write \"**/*.{js,ts,less,md,json}\"",
"coverage": "tsbb test --coverage",
"test": "tsbb test"
"coverage": "tsbb test --coverage --detectOpenHandles",
"test": "tsbb test --detectOpenHandles"
},
"files": [
"lib",
Expand Down Expand Up @@ -48,6 +48,9 @@
"prettier --write"
]
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"devDependencies": {
"husky": "7.0.2",
"lint-staged": "11.2.0",
Expand All @@ -60,7 +63,7 @@
"@types/fs-extra": "9.0.13",
"@types/minimist": "1.2.2",
"@types/node": "16.7.1",
"ora": "6.0.1",
"ora": "5.4.1",
"download": "8.0.0",
"minimist": "1.2.5",
"fs-extra": "10.0.0"
Expand Down
90 changes: 37 additions & 53 deletions src/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,44 @@ export type CreateOptions = {
output?: string;
p?: string;
path?: string;
} & ParsedArgs;
} & Omit<ParsedArgs, '_'>;

export async function create(argv: CreateOptions, exampleHelp: () => void) {
export async function create(argv: CreateOptions, exampleHelp: string) {
const spinner = ora('Downloading Example.');
try {
if (!argv.appName || !/^[A-Za-z0-9_\-\.]{1,}$/.test(argv.appName)) {
console.log(`\n \x1b[31mPlease specify the project directory name\x1b[0m.`);
if (!/^[A-Za-z0-9_\-\.]{1,}$/.test(argv.appName)) {
console.log(
` \x1b[31mThe name directory name\x1b[0m \x1b[33m${argv.appName}\x1b[0m \x1b[31mcontains special characters.\x1b[0m`,
);
}
exampleHelp && exampleHelp();
console.log(`\n`);
console.log(`\n \x1b[31mPlease specify the project directory name\x1b[0m.
${
!/^[A-Za-z0-9_\-\.]{1,}$/.test(argv.appName)
? `\x1b[31mThe name directory name\x1b[0m \x1b[33m${argv.appName}\x1b[0m \x1b[31mcontains special characters.\x1b[0m`
: ''
}
${exampleHelp || ''}
`);
return;
}
if (!argv.path || typeof argv.path !== 'string') {
console.log(`\n Uh oh! \x1b[31mPlease specify download address\x1b[0m.`);
exampleHelp && exampleHelp();
console.log(`\n`);
console.log(
`\n Uh oh! \x1b[31mPlease specify download address\x1b[0m. ${exampleHelp || ''}`,
);
return;
}
const projectPath = path.join(process.cwd(), argv.output, argv.appName);
if (argv.force) {
await fs.remove(projectPath);
await fs.ensureDir(projectPath);
} else if (fs.existsSync(projectPath)) {
console.log(
`\n Uh oh! Looks like there's already a directory called \x1b[31m${argv.appName}\x1b[0m\n`,
`\x1b[33mPlease try a different name or delete that folder.\x1b[0m\n`,
`Path: \x1b[33m${projectPath}\x1b[0m\n`,
);
console.log(`
Uh oh! Looks like there's already a directory called \x1b[31m${argv.appName}\x1b[0m\n
\x1b[33mPlease try a different name or delete that folder.\x1b[0m\n
Path: \x1b[33m${projectPath}\x1b[0m\n
`);
process.exit(1);
}
await fs.ensureDir(projectPath);
const resultDirTree: string[] = [];
console.log();
spinner.start(`Downloading \x1b[32m${argv.example}.zip\x1b[0m example.`);
spinner.start(`\nDownloading \x1b[32m${argv.example}.zip\x1b[0m example.`);
await download(`${argv.path}${argv.example}.zip`, projectPath, {
extract: true,
filter: (file) => {
resultDirTree.push(file.path);
return true;
},
}).on('downloadProgress', (progress) => {
if (progress.percent !== 1) {
spinner.text = `The example \x1b[32m${argv.example}.zip\x1b[0m has been downloaded ${(
Expand All @@ -71,42 +65,32 @@ export async function create(argv: CreateOptions, exampleHelp: () => void) {

const pkgPath = path.resolve(projectPath, 'package.json');

console.log(
` Success! Created \x1b[35m${argv.appName}\x1b[0m at \x1b[32m${projectPath}\x1b[0m`,
);
let logstr = `Success! Created \x1b[35m${argv.appName}\x1b[0m at \x1b[32m${projectPath}\x1b[0m\n`;
if (fs.existsSync(pkgPath)) {
console.log(' Inside that directory, you can run several commands:');
console.log('');
const pkg = require(pkgPath);
if (pkg.version) {
await fs.writeJSON(pkgPath, { ...pkg, version: '1.0.0' }, { spaces: ' ' });
}
logstr += `\nInside that directory, you can run several commands:\n`;
if (pkg.scripts) {
Object.keys(pkg.scripts).forEach((keyname) => {
console.log(` \x1b[36myarn run ${keyname}\x1b[0m`);
console.log(` └─> ${pkg.scripts[keyname]}\n`);
logstr += ` \x1b[36myarn run ${keyname}\x1b[0m\n`;
logstr += ` └─> ${pkg.scripts[keyname]}\n`;
});
} else {
console.log(` ---\n`);
}
if (pkg.version) {
await fs.writeJSON(pkgPath, { ...pkg, version: '1.0.0' }, { spaces: ' ' });
}
console.log(' We suggest that you begin by typing:');
console.log('');
console.log(` \x1b[36mcd ${argv.appName}\x1b[0m`);
console.log(` \x1b[36myarn install\x1b[0m`);
console.log(' \x1b[36myarn build\x1b[0m && \x1b[36myarn start\x1b[0m ');
logstr += '\nWe suggest that you begin by typing:\n';
logstr += ` \x1b[36mcd ${argv.appName}\x1b[0m\n`;
logstr += ' \x1b[36myarn install\x1b[0m\n';
logstr += ' \x1b[36myarn build\x1b[0m && \x1b[36myarn start\x1b[0m\n';
}
console.log('');
console.log(' Happy hacking!\n');
logstr += '\nHappy hacking!\n';
console.log(logstr);
} catch (error) {
spinner.fail(`\x1b[31m${error.message}\x1b[0m`);
if (error && error.statusCode === 404) {
console.log(
` Error: \x1b[31m${error.statusCode}\x1b[0m, The example \x1b[31m${argv.example}.zip\x1b[0m does not exist.`,
);
console.log(` Download link: \x1b[31m${argv.path}${argv.example}.zip\x1b[0m`);
} else {
console.log(error);
}
spinner.fail(`\x1b[31m${error.message}\x1b[0m\n Error: \x1b[31m${
error.statusCode || '000'
}\x1b[0m, The example \x1b[31m${argv.example}.zip\x1b[0m does not exist.
\n Download link: \x1b[31m${argv.path}${argv.example}.zip\x1b[0m
`);
process.exit(1);
}
}
48 changes: 20 additions & 28 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,7 @@ export async function run(): Promise<void> {
},
});
if (argvs.h || argvs.help) {
console.log('\n Usage: create-kkt <app-name> [options] [--help|h]');
console.log('\n Options:');
console.log(' --version, -v', 'Show version number');
console.log(' --help, -h', 'Displays help information.');
console.log(' --output, -o', 'Output directory.');
console.log(
' --example, -e',
'Example from: \x1b[34mhttps://kktjs.github.io/zip/ \x1b[0m , default: "basic"',
);
console.log(' --force, -f', 'Overwrite target directory if it exists. default: false');
console.log(
' --path, -p',
'Specify the download target git address. default: "\x1b[34mhttps://kktjs.github.io/zip/ \x1b[0m"',
);
exampleHelp();
console.log('\n Copyright 2021');
console.log('\n');
console.log(`${helpCli}${helpExample}${helpCopyright}`);
return;
}
const { version } = require('../package.json');
Expand All @@ -46,21 +30,29 @@ export async function run(): Promise<void> {
}
argvs.appName = argvs._[0];
argvs.example = argvs.e = String(argvs.example).toLocaleLowerCase();
await create(argvs, exampleHelp);
await create(argvs, helpExample);
} catch (error) {
console.log(`\x1b[31m${error.message}\x1b[0m`);
console.log(error);
process.exit(1);
}
}

export function exampleHelp() {
console.log('\n Example:');
console.log(' \x1b[35myarn\x1b[0m create kkt \x1b[33mappName\x1b[0m');
console.log(' \x1b[35mnpx\x1b[0m create-kkt \x1b[33mmy-app\x1b[0m');
console.log(' \x1b[35mnpm\x1b[0m create kkt \x1b[33mmy-app\x1b[0m');
console.log(' \x1b[35mnpm\x1b[0m create kkt \x1b[33mmy-app\x1b[0m -f');
console.log(
' \x1b[35mnpm\x1b[0m create kkt \x1b[33mmy-app\x1b[0m -p \x1b[34mhttps://kktjs.github.io/zip/\x1b[0m',
);
}
export const helpCli = `\n Usage: create-kkt <app-name> [options] [--help|h]
Options:
--version, -v Show version number
--help, -h Displays help information.
--output, -o Output directory.
--example, -e Example from: \x1b[34mhttps://kktjs.github.io/zip/ \x1b[0m , default: "basic"
--force, -f Overwrite target directory if it exists. default: false
--path, -p Specify the download target git address. default: "\x1b[34mhttps://kktjs.github.io/zip/ \x1b[0m"
`;
export const helpExample: string = `\n Example:
\x1b[35myarn\x1b[0m create kkt \x1b[33mappName\x1b[0m
\x1b[35mnpx\x1b[0m create-kkt \x1b[33mmy-app\x1b[0m
\x1b[35mnpm\x1b[0m create kkt \x1b[33mmy-app\x1b[0m
\x1b[35mnpm\x1b[0m create kkt \x1b[33mmy-app\x1b[0m -f
\x1b[35mnpm\x1b[0m create kkt \x1b[33mmy-app\x1b[0m -p \x1b[34mhttps://kktjs.github.io/zip/\x1b[0m
`;
export const helpCopyright: string = `\n Copyright 2021`;
28 changes: 16 additions & 12 deletions test/cli.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
/** @jest-environment node */
import { exampleHelp, run } from '../src/';
import fs from 'fs-extra';
import path from 'path';

it('cliHelp test case', async () => {
expect(exampleHelp()).toBeUndefined();
// process.argv.push('-v');
// expect(await run()).toBeUndefined();
process.argv.push('--version');
expect(await run()).toBeUndefined();
});
console.log = jest.fn();

const argv = process.argv.slice(0, 2);

it('version test case', async () => {
expect(exampleHelp()).toBeUndefined();
process.argv.push('-h');
expect(await run()).toBeUndefined();
it('create project. 1', async () => {
process.argv = argv;
process.argv.push('my-app2');
process.argv.push('-f');
process.argv.push('--output');
process.argv.push('test');
// console.log(process.argv)
await import('../src/cli');
// console.log(path.resolve(__dirname, 'my-app2'))
expect(await fs.existsSync(path.resolve(__dirname, 'my-app2'))).toBeTruthy();
await fs.remove('test/my-app2');
});
87 changes: 87 additions & 0 deletions test/create.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/** @jest-environment node */
import fs from 'fs-extra';
import { create, CreateOptions } from '../src/create';
import { helpExample } from '../src';

console.log = jest.fn();

it('create project. 1', async () => {
const opts: CreateOptions = {};
await create(opts, '');
// @ts-ignore
expect(
console.log.mock.calls[0][0].indexOf('Please specify the project directory name') > -1,
).toBeTruthy();
});

it('create project. 2', async () => {
const opts: CreateOptions = {};
await create(opts, helpExample);
// @ts-ignore
expect(console.log.mock.calls[0][0].indexOf('Example:') > -1).toBeTruthy();
});

it('create project. options => appName', async () => {
const opts: CreateOptions = { appName: 'my-app' };
await create(opts, helpExample);
// @ts-ignore
expect(console.log.mock.calls[0][0].indexOf('my-app') > -1).toBeTruthy();
});

it('create project. options => appName', async () => {
const opts: CreateOptions = { appName: [] as any };
await create(opts, '');
// @ts-ignore
expect(console.log.mock.calls[0][0].indexOf('The name directory nam') > -1).toBeTruthy();
});

it('create project. options => path', async () => {
const opts: CreateOptions = { appName: 'my-app', path: [] as any };
await create(opts, '');
// @ts-ignore
expect(console.log.mock.calls[0][0].indexOf('Please specify download address') > -1).toBeTruthy();
});

it('create project. options => force/example', async () => {
const mockExit = jest.spyOn(process, 'exit').mockImplementation();
const opts: CreateOptions = {
force: true,
output: 'test',
appName: 'my-app',
path: 'https://kktjs.github.io/zip/',
};
await create(opts, '');
expect(mockExit).toHaveBeenCalledWith(1);
mockExit.mockRestore();
});

it('create project. options => force', async () => {
await fs.ensureDir('test/my-app');
const mockExit = jest.spyOn(process, 'exit').mockImplementation();
const opts: CreateOptions = {
output: 'test',
appName: 'my-app',
path: 'https://kktjs.github.io/zip/',
};
await create(opts, '');
// @ts-ignore
expect(
console.log.mock.calls[0][0].indexOf("Looks like there's already a directory called") > -1,
).toBeTruthy();
expect(mockExit).toHaveBeenCalledWith(1);
mockExit.mockRestore();
});

it('create project. options => example', async () => {
const opts: CreateOptions = {
force: true,
output: 'test',
example: 'basic',
appName: 'my-app',
path: 'https://kktjs.github.io/zip/',
};
await create(opts, '');
// @ts-ignore
expect(console.log.mock.calls[0][0].indexOf('Success! Created') > -1).toBeTruthy();
await fs.remove('test/my-app');
});
Loading

0 comments on commit 12658b6

Please sign in to comment.