s2cfgtojson 3.3.0 → 3.5.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/Struct.mts +79 -13
- package/Struct.test.mts +90 -5
- package/package.json +1 -1
package/Struct.mts
CHANGED
|
@@ -13,17 +13,33 @@ const KEYWORDS = [
|
|
|
13
13
|
"bpatch", // allows patching only specific keys
|
|
14
14
|
];
|
|
15
15
|
const REMOVE_NODE = "removenode";
|
|
16
|
-
const INTERNAL_PROPS = new
|
|
17
|
-
"__internal__",
|
|
18
|
-
"fork",
|
|
19
|
-
"removeNode",
|
|
20
|
-
"addNode",
|
|
21
|
-
"clone",
|
|
22
|
-
"forEach",
|
|
23
|
-
"filter",
|
|
24
|
-
"map",
|
|
25
|
-
"toString",
|
|
26
|
-
]
|
|
16
|
+
const INTERNAL_PROPS = new Map([
|
|
17
|
+
["__internal__", "_"],
|
|
18
|
+
["fork", ""], // methods
|
|
19
|
+
["removeNode", ""], // methods
|
|
20
|
+
["addNode", ""], // methods
|
|
21
|
+
["clone", ""], // methods
|
|
22
|
+
["forEach", ""], // methods
|
|
23
|
+
["filter", ""], // methods
|
|
24
|
+
["map", ""], // methods
|
|
25
|
+
["toString", ""], // methods
|
|
26
|
+
] as const);
|
|
27
|
+
const INTERNAL_PROPS_INV = new Map(
|
|
28
|
+
Array.from(INTERNAL_PROPS.entries()).map(([k, v]) => [v, k]),
|
|
29
|
+
);
|
|
30
|
+
const REF_INTERNAL_PROPS = new Map([
|
|
31
|
+
["rawName", "w"],
|
|
32
|
+
["refurl", "u"],
|
|
33
|
+
["refkey", "k"],
|
|
34
|
+
["bskipref", "s"],
|
|
35
|
+
["bpatch", "p"],
|
|
36
|
+
["isArray", "a"],
|
|
37
|
+
["isRoot", "r"],
|
|
38
|
+
["useAsterisk", "*"],
|
|
39
|
+
] as const);
|
|
40
|
+
const REF_INTERNAL_PROPS_INV = new Map(
|
|
41
|
+
Array.from(REF_INTERNAL_PROPS.entries()).map(([k, v]) => [v, k]),
|
|
42
|
+
);
|
|
27
43
|
|
|
28
44
|
/**
|
|
29
45
|
* This file is part of the Stalker 2 Modding Tools project.
|
|
@@ -152,11 +168,27 @@ export class Struct {
|
|
|
152
168
|
return clone;
|
|
153
169
|
}
|
|
154
170
|
|
|
155
|
-
static fromJson<T>(
|
|
171
|
+
static fromJson<T>(
|
|
172
|
+
obj: T,
|
|
173
|
+
minified = false,
|
|
174
|
+
): T extends object ? GetStructType<T> : T {
|
|
156
175
|
if (typeof obj === "object" && !!obj) {
|
|
157
176
|
const instance = new Struct();
|
|
158
177
|
Object.entries(obj).forEach(([key, value]) => {
|
|
159
|
-
|
|
178
|
+
const nKey = fromMinifiedKey(key, minified);
|
|
179
|
+
|
|
180
|
+
if (nKey === "__internal__") {
|
|
181
|
+
instance[nKey] = new Refs(
|
|
182
|
+
Object.fromEntries(
|
|
183
|
+
Object.entries(value).map(([k, v]) => [
|
|
184
|
+
fromMinifiedKey(k, minified),
|
|
185
|
+
v,
|
|
186
|
+
]),
|
|
187
|
+
),
|
|
188
|
+
);
|
|
189
|
+
} else {
|
|
190
|
+
instance[nKey] = Struct.fromJson(value, minified);
|
|
191
|
+
}
|
|
160
192
|
});
|
|
161
193
|
return instance as any;
|
|
162
194
|
}
|
|
@@ -164,6 +196,24 @@ export class Struct {
|
|
|
164
196
|
return obj as any;
|
|
165
197
|
}
|
|
166
198
|
|
|
199
|
+
toJson<T extends object>(minify = false): T {
|
|
200
|
+
const obj = {};
|
|
201
|
+
|
|
202
|
+
Object.entries(this).forEach(([key, value]) => {
|
|
203
|
+
let nKey = maybeMinifyKey(key, minify);
|
|
204
|
+
if (value instanceof Struct) {
|
|
205
|
+
obj[nKey] = value.toJson(minify);
|
|
206
|
+
} else if (value instanceof Refs) {
|
|
207
|
+
obj[nKey] = Object.fromEntries(
|
|
208
|
+
Object.entries(value).map(([k, v]) => [maybeMinifyKey(k, minify), v]),
|
|
209
|
+
);
|
|
210
|
+
} else {
|
|
211
|
+
obj[nKey] = value;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
return obj as T;
|
|
215
|
+
}
|
|
216
|
+
|
|
167
217
|
toString(): string {
|
|
168
218
|
if (!(this.__internal__ instanceof Refs)) {
|
|
169
219
|
this.__internal__ = new Refs(this.__internal__);
|
|
@@ -431,3 +481,19 @@ function parseStructName(name: string): string {
|
|
|
431
481
|
.replace(/_+/g, "_")
|
|
432
482
|
.replace(/^_+/, "");
|
|
433
483
|
}
|
|
484
|
+
|
|
485
|
+
function maybeMinifyKey(key: string, minify: boolean) {
|
|
486
|
+
return minify &&
|
|
487
|
+
(INTERNAL_PROPS.has(key as any) || REF_INTERNAL_PROPS.has(key as any))
|
|
488
|
+
? INTERNAL_PROPS.get(key as any) || REF_INTERNAL_PROPS.get(key as any)
|
|
489
|
+
: key;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function fromMinifiedKey(key: string, minified: boolean) {
|
|
493
|
+
if (!minified) return key;
|
|
494
|
+
return (
|
|
495
|
+
INTERNAL_PROPS_INV.get(key as any) ||
|
|
496
|
+
REF_INTERNAL_PROPS_INV.get(key as any) ||
|
|
497
|
+
key
|
|
498
|
+
);
|
|
499
|
+
}
|
package/Struct.test.mts
CHANGED
|
@@ -10,32 +10,36 @@ import {
|
|
|
10
10
|
import fs from "node:fs";
|
|
11
11
|
|
|
12
12
|
class ChimeraHPFix extends Struct {
|
|
13
|
-
__internal__ = {
|
|
13
|
+
__internal__ = new Refs({
|
|
14
14
|
rawName: "ChimeraHPFix",
|
|
15
15
|
isRoot: true,
|
|
16
16
|
bskipref: true,
|
|
17
|
-
};
|
|
17
|
+
});
|
|
18
18
|
|
|
19
19
|
MaxHP = 750;
|
|
20
20
|
}
|
|
21
21
|
class TradePrototype extends Struct {
|
|
22
|
-
__internal__ = {
|
|
22
|
+
__internal__ = new Refs({
|
|
23
23
|
rawName: "TradersDontBuyWeaponsArmor",
|
|
24
24
|
refurl: "../TradePrototypes.cfg",
|
|
25
25
|
refkey: 0,
|
|
26
26
|
isRoot: true,
|
|
27
|
-
};
|
|
27
|
+
});
|
|
28
28
|
|
|
29
29
|
TradeGenerators = new TradeGenerators();
|
|
30
30
|
}
|
|
31
31
|
class TradeGenerators extends Struct {
|
|
32
32
|
__internal__ = new Refs({
|
|
33
33
|
isArray: true,
|
|
34
|
+
rawName: "TradeGenerators",
|
|
34
35
|
//useAsterisk: true, this option is not supported for now
|
|
35
36
|
});
|
|
36
37
|
"0" = new TradeGenerator();
|
|
37
38
|
}
|
|
38
39
|
class TradeGenerator extends Struct {
|
|
40
|
+
__internal__ = new Refs({
|
|
41
|
+
rawName: "0",
|
|
42
|
+
});
|
|
39
43
|
BuyLimitations = new BuyLimitations();
|
|
40
44
|
}
|
|
41
45
|
|
|
@@ -270,7 +274,7 @@ struct.end`;
|
|
|
270
274
|
expect(a.TradeGenerators[0].BuyLimitations[0]).toBe("EItemType::Weapon");
|
|
271
275
|
expect(a.TradeGenerators[0].BuyLimitations[1]).toBe("EItemType::Armor");
|
|
272
276
|
a.TradeGenerators[0].BuyLimitations.forEach(([k]) => {
|
|
273
|
-
a.TradeGenerators[0].BuyLimitations[k] = "forEach";
|
|
277
|
+
a.TradeGenerators[0].BuyLimitations[k] = "forEach" as any;
|
|
274
278
|
});
|
|
275
279
|
expect(a.TradeGenerators[0].BuyLimitations[0]).toBe("forEach");
|
|
276
280
|
expect(a.TradeGenerators[0].BuyLimitations[1]).toBe("forEach");
|
|
@@ -321,6 +325,39 @@ struct.end`;
|
|
|
321
325
|
});
|
|
322
326
|
});
|
|
323
327
|
|
|
328
|
+
describe("toJson", () => {
|
|
329
|
+
test("1", () => {
|
|
330
|
+
const struct = new TradePrototype();
|
|
331
|
+
expect(struct.toJson()).toEqual({
|
|
332
|
+
__internal__: {
|
|
333
|
+
rawName: "TradersDontBuyWeaponsArmor",
|
|
334
|
+
isRoot: true,
|
|
335
|
+
refurl: "../TradePrototypes.cfg",
|
|
336
|
+
refkey: 0,
|
|
337
|
+
},
|
|
338
|
+
TradeGenerators: {
|
|
339
|
+
__internal__: { rawName: "TradeGenerators", isArray: true },
|
|
340
|
+
"0": {
|
|
341
|
+
__internal__: { rawName: "0" },
|
|
342
|
+
BuyLimitations: {
|
|
343
|
+
__internal__: { rawName: "BuyLimitations", isArray: true },
|
|
344
|
+
"0": "EItemType::Weapon",
|
|
345
|
+
"1": "EItemType::Armor",
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
test("2", () => {
|
|
353
|
+
const struct = new ChimeraHPFix();
|
|
354
|
+
expect(struct.toJson(true)).toEqual({
|
|
355
|
+
_: { w: "ChimeraHPFix", r: true, s: true },
|
|
356
|
+
MaxHP: 750,
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
324
361
|
describe("fromJson", () => {
|
|
325
362
|
test("1", () => {
|
|
326
363
|
const json = {
|
|
@@ -367,6 +404,54 @@ struct.end`;
|
|
|
367
404
|
struct.end
|
|
368
405
|
struct.end
|
|
369
406
|
struct.end
|
|
407
|
+
struct.end`);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test("2", () => {
|
|
411
|
+
const json = {
|
|
412
|
+
_: { w: "Test", r: true },
|
|
413
|
+
MeshGenerator: {
|
|
414
|
+
_: { w: "MeshGenerator" },
|
|
415
|
+
Meshes: {
|
|
416
|
+
_: { w: "Meshes", a: true },
|
|
417
|
+
"0": {
|
|
418
|
+
_: { w: "0" },
|
|
419
|
+
MeshPath: "path/to/mesh",
|
|
420
|
+
Offset: {
|
|
421
|
+
_: { w: "Offset" },
|
|
422
|
+
X: 0,
|
|
423
|
+
Y: 0,
|
|
424
|
+
Z: 0,
|
|
425
|
+
},
|
|
426
|
+
Rotation: {
|
|
427
|
+
_: { w: "Rotation" },
|
|
428
|
+
Pitch: 0,
|
|
429
|
+
Yaw: 0,
|
|
430
|
+
Roll: 0,
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
};
|
|
436
|
+
const struct = Struct.fromJson(json, true);
|
|
437
|
+
expect(struct.toString()).toBe(`Test : struct.begin
|
|
438
|
+
MeshGenerator : struct.begin
|
|
439
|
+
Meshes : struct.begin
|
|
440
|
+
[0] : struct.begin
|
|
441
|
+
MeshPath = path/to/mesh
|
|
442
|
+
Offset : struct.begin
|
|
443
|
+
X = 0
|
|
444
|
+
Y = 0
|
|
445
|
+
Z = 0
|
|
446
|
+
struct.end
|
|
447
|
+
Rotation : struct.begin
|
|
448
|
+
Pitch = 0
|
|
449
|
+
Yaw = 0
|
|
450
|
+
Roll = 0
|
|
451
|
+
struct.end
|
|
452
|
+
struct.end
|
|
453
|
+
struct.end
|
|
454
|
+
struct.end
|
|
370
455
|
struct.end`);
|
|
371
456
|
});
|
|
372
457
|
});
|