Skip to main content
On this page

@std/ini

Unstable

This @std package is experimental and its API may change without a major version bump.

Overview Jump to heading

parse and stringify for handling INI encoded data, such as the Desktop Entry specification. Values are parsed as strings by default to preserve data parity from the original. Customization is possible in the form of reviver/replacer functions like those in JSON.parse and JSON.stringify. Nested sections, repeated key names within a section, and key/value arrays are not supported, but will be preserved when using IniMap. Multi-line values are not supported and will throw a syntax error. White space padding and lines starting with '#', ';', or '//' will be treated as comments.

import * as ini from "@std/ini";
import { assertEquals } from "@std/assert";

const iniFile = `# Example configuration file
Global Key=Some data here

[Section #1]
Section Value=42
Section Date=1977-05-25`;

const parsed = ini.parse(iniFile, {
  reviver(key, value, section) {
    if (section === "Section #1") {
      if (key === "Section Value") return Number(value);
      if (key === "Section Date") return new Date(value);
    }
    return value;
  },
});

assertEquals(parsed, {
  "Global Key": "Some data here",
  "Section #1": {
    "Section Value": 42,
    "Section Date": new Date("1977-05-25T00:00:00.000Z"),
  },
});

const text = ini.stringify(parsed, {
  replacer(key, value, section) {
    if (section === "Section #1" && key === "Section Date") {
      return (value as Date).toISOString().split("T")[0];
    }
    return value;
  },
});

assertEquals(text, `Global Key=Some data here
[Section #1]
Section Value=42
Section Date=1977-05-25`);

Optionally, IniMap may be used for finer INI handling. Using this class will permit preserving comments, accessing values like a map, iterating over key/value/section entries, and more.

import { IniMap } from "@std/ini/ini-map";
import { assertEquals } from "@std/assert";

const ini = new IniMap();
ini.set("section1", "keyA", 100);
assertEquals(ini.toString(), `[section1]
keyA=100`);

ini.set('keyA', 25)
assertEquals(ini.toObject(), {
  keyA: 25,
  section1: {
    keyA: 100
  }
});

The reviver and replacer APIs can be used to extend the behavior of IniMap, such as adding support for duplicate keys as if they were arrays of values.

import { IniMap } from "@std/ini/ini-map";
import { assertEquals } from "@std/assert";

const iniFile = `# Example of key/value arrays
[section1]
key1=This key
key1=is non-standard
key1=but can be captured!`;

const ini = new IniMap({ assignment: "=", deduplicate: true });
ini.parse(iniFile, (key, value, section) => {
  if (section) {
    if (ini.has(section, key)) {
      const exists = ini.get(section, key);
      if (Array.isArray(exists)) {
        exists.push(value);
        return exists;
      } else {
        return [exists, value];
      }
    }
  }
  return value;
});

assertEquals(
  ini.get("section1", "key1"),
  ["This key", "is non-standard", "but can be captured!"]
);

const result = ini.toString((key, value) => {
  if (Array.isArray(value)) {
    return value.join(
      `${ini.formatting.lineBreak}${key}${ini.formatting.assignment}`,
    );
  }
  return value;
});

assertEquals(result, iniFile);

Add to your project Jump to heading

deno add jsr:@std/ini

See all symbols in @std/ini on

什么是 INI 文件? Jump to heading

INI 文件是用作配置的简单文本文件。它们由键值对组成,按节分组,便于人类阅读和编辑。INI 文件常用于应用设置、偏好和其他配置数据。

为什么使用 @std/ini? Jump to heading

  • INI 规范较宽松;推荐使用简单的键/值及扁平化的节以获得最佳互操作性。
  • 默认解析值为字符串。使用 reviver/replacer 明确转换为数字/日期/布尔值。
  • 多行值和数组非标准;若需要可通过 IniMap 结合自定义 reviver/replacer 模拟。
  • 注释以 #;// 开头,IniMap 能保留注释。

示例 Jump to heading

类型强制转换

import * as ini from "@std/ini";

const cfg = ini.parse(text, {
  reviver(key, value) {
    if (/^(true|false)$/i.test(value)) return value.toLowerCase() === "true";
    if (/^\d+$/.test(value)) return Number(value);
    return value;
  },
});

自定义赋值运算符及美化格式化

import * as ini from "@std/ini";

const txt = `name: Deno\nversion: 1`;

// 解析时使用 ':' 替代 '='
const parsed = ini.parse(txt, { assignment: ":" });

// 写出时继续使用 ':' 并进行美化间距
const out = ini.stringify(parsed, { assignment: ":", pretty: true });
// out => "name : Deno\nversion : 1"

使用 IniMap 保留注释和顺序

import { IniMap } from "@std/ini/ini-map";

const text = `# Global
[app]
# 监听端口
port=8080`;

const im = new IniMap();
im.parse(text);

// 修改值同时保留注释和顺序
im.set("app", "port", "9090");

// 输出时保留注释和结构
const roundTrip = im.toString();

合并分层配置(基础 + 本地覆盖)

import { IniMap } from "@std/ini/ini-map";

const baseText = `[db]\nhost=localhost\nport=5432\n[app]\nmode=prod`;
const localText = `[db]\nport=6543\n[app]\nmode=dev`;

const base = new IniMap();
base.parse(baseText);

const local = new IniMap();
local.parse(localText);

// 将本地覆盖的值叠加到基础配置
const overlay = (target: IniMap, source: IniMap) => {
  const obj = source.toObject() as Record<string, unknown>;
  for (const [k, v] of Object.entries(obj)) {
    if (v && typeof v === "object" && !Array.isArray(v)) {
      for (const [kk, vv] of Object.entries(v as Record<string, string>)) {
        target.set(k, kk, vv);
      }
    } else {
      target.set(k, v as string);
    }
  }
};

overlay(base, local);
const merged = base.toString();

重复键:后者覆盖与保留

import * as ini from "@std/ini";
import { IniMap } from "@std/ini/ini-map";

const dup = `x=1\nx=2`;

// 简单解析:以最后一个值为准
const simple = ini.parse(dup); // { x: "2" }

// 使用 IniMap 保留重复键(你可以实现自定义处理)
const im = new IniMap({ deduplicate: true });
im.parse(dup);
// 例如 im.get("x") 默认返回 "2";可利用自定义 reviver 收集所有值

你找到了你需要的东西吗?

编辑此页面
隐私政策