@amxts/config-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/PAWN.md +13 -0
- package/PAWN.ru.md +13 -0
- package/README.md +249 -0
- package/README.ru.md +249 -0
- package/include/universal_config.inc +355 -0
- package/package.json +67 -0
- package/prebuilt/linux/config-core.aot +0 -0
- package/prebuilt/manifest.json +2281 -0
- package/prebuilt/windows/config-core.aot +0 -0
- package/scripts/docs/src/index.ts +197 -0
- package/scripts/docs/src/types.ts +20 -0
- package/src/files.ts +27 -0
- package/src/index.ts +360 -0
- package/src/ini-tree.ts +144 -0
- package/src/ini.ts +723 -0
- package/src/internal.ts +44 -0
- package/src/json.ts +386 -0
- package/src/natives.ts +271 -0
- package/src/tree.ts +171 -0
- package/src/typed.ts +419 -0
- package/src/types.ts +22 -0
- package/src/yaml.ts +840 -0
package/src/ini-tree.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An INI file as Config Core's tree - its sections an object of objects - and
|
|
3
|
+
* the tree written back as INI. Not part of the API.
|
|
4
|
+
*/
|
|
5
|
+
import { Config, Entry, Section } from "./ini";
|
|
6
|
+
import { Place, TreeDocument, TreeNode } from "./internal";
|
|
7
|
+
import { isScalar, makeNode, memberIndex, writeComments } from "./tree";
|
|
8
|
+
|
|
9
|
+
/** The line of an INI entry; its column is not kept. */
|
|
10
|
+
function placeOfLine(line: number) {
|
|
11
|
+
const place: Place = { line, column: 0 };
|
|
12
|
+
return place;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** A line of values: none is null, one is text, several are a list of text. */
|
|
16
|
+
function valuesNode(values: string[], line: number) {
|
|
17
|
+
if (values.length == 0) return makeNode("null", "", "", placeOfLine(line));
|
|
18
|
+
if (values.length == 1) return makeNode("string", "", values[0], placeOfLine(line));
|
|
19
|
+
const list = makeNode("array", "", "", placeOfLine(line));
|
|
20
|
+
for (const value of values) list.items.push(makeNode("string", "", value, placeOfLine(line)));
|
|
21
|
+
return list;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** A block of `key = value` lines is an object; a block with rows is a list of them. */
|
|
25
|
+
function blockNode(entry: Entry) {
|
|
26
|
+
if (entry.content == "strings") return valuesNode(entry.values, entry.line);
|
|
27
|
+
const keyed = entry.rows.every(row => row.key.length > 0);
|
|
28
|
+
const node = makeNode(keyed ? "object" : "array", "", "", placeOfLine(entry.line));
|
|
29
|
+
node.foldCase = keyed;
|
|
30
|
+
node.block = !keyed;
|
|
31
|
+
|
|
32
|
+
for (const row of entry.rows) {
|
|
33
|
+
if (keyed && memberIndex(node, row.key) >= 0) continue;
|
|
34
|
+
const made = row.key.length > 0 && !keyed ? keyedRow(row) : entryNode(row);
|
|
35
|
+
node.items.push(made);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return node;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** A `key = value` line among rows: an object with that one member. */
|
|
42
|
+
function keyedRow(row: Entry) {
|
|
43
|
+
const node = makeNode("object", "", "", placeOfLine(row.line));
|
|
44
|
+
node.foldCase = true;
|
|
45
|
+
node.items.push(entryNode(row));
|
|
46
|
+
node.comments = row.comments;
|
|
47
|
+
return node;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function entryNode(entry: Entry) {
|
|
51
|
+
const node = entry.kind == "block" ? blockNode(entry) : valuesNode(entry.values, entry.line);
|
|
52
|
+
node.key = entry.key;
|
|
53
|
+
node.comments = entry.comments;
|
|
54
|
+
return node;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function sectionNode(section: Section) {
|
|
58
|
+
const node = makeNode("object", section.name, "", placeOfLine(section.line));
|
|
59
|
+
node.foldCase = true;
|
|
60
|
+
node.comments = section.comments;
|
|
61
|
+
|
|
62
|
+
for (const entry of section.entries) {
|
|
63
|
+
// The first of a key found twice is the one read, as cfg_get_value reads it.
|
|
64
|
+
if (memberIndex(node, entry.key) < 0) node.items.push(entryNode(entry));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return node;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The sections as an object; a name found twice is the last section of that name, as cfg_get_section finds it. */
|
|
71
|
+
export function iniTree(config: Config) {
|
|
72
|
+
const root = makeNode("object", "", "", { line: 1, column: 0 });
|
|
73
|
+
for (const section of config.sections) {
|
|
74
|
+
const node = sectionNode(section);
|
|
75
|
+
const known = memberIndex(root, section.name);
|
|
76
|
+
if (known >= 0) root.items[known] = node;
|
|
77
|
+
else root.items.push(node);
|
|
78
|
+
}
|
|
79
|
+
return root;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** A value as INI writes it: in quotes when it has a space in it, or nothing in it. */
|
|
83
|
+
function iniValue(node: TreeNode) {
|
|
84
|
+
if (node.kind == "boolean") return node.text == "true" ? "1" : "0";
|
|
85
|
+
const text = node.kind == "number" && node.text.length == 0 ? `${node.value}` : node.text;
|
|
86
|
+
return text.length == 0 || text.includes(" ") || text.includes("\t") ? `"${text}"` : text;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** A row of a block of rows: "value" "value" - or the lines of a `key = value` row. */
|
|
90
|
+
function writeRow(lines: string[], row: TreeNode, level: number) {
|
|
91
|
+
const pad = "\t".repeat(level);
|
|
92
|
+
writeComments(lines, row.comments, pad);
|
|
93
|
+
|
|
94
|
+
if (row.kind == "object") {
|
|
95
|
+
for (const each of row.items) writeEntry(lines, each, level);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const values = (row.kind == "array" ? row.items : [row]).filter(isScalar);
|
|
100
|
+
lines.push(`${pad}${values.map(each => `"${iniValue(each).replaceAll("\"", "")}"`).join(" ")}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function writeEntry(lines: string[], entry: TreeNode, level: number) {
|
|
104
|
+
const pad = "\t".repeat(level);
|
|
105
|
+
writeComments(lines, entry.comments, pad);
|
|
106
|
+
|
|
107
|
+
if (entry.kind == "null") {
|
|
108
|
+
lines.push(`${pad}${entry.key} =`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (isScalar(entry)) {
|
|
113
|
+
lines.push(`${pad}${entry.key} = ${iniValue(entry)}`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (entry.kind == "array" && !entry.block && entry.items.every(isScalar)) {
|
|
118
|
+
lines.push(`${pad}${entry.key} = ${entry.items.map(iniValue).join(" ")}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
lines.push(`${pad}${entry.key} = {`);
|
|
123
|
+
if (entry.kind == "object") {
|
|
124
|
+
for (const each of entry.items) writeEntry(lines, each, level + 1);
|
|
125
|
+
} else {
|
|
126
|
+
for (const row of entry.items) writeRow(lines, row, level + 1);
|
|
127
|
+
}
|
|
128
|
+
lines.push(`${pad}}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The document as INI lines: each member of the top an [section], what is not an object left out. */
|
|
132
|
+
export function writeIni(document: TreeDocument) {
|
|
133
|
+
const lines: string[] = [];
|
|
134
|
+
for (const section of document.root.items) {
|
|
135
|
+
if (section.kind != "object") continue;
|
|
136
|
+
// A section made at run time gets a blank line before it, as save() gives one.
|
|
137
|
+
if (section.line == 0 && lines.length > 0) lines.push("");
|
|
138
|
+
writeComments(lines, section.comments, "");
|
|
139
|
+
lines.push(`[${section.key}]`);
|
|
140
|
+
for (const each of section.items) writeEntry(lines, each, 0);
|
|
141
|
+
}
|
|
142
|
+
writeComments(lines, document.tail, "");
|
|
143
|
+
return lines;
|
|
144
|
+
}
|