webgal-parser 4.4.15 → 4.5.13

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.
@@ -36,52 +36,62 @@ var webgalParser = (function (exports) {
36
36
  commandType[commandType["setTransition"] = 30] = "setTransition";
37
37
  commandType[commandType["getUserInput"] = 31] = "getUserInput";
38
38
  commandType[commandType["applyStyle"] = 32] = "applyStyle";
39
+ commandType[commandType["wait"] = 33] = "wait";
39
40
  })(commandType || (commandType = {}));
40
41
 
41
42
  const SCRIPT_CONFIG = [
42
- { scriptString: 'intro', scriptType: commandType.intro },
43
+ { scriptString: 'say', scriptType: commandType.say },
43
44
  { scriptString: 'changeBg', scriptType: commandType.changeBg },
44
45
  { scriptString: 'changeFigure', scriptType: commandType.changeFigure },
46
+ { scriptString: 'bgm', scriptType: commandType.bgm },
47
+ { scriptString: 'playVideo', scriptType: commandType.video },
48
+ { scriptString: 'pixiPerform', scriptType: commandType.pixi },
49
+ { scriptString: 'pixiInit', scriptType: commandType.pixiInit },
50
+ { scriptString: 'intro', scriptType: commandType.intro },
45
51
  { scriptString: 'miniAvatar', scriptType: commandType.miniAvatar },
46
52
  { scriptString: 'changeScene', scriptType: commandType.changeScene },
47
53
  { scriptString: 'choose', scriptType: commandType.choose },
48
54
  { scriptString: 'end', scriptType: commandType.end },
49
- { scriptString: 'bgm', scriptType: commandType.bgm },
50
- { scriptString: 'playVideo', scriptType: commandType.video },
51
55
  {
52
56
  scriptString: 'setComplexAnimation',
53
57
  scriptType: commandType.setComplexAnimation,
54
58
  },
55
59
  { scriptString: 'setFilter', scriptType: commandType.setFilter },
56
- { scriptString: 'pixiInit', scriptType: commandType.pixiInit },
57
- { scriptString: 'pixiPerform', scriptType: commandType.pixi },
58
60
  { scriptString: 'label', scriptType: commandType.label },
59
61
  { scriptString: 'jumpLabel', scriptType: commandType.jumpLabel },
62
+ { scriptString: 'chooseLabel', scriptType: commandType.chooseLabel },
60
63
  { scriptString: 'setVar', scriptType: commandType.setVar },
64
+ { scriptString: 'if', scriptType: commandType.if },
61
65
  { scriptString: 'callScene', scriptType: commandType.callScene },
62
66
  { scriptString: 'showVars', scriptType: commandType.showVars },
63
67
  { scriptString: 'unlockCg', scriptType: commandType.unlockCg },
64
68
  { scriptString: 'unlockBgm', scriptType: commandType.unlockBgm },
65
- { scriptString: 'say', scriptType: commandType.say },
66
69
  { scriptString: 'filmMode', scriptType: commandType.filmMode },
67
- { scriptString: 'callScene', scriptType: commandType.callScene },
68
70
  { scriptString: 'setTextbox', scriptType: commandType.setTextbox },
69
71
  { scriptString: 'setAnimation', scriptType: commandType.setAnimation },
70
72
  { scriptString: 'playEffect', scriptType: commandType.playEffect },
73
+ { scriptString: 'setTempAnimation', scriptType: commandType.setTempAnimation },
74
+ // comment?
75
+ { scriptString: 'setTransform', scriptType: commandType.setTransform },
76
+ { scriptString: 'setTransition', scriptType: commandType.setTransition },
77
+ { scriptString: 'getUserInput', scriptType: commandType.getUserInput },
71
78
  { scriptString: 'applyStyle', scriptType: commandType.applyStyle },
79
+ { scriptString: 'wait', scriptType: commandType.wait },
72
80
  ];
73
81
  const ADD_NEXT_ARG_LIST = [
74
82
  commandType.bgm,
75
83
  commandType.pixi,
76
84
  commandType.pixiInit,
85
+ commandType.miniAvatar,
77
86
  commandType.label,
78
87
  commandType.if,
79
- commandType.miniAvatar,
80
88
  commandType.setVar,
81
- commandType.unlockBgm,
82
89
  commandType.unlockCg,
90
+ commandType.unlockBgm,
83
91
  commandType.filmMode,
84
92
  commandType.playEffect,
93
+ commandType.setTransition,
94
+ commandType.applyStyle,
85
95
  ];
86
96
 
87
97
  /**
@@ -181,7 +191,7 @@ var webgalParser = (function (exports) {
181
191
  };
182
192
  }
183
193
  // 截取命令
184
- const getCommandResult = /:/.exec(newSentenceRaw);
194
+ const getCommandResult = /\s*:\s*/.exec(newSentenceRaw);
185
195
  // 没有command
186
196
  if (getCommandResult === null) {
187
197
  command = '';
@@ -303,12 +313,12 @@ var webgalParser = (function (exports) {
303
313
  }
304
314
  };
305
315
  function getChooseContent(contentRaw, assetSetter) {
306
- const chooseList = contentRaw.split('|');
316
+ const chooseList = contentRaw.split(/(?<!\\)\|/);
307
317
  const chooseKeyList = [];
308
318
  const chooseValueList = [];
309
319
  for (const e of chooseList) {
310
- chooseKeyList.push(e.split(':')[0] ?? '');
311
- chooseValueList.push(e.split(':')[1] ?? '');
320
+ chooseKeyList.push(e.split(/(?<!\\):/)[0] ?? '');
321
+ chooseValueList.push(e.split(/(?<!\\):/)[1] ?? '');
312
322
  }
313
323
  const parsedChooseList = chooseValueList.map((e) => {
314
324
  if (e.match(/\./)) {
@@ -435,8 +445,9 @@ var webgalParser = (function (exports) {
435
445
  let parsedCommand; // 解析后的命令
436
446
  let commandRaw;
437
447
  // 正式开始解析
438
- // 去分号,前面已做,这里不再需要
439
- let newSentenceRaw = sentenceRaw.split(';')[0];
448
+ // 去分号
449
+ let newSentenceRaw = sentenceRaw.split(/(?<!\\);/)[0];
450
+ newSentenceRaw = newSentenceRaw.replaceAll('\\;', ';');
440
451
  if (newSentenceRaw === '') {
441
452
  // 注释提前返回
442
453
  return {
@@ -486,12 +497,12 @@ var webgalParser = (function (exports) {
486
497
  args.push(e);
487
498
  }
488
499
  }
489
- content = contentParser(newSentenceRaw, command, assetSetter); // 将语句内容里的文件名转为相对或绝对路径
500
+ content = contentParser(newSentenceRaw.trim(), command, assetSetter); // 将语句内容里的文件名转为相对或绝对路径
490
501
  sentenceAssets = assetsScanner(command, content, args); // 扫描语句携带资源
491
502
  subScene = subSceneScanner(command, content); // 扫描语句携带子场景
492
503
  return {
493
504
  command: command,
494
- commandRaw: commandRaw,
505
+ commandRaw: commandRaw.trim(),
495
506
  content: content,
496
507
  args: args,
497
508
  sentenceAssets: sentenceAssets,
@@ -1815,6 +1826,198 @@ var webgalParser = (function (exports) {
1815
1826
  return [result, specialRules.trim()];
1816
1827
  }
1817
1828
 
1829
+ /**
1830
+ * Preprocessor for scene text.
1831
+ *
1832
+ * Use two-pass to generate a new scene text that concats multiline sequences
1833
+ * into a single line and add placeholder lines to preserve the original number
1834
+ * of lines.
1835
+ *
1836
+ * @param sceneText The original scene text
1837
+ * @returns The processed scene text
1838
+ */
1839
+ function sceneTextPreProcess(sceneText) {
1840
+ let lines = sceneText.replaceAll('\r', '').split('\n');
1841
+ lines = sceneTextPreProcessPassOne(lines);
1842
+ lines = sceneTextPreProcessPassTwo(lines);
1843
+ return lines.join('\n');
1844
+ }
1845
+ /**
1846
+ * Pass one.
1847
+ *
1848
+ * Add escape character to all lines that should be multiline.
1849
+ *
1850
+ * @param lines The original lines
1851
+ * @returns The processed lines
1852
+ */
1853
+ function sceneTextPreProcessPassOne(lines) {
1854
+ const processedLines = [];
1855
+ let lastLineIsMultiline = false;
1856
+ let thisLineIsMultiline = false;
1857
+ for (const line of lines) {
1858
+ thisLineIsMultiline = false;
1859
+ if (canBeMultiline(line)) {
1860
+ thisLineIsMultiline = true;
1861
+ }
1862
+ if (shouldNotBeMultiline(line, lastLineIsMultiline)) {
1863
+ thisLineIsMultiline = false;
1864
+ }
1865
+ if (thisLineIsMultiline) {
1866
+ processedLines[processedLines.length - 1] += '\\';
1867
+ }
1868
+ processedLines.push(line);
1869
+ lastLineIsMultiline = thisLineIsMultiline;
1870
+ }
1871
+ return processedLines;
1872
+ }
1873
+ function canBeMultiline(line) {
1874
+ if (!line.startsWith(' ')) {
1875
+ return false;
1876
+ }
1877
+ const trimmedLine = line.trimStart();
1878
+ return trimmedLine.startsWith('|') || trimmedLine.startsWith('-');
1879
+ }
1880
+ /**
1881
+ * Logic to check if a line should not be multiline.
1882
+ *
1883
+ * @param line The line to check
1884
+ * @returns If the line should not be multiline
1885
+ */
1886
+ function shouldNotBeMultiline(line, lastLineIsMultiline) {
1887
+ if (!lastLineIsMultiline && isEmptyLine(line)) {
1888
+ return true;
1889
+ }
1890
+ // Custom logic: if the line contains -concat, it should not be multiline
1891
+ if (line.indexOf('-concat') !== -1) {
1892
+ return true;
1893
+ }
1894
+ return false;
1895
+ }
1896
+ function isEmptyLine(line) {
1897
+ return line.trim() === '';
1898
+ }
1899
+ /**
1900
+ * Pass two.
1901
+ *
1902
+ * Traverse the lines to
1903
+ * - remove escape characters
1904
+ * - add placeholder lines to preserve the original number of lines.
1905
+ *
1906
+ * @param lines The lines in pass one
1907
+ * @returns The processed lines
1908
+ */
1909
+ function sceneTextPreProcessPassTwo(lines) {
1910
+ const processedLines = [];
1911
+ let currentMultilineContent = "";
1912
+ let placeHolderLines = [];
1913
+ function concat(line) {
1914
+ let trimmed = line.trim();
1915
+ if (trimmed.startsWith('-')) {
1916
+ trimmed = " " + trimmed;
1917
+ }
1918
+ currentMultilineContent = currentMultilineContent + trimmed;
1919
+ placeHolderLines.push(placeholderLine(line));
1920
+ }
1921
+ for (const line of lines) {
1922
+ console.log(line);
1923
+ if (line.endsWith('\\')) {
1924
+ const trueLine = line.slice(0, -1);
1925
+ if (currentMultilineContent === "") {
1926
+ // first line
1927
+ currentMultilineContent = trueLine;
1928
+ }
1929
+ else {
1930
+ // middle line
1931
+ concat(trueLine);
1932
+ }
1933
+ continue;
1934
+ }
1935
+ if (currentMultilineContent !== "") {
1936
+ // end line
1937
+ concat(line);
1938
+ processedLines.push(currentMultilineContent);
1939
+ processedLines.push(...placeHolderLines);
1940
+ placeHolderLines = [];
1941
+ currentMultilineContent = "";
1942
+ continue;
1943
+ }
1944
+ processedLines.push(line);
1945
+ }
1946
+ return processedLines;
1947
+ }
1948
+ /**
1949
+ * Placeholder Line. Adding this line preserves the original number of lines
1950
+ * in the scene text, so that it can be compatible with the graphical editor.
1951
+ *
1952
+ * @param content The original content on this line
1953
+ * @returns The placeholder line
1954
+ */
1955
+ function placeholderLine(content = "") {
1956
+ return ";_WEBGAL_LINE_BREAK_" + content;
1957
+ }
1958
+ // export function sceneTextPreProcess(sceneText: string): string {
1959
+ // const lines = sceneText.replaceAll('\r', '').split('\n');
1960
+ // const processedLines: string[] = [];
1961
+ // let lastNonMultilineIndex = -1;
1962
+ // let isInMultilineSequence = false;
1963
+ // function isMultiline(line: string): boolean {
1964
+ // if (!line.startsWith(' ')) return false;
1965
+ // const trimmedLine = line.trimStart();
1966
+ // return trimmedLine.startsWith('|') || trimmedLine.startsWith('-');
1967
+ // }
1968
+ // for (let i = 0; i < lines.length; i++) {
1969
+ // const line = lines[i];
1970
+ // if (line.trim() === '') {
1971
+ // // Empty line handling
1972
+ // if (isInMultilineSequence) {
1973
+ // // Check if the next line is a multiline line
1974
+ // let isStillInMulti = false;
1975
+ // for (let j = i + 1; j < lines.length; j++) {
1976
+ // const lookForwardLine = lines[j] || '';
1977
+ // // 遇到正常语句了,直接中断
1978
+ // if (lookForwardLine.trim() !== '' && !isMultiline(lookForwardLine)) {
1979
+ // isStillInMulti = false;
1980
+ // break;
1981
+ // }
1982
+ // // 必须找到后面接的是参数,并且中间没有遇到任何正常语句才行
1983
+ // if (lookForwardLine.trim() !== '' && isMultiline(lookForwardLine)) {
1984
+ // isStillInMulti = true;
1985
+ // break;
1986
+ // }
1987
+ // }
1988
+ // if (isStillInMulti) {
1989
+ // // Still within a multiline sequence
1990
+ // processedLines.push(';_WEBGAL_LINE_BREAK_');
1991
+ // } else {
1992
+ // // End of multiline sequence
1993
+ // isInMultilineSequence = false;
1994
+ // processedLines.push(line);
1995
+ // }
1996
+ // } else {
1997
+ // // Preserve empty lines outside of multiline sequences
1998
+ // processedLines.push(line);
1999
+ // }
2000
+ // } else if (isMultiline(line)) {
2001
+ // // Multiline statement handling
2002
+ // if (lastNonMultilineIndex >= 0) {
2003
+ // // Concatenate to the previous non-multiline statement
2004
+ // const trimedLine = line.trimStart();
2005
+ // const addBlank = trimedLine.startsWith('-') ? ' ' : '';
2006
+ // processedLines[lastNonMultilineIndex] += addBlank + trimedLine;
2007
+ // }
2008
+ // // Add the special comment line
2009
+ // processedLines.push(';_WEBGAL_LINE_BREAK_' + line);
2010
+ // isInMultilineSequence = true;
2011
+ // } else {
2012
+ // // Non-multiline statement handling
2013
+ // processedLines.push(line);
2014
+ // lastNonMultilineIndex = processedLines.length - 1;
2015
+ // isInMultilineSequence = false;
2016
+ // }
2017
+ // }
2018
+ // return processedLines.join('\n');
2019
+ // }
2020
+
1818
2021
  class SceneParser {
1819
2022
  assetsPrefetcher;
1820
2023
  assetSetter;
@@ -1861,6 +2064,7 @@ var webgalParser = (function (exports) {
1861
2064
  exports.ADD_NEXT_ARG_LIST = ADD_NEXT_ARG_LIST;
1862
2065
  exports.SCRIPT_CONFIG = SCRIPT_CONFIG;
1863
2066
  exports.default = SceneParser;
2067
+ exports.sceneTextPreProcess = sceneTextPreProcess;
1864
2068
 
1865
2069
  Object.defineProperty(exports, '__esModule', { value: true });
1866
2070
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webgal-parser",
3
- "version": "4.4.15",
3
+ "version": "4.5.13",
4
4
  "description": "WebGAL script parser",
5
5
  "scripts": {
6
6
  "test": "vitest",
@@ -8,7 +8,8 @@
8
8
  "build": "rimraf -rf ./build && rollup --config",
9
9
  "build-ci": "rollup --config",
10
10
  "debug": "tsx test/debug.ts",
11
- "debug-scss-parser": "tsx test/debugCssParser.ts"
11
+ "debug-scss-parser": "tsx test/debugCssParser.ts",
12
+ "debug-linebreak-parser": "tsx test/debug-linebreak.ts"
12
13
  },
13
14
  "types": "./build/types/index.d.ts",
14
15
  "module": "./build/es/index.js",
@@ -29,7 +30,7 @@
29
30
  "@types/lodash": "^4.14.189",
30
31
  "@types/node": "^18.14.0",
31
32
  "@vitest/coverage-c8": "^0.28.5",
32
- "rollup": "^3.3.0",
33
+ "rollup": "^3.29.5",
33
34
  "rollup-plugin-babel": "^4.4.0",
34
35
  "rollup-plugin-terser": "^7.0.2",
35
36
  "rollup-plugin-typescript2": "^0.34.1",
@@ -1,49 +1,58 @@
1
1
  import {commandType} from '../interface/sceneInterface';
2
2
 
3
3
  export const SCRIPT_CONFIG = [
4
- { scriptString: 'intro', scriptType: commandType.intro },
4
+ { scriptString: 'say', scriptType: commandType.say },
5
5
  { scriptString: 'changeBg', scriptType: commandType.changeBg },
6
6
  { scriptString: 'changeFigure', scriptType: commandType.changeFigure },
7
+ { scriptString: 'bgm', scriptType: commandType.bgm },
8
+ { scriptString: 'playVideo', scriptType: commandType.video },
9
+ { scriptString: 'pixiPerform', scriptType: commandType.pixi },
10
+ { scriptString: 'pixiInit', scriptType: commandType.pixiInit },
11
+ { scriptString: 'intro', scriptType: commandType.intro },
7
12
  { scriptString: 'miniAvatar', scriptType: commandType.miniAvatar },
8
13
  { scriptString: 'changeScene', scriptType: commandType.changeScene },
9
14
  { scriptString: 'choose', scriptType: commandType.choose },
10
15
  { scriptString: 'end', scriptType: commandType.end },
11
- { scriptString: 'bgm', scriptType: commandType.bgm },
12
- { scriptString: 'playVideo', scriptType: commandType.video },
13
16
  {
14
17
  scriptString: 'setComplexAnimation',
15
18
  scriptType: commandType.setComplexAnimation,
16
19
  },
17
20
  { scriptString: 'setFilter', scriptType: commandType.setFilter },
18
- { scriptString: 'pixiInit', scriptType: commandType.pixiInit },
19
- { scriptString: 'pixiPerform', scriptType: commandType.pixi },
20
21
  { scriptString: 'label', scriptType: commandType.label },
21
22
  { scriptString: 'jumpLabel', scriptType: commandType.jumpLabel },
23
+ { scriptString: 'chooseLabel', scriptType: commandType.chooseLabel },
22
24
  { scriptString: 'setVar', scriptType: commandType.setVar },
25
+ { scriptString: 'if', scriptType: commandType.if },
23
26
  { scriptString: 'callScene', scriptType: commandType.callScene },
24
27
  { scriptString: 'showVars', scriptType: commandType.showVars },
25
28
  { scriptString: 'unlockCg', scriptType: commandType.unlockCg },
26
29
  { scriptString: 'unlockBgm', scriptType: commandType.unlockBgm },
27
- { scriptString: 'say', scriptType: commandType.say },
28
30
  { scriptString: 'filmMode', scriptType: commandType.filmMode },
29
- { scriptString: 'callScene', scriptType: commandType.callScene },
30
31
  { scriptString: 'setTextbox', scriptType: commandType.setTextbox },
31
32
  { scriptString: 'setAnimation', scriptType: commandType.setAnimation },
32
33
  { scriptString: 'playEffect', scriptType: commandType.playEffect },
34
+ { scriptString: 'setTempAnimation', scriptType: commandType.setTempAnimation },
35
+ // comment?
36
+ { scriptString: 'setTransform', scriptType: commandType.setTransform },
37
+ { scriptString: 'setTransition', scriptType: commandType.setTransition },
38
+ { scriptString: 'getUserInput', scriptType: commandType.getUserInput },
33
39
  { scriptString: 'applyStyle', scriptType: commandType.applyStyle },
40
+ { scriptString: 'wait', scriptType: commandType.wait },
34
41
  ];
35
42
  export const ADD_NEXT_ARG_LIST = [
36
43
  commandType.bgm,
37
44
  commandType.pixi,
38
45
  commandType.pixiInit,
46
+ commandType.miniAvatar,
39
47
  commandType.label,
40
48
  commandType.if,
41
- commandType.miniAvatar,
42
49
  commandType.setVar,
43
- commandType.unlockBgm,
44
50
  commandType.unlockCg,
51
+ commandType.unlockBgm,
45
52
  commandType.filmMode,
46
53
  commandType.playEffect,
54
+ commandType.setTransition,
55
+ commandType.applyStyle,
47
56
  ];
48
57
 
49
58
  export type ConfigMap = Map<string, ConfigItem>;
@@ -26,7 +26,7 @@ function configLineParser(inputLine: string): IConfigItem {
26
26
  };
27
27
  }
28
28
  // 截取命令
29
- const getCommandResult = /:/.exec(newSentenceRaw);
29
+ const getCommandResult = /\s*:\s*/.exec(newSentenceRaw);
30
30
 
31
31
  // 没有command
32
32
  if (getCommandResult === null) {
package/src/index.ts CHANGED
@@ -8,7 +8,8 @@ import { configParser, WebgalConfig } from './configParser/configParser';
8
8
  import { fileType } from './interface/assets';
9
9
  import { IAsset } from './interface/sceneInterface';
10
10
  import { sceneParser } from './sceneParser';
11
- import {IWebGALStyleObj, scss2cssinjsParser} from "./styleParser";
11
+ import { IWebGALStyleObj, scss2cssinjsParser } from "./styleParser";
12
+ import { sceneTextPreProcess } from "./sceneTextPreProcessor";
12
13
 
13
14
  export default class SceneParser {
14
15
  private readonly SCRIPT_CONFIG_MAP: ConfigMap;
@@ -76,3 +77,4 @@ export default class SceneParser {
76
77
  }
77
78
 
78
79
  export { ADD_NEXT_ARG_LIST, SCRIPT_CONFIG };
80
+ export { sceneTextPreProcess };
@@ -37,7 +37,8 @@ export enum commandType {
37
37
  setTransform,
38
38
  setTransition,
39
39
  getUserInput,
40
- applyStyle
40
+ applyStyle,
41
+ wait
41
42
  }
42
43
 
43
44
  /**
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Preprocessor for scene text.
3
+ *
4
+ * Use two-pass to generate a new scene text that concats multiline sequences
5
+ * into a single line and add placeholder lines to preserve the original number
6
+ * of lines.
7
+ *
8
+ * @param sceneText The original scene text
9
+ * @returns The processed scene text
10
+ */
11
+ export function sceneTextPreProcess(sceneText: string): string {
12
+ let lines = sceneText.replaceAll('\r', '').split('\n');
13
+
14
+ lines = sceneTextPreProcessPassOne(lines);
15
+ lines = sceneTextPreProcessPassTwo(lines);
16
+
17
+ return lines.join('\n');
18
+ }
19
+
20
+ /**
21
+ * Pass one.
22
+ *
23
+ * Add escape character to all lines that should be multiline.
24
+ *
25
+ * @param lines The original lines
26
+ * @returns The processed lines
27
+ */
28
+ function sceneTextPreProcessPassOne(lines: string[]): string[] {
29
+ const processedLines: string[] = [];
30
+ let lastLineIsMultiline = false;
31
+ let thisLineIsMultiline = false;
32
+
33
+ for (const line of lines) {
34
+ thisLineIsMultiline = false;
35
+
36
+ if (canBeMultiline(line)) {
37
+ thisLineIsMultiline = true;
38
+ }
39
+
40
+ if (shouldNotBeMultiline(line, lastLineIsMultiline)) {
41
+ thisLineIsMultiline = false;
42
+ }
43
+
44
+ if (thisLineIsMultiline) {
45
+ processedLines[processedLines.length - 1] += '\\';
46
+ }
47
+
48
+ processedLines.push(line);
49
+
50
+ lastLineIsMultiline = thisLineIsMultiline;
51
+ }
52
+
53
+ return processedLines;
54
+ }
55
+
56
+ function canBeMultiline(line: string): boolean {
57
+ if (!line.startsWith(' ')) {
58
+ return false;
59
+ }
60
+
61
+ const trimmedLine = line.trimStart();
62
+ return trimmedLine.startsWith('|') || trimmedLine.startsWith('-');
63
+ }
64
+
65
+ /**
66
+ * Logic to check if a line should not be multiline.
67
+ *
68
+ * @param line The line to check
69
+ * @returns If the line should not be multiline
70
+ */
71
+ function shouldNotBeMultiline(line: string, lastLineIsMultiline: boolean): boolean {
72
+ if (!lastLineIsMultiline && isEmptyLine(line)) {
73
+ return true;
74
+ }
75
+
76
+ // Custom logic: if the line contains -concat, it should not be multiline
77
+ if (line.indexOf('-concat') !== -1) {
78
+ return true;
79
+ }
80
+
81
+ return false;
82
+ }
83
+
84
+ function isEmptyLine(line: string): boolean {
85
+ return line.trim() === '';
86
+ }
87
+
88
+
89
+ /**
90
+ * Pass two.
91
+ *
92
+ * Traverse the lines to
93
+ * - remove escape characters
94
+ * - add placeholder lines to preserve the original number of lines.
95
+ *
96
+ * @param lines The lines in pass one
97
+ * @returns The processed lines
98
+ */
99
+ function sceneTextPreProcessPassTwo(lines: string[]): string[] {
100
+ const processedLines: string[] = [];
101
+ let currentMultilineContent = "";
102
+ let placeHolderLines: string[] = [];
103
+
104
+ function concat(line: string) {
105
+ let trimmed = line.trim();
106
+ if (trimmed.startsWith('-')) {
107
+ trimmed = " " + trimmed;
108
+ }
109
+ currentMultilineContent = currentMultilineContent + trimmed;
110
+ placeHolderLines.push(placeholderLine(line));
111
+ }
112
+
113
+ for (const line of lines) {
114
+ console.log(line);
115
+ if (line.endsWith('\\')) {
116
+ const trueLine = line.slice(0, -1);
117
+
118
+ if (currentMultilineContent === "") {
119
+ // first line
120
+ currentMultilineContent = trueLine;
121
+ } else {
122
+ // middle line
123
+ concat(trueLine);
124
+ }
125
+ continue;
126
+ }
127
+
128
+ if (currentMultilineContent !== "") {
129
+ // end line
130
+ concat(line);
131
+ processedLines.push(currentMultilineContent);
132
+ processedLines.push(...placeHolderLines);
133
+
134
+ placeHolderLines = [];
135
+ currentMultilineContent = "";
136
+ continue;
137
+ }
138
+
139
+ processedLines.push(line);
140
+ }
141
+
142
+ return processedLines;
143
+ }
144
+
145
+ /**
146
+ * Placeholder Line. Adding this line preserves the original number of lines
147
+ * in the scene text, so that it can be compatible with the graphical editor.
148
+ *
149
+ * @param content The original content on this line
150
+ * @returns The placeholder line
151
+ */
152
+ function placeholderLine(content = "") {
153
+ return ";_WEBGAL_LINE_BREAK_" + content;
154
+ }
155
+
156
+ // export function sceneTextPreProcess(sceneText: string): string {
157
+ // const lines = sceneText.replaceAll('\r', '').split('\n');
158
+ // const processedLines: string[] = [];
159
+ // let lastNonMultilineIndex = -1;
160
+ // let isInMultilineSequence = false;
161
+
162
+ // function isMultiline(line: string): boolean {
163
+ // if (!line.startsWith(' ')) return false;
164
+ // const trimmedLine = line.trimStart();
165
+ // return trimmedLine.startsWith('|') || trimmedLine.startsWith('-');
166
+ // }
167
+
168
+ // for (let i = 0; i < lines.length; i++) {
169
+ // const line = lines[i];
170
+
171
+ // if (line.trim() === '') {
172
+ // // Empty line handling
173
+ // if (isInMultilineSequence) {
174
+ // // Check if the next line is a multiline line
175
+
176
+ // let isStillInMulti = false;
177
+ // for (let j = i + 1; j < lines.length; j++) {
178
+ // const lookForwardLine = lines[j] || '';
179
+ // // 遇到正常语句了,直接中断
180
+ // if (lookForwardLine.trim() !== '' && !isMultiline(lookForwardLine)) {
181
+ // isStillInMulti = false;
182
+ // break;
183
+ // }
184
+ // // 必须找到后面接的是参数,并且中间没有遇到任何正常语句才行
185
+ // if (lookForwardLine.trim() !== '' && isMultiline(lookForwardLine)) {
186
+ // isStillInMulti = true;
187
+ // break;
188
+ // }
189
+ // }
190
+ // if (isStillInMulti) {
191
+ // // Still within a multiline sequence
192
+ // processedLines.push(';_WEBGAL_LINE_BREAK_');
193
+ // } else {
194
+ // // End of multiline sequence
195
+ // isInMultilineSequence = false;
196
+ // processedLines.push(line);
197
+ // }
198
+ // } else {
199
+ // // Preserve empty lines outside of multiline sequences
200
+ // processedLines.push(line);
201
+ // }
202
+ // } else if (isMultiline(line)) {
203
+ // // Multiline statement handling
204
+ // if (lastNonMultilineIndex >= 0) {
205
+ // // Concatenate to the previous non-multiline statement
206
+ // const trimedLine = line.trimStart();
207
+ // const addBlank = trimedLine.startsWith('-') ? ' ' : '';
208
+ // processedLines[lastNonMultilineIndex] += addBlank + trimedLine;
209
+ // }
210
+
211
+ // // Add the special comment line
212
+ // processedLines.push(';_WEBGAL_LINE_BREAK_' + line);
213
+ // isInMultilineSequence = true;
214
+ // } else {
215
+ // // Non-multiline statement handling
216
+ // processedLines.push(line);
217
+ // lastNonMultilineIndex = processedLines.length - 1;
218
+ // isInMultilineSequence = false;
219
+ // }
220
+ // }
221
+
222
+ // return processedLines.join('\n');
223
+ // }