create-aomex 0.0.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/LICENSE +21 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +169 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -0
- package/templates/.commitlintrc.yml +2 -0
- package/templates/.env +1 -0
- package/templates/.eslintrc.yml +37 -0
- package/templates/.husky/commit-msg +3 -0
- package/templates/.husky/pre-commit +4 -0
- package/templates/.prettierignore +5 -0
- package/templates/.prettierrc.yml +16 -0
- package/templates/.vscode/extensions.json +3 -0
- package/templates/.vscode/settings.json +16 -0
- package/templates/README.md +15 -0
- package/templates/package.json +12 -0
- package/templates/prisma/schema.prisma +26 -0
- package/templates/src/cli.ts +10 -0
- package/templates/src/commanders/hello.cmd.ts +12 -0
- package/templates/src/middleware/console.chain.ts +9 -0
- package/templates/src/middleware/openapi.md.ts +13 -0
- package/templates/src/middleware/web.chain.ts +17 -0
- package/templates/src/routers/user.router.ts +18 -0
- package/templates/src/services/db.ts +5 -0
- package/templates/src/services/index.ts +11 -0
- package/templates/src/services/user.service.ts +12 -0
- package/templates/src/web.ts +11 -0
- package/templates/tsconfig.json +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2024 geekact
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// src/input-package-manager.ts
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
var packageManagers = ["pnpm", "npm", "yarn"];
|
|
4
|
+
var inputPackageManager = async (argv2) => {
|
|
5
|
+
for (const expected of packageManagers) {
|
|
6
|
+
if (argv2[expected]) return expected;
|
|
7
|
+
}
|
|
8
|
+
const { manager } = await inquirer.prompt({
|
|
9
|
+
name: "manager",
|
|
10
|
+
message: "\u9009\u62E9\u5305\u7BA1\u7406\u5DE5\u5177",
|
|
11
|
+
type: "list",
|
|
12
|
+
choices: packageManagers,
|
|
13
|
+
default: "pnpm",
|
|
14
|
+
askAnswered: true
|
|
15
|
+
});
|
|
16
|
+
return manager;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// src/input-project-name.ts
|
|
20
|
+
import inquirer2 from "inquirer";
|
|
21
|
+
import kebabCase from "lodash.kebabcase";
|
|
22
|
+
import { existsSync } from "node:fs";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
var inputProjectName = async (argv2) => {
|
|
25
|
+
if (typeof argv2["name"] === "string") return argv2["name"];
|
|
26
|
+
const result = await inquirer2.prompt({
|
|
27
|
+
name: "projectName",
|
|
28
|
+
type: "input",
|
|
29
|
+
message: "\u9879\u76EE\u540D\u79F0",
|
|
30
|
+
suffix: ":"
|
|
31
|
+
});
|
|
32
|
+
const projectName2 = kebabCase(result.projectName);
|
|
33
|
+
const absolutePath = path.posix.resolve(projectName2);
|
|
34
|
+
if (existsSync(absolutePath) && argv2["force"] !== true) {
|
|
35
|
+
const { goon } = await inquirer2.prompt({
|
|
36
|
+
name: "goon",
|
|
37
|
+
type: "confirm",
|
|
38
|
+
message: `\u76EE\u5F55 "${absolutePath}" \u5DF2\u7ECF\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6\uFF1F`,
|
|
39
|
+
suffix: ":"
|
|
40
|
+
});
|
|
41
|
+
if (!goon) {
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return projectName2;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// src/index.ts
|
|
49
|
+
import path3 from "node:path/posix";
|
|
50
|
+
import yargsParser from "yargs-parser";
|
|
51
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
52
|
+
import { cp, mkdir, rm } from "node:fs/promises";
|
|
53
|
+
import { Listr } from "listr2";
|
|
54
|
+
import { promisify, styleText } from "node:util";
|
|
55
|
+
import childProcess from "node:child_process";
|
|
56
|
+
|
|
57
|
+
// src/replace-variables.ts
|
|
58
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
59
|
+
import path2 from "node:path";
|
|
60
|
+
var replaceVariables = async (filename, variables) => {
|
|
61
|
+
const packageJSONFile = path2.resolve(filename);
|
|
62
|
+
let packageContent = await readFile(packageJSONFile, "utf8");
|
|
63
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
64
|
+
packageContent = packageContent.replaceAll(`{{${key}}}`, value);
|
|
65
|
+
});
|
|
66
|
+
await writeFile(packageJSONFile, packageContent);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// src/index.ts
|
|
70
|
+
var argv = yargsParser(process.argv.slice(2));
|
|
71
|
+
var projectName = await inputProjectName(argv);
|
|
72
|
+
var packageManager = await inputPackageManager(argv);
|
|
73
|
+
var templateDir = path3.join(import.meta.dirname, "..", "templates");
|
|
74
|
+
var targetDir = path3.resolve(projectName);
|
|
75
|
+
var exec = promisify(childProcess.exec);
|
|
76
|
+
var sleep = () => new Promise((resolve) => setTimeout(resolve, 500));
|
|
77
|
+
var spinner = new Listr([]);
|
|
78
|
+
spinner.add({
|
|
79
|
+
title: "\u521B\u5EFA\u76EE\u5F55",
|
|
80
|
+
task: async () => {
|
|
81
|
+
if (existsSync2(targetDir)) {
|
|
82
|
+
await rm(targetDir, { recursive: true, force: true });
|
|
83
|
+
}
|
|
84
|
+
await mkdir(targetDir, { recursive: true });
|
|
85
|
+
process.chdir(path3.resolve(projectName));
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
spinner.add({
|
|
89
|
+
title: "git\u521D\u59CB\u5316",
|
|
90
|
+
task: async () => {
|
|
91
|
+
await exec("git init");
|
|
92
|
+
await sleep();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
spinner.add({
|
|
96
|
+
title: "\u590D\u5236\u6A21\u677F\u6587\u4EF6",
|
|
97
|
+
task: async () => {
|
|
98
|
+
await cp(templateDir, targetDir, { recursive: true });
|
|
99
|
+
await replaceVariables("package.json", { projectName, packageManager });
|
|
100
|
+
await replaceVariables("README.md", { projectName, packageManager });
|
|
101
|
+
await sleep();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
spinner.add({
|
|
105
|
+
title: "\u589E\u52A0volta\u914D\u7F6E",
|
|
106
|
+
skip: async () => {
|
|
107
|
+
return !/\d\.\d/.test((await exec("volta -v")).stdout);
|
|
108
|
+
},
|
|
109
|
+
task: async () => {
|
|
110
|
+
await exec("volta pin node");
|
|
111
|
+
if (packageManager !== "npm") {
|
|
112
|
+
await exec(`volta pin ${packageManager}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
spinner.add({
|
|
117
|
+
title: "\u5B89\u88C5\u63D2\u4EF6",
|
|
118
|
+
task: async (_, task) => {
|
|
119
|
+
const packages = [
|
|
120
|
+
{ pkg: "@aomex/core" },
|
|
121
|
+
{ pkg: "@aomex/web" },
|
|
122
|
+
{ pkg: "@aomex/console" },
|
|
123
|
+
{ pkg: "@aomex/router" },
|
|
124
|
+
{ pkg: "@aomex/cors" },
|
|
125
|
+
{ pkg: "@aomex/etag" },
|
|
126
|
+
{ pkg: "@aomex/compress" },
|
|
127
|
+
{ pkg: "@aomex/http-logger" },
|
|
128
|
+
{ pkg: "@aomex/commander" },
|
|
129
|
+
{ pkg: "@aomex/openapi" },
|
|
130
|
+
{ pkg: "@prisma/client" },
|
|
131
|
+
{ pkg: "prisma", dev: true },
|
|
132
|
+
{ pkg: "typescript", dev: true },
|
|
133
|
+
{ pkg: "@types/node", dev: true },
|
|
134
|
+
{ pkg: "tsx", dev: true },
|
|
135
|
+
{ pkg: "husky", dev: true },
|
|
136
|
+
{ pkg: "tsc-alias", dev: true },
|
|
137
|
+
{ pkg: "prettier", dev: true },
|
|
138
|
+
{ pkg: "@commitlint/cli", dev: true },
|
|
139
|
+
{ pkg: "@commitlint/config-conventional", dev: true },
|
|
140
|
+
{ pkg: "eslint", dev: true },
|
|
141
|
+
{ pkg: "@typescript-eslint/eslint-plugin", dev: true },
|
|
142
|
+
{ pkg: "@typescript-eslint/parser", dev: true },
|
|
143
|
+
{ pkg: "eslint-plugin-check-file", dev: true }
|
|
144
|
+
];
|
|
145
|
+
const action = packageManager === "npm" ? "install" : "add";
|
|
146
|
+
const devSuffix = packageManager === "npm" ? "--save-dev" : "-D";
|
|
147
|
+
for (let i = 0; i < packages.length; ++i) {
|
|
148
|
+
const { pkg, dev } = packages[i];
|
|
149
|
+
task.title = "\u5B89\u88C5\u63D2\u4EF6 " + styleText("gray", pkg);
|
|
150
|
+
await exec(`${packageManager} ${action} ${pkg} ${dev ? devSuffix : ""}`, {
|
|
151
|
+
cwd: process.cwd(),
|
|
152
|
+
env: process.env
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
task.title = "\u5B89\u88C5\u63D2\u4EF6";
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
spinner.add({
|
|
159
|
+
title: "\u751F\u6210prisma/client\u6587\u4EF6",
|
|
160
|
+
task: async () => {
|
|
161
|
+
await exec("npx prisma generate");
|
|
162
|
+
await sleep();
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
await spinner.run();
|
|
166
|
+
console.log(
|
|
167
|
+
"\n\u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF1A" + styleText(["blue", "underline"], process.cwd()) + "\n"
|
|
168
|
+
);
|
|
169
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/input-package-manager.ts","../src/input-project-name.ts","../src/index.ts","../src/replace-variables.ts"],"sourcesContent":["import inquirer from 'inquirer';\n\nconst packageManagers = <const>['pnpm', 'npm', 'yarn'];\n\nexport type PackageManager = (typeof packageManagers)[number];\n\nexport const inputPackageManager = async (\n argv: Record<string, any>,\n): Promise<PackageManager> => {\n for (const expected of packageManagers) {\n if (argv[expected]) return expected;\n }\n\n const { manager } = await inquirer.prompt<{\n manager: PackageManager;\n }>({\n name: 'manager',\n message: '选择包管理工具',\n type: 'list',\n choices: packageManagers,\n default: 'pnpm',\n askAnswered: true,\n });\n\n return manager;\n};\n","import inquirer from 'inquirer';\nimport kebabCase from 'lodash.kebabcase';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\n\nexport const inputProjectName = async (\n argv: Record<string, any>,\n): Promise<string> => {\n if (typeof argv['name'] === 'string') return argv['name'];\n\n const result = await inquirer.prompt<{ projectName: string }>({\n name: 'projectName',\n type: 'input',\n message: '项目名称',\n suffix: ':',\n });\n\n const projectName = kebabCase(result.projectName);\n\n const absolutePath = path.posix.resolve(projectName);\n if (existsSync(absolutePath) && argv['force'] !== true) {\n const { goon } = await inquirer.prompt<{ goon: boolean }>({\n name: 'goon',\n type: 'confirm',\n message: `目录 \"${absolutePath}\" 已经存在,是否覆盖?`,\n suffix: ':',\n });\n\n if (!goon) {\n process.exit(0);\n }\n }\n\n return projectName;\n};\n","import { inputPackageManager } from './input-package-manager';\nimport { inputProjectName } from './input-project-name';\nimport path from 'node:path/posix';\nimport yargsParser from 'yargs-parser';\nimport { existsSync } from 'node:fs';\nimport { cp, mkdir, rm } from 'node:fs/promises';\nimport { Listr } from 'listr2';\nimport { promisify, styleText } from 'node:util';\nimport childProcess from 'node:child_process';\nimport { replaceVariables } from './replace-variables';\n\nconst argv = yargsParser(process.argv.slice(2));\nconst projectName = await inputProjectName(argv);\nconst packageManager = await inputPackageManager(argv);\nconst templateDir = path.join(import.meta.dirname, '..', 'templates');\nconst targetDir = path.resolve(projectName);\n\nconst exec = promisify(childProcess.exec);\nconst sleep = () => new Promise((resolve) => setTimeout(resolve, 500));\n\nconst spinner = new Listr([]);\n\nspinner.add({\n title: '创建目录',\n task: async () => {\n if (existsSync(targetDir)) {\n await rm(targetDir, { recursive: true, force: true });\n }\n await mkdir(targetDir, { recursive: true });\n process.chdir(path.resolve(projectName));\n },\n});\n\nspinner.add({\n title: 'git初始化',\n task: async () => {\n await exec('git init');\n await sleep();\n },\n});\n\nspinner.add({\n title: '复制模板文件',\n task: async () => {\n await cp(templateDir, targetDir, { recursive: true });\n await replaceVariables('package.json', { projectName, packageManager });\n await replaceVariables('README.md', { projectName, packageManager });\n await sleep();\n },\n});\n\nspinner.add({\n title: '增加volta配置',\n skip: async () => {\n return !/\\d\\.\\d/.test((await exec('volta -v')).stdout);\n },\n task: async () => {\n await exec('volta pin node');\n if (packageManager !== 'npm') {\n await exec(`volta pin ${packageManager}`);\n }\n },\n});\n\nspinner.add({\n title: '安装插件',\n task: async (_, task) => {\n const packages: { pkg: string; dev?: boolean }[] = [\n { pkg: '@aomex/core' },\n { pkg: '@aomex/web' },\n { pkg: '@aomex/console' },\n { pkg: '@aomex/router' },\n { pkg: '@aomex/cors' },\n { pkg: '@aomex/etag' },\n { pkg: '@aomex/compress' },\n { pkg: '@aomex/http-logger' },\n { pkg: '@aomex/commander' },\n { pkg: '@aomex/openapi' },\n { pkg: '@prisma/client' },\n { pkg: 'prisma', dev: true },\n { pkg: 'typescript', dev: true },\n { pkg: '@types/node', dev: true },\n { pkg: 'tsx', dev: true },\n { pkg: 'husky', dev: true },\n { pkg: 'tsc-alias', dev: true },\n { pkg: 'prettier', dev: true },\n { pkg: '@commitlint/cli', dev: true },\n { pkg: '@commitlint/config-conventional', dev: true },\n { pkg: 'eslint', dev: true },\n { pkg: '@typescript-eslint/eslint-plugin', dev: true },\n { pkg: '@typescript-eslint/parser', dev: true },\n { pkg: 'eslint-plugin-check-file', dev: true },\n ];\n const action = packageManager === 'npm' ? 'install' : 'add';\n const devSuffix = packageManager === 'npm' ? '--save-dev' : '-D';\n\n for (let i = 0; i < packages.length; ++i) {\n const { pkg, dev } = packages[i]!;\n task.title = '安装插件 ' + styleText('gray', pkg);\n await exec(`${packageManager} ${action} ${pkg} ${dev ? devSuffix : ''}`, {\n cwd: process.cwd(),\n env: process.env,\n });\n }\n task.title = '安装插件';\n },\n});\n\nspinner.add({\n title: '生成prisma/client文件',\n task: async () => {\n await exec('npx prisma generate');\n await sleep();\n },\n});\n\nawait spinner.run();\n\nconsole.log(\n '\\n项目创建成功:' + styleText(['blue', 'underline'], process.cwd()) + '\\n',\n);\n","import { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\n\nexport const replaceVariables = async (\n filename: string,\n variables: Record<string, string>,\n) => {\n const packageJSONFile = path.resolve(filename);\n let packageContent = await readFile(packageJSONFile, 'utf8');\n Object.entries(variables).forEach(([key, value]) => {\n packageContent = packageContent.replaceAll(`{{${key}}}`, value);\n });\n await writeFile(packageJSONFile, packageContent);\n};\n"],"mappings":"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","names":["argv","inquirer","argv","projectName","path","existsSync","path","path","existsSync"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-aomex",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"repository": "git@github.com:aomex/create-aomex.git",
|
|
5
|
+
"author": "geekact <fanwenhua1990@gmail.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"cli": "tsx src/index.ts",
|
|
10
|
+
"release": "release-it --ci",
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"prepublishOnly": "pnpm build"
|
|
13
|
+
},
|
|
14
|
+
"volta": {
|
|
15
|
+
"node": "20.15.0",
|
|
16
|
+
"pnpm": "9.4.0"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"templates",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"package.json",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"bin": "dist/index.js",
|
|
32
|
+
"packageManager": "pnpm@9.4.0",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"inquirer": "^9.2.23",
|
|
35
|
+
"listr2": "^8.2.3",
|
|
36
|
+
"lodash.kebabcase": "^4.1.1",
|
|
37
|
+
"yargs-parser": "^21.1.1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@aomex/commander": "^1.0.4",
|
|
41
|
+
"@aomex/compress": "^1.0.4",
|
|
42
|
+
"@aomex/console": "^1.0.4",
|
|
43
|
+
"@aomex/core": "^1.0.4",
|
|
44
|
+
"@aomex/cors": "^1.0.4",
|
|
45
|
+
"@aomex/etag": "^1.0.4",
|
|
46
|
+
"@aomex/helmet": "^1.0.4",
|
|
47
|
+
"@aomex/http-logger": "^1.0.4",
|
|
48
|
+
"@aomex/openapi": "^1.0.4",
|
|
49
|
+
"@aomex/router": "^1.0.4",
|
|
50
|
+
"@aomex/web": "^1.0.4",
|
|
51
|
+
"@prisma/client": "^5.16.0",
|
|
52
|
+
"@types/inquirer": "^9.0.7",
|
|
53
|
+
"@types/lodash.kebabcase": "^4.1.9",
|
|
54
|
+
"@types/node": "^20.14.8",
|
|
55
|
+
"@types/yargs-parser": "^21.0.3",
|
|
56
|
+
"prisma": "^5.16.0",
|
|
57
|
+
"release-it": "^17.4.0",
|
|
58
|
+
"tsup": "^8.1.0",
|
|
59
|
+
"tsx": "^4.15.7",
|
|
60
|
+
"typescript": "^5.5.2"
|
|
61
|
+
}
|
|
62
|
+
}
|
package/templates/.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DATABASE_URL="mysql://USERNAME:PASSWORD@HOST:PORT/DB_NAME"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
parser: '@typescript-eslint/parser'
|
|
2
|
+
plugins:
|
|
3
|
+
- '@typescript-eslint'
|
|
4
|
+
- 'check-file'
|
|
5
|
+
root: true
|
|
6
|
+
parserOptions:
|
|
7
|
+
project: true
|
|
8
|
+
rules:
|
|
9
|
+
'@typescript-eslint/no-explicit-any': 'error'
|
|
10
|
+
'@typescript-eslint/no-unsafe-argument': 'error'
|
|
11
|
+
'@typescript-eslint/no-unsafe-assignment': 'error'
|
|
12
|
+
'@typescript-eslint/no-unsafe-call': 'error'
|
|
13
|
+
'@typescript-eslint/no-unsafe-member-access': 'error'
|
|
14
|
+
'@typescript-eslint/no-unsafe-return': 'error'
|
|
15
|
+
|
|
16
|
+
'@typescript-eslint/await-thenable': 'error'
|
|
17
|
+
# Number String Object
|
|
18
|
+
'@typescript-eslint/ban-types': 'error'
|
|
19
|
+
'@typescript-eslint/ban-ts-comments': 'error'
|
|
20
|
+
'@typescript-eslint/no-duplicate-type-constituents': 'error'
|
|
21
|
+
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error'
|
|
22
|
+
# foo?.bar!
|
|
23
|
+
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error'
|
|
24
|
+
'@typescript-eslint/no-unnecessary-condition': 'error'
|
|
25
|
+
'@typescript-eslint/no-unnecessary-type-assertion': 'error'
|
|
26
|
+
'@typescript-eslint/no-unnecessary-type-constraint': 'error'
|
|
27
|
+
|
|
28
|
+
'@typescript-eslint/non-nullable-type-assertion-style': 'error'
|
|
29
|
+
'@typescript-eslint/prefer-as-const': 'error'
|
|
30
|
+
'@typescript-eslint/prefer-destructuring': 'error',
|
|
31
|
+
'@typescript-eslint/prefer-optional-chain': 'error'
|
|
32
|
+
'@typescript-eslint/prefer-reduce-type-parameter': 'error'
|
|
33
|
+
'@typescript-eslint/switch-exhaustiveness-check': 'error'
|
|
34
|
+
'@typescript-eslint/consistent-type-definitions': ['error', 'interface']
|
|
35
|
+
|
|
36
|
+
'check-file/filename-naming-convention': ['error', { '**/*': '[a-z0-9-.]+' }]
|
|
37
|
+
'check-file/folder-naming-convention': ['error', { '**/': '[a-z0-9-]+' }]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
semi: true
|
|
2
|
+
singleQuote: true
|
|
3
|
+
# Change when properties in objects are quoted.
|
|
4
|
+
# If at least one property in an object requires quotes, quote all properties.
|
|
5
|
+
quoteProps: consistent
|
|
6
|
+
tabWidth: 2
|
|
7
|
+
printWidth: 100
|
|
8
|
+
endOfLine: lf
|
|
9
|
+
trailingComma: all
|
|
10
|
+
bracketSpacing: true
|
|
11
|
+
# Include parentheses around a sole arrow function parameter.
|
|
12
|
+
arrowParens: always
|
|
13
|
+
proseWrap: preserve
|
|
14
|
+
jsxSingleQuote: false
|
|
15
|
+
# Put > on the last line instead of at a new line.
|
|
16
|
+
bracketSameLine: false
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"editor.formatOnSave": true,
|
|
3
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
4
|
+
"[prisma]": {
|
|
5
|
+
"editor.defaultFormatter": "Prisma.prisma"
|
|
6
|
+
},
|
|
7
|
+
"editor.tabSize": 2,
|
|
8
|
+
"editor.inlayHints.fontSize": 9,
|
|
9
|
+
"typescript.inlayHints.parameterNames.enabled": "all",
|
|
10
|
+
"typescript.inlayHints.enumMemberValues.enabled": true,
|
|
11
|
+
"typescript.inlayHints.functionLikeReturnTypes.enabled": true,
|
|
12
|
+
"typescript.tsdk": "node_modules/typescript/lib",
|
|
13
|
+
"typescript.preferences.quoteStyle": "single",
|
|
14
|
+
"typescript.suggest.autoImports": true,
|
|
15
|
+
"cSpell.ignoreWords": ["aomex", "mdchain", "openapi", "commitlint"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"license": "UNLICENSED",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node --import tsx/esm --watch src/web.ts",
|
|
8
|
+
"build": "tsc && tsc-alias --resolve-full-paths",
|
|
9
|
+
"prepare": "husky",
|
|
10
|
+
"preinstall": "npx only-allow {{packageManager}}"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
datasource db {
|
|
2
|
+
provider = "mysql"
|
|
3
|
+
url = env("DATABASE_URL")
|
|
4
|
+
relationMode = "prisma"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
generator client {
|
|
8
|
+
provider = "prisma-client-js"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
model User {
|
|
12
|
+
id Int @id @default(autoincrement())
|
|
13
|
+
name String
|
|
14
|
+
age Int
|
|
15
|
+
created_at DateTime @default(now()) @db.DateTime(0)
|
|
16
|
+
updated_at DateTime @default(now()) @updatedAt @db.DateTime(0)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
model Post {
|
|
20
|
+
id Int @id @default(autoincrement())
|
|
21
|
+
user_id Int
|
|
22
|
+
title String
|
|
23
|
+
content String @db.Text()
|
|
24
|
+
created_at DateTime @default(now()) @db.DateTime(0)
|
|
25
|
+
updated_at DateTime @default(now()) @updatedAt @db.DateTime(0)
|
|
26
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Commander } from '@aomex/commander';
|
|
2
|
+
import { commanderChain } from '../middleware/console.chain';
|
|
3
|
+
|
|
4
|
+
export const commander = new Commander({
|
|
5
|
+
mount: commanderChain,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
commander.create('hello', {
|
|
9
|
+
async action(_ctx) {
|
|
10
|
+
console.log('Hello World');
|
|
11
|
+
},
|
|
12
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { mdchain } from '@aomex/core';
|
|
2
|
+
import { openapiGenerator } from './openapi.md';
|
|
3
|
+
import { commanders } from '@aomex/commander';
|
|
4
|
+
|
|
5
|
+
export const appChain = mdchain.console
|
|
6
|
+
.mount(openapiGenerator)
|
|
7
|
+
.mount(commanders('./src/commanders'));
|
|
8
|
+
|
|
9
|
+
export const commanderChain = appChain.mount(null);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { mdchain } from '@aomex/core';
|
|
2
|
+
import { cors } from '@aomex/cors';
|
|
3
|
+
import { compress } from '@aomex/compress';
|
|
4
|
+
import { routers } from '@aomex/router';
|
|
5
|
+
import { httpLogger } from '@aomex/http-logger';
|
|
6
|
+
import { helmet } from '@aomex/helmet';
|
|
7
|
+
import { etag } from '@aomex/etag';
|
|
8
|
+
|
|
9
|
+
export const appChain = mdchain.web
|
|
10
|
+
.mount(cors())
|
|
11
|
+
.mount(compress())
|
|
12
|
+
.mount(httpLogger())
|
|
13
|
+
.mount(etag())
|
|
14
|
+
.mount(helmet())
|
|
15
|
+
.mount(routers('./src/routers'));
|
|
16
|
+
|
|
17
|
+
export const routerChain = appChain;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Router } from '@aomex/router';
|
|
2
|
+
import { routerChain } from '../middleware/web.chain';
|
|
3
|
+
|
|
4
|
+
export const router = new Router({
|
|
5
|
+
mount: routerChain,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
router.get('/', {
|
|
9
|
+
async action(ctx) {
|
|
10
|
+
ctx.send('hello world');
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
router.post('/', {
|
|
15
|
+
async action(ctx) {
|
|
16
|
+
ctx.send(201, { id: 1 });
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { combineServices } from '@aomex/core';
|
|
2
|
+
import { UserService } from './user.service';
|
|
3
|
+
|
|
4
|
+
export const services = combineServices({
|
|
5
|
+
user: UserService,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
declare module '@aomex/core' {
|
|
9
|
+
type T = typeof services;
|
|
10
|
+
export interface CombinedServices extends T {}
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Service } from '@aomex/core';
|
|
2
|
+
import { db } from './db';
|
|
3
|
+
|
|
4
|
+
export class UserService extends Service {
|
|
5
|
+
findAll() {
|
|
6
|
+
return db.user.findAll();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
findById(userId: number) {
|
|
10
|
+
return db.user.findUnique({ where: { id: userId } });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2022",
|
|
4
|
+
"module": "es2022",
|
|
5
|
+
"lib": ["es2022"],
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"moduleResolution": "node",
|
|
11
|
+
"allowUnusedLabels": false,
|
|
12
|
+
"allowUnreachableCode": false,
|
|
13
|
+
"exactOptionalPropertyTypes": false,
|
|
14
|
+
"noFallthroughCasesInSwitch": true,
|
|
15
|
+
"noImplicitOverride": true,
|
|
16
|
+
"noImplicitReturns": true,
|
|
17
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
18
|
+
"noUncheckedIndexedAccess": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"verbatimModuleSyntax": true,
|
|
22
|
+
"allowJs": false,
|
|
23
|
+
"checkJs": false,
|
|
24
|
+
"declaration": false,
|
|
25
|
+
"removeComments": false,
|
|
26
|
+
"rootDir": "./",
|
|
27
|
+
"noEmit": true,
|
|
28
|
+
"importHelpers": false,
|
|
29
|
+
"downlevelIteration": true,
|
|
30
|
+
"noImplicitAny": true,
|
|
31
|
+
"noImplicitThis": true,
|
|
32
|
+
"allowSyntheticDefaultImports": true,
|
|
33
|
+
"resolveJsonModule": true
|
|
34
|
+
}
|
|
35
|
+
}
|