├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .npmrc ├── cli.js ├── index.js ├── license ├── media └── demo.gif ├── package.json ├── readme.md ├── templates ├── _common │ ├── _editorconfig │ ├── _gitattributes │ ├── _gitignore │ ├── _prettierignore │ └── readme.md ├── js │ ├── _package.json │ ├── source │ │ ├── app.js │ │ └── cli.js │ └── test.js └── ts │ ├── _package.json │ ├── readme.md │ ├── source │ ├── app.tsx │ └── cli.tsx │ ├── test.tsx │ └── tsconfig.json └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | test: 6 | name: Node.js ${{ matrix.node_version }} 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node_version: [16, 18] 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Use Node.js ${{ matrix.node_version }} 15 | uses: actions/setup-node@v3 16 | with: 17 | node-version: ${{ matrix.node_version }} 18 | - run: npm install 19 | - run: npm test 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import process from 'node:process'; 3 | import path from 'node:path'; 4 | import meow from 'meow'; 5 | import createInkApp from './index.js'; 6 | 7 | const cli = meow( 8 | ` 9 | Options 10 | --typescript Use TypeScript React template 11 | 12 | Usage 13 | $ create-ink-app 14 | 15 | Examples 16 | $ create-ink-app my-cli 17 | $ create-ink-app . 18 | `, 19 | { 20 | importMeta: import.meta, 21 | flags: { 22 | typescript: { 23 | type: 'boolean', 24 | }, 25 | }, 26 | }, 27 | ); 28 | 29 | const projectDirectoryPath = path.resolve(process.cwd(), cli.input[0] || '.'); 30 | 31 | try { 32 | console.log(); 33 | await createInkApp(projectDirectoryPath, cli.flags); 34 | 35 | const pkgName = path.basename(projectDirectoryPath); 36 | const relativePath = path.relative(process.cwd(), projectDirectoryPath); 37 | 38 | console.log( 39 | [ 40 | '', 41 | `Ink app created in ${relativePath ?? 'the current directory'}:`, 42 | relativePath ? ` $ cd ${relativePath}` : undefined, 43 | relativePath ? '' : undefined, 44 | 'Build:', 45 | ' $ npm run build', 46 | '', 47 | 'Watch and rebuild:', 48 | ' $ npm run dev', 49 | '', 50 | 'Run:', 51 | ` $ ${pkgName}`, 52 | '', 53 | ] 54 | .filter(line => line !== undefined) 55 | .map(line => ` ${line}`) 56 | .join('\n'), 57 | ); 58 | } catch (error) { 59 | console.error(error.stack); 60 | process.exit(1); 61 | } 62 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import {fileURLToPath} from 'node:url'; 3 | import path from 'node:path'; 4 | import fs from 'node:fs/promises'; 5 | import makeDir from 'make-dir'; 6 | import replaceString from 'replace-string'; 7 | import slugify from 'slugify'; 8 | import {execa} from 'execa'; 9 | import Listr from 'listr'; 10 | 11 | const copyWithTemplate = async (from, to, variables) => { 12 | const dirname = path.dirname(to); 13 | await makeDir(dirname); 14 | 15 | const source = await fs.readFile(from, 'utf8'); 16 | let generatedSource = source; 17 | 18 | if (typeof variables === 'object') { 19 | generatedSource = replaceString(source, '%NAME%', variables.name); 20 | } 21 | 22 | await fs.writeFile(to, generatedSource); 23 | }; 24 | 25 | const createInkApp = ( 26 | projectDirectoryPath = process.cwd(), 27 | {typescript, silent}, 28 | ) => { 29 | const pkgName = slugify(path.basename(projectDirectoryPath)); 30 | 31 | const execaInDirectory = (file, args, options = {}) => 32 | execa(file, args, { 33 | ...options, 34 | cwd: projectDirectoryPath, 35 | }); 36 | 37 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); 38 | const templatePath = typescript ? 'templates/ts' : 'templates/js'; 39 | 40 | const fromPath = file => 41 | path.join(path.resolve(__dirname, templatePath), file); 42 | 43 | const toPath = (rootPath, file) => path.join(rootPath, file); 44 | 45 | const tasks = new Listr( 46 | [ 47 | { 48 | title: 'Copy files', 49 | task() { 50 | const variables = { 51 | name: pkgName, 52 | }; 53 | 54 | return new Listr([ 55 | { 56 | title: 'Common files', 57 | async task() { 58 | await copyWithTemplate( 59 | fromPath('_package.json'), 60 | toPath(projectDirectoryPath, 'package.json'), 61 | variables, 62 | ); 63 | 64 | await copyWithTemplate( 65 | fromPath('../_common/readme.md'), 66 | toPath(projectDirectoryPath, 'readme.md'), 67 | variables, 68 | ); 69 | 70 | await fs.copyFile( 71 | fromPath('../_common/_editorconfig'), 72 | toPath(projectDirectoryPath, '.editorconfig'), 73 | ); 74 | 75 | await fs.copyFile( 76 | fromPath('../_common/_gitattributes'), 77 | toPath(projectDirectoryPath, '.gitattributes'), 78 | ); 79 | 80 | await fs.copyFile( 81 | fromPath('../_common/_gitignore'), 82 | toPath(projectDirectoryPath, '.gitignore'), 83 | ); 84 | 85 | await fs.copyFile( 86 | fromPath('../_common/_prettierignore'), 87 | toPath(projectDirectoryPath, '.prettierignore'), 88 | ); 89 | }, 90 | }, 91 | { 92 | title: 'JavaScript files', 93 | enabled: () => !typescript, 94 | async task() { 95 | await makeDir(toPath(projectDirectoryPath, 'source')); 96 | 97 | await fs.copyFile( 98 | fromPath('source/app.js'), 99 | toPath(projectDirectoryPath, 'source/app.js'), 100 | ); 101 | 102 | await copyWithTemplate( 103 | fromPath('source/cli.js'), 104 | toPath(projectDirectoryPath, 'source/cli.js'), 105 | variables, 106 | ); 107 | 108 | await fs.copyFile( 109 | fromPath('test.js'), 110 | toPath(projectDirectoryPath, 'test.js'), 111 | ); 112 | }, 113 | }, 114 | { 115 | title: 'TypeScript files', 116 | enabled: () => typescript, 117 | async task() { 118 | await makeDir(toPath(projectDirectoryPath, 'source')); 119 | 120 | await fs.copyFile( 121 | fromPath('source/app.tsx'), 122 | toPath(projectDirectoryPath, 'source/app.tsx'), 123 | ); 124 | 125 | await copyWithTemplate( 126 | fromPath('source/cli.tsx'), 127 | toPath(projectDirectoryPath, 'source/cli.tsx'), 128 | variables, 129 | ); 130 | 131 | await fs.copyFile( 132 | fromPath('test.tsx'), 133 | toPath(projectDirectoryPath, 'test.tsx'), 134 | ); 135 | 136 | await fs.copyFile( 137 | fromPath('tsconfig.json'), 138 | toPath(projectDirectoryPath, 'tsconfig.json'), 139 | ); 140 | }, 141 | }, 142 | ]); 143 | }, 144 | }, 145 | { 146 | title: 'Install dependencies', 147 | async task() { 148 | await execaInDirectory('npm', ['install']); 149 | }, 150 | }, 151 | { 152 | title: 'Format code', 153 | task() { 154 | return execaInDirectory('npx', ['prettier', '--write', '.']); 155 | }, 156 | }, 157 | { 158 | title: 'Build', 159 | task() { 160 | return execaInDirectory('npm', ['run', 'build']); 161 | }, 162 | }, 163 | { 164 | title: 'Link executable', 165 | async task(_, task) { 166 | try { 167 | await execaInDirectory('npm', ['link']); 168 | } catch { 169 | task.skip('`npm link` failed, try running it yourself'); 170 | } 171 | }, 172 | }, 173 | ], 174 | { 175 | renderer: silent ? 'silent' : 'default', 176 | }, 177 | ); 178 | 179 | return tasks.run(); 180 | }; 181 | 182 | export default createInkApp; 183 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Vadym Demedes (vadimdemedes.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /media/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vadimdemedes/create-ink-app/e0db9a086c56f6c35d9699aefee419f89e8f62dd/media/demo.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-ink-app", 3 | "version": "3.0.2", 4 | "description": "Generate a starter Ink app", 5 | "license": "MIT", 6 | "repository": "vadimdemedes/create-ink-app", 7 | "author": { 8 | "name": "Vadim Demedes", 9 | "email": "vadimdemedes@hey.com", 10 | "url": "vadimdemedes.com" 11 | }, 12 | "bin": "cli.js", 13 | "type": "module", 14 | "engines": { 15 | "node": ">=16" 16 | }, 17 | "scripts": { 18 | "test": "xo && ava" 19 | }, 20 | "files": [ 21 | "index.js", 22 | "cli.js", 23 | "templates" 24 | ], 25 | "keywords": [ 26 | "ink", 27 | "ink-app", 28 | "ink", 29 | "ink-app", 30 | "cli" 31 | ], 32 | "dependencies": { 33 | "cpy": "^9.0.1", 34 | "execa": "^7.1.1", 35 | "listr": "^0.14.3", 36 | "make-dir": "^3.1.0", 37 | "meow": "^11.0.0", 38 | "replace-string": "^4.0.0", 39 | "slugify": "^1.6.6" 40 | }, 41 | "devDependencies": { 42 | "@vdemedes/prettier-config": "^2.0.1", 43 | "ava": "^5.2.0", 44 | "del": "^7.0.0", 45 | "prettier": "^2.8.7", 46 | "strip-ansi": "^7.0.1", 47 | "tempy": "^3.0.0", 48 | "xo": "^0.53.1" 49 | }, 50 | "ava": { 51 | "timeout": "5m" 52 | }, 53 | "xo": { 54 | "prettier": true, 55 | "ignores": [ 56 | "templates/**" 57 | ] 58 | }, 59 | "prettier": "@vdemedes/prettier-config" 60 | } 61 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # create-ink-app [![test](https://github.com/vadimdemedes/create-ink-app/workflows/test/badge.svg)](https://github.com/vadimdemedes/create-ink-app/actions) 2 | 3 | > Generate a starter [Ink](https://github.com/vadimdemedes/ink) app 4 | 5 | ## Usage 6 | 7 | This helper tool scaffolds out basic project structure for Ink apps and lets you avoid the boilerplate and get to building beautiful CLIs in no time. 8 | 9 | ```bash 10 | $ npx create-ink-app js-app 11 | $ js-app 12 | 13 | # Or create with TypeScript 14 | $ npx create-ink-app --typescript ts-app 15 | $ ts-app 16 | ``` 17 | 18 | ![](media/demo.gif) 19 | -------------------------------------------------------------------------------- /templates/_common/_editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /templates/_common/_gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /templates/_common/_gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /templates/_common/_prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /templates/_common/readme.md: -------------------------------------------------------------------------------- 1 | # %NAME% 2 | 3 | > This readme is automatically generated by [create-ink-app](https://github.com/vadimdemedes/create-ink-app) 4 | 5 | ## Install 6 | 7 | ```bash 8 | $ npm install --global %NAME% 9 | ``` 10 | 11 | ## CLI 12 | 13 | ``` 14 | $ %NAME% --help 15 | 16 | Usage 17 | $ %NAME% 18 | 19 | Options 20 | --name Your name 21 | 22 | Examples 23 | $ %NAME% --name=Jane 24 | Hello, Jane 25 | ``` 26 | -------------------------------------------------------------------------------- /templates/js/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "%NAME%", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "bin": "dist/cli.js", 6 | "type": "module", 7 | "engines": { 8 | "node": ">=16" 9 | }, 10 | "scripts": { 11 | "build": "babel --out-dir=dist source", 12 | "dev": "babel --out-dir=dist --watch source", 13 | "test": "prettier --check . && xo && ava" 14 | }, 15 | "files": ["dist"], 16 | "dependencies": { 17 | "ink": "^4.1.0", 18 | "meow": "^11.0.0", 19 | "react": "^18.2.0" 20 | }, 21 | "devDependencies": { 22 | "@babel/cli": "^7.21.0", 23 | "@babel/preset-react": "^7.18.6", 24 | "@vdemedes/prettier-config": "^2.0.1", 25 | "ava": "^5.2.0", 26 | "chalk": "^5.2.0", 27 | "eslint-config-xo-react": "^0.27.0", 28 | "eslint-plugin-react": "^7.32.2", 29 | "eslint-plugin-react-hooks": "^4.6.0", 30 | "import-jsx": "^5.0.0", 31 | "ink-testing-library": "^3.0.0", 32 | "prettier": "^2.8.7", 33 | "xo": "^0.53.1" 34 | }, 35 | "ava": { 36 | "environmentVariables": { 37 | "NODE_NO_WARNINGS": "1" 38 | }, 39 | "nodeArguments": ["--loader=import-jsx"] 40 | }, 41 | "xo": { 42 | "extends": "xo-react", 43 | "prettier": true, 44 | "rules": { 45 | "react/prop-types": "off" 46 | } 47 | }, 48 | "prettier": "@vdemedes/prettier-config", 49 | "babel": { 50 | "presets": ["@babel/preset-react"] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /templates/js/source/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Text} from 'ink'; 3 | 4 | export default function App({name = 'Stranger'}) { 5 | return ( 6 | 7 | Hello, {name} 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /templates/js/source/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import React from 'react'; 3 | import {render} from 'ink'; 4 | import meow from 'meow'; 5 | import App from './app.js'; 6 | 7 | const cli = meow( 8 | ` 9 | Usage 10 | $ %NAME% 11 | 12 | Options 13 | --name Your name 14 | 15 | Examples 16 | $ %NAME% --name=Jane 17 | Hello, Jane 18 | `, 19 | { 20 | importMeta: import.meta, 21 | }, 22 | ); 23 | 24 | render(); 25 | -------------------------------------------------------------------------------- /templates/js/test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import chalk from 'chalk'; 3 | import test from 'ava'; 4 | import {render} from 'ink-testing-library'; 5 | import App from './source/app.js'; 6 | 7 | test('greet unknown user', t => { 8 | const {lastFrame} = render(); 9 | 10 | t.is(lastFrame(), `Hello, ${chalk.green('Stranger')}`); 11 | }); 12 | 13 | test('greet user with a name', t => { 14 | const {lastFrame} = render(); 15 | 16 | t.is(lastFrame(), `Hello, ${chalk.green('Jane')}`); 17 | }); 18 | -------------------------------------------------------------------------------- /templates/ts/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "%NAME%", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "bin": "dist/cli.js", 6 | "type": "module", 7 | "engines": { 8 | "node": ">=16" 9 | }, 10 | "scripts": { 11 | "build": "tsc", 12 | "dev": "tsc --watch", 13 | "test": "prettier --check . && xo && ava" 14 | }, 15 | "files": ["dist"], 16 | "dependencies": { 17 | "ink": "^4.1.0", 18 | "meow": "^11.0.0", 19 | "react": "^18.2.0" 20 | }, 21 | "devDependencies": { 22 | "@sindresorhus/tsconfig": "^3.0.1", 23 | "@types/react": "^18.0.32", 24 | "@vdemedes/prettier-config": "^2.0.1", 25 | "ava": "^5.2.0", 26 | "chalk": "^5.2.0", 27 | "eslint-config-xo-react": "^0.27.0", 28 | "eslint-plugin-react": "^7.32.2", 29 | "eslint-plugin-react-hooks": "^4.6.0", 30 | "ink-testing-library": "^3.0.0", 31 | "prettier": "^2.8.7", 32 | "ts-node": "^10.9.1", 33 | "typescript": "^5.0.3", 34 | "xo": "^0.53.1" 35 | }, 36 | "ava": { 37 | "extensions": { 38 | "ts": "module", 39 | "tsx": "module" 40 | }, 41 | "nodeArguments": ["--loader=ts-node/esm"] 42 | }, 43 | "xo": { 44 | "extends": "xo-react", 45 | "prettier": true, 46 | "rules": { 47 | "react/prop-types": "off" 48 | } 49 | }, 50 | "prettier": "@vdemedes/prettier-config" 51 | } 52 | -------------------------------------------------------------------------------- /templates/ts/readme.md: -------------------------------------------------------------------------------- 1 | # %NAME% 2 | 3 | > This readme is automatically generated by [create-ink-app](https://github.com/vadimdemedes/create-ink-app) 4 | 5 | ## Install 6 | 7 | ```bash 8 | $ npm install --global %NAME% 9 | ``` 10 | 11 | ## CLI 12 | 13 | ``` 14 | $ %NAME% --help 15 | 16 | Usage 17 | $ %NAME% 18 | 19 | Options 20 | --name Your name 21 | 22 | Examples 23 | $ %NAME% --name=Jane 24 | Hello, Jane 25 | ``` 26 | -------------------------------------------------------------------------------- /templates/ts/source/app.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Text} from 'ink'; 3 | 4 | type Props = { 5 | name: string | undefined; 6 | }; 7 | 8 | export default function App({name = 'Stranger'}: Props) { 9 | return ( 10 | 11 | Hello, {name} 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /templates/ts/source/cli.tsx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import React from 'react'; 3 | import {render} from 'ink'; 4 | import meow from 'meow'; 5 | import App from './app.js'; 6 | 7 | const cli = meow( 8 | ` 9 | Usage 10 | $ %NAME% 11 | 12 | Options 13 | --name Your name 14 | 15 | Examples 16 | $ %NAME% --name=Jane 17 | Hello, Jane 18 | `, 19 | { 20 | importMeta: import.meta, 21 | flags: { 22 | name: { 23 | type: 'string', 24 | }, 25 | }, 26 | }, 27 | ); 28 | 29 | render(); 30 | -------------------------------------------------------------------------------- /templates/ts/test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import chalk from 'chalk'; 3 | import test from 'ava'; 4 | import {render} from 'ink-testing-library'; 5 | import App from './source/app.js'; 6 | 7 | test('greet unknown user', t => { 8 | const {lastFrame} = render(); 9 | 10 | t.is(lastFrame(), `Hello, ${chalk.green('Stranger')}`); 11 | }); 12 | 13 | test('greet user with a name', t => { 14 | const {lastFrame} = render(); 15 | 16 | t.is(lastFrame(), `Hello, ${chalk.green('Jane')}`); 17 | }); 18 | -------------------------------------------------------------------------------- /templates/ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@sindresorhus/tsconfig", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["source"] 7 | } 8 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import test from 'ava'; 3 | import {execa} from 'execa'; 4 | import stripAnsi from 'strip-ansi'; 5 | import {temporaryDirectoryTask} from 'tempy'; 6 | import {deleteAsync} from 'del'; 7 | import createInkApp from './index.js'; 8 | 9 | const temporaryProjectTask = async (type, callback) => { 10 | await temporaryDirectoryTask(async temporaryDirectory => { 11 | const projectDirectory = path.join(temporaryDirectory, `test-${type}-app`); 12 | await deleteAsync(projectDirectory); 13 | 14 | try { 15 | await callback(projectDirectory); 16 | } finally { 17 | await execa('npm', ['unlink', '--global', `test-${type}-app`]); 18 | } 19 | }); 20 | }; 21 | 22 | test.serial('javascript app', async t => { 23 | await temporaryProjectTask('js', async projectDirectory => { 24 | await createInkApp(projectDirectory, { 25 | typescript: false, 26 | silent: true, 27 | }); 28 | 29 | const result = await execa('test-js-app'); 30 | t.is(stripAnsi(result.stdout).trim(), 'Hello, Stranger'); 31 | 32 | await t.notThrowsAsync( 33 | execa('npm', ['test'], { 34 | cwd: projectDirectory, 35 | }), 36 | ); 37 | }); 38 | }); 39 | 40 | test.serial('typescript app', async t => { 41 | await temporaryProjectTask('ts', async projectDirectory => { 42 | await createInkApp(projectDirectory, { 43 | typescript: false, 44 | silent: true, 45 | }); 46 | 47 | const result = await execa('test-ts-app'); 48 | t.is(stripAnsi(result.stdout).trim(), 'Hello, Stranger'); 49 | 50 | await t.notThrowsAsync( 51 | execa('npm', ['test'], { 52 | cwd: projectDirectory, 53 | }), 54 | ); 55 | }); 56 | }); 57 | --------------------------------------------------------------------------------