Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1548c01

Browse files
[PR] 新增题目文件创建器 (#1)
* [新增] 新增题目文件创建器 * [新增] 新增题目文件创建器
1 parent 1cdde66 commit 1548c01

File tree

8 files changed

+522
-5
lines changed

8 files changed

+522
-5
lines changed

‎.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# EJS template
2+
**/*.ejs

‎README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
Ruixe 的 LeetCode 算法题集,使用 TypeScript 语言,集成 Jest 单元测试
44

5+
## 新建题目
6+
7+
创建新的题目源码、单元测试与测试用例文件
8+
9+
```shell
10+
# NPM
11+
npm run create-files
12+
13+
# Yarn
14+
yarn create-files
15+
```
16+
517
## 运行单元测试
618

719
### 安装依赖
@@ -45,6 +57,7 @@ ts-node --esm ./src/[题目文件名]
4557
## 目录结构
4658

4759
```
60+
├── creator - 题目文件创建器
4861
├── src - 题目与题解源码
4962
└── tests - 单元测试文件
5063
└── testCases - 测试用例

‎creator/index.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import inquirer from 'inquirer'
2+
import ejs from 'ejs'
3+
import path from 'path'
4+
import { fileURLToPath } from 'url'
5+
import * as fs from 'fs/promises'
6+
7+
// 获取当前所在路径
8+
const dirname = path.dirname(fileURLToPath(import.meta.url))
9+
10+
/** EJS 模板参数 */
11+
const templateParams = {
12+
/** 题目编号 */
13+
titleNumber: 0,
14+
/** 题目中文标题 */
15+
titleChinese: '',
16+
/** 题目英文标题 */
17+
titleEnglish: '',
18+
/** LeetCode 入口函数名 */
19+
leetCodeFunctionName: '',
20+
/** LeetCode 题目链接 */
21+
problemLink: '',
22+
/** 题目难度(简单 中等 困难) */
23+
difficulty: '',
24+
/** JS 模块名称,格式:[题目编号]_[英文小驼峰题目名称] */
25+
moduleName: ''
26+
}
27+
28+
/**
29+
* 将英文句子转换为小驼峰字符串
30+
* @param {string} sentence - 英文句子
31+
*/
32+
function getLowerCamelCaseBySentence (sentence: string): string {
33+
let result: string = ''
34+
const words = sentence.split(' ').map(word => word.toLowerCase())
35+
result += words.shift() ?? ''
36+
words.forEach(word => { result += word.charAt(0).toUpperCase() + word.slice(1) })
37+
return result
38+
}
39+
40+
/**
41+
* 通过用户输入设置模板参数
42+
*/
43+
async function setTemplateParams (): Promise<void> {
44+
// 通过控制台用户输入或选择参数
45+
const answers = await inquirer.prompt(
46+
[
47+
{ name: 'titleNumber', type: 'number', message: 'Title number:' },
48+
{ name: 'titleChinese', type: 'string', message: 'Chinese title:' },
49+
{ name: 'titleEnglish', type: 'string', message: 'English title:' },
50+
{ name: 'leetCodeFunctionName', type: 'string', message: 'LeetCode function name:', default: 'main' },
51+
{ name: 'problemLink', type: 'string', message: 'LeetCode link:' },
52+
{ name: 'difficulty', type: 'list', message: 'Difficulty:', choices: ['Easy', 'Medium', 'Hard'], default: 'Medium' }
53+
]
54+
)
55+
56+
// 设置难度
57+
answers.difficulty = {
58+
Easy: '简单',
59+
Medium: '中等',
60+
Hard: '困难'
61+
}[answers.difficulty as string]
62+
63+
// 设置模块名称
64+
templateParams.moduleName = `${answers.titleNumber as string}_${getLowerCamelCaseBySentence(answers.titleEnglish)}`
65+
66+
// 合并模板参数
67+
Object.assign(templateParams, answers)
68+
}
69+
70+
/**
71+
* 创建文件
72+
* @description 创建源码、单元测试、测试用例文件
73+
*/
74+
function createFiles (): void {
75+
// 创建源码文件
76+
const srcFilePath = path.join(dirname, `../src/${templateParams.moduleName}.ts`)
77+
ejs.renderFile(path.join(dirname, './templates/src.ts.ejs'), templateParams).then(result => {
78+
void fs.writeFile(srcFilePath, result)
79+
})
80+
81+
// 创建单元测试文件
82+
const unitTestFilePath = path.join(dirname, `../tests/${templateParams.moduleName}.test.ts`)
83+
ejs.renderFile(path.join(dirname, './templates/unitTest.ts.ejs'), templateParams).then(result => {
84+
void fs.writeFile(unitTestFilePath, result)
85+
})
86+
87+
// 创建测试用例文件
88+
const testCaseFilePath = path.join(dirname, `../tests/testCases/${templateParams.moduleName}.ts`)
89+
ejs.renderFile(path.join(dirname, './templates/testCase.ts.ejs'), templateParams).then(result => {
90+
void fs.writeFile(testCaseFilePath, result)
91+
})
92+
}
93+
94+
// 程序入口
95+
void (async function (): Promise<void> {
96+
// 设置模板参数
97+
await setTemplateParams()
98+
99+
// 创建文件
100+
createFiles()
101+
})()

‎creator/templates/src.ts.ejs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
<%= titleNumber %>. <%= titleChinese %>
3+
难度:<%= difficulty %>
4+
题目链接:<%= problemLink %>
5+
6+
7+
*/
8+
9+
import { fileURLToPath } from 'url'
10+
import testCases from '../tests/testCases/<%= moduleName %>.js'
11+
12+
/**
13+
* <%= titleChinese %>
14+
* - LeetCode 入口
15+
* @param {string} param1 -
16+
* @returns {string}
17+
*/
18+
export function <%= leetCodeFunctionName %> (param1: string): string {
19+
20+
}
21+
22+
// Debug
23+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
24+
const { input, expected } = testCases[0]
25+
const output = <%= leetCodeFunctionName %>(input)
26+
console.log({ input, output, expected })
27+
}

‎creator/templates/testCase.ts.ejs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default [
2+
{ input: 'input_1', expected: 'expected_1' },
3+
{ input: 'input_2', expected: 'expected_2' }
4+
]

‎creator/templates/unitTest.ts.ejs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { describe, test, expect } from '@jest/globals'
2+
import testCases from './testCases/<%= moduleName %>.js'
3+
import { <%= leetCodeFunctionName %> } from '../src/<%= moduleName %>.js'
4+
5+
describe('<%= titleNumber %>. <%= titleEnglish %>', () => {
6+
testCases.forEach((testCase, index) => {
7+
test(`Test case index: ${index}, Input: ${testCase.input}`, () => {
8+
expect(<%= leetCodeFunctionName %>(testCase.input)).toEqual(testCase.expected)
9+
})
10+
})
11+
})

‎package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"node": ">=14.16"
99
},
1010
"scripts": {
11+
"create-files": "ts-node --esm ./creator/index.ts",
1112
"test": "jest"
1213
},
1314
"keywords": [
@@ -20,14 +21,18 @@
2021
"devDependencies": {
2122
"@babel/preset-env": "^7.20.2",
2223
"@babel/preset-typescript": "^7.18.6",
24+
"@types/ejs": "^3.1.1",
25+
"@types/inquirer": "^9.0.3",
2326
"@types/jest": "^29.2.2",
2427
"@typescript-eslint/eslint-plugin": "^5.0.0",
2528
"babel-plugin-transform-import-meta": "^2.2.0",
29+
"ejs": "^3.1.8",
2630
"eslint": "^8.0.1",
2731
"eslint-config-standard-with-typescript": "^23.0.0",
2832
"eslint-plugin-import": "^2.25.2",
2933
"eslint-plugin-n": "^15.0.0",
3034
"eslint-plugin-promise": "^6.0.0",
35+
"inquirer": "^9.1.4",
3136
"jest": "^29.2.2",
3237
"ts-jest": "^29.0.3",
3338
"ts-node": "^10.9.1",

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /