jax-hono 1.0.0 → 1.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/bin/jax.ts CHANGED
@@ -3,17 +3,31 @@
3
3
  import { cac } from "cac";
4
4
  import { $ } from "bun";
5
5
  import path from "node:path";
6
+ import { existsSync } from "node:fs";
7
+ import { mkdir } from "node:fs/promises";
6
8
 
7
9
  const cli = cac("jax");
8
10
 
9
11
  cli
10
12
  .command(
11
13
  "link",
12
- "Create a symlink (./jax -> jax-hono installation directory)",
14
+ "Create a symlink to the jax-hono installation directory",
13
15
  )
14
16
  .action(async () => {
17
+ const cwd = process.cwd();
15
18
  const sourceDir = path.resolve(import.meta.dir, "..");
16
- const targetDir = path.resolve(process.cwd(), "jax");
19
+ const shouldUseNodeModules =
20
+ existsSync(path.join(cwd, "package.json")) ||
21
+ existsSync(path.join(cwd, "node_modules"));
22
+ const targetRoot = shouldUseNodeModules
23
+ ? path.join(cwd, "node_modules")
24
+ : cwd;
25
+ const targetName = shouldUseNodeModules ? "jax-hono" : "jax";
26
+ const targetDir = path.resolve(targetRoot, targetName);
27
+
28
+ if (shouldUseNodeModules) {
29
+ await mkdir(targetRoot, { recursive: true });
30
+ }
17
31
 
18
32
  if (process.platform === "win32") {
19
33
  const result =
@@ -1,10 +1,12 @@
1
1
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
2
+ import { cwd } from 'node:process'
2
3
  import { join, parse, relative } from 'node:path'
3
4
 
4
- const srcDir = join(import.meta.dir, '../..')
5
+ const packageDir = join(import.meta.dir, '..')
6
+ const srcDir = join(cwd(), 'src')
5
7
  const configDir = join(srcDir, 'config')
6
8
  const typesFile = join(srcDir, 'types/index.ts')
7
- const generatedDir = join(srcDir, 'jax/generated')
9
+ const generatedDir = join(packageDir, 'generated')
8
10
  const outputFile = join(generatedDir, 'config.ts')
9
11
  const envStages = new Set([
10
12
  'default',
@@ -35,9 +37,9 @@ function getStage(fileName: string) {
35
37
 
36
38
  function getImportPath(fileName: string) {
37
39
  const { dir, name } = parse(fileName)
38
- const path = join('../../config', dir, name).replaceAll('\\', '/')
40
+ const path = join(configDir, dir, name).replaceAll('\\', '/')
39
41
 
40
- return path.startsWith('.') ? path : `./${path}`
42
+ return path
41
43
  }
42
44
 
43
45
  function getConfigFiles() {
@@ -83,7 +85,7 @@ export function generateConfig() {
83
85
  return ` { name: '${fileName}', stage: '${getStage(fileName)}', config: ${toImportName(fileName, index)} },`
84
86
  })
85
87
  const hasProjectTypes = hasProjectConfigType()
86
- const typeImports = hasProjectTypes ? [`import type { ProjectConfig } from '../../types'`] : []
88
+ const typeImports = hasProjectTypes ? [`import type { ProjectConfig } from '${join(srcDir, 'types').replaceAll('\\', '/')}'`] : []
87
89
  const projectConfigType = hasProjectTypes
88
90
  ? 'export type { ProjectConfig }'
89
91
  : defaultConfigIndex === -1
@@ -1,10 +1,12 @@
1
1
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
2
+ import { cwd } from 'node:process'
2
3
  import { basename, join, parse, relative } from 'node:path'
3
4
 
4
- const srcDir = join(import.meta.dir, '../..')
5
- const generatedDir = join(srcDir, 'jax/generated')
5
+ const packageDir = join(import.meta.dir, '..')
6
+ const srcDir = join(cwd(), 'src')
7
+ const generatedDir = join(packageDir, 'generated')
6
8
  const moduleExtensions = new Set(['.ts', '.js', '.mjs', '.cjs'])
7
- const generatedHeader = `// This file is generated by src/jax/build/generate-registry.ts.
9
+ const generatedHeader = `// This file is generated by jax-hono/build/generate-registry.ts.
8
10
  // Do not edit it directly.
9
11
  `
10
12
 
@@ -75,11 +77,11 @@ function writeGeneratedFile(fileName: string, content: string) {
75
77
  }
76
78
 
77
79
  function toImportPath(filePath: string) {
78
- const path = relative(srcDir, filePath)
80
+ const path = filePath
79
81
  .replace(parse(filePath).ext, '')
80
82
  .replaceAll('\\', '/')
81
83
 
82
- return `@/${path}`
84
+ return path
83
85
  }
84
86
 
85
87
  function toIdentifier(parts: string[]) {
@@ -277,7 +279,7 @@ function generateControllersRegistry() {
277
279
  }
278
280
 
279
281
  const helperImport = imports.length > 0
280
- ? `import { createController } from '@/jax/core/controller'\n`
282
+ ? `import { createController } from 'jax-hono/core/controller'\n`
281
283
  : ''
282
284
  const content = `${generatedHeader}
283
285
  ${helperImport}${imports.join('\n')}
@@ -531,15 +533,11 @@ function normalizePluginPackage(packageName: string, configFile: string) {
531
533
  return packageName
532
534
  }
533
535
 
534
- const normalized = relative(srcDir, join(configFile, '..', packageName))
536
+ const normalized = join(configFile, '..', packageName)
535
537
  .replaceAll('\\', '/')
536
538
  .replace(/\/index$/, '')
537
539
 
538
- if (normalized.startsWith('jax/')) {
539
- return normalized
540
- }
541
-
542
- return `@/${normalized}`
540
+ return normalized
543
541
  }
544
542
 
545
543
  function mergePluginConfig(configs: { filePath: string; config: PluginConfig }[]) {
@@ -578,7 +576,6 @@ function serializePluginOptions(options: unknown) {
578
576
 
579
577
  function generatePluginContextRegistry() {
580
578
  const enabledPlugins = mergePluginConfig([
581
- { filePath: join(srcDir, 'jax/plugins/config.ts'), config: readPluginConfig(join(srcDir, 'jax/plugins/config.ts')) },
582
579
  { filePath: join(srcDir, 'config/plugin.ts'), config: readPluginConfig(join(srcDir, 'config/plugin.ts')) },
583
580
  ])
584
581
  const imports = enabledPlugins.map(([name, item]) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jax-hono",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Lightweight framework layer on top of Hono, built for Bun",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -10,7 +10,54 @@
10
10
  "import": "./index.ts",
11
11
  "types": "./index.ts"
12
12
  },
13
- "./*": "./*"
13
+ "./setup": {
14
+ "import": "./setup.ts",
15
+ "types": "./setup.ts"
16
+ },
17
+ "./config": {
18
+ "import": "./config.ts",
19
+ "types": "./config.ts"
20
+ },
21
+ "./core/*": {
22
+ "import": "./core/*.ts",
23
+ "types": "./core/*.ts"
24
+ },
25
+ "./helpers": {
26
+ "import": "./helpers/index.ts",
27
+ "types": "./helpers/index.ts"
28
+ },
29
+ "./helpers/*": {
30
+ "import": "./helpers/*.ts",
31
+ "types": "./helpers/*.ts"
32
+ },
33
+ "./middleware/*": {
34
+ "import": "./middleware/*.ts",
35
+ "types": "./middleware/*.ts"
36
+ },
37
+ "./plugins/*": {
38
+ "import": "./plugins/*/index.ts",
39
+ "types": "./plugins/*/index.ts"
40
+ },
41
+ "./plugins/*/*": {
42
+ "import": "./plugins/*/*.ts",
43
+ "types": "./plugins/*/*.ts"
44
+ },
45
+ "./utils": {
46
+ "import": "./utils/index.ts",
47
+ "types": "./utils/index.ts"
48
+ },
49
+ "./utils/*": {
50
+ "import": "./utils/*.ts",
51
+ "types": "./utils/*.ts"
52
+ },
53
+ "./types": {
54
+ "import": "./types/index.ts",
55
+ "types": "./types/index.ts"
56
+ },
57
+ "./types/*": {
58
+ "import": "./types/*.ts",
59
+ "types": "./types/*.ts"
60
+ }
14
61
  },
15
62
  "bin": {
16
63
  "jax": "./bin/jax.ts"
@@ -40,12 +87,20 @@
40
87
  },
41
88
  "peerDependencies": {
42
89
  "dayjs": "*",
43
- "deepmerge": "*",
44
- "dotenv": "*",
90
+ "deepmerge": "^4.3.1",
91
+ "dotenv": "^17.4.2",
45
92
  "jsonwebtoken": "*",
46
- "minimist": "*",
93
+ "minimist": "^1.2.8",
47
94
  "mongoose": "*"
48
95
  },
96
+ "devDependencies": {
97
+ "dayjs": "^1.11.21",
98
+ "deepmerge": "^4.3.1",
99
+ "dotenv": "^17.4.2",
100
+ "jsonwebtoken": "^9.0.3",
101
+ "minimist": "^1.2.8",
102
+ "mongoose": "^8.24.1"
103
+ },
49
104
  "peerDependenciesMeta": {
50
105
  "dayjs": {
51
106
  "optional": true
@@ -61,4 +116,4 @@
61
116
  "bun": ">=1.0.0"
62
117
  },
63
118
  "license": "MIT"
64
- }
119
+ }
@@ -1,14 +1,14 @@
1
- import { basename, parse } from 'node:path';
1
+ import { basename, parse } from "node:path";
2
2
  import mongoose, {
3
3
  Schema,
4
4
  model as mongooseModel,
5
5
  type InferSchemaType,
6
6
  type Model,
7
- type SchemaOptions
8
- } from 'mongoose';
9
- import config from '@/jax/config';
10
- import { rankSetter } from './schema';
11
- import dayjs from 'dayjs';
7
+ type SchemaOptions,
8
+ } from "mongoose";
9
+ import config from "@/config";
10
+ import { rankSetter } from "./schema";
11
+ import dayjs from "dayjs";
12
12
 
13
13
  export { rankSetter };
14
14
 
@@ -21,7 +21,7 @@ type PageOptions = {
21
21
  export type ModelStatics = {
22
22
  findPage(
23
23
  filter?: Record<string, unknown>,
24
- options?: PageOptions
24
+ options?: PageOptions,
25
25
  ): Promise<{
26
26
  total: number;
27
27
  list: unknown[];
@@ -48,14 +48,15 @@ export function createLooseModel(filePathOrName: string, collection?: string) {
48
48
  installModelStatics(schema);
49
49
 
50
50
  return (
51
- mongoose.models[name] ?? mongooseModel(name, schema, collection ?? getCollectionName(name))
51
+ mongoose.models[name] ??
52
+ mongooseModel(name, schema, collection ?? getCollectionName(name))
52
53
  );
53
54
  }
54
55
 
55
56
  export function createSchemaModel<TSchema extends Schema>(
56
57
  filePathOrName: string,
57
58
  schema: TSchema,
58
- collection?: string
59
+ collection?: string,
59
60
  ): Model<InferSchemaType<TSchema>> & ModelStatics {
60
61
  const name = getModelName(filePathOrName);
61
62
 
@@ -67,7 +68,7 @@ export function createSchemaModel<TSchema extends Schema>(
67
68
  mongooseModel<InferSchemaType<TSchema>>(
68
69
  name,
69
70
  schema as any,
70
- collection ?? getCollectionName(name)
71
+ collection ?? getCollectionName(name),
71
72
  )) as Model<InferSchemaType<TSchema>> & ModelStatics;
72
73
  }
73
74
 
@@ -75,15 +76,16 @@ export const createModel = createSchemaModel;
75
76
 
76
77
  export function getModelName(filePathOrName: string) {
77
78
  const baseName =
78
- filePathOrName.includes('/') || filePathOrName.includes('\\')
79
- ? parse(basename(filePathOrName)).name.replace(/\.model$/, '')
79
+ filePathOrName.includes("/") || filePathOrName.includes("\\")
80
+ ? parse(basename(filePathOrName)).name.replace(/\.model$/, "")
80
81
  : filePathOrName;
81
82
 
82
83
  return toPascalCase(baseName);
83
84
  }
84
85
 
85
86
  export function getCollectionName(modelName: string) {
86
- const prefix = (config as any).mongoose?.prefix ?? (config as any).mongo?.prefix ?? '';
87
+ const prefix =
88
+ (config as any).mongoose?.prefix ?? (config as any).mongo?.prefix ?? "";
87
89
  const name = toSnakeCase(modelName);
88
90
 
89
91
  return prefix ? `${prefix}_${name}` : name;
@@ -102,23 +104,23 @@ export function schemaOptions(): SchemaOptions {
102
104
  // }
103
105
 
104
106
  if (ret.createdAt) {
105
- ret.createdAt = dayjs(ret.createdAt).format('YYYY-MM-DD HH:mm:ss');
107
+ ret.createdAt = dayjs(ret.createdAt).format("YYYY-MM-DD HH:mm:ss");
106
108
  }
107
109
 
108
110
  if (ret.updatedAt) {
109
- ret.updatedAt = dayjs(ret.updatedAt).format('YYYY-MM-DD HH:mm:ss');
111
+ ret.updatedAt = dayjs(ret.updatedAt).format("YYYY-MM-DD HH:mm:ss");
110
112
  }
111
113
 
112
114
  delete ret.__v;
113
115
  delete ret._id;
114
116
 
115
117
  return ret;
116
- }
118
+ },
117
119
  },
118
120
  toObject: {
119
121
  virtuals: true,
120
- getters: true
121
- }
122
+ getters: true,
123
+ },
122
124
  };
123
125
  }
124
126
 
@@ -126,37 +128,40 @@ export function applyDefaultSchemaOptions(schema: Schema) {
126
128
  const defaults = schemaOptions();
127
129
 
128
130
  if (schema.options.timestamps === undefined) {
129
- schema.set('timestamps', defaults.timestamps);
131
+ schema.set("timestamps", defaults.timestamps);
130
132
  }
131
133
 
132
- if (schema.options.versionKey === undefined || schema.options.versionKey === '__v') {
133
- schema.set('versionKey', defaults.versionKey);
134
+ if (
135
+ schema.options.versionKey === undefined ||
136
+ schema.options.versionKey === "__v"
137
+ ) {
138
+ schema.set("versionKey", defaults.versionKey);
134
139
  }
135
140
 
136
141
  const toJSON = {
137
142
  ...defaults.toJSON,
138
- ...(schema.options.toJSON ?? {})
143
+ ...(schema.options.toJSON ?? {}),
139
144
  } as any;
140
145
 
141
- schema.set('toJSON', toJSON);
142
- schema.set('toObject', {
146
+ schema.set("toJSON", toJSON);
147
+ schema.set("toObject", {
143
148
  ...defaults.toObject,
144
- ...(schema.options.toObject ?? {})
149
+ ...(schema.options.toObject ?? {}),
145
150
  } as any);
146
151
  }
147
152
 
148
153
  export function installRankHooks(schema: Schema) {
149
- schema.pre(['updateOne', 'findOneAndUpdate', 'updateMany'], function () {
154
+ schema.pre(["updateOne", "findOneAndUpdate", "updateMany"], function () {
150
155
  normalizeRank(this.getUpdate());
151
156
  });
152
157
 
153
- schema.pre('save', function () {
158
+ schema.pre("save", function () {
154
159
  normalizeRank(this);
155
160
  });
156
161
  }
157
162
 
158
163
  export function installAutoNo(schema: Schema, field: string, start = 0) {
159
- schema.pre('save', async function () {
164
+ schema.pre("save", async function () {
160
165
  if (!this.isNew || this.get(field)) {
161
166
  return;
162
167
  }
@@ -169,29 +174,32 @@ export function installAutoNo(schema: Schema, field: string, start = 0) {
169
174
  }
170
175
 
171
176
  export function installModelStatics(schema: Schema) {
172
- schema.static('findPage', async function findPage(filter = {}, options: PageOptions = {}) {
173
- const page = Number(options.page || 1);
174
- const pageSize = Number(options.pageSize || 20);
175
- const sort = (options.sort ?? { _id: -1 }) as any;
176
- const total = await this.countDocuments(filter);
177
- let query = this.find(filter).sort(sort);
178
-
179
- if (pageSize !== -1) {
180
- query = query.skip((page - 1) * pageSize).limit(pageSize);
181
- }
177
+ schema.static(
178
+ "findPage",
179
+ async function findPage(filter = {}, options: PageOptions = {}) {
180
+ const page = Number(options.page || 1);
181
+ const pageSize = Number(options.pageSize || 20);
182
+ const sort = (options.sort ?? { _id: -1 }) as any;
183
+ const total = await this.countDocuments(filter);
184
+ let query = this.find(filter).sort(sort);
185
+
186
+ if (pageSize !== -1) {
187
+ query = query.skip((page - 1) * pageSize).limit(pageSize);
188
+ }
182
189
 
183
- const list = await query;
190
+ const list = await query;
184
191
 
185
- return {
186
- total,
187
- list,
188
- maxPage: pageSize === -1 ? 1 : Math.ceil(total / pageSize),
189
- page,
190
- pageSize
191
- };
192
- });
192
+ return {
193
+ total,
194
+ list,
195
+ maxPage: pageSize === -1 ? 1 : Math.ceil(total / pageSize),
196
+ page,
197
+ pageSize,
198
+ };
199
+ },
200
+ );
193
201
 
194
- schema.static('tree', async function tree(options: any = {}) {
202
+ schema.static("tree", async function tree(options: any = {}) {
195
203
  const docs = await this.find(options.filter ?? {})
196
204
  .sort(options.sort ?? {})
197
205
  .lean({ virtuals: true });
@@ -204,7 +212,7 @@ export function installModelStatics(schema: Schema) {
204
212
  }
205
213
 
206
214
  for (const item of byId.values()) {
207
- const parentId = item.parentId ? String(item.parentId) : '';
215
+ const parentId = item.parentId ? String(item.parentId) : "";
208
216
  const parent = parentId ? byId.get(parentId) : undefined;
209
217
 
210
218
  if (parent) {
@@ -217,24 +225,27 @@ export function installModelStatics(schema: Schema) {
217
225
  return tree;
218
226
  });
219
227
 
220
- schema.static('flatTree', async function flatTree(this: any, options: any = {}) {
221
- const tree = await this.tree(options);
222
- const list: any[] = [];
228
+ schema.static(
229
+ "flatTree",
230
+ async function flatTree(this: any, options: any = {}) {
231
+ const tree = await this.tree(options);
232
+ const list: any[] = [];
223
233
 
224
- walkTree(tree, 1, list);
234
+ walkTree(tree, 1, list);
225
235
 
226
- return list;
227
- });
236
+ return list;
237
+ },
238
+ );
228
239
  }
229
240
 
230
241
  export function installCommonFields(schema: Schema) {
231
242
  const fields: Record<string, unknown> = {};
232
243
 
233
- if (!schema.path('isDelete')) {
244
+ if (!schema.path("isDelete")) {
234
245
  fields.isDelete = { type: Boolean, default: false };
235
246
  }
236
247
 
237
- if (!schema.path('isOpen')) {
248
+ if (!schema.path("isOpen")) {
238
249
  fields.isOpen = { type: Boolean, default: false };
239
250
  }
240
251
 
@@ -245,14 +256,14 @@ export function installCommonFields(schema: Schema) {
245
256
 
246
257
  export function toSnakeCase(value: string) {
247
258
  return value
248
- .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
249
- .replace(/[-\s]+/g, '_')
259
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
260
+ .replace(/[-\s]+/g, "_")
250
261
  .toLowerCase();
251
262
  }
252
263
 
253
264
  function toPascalCase(value: string) {
254
265
  const camel = value.replace(/[-_\s]+([a-zA-Z0-9])/g, (_match, char: string) =>
255
- char.toUpperCase()
266
+ char.toUpperCase(),
256
267
  );
257
268
 
258
269
  return camel.charAt(0).toUpperCase() + camel.slice(1);