ronantakizawa/codereview-bench huggingface dataset:
Repository: honojs/hono
File: deno_dist/helper/ssg/index.ts (TypeScript)

Code before:
import { Buffer } from "node:buffer";
import * as path from 'node:path'
import { inspectRoutes } from '../../helper/dev/index.ts'
import type { Hono } from '../../hono.ts'
import type { Env, Schema } from '../../types.ts'

export interface FileSystemModule {
  writeFile(path: string, data: string | Buffer): Promise<void>
  mkdir(path: string, options: { recursive: boolean }): Promise<void | string>
}

export interface ToSsgResult {
  success: boolean
  files?: string[]
  error?: Error
}

const generateFilePath = (routePath: string, outDir: string) => {
  const fileName = routePath === '/' ? 'index.html' : routePath + '.html'
  return path.join(outDir, fileName)
}

export const generateHtmlMap = async <
  E extends Env = Env,
  S extends Schema = {},
  BasePath extends string = '/'
>(
  app: Hono<E, S, BasePath>
): Promise<Map<string, string>> => {
  const htmlMap = new Map<string, string>()
  const baseURL = 'http://localhost'

  for (const route of inspectRoutes(app)) {
    if (route.isMiddleware) continue

    const url = new URL(route.path, baseURL).toString()
    const response = await app.fetch(new Request(url))

Review comment (suggestion):
If you made `ToSsg` into `ToSSG`, you might as well make `ToSsgResult` into `ToSSGResult` too. Like `URL` and `URLSearchParams`.

Code after:
import { Buffer } from "node:buffer";
import * as path from 'node:path'
import { inspectRoutes } from '../../helper/dev/index.ts'
import type { Hono } from '../../hono.ts'
import type { Env, Schema } from '../../types.ts'

export interface FileSystemModule {
  writeFile(path: string, data: string | Buffer): Promise<void>
  mkdir(path: string, options: { recursive: boolean }): Promise<void | string>
}

export interface ToSSGResult {
  success: boolean
  files?: string[]
  error?: Error
}

const generateFilePath = (routePath: string, outDir: string) => {
  const fileName = routePath === '/' ? 'index.html' : routePath + '.html'
  return path.join(outDir, fileName)
}

export const generateHtmlMap = async <
  E extends Env = Env,
  S extends Schema = {},
  BasePath extends string = '/'
>(
  app: Hono<E, S, BasePath>
): Promise<Map<string, string>> => {
  const htmlMap = new Map<string, string>()
  const baseURL = 'http://localhost'

  for (const route of inspectRoutes(app)) {
    if (route.isMiddleware) continue

    const url = new URL(route.path, baseURL).toString()
    const response = await app.fetch(new Request(url))
Repository: honojs/hono
File: src/helper/ssg/index.ts (TypeScript)

Code before:

export const saveHtmlToLocal = async (
  htmlMap: Map<string, string>,
  fsModule: FileSystemModule,
  outDir: string
): Promise<string[]> => {
  const files: string[] = []

  for (const [routePath, html] of htmlMap) {
    const filePath = generateFilePath(routePath, outDir)
    const dirPath = path.dirname(filePath)

    await fsModule.mkdir(dirPath, { recursive: true })
    await fsModule.writeFile(filePath, html)
    files.push(filePath)
  }

  return files
}

export interface ToSSGInterface<
  E extends Env = Env,
  S extends Schema = {},
  BasePath extends string = '/'
> {
  (app: Hono<E, S, BasePath>, fsModule: FileSystemModule, options: { dir: string }): Promise<{
    success: boolean
    files?: string[]
    error?: Error
  }>
}


Review comment (suggestion):
Can you write this as? :

```ts
Promise<ToSSGResult>
```

Code after:

export const saveHtmlToLocal = async (
  htmlMap: Map<string, string>,
  fsModule: FileSystemModule,
  outDir: string
): Promise<string[]> => {
  const files: string[] = []

  for (const [routePath, html] of htmlMap) {
    const filePath = generateFilePath(routePath, outDir)
    const dirPath = path.dirname(filePath)

    await fsModule.mkdir(dirPath, { recursive: true })
    await fsModule.writeFile(filePath, html)
    files.push(filePath)
  }

  return files
}

export interface ToSSGInterface<
  E extends Env = Env,
  S extends Schema = {},
  BasePath extends string = '/'
> {
  (
    app: Hono<E, S, BasePath>,
    fsModule: FileSystemModule,
    options?: { dir?: string }
  ): Promise<ToSSGResult>
}

export interface ToSSGAdaptorInterface<
  E extends Env = Env,
  S extends Schema = {},
  BasePath extends string = '/'
> {
  (app: Hono<E, S, BasePath>, options?: { dir?: string }): Promise<ToSSGResult>
}

export const toSSG: ToSSGInterface = async (app, fs, options) => {
  try {
    const outputDir = options?.dir ?? './static'
    const maps = await generateHtmlMap(app)
    const files = await saveHtmlToLocal(maps, fs, outputDir)
    return { success: true, files }
  } catch (error) {
    const errorObj = error instanceof Error ? error : new Error(String(error))
    return { success: false, error: errorObj }
  }
}
Repository: honojs/hono
File: src/adapter/deno/ssg.ts (TypeScript)

Code before:
import { generateHtmlMap, saveHtmlToLocal } from '../../../deno_dist/helper/ssg/index.ts'
import type { FileSystemModule, ToSSGInterface } from '../../../deno_dist/helper/ssg/index.ts'

export const denoFileSystemModule: FileSystemModule = {
  writeFile: async (path, data) => {
    const uint8Data = typeof data === 'string' ? new TextEncoder().encode(data) : data
    await Deno.writeFile(path, uint8Data)
  },
  mkdir: async (path, options) => {
    return Deno.mkdir(path, { recursive: options?.recursive ?? false })
  },
}

export const toSSG: ToSSGInterface = async (
  app,
  denoFileSystemModule,
  options: { dir: string }
) => {
  try {
    const maps = await generateHtmlMap(app)
    const files = await saveHtmlToLocal(maps, denoFileSystemModule, options.dir)

    return { success: true, files }
  } catch (error) {
    const errorObj = error instanceof Error ? error : new Error(String(error))
    return { success: false, error: errorObj }

Review comment (refactor):
These lines should be:

```ts
import { generateHtmlMap, saveHtmlToLocal } from '../../helper/ssg/index'
import type { FileSystemModule, ToSSGInterface } from '../../helper/ssg/index'
```

`denoify` will change the proper paths and add the extensions automatically.

Code after:
import { toSSG as baseToSSG } from '../../helper/ssg/index'
import type { FileSystemModule, ToSSGAdaptorInterface } from '../../helper/ssg/index'

export const denoFileSystemModule: FileSystemModule = {
  writeFile: async (path, data) => {
    const uint8Data = typeof data === 'string' ? new TextEncoder().encode(data) : data
    await Deno.writeFile(path, uint8Data)
  },
  mkdir: async (path, options) => {
    return Deno.mkdir(path, { recursive: options?.recursive ?? false })
  },
}

export const toSSG: ToSSGAdaptorInterface = async (app, options) => {
  return baseToSSG(app, denoFileSystemModule, options)
}
Repository: honojs/hono
File: deno_dist/helper/ssg/index.ts (TypeScript)

Code before:
}

/**
 * @experimental
 * `ToSSGResult` is an experimental feature.
 * The API might be changed.
 */
export interface ToSSGResult {
  success: boolean
  files?: string[]
  error?: Error
}

const generateFilePath = (routePath: string, outDir: string, mimeType: string) => {
  const extension = determineExtension(mimeType)
  const fileName = routePath === '/' ? `index${extension}` : `${routePath}${extension}`
  return joinPaths(outDir, fileName)
}

const parseResponseContent = async (response: Response): Promise<string | ArrayBuffer> => {
  const contentType = response.headers.get('Content-Type')

  try {
    if (contentType?.includes('text')) {
      return await response.text()
    } else if (contentType?.includes('json')) {
      return JSON.stringify(await response.json())
    } else {
      return await response.arrayBuffer()
    }
  } catch (error) {
    throw new Error(
      `Error processing response: ${error instanceof Error ? error.message : 'Unknown error'}`
    )
  }
}

const determineExtension = (mimeType: string): string => {
  switch (mimeType) {
    case 'text/html':
      return '.html'
    case 'text/xml':
    case 'application/xml':
      return '.xml'
    default:
      return '.html'
  }
}

/**
 * @experimental

Review comment (suggestion):
Maybe we can use `response.text()` for json also? I don't think it is necessary to decode JSON and then turn it into a string.

Code after:
  mkdir(path: string, options: { recursive: boolean }): Promise<void | string>
}

/**
 * @experimental
 * `ToSSGResult` is an experimental feature.
 * The API might be changed.
 */
export interface ToSSGResult {
  success: boolean
  files?: string[]
  error?: Error
}

const generateFilePath = (routePath: string, outDir: string, mimeType: string) => {
  const extension = determineExtension(mimeType)
  const fileName = routePath === '/' ? `index${extension}` : `${routePath}${extension}`
  return joinPaths(outDir, fileName)
}

const parseResponseContent = async (response: Response): Promise<string | ArrayBuffer> => {
  const contentType = response.headers.get('Content-Type')

  try {
    if (contentType?.includes('text') || contentType?.includes('json')) {
      return await response.text()
    } else {
      return await response.arrayBuffer()
    }
  } catch (error) {
    throw new Error(
      `Error processing response: ${error instanceof Error ? error.message : 'Unknown error'}`
    )
  }
}

const determineExtension = (mimeType: string): string => {
  switch (mimeType) {
    case 'text/html':
      return '.html'
    case 'text/xml':
    case 'application/xml':
      return '.xml'
    default: {
      const extension = getExtension(mimeType)
      return extension || '.html'
    }
  }
}

/**
Repository: honojs/hono
File: src/helper/accept/accept.test.ts (TypeScript)

Code before:
})

describe('matchAccept', () => {
  test('should return matched support', () => {
    const c = {
      req: {
        header: () => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
      },
    } as any
    const options: MatchAcceptConfig = {
      header: 'Accept',
      supports: ['application/xml', 'text/html'],
      default: 'application/json',
    }
    const result = matchAccept(c, options)
    expect(result).toBe('text/html')
  })

  test('should return default support if no matched support', () => {
    const c = {
      req: {
        header: () => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
      },
    } as any
    const options: MatchAcceptConfig = {
      header: 'Accept',
      supports: ['application/json'],
      default: 'text/html',
    }
    const result = matchAccept(c, options)
    expect(result).toBe('text/html')
  })

  test('should return default support if no accept header', () => {
    const c = {
      req: {
        header: () => undefined,
      },
    } as any
    const options: MatchAcceptConfig = {
      header: 'Accept',
      supports: ['application/json'],
      default: 'text/html',
    }
    const result = matchAccept(c, options)
    expect(result).toBe('text/html')
  })

  test('should return matched support with custom match function', () => {
    const c = {
      req: {

Review comment (suggestion):
Please remove the warning. Maybe you can avoid it with:

```ts
// eslint-disable-next-line @typescript-eslint/no-explicit-any
```

Code after:
})

describe('accepts', () => {
  test('should return matched support', () => {
    const c = {
      req: {
        header: () => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
      },
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } as any
    const options: acceptsConfig = {
      header: 'Accept',
      supports: ['application/xml', 'text/html'],
      default: 'application/json',
    }
    const result = accepts(c, options)
    expect(result).toBe('text/html')
  })

  test('should return default support if no matched support', () => {
    const c = {
      req: {
        header: () => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
      },
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } as any
    const options: acceptsConfig = {
      header: 'Accept',
      supports: ['application/json'],
      default: 'text/html',
    }
    const result = accepts(c, options)
    expect(result).toBe('text/html')
  })

  test('should return default support if no accept header', () => {
    const c = {
      req: {
        header: () => undefined,
      },
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } as any
    const options: acceptsConfig = {
      header: 'Accept',
      supports: ['application/json'],
      default: 'text/html',
    }
    const result = accepts(c, options)
    expect(result).toBe('text/html')
  })
Repository: honojs/hono
File: src/adapter/bun/ssg.ts (TypeScript)

Code before:
// @denoify-ignore
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { toSSG as baseToSSG } from '../../helper/ssg'
import type { FileSystemModule, ToSSGAdaptorInterface } from '../../helper/ssg'

// @ts-ignore
const { write } = Bun

/**
 * @experimental
 * `bunFileSystemModule` is an experimental feature.
 * The API might be changed.
 */
export const bunFileSystemModule: FileSystemModule = {
  writeFile: async (path, data) => {
    await write(path, data)
  },
  mkdir: async () => {},
}

/**
 * @experimental
 * `toBunSSG` is an experimental feature.
 * The API might be changed.
 */
export const toBunSSG: ToSSGAdaptorInterface = async (app, options) => {
  return baseToSSG(app, bunFileSystemModule, options)
}


Review comment (suggestion):
The import is the same as for the Bun.file because it took a long time to break other parts of the Bun type when it was introduced.

Code after:
// @denoify-ignore
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { toSSG as baseToSSG } from '../../helper/ssg'
import type { FileSystemModule, ToSSGAdaptorInterface } from '../../helper/ssg'

// @ts-ignore
const { write } = Bun

/**
 * @experimental
 * `bunFileSystemModule` is an experimental feature.
 * The API might be changed.
 */
export const bunFileSystemModule: FileSystemModule = {
  writeFile: async (path, data) => {
    await write(path, data)
  },
  mkdir: async () => {},
}

/**
 * @experimental
 * `toSSG` is an experimental feature.
 * The API might be changed.
 */
export const toSSG: ToSSGAdaptorInterface = async (app, options) => {
  return baseToSSG(app, bunFileSystemModule, options)
}
Repository: honojs/hono
File: deno_dist/helper/ssg/index.ts (TypeScript)

Code before:
    case 'text/html':
      return '.html'
    case 'text/xml':
    case 'application/xml':
      return '.xml'
    default: {
      const extension = getExtension(mimeType)
      return extension || '.html'
    }
  }
}

interface SSGParam {
  [key: string]: string
}
type SSGParams = SSGParam[]

type AddedSSGDataRequest = Request & {
  ssgParams?: SSGParams
}
/**
 * Define SSG Route
 */
export const ssgParams =
  <E extends Env = Env>(
    params: ((c: Context<E>) => SSGParams | Promise<SSGParams>) | SSGParams
  ): MiddlewareHandler<E> =>
  async (c, next) => {
    ;(c.req.raw as AddedSSGDataRequest).ssgParams = Array.isArray(params) ? params : await params(c)
    await next()
  }

export interface ToSSGOptions {
  dir?: string
}

/**
 * @experimental
 * `fetchRoutesContent` is an experimental feature.
 * The API might be changed.
 */
export const fetchRoutesContent = async <
  E extends Env = Env,
  S extends Schema = {},
  BasePath extends string = '/'
>(
  app: Hono<E, S, BasePath>
): Promise<Map<string, { content: string | ArrayBuffer; mimeType: string }>> => {
  const htmlMap = new Map<string, { content: string | ArrayBuffer; mimeType: string }>()
  const baseURL = 'http://localhost'


Review comment (suggestion):
You can write them here:

```ts
interface SSGParamsMiddleware {
  <E extends Env = Env>(
    generateParams: (c: Context<E>) => SSGParams | Promise<SSGParams>
  ): MiddlewareHandler<E>
}
```

I would suggest separating implementation and interface in this case.

Code after:
    case 'text/html':
      return '.html'
    case 'text/xml':
    case 'application/xml':
      return '.xml'
    default: {
      const extension = getExtension(mimeType)
      return extension || '.html'
    }
  }
}

interface SSGParam {
  [key: string]: string
}
type SSGParams = SSGParam[]

interface SSGParamsMiddleware {
  <E extends Env = Env>(
    generateParams: (c: Context<E>) => SSGParams | Promise<SSGParams>
  ): MiddlewareHandler<E>
  <E extends Env = Env>(params: SSGParams): MiddlewareHandler<E>
}

type AddedSSGDataRequest = Request & {
  ssgParams?: SSGParams
}
/**
 * Define SSG Route
 */
export const ssgParams: SSGParamsMiddleware = (params) => async (c, next) => {
  ;(c.req.raw as AddedSSGDataRequest).ssgParams = Array.isArray(params) ? params : await params(c)
  await next()
}

export interface ToSSGOptions {
  dir?: string
}

/**
 * @experimental
 * `fetchRoutesContent` is an experimental feature.
 * The API might be changed.
 */
export const fetchRoutesContent = async <
  E extends Env = Env,
  S extends Schema = {},
  BasePath extends string = '/'
>(
  app: Hono<E, S, BasePath>
): Promise<Map<string, { content: string | ArrayBuffer; mimeType: string }>> => {
Repository: honojs/hono
File: src/helper/ssg/index.ts (TypeScript)

Code before:
      const extension = getExtension(mimeType)
      return extension || '.html'
    }
  }
}

interface SSGParam {
  [key: string]: string
}
type SSGParams = SSGParam[]

interface SSGParamsMiddleware {
  <E extends Env = Env>(
    generateParams: (c: Context<E>) => SSGParams | Promise<SSGParams>
  ): MiddlewareHandler<E>
}

type AddedSSGDataRequest = Request & {
  ssgParams?: SSGParams
}
/**
 * Define SSG Route
 */
export const ssgParams: SSGParamsMiddleware = (params) => async (c, next) => {
  ;(c.req.raw as AddedSSGDataRequest).ssgParams = Array.isArray(params) ? params : await params(c)
  await next()
}

export interface ToSSGOptions {
  dir?: string
}

/**
 * @experimental
 * `fetchRoutesContent` is an experimental feature.
 * The API might be changed.
 */
export const fetchRoutesContent = async <
  E extends Env = Env,
  S extends Schema = {},
  BasePath extends string = '/'
>(
  app: Hono<E, S, BasePath>
): Promise<Map<string, { content: string | ArrayBuffer; mimeType: string }>> => {
  const htmlMap = new Map<string, { content: string | ArrayBuffer; mimeType: string }>()
  const baseURL = 'http://localhost'

  for (const route of inspectRoutes(app)) {
    if (route.isMiddleware) continue

    // GET Route Info

Review comment (suggestion):
@sor4chi Should you rewrite these lines? I think `generateParams` is always `function`.

Code after:
      const extension = getExtension(mimeType)
      return extension || '.html'
    }
  }
}

interface SSGParam {
  [key: string]: string
}
type SSGParams = SSGParam[]

interface SSGParamsMiddleware {
  <E extends Env = Env>(
    generateParams: (c: Context<E>) => SSGParams | Promise<SSGParams>
  ): MiddlewareHandler<E>
  <E extends Env = Env>(params: SSGParams): MiddlewareHandler<E>
}

type AddedSSGDataRequest = Request & {
  ssgParams?: SSGParams
}
/**
 * Define SSG Route
 */
export const ssgParams: SSGParamsMiddleware = (params) => async (c, next) => {
  ;(c.req.raw as AddedSSGDataRequest).ssgParams = Array.isArray(params) ? params : await params(c)
  await next()
}

export interface ToSSGOptions {
  dir?: string
}

/**
 * @experimental
 * `fetchRoutesContent` is an experimental feature.
 * The API might be changed.
 */
export const fetchRoutesContent = async <
  E extends Env = Env,
  S extends Schema = {},
  BasePath extends string = '/'
>(
  app: Hono<E, S, BasePath>
): Promise<Map<string, { content: string | ArrayBuffer; mimeType: string }>> => {
  const htmlMap = new Map<string, { content: string | ArrayBuffer; mimeType: string }>()
  const baseURL = 'http://localhost'

  for (const route of inspectRoutes(app)) {
    if (route.isMiddleware) continue
Repository: honojs/hono
File: src/helper/ssg/index.ts (TypeScript)

Code before:
    )
  }
}

const determineExtension = (mimeType: string): string => {
  switch (mimeType) {
    case 'text/html':
      return '.html'
    case 'text/xml':
    case 'application/xml':
      return '.xml'
    default: {
      const extension = getExtension(mimeType)
      return extension || '.html'
    }
  }
}

interface SSGParam {
  [key: string]: string
}
type SSGParams = SSGParam[]

interface SSGParamsMiddleware {
  <E extends Env = Env>(
    generateParams: (c: Context<E>) => SSGParams | Promise<SSGParams>
  ): MiddlewareHandler<E>
}

type AddedSSGDataRequest = Request & {
  ssgParams?: SSGParams
}
/**
 * Define SSG Route
 */
export const ssgParams: SSGParamsMiddleware = (params) => async (c, next) => {
  ;(c.req.raw as AddedSSGDataRequest).ssgParams = Array.isArray(params) ? params : await params(c)
  await next()
}

export interface ToSSGOptions {
  dir?: string
}

/**
 * @experimental
 * `fetchRoutesContent` is an experimental feature.
 * The API might be changed.
 */
export const fetchRoutesContent = async <
  E extends Env = Env,

Review comment (suggestion):
You have to add the line for overloading:

```ts
<E extends Env = Env>(params: SSGParams): MiddlewareHandler<E>
```

Code after:
    )
  }
}

const determineExtension = (mimeType: string): string => {
  switch (mimeType) {
    case 'text/html':
      return '.html'
    case 'text/xml':
    case 'application/xml':
      return '.xml'
    default: {
      const extension = getExtension(mimeType)
      return extension || '.html'
    }
  }
}

interface SSGParam {
  [key: string]: string
}
type SSGParams = SSGParam[]

interface SSGParamsMiddleware {
  <E extends Env = Env>(
    generateParams: (c: Context<E>) => SSGParams | Promise<SSGParams>
  ): MiddlewareHandler<E>
  <E extends Env = Env>(params: SSGParams): MiddlewareHandler<E>
}

type AddedSSGDataRequest = Request & {
  ssgParams?: SSGParams
}
/**
 * Define SSG Route
 */
export const ssgParams: SSGParamsMiddleware = (params) => async (c, next) => {
  ;(c.req.raw as AddedSSGDataRequest).ssgParams = Array.isArray(params) ? params : await params(c)
  await next()
}

export interface ToSSGOptions {
  dir?: string
}

/**
 * @experimental
 * `fetchRoutesContent` is an experimental feature.
 * The API might be changed.
 */
export const fetchRoutesContent = async <