dotink/jin

Jsonified Ini Notation

4.8.0 2023-10-31 04:30 UTC

README

JIN 是一种数据格式,它使用与 JSON 类似的 INI 文件结构。

它是一种简单、非正式的语言,非常适合配置数据和设置。它最好用作元配置或某种类型的模式配置,但也可以为像 .env 文件这样的简单内容提供丰富的类型和对象支持。

在某种程度上,它与 TOML (https://github.com/toml-lang/toml) 类似,但没有正式规范。解析规则可以最好地描述如下

  • 文件结构类似于 INI 文件
    • key = value
    • [section]
    • ; comment
  • 值类似于 JSON,但有以下不同
    • 不支持转义字符,例如 \n, \b, \t
    • 单个 \ 不需要转义

基本用法

$jin_parser  = new Dotink\Jin\Parser()
$jin_string  = file_get_contents('config.jin');
$config_data = $jin_parser->parse($jin_string)->get();

在集合上调用 get() 将返回作为关联数组的完整解析数据。

如果您想直接与集合一起工作,可以省略 get()。您可以在 (https://github.com/adbario/php-dot-notation) 查看有关集合的更多文档。

$config = $jin_parser->parse($jin_string);

直接使用集合将允许您使用“点表示法”引用和检索特定值,如果它们不存在,还可以提供默认值

$config->get('database.connections.default', [
	'name' => 'website',
	'host' => 'localhost',
	'user' => 'web',
	'pass' => '3ch0th3w4lRUS'
]);

您还可以通过将第二个参数传递为 FALSE 来在解析的 JSON 中保留 stdClass 对象

$config_data = $jin_parser->parse($jin_string, FALSE)->get();

语言

简单字段

field = value ; INI style string

字符串不必加引号,但也可以加

field = "value" ; JSON style string

整数会自动转换为正确的类型

integerValue = 1

浮点数也是如此...

floatValue = 1.03

布尔值和 NULL 值不区分大小写

boolValue = false
boolValue = TRUE
nullValue = NULL

多行文本

multi = JIN supports multi-line values until the new line resembles
an INI database structure.  So, for example, this line would be parsed
with new lines preserved until `foo=bar` or `[section]` or `\n\n`.

注释

注释可以在值的任何位置允许,因此请记住,任何在 ; 字符之后的内容都将被截断。

field = "This probably does not do what you expect; this is stripped"

类似于 JSON 的值

数组以字面量定义

favoriteFoods = ["Tacos", "Sushi", "Curry"]

对象也以字面量定义

favorites = {"food":  "Indian", "music": "Classic Rock"}

两者都可以跨越多行并包含注释

multiFoods = [
	"Tacos",
	"Sushi", ; Most keto friendly
	"Curry"
]

multiFavorites = {
	;
	; The basics
	;

	"food": "Tacos",
	"music": "Classic Rock" ; Not actually my favorite
}

差异

虽然值类似于 JSON,但严格来说,它们不是 JSON。主要区别是它们不支持 JSON 的内置转义字符,因此您不能使用 \n\t。另一方面,您不需要转义反斜杠

middlewares = [
	"App\Middleware\ResponseHandler"
]

部分

部分提供了对 JSON 对象结构的替代方案。请注意,部分永远不会解析为 stdClass 对象,但总是返回关联数组。

[category]

	fieldOne   = valueOne
	fieldTwo   = valueTwo
	fieldThree = 1
	fieldFour  = [0, 7, 9, 13]
	fieldFive  = {
		"foo": "bar"
	}

子部分

您可以通过用点分隔前一个类别名称来添加子部分。这对于具有重复数据的键配置值非常有用,例如,想象一个具有多个别名连接的数据库配置

[database]

	[database.connections.default]
		driver = pgsql
		dbname = website
		host   = localhost

	[database.connections.forums]
		driver = mysql
		dbname = forums
		host   = localhost
		user   = web
		pass   = 3ch0th3w4lRUS

部分引用

您可以通过简短的部分名称来引用父部分。

[database]

	[&.connections.default]
		driver = pgsql
		dbname = website
		host   = localhost

可以堆叠引用以引用子子部分。引用堆叠始终从最后一个未引用定义的部分开始

[database]

	[&.connections]

		;
		; This section contains all of our database connections
		;

		[&&.default]
			driver = pgsql
			dbname = website
			host   = localhost

环境变量

您可以获取环境中的值。

envField = env(DEBUGGING)

并提供默认值,当它们未设置时

envField = env(DEBUGGING, TRUE)

本地语言值

您可以使用本地语言函数(在本实现中为 PHP)

runField = run(md5('hash this thing'))

您还可以为解析器添加上下文以访问变量

$jin_parser  = new Dotink\Jin\Parser([
	'app' => $app
]);

然后像您预期的那样访问/使用它们

cacheDirectory = run($app->getDirectory('storage/cache', TRUE))

自定义函数

您可以通过将函数名键的调用来作为第二个参数传递给解析器来添加自定义函数

$jin_parser  = new Dotink\Jin\Parser([], [
	'hello' => function($name) {
		return 'Hello ' . $name;
	}
]);

然后像您预期的那样使用它们。

hello = hello(Matt)

注意,您可以重载 env() 和甚至 run() 函数,但是重载如 map()def()inc() 这样的结构将不会工作。

模板

模板提供了一种强大的方式来重复具有不同值的复杂数据结构

[database]

	settings = def(type, name, host, user, pass) {
		{
			"type": $type,
			"name": $name,
			"host": $host,
			"auth": {
				"user": $user,
				"pass": $pass
			}
		}
	}

	[&.connections]

		default = inc(database.settings) {
			pgsql
			my_database
			localhost

			;
			; Do not be afraid to use any valid value where values are
			; specified
			;

			env(DB_USER, web)
			env(DB_PASS, NULL)
		}

模板还可以用来创建非键控对象的数组

[routing]

	route = def(methods, pattern, target) {
		{
			"methods": $methods,
			"pattern": $pattern,
			"target": $target
		}
	}

	;
	; The map function takes a tab separated list of values.  Multiple tabs
	; are reduced to one before parsing.
	;

	routes = map(routing.route) {
		["GET"]		/		ViewHome
		["GET"]		/articles	ListArticles
		["POST"]	/articles	CreateArticle
		["GET"]		/articles/{id}	ViewArticle
		["POST"]	/articles/{id}	EditArticle
	}

测试

php vendor/bin/phpunit --bootstrap vendor/autoload.php test/routines/

附录

JIN最初被编写为配置数据映射ORM的一种方式。它是一种非常灵活且直观的语言,但在某些情况下可能没有意义。强烈建议如果您经常使用它进行访问配置(如运行时),则应将结果集合序列化和缓存,而不是每次加载时都解析它。

编辑器支持

这里有一个为Atom准备的语法文件,可以在这里找到

https://github.com/dotink/atom-language-jin

由于其与TOML的相似性,TOML语法高亮也往往看起来不错。您还可以尝试JS/JSON语法高亮,但具体效果可能因语法高亮实现而异。