create-aomex 0.0.1 → 0.0.3

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/dist/index.d.ts CHANGED
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ #!/usr/bin/env node
package/dist/index.js CHANGED
@@ -1,64 +1,19 @@
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
- };
1
+ #!/usr/bin/env node
47
2
 
48
3
  // src/index.ts
49
- import path3 from "node:path/posix";
4
+ import path2 from "node:path/posix";
50
5
  import yargsParser from "yargs-parser";
51
- import { existsSync as existsSync2 } from "node:fs";
6
+ import { existsSync } from "node:fs";
52
7
  import { cp, mkdir, rm } from "node:fs/promises";
53
8
  import { Listr } from "listr2";
54
- import { promisify, styleText } from "node:util";
55
- import childProcess from "node:child_process";
9
+ import { styleText } from "node:util";
10
+ import { execSync, spawn } from "node:child_process";
56
11
 
57
12
  // src/replace-variables.ts
58
13
  import { readFile, writeFile } from "node:fs/promises";
59
- import path2 from "node:path";
14
+ import path from "node:path";
60
15
  var replaceVariables = async (filename, variables) => {
61
- const packageJSONFile = path2.resolve(filename);
16
+ const packageJSONFile = path.resolve(filename);
62
17
  let packageContent = await readFile(packageJSONFile, "utf8");
63
18
  Object.entries(variables).forEach(([key, value]) => {
64
19
  packageContent = packageContent.replaceAll(`{{${key}}}`, value);
@@ -67,28 +22,49 @@ var replaceVariables = async (filename, variables) => {
67
22
  };
68
23
 
69
24
  // src/index.ts
25
+ import kebabCase from "lodash.kebabcase";
70
26
  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);
27
+ var templateDir = path2.join(import.meta.dirname, "..", "templates");
28
+ var projectName = kebabCase(argv["project"] || "my-aomex-project");
29
+ var targetDir = path2.resolve(projectName);
30
+ if (existsSync(targetDir)) {
31
+ console.error(styleText("red", `\u76EE\u5F55 "${targetDir}" \u5DF2\u5B58\u5728\uFF01`));
32
+ process.exit(1);
33
+ }
34
+ var packageManager = "npm";
35
+ for (const item of ["pnpm", "npm", "yarn"]) {
36
+ if (argv[item]) {
37
+ packageManager = item;
38
+ break;
39
+ }
40
+ }
41
+ var runShell = async (command) => {
42
+ await new Promise((resolve, reject) => {
43
+ const stream = spawn(command, {
44
+ cwd: process.cwd(),
45
+ env: process.env,
46
+ shell: true
47
+ });
48
+ stream.on("close", resolve);
49
+ stream.on("error", reject);
50
+ });
51
+ };
76
52
  var sleep = () => new Promise((resolve) => setTimeout(resolve, 500));
77
53
  var spinner = new Listr([]);
78
54
  spinner.add({
79
55
  title: "\u521B\u5EFA\u76EE\u5F55",
80
56
  task: async () => {
81
- if (existsSync2(targetDir)) {
57
+ if (existsSync(targetDir)) {
82
58
  await rm(targetDir, { recursive: true, force: true });
83
59
  }
84
60
  await mkdir(targetDir, { recursive: true });
85
- process.chdir(path3.resolve(projectName));
61
+ process.chdir(path2.resolve(projectName));
86
62
  }
87
63
  });
88
64
  spinner.add({
89
65
  title: "git\u521D\u59CB\u5316",
90
66
  task: async () => {
91
- await exec("git init");
67
+ await runShell("git init");
92
68
  await sleep();
93
69
  }
94
70
  });
@@ -104,12 +80,12 @@ spinner.add({
104
80
  spinner.add({
105
81
  title: "\u589E\u52A0volta\u914D\u7F6E",
106
82
  skip: async () => {
107
- return !/\d\.\d/.test((await exec("volta -v")).stdout);
83
+ return !/\d\.\d/.test(execSync("volta -v", { encoding: "utf8" }));
108
84
  },
109
85
  task: async () => {
110
- await exec("volta pin node");
86
+ await runShell("volta pin node");
111
87
  if (packageManager !== "npm") {
112
- await exec(`volta pin ${packageManager}`);
88
+ await runShell(`volta pin ${packageManager}`);
113
89
  }
114
90
  }
115
91
  });
@@ -117,53 +93,70 @@ spinner.add({
117
93
  title: "\u5B89\u88C5\u63D2\u4EF6",
118
94
  task: async (_, task) => {
119
95
  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 }
96
+ {
97
+ label: "dependencies",
98
+ pkgs: [
99
+ "@aomex/core",
100
+ "@aomex/web",
101
+ "@aomex/router",
102
+ "@aomex/cors",
103
+ "@aomex/etag",
104
+ "@aomex/compress",
105
+ "@aomex/http-logger",
106
+ "@aomex/response-time",
107
+ "@aomex/console",
108
+ "@aomex/commander",
109
+ "@aomex/cron",
110
+ "@aomex/helmet",
111
+ "@aomex/openapi",
112
+ "@prisma/client",
113
+ // prisma不会直接导入代码,但是需要在生产环境中生成代码。
114
+ // 导致devDependencies被忽略的场景:
115
+ // 1. pnpm install --production
116
+ // 2. NODE_ENV='production'
117
+ "prisma"
118
+ ]
119
+ },
120
+ {
121
+ label: "dev dependencies",
122
+ pkgs: [
123
+ "typescript",
124
+ "tsx",
125
+ "tsc-alias",
126
+ "@types/node",
127
+ "husky",
128
+ "prettier",
129
+ "@commitlint/cli",
130
+ "@commitlint/config-conventional",
131
+ "eslint",
132
+ "@typescript-eslint/eslint-plugin",
133
+ "@typescript-eslint/parser",
134
+ "eslint-plugin-check-file"
135
+ ],
136
+ dev: true
137
+ }
144
138
  ];
145
139
  const action = packageManager === "npm" ? "install" : "add";
146
140
  const devSuffix = packageManager === "npm" ? "--save-dev" : "-D";
147
141
  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
- });
142
+ const { pkgs, dev, label } = packages[i];
143
+ task.title = "\u5B89\u88C5\u63D2\u4EF6 " + styleText("gray", label);
144
+ await runShell(
145
+ `${packageManager} ${action} ${pkgs.join(" ")} ${dev ? devSuffix : ""}`
146
+ );
154
147
  }
155
148
  task.title = "\u5B89\u88C5\u63D2\u4EF6";
156
149
  }
157
150
  });
158
151
  spinner.add({
159
- title: "\u751F\u6210prisma/client\u6587\u4EF6",
152
+ title: "\u751F\u6210prisma\u5BA2\u6237\u7AEF",
160
153
  task: async () => {
161
- await exec("npx prisma generate");
154
+ await runShell("npx prisma generate");
162
155
  await sleep();
163
156
  }
164
157
  });
165
158
  await spinner.run();
166
159
  console.log(
167
- "\n\u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF1A" + styleText(["blue", "underline"], process.cwd()) + "\n"
160
+ "\n\u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF1A" + styleText(["blue", "underline"], process.cwd()) + "\n\u542F\u52A8\u9879\u76EE\u53EF\u6267\u884C\u5982\u4E0B\u6307\u4EE4\uFF1A\n\n" + styleText("green", `cd ${projectName} && ${packageManager} start`) + "\n"
168
161
  );
169
162
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +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"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/replace-variables.ts"],"sourcesContent":["#!/usr/bin/env node\n\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 { styleText } from 'node:util';\nimport { execSync, spawn } from 'node:child_process';\nimport { replaceVariables } from './replace-variables';\nimport kebabCase from 'lodash.kebabcase';\n\nconst argv = yargsParser(process.argv.slice(2));\nconst templateDir = path.join(import.meta.dirname, '..', 'templates');\n\nconst projectName = kebabCase(argv['project'] || 'my-aomex-project');\nconst targetDir = path.resolve(projectName);\nif (existsSync(targetDir)) {\n console.error(styleText('red', `目录 \"${targetDir}\" 已存在!`));\n process.exit(1);\n}\n\nlet packageManager = 'npm';\nfor (const item of <const>['pnpm', 'npm', 'yarn']) {\n if (argv[item]) {\n packageManager = item;\n break;\n }\n}\n\nconst runShell = async (command: string) => {\n await new Promise((resolve, reject) => {\n const stream = spawn(command, {\n cwd: process.cwd(),\n env: process.env,\n shell: true,\n });\n stream.on('close', resolve);\n stream.on('error', reject);\n });\n};\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 runShell('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(execSync('volta -v', { encoding: 'utf8' }));\n },\n task: async () => {\n await runShell('volta pin node');\n if (packageManager !== 'npm') {\n await runShell(`volta pin ${packageManager}`);\n }\n },\n});\n\nspinner.add({\n title: '安装插件',\n task: async (_, task) => {\n const packages: { label: string; pkgs: string[]; dev?: boolean }[] = [\n {\n label: 'dependencies',\n pkgs: [\n '@aomex/core',\n '@aomex/web',\n '@aomex/router',\n '@aomex/cors',\n '@aomex/etag',\n '@aomex/compress',\n '@aomex/http-logger',\n '@aomex/response-time',\n '@aomex/console',\n '@aomex/commander',\n '@aomex/cron',\n '@aomex/helmet',\n '@aomex/openapi',\n '@prisma/client',\n // prisma不会直接导入代码,但是需要在生产环境中生成代码。\n // 导致devDependencies被忽略的场景:\n // 1. pnpm install --production\n // 2. NODE_ENV='production'\n 'prisma',\n ],\n },\n {\n label: 'dev dependencies',\n pkgs: [\n 'typescript',\n 'tsx',\n 'tsc-alias',\n '@types/node',\n 'husky',\n 'prettier',\n '@commitlint/cli',\n '@commitlint/config-conventional',\n 'eslint',\n '@typescript-eslint/eslint-plugin',\n '@typescript-eslint/parser',\n 'eslint-plugin-check-file',\n ],\n dev: true,\n },\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 { pkgs, dev, label } = packages[i]!;\n task.title = '安装插件 ' + styleText('gray', label);\n await runShell(\n `${packageManager} ${action} ${pkgs.join(' ')} ${dev ? devSuffix : ''}`,\n );\n }\n task.title = '安装插件';\n },\n});\n\nspinner.add({\n title: '生成prisma客户端',\n task: async () => {\n await runShell('npx prisma generate');\n await sleep();\n },\n});\n\nawait spinner.run();\n\nconsole.log(\n '\\n项目创建成功:' +\n styleText(['blue', 'underline'], process.cwd()) +\n '\\n' +\n '启动项目可执行如下指令:' +\n '\\n\\n' +\n styleText('green', `cd ${projectName} && ${packageManager} start`) +\n '\\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":["path","path"]}
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "create-aomex",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "repository": "git@github.com:aomex/create-aomex.git",
5
5
  "author": "geekact <fanwenhua1990@gmail.com>",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
8
  "scripts": {
9
- "cli": "tsx src/index.ts",
9
+ "cli": "tsx src/index.ts --project=abc --pnpm",
10
10
  "release": "release-it --ci",
11
11
  "build": "tsup",
12
- "prepublishOnly": "pnpm build"
12
+ "prepublishOnly": "tsup"
13
13
  },
14
14
  "volta": {
15
15
  "node": "20.15.0",
16
16
  "pnpm": "9.4.0"
17
17
  },
18
18
  "engines": {
19
- "node": ">=20"
19
+ "node": ">=20.13.0"
20
20
  },
21
21
  "publishConfig": {
22
22
  "access": "public"
@@ -37,17 +37,19 @@
37
37
  "yargs-parser": "^21.1.1"
38
38
  },
39
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",
40
+ "@aomex/commander": "^1.0.5",
41
+ "@aomex/compress": "^1.0.5",
42
+ "@aomex/console": "^1.0.5",
43
+ "@aomex/core": "^1.0.5",
44
+ "@aomex/cors": "^1.0.5",
45
+ "@aomex/cron": "^1.3.0",
46
+ "@aomex/etag": "^1.0.5",
47
+ "@aomex/helmet": "^1.0.5",
48
+ "@aomex/http-logger": "^1.0.5",
49
+ "@aomex/openapi": "^1.0.5",
50
+ "@aomex/response-time": "^1.3.0",
51
+ "@aomex/router": "^1.0.5",
52
+ "@aomex/web": "^1.0.5",
51
53
  "@prisma/client": "^5.16.0",
52
54
  "@types/inquirer": "^9.0.7",
53
55
  "@types/lodash.kebabcase": "^4.1.9",
package/templates/.env CHANGED
@@ -1 +1 @@
1
- DATABASE_URL="mysql://USERNAME:PASSWORD@HOST:PORT/DB_NAME"
1
+ DATABASE_URL="mysql://root:123456@localhost:3306/demo_db"
@@ -15,12 +15,3 @@ model User {
15
15
  created_at DateTime @default(now()) @db.DateTime(0)
16
16
  updated_at DateTime @default(now()) @updatedAt @db.DateTime(0)
17
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
- }
@@ -1,10 +1,36 @@
1
1
  import { ConsoleApp } from '@aomex/console';
2
- import { appChain } from './middleware/console.chain';
2
+ import { commanders } from '@aomex/commander';
3
+ import { openapi } from '@aomex/openapi';
4
+ import { cron } from '@aomex/cron';
3
5
 
4
6
  const app = new ConsoleApp({
5
7
  locale: 'zh_CN',
6
- mount: appChain,
8
+ mount: [
9
+ openapi({
10
+ routers: './src/routers',
11
+ docs: {
12
+ servers: [{ url: 'http://localhost:3000', description: 'Local' }],
13
+ },
14
+ }),
15
+ cron({
16
+ path: './src/commanders',
17
+ // store: RedisCache,
18
+ }),
19
+ commanders('./src/commanders'),
20
+ ],
21
+ });
22
+
23
+ app.on('error', (err) => {
24
+ // 上报错误日志
25
+ app.log(err);
7
26
  });
8
27
 
9
28
  await app.run();
10
29
  process.exit(0);
30
+
31
+ declare module '@aomex/console' {
32
+ namespace ConsoleApp {
33
+ type T = ConsoleApp.Infer<typeof app>;
34
+ interface Props extends T {}
35
+ }
36
+ }
@@ -1,12 +1,25 @@
1
1
  import { Commander } from '@aomex/commander';
2
- import { commanderChain } from '../middleware/console.chain';
2
+ import { options } from '@aomex/console';
3
+ import { rule } from '@aomex/core';
3
4
 
4
- export const commander = new Commander({
5
- mount: commanderChain,
6
- });
5
+ export const commander = new Commander();
7
6
 
7
+ // npx aomex hello
8
+ // npx aomex hello --user World
9
+ // npx aomex hello -u aomex.js
8
10
  commander.create('hello', {
9
- async action(_ctx) {
10
- console.log('Hello World');
11
+ mount: [
12
+ options(
13
+ {
14
+ user: rule.string().default('World'),
15
+ },
16
+ {
17
+ user: ['u'],
18
+ },
19
+ ),
20
+ ],
21
+ action: async (ctx) => {
22
+ const { user } = ctx.options;
23
+ console.log(`Hello ${user}`);
11
24
  },
12
25
  });
@@ -0,0 +1,43 @@
1
+ import { Commander } from '@aomex/commander';
2
+ import { options } from '@aomex/console';
3
+ import { rule } from '@aomex/core';
4
+ import { schedule } from '@aomex/cron';
5
+
6
+ export const commander = new Commander();
7
+
8
+ // npx aomex cron:start
9
+ commander.create('schedule', {
10
+ mount: [
11
+ schedule({
12
+ second: '*/5',
13
+ }),
14
+ schedule({
15
+ second: '*/8',
16
+ args: ['--user', 'aomex.js'],
17
+ }),
18
+ options({
19
+ user: rule.string().default('World'),
20
+ }),
21
+ ],
22
+ action: async (ctx) => {
23
+ const { user } = ctx.options;
24
+ console.log(`Hello ${user}`);
25
+ await new Promise((resolve) => {
26
+ setTimeout(resolve, 2_000);
27
+ });
28
+ },
29
+ });
30
+
31
+ commander.create('long:schedule', {
32
+ mount: [
33
+ schedule({
34
+ second: '*/10',
35
+ overlap: true,
36
+ }),
37
+ ],
38
+ action: async () => {
39
+ await new Promise((resolve) => {
40
+ setTimeout(resolve, 15_000);
41
+ });
42
+ },
43
+ });
@@ -0,0 +1,9 @@
1
+ import { Router } from '@aomex/router';
2
+
3
+ export const router = new Router();
4
+
5
+ router.get('/', {
6
+ action: (ctx) => {
7
+ ctx.send('hello world');
8
+ },
9
+ });
@@ -1,18 +1,45 @@
1
1
  import { Router } from '@aomex/router';
2
- import { routerChain } from '../middleware/web.chain';
2
+ import { services } from '../services';
3
+ import { body, params } from '@aomex/web';
4
+ import { rule } from '@aomex/core';
3
5
 
4
6
  export const router = new Router({
5
- mount: routerChain,
7
+ prefix: '/users',
6
8
  });
7
9
 
8
10
  router.get('/', {
9
- async action(ctx) {
10
- ctx.send('hello world');
11
+ action: async (ctx) => {
12
+ const users = await services.user.findAll();
13
+ ctx.send(200, users);
14
+ },
15
+ });
16
+
17
+ router.get('/:id', {
18
+ mount: [
19
+ params({
20
+ id: rule.int().min(1),
21
+ }),
22
+ ],
23
+ action: async (ctx) => {
24
+ const { id } = ctx.params;
25
+ const user = await services.user.findById(id);
26
+ if (!user) {
27
+ ctx.throw(404, 'user not found');
28
+ }
29
+ ctx.send(user);
11
30
  },
12
31
  });
13
32
 
14
33
  router.post('/', {
15
- async action(ctx) {
16
- ctx.send(201, { id: 1 });
34
+ mount: [
35
+ body({
36
+ name: rule.string(),
37
+ age: rule.number(),
38
+ }),
39
+ ],
40
+ action: async (ctx) => {
41
+ const { name, age } = ctx.body;
42
+ await services.user.createUser(name, age);
43
+ ctx.send(201);
17
44
  },
18
45
  });
@@ -1,7 +1,7 @@
1
1
  import { combineServices } from '@aomex/core';
2
2
  import { UserService } from './user.service';
3
3
 
4
- export const services = combineServices({
4
+ export const services = await combineServices({
5
5
  user: UserService,
6
6
  });
7
7
 
@@ -1,12 +1,28 @@
1
1
  import { Service } from '@aomex/core';
2
2
  import { db } from './db';
3
+ import { Prisma } from '@prisma/client';
3
4
 
4
5
  export class UserService extends Service {
5
6
  findAll() {
6
- return db.user.findAll();
7
+ return db.user.findMany({
8
+ orderBy: [
9
+ {
10
+ id: Prisma.SortOrder.desc,
11
+ },
12
+ ],
13
+ });
7
14
  }
8
15
 
9
16
  findById(userId: number) {
10
17
  return db.user.findUnique({ where: { id: userId } });
11
18
  }
19
+
20
+ async createUser(name: string, age: number) {
21
+ await db.user.create({
22
+ data: {
23
+ name,
24
+ age,
25
+ },
26
+ });
27
+ }
12
28
  }
@@ -1,11 +1,42 @@
1
1
  import { WebApp } from '@aomex/web';
2
- import { appChain } from './middleware/web.chain';
2
+ import { cors } from '@aomex/cors';
3
+ import { compress } from '@aomex/compress';
4
+ import { httpLogger } from '@aomex/http-logger';
5
+ import { etag } from '@aomex/etag';
6
+ import { routers } from '@aomex/router';
7
+ import { helmet } from '@aomex/helmet';
8
+ import { responseTime } from '@aomex/response-time';
3
9
 
4
10
  export const app = new WebApp({
5
11
  locale: 'zh_CN',
6
- mount: appChain,
12
+ mount: [
13
+ responseTime,
14
+ cors(),
15
+ compress(),
16
+ httpLogger(),
17
+ etag(),
18
+ helmet(),
19
+ routers('./src/routers'),
20
+ ],
7
21
  });
8
22
 
9
- app.listen(process.env['PORT'] || 3000, () => {
10
- console.log('服务已启动');
23
+ app.on('error', (err, ctx) => {
24
+ // 上报错误日志
25
+ app.log(err, ctx);
26
+ ctx.response.body = {
27
+ status: ctx.response.statusCode,
28
+ message: ctx.response.body,
29
+ };
11
30
  });
31
+
32
+ const port = process.env['PORT'] || 3000;
33
+ app.listen(port, () => {
34
+ console.log(`服务已启动,点击 http://localhost:${port} 访问`);
35
+ });
36
+
37
+ declare module '@aomex/web' {
38
+ namespace WebApp {
39
+ type T = WebApp.Infer<typeof app>;
40
+ interface Props extends T {}
41
+ }
42
+ }
@@ -22,9 +22,10 @@
22
22
  "allowJs": false,
23
23
  "checkJs": false,
24
24
  "declaration": false,
25
- "removeComments": false,
25
+ "removeComments": true,
26
26
  "rootDir": "./",
27
- "noEmit": true,
27
+ "outDir": "build",
28
+ "noEmit": false,
28
29
  "importHelpers": false,
29
30
  "downlevelIteration": true,
30
31
  "noImplicitAny": true,
@@ -1,9 +0,0 @@
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);
@@ -1,13 +0,0 @@
1
- import { openapi } from '@aomex/openapi';
2
-
3
- export const openapiGenerator = openapi({
4
- routers: ['./src/routers'],
5
- docs: {
6
- servers: [
7
- {
8
- url: 'http://localhost:3000',
9
- description: 'Local',
10
- },
11
- ],
12
- },
13
- });
@@ -1,17 +0,0 @@
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;