Repository: honojs/hono
File: src/helper/ssg/index.ts (TypeScript)

Code before:

    htmlMap.set(route.path, html)
  }

  return htmlMap
}

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 (refactor):
I think `helper/ssg` should implement `toSSG` not only exporting `ToSSGInterface`.

```ts
export const toSSG: ToSSGInterface = async (app, fs, options) => {
  try {
    const maps = await generateHtmlMap(app)
    const files = await saveHtmlToLocal(maps, fs, options.dir)
    return { success: true, files }
  } catch (error) {
    const errorObj = error instanceof Error ? error : new Error(String(error))
    return { success: false, error: errorObj }
  }
}
```

Then, for Node.js, you can do the following without an adapter. Also, for platforms other than Node.js, Bun, and Deno, a user can just import `toSSG()` from `hono/ssg`.

```ts
import { toSSG } from 'hono/ssg'
import fs from 'node:fs/promises'

toSSG(app, fs, { dir: './static '})
```

Also, for example, Bun's adapter can be written as follows:

```ts
import { toSSG as baseToSSG } from '../../helper/ssg'

// ...

export const toSSG: ToSSGInterface = async (app, bunFileSystemModule, options: { dir: string }) => {
  return baseToSSG(app, bunFileSystemModule, options)
}
```

Code after:

    htmlMap.set(route.path, html)
  }

  return htmlMap
}

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)