create-bananass 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,160 +1,18 @@
1
- # 바나나<sup>Bananass</sup>
1
+ # `create-bananass`
2
2
 
3
- [![ci](https://img.shields.io/github/actions/workflow/status/lumirlumir/npm-bananass/ci.yml?label=ci&color=fff478&labelColor=333333&logo=github)](https://github.com/lumirlumir/npm-bananass/actions/workflows/ci.yml)
4
- [![test](https://img.shields.io/github/actions/workflow/status/lumirlumir/npm-bananass/test.yml?label=test&color=fff478&labelColor=333333&logo=github)](https://github.com/lumirlumir/npm-bananass/actions/workflows/test.yml)
5
- [![Codecov](https://img.shields.io/codecov/c/gh/lumirlumir/npm-bananass?token=2zUCHlMFT3&label=Codecov&color=fff478&labelColor=333333&logo=codecov)](https://codecov.io/gh/lumirlumir/npm-bananass)
6
- ![Node Current](https://img.shields.io/node/v/bananass?label=Node&color=fff478&labelColor=333333&logo=node.js)
3
+ Create a Bananass framework project for solving Baekjoon problems with JavaScript/TypeScript.🍌
7
4
 
8
- [![npm package bananass latest version](https://img.shields.io/npm/v/bananass?label=bananass@latest&color=fff478&labelColor=333333&logo=npm)](https://www.npmjs.com/package/bananass)
9
- [![npm package bananass next version](https://img.shields.io/npm/v/bananass/next?label=bananass@next&color=fff478&labelColor=333333&logo=npm)](https://www.npmjs.com/package/bananass)
5
+ ## Documentation
10
6
 
11
- <kbd>한국어</kbd> | <kbd>[English](README.en.md)</kbd>
7
+ - [English](https://bananass.lumir.page/en/)
8
+ - [Korean](https://bananass.lumir.page/)
12
9
 
13
- 백준 자바스크립트 프레임워크.
10
+ ## Repository
14
11
 
15
- 자바스크립트 알고리즘 문제 풀이의 새로운 패러다임.
12
+ - [`create-bananass` monorepo](https://github.com/lumirlumir/npm-bananass)
13
+ - [`create-bananass` package](https://github.com/lumirlumir/npm-bananass/tree/main/packages/create-bananass)
16
14
 
17
- > [!IMPORTANT]
18
- >
19
- > ```js
20
- > const whyBananass = {
21
- > banana: '🍌',
22
- > bananas: '🍌🍌',
23
- > bananass: '🍌🍌🍌🍌',
24
- > }
25
- > ```
26
- >
27
- > ```js
28
- > console.log(('b' + 'a' + +'a' + 'a').toLowerCase() + (!(1/0) + [])[3].repeat(2));
29
- > ```
15
+ ## npm
30
16
 
31
- <!-- markdownlint-disable-next-line md026 -->
32
- ## 안녕, 바나나!
33
-
34
- 바나나<sup>Bananass</sup> 프레임워크에 오신 것을 환영합니다!
35
-
36
- 바나나는 **자바스크립트<sup>JavaScript</sup> 및 타입스크립트<sup>TypeScript</sup> 기반의 알고리즘 문제 풀이를 위한 프레임워크**로, [백준](https://www.acmicpc.net/)ㆍ[코드포스](https://codeforces.com/) 등 다양한 문제 풀이 플랫폼들의 Node.js 환경에서 반복적으로 마주치는 문제점들을 해결하며, 간결하고 편리한 사용자 경험을 제공합니다.
37
-
38
- - 타입스크립트<sup>TypeScript</sup> 지원이 필요하시다고요?
39
- - ES16<sup>ES2025</sup> 등 자바스크립트 최신 문법을 쓰고 싶은데 막히셨나요?
40
- - 외부 라이브러리를 사용하고 싶으신가요?
41
- - 매번 `readline` / `fs` 템플릿 코드 복붙하기 지치셨나요?
42
-
43
- 이제 걱정하지 마세요! 바나나 프레임워크는 이런 문제점들을 모두 해결합니다.
44
-
45
- ## 왜 바나나일까요?
46
-
47
- 함께 자바스크립트를 이용한 [백준 1000번: A+B](https://www.acmicpc.net/problem/1000) 문제 풀이 예제를 살펴봅시다!
48
-
49
- - 기존 방법을 통한 문제 풀이.
50
-
51
- ```js
52
- const readline = require('node:readline');
53
- const { EOL } = require('node:os');
54
-
55
- let inputStr = '';
56
-
57
- const rl = readline.createInterface({
58
- input: process.stdin,
59
- output: process.stdout,
60
- });
61
-
62
- rl.on('line', line => {
63
- inputStr = `${inputStr}${line}${EOL}`;
64
- }).on('close', () => {
65
- console.log(solution(inputStr));
66
-
67
- process.exit(0);
68
- });
69
-
70
- function solution(input) {
71
- const [a, b] = input
72
- .trim()
73
- .split(' ')
74
- .map(val => Number(val));
75
-
76
- return a + b;
77
- }
78
- ```
79
-
80
- - 바나나 프레임워크를 이용한 문제 풀이.
81
-
82
- ```js
83
- function solution(input) {
84
- const [a, b] = input
85
- .trim()
86
- .split(' ')
87
- .map(Number);
88
-
89
- return a + b;
90
- }
91
-
92
- export default { solution };
93
- ```
94
-
95
- 더 간결하고, 더 직관적인 코드! 입력 처리에 들이던 시간은 줄이고, 오직 알고리즘에만 집중할 수 있습니다.
96
-
97
- ## 이게 전부인가요?
98
-
99
- 물론, 아닙니다!
100
-
101
- - 자바스크립트<sup>JavaScript</sup> 및 타입스크립트<sup>TypeScript</sup> 지원.
102
- - ESM<sup>ECMAScript Module</sup> 및 CommonJS 모듈 시스템 지원.
103
- - 백준 Node.js 환경에 구애받지 않는 ES16<sup>ES2025</sup> 등 최신 문법 지원.
104
- - 사용자 정의 모듈 및 `lodash` 등 외부 라이브러리 불러오기 지원.
105
- - 프로그래머스처럼 `solution` 함수 하나로 시작하기 지원.
106
- - 테스트 케이스 작성 및 실행 지원.
107
- - `create-bananass`로 시작하기 지원.
108
- - `fs` 모듈을 사용한 더욱 빠른 입출력 지원.
109
- - 편의를 위한 다양한 CLI 명령어 지원.
110
- - 풍부하고 상세한 문서 지원.
111
- - ESLint 및 Prettier 설정 지원.
112
-
113
- 어떤가요? 바나나 프레임워크를 통해 더욱 편리한 문제 풀이를 경험해보고 싶지 않으신가요?
114
-
115
- ## 바나나로 시작하기
116
-
117
- [React](https://ko.react.dev)의 `create-react-app`, [Next.js](https://nextjs.org)의 `create-next-app` 처럼, 바나나 프레임워크에서 제공하는 `create-bananass`로 지금 바로 새로운 문제 풀이 패러다임을 경험해보세요!
118
-
119
- 바나나 프레임워크는 `create-bananass`를 통해 즉시 설치하고 사용할 수 있습니다.
120
-
121
- ```sh
122
- npm create bananass@latest
123
- ```
124
-
125
- 더 자세한 사용법은 [바나나 프레임워크 문서](https://bananass.lumir.page)를 참고해주세요.
126
-
127
- ## 바나나 프레임워크 문서
128
-
129
- 바나나 프레임워크는 문서화를 가장 큰 가치로 여깁니다. 바나나 프레임워크의 모든 사용법과 기능은 [바나나 프레임워크 문서](https://bananass.lumir.page)에서 확인하실 수 있습니다.
130
-
131
- ## 기여(이슈<sup>Issue</sup>, 끌어오기 요청<sup>Pull Request</sup>, 토론<sup>Discussion</sup>)
132
-
133
- 바나나 프레임워크 기여에 관심을 가져주셔서 감사합니다!
134
-
135
- 버그<sup>Bug</sup> 및 제안<sup>Suggestion</sup> 등 여러 주제에 대한 이슈<sup>Issue</sup>, 끌어오기 요청<sup>Pull Request</sup>, 토론<sup>Discussion</sup> 등을 모두 환영합니다.
136
-
137
- 다만, 올바른 커뮤니티 환경을 준수하고 더 나은 오픈 소스를 만들기 위해, 바나나 프레임워크에 기여하기 전 반드시 아래 내용들을 확인해주세요.
138
-
139
- - [기여자 행동 강령 규약](https://github.com/lumirlumir/.github/blob/main/CODE_OF_CONDUCT_KO.md#%EA%B8%B0%EC%97%AC%EC%9E%90-%ED%96%89%EB%8F%99-%EA%B0%95%EB%A0%B9-%EA%B7%9C%EC%95%BD)
140
- - [기여하기](CONTRIBUTING.md)
141
-
142
- ## 버전 정책<sup>Versioning</sup>
143
-
144
- 바나나 프레임워크는 [유의적 버전 정책<sup>Semantic Versioning</sup>](https://semver.org/lang/ko/)을 따릅니다. 모든 릴리즈 버전은 `주(MAJOR).부(MINOR).수(PATCH)` 형식을 따릅니다.
145
-
146
- ## 기여자 행동 강령 규약<sup>Code of Conduct</sup>
147
-
148
- 커뮤니티에 기여하기 전, [기여자 행동 강령 규약](https://github.com/lumirlumir/.github/blob/main/CODE_OF_CONDUCT_KO.md#%EA%B8%B0%EC%97%AC%EC%9E%90-%ED%96%89%EB%8F%99-%EA%B0%95%EB%A0%B9-%EA%B7%9C%EC%95%BD)을 참고해주세요.
149
-
150
- ## 변경 사항<sup>Change Log</sup>
151
-
152
- 변경 사항에 대한 상세한 내용을 확인하려면, [변경 사항](CHANGELOG.md)을 참고해주세요.
153
-
154
- ## 보안<sup>Security</sup>
155
-
156
- 보안 문제를 발견하셨나요? [보안](https://github.com/lumirlumir/.github/blob/main/SECURITY_KO.md#%EB%B3%B4%EC%95%88) 문서를 참고해주세요.
157
-
158
- ## 라이선스<sup>License</sup>
159
-
160
- 바나나 프레임워크는 MIT 라이선스를 따릅니다. [라이선스](LICENSE.md) 문서를 참고해주세요.
17
+ - [`npm`](https://www.npmjs.com/package/create-bananass)
18
+ - [`npmx`](https://npmx.dev/package/create-bananass)
package/build/cli.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @fileoverview Entry file for the `npx create-bananass` CLI command. See the `bin` field in `../package.json`.
4
+ *
5
+ * We receive arguments from both CLI and PROMPT.
6
+ */
7
+ export {};
package/build/cli.js ADDED
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @fileoverview Entry file for the `npx create-bananass` CLI command. See the `bin` field in `../package.json`.
4
+ *
5
+ * We receive arguments from both CLI and PROMPT.
6
+ */
7
+ // --------------------------------------------------------------------------------
8
+ // Import
9
+ // --------------------------------------------------------------------------------
10
+ import { cp, rename } from 'node:fs/promises';
11
+ import { spawn } from 'node:child_process';
12
+ import { resolve } from 'node:path';
13
+ import isInteractive from 'bananass-utils-console/is-interactive';
14
+ import createLogger from 'bananass-utils-console/logger';
15
+ import createSpinner from 'bananass-utils-console/spinner';
16
+ import { bananass, error, success } from 'bananass-utils-console/theme';
17
+ import { program } from 'commander';
18
+ import { consola } from 'consola';
19
+ import pkg from '../package.json' with { type: 'json' };
20
+ // --------------------------------------------------------------------------------
21
+ // Commander
22
+ // --------------------------------------------------------------------------------
23
+ program
24
+ .name(pkg.name)
25
+ .description(`${pkg.description} (${pkg.homepage})`)
26
+ .version(pkg.version, '-v, --version')
27
+ .argument('[directory]', 'the directory in which this project should be located', '.')
28
+ .usage('[directory] [options]')
29
+ .option('-d, --debug', 'enable debug mode', false)
30
+ .option('-q, --quiet', 'enable quiet mode', false)
31
+ .option('-f, --force', 'create a project even if the directory is not empty', false)
32
+ .option('-y, --yes', 'skip all prompts and accept only cli options', false)
33
+ .option('-c, --cjs', 'initialize as a commonjs project', false)
34
+ .option('-t, --typescript', 'initialize as a typescript project', false)
35
+ .option('--skip-vsc', 'skip initializing visual studio code', false)
36
+ .option('--skip-git', 'skip initializing git', false)
37
+ .option('--skip-install', 'skip installing packages with npm', false)
38
+ .action(async (cliDirectory, cliOptions) => {
39
+ // --------------------------------------------------------------------------
40
+ // CLI
41
+ // --------------------------------------------------------------------------
42
+ const { debug: cliDebug, quiet: cliQuiet, force: cliForce, yes: cliYes, cjs: cliCjs, typescript: cliTypescript, skipVsc: cliSkipVsc, skipGit: cliSkipGit, skipInstall: cliSkipInstall, } = cliOptions;
43
+ // --------------------------------------------------------------------------
44
+ // PROMPT
45
+ // --------------------------------------------------------------------------
46
+ let promptDirectory;
47
+ let promptCjs;
48
+ let promptTypescript;
49
+ let promptSkipVsc;
50
+ let promptSkipGit;
51
+ let promptSkipInstall;
52
+ if (isInteractive() && !cliYes) {
53
+ promptDirectory = await consola.prompt('Which directory should this project be located in?', {
54
+ placeholder: cliDirectory,
55
+ type: 'text',
56
+ cancel: 'reject',
57
+ });
58
+ promptCjs = await consola.prompt('Would you like to use CommonJS module system?', {
59
+ initial: false,
60
+ type: 'confirm',
61
+ cancel: 'reject',
62
+ });
63
+ promptTypescript = await consola.prompt('Would you like to use TypeScript?', {
64
+ initial: false,
65
+ type: 'confirm',
66
+ cancel: 'reject',
67
+ });
68
+ promptSkipVsc = await consola.prompt('Would you like to skip initializing Visual Studio Code configurations?', {
69
+ initial: false,
70
+ type: 'confirm',
71
+ cancel: 'reject',
72
+ });
73
+ promptSkipGit = await consola.prompt('Would you like to skip initializing Git?', {
74
+ initial: false,
75
+ type: 'confirm',
76
+ cancel: 'reject',
77
+ });
78
+ promptSkipInstall = await consola.prompt('Would you like to skip installing packages with npm?', {
79
+ initial: false,
80
+ type: 'confirm',
81
+ cancel: 'reject',
82
+ });
83
+ console.log(); // eslint-disable-line no-console -- Add a new line.
84
+ }
85
+ // --------------------------------------------------------------------------
86
+ // Merge CLI and PROMPT values (PROMPT values override CLI values)
87
+ // --------------------------------------------------------------------------
88
+ const directory = promptDirectory ?? cliDirectory;
89
+ const debug = cliDebug;
90
+ const quiet = cliQuiet;
91
+ const force = cliForce;
92
+ const yes = cliYes;
93
+ const cjs = promptCjs ?? cliCjs;
94
+ const typescript = promptTypescript ?? cliTypescript;
95
+ const skipVsc = promptSkipVsc ?? cliSkipVsc;
96
+ const skipGit = promptSkipGit ?? cliSkipGit;
97
+ const skipInstall = promptSkipInstall ?? cliSkipInstall;
98
+ // --------------------------------------------------------------------------
99
+ // Declarations
100
+ // --------------------------------------------------------------------------
101
+ const logger = createLogger({ debug, quiet });
102
+ const spinner = createSpinner();
103
+ // --------------------------------------------------------------------------
104
+ // Debug
105
+ // --------------------------------------------------------------------------
106
+ logger
107
+ .debug('cli directory:', cliDirectory)
108
+ .debug('cli options:', cliOptions)
109
+ .eol()
110
+ .debug('prompt directory:', promptDirectory)
111
+ .debug('prompt cjs:', promptCjs)
112
+ .debug('prompt typescript:', promptTypescript)
113
+ .debug('prompt skip vsc:', promptSkipVsc)
114
+ .debug('prompt skip git:', promptSkipGit)
115
+ .debug('prompt skip install:', promptSkipInstall)
116
+ .eol()
117
+ .debug('merged directory:', directory)
118
+ .debug('merged debug:', debug)
119
+ .debug('merged quiet:', quiet)
120
+ .debug('merged force:', force)
121
+ .debug('merged yes:', yes)
122
+ .debug('merged cjs:', cjs)
123
+ .debug('merged typescript:', typescript)
124
+ .debug('merged skip vsc:', skipVsc)
125
+ .debug('merged skip git:', skipGit)
126
+ .debug('merged skip install:', skipInstall)
127
+ .eol();
128
+ // --------------------------------------------------------------------------
129
+ // CLI Animation
130
+ // --------------------------------------------------------------------------
131
+ logger.log(() => spinner.start(bananass('Creating a new Bananass framework project...', true)));
132
+ // --------------------------------------------------------------------------
133
+ // Copy Files: Required
134
+ // --------------------------------------------------------------------------
135
+ logger.log(() => spinner.start(bananass('Copying files...', true)));
136
+ try {
137
+ await cp(new URL(`../templates/${typescript ? 'typescript' : 'javascript'}-${cjs ? 'cjs' : 'esm'}`, import.meta.url), directory, {
138
+ errorOnExist: true,
139
+ recursive: true,
140
+ force,
141
+ filter: src => !(skipVsc && src.includes('.vscode')), // Exclude `.vscode` folder if `skipVsc` is `true`.
142
+ });
143
+ await rename(resolve(directory, 'gitignore'), resolve(directory, '.gitignore'));
144
+ }
145
+ catch (err) {
146
+ logger.log(() => spinner.error(error('Failed to copy files')));
147
+ const message = err instanceof Error ? err.message : String(err);
148
+ throw new Error(error(message, true), { cause: err });
149
+ }
150
+ // --------------------------------------------------------------------------
151
+ // Install Visual Studio Code Extensions: Optional
152
+ // --------------------------------------------------------------------------
153
+ if (!skipVsc) {
154
+ logger.log(() => spinner.start(bananass('Installing Visual Studio Code extensions...', true)));
155
+ try {
156
+ const extensions = ['dbaeumer.vscode-eslint', 'esbenp.prettier-vscode'];
157
+ await Promise.all(extensions.map(extension => new Promise((res, rej) => {
158
+ const installExtension = spawn('code', ['--install-extension', extension], {
159
+ cwd: directory,
160
+ shell: true, // Required for Windows
161
+ });
162
+ installExtension.on('close', code => {
163
+ if (code === 0) {
164
+ res(undefined);
165
+ }
166
+ else {
167
+ rej(new Error(`code --install-extension ${extension} failed with exit code ${code}`));
168
+ }
169
+ });
170
+ installExtension.on('error', err => {
171
+ rej(err);
172
+ });
173
+ })));
174
+ }
175
+ catch (err) {
176
+ logger.log(() => spinner.error(error('Failed to install Visual Studio Code extensions')));
177
+ const message = err instanceof Error ? err.message : String(err);
178
+ throw new Error(error(message, true), { cause: err });
179
+ }
180
+ }
181
+ // --------------------------------------------------------------------------
182
+ // Initialize Git: Optional
183
+ // --------------------------------------------------------------------------
184
+ if (!skipGit) {
185
+ logger.log(() => spinner.start(bananass('Initializing git...', true)));
186
+ try {
187
+ await new Promise((res, rej) => {
188
+ const gitInit = spawn('git', ['init'], {
189
+ cwd: directory,
190
+ shell: true, // Required for Windows
191
+ });
192
+ gitInit.on('close', code => {
193
+ if (code === 0) {
194
+ res(undefined);
195
+ }
196
+ else {
197
+ rej(new Error(`git init failed with exit code ${code}`));
198
+ }
199
+ });
200
+ gitInit.on('error', err => {
201
+ rej(err);
202
+ });
203
+ });
204
+ }
205
+ catch (err) {
206
+ logger.log(() => spinner.error(error('Failed to initialize git')));
207
+ const message = err instanceof Error ? err.message : String(err);
208
+ throw new Error(error(message, true), { cause: err });
209
+ }
210
+ }
211
+ // --------------------------------------------------------------------------
212
+ // Install Packages: Optional
213
+ // --------------------------------------------------------------------------
214
+ if (!skipInstall) {
215
+ logger.log(() => spinner.start(bananass('Installing packages...', true)));
216
+ try {
217
+ await new Promise((res, rej) => {
218
+ const npmInstall = spawn('npm', ['install'], {
219
+ cwd: directory,
220
+ shell: true, // Required for Windows
221
+ });
222
+ npmInstall.on('close', code => {
223
+ if (code === 0) {
224
+ res(undefined);
225
+ }
226
+ else {
227
+ rej(new Error(`npm install failed with exit code ${code}`));
228
+ }
229
+ });
230
+ npmInstall.on('error', err => {
231
+ rej(err);
232
+ });
233
+ });
234
+ }
235
+ catch (err) {
236
+ logger.log(() => spinner.error(error('Failed to install packages')));
237
+ const message = err instanceof Error ? err.message : String(err);
238
+ throw new Error(error(message, true), { cause: err });
239
+ }
240
+ }
241
+ // --------------------------------------------------------------------------
242
+ // Exit
243
+ // --------------------------------------------------------------------------
244
+ logger.log(() => spinner.success(success('Successfully created a new Bananass framework project!')));
245
+ })
246
+ .parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bananass",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "description": "Create a Bananass framework project for solving Baekjoon problems with JavaScript/TypeScript.🍌",
6
6
  "exports": {
@@ -11,15 +11,13 @@
11
11
  "./templates/typescript-esm/package.json": "./templates/typescript-esm/package.json"
12
12
  },
13
13
  "bin": {
14
- "create-bananass": "src/cli.js"
14
+ "create-bananass": "build/cli.js"
15
15
  },
16
16
  "files": [
17
- "src",
17
+ "build",
18
18
  "templates",
19
19
  "LICENSE.md",
20
- "README.md",
21
- "!src/**/*.test.{js,ts}",
22
- "!**/fixtures/**"
20
+ "README.md"
23
21
  ],
24
22
  "keywords": [
25
23
  "bananass",
@@ -52,12 +50,14 @@
52
50
  },
53
51
  "scripts": {
54
52
  "prepublishOnly": "npm run build",
55
- "build": "tsc --noEmit && node ../../scripts/cp.js ../../LICENSE.md LICENSE.md ../../README.md README.md",
56
- "test": "node --test",
57
- "dev": "node src/cli.js"
53
+ "build": "tsc -b tsconfig.build.json",
54
+ "test": "npm run test:types && npm run test:unit",
55
+ "test:types": "tsc -b tsconfig.json",
56
+ "test:unit": "node --test",
57
+ "dev": "node src/cli.ts"
58
58
  },
59
59
  "dependencies": {
60
- "bananass-utils-console": "^0.8.0",
60
+ "bananass-utils-console": "^0.9.1",
61
61
  "commander": "^15.0.0",
62
62
  "consola": "^3.4.2"
63
63
  }
@@ -1,24 +1,28 @@
1
1
  import { defineConfig, globalIgnores } from 'eslint/config';
2
- import js from 'eslint-config-bananass/js';
2
+ import js from '@eslint/js';
3
+ import globals from 'globals';
3
4
 
4
- export default defineConfig([
5
+ export default defineConfig(
5
6
  // Bananass build directory.
6
7
  // Rename it if you change the `outDir` field in `bananass.config.cjs`.
7
8
  globalIgnores(['**/.bananass/']),
8
9
 
9
- js,
10
+ {
11
+ files: ['**/*.{js,mjs,cjs}'],
12
+ extends: [js.configs.recommended],
13
+ languageOptions: {
14
+ globals: globals.node,
15
+ },
10
16
 
11
- // Add your custom ESLint configuration here.
12
- //
13
- // For example:
14
- //
15
- // {
16
- // rules: {
17
- // 'no-console': 'off',
18
- // },
19
- // }
20
- // ...
21
- ]);
17
+ // Add your custom ESLint configuration here.
18
+ //
19
+ // For example:
20
+ //
21
+ // rules: {
22
+ // 'no-console': 'off',
23
+ // },
24
+ // ...
25
+ },
26
+ );
22
27
 
23
- // Please take a look at https://eslint-config-bananass.lumir.page
24
- // which contains all the available configurations.
28
+ // See https://eslint.org/docs/latest/use/configure/ for more configuration options.
@@ -21,9 +21,10 @@
21
21
  "prettier:fix": "prettier . --write --ignore-unknown"
22
22
  },
23
23
  "devDependencies": {
24
- "bananass": "^0.8.0",
25
- "eslint": "^9.39.4",
26
- "eslint-config-bananass": "^0.8.0",
27
- "prettier": "^3.9.4"
24
+ "@eslint/js": "^10.0.1",
25
+ "bananass": "^0.9.1",
26
+ "eslint": "^10.13.0",
27
+ "globals": "^17.13.0",
28
+ "prettier": "^3.9.6"
28
29
  }
29
30
  }
@@ -1,24 +1,28 @@
1
1
  import { defineConfig, globalIgnores } from 'eslint/config';
2
- import js from 'eslint-config-bananass/js';
2
+ import js from '@eslint/js';
3
+ import globals from 'globals';
3
4
 
4
- export default defineConfig([
5
+ export default defineConfig(
5
6
  // Bananass build directory.
6
7
  // Rename it if you change the `outDir` field in `bananass.config.mjs`.
7
8
  globalIgnores(['**/.bananass/']),
8
9
 
9
- js,
10
+ {
11
+ files: ['**/*.{js,mjs,cjs}'],
12
+ extends: [js.configs.recommended],
13
+ languageOptions: {
14
+ globals: globals.node,
15
+ },
10
16
 
11
- // Add your custom ESLint configuration here.
12
- //
13
- // For example:
14
- //
15
- // {
16
- // rules: {
17
- // 'no-console': 'off',
18
- // },
19
- // }
20
- // ...
21
- ]);
17
+ // Add your custom ESLint configuration here.
18
+ //
19
+ // For example:
20
+ //
21
+ // rules: {
22
+ // 'no-console': 'off',
23
+ // },
24
+ // ...
25
+ },
26
+ );
22
27
 
23
- // Please take a look at https://eslint-config-bananass.lumir.page
24
- // which contains all the available configurations.
28
+ // See https://eslint.org/docs/latest/use/configure/ for more configuration options.
@@ -21,9 +21,10 @@
21
21
  "prettier:fix": "prettier . --write --ignore-unknown"
22
22
  },
23
23
  "devDependencies": {
24
- "bananass": "^0.8.0",
25
- "eslint": "^9.39.4",
26
- "eslint-config-bananass": "^0.8.0",
27
- "prettier": "^3.9.4"
24
+ "@eslint/js": "^10.0.1",
25
+ "bananass": "^0.9.1",
26
+ "eslint": "^10.13.0",
27
+ "globals": "^17.13.0",
28
+ "prettier": "^3.9.6"
28
29
  }
29
30
  }
@@ -1,26 +1,36 @@
1
1
  import { defineConfig, globalIgnores } from 'eslint/config';
2
- import js from 'eslint-config-bananass/js';
3
- import ts from 'eslint-config-bananass/ts';
2
+ import js from '@eslint/js';
3
+ import parser from '@typescript-eslint/parser';
4
+ import globals from 'globals';
4
5
 
5
- export default defineConfig([
6
+ export default defineConfig(
6
7
  // Bananass build directory.
7
8
  // Rename it if you change the `outDir` field in `bananass.config.cts`.
8
9
  globalIgnores(['**/.bananass/']),
9
10
 
10
- js,
11
- ts,
11
+ {
12
+ files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],
13
+ extends: [js.configs.recommended],
14
+ languageOptions: {
15
+ globals: globals.node,
16
+ },
12
17
 
13
- // Add your custom ESLint configuration here.
14
- //
15
- // For example:
16
- //
17
- // {
18
- // rules: {
19
- // 'no-console': 'off',
20
- // },
21
- // }
22
- // ...
23
- ]);
18
+ // Add your custom ESLint configuration here.
19
+ //
20
+ // For example:
21
+ //
22
+ // rules: {
23
+ // 'no-console': 'off',
24
+ // },
25
+ // ...
26
+ },
24
27
 
25
- // Please take a look at https://eslint-config-bananass.lumir.page
26
- // which contains all the available configurations.
28
+ {
29
+ files: ['**/*.{ts,mts,cts}'],
30
+ languageOptions: {
31
+ parser,
32
+ },
33
+ },
34
+ );
35
+
36
+ // See https://eslint.org/docs/latest/use/configure/ for more configuration options.
@@ -22,12 +22,14 @@
22
22
  "tsc": "tsc"
23
23
  },
24
24
  "devDependencies": {
25
+ "@eslint/js": "^10.0.1",
25
26
  "@types/node": "^22.20.0",
26
- "bananass": "^0.8.0",
27
- "eslint": "^9.39.4",
28
- "eslint-config-bananass": "^0.8.0",
27
+ "@typescript-eslint/parser": "^8.72.0",
28
+ "bananass": "^0.9.1",
29
+ "eslint": "^10.13.0",
30
+ "globals": "^17.13.0",
29
31
  "jiti": "^2.7.0",
30
- "prettier": "^3.9.4",
32
+ "prettier": "^3.9.6",
31
33
  "typescript": "^6.0.3"
32
34
  }
33
35
  }
@@ -1,26 +1,36 @@
1
1
  import { defineConfig, globalIgnores } from 'eslint/config';
2
- import js from 'eslint-config-bananass/js';
3
- import ts from 'eslint-config-bananass/ts';
2
+ import js from '@eslint/js';
3
+ import parser from '@typescript-eslint/parser';
4
+ import globals from 'globals';
4
5
 
5
- export default defineConfig([
6
+ export default defineConfig(
6
7
  // Bananass build directory.
7
8
  // Rename it if you change the `outDir` field in `bananass.config.mts`.
8
9
  globalIgnores(['**/.bananass/']),
9
10
 
10
- js,
11
- ts,
11
+ {
12
+ files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],
13
+ extends: [js.configs.recommended],
14
+ languageOptions: {
15
+ globals: globals.node,
16
+ },
12
17
 
13
- // Add your custom ESLint configuration here.
14
- //
15
- // For example:
16
- //
17
- // {
18
- // rules: {
19
- // 'no-console': 'off',
20
- // },
21
- // }
22
- // ...
23
- ]);
18
+ // Add your custom ESLint configuration here.
19
+ //
20
+ // For example:
21
+ //
22
+ // rules: {
23
+ // 'no-console': 'off',
24
+ // },
25
+ // ...
26
+ },
24
27
 
25
- // Please take a look at https://eslint-config-bananass.lumir.page
26
- // which contains all the available configurations.
28
+ {
29
+ files: ['**/*.{ts,mts,cts}'],
30
+ languageOptions: {
31
+ parser,
32
+ },
33
+ },
34
+ );
35
+
36
+ // See https://eslint.org/docs/latest/use/configure/ for more configuration options.
@@ -22,12 +22,14 @@
22
22
  "tsc": "tsc"
23
23
  },
24
24
  "devDependencies": {
25
+ "@eslint/js": "^10.0.1",
25
26
  "@types/node": "^22.20.0",
26
- "bananass": "^0.8.0",
27
- "eslint": "^9.39.4",
28
- "eslint-config-bananass": "^0.8.0",
27
+ "@typescript-eslint/parser": "^8.72.0",
28
+ "bananass": "^0.9.1",
29
+ "eslint": "^10.13.0",
30
+ "globals": "^17.13.0",
29
31
  "jiti": "^2.7.0",
30
- "prettier": "^3.9.4",
32
+ "prettier": "^3.9.6",
31
33
  "typescript": "^6.0.3"
32
34
  }
33
35
  }
package/src/cli.js DELETED
@@ -1,377 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * @fileoverview Entry file for the `npx create-bananass` CLI command. See the `bin` field in `../package.json`.
5
- *
6
- * We receive arguments from both CLI and PROMPT.
7
- */
8
-
9
- // --------------------------------------------------------------------------------
10
- // Import
11
- // --------------------------------------------------------------------------------
12
-
13
- import { cp, rename } from 'node:fs/promises';
14
- import { createRequire } from 'node:module';
15
- import { spawn } from 'node:child_process';
16
- import { resolve } from 'node:path';
17
-
18
- import isInteractive from 'bananass-utils-console/is-interactive';
19
- import createLogger from 'bananass-utils-console/logger';
20
- import createSpinner from 'bananass-utils-console/spinner';
21
- import { bananass, error, success } from 'bananass-utils-console/theme';
22
- import { program } from 'commander';
23
- import { consola } from 'consola';
24
-
25
- // --------------------------------------------------------------------------------
26
- // Typedef
27
- // --------------------------------------------------------------------------------
28
-
29
- /**
30
- * @typedef cliOptions
31
- * @property {boolean} [debug] Enable debug mode.
32
- * @property {boolean} [quiet] Enable quiet mode.
33
- * @property {boolean} [force] Create a project even if the directory is not empty.
34
- * @property {boolean} [yes] Skip all prompts and accept only CLI options.
35
- * @property {boolean} [cjs] Initialize as a CommonJS project.
36
- * @property {boolean} [typescript] Initialize as a typescript project.
37
- * @property {boolean} [skipVsc] Skip initializing visual studio code.
38
- * @property {boolean} [skipGit] Skip initializing git.
39
- * @property {boolean} [skipInstall] Skip installing packages with npm.
40
- */
41
-
42
- // --------------------------------------------------------------------------------
43
- // Declarations
44
- // --------------------------------------------------------------------------------
45
-
46
- /** @type {{ description: string, homepage: string, name: string, version: string }} */
47
- const {
48
- description: pkgDescription,
49
- homepage: pkgHomepage,
50
- name: pkgName,
51
- version: pkgVersion,
52
- } = createRequire(import.meta.url)('../package.json');
53
-
54
- // --------------------------------------------------------------------------------
55
- // Commander
56
- // --------------------------------------------------------------------------------
57
-
58
- program
59
- .name(pkgName)
60
- .description(`${pkgDescription} (${pkgHomepage})`)
61
- .version(pkgVersion, '-v, --version')
62
- .argument('[directory]', 'the directory in which this project should be located', '.')
63
- .usage('[directory] [options]')
64
- .option('-d, --debug', 'enable debug mode', false)
65
- .option('-q, --quiet', 'enable quiet mode', false)
66
- .option('-f, --force', 'create a project even if the directory is not empty', false)
67
- .option('-y, --yes', 'skip all prompts and accept only cli options', false)
68
- .option('-c, --cjs', 'initialize as a commonjs project', false)
69
- .option('-t, --typescript', 'initialize as a typescript project', false)
70
- .option('--skip-vsc', 'skip initializing visual studio code', false)
71
- .option('--skip-git', 'skip initializing git', false)
72
- .option('--skip-install', 'skip installing packages with npm', false)
73
- .action(
74
- async (
75
- /** @type {string} */ cliDirectory,
76
- /** @type {Required<cliOptions>} */ cliOptions,
77
- ) => {
78
- // --------------------------------------------------------------------------
79
- // CLI
80
- // --------------------------------------------------------------------------
81
-
82
- const {
83
- debug: cliDebug,
84
- quiet: cliQuiet,
85
- force: cliForce,
86
- yes: cliYes,
87
- cjs: cliCjs,
88
- typescript: cliTypescript,
89
- skipVsc: cliSkipVsc,
90
- skipGit: cliSkipGit,
91
- skipInstall: cliSkipInstall,
92
- } = cliOptions;
93
-
94
- // --------------------------------------------------------------------------
95
- // PROMPT
96
- // --------------------------------------------------------------------------
97
-
98
- let promptDirectory;
99
- let promptCjs;
100
- let promptTypescript;
101
- let promptSkipVsc;
102
- let promptSkipGit;
103
- let promptSkipInstall;
104
-
105
- if (isInteractive() && !cliYes) {
106
- promptDirectory = await consola.prompt(
107
- 'Which directory should this project be located in?',
108
- {
109
- placeholder: cliDirectory,
110
- type: 'text',
111
- cancel: 'reject',
112
- },
113
- );
114
-
115
- promptCjs = await consola.prompt(
116
- 'Would you like to use CommonJS module system?',
117
- {
118
- initial: false,
119
- type: 'confirm',
120
- cancel: 'reject',
121
- },
122
- );
123
-
124
- promptTypescript = await consola.prompt('Would you like to use TypeScript?', {
125
- initial: false,
126
- type: 'confirm',
127
- cancel: 'reject',
128
- });
129
-
130
- promptSkipVsc = await consola.prompt(
131
- 'Would you like to skip initializing Visual Studio Code configurations?',
132
- {
133
- initial: false,
134
- type: 'confirm',
135
- cancel: 'reject',
136
- },
137
- );
138
-
139
- promptSkipGit = await consola.prompt('Would you like to skip initializing Git?', {
140
- initial: false,
141
- type: 'confirm',
142
- cancel: 'reject',
143
- });
144
-
145
- promptSkipInstall = await consola.prompt(
146
- 'Would you like to skip installing packages with npm?',
147
- {
148
- initial: false,
149
- type: 'confirm',
150
- cancel: 'reject',
151
- },
152
- );
153
-
154
- console.log(); // eslint-disable-line no-console -- Add a new line.
155
- }
156
-
157
- // --------------------------------------------------------------------------
158
- // Merge CLI and PROMPT values (PROMPT values override CLI values)
159
- // --------------------------------------------------------------------------
160
-
161
- const directory = promptDirectory ?? cliDirectory;
162
- const debug = cliDebug;
163
- const quiet = cliQuiet;
164
- const force = cliForce;
165
- const yes = cliYes;
166
- const cjs = promptCjs ?? cliCjs;
167
- const typescript = promptTypescript ?? cliTypescript;
168
- const skipVsc = promptSkipVsc ?? cliSkipVsc;
169
- const skipGit = promptSkipGit ?? cliSkipGit;
170
- const skipInstall = promptSkipInstall ?? cliSkipInstall;
171
-
172
- // --------------------------------------------------------------------------
173
- // Declarations
174
- // --------------------------------------------------------------------------
175
-
176
- const logger = createLogger({ debug, quiet });
177
- const spinner = createSpinner();
178
-
179
- // --------------------------------------------------------------------------
180
- // Debug
181
- // --------------------------------------------------------------------------
182
-
183
- logger
184
- .debug('cli directory:', cliDirectory)
185
- .debug('cli options:', cliOptions)
186
- .eol()
187
- .debug('prompt directory:', promptDirectory)
188
- .debug('prompt cjs:', promptCjs)
189
- .debug('prompt typescript:', promptTypescript)
190
- .debug('prompt skip vsc:', promptSkipVsc)
191
- .debug('prompt skip git:', promptSkipGit)
192
- .debug('prompt skip install:', promptSkipInstall)
193
- .eol()
194
- .debug('merged directory:', directory)
195
- .debug('merged debug:', debug)
196
- .debug('merged quiet:', quiet)
197
- .debug('merged force:', force)
198
- .debug('merged yes:', yes)
199
- .debug('merged cjs:', cjs)
200
- .debug('merged typescript:', typescript)
201
- .debug('merged skip vsc:', skipVsc)
202
- .debug('merged skip git:', skipGit)
203
- .debug('merged skip install:', skipInstall)
204
- .eol();
205
-
206
- // --------------------------------------------------------------------------
207
- // CLI Animation
208
- // --------------------------------------------------------------------------
209
-
210
- logger.log(() =>
211
- spinner.start(bananass('Creating a new Bananass framework project...', true)),
212
- );
213
-
214
- // --------------------------------------------------------------------------
215
- // Copy Files: Required
216
- // --------------------------------------------------------------------------
217
-
218
- logger.log(() => spinner.start(bananass('Copying files...', true)));
219
-
220
- try {
221
- await cp(
222
- new URL(
223
- `../templates/${typescript ? 'typescript' : 'javascript'}-${
224
- cjs ? 'cjs' : 'esm'
225
- }`,
226
- import.meta.url,
227
- ),
228
- directory,
229
- {
230
- errorOnExist: true,
231
- recursive: true,
232
- force,
233
- filter: src => !(skipVsc && src.includes('.vscode')), // Exclude `.vscode` folder if `skipVsc` is `true`.
234
- },
235
- );
236
-
237
- await rename(resolve(directory, 'gitignore'), resolve(directory, '.gitignore'));
238
- } catch (err) {
239
- logger.log(() => spinner.error(error('Failed to copy files')));
240
-
241
- const message = err instanceof Error ? err.message : String(err);
242
- throw new Error(error(message, true));
243
- }
244
-
245
- // --------------------------------------------------------------------------
246
- // Install Visual Studio Code Extensions: Optional
247
- // --------------------------------------------------------------------------
248
-
249
- if (!skipVsc) {
250
- logger.log(() =>
251
- spinner.start(bananass('Installing Visual Studio Code extensions...', true)),
252
- );
253
-
254
- try {
255
- const extensions = ['dbaeumer.vscode-eslint', 'esbenp.prettier-vscode'];
256
-
257
- await Promise.all(
258
- extensions.map(
259
- extension =>
260
- new Promise((res, rej) => {
261
- const installExtension = spawn(
262
- 'code',
263
- ['--install-extension', extension],
264
- {
265
- cwd: directory,
266
- shell: true, // Required for Windows
267
- },
268
- );
269
-
270
- installExtension.on('close', code => {
271
- if (code === 0) {
272
- res(undefined);
273
- } else {
274
- rej(
275
- new Error(
276
- `code --install-extension ${extension} failed with exit code ${code}`,
277
- ),
278
- );
279
- }
280
- });
281
-
282
- installExtension.on('error', err => {
283
- rej(err);
284
- });
285
- }),
286
- ),
287
- );
288
- } catch (err) {
289
- logger.log(() =>
290
- spinner.error(error('Failed to install Visual Studio Code extensions')),
291
- );
292
-
293
- const message = err instanceof Error ? err.message : String(err);
294
- throw new Error(error(message, true));
295
- }
296
- }
297
-
298
- // --------------------------------------------------------------------------
299
- // Initialize Git: Optional
300
- // --------------------------------------------------------------------------
301
-
302
- if (!skipGit) {
303
- logger.log(() => spinner.start(bananass('Initializing git...', true)));
304
-
305
- try {
306
- await new Promise((res, rej) => {
307
- const gitInit = spawn('git', ['init'], {
308
- cwd: directory,
309
- shell: true, // Required for Windows
310
- });
311
-
312
- gitInit.on('close', code => {
313
- if (code === 0) {
314
- res(undefined);
315
- } else {
316
- rej(new Error(`git init failed with exit code ${code}`));
317
- }
318
- });
319
-
320
- gitInit.on('error', err => {
321
- rej(err);
322
- });
323
- });
324
- } catch (err) {
325
- logger.log(() => spinner.error(error('Failed to initialize git')));
326
-
327
- const message = err instanceof Error ? err.message : String(err);
328
- throw new Error(error(message, true));
329
- }
330
- }
331
-
332
- // --------------------------------------------------------------------------
333
- // Install Packages: Optional
334
- // --------------------------------------------------------------------------
335
-
336
- if (!skipInstall) {
337
- logger.log(() => spinner.start(bananass('Installing packages...', true)));
338
-
339
- try {
340
- await new Promise((res, rej) => {
341
- const npmInstall = spawn('npm', ['install'], {
342
- cwd: directory,
343
- shell: true, // Required for Windows
344
- });
345
-
346
- npmInstall.on('close', code => {
347
- if (code === 0) {
348
- res(undefined);
349
- } else {
350
- rej(new Error(`npm install failed with exit code ${code}`));
351
- }
352
- });
353
-
354
- npmInstall.on('error', err => {
355
- rej(err);
356
- });
357
- });
358
- } catch (err) {
359
- logger.log(() => spinner.error(error('Failed to install packages')));
360
-
361
- const message = err instanceof Error ? err.message : String(err);
362
- throw new Error(error(message, true));
363
- }
364
- }
365
-
366
- // --------------------------------------------------------------------------
367
- // Exit
368
- // --------------------------------------------------------------------------
369
-
370
- logger.log(() =>
371
- spinner.success(
372
- success('Successfully created a new Bananass framework project!'),
373
- ),
374
- );
375
- },
376
- )
377
- .parse();