jax-hono 1.0.16 → 1.0.17

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.
@@ -91,18 +91,36 @@ function toImportPath(filePath: string) {
91
91
  return path
92
92
  }
93
93
 
94
- function toIdentifier(parts: string[]) {
95
- const value = parts
96
- .join('_')
94
+ function toIdentifier(parts: string[]) {
95
+ const value = parts
96
+ .join('_')
97
97
  .replace(/[^a-zA-Z0-9_$]/g, '_')
98
98
  .replace(/^([^a-zA-Z_$])/, '_$1')
99
-
100
- return value || 'module'
101
- }
102
-
103
- function toCamelCase(value: string) {
104
- return value.replace(/[-_]+([a-zA-Z0-9])/g, (_match, char: string) => char.toUpperCase())
105
- }
99
+
100
+ return value || 'module'
101
+ }
102
+
103
+ function toLowerCamelIdentifier(parts: string[], suffix = '') {
104
+ const words = parts
105
+ .join('/')
106
+ .split(/[^a-zA-Z0-9_$]+/)
107
+ .filter(Boolean)
108
+ const value = words
109
+ .map((word, index) => {
110
+ const normalized = toCamelCase(word)
111
+
112
+ return index === 0
113
+ ? normalized.charAt(0).toLowerCase() + normalized.slice(1)
114
+ : toPascalCase(normalized)
115
+ })
116
+ .join('')
117
+
118
+ return toIdentifier([`${value}${suffix}`])
119
+ }
120
+
121
+ function toCamelCase(value: string) {
122
+ return value.replace(/[-_]+([a-zA-Z0-9])/g, (_match, char: string) => char.toUpperCase())
123
+ }
106
124
 
107
125
  function toPascalCase(value: string) {
108
126
  const camel = toCamelCase(value)
@@ -258,9 +276,10 @@ function buildNestedObject(entries: { path: string[]; value: string }[]): string
258
276
  return lines.join('\n')
259
277
  }
260
278
 
261
- function generateControllersRegistry() {
279
+ function generateControllersRegistry() {
262
280
  const used = new Set<string>()
263
281
  const imports: string[] = []
282
+ const controllerExports: string[] = []
264
283
  const groupLines: string[] = []
265
284
 
266
285
  for (const group of controllerGroups) {
@@ -274,8 +293,9 @@ function generateControllersRegistry() {
274
293
  }) ?? group.dirs[0]
275
294
  const modulePath = toModulePath(baseDir, filePath, group.suffix ? [group.suffix] : [])
276
295
  const importName = toIdentifier([group.name, modulePath, String(index), 'Controller'])
296
+ const exportName = toLowerCamelIdentifier(group.name === 'controller' ? [modulePath] : [group.name, modulePath], 'Controller')
277
297
 
278
- return { modulePath, importName, filePath }
298
+ return { modulePath, importName, exportName, filePath }
279
299
  })
280
300
  const pluginEntries = group.name === 'controller'
281
301
  ? getEnabledPluginFiles('.controller')
@@ -284,8 +304,9 @@ function generateControllersRegistry() {
284
304
  .map(({ name, rootDir, filePath }, index) => {
285
305
  const modulePath = toPluginModulePath(name, rootDir, filePath, ['.controller'])
286
306
  const importName = toIdentifier([group.name, 'plugin', modulePath, String(index), 'Controller'])
307
+ const exportName = toLowerCamelIdentifier([modulePath], 'Controller')
287
308
 
288
- return { modulePath, importName, filePath }
309
+ return { modulePath, importName, exportName, filePath }
289
310
  })
290
311
  : []
291
312
  const entries = [...projectEntries, ...pluginEntries]
@@ -310,15 +331,16 @@ function generateControllersRegistry() {
310
331
  return true
311
332
  })
312
333
 
313
- imports.push(...entries.map((entry) => `import ${entry.importName} from '${toImportPath(entry.filePath)}'`))
314
-
315
- if (entries.length === 0) {
316
- continue
334
+ imports.push(...entries.map((entry) => `import ${entry.importName} from '${toImportPath(entry.filePath)}'`))
335
+ controllerExports.push(...entries.map((entry) => `export const ${entry.exportName} = createController(${entry.importName})`))
336
+
337
+ if (entries.length === 0) {
338
+ continue
317
339
  }
318
340
 
319
341
  const objectBody = buildNestedObject(entries.map((entry) => ({
320
342
  path: entry.modulePath.split('/').map(toCamelCase),
321
- value: `createController(${entry.importName})`,
343
+ value: entry.exportName,
322
344
  })))
323
345
 
324
346
  if (group.name === 'controller') {
@@ -331,57 +353,84 @@ function generateControllersRegistry() {
331
353
  const helperImport = imports.length > 0
332
354
  ? `import { createController } from 'jax-hono/core/controller'\n`
333
355
  : ''
334
- const content = `${generatedHeader}
335
- ${helperImport}${imports.join('\n')}
336
-
337
- export const controllers = {
338
- ${groupLines.join('\n')}
356
+ const content = `${generatedHeader}
357
+ ${helperImport}${imports.join('\n')}
358
+
359
+ ${controllerExports.join('\n')}
360
+
361
+ export const controllers = {
362
+ ${groupLines.join('\n')}
339
363
  }
340
364
  `
341
365
 
342
366
  writeGeneratedFile('controllers.generated.ts', content)
343
367
  }
344
368
 
345
- function toObjectKey(value: string) {
346
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(value) ? value : JSON.stringify(value)
347
- }
348
-
349
- function generateMiddlewaresRegistry() {
350
- const files = getFilesFromDirs(['middlewares', 'middleware', 'modules'])
351
- .filter((filePath) => isModuleFeatureFile(filePath, '.middleware'))
352
- const imports: string[] = []
353
- const entries: string[] = []
354
-
355
- files.forEach((filePath, index) => {
356
- const source = readFileSync(filePath, 'utf8')
357
- const exportNames = [...source.matchAll(/\bexport\s+(?:const|function)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g)]
358
- .map((match) => match[1])
359
- .sort((left, right) => left.localeCompare(right))
360
-
361
- if (exportNames.length === 0) {
362
- return
363
- }
364
-
365
- imports.push(`import { ${exportNames.join(', ')} } from '${toImportPath(filePath)}'`)
366
- entries.push(...exportNames.map((name) => ` ${toMiddlewareKey(name)}: ${name},`))
367
- })
368
-
369
- const content = `${generatedHeader}
370
- ${imports.join('\n')}
371
-
372
- export const middlewares = {
373
- ${entries.join('\n')}
374
- }
375
- `
369
+ function toObjectKey(value: string) {
370
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(value) ? value : JSON.stringify(value)
371
+ }
372
+
373
+ function formatExportBlock(names: string[]) {
374
+ if (names.length === 0) {
375
+ return ''
376
+ }
377
+
378
+ return `export {\n${names.map((name) => ` ${name},`).join('\n')}\n}\n`
379
+ }
380
+
381
+ function createGeneratedContent(sections: string[]) {
382
+ return `${generatedHeader}\n${sections
383
+ .map((section) => section.trimEnd())
384
+ .filter((section) => section.trim())
385
+ .join('\n\n')}\n`
386
+ }
387
+
388
+ function generateMiddlewaresRegistry() {
389
+ const files = getFilesFromDirs(['middlewares', 'middleware', 'modules'])
390
+ .filter((filePath) => isModuleFeatureFile(filePath, '.middleware'))
391
+ const imports: string[] = []
392
+ const entries: string[] = []
393
+ const exportNames = new Set<string>()
376
394
 
377
- writeGeneratedFile('middlewares.generated.ts', content)
378
- }
395
+ files.forEach((filePath) => {
396
+ const source = readFileSync(filePath, 'utf8')
397
+ const middlewareNames = [...source.matchAll(/\bexport\s+(?:const|function)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g)]
398
+ .map((match) => match[1])
399
+ .sort((left, right) => left.localeCompare(right))
400
+
401
+ if (middlewareNames.length === 0) {
402
+ return
403
+ }
404
+
405
+ imports.push(`import { ${middlewareNames.join(', ')} } from '${toImportPath(filePath)}'`)
406
+ middlewareNames.forEach((name) => exportNames.add(name))
407
+ entries.push(...middlewareNames.map((name) => {
408
+ const key = toMiddlewareKey(name)
409
+
410
+ return key === name
411
+ ? ` ${name},`
412
+ : ` ${key}: ${name},`
413
+ }))
414
+ })
415
+
416
+ const exportBlock = formatExportBlock(Array.from(exportNames).sort((left, right) => left.localeCompare(right)))
417
+ const content = createGeneratedContent([
418
+ imports.join('\n'),
419
+ exportBlock,
420
+ `export const middlewares = {
421
+ ${entries.join('\n')}
422
+ }`,
423
+ ])
424
+
425
+ writeGeneratedFile('middlewares.generated.ts', content)
426
+ }
379
427
 
380
428
  function generateModelsRegistry() {
381
- const files = getFilesFromDirs(['models', 'model', 'modules'])
382
- .filter((filePath) => isModuleFeatureFile(filePath, '.model'))
383
- const imports: string[] = []
384
- const entries: string[] = []
429
+ const files = getFilesFromDirs(['models', 'model', 'modules'])
430
+ .filter((filePath) => isModuleFeatureFile(filePath, '.model'))
431
+ const imports: string[] = []
432
+ const entries: string[] = []
433
+ const exportNames = new Set<string>()
385
434
 
386
435
  files.forEach((filePath) => {
387
436
  const source = readFileSync(filePath, 'utf8')
@@ -399,25 +448,31 @@ function generateModelsRegistry() {
399
448
  filePath,
400
449
  ['.model'],
401
450
  ))
402
-
403
- imports.push(`import { ${exportedModels.join(', ')} } from '${toImportPath(filePath)}'`)
404
- entries.push(...exportedModels.map((name) => {
451
+
452
+ imports.push(`import { ${exportedModels.join(', ')} } from '${toImportPath(filePath)}'`)
453
+ exportedModels.forEach((name) => exportNames.add(name))
454
+ entries.push(...exportedModels.map((name) => {
405
455
  const key = exportedModels.length === 1 && modelKey
406
456
  ? modelKey
407
457
  : name === `${fileModelName}Model`
408
458
  ? fileModelName
409
459
  : name
410
460
 
411
- return ` ${key}: ${name},`
412
- }))
413
- })
414
-
415
- const content = `${generatedHeader}
416
- ${imports.join('\n')}
417
-
418
- export const models = {
419
- ${entries.join('\n')}
420
- }
461
+ return key === name
462
+ ? ` ${name},`
463
+ : ` ${key}: ${name},`
464
+ }))
465
+ })
466
+
467
+ const exportBlock = formatExportBlock(Array.from(exportNames).sort((left, right) => left.localeCompare(right)))
468
+
469
+ const content = `${generatedHeader}
470
+ ${imports.join('\n')}
471
+
472
+ ${exportBlock}
473
+ export const models = {
474
+ ${entries.join('\n')}
475
+ }
421
476
 
422
477
  export type Models = typeof models
423
478
  `
@@ -434,6 +489,7 @@ function generateServicesRegistry() {
434
489
  ]
435
490
  const imports: string[] = []
436
491
  const entries: string[] = []
492
+ const exportNames = new Set<string>()
437
493
 
438
494
  files.forEach((item) => {
439
495
  const { filePath } = item
@@ -456,23 +512,27 @@ function generateServicesRegistry() {
456
512
  return
457
513
  }
458
514
 
459
- if (defaultServiceName) {
460
- imports.push(`import ${defaultImportName} from '${toImportPath(filePath)}'`)
461
- entries.push(` ${toServiceKey(defaultServiceName)}: new ${defaultImportName}(deps),`)
462
- }
463
-
464
- if (namedServiceClasses.length > 0) {
465
- imports.push(`import { ${namedServiceClasses.join(', ')} } from '${toImportPath(filePath)}'`)
466
- entries.push(...namedServiceClasses.map((name) => ` ${toServiceKey(name)}: new ${name}(deps),`))
467
- }
468
- })
469
-
470
- const content = `${generatedHeader}
471
- ${imports.join('\n')}
472
-
473
- export function createServices(deps: any) {
474
- return {
475
- ${entries.join('\n')}
515
+ if (defaultServiceName) {
516
+ imports.push(`import ${defaultImportName} from '${toImportPath(filePath)}'`)
517
+ exportNames.add(`${defaultImportName} as ${defaultServiceName}`)
518
+ entries.push(` ${toServiceKey(defaultServiceName)}: new ${defaultImportName}(deps),`)
519
+ }
520
+
521
+ if (namedServiceClasses.length > 0) {
522
+ imports.push(`import { ${namedServiceClasses.join(', ')} } from '${toImportPath(filePath)}'`)
523
+ namedServiceClasses.forEach((name) => exportNames.add(name))
524
+ entries.push(...namedServiceClasses.map((name) => ` ${toServiceKey(name)}: new ${name}(deps),`))
525
+ }
526
+ })
527
+
528
+ const exportBlock = formatExportBlock(Array.from(exportNames).sort((left, right) => left.localeCompare(right)))
529
+ const content = `${generatedHeader}
530
+ ${imports.join('\n')}
531
+
532
+ ${exportBlock}
533
+ export function createServices(deps: any) {
534
+ return {
535
+ ${entries.join('\n')}
476
536
  }
477
537
  }
478
538
 
@@ -508,19 +568,23 @@ function generateCronsRegistry() {
508
568
  })
509
569
  .sort((left, right) => left.modulePath.localeCompare(right.modulePath))
510
570
 
511
- const imports = files.map((item, index) => {
512
- return `import * as ${toIdentifier(['cron', item.modulePath, String(index)])} from '${toImportPath(item.filePath)}'`
571
+ const imports = files.map((item) => {
572
+ return `import * as ${toLowerCamelIdentifier([item.modulePath], 'Cron')} from '${toImportPath(item.filePath)}'`
513
573
  })
514
- const entries = files.map((item, index) => {
515
- const importName = toIdentifier(['cron', item.modulePath, String(index)])
574
+ const exportNames = files.map((item) => toLowerCamelIdentifier([item.modulePath], 'Cron'))
575
+ const entries = files.map((item) => {
576
+ const importName = toLowerCamelIdentifier([item.modulePath], 'Cron')
516
577
 
517
578
  return ` { name: ${JSON.stringify(item.modulePath)}, module: ${importName} },`
518
579
  })
519
- const content = `${generatedHeader}${imports.length > 0 ? `${imports.join('\n')}\n\n` : ''}
520
- export const cronModules = [
580
+ const exportBlock = formatExportBlock(exportNames)
581
+ const content = createGeneratedContent([
582
+ imports.join('\n'),
583
+ exportBlock,
584
+ `export const cronModules = [
521
585
  ${entries.join('\n')}
522
- ] as const
523
- `
586
+ ] as const`,
587
+ ])
524
588
 
525
589
  writeGeneratedFile('crons.generated.ts', content)
526
590
  }
@@ -747,26 +811,30 @@ function serializePluginOptions(options: unknown) {
747
811
 
748
812
  function generatePluginContextRegistry() {
749
813
  const enabledPlugins = getEnabledPluginConfigItems()
750
- const imports = enabledPlugins.map(([name, item]) => {
751
- return `import ${toIdentifier(['plugin', name])} from ${JSON.stringify(item.package)}`
752
- })
753
- const moduleEntries = enabledPlugins.map(
754
- ([name, item]) =>
755
- ` { name: ${JSON.stringify(name)}, module: ${toIdentifier(['plugin', name])}${serializePluginOptions(item.options)} },`,
756
- )
757
-
758
- const content = `${generatedHeader}${imports.length > 0 ? `${imports.join('\n')}\n\n` : ''}
759
- export const plugins = {} as Record<string, unknown>
760
-
761
- export type Plugins = typeof plugins
762
-
763
- export const pluginModules = [
764
- ${moduleEntries.join('\n')}
765
- ] as const
766
- `
767
-
768
- writeGeneratedFile('plugins.generated.ts', content)
769
- }
814
+ const imports = enabledPlugins.map(([name, item]) => {
815
+ return `import ${toLowerCamelIdentifier([name], 'Plugin')} from ${JSON.stringify(item.package)}`
816
+ })
817
+ const exportNames = enabledPlugins.map(([name]) => toLowerCamelIdentifier([name], 'Plugin'))
818
+ const moduleEntries = enabledPlugins.map(
819
+ ([name, item]) =>
820
+ ` { name: ${JSON.stringify(name)}, module: ${toLowerCamelIdentifier([name], 'Plugin')}${serializePluginOptions(item.options)} },`,
821
+ )
822
+ const exportBlock = formatExportBlock(exportNames)
823
+
824
+ const content = createGeneratedContent([
825
+ imports.join('\n'),
826
+ exportBlock,
827
+ `export const plugins = {} as Record<string, unknown>
828
+
829
+ export type Plugins = typeof plugins
830
+
831
+ export const pluginModules = [
832
+ ${moduleEntries.join('\n')}
833
+ ] as const`,
834
+ ])
835
+
836
+ writeGeneratedFile('plugins.generated.ts', content)
837
+ }
770
838
 
771
839
  export function generateRegistry() {
772
840
  generateControllersRegistry()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jax-hono",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "Lightweight framework layer on top of Hono, built for Bun",
5
5
  "type": "module",
6
6
  "main": "./index.ts",