Skip to content

Commit

Permalink
Add TypeScript template (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
LitoMore authored Oct 4, 2020
1 parent 1c7ff02 commit 70897c5
Show file tree
Hide file tree
Showing 21 changed files with 228 additions and 33 deletions.
3 changes: 3 additions & 0 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const meow = require('meow');
const createInkApp = require('.');

meow(`
Options
--typescript Use TypeScript React template
Usage
$ mkdir my-cli
$ cd my-cli
Expand Down
113 changes: 82 additions & 31 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const {promisify} = require('util');
const path = require('path');
const fs = require('fs');
const makeDir = require('make-dir');
const replaceString = require('replace-string');
const slugify = require('slugify');
const execa = require('execa');
Expand All @@ -12,6 +13,9 @@ const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);

const copyWithTemplate = async (from, to, variables) => {
const dirname = path.dirname(to);
await makeDir(dirname);

const source = await readFile(from, 'utf8');
let generatedSource = source;

Expand All @@ -22,9 +26,69 @@ const copyWithTemplate = async (from, to, variables) => {
await writeFile(to, generatedSource);
};

const fromPath = file => path.join(__dirname, 'template', file);
const useTypeScript = process.argv.includes('--typescript');
let templatePath = 'templates/js';

if (useTypeScript) {
templatePath = 'templates/ts';
}

const fromPath = file => path.join(__dirname, templatePath, file);
const toPath = file => path.join(process.cwd(), file);

const copyTasks = variables => {
const commonTasks = [
copyWithTemplate(
fromPath('_package.json'),
toPath('package.json'),
variables
),
copyWithTemplate(
fromPath('../_common/readme.md'),
toPath('readme.md'),
variables
),
cpy(
[
fromPath('../_common/.editorconfig'),
fromPath('../_common/.gitattributes'),
fromPath('../_common/.gitignore')
],
process.cwd()
)
];

return useTypeScript
? [
...commonTasks,
cpy(fromPath('source/ui.tsx'), toPath('source')),
copyWithTemplate(
fromPath('source/cli.tsx'),
toPath('source/cli.tsx'),
variables
),
cpy(fromPath('source/test.tsx'), toPath('source')),
cpy(fromPath('tsconfig.json'), process.cwd())
]
: [
...commonTasks,
copyWithTemplate(fromPath('cli.js'), toPath('cli.js'), variables),
cpy(fromPath('ui.js'), process.cwd()),
cpy(fromPath('test.js'), process.cwd())
];
};

const dependencies = useTypeScript ? [''] : ['import-jsx'];

const devDependencies = useTypeScript
? ['@ava/typescript', '@sindresorhus/tsconfig', '@types/react', 'typescript']
: [
'@ava/babel',
'@babel/preset-env',
'@babel/preset-react',
'@babel/register'
];

module.exports = () => {
const pkgName = slugify(path.basename(process.cwd()));

Expand All @@ -36,56 +100,43 @@ module.exports = () => {
name: pkgName
};

return Promise.all([
copyWithTemplate(
fromPath('_package.json'),
toPath('package.json'),
variables
),
copyWithTemplate(
fromPath('readme.md'),
toPath('readme.md'),
variables
),
copyWithTemplate(fromPath('cli.js'), toPath('cli.js'), variables),
cpy(fromPath('ui.js'), process.cwd()),
cpy(fromPath('test.js'), process.cwd()),
cpy(
[
fromPath('.editorconfig'),
fromPath('.gitattributes'),
fromPath('.gitignore')
],
process.cwd()
)
]);
return Promise.all(copyTasks(variables));
}
},
{
title: 'Install dependencies',
task: async () => {
await execa('npm', ['install', 'meow', 'ink', 'react', 'import-jsx']);
await execa('npm', [
'install',
'meow',
'ink',
'react',
...dependencies
]);

return execa('npm', [
'install',
'--save-dev',
'xo',
'ava',
'@ava/babel',
'ink-testing-library',
'chalk',
'@babel/preset-env',
'@babel/preset-react',
'@babel/register',
'eslint-config-xo-react',
'eslint-plugin-react',
'eslint-plugin-react-hooks'
'eslint-plugin-react-hooks',
...devDependencies
]);
}
},
{
title: 'Link executable',
task: () => execa('npm', ['link'])
task: async () => {
if (useTypeScript) {
await execa('npm', ['run', 'build']);
}

return execa('npm', ['link']);
}
}
]);

Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"files": [
"index.js",
"cli.js",
"template"
"templates"
],
"keywords": [
"ink",
Expand All @@ -32,6 +32,7 @@
"cpy": "^7.2.0",
"execa": "^1.0.0",
"listr": "^0.14.3",
"make-dir": "^3.1.0",
"meow": "^5.0.0",
"replace-string": "^3.0.0",
"slugify": "^1.3.4"
Expand All @@ -44,7 +45,7 @@
"xo": {
"prettier": true,
"ignores": [
"template"
"templates/**"
]
},
"prettier": "@vdemedes/prettier-config"
Expand Down
2 changes: 2 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ This helper tool scaffolds out basic project structure for Ink apps and lets you
$ mkdir my-fancy-cli
$ cd my-fancy-cli
$ npx create-ink-app
# Or create with TypeScript React
$ npx create-ink-app --typescript
```

![](media/demo.gif)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
12 changes: 12 additions & 0 deletions templates/ts/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.yml]
indent_style = space
indent_size = 2
1 change: 1 addition & 0 deletions templates/ts/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
2 changes: 2 additions & 0 deletions templates/ts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
yarn.lock
34 changes: 34 additions & 0 deletions templates/ts/_package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "%NAME%",
"version": "0.0.0",
"license": "MIT",
"bin": "dist/cli.js",
"engines": {
"node": ">=10"
},
"scripts": {
"build": "tsc",
"start": "npm run build && dist/cli.js",
"pretest": "npm run build",
"test": "xo && ava"
},
"files": [
"dist/cli.js"
],
"dependencies": {},
"devDependencies": {},
"ava": {
"typescript": {
"extensions": ["tsx"],
"rewritePaths": {
"source/": "dist/"
}
}
},
"xo": {
"extends": "xo-react",
"rules": {
"react/prop-types": "off"
}
}
}
27 changes: 27 additions & 0 deletions templates/ts/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# %NAME%

> This readme is automatically generated by [create-ink-app](https://github.com/vadimdemedes/create-ink-app)

## Install

```bash
$ npm install --global %NAME%
```


## CLI

```
$ %NAME% --help
Usage
$ %NAME%
Options
--name Your name
Examples
$ %NAME% --name=Jane
Hello, Jane
```
25 changes: 25 additions & 0 deletions templates/ts/source/cli.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env node
import React from 'react';
import {render} from 'ink';
import meow from 'meow';
import App from './ui';

const cli = meow(`
Usage
$ %NAME%
Options
--name Your name
Examples
$ %NAME% --name=Jane
Hello, Jane
`, {
flags: {
name: {
type: 'string'
}
}
});

render(<App name={cli.flags.name}/>);
17 changes: 17 additions & 0 deletions templates/ts/source/test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import chalk from 'chalk';
import test from 'ava';
import {render} from 'ink-testing-library';
import App from './ui';

test('greet unknown user', t => {
const {lastFrame} = render(<App/>);

t.is(lastFrame(), chalk`Hello, {green Stranger}`);
});

test('greet user with a name', t => {
const {lastFrame} = render(<App name="Jane"/>);

t.is(lastFrame(), chalk`Hello, {green Jane}`);
});
11 changes: 11 additions & 0 deletions templates/ts/source/ui.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, {FC} from 'react';
import {Text} from 'ink';

const App: FC<{name?: string}> = ({name = 'Stranger'}) => (
<Text>
Hello, <Text color="green">{name}</Text>
</Text>
);

module.exports = App;
export default App;
9 changes: 9 additions & 0 deletions templates/ts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "@sindresorhus/tsconfig",
"compilerOptions": {
"jsx": "react",
"esModuleInterop": true,
"outDir": "dist"
},
"include": ["source"]
}

0 comments on commit 70897c5

Please sign in to comment.