執行環境套件管理器打包器測試執行器程式碼檢查格式化指南參考部落格意見回饋

TOML

通過執行環境 API 和打包器整合,使用 Bun 對 TOML 檔案的內建支援

在 Bun 中,TOML 與 JSON、JSON5 和 YAML 同為一等公民。你可以:

  • 使用 Bun.TOML.parse 解析 TOML 字串
  • 在執行環境將 TOML 檔案作為模組進行 import 和 require(包括熱過載和監視模式支援)
  • 在前端應用中使用 Bun 的打包器 import 和 require TOML 檔案

執行環境 API

Bun.TOML.parse()

將 TOML 字串解析為 JavaScript 物件。

TypeScript
import { TOML } from "bun";
const text = `
name = "my-app"
version = "1.0.0"
debug = true

[database]
host = "localhost"
port = 5432

[features]
tags = ["web", "api"]
`;

const data = TOML.parse(text);
console.log(data);
// {
//   name: "my-app",
//   version: "1.0.0",
//   debug: true,
//   database: { host: "localhost", port: 5432 },
//   features: { tags: ["web", "api"] }
// }

支援的 TOML 特性

Bun 的 TOML 解析器實現了完整的 TOML v1.1.0 規範,並通過了完整的官方 toml-test 一致性測試套件。

  • 字串:基本字串("...")和字面字串('...'),包括多行字串,以及所有轉義序列(\uHHHH、\UHHHHHHHH 和 TOML 1.1 中的 \xHH 與 \e)
  • 整數:十進位制、十六進位制(0x)、八進位制(0o)和二進位制(0b)。超出 ±(2^53 - 1) 的整數會丟擲錯誤,因為 JavaScript 數字無法無損表示它們
  • 浮點數:包括 inf 和 nan
  • 布林值:true 和 false
  • 日期/時間:以 Temporal 物件傳回——帶偏移量的日期時間對應 Temporal.Instant,本地日期時間對應 Temporal.PlainDateTime,本地日期對應 Temporal.PlainDate,本地時間對應 Temporal.PlainTime
  • 陣列:包括混合型別和巢狀陣列
  • 表:標準表([table])和內聯表({ key = "value" }),包括 TOML 1.1 多行內聯表
  • 表陣列:[[array]]
  • 點分鍵:a.b.c = "value"
  • 註釋:使用 #
TypeScript
const data = Bun.TOML.parse(`
# 應用設定
title = "My App"

[owner]
name = "John Doe"

[database]
enabled = true
ports = [8000, 8001, 8002]
connection_max = 5000

[servers.alpha]
ip = "10.0.0.1"
role = "frontend"

[servers.beta]
ip = "10.0.0.2"
role = "backend"
`);

日期/時間

TOML 的四種日期/時間型別分別一一對應一種 Temporal 型別。Temporal 支援納秒精度;按照 TOML 規範的允許範圍,超過九位數的小數秒會被截斷:

TypeScript
const doc = Bun.TOML.parse(`
created = 1979-05-27T00:32:00-07:00  # offset date-time
meeting = 1979-05-27T07:32:00       # local date-time
birthday = 1979-05-27               # local date
opens = 07:32:00                    # local time
`);

doc.created; // Temporal.Instant (an offset date-time specifies an instant;
//              the written offset normalizes away: 1979-05-27T07:32:00Z)
doc.meeting; // Temporal.PlainDateTime
doc.birthday; // Temporal.PlainDate
doc.opens; // Temporal.PlainTime

錯誤處理

如果 TOML 無效,Bun.TOML.parse() 會丟擲 SyntaxError:

TypeScript
try {
  Bun.TOML.parse("invalid = = =");
} catch (error) {
  console.error("Failed to parse TOML:", error.message);
  // 解析 TOML 失敗:TOML 解析錯誤:應為值,但發現了 '='
}

Bun.TOML.stringify()

將 JavaScript 物件序列化為 TOML 文件。標量鍵位於前面,隨後是 [table] 和 [[array-of-tables]] 部分:

TypeScript
Bun.TOML.stringify({
  name: "app",
  server: { host: "localhost", port: 8080 },
  points: [{ x: 1 }, { x: 2 }],
});
// name = "app"
//
// [server]
// host = "localhost"
// port = 8080
//
// [[points]]
// x = 1
//
// [[points]]
// x = 2

頂層值必須是一個物件——TOML 文件是一個表。Temporal.Instant、Temporal.PlainDateTime、Temporal.PlainDate 和 Temporal.PlainTime 值會轉換為對應的 TOML 日期/時間字面量,因此 stringify(parse(doc)) 可以往返保留日期/時間型別。Temporal.ZonedDateTime 會轉換為帶偏移量的日期時間,Date 會轉換為 UTC 時區中的帶偏移量日期時間。TOML 沒有用於時區或日曆註解的語法,因此這些註解會被丟棄(寫入 ISO 欄位);其年份為四位數,因此超出 0000–9999 範圍的日期值和無效的 Date 會丟擲錯誤。由於 TOML 無法表示這些值,null 值、BigInt、迴圈結構、Temporal.PlainYearMonth、Temporal.PlainMonthDay 和 Temporal.Duration 也會丟擲錯誤;undefined、函式和 symbol 屬性會被跳過(在陣列中會丟擲錯誤,因為 TOML 陣列不能有空位),將其中任意一種作為頂層值傳入時會傳回 undefined,與 JSON.stringify 的行為相同。


模組匯入

ES 模組

直接將 TOML 檔案作為 ES 模組匯入。Bun 會解析 TOML,並將其同時作為預設匯出和命名匯出提供:

config.toml
[database]
host = "localhost"
port = 5432
name = "myapp"

[redis]
host = "localhost"
port = 6379

[features]
auth = true
rateLimit = true
analytics = false

預設匯入

app.ts
import config from "./config.toml";

console.log(config.database.host); // "localhost"
console.log(config.redis.port); // 6379

命名匯入

你可以將頂層 TOML 表解構為命名匯入:

app.ts
import { database, redis, features } from "./config.toml";

console.log(database.host); // "localhost"
console.log(redis.port); // 6379
console.log(features.auth); // true

或者兩者結合:

app.ts
import config, { database, features } from "./config.toml";

// 使用完整設定物件
console.log(config);

// 或者使用特定部分
if (features.rateLimit) {
  setupRateLimiting(database);
}

匯入屬性

使用匯入屬性將任意檔案作為 TOML 載入:

app.ts
import myConfig from "./my.config" with { type: "toml" };

CommonJS

你也可以在 CommonJS 中使用 require 匯入 TOML 檔案:

app.ts
const config = require("./config.toml");
console.log(config.database.name); // "myapp"

// 解構同樣可用
const { database, redis } = require("./config.toml");
console.log(database.port); // 5432

TOML 熱過載

當你使用 bun --hot 執行應用程式時,Bun 會檢測 TOML 檔案的更改,並在不重啟的情況下重新載入:

config.toml
[server]
port = 3000
host = "localhost"

[features]
debug = true
verbose = false
server.ts
import { server, features } from "./config.toml";

console.log(`啟動伺服器:${server.host}:${server.port}`);

Bun.serve({
  port: server.port,
  hostname: server.host,
  fetch(req) {
    if (features.verbose) {
      console.log(`${req.method} ${req.url}`);
    }
    return new Response("Hello World");
  },
});

使用熱過載執行:

terminal
bun --hot server.ts

打包器整合

使用 Bun 進行打包時,打包器會在建置時解析匯入的 TOML,並將其作為 JavaScript 模組包含在內:

terminal
bun build app.ts --outdir=dist

這意味著:

  • 生產環境中無需承擔 TOML 執行環境解析開銷
  • 更小的打包體積
  • 對未使用的屬性進行 Tree Shaking(命名匯入)

動態匯入

你也可以動態匯入 TOML 檔案:

TypeScript
const config = await import("./config.toml");