s2cfgtojson 7.0.13 → 7.0.15
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/dist/Struct.d.ts +67 -0
- package/dist/Struct.mjs +481 -0
- package/dist/enums.d.ts +205 -0
- package/dist/enums.mjs +2 -0
- package/dist/types.d.ts +9842 -0
- package/dist/types.mjs +3 -0
- package/dist/utility-types.d.ts +23 -0
- package/dist/utility-types.mjs +1 -0
- package/package.json +34 -3
- package/readme.md +1 -1
- package/Struct.mts +0 -623
- package/Struct.test.mts +0 -488
- package/enums.mts +0 -1980
- package/test.cfg +0 -598
- package/tsconfig.json +0 -8
- package/types.mts +0 -12248
- package/utility-types.mts +0 -668
package/Struct.mts
DELETED
|
@@ -1,623 +0,0 @@
|
|
|
1
|
-
export * from "./types.mts";
|
|
2
|
-
export * from "./enums.mts";
|
|
3
|
-
|
|
4
|
-
export type Internal =
|
|
5
|
-
| "__internal__"
|
|
6
|
-
| "fork"
|
|
7
|
-
| "removeNode"
|
|
8
|
-
| "addNode"
|
|
9
|
-
| "clone"
|
|
10
|
-
| "entries"
|
|
11
|
-
| "forEach"
|
|
12
|
-
| "filter"
|
|
13
|
-
| "map"
|
|
14
|
-
| "toJson"
|
|
15
|
-
| "toString";
|
|
16
|
-
|
|
17
|
-
export type InternalPlus = Internal | "fromString" | "fromJson";
|
|
18
|
-
|
|
19
|
-
export interface DefaultEntries {
|
|
20
|
-
bpatch?: boolean;
|
|
21
|
-
bskipref?: boolean;
|
|
22
|
-
isArray?: boolean;
|
|
23
|
-
isRoot?: boolean;
|
|
24
|
-
rawName?: string;
|
|
25
|
-
refkey?: string | number;
|
|
26
|
-
refurl?: string;
|
|
27
|
-
removenode?: boolean;
|
|
28
|
-
useAsterisk?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type GetStructType<In> =
|
|
32
|
-
In extends Array<any>
|
|
33
|
-
? Struct & { [key: `${number}`]: GetStructType<In[typeof key]> }
|
|
34
|
-
: In extends Record<any, any>
|
|
35
|
-
? Struct & {
|
|
36
|
-
[key in keyof In]: key extends Internal
|
|
37
|
-
? Struct[key]
|
|
38
|
-
: GetStructType<In[key]>;
|
|
39
|
-
}
|
|
40
|
-
: In extends string
|
|
41
|
-
? In
|
|
42
|
-
: In extends number
|
|
43
|
-
? number
|
|
44
|
-
: In extends boolean
|
|
45
|
-
? boolean
|
|
46
|
-
: In;
|
|
47
|
-
|
|
48
|
-
const TAB = " ";
|
|
49
|
-
const WILDCARD = "_wildcard";
|
|
50
|
-
const KEYWORDS = [
|
|
51
|
-
"refurl", // a file path to override
|
|
52
|
-
"refkey", // SID to override
|
|
53
|
-
"bskipref", // ??? not sure
|
|
54
|
-
"bpatch", // allows patching only specific keys
|
|
55
|
-
];
|
|
56
|
-
const REMOVE_NODE = "removenode";
|
|
57
|
-
const INTERNAL_PROPS = new Map([
|
|
58
|
-
["__internal__", "_"],
|
|
59
|
-
["fork", ""], // methods
|
|
60
|
-
["removeNode", ""], // methods
|
|
61
|
-
["addNode", ""], // methods
|
|
62
|
-
["clone", ""], // methods
|
|
63
|
-
["entries", ""], // methods
|
|
64
|
-
["forEach", ""], // methods
|
|
65
|
-
["filter", ""], // methods
|
|
66
|
-
["map", ""], // methods
|
|
67
|
-
["fromJson", ""], // methods
|
|
68
|
-
["toJson", ""], // methods
|
|
69
|
-
["toString", ""], // methods
|
|
70
|
-
["fromString", ""], // methods
|
|
71
|
-
] as const);
|
|
72
|
-
const INTERNAL_PROPS_INV = new Map(
|
|
73
|
-
Array.from(INTERNAL_PROPS.entries()).map(([k, v]) => [v, k]),
|
|
74
|
-
);
|
|
75
|
-
const REF_INTERNAL_PROPS = new Map([
|
|
76
|
-
["rawName", "w"],
|
|
77
|
-
["refurl", "u"],
|
|
78
|
-
["refkey", "k"],
|
|
79
|
-
["bskipref", "s"],
|
|
80
|
-
["bpatch", "p"],
|
|
81
|
-
["isArray", "a"],
|
|
82
|
-
["isRoot", "r"],
|
|
83
|
-
["useAsterisk", "*"],
|
|
84
|
-
] as const);
|
|
85
|
-
const REF_INTERNAL_PROPS_INV = new Map(
|
|
86
|
-
Array.from(REF_INTERNAL_PROPS.entries()).map(([k, v]) => [v, k]),
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* This file is part of the Stalker 2 Modding Tools project.
|
|
91
|
-
* This is a base class for all structs.
|
|
92
|
-
*/
|
|
93
|
-
export class Struct implements Record<Internal, any> {
|
|
94
|
-
__internal__: Refs = new Refs();
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Creates a new struct instance.
|
|
98
|
-
*/
|
|
99
|
-
constructor(parentOrRaw?: string | Struct | object) {
|
|
100
|
-
if (parentOrRaw instanceof Struct) {
|
|
101
|
-
Object.assign(this, parentOrRaw.clone());
|
|
102
|
-
}
|
|
103
|
-
if (typeof parentOrRaw === "string") {
|
|
104
|
-
Object.assign(this, Struct.fromString(parentOrRaw)[0]);
|
|
105
|
-
}
|
|
106
|
-
if (typeof parentOrRaw === "object" && parentOrRaw !== null) {
|
|
107
|
-
Object.assign(this, Struct.fromJson(parentOrRaw));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
fork(clone = false) {
|
|
112
|
-
const patch = clone
|
|
113
|
-
? this.clone()
|
|
114
|
-
: createDynamicClassInstance(
|
|
115
|
-
this.__internal__.rawName || this.constructor.name,
|
|
116
|
-
);
|
|
117
|
-
patch.__internal__.isRoot = this.__internal__.isRoot;
|
|
118
|
-
patch.__internal__.isArray = this.__internal__.isArray;
|
|
119
|
-
patch.__internal__.useAsterisk = this.__internal__.useAsterisk;
|
|
120
|
-
|
|
121
|
-
function markAsbPatch(s: Struct) {
|
|
122
|
-
s.__internal__.bpatch = true;
|
|
123
|
-
Object.values(s)
|
|
124
|
-
.filter((v) => v instanceof Struct)
|
|
125
|
-
.forEach(markAsbPatch);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
markAsbPatch(patch);
|
|
129
|
-
return patch as this;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
removeNode(key: Exclude<keyof this, Symbol>) {
|
|
133
|
-
if (this.__internal__.bpatch !== true) {
|
|
134
|
-
throw new Error(
|
|
135
|
-
"Cannot remove node from non-patch struct. Use fork() first.",
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
if (this[key] instanceof Struct) {
|
|
139
|
-
this[key].__internal__.removenode = true;
|
|
140
|
-
} else {
|
|
141
|
-
console.warn(
|
|
142
|
-
`Attempting to remove node on non-struct value. Old value: '${this.__internal__.rawName}.${key}' = ${this[key]}. Assigning 'empty' instead.`,
|
|
143
|
-
);
|
|
144
|
-
this[key] = "empty" as any;
|
|
145
|
-
}
|
|
146
|
-
return this;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
addNode(value: any, key?: string | number): this {
|
|
150
|
-
if (key === undefined) {
|
|
151
|
-
const nextIndex = Object.keys(this)
|
|
152
|
-
.map((k) => parseInt(k))
|
|
153
|
-
.filter((k) => !isNaN(k))
|
|
154
|
-
.sort((a, b) => a - b)
|
|
155
|
-
.pop();
|
|
156
|
-
this[nextIndex !== undefined ? nextIndex + 1 : 0] = value;
|
|
157
|
-
} else {
|
|
158
|
-
if (value instanceof Struct) {
|
|
159
|
-
value.__internal__.rawName = String(key);
|
|
160
|
-
}
|
|
161
|
-
this[key] = value;
|
|
162
|
-
}
|
|
163
|
-
return this;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
clone() {
|
|
167
|
-
const newInstance = new Struct() as typeof this;
|
|
168
|
-
newInstance.__internal__ = new Refs(this.__internal__);
|
|
169
|
-
this.forEach(([k, v]) => {
|
|
170
|
-
if (v instanceof Struct) {
|
|
171
|
-
newInstance[k] = v.clone();
|
|
172
|
-
} else {
|
|
173
|
-
newInstance[k] = v;
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
return newInstance;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
entries<
|
|
180
|
-
K extends Exclude<keyof this, InternalPlus>,
|
|
181
|
-
V extends (typeof this)[K],
|
|
182
|
-
>() {
|
|
183
|
-
return Object.entries(this).filter(
|
|
184
|
-
([key]) => !INTERNAL_PROPS.has(key as any),
|
|
185
|
-
) as [K, V][];
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
forEach<
|
|
189
|
-
K extends Exclude<keyof this, InternalPlus>,
|
|
190
|
-
V extends (typeof this)[K],
|
|
191
|
-
>(callback: ([key, value]: [K, V], i: number, arr: [K, V][]) => void): void {
|
|
192
|
-
this.entries().forEach(([key, value], i, arr) =>
|
|
193
|
-
callback([key as K, value as V], i, arr as any),
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Filters the struct entries based on a callback function. Returns a copy.
|
|
199
|
-
* @param callback
|
|
200
|
-
*/
|
|
201
|
-
filter<
|
|
202
|
-
K extends Exclude<keyof this, InternalPlus>,
|
|
203
|
-
V extends (typeof this)[K],
|
|
204
|
-
S extends this,
|
|
205
|
-
>(callback: (value: [K, V], index: number, array: [K, V][]) => boolean): S {
|
|
206
|
-
const clone = this.clone();
|
|
207
|
-
clone.entries().forEach((entry, i, arr) => {
|
|
208
|
-
if (!callback(entry as any, i, arr as any)) {
|
|
209
|
-
delete clone[entry[0]];
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
return clone as any;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Maps the struct entries based on a callback function. Returns a copy.
|
|
217
|
-
* @param callback
|
|
218
|
-
*/
|
|
219
|
-
map<K extends Exclude<keyof this, InternalPlus>, V extends (typeof this)[K]>(
|
|
220
|
-
callback: ([key, value]: [K, V], i: number, arr: [K, V][]) => V,
|
|
221
|
-
): this {
|
|
222
|
-
const clone = this.clone();
|
|
223
|
-
clone.entries().forEach(([key, value], i, arr) => {
|
|
224
|
-
clone[key] = callback([key as K, value as V], i, arr as any);
|
|
225
|
-
if (clone[key] === null || clone[key] === undefined) {
|
|
226
|
-
delete clone[key];
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
return clone;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
static fromJson<T>(
|
|
233
|
-
obj: T,
|
|
234
|
-
minified = false,
|
|
235
|
-
): T extends object ? GetStructType<T> : T {
|
|
236
|
-
if (typeof obj === "object" && !!obj) {
|
|
237
|
-
const instance = new Struct();
|
|
238
|
-
Object.entries(obj).forEach(([key, value]) => {
|
|
239
|
-
const nKey = fromMinifiedKey(key, minified);
|
|
240
|
-
|
|
241
|
-
if (nKey === "__internal__") {
|
|
242
|
-
instance[nKey] = new Refs(
|
|
243
|
-
Object.fromEntries(
|
|
244
|
-
Object.entries(value).map(([k, v]) => [
|
|
245
|
-
fromMinifiedKey(k, minified),
|
|
246
|
-
v,
|
|
247
|
-
]),
|
|
248
|
-
),
|
|
249
|
-
);
|
|
250
|
-
} else {
|
|
251
|
-
instance[nKey] = Struct.fromJson(value, minified);
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
return instance as any;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return obj as any;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
toJson<T extends object>(minify = false): T {
|
|
261
|
-
const obj = {};
|
|
262
|
-
|
|
263
|
-
Object.entries(this).forEach(([key, value]) => {
|
|
264
|
-
let nKey = maybeMinifyKey(key, minify);
|
|
265
|
-
if (value instanceof Struct) {
|
|
266
|
-
obj[nKey] = value.toJson(minify);
|
|
267
|
-
} else if (value instanceof Refs) {
|
|
268
|
-
obj[nKey] = Object.fromEntries(
|
|
269
|
-
Object.entries(value).map(([k, v]) => [maybeMinifyKey(k, minify), v]),
|
|
270
|
-
);
|
|
271
|
-
} else {
|
|
272
|
-
obj[nKey] = value;
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
return obj as T;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
toString(): string {
|
|
279
|
-
if (!(this.__internal__ instanceof Refs)) {
|
|
280
|
-
this.__internal__ = new Refs(this.__internal__);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
let text: string = this.__internal__.isRoot
|
|
284
|
-
? `${this.__internal__.rawName} : `
|
|
285
|
-
: "";
|
|
286
|
-
text += "struct.begin";
|
|
287
|
-
|
|
288
|
-
const refs = this.__internal__.toString();
|
|
289
|
-
if (refs) {
|
|
290
|
-
text += ` {${refs}}`;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
text += "\n";
|
|
294
|
-
// Add all keys
|
|
295
|
-
text += this.entries()
|
|
296
|
-
.map(([key, value]) => {
|
|
297
|
-
const nameAlreadyRendered =
|
|
298
|
-
value instanceof Struct && value.__internal__.isRoot;
|
|
299
|
-
const useAsterisk =
|
|
300
|
-
this.__internal__.isArray && this.__internal__.useAsterisk;
|
|
301
|
-
let keyOrIndex = "";
|
|
302
|
-
let equalsOrColon = "";
|
|
303
|
-
let spaceOrNoSpace = "";
|
|
304
|
-
if (!nameAlreadyRendered) {
|
|
305
|
-
keyOrIndex = renderKeyName(key as string, useAsterisk) + " ";
|
|
306
|
-
equalsOrColon = value instanceof Struct ? ":" : "=";
|
|
307
|
-
spaceOrNoSpace = value === "" ? "" : " ";
|
|
308
|
-
}
|
|
309
|
-
const renderedValue =
|
|
310
|
-
value instanceof Struct && value.__internal__.removenode
|
|
311
|
-
? REMOVE_NODE
|
|
312
|
-
: value;
|
|
313
|
-
return pad(
|
|
314
|
-
`${keyOrIndex}${equalsOrColon}${spaceOrNoSpace}${renderedValue}`,
|
|
315
|
-
);
|
|
316
|
-
})
|
|
317
|
-
.join("\n");
|
|
318
|
-
text += "\nstruct.end";
|
|
319
|
-
return text;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
static fromString<IntendedType>(text: string): (IntendedType & Struct)[] {
|
|
323
|
-
return walk(text.trim().split("\n")) as any[];
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
export class Refs implements DefaultEntries {
|
|
328
|
-
rawName?: string;
|
|
329
|
-
refurl?: string;
|
|
330
|
-
refkey?: string | number;
|
|
331
|
-
bskipref?: boolean;
|
|
332
|
-
bpatch?: boolean;
|
|
333
|
-
isArray?: boolean;
|
|
334
|
-
isRoot?: boolean;
|
|
335
|
-
useAsterisk?: boolean;
|
|
336
|
-
removenode?: boolean;
|
|
337
|
-
|
|
338
|
-
constructor(ref?: string | Refs) {
|
|
339
|
-
if (typeof ref === "string") {
|
|
340
|
-
ref
|
|
341
|
-
.split(";")
|
|
342
|
-
.map((ref) => ref.trim())
|
|
343
|
-
.filter(Boolean)
|
|
344
|
-
.reduce((acc, ref) => {
|
|
345
|
-
const [key, value] = ref.split("=");
|
|
346
|
-
if (KEYWORDS.includes(key.trim())) {
|
|
347
|
-
acc[key.trim()] = value ? value.trim() : true;
|
|
348
|
-
}
|
|
349
|
-
return acc;
|
|
350
|
-
}, this);
|
|
351
|
-
}
|
|
352
|
-
if (typeof ref === "object") {
|
|
353
|
-
Object.assign(this, ref);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
toString() {
|
|
358
|
-
return KEYWORDS.map((k) => [k, this[k]])
|
|
359
|
-
.filter(([_, v]) => v !== "" && v !== undefined && v !== false)
|
|
360
|
-
.map(([k, v]) => {
|
|
361
|
-
if (v === true) return k;
|
|
362
|
-
if (k === "refkey") {
|
|
363
|
-
return `${k}=${renderKeyName(`${v}`, this.useAsterisk)}`;
|
|
364
|
-
}
|
|
365
|
-
return `${k}=${v}`;
|
|
366
|
-
})
|
|
367
|
-
.join(";");
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const structHeadRegex = new RegExp(
|
|
372
|
-
`^\\s*((.*)\\s*:)?\\s*struct\\.begin\\s*({\\s*((${KEYWORDS.join("|")})\\s*(=.+)?)\\s*})?`,
|
|
373
|
-
);
|
|
374
|
-
|
|
375
|
-
function parseHead(line: string, index: number): Struct {
|
|
376
|
-
const match = line.match(structHeadRegex);
|
|
377
|
-
if (!match) {
|
|
378
|
-
throw new Error(`Invalid struct head: ${line}`);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const dummy = createDynamicClassInstance(match[2]?.trim() || "", index);
|
|
382
|
-
if (match[3]) {
|
|
383
|
-
const parsed = new Refs(match[4]);
|
|
384
|
-
dummy.__internal__.refurl = parsed.refurl;
|
|
385
|
-
dummy.__internal__.refkey = parsed.refkey;
|
|
386
|
-
dummy.__internal__.bskipref = parsed.bskipref;
|
|
387
|
-
dummy.__internal__.bpatch = parsed.bpatch;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
return dummy as Struct;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
export function pad(text: string): string {
|
|
394
|
-
return `${TAB}${text.replace(/\n+/g, `\n${TAB}`)}`;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function isNumber(ref: string): boolean {
|
|
398
|
-
return Number.isInteger(parseInt(ref)) || typeof ref === "number";
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
export function createDynamicClassInstance<T extends Struct = Struct>(
|
|
402
|
-
rawName: string,
|
|
403
|
-
index?: number,
|
|
404
|
-
): T {
|
|
405
|
-
const parsedName = parseStructName(rawName) || `UnnamedStruct${index}`;
|
|
406
|
-
const name = makeSafeClassName(parsedName);
|
|
407
|
-
return new (new Function(
|
|
408
|
-
"parent",
|
|
409
|
-
"Refs",
|
|
410
|
-
`return class ${name} extends parent {
|
|
411
|
-
__internal__ = new Refs({ rawName: "${rawName.trim()}" });
|
|
412
|
-
}`,
|
|
413
|
-
)(Struct, Refs))() as T;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
function parseKeyValue(line: string, parent: Struct, index: number): void {
|
|
417
|
-
const match = line.match(/^(.*?)(\s*:\s*|\s*=\s*)(.*)$/);
|
|
418
|
-
if (!match) {
|
|
419
|
-
throw new Error(`Invalid key-value pair: ${line}`);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
const key = parseKey(match[1].trim(), parent, index);
|
|
423
|
-
|
|
424
|
-
parent[key] = parseValue(match[3].trim());
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
function walk(lines: string[]) {
|
|
428
|
-
const roots: Struct[] = [];
|
|
429
|
-
const stack = [];
|
|
430
|
-
let index = 0;
|
|
431
|
-
while (index < lines.length) {
|
|
432
|
-
const line = lines[index++].trim();
|
|
433
|
-
if (line.startsWith("#") || line.startsWith("//")) {
|
|
434
|
-
continue; // Skip comments
|
|
435
|
-
}
|
|
436
|
-
const current = stack[stack.length - 1];
|
|
437
|
-
|
|
438
|
-
if (line.includes("struct.begin")) {
|
|
439
|
-
const newStruct = parseHead(line, index);
|
|
440
|
-
if (current) {
|
|
441
|
-
const key = parseKey(
|
|
442
|
-
renderStructName(newStruct.constructor.name),
|
|
443
|
-
current,
|
|
444
|
-
index,
|
|
445
|
-
);
|
|
446
|
-
current[key] = newStruct;
|
|
447
|
-
} else {
|
|
448
|
-
newStruct.__internal__.isRoot = true;
|
|
449
|
-
roots.push(newStruct);
|
|
450
|
-
}
|
|
451
|
-
stack.push(newStruct);
|
|
452
|
-
} else if (line.includes("struct.end")) {
|
|
453
|
-
stack.pop();
|
|
454
|
-
} else if (line.includes("=") && current) {
|
|
455
|
-
parseKeyValue(line, current, index);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
return roots;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
export function parseKey(key: string, parent: Struct, index: number) {
|
|
462
|
-
let normKey: string | number = key;
|
|
463
|
-
|
|
464
|
-
if (key.startsWith("[") && key.endsWith("]")) {
|
|
465
|
-
parent.__internal__.isArray = true;
|
|
466
|
-
normKey = extractKeyFromBrackets(key);
|
|
467
|
-
|
|
468
|
-
if (normKey === "*") {
|
|
469
|
-
parent.__internal__.useAsterisk = true;
|
|
470
|
-
return Object.keys(parent).length - 1;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
if (parent[normKey] !== undefined) {
|
|
474
|
-
return `${normKey}_dupe_${index}`;
|
|
475
|
-
}
|
|
476
|
-
return normKey;
|
|
477
|
-
}
|
|
478
|
-
if (parent[normKey] !== undefined) {
|
|
479
|
-
return `${normKey}_dupe_${index}`;
|
|
480
|
-
}
|
|
481
|
-
return normKey;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
function parseValue(value: string): string | number | boolean {
|
|
485
|
-
if (value === "true" || value === "false") {
|
|
486
|
-
return value === "true";
|
|
487
|
-
}
|
|
488
|
-
try {
|
|
489
|
-
// understand +- 0.1f / 1. / 0.f / .1 / .1f -> ((\d*)\.?(\d+)|(\d+)\.?(\d*))f?
|
|
490
|
-
const matches = value.match(/^(-?)(\d*)\.?(\d*)f?$/);
|
|
491
|
-
const minus = matches[1];
|
|
492
|
-
const first = matches[2];
|
|
493
|
-
const second = matches[3];
|
|
494
|
-
if (first || second) {
|
|
495
|
-
return parseFloat(
|
|
496
|
-
`${minus ? "-" : ""}${first || 0}${second ? `.${second}` : ""}`,
|
|
497
|
-
);
|
|
498
|
-
}
|
|
499
|
-
} catch (e) {}
|
|
500
|
-
return value;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
function renderStructName(name: string): string {
|
|
504
|
-
if (name === WILDCARD) {
|
|
505
|
-
return "[*]"; // Special case for wildcard structs
|
|
506
|
-
}
|
|
507
|
-
if (`${name}`.startsWith("_")) {
|
|
508
|
-
return renderStructName(name.slice(1)); // Special case for indexed structs
|
|
509
|
-
}
|
|
510
|
-
if (isNumber(name)) {
|
|
511
|
-
return `[${parseInt(name)}]`;
|
|
512
|
-
}
|
|
513
|
-
return name;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
function renderKeyName(key: string, useAsterisk?: boolean): string {
|
|
517
|
-
if (`${key}`.startsWith("_")) {
|
|
518
|
-
return renderKeyName(key.slice(1), useAsterisk); // Special case for indexed structs
|
|
519
|
-
}
|
|
520
|
-
if (`${key}`.includes("*") || useAsterisk) {
|
|
521
|
-
return "[*]"; // Special case for wildcard structs
|
|
522
|
-
}
|
|
523
|
-
if (`${key}`.includes("_dupe_")) {
|
|
524
|
-
return renderKeyName(key.slice(0, key.indexOf("_dupe_")));
|
|
525
|
-
}
|
|
526
|
-
if (isNumber(key)) {
|
|
527
|
-
return `[${parseInt(key)}]`;
|
|
528
|
-
}
|
|
529
|
-
return key;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
function extractKeyFromBrackets(key: string) {
|
|
533
|
-
if (/\[(.+)]/.test(key)) {
|
|
534
|
-
return key.match(/\[(.+)]/)[1];
|
|
535
|
-
}
|
|
536
|
-
return "";
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
function parseStructName(name: string): string {
|
|
540
|
-
if (extractKeyFromBrackets(name) === "*") {
|
|
541
|
-
return WILDCARD; // Special case for wildcard structs
|
|
542
|
-
}
|
|
543
|
-
if (isNumber(extractKeyFromBrackets(name))) {
|
|
544
|
-
return `_${name.match(/\[(\d+)]/)[1]}`; // Special case for indexed structs
|
|
545
|
-
}
|
|
546
|
-
return name
|
|
547
|
-
.replace(/\W/g, "_")
|
|
548
|
-
.replace(/^\d+/, "_")
|
|
549
|
-
.replace(/_+/g, "_")
|
|
550
|
-
.replace(/^_+/, "");
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
const RESERVED_IDENTIFIERS = new Set([
|
|
554
|
-
"break",
|
|
555
|
-
"case",
|
|
556
|
-
"catch",
|
|
557
|
-
"class",
|
|
558
|
-
"const",
|
|
559
|
-
"continue",
|
|
560
|
-
"debugger",
|
|
561
|
-
"default",
|
|
562
|
-
"delete",
|
|
563
|
-
"do",
|
|
564
|
-
"else",
|
|
565
|
-
"export",
|
|
566
|
-
"extends",
|
|
567
|
-
"finally",
|
|
568
|
-
"for",
|
|
569
|
-
"function",
|
|
570
|
-
"if",
|
|
571
|
-
"import",
|
|
572
|
-
"in",
|
|
573
|
-
"instanceof",
|
|
574
|
-
"new",
|
|
575
|
-
"return",
|
|
576
|
-
"super",
|
|
577
|
-
"switch",
|
|
578
|
-
"this",
|
|
579
|
-
"throw",
|
|
580
|
-
"try",
|
|
581
|
-
"typeof",
|
|
582
|
-
"var",
|
|
583
|
-
"void",
|
|
584
|
-
"while",
|
|
585
|
-
"with",
|
|
586
|
-
"yield",
|
|
587
|
-
"enum",
|
|
588
|
-
"await",
|
|
589
|
-
"implements",
|
|
590
|
-
"package",
|
|
591
|
-
"protected",
|
|
592
|
-
"static",
|
|
593
|
-
"interface",
|
|
594
|
-
"private",
|
|
595
|
-
"public",
|
|
596
|
-
"let",
|
|
597
|
-
]);
|
|
598
|
-
|
|
599
|
-
function makeSafeClassName(name: string): string {
|
|
600
|
-
if (
|
|
601
|
-
!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ||
|
|
602
|
-
RESERVED_IDENTIFIERS.has(name)
|
|
603
|
-
) {
|
|
604
|
-
return `_${name}`;
|
|
605
|
-
}
|
|
606
|
-
return name;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
function maybeMinifyKey(key: string, minify: boolean) {
|
|
610
|
-
return minify &&
|
|
611
|
-
(INTERNAL_PROPS.has(key as any) || REF_INTERNAL_PROPS.has(key as any))
|
|
612
|
-
? INTERNAL_PROPS.get(key as any) || REF_INTERNAL_PROPS.get(key as any)
|
|
613
|
-
: key;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
function fromMinifiedKey(key: string, minified: boolean) {
|
|
617
|
-
if (!minified) return key;
|
|
618
|
-
return (
|
|
619
|
-
INTERNAL_PROPS_INV.get(key as any) ||
|
|
620
|
-
REF_INTERNAL_PROPS_INV.get(key as any) ||
|
|
621
|
-
key
|
|
622
|
-
);
|
|
623
|
-
}
|