Skip to content

Commit

Permalink
implement typescript project creation
Browse files Browse the repository at this point in the history
  • Loading branch information
jihyunlab-phil committed Jan 16, 2024
1 parent 187208e commit 96d78a7
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 8 deletions.
64 changes: 64 additions & 0 deletions bin/creators/typescript-project.creator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Location as LocationHelper } from '../helpers/location.helper';
import { readFileSync, rmSync, writeFileSync } from 'fs';
import { join } from 'path';
import { execSync, spawn } from 'child_process';

export const TypescriptProject = {
createApp(name: string) {
if (!name || name.trim().length === 0) {
throw new Error('project name is empty.');
}

const location = LocationHelper.toAbsolute(name);

if (LocationHelper.isExist(location)) {
throw new Error('project name already exists.');
}

execSync(`git clone https://github.com/jihyunlab/typescript-starter.git ${name}`, { stdio: 'pipe' });

if (!LocationHelper.isExist(location)) {
throw new Error('failed to clone starter project.');
}

const basename = LocationHelper.toBasename(location);

// package.json
const packageJson = JSON.parse(readFileSync(join(location, 'package.json')).toString());

packageJson['name'] = basename;
packageJson['description'] = '';
packageJson['license'] = 'UNLICENSED';

delete packageJson['author'];
delete packageJson['homepage'];
delete packageJson['repository'];
delete packageJson['bugs'];

packageJson['keywords'] = [];

writeFileSync(join(location, 'package.json'), JSON.stringify(packageJson, null, 2));

// README.md
writeFileSync(join(location, 'README.md'), `# ${basename}`);

// LICENSE
rmSync(join(location, 'LICENSE'), { recursive: true, force: true });

// package-lock.json
rmSync(join(location, 'package-lock.json'), { recursive: true, force: true });

// .git
rmSync(join(location, '.git'), { recursive: true, force: true });

// npm i
const install = spawn('npm', ['i'], {
cwd: location,
env: process.env,
shell: process.platform === 'win32',
stdio: [null, process.stdout, process.stderr],
});

install.on('close', () => {});
},
};
55 changes: 55 additions & 0 deletions bin/helpers/location.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as fs from 'fs';
import * as path from 'path';

export const Location = {
isAbsolute(location: string) {
return path.isAbsolute(location);
},

toAbsolute(location: string) {
let absolute: string;

if (this.isAbsolute(location)) {
absolute = location;
} else {
absolute = path.join(process.cwd(), location);
}

return path.normalize(absolute);
},

toRelative(location: string) {
const absolute = this.toAbsolute(location);
const relative = path.relative(process.cwd(), absolute);

return path.normalize(relative);
},

toBasename(location: string) {
return path.basename(this.toAbsolute(location));
},

isExist(location: string) {
return fs.existsSync(location);
},

isDirectory(location: string) {
if (!this.isExist(location)) {
return undefined;
}

return fs.lstatSync(location).isDirectory();
},

toDirectory(location: string, file = false) {
let dirname: string;

if (file) {
dirname = this.toAbsolute(path.dirname(location));
} else {
dirname = this.toAbsolute(location);
}

return path.normalize(dirname);
},
};
74 changes: 70 additions & 4 deletions bin/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,71 @@
export function main() {
return true;
}
#!/usr/bin/env node
import { Command } from 'commander';
import { TypescriptProject as TypescriptProjectCreator } from './creators/typescript-project.creator';
import { Location as LocationHelper } from './helpers/location.helper';
import prompts, { InitialReturnValue } from 'prompts';
import { setMaxListeners } from 'events';

main();
setMaxListeners(36);

const handleSigTerm = () => process.exit(0);

process.on('SIGINT', handleSigTerm);
process.on('SIGTERM', handleSigTerm);

const onPromptState = (state: { value: InitialReturnValue; aborted: boolean; exited: boolean }) => {
if (state.aborted) {
process.stdout.write('\x1B[?25h');
process.stdout.write('\n');
process.exit(1);
}
};

const program = new Command('create-typescript-app')
.description('JihyunLab Create typescript app')
.addHelpText('after', ' ')
.addHelpText('after', 'Usage example:')
.addHelpText('after', ' npx @jihyunlab/create-typescript-app@latest')
.version('1.0.0');

program.action(async () => {
console.log('');

const response = await prompts({
onState: onPromptState,
type: 'text',
name: 'path',
message: 'What is your project name?',
initial: 'my-app',
validate: (name) => {
if (!name || name.trim().length === 0) {
console.log('');
console.log('error: project name is empty.');
process.exit(1);
}

const location = LocationHelper.toAbsolute(name);

if (LocationHelper.isExist(location)) {
console.log('');
console.log('error: project name already exists.');
process.exit(1);
}

return true;
},
});

try {
TypescriptProjectCreator.createApp(response.path.trim());
} catch (error) {
if (error instanceof Error) {
console.log(`error: ${error.message}`);
} else {
console.log(error);
}

process.exit(1);
}
});

program.parse();
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"repository": "https://github.com/jihyunlab/create-typescript-app",
"bugs": "https://github.com/jihyunlab/create-typescript-app/issues",
"bin": {
"@jihyunlab/create-typescript-app": "dist/index.js"
"create-typescript-app": "dist/index.js"
},
"scripts": {
"build": "tsc --build",
Expand All @@ -31,6 +31,7 @@
"@jihyunlab/prettier-config": "^1.1.3",
"@types/jest": "^29.5.11",
"@types/node": "^20.11.3",
"@types/prompts": "^2.4.9",
"jest": "^29.7.0",
"ts-jest": "^29.1.1",
"typescript": "^5.3.3"
Expand Down
4 changes: 1 addition & 3 deletions test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { main } from '../bin/index';

describe('Index', () => {
beforeEach(() => {});

afterEach(() => {});

test('main()', () => {
expect(main()).toBe(true);
expect(true).toBe(true);
});
});

0 comments on commit 96d78a7

Please sign in to comment.