UNPKG

3.53 kBPlain TextView Raw
1import { GameSetting } from "@xmcl/common";
2
3declare module "@xmcl/common/gamesetting" {
4 namespace GameSetting {
5 /**
6 * Parse raw game setting options.txt content
7 *
8 * @param str the options.txt content
9 * @param strict strictly follow the current version of options format (outdate version might cause problem. If your options.txt is new one with new fields, don't turn on this)
10 */
11 export function parse<T extends boolean>(str: string, strict?: T): T extends true ? GameSetting : GameSetting.Frame;
12
13 /**
14 * Generate text format game setting for options.txt file.
15 *
16 * @param setting The game setting object
17 * @param original
18 * @param eol The end of line character, default is `\n`
19 */
20 export function stringify(setting: GameSetting | GameSetting.Frame | any, original?: string, eol?: string): string;
21 }
22}
23
24
25GameSetting.parse = parse as <T extends boolean>(str: string, strict?: T) => T extends true ? GameSetting : GameSetting.Frame;
26GameSetting.stringify = stringify;
27
28/**
29 * Parse raw game setting options.txt content
30 *
31 * @param str the options.txt content
32 * @param strict strictly follow the current version of options format (outdate version might cause problem. If your options.txt is new one with new fields, don't turn on this)
33 */
34function parse(str: string, strict?: boolean): GameSetting | GameSetting.Frame {
35 const lines = str.split("\n");
36 const intPattern = /^\d+$/;
37 const floatPattern = /^[-+]?[0-9]*\.[0-9]+$/;
38 const booleanPattern = /^(true)|(false)$/;
39 if (!lines || lines.length === 0) {
40 return strict ? GameSetting.getDefaultFrame() : {};
41 }
42 const setting = lines.map((line) => line.trim().split(":"))
43 .filter((pair) => pair[0].length !== 0)
44 .map((pair) => {
45 let value: any = pair[1];
46 if (intPattern.test(value)) {
47 value = Number.parseInt(value, 10);
48 } else if (floatPattern.test(value)) {
49 value = Number.parseFloat(value);
50 } else if (booleanPattern.test(value)) {
51 value = value === "true";
52 } else {
53 try {
54 value = JSON.parse(value);
55 } catch (e) { }
56 }
57
58 return { [pair[0]]: value };
59 })
60 .reduce((prev, current) => Object.assign(prev, current), {});
61 if (!strict) { return setting as GameSetting.Frame; }
62 const source: any = GameSetting.getDefaultFrame();
63 const target: any = {};
64 Object.keys(source).forEach((key) => {
65 target[key] = typeof setting[key] === typeof source[key] ? setting[key] : source[key];
66 delete setting.key;
67 });
68 return target as GameSetting;
69}
70
71function stringify(setting: GameSetting | GameSetting.Frame | any, original?: string, eol: string = "\n"): string {
72 let model: any;
73 if (original) {
74 model = parse(original) as any;
75 for (const key in model) {
76 if (model.hasOwnProperty(key) && setting.hasOwnProperty(key)) {
77 model[key] = setting[key];
78 }
79 }
80 } else { model = setting; }
81 return Object.keys(model)
82 .filter((key) => key !== undefined && key !== "undefined")
83 .map((key) => {
84 const val = model[key];
85 return typeof val !== "string" ? `${key}:${JSON.stringify(val)}` : `${key}:${val}`;
86 }).join(eol);
87}
88
89export * from "@xmcl/common/gamesetting";