webgal-parser 4.6.1 → 4.6.3-beta.1
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/CHANGELOG.md +13 -0
- package/build/cjs/index.cjs +145 -1391
- package/build/cjs/index.d.ts +2 -2
- package/build/cjs/interface/runtimeInterface.d.ts +2 -0
- package/build/cjs/interface/sceneInterface.d.ts +11 -1
- package/build/cjs/sceneTextPreProcessor.d.ts +10 -0
- package/build/es/index.d.ts +2 -2
- package/build/es/index.js +144 -1392
- package/build/es/interface/runtimeInterface.d.ts +2 -0
- package/build/es/interface/sceneInterface.d.ts +11 -1
- package/build/es/sceneTextPreProcessor.d.ts +10 -0
- package/build/types/index.d.ts +2 -2
- package/build/types/interface/runtimeInterface.d.ts +2 -0
- package/build/types/interface/sceneInterface.d.ts +11 -1
- package/build/types/sceneTextPreProcessor.d.ts +10 -0
- package/build/umd/index.global.js +145 -1391
- package/package.json +3 -13
- package/src/config/scriptConfig.ts +1 -0
- package/src/index.ts +6 -2
- package/src/interface/runtimeInterface.ts +2 -0
- package/src/interface/sceneInterface.ts +10 -0
- package/src/sceneParser.ts +52 -3
- package/src/sceneTextPreProcessor.ts +25 -80
- package/src/scriptParser/argsParser.ts +1 -1
- package/src/scriptParser/scriptParser.ts +8 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webgal-parser",
|
|
3
|
-
"version": "4.6.1",
|
|
3
|
+
"version": "4.6.3-beta.1",
|
|
4
4
|
"description": "WebGAL script parser",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "vitest",
|
|
@@ -17,26 +17,16 @@
|
|
|
17
17
|
"main": "./build/cjs/index.cjs",
|
|
18
18
|
"author": "Mahiru <Mahiru_@outlook.com>",
|
|
19
19
|
"license": "MPL-2.0",
|
|
20
|
-
"dependencies": {
|
|
21
|
-
"chevrotain": "^10.5.0",
|
|
22
|
-
"cloudlogjs": "^1.0.11",
|
|
23
|
-
"lodash": "^4.17.23",
|
|
24
|
-
"tsx": "^3.12.7"
|
|
25
|
-
},
|
|
26
20
|
"devDependencies": {
|
|
27
21
|
"@rollup/plugin-commonjs": "^23.0.2",
|
|
28
|
-
"@rollup/plugin-json": "^5.0.1",
|
|
29
22
|
"@rollup/plugin-node-resolve": "^15.0.1",
|
|
30
|
-
"@rollup/plugin-typescript": "^9.0.2",
|
|
31
|
-
"@types/lodash": "^4.14.189",
|
|
32
23
|
"@types/node": "^18.14.0",
|
|
33
24
|
"@vitest/coverage-c8": "^0.28.5",
|
|
25
|
+
"rimraf": "^3.0.2",
|
|
34
26
|
"rollup": "^3.29.5",
|
|
35
|
-
"rollup-plugin-babel": "^4.4.0",
|
|
36
|
-
"rollup-plugin-terser": "^7.0.2",
|
|
37
27
|
"rollup-plugin-typescript2": "^0.34.1",
|
|
38
|
-
"ts-node": "^10.9.1",
|
|
39
28
|
"tslib": "^2.4.1",
|
|
29
|
+
"tsx": "^3.12.7",
|
|
40
30
|
"typescript": "^4.9.3",
|
|
41
31
|
"vitest": "^0.28.5"
|
|
42
32
|
},
|
|
@@ -39,6 +39,7 @@ export const SCRIPT_CONFIG = [
|
|
|
39
39
|
{ scriptString: 'applyStyle', scriptType: commandType.applyStyle },
|
|
40
40
|
{ scriptString: 'wait', scriptType: commandType.wait },
|
|
41
41
|
{ scriptString: 'callSteam', scriptType: commandType.callSteam },
|
|
42
|
+
{ scriptString: 'return', scriptType: commandType.return },
|
|
42
43
|
];
|
|
43
44
|
export const ADD_NEXT_ARG_LIST = [
|
|
44
45
|
commandType.bgm,
|
package/src/index.ts
CHANGED
|
@@ -9,7 +9,11 @@ import { fileType } from './interface/assets';
|
|
|
9
9
|
import { IAsset } from './interface/sceneInterface';
|
|
10
10
|
import { sceneParser } from './sceneParser';
|
|
11
11
|
import { IWebGALStyleObj, scss2cssinjsParser } from "./styleParser";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
isLineBreakPlaceholder,
|
|
14
|
+
sceneTextPreProcess,
|
|
15
|
+
WEBGAL_LINE_BREAK_MARK,
|
|
16
|
+
} from "./sceneTextPreProcessor";
|
|
13
17
|
|
|
14
18
|
export default class SceneParser {
|
|
15
19
|
private readonly SCRIPT_CONFIG_MAP: ConfigMap;
|
|
@@ -77,4 +81,4 @@ export default class SceneParser {
|
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
export { ADD_NEXT_ARG_LIST, SCRIPT_CONFIG };
|
|
80
|
-
export { sceneTextPreProcess };
|
|
84
|
+
export { sceneTextPreProcess, isLineBreakPlaceholder, WEBGAL_LINE_BREAK_MARK };
|
|
@@ -40,6 +40,7 @@ export enum commandType {
|
|
|
40
40
|
applyStyle,
|
|
41
41
|
wait,
|
|
42
42
|
callSteam, // 调用Steam功能
|
|
43
|
+
return, // 从被调用的场景返回
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
/**
|
|
@@ -74,6 +75,15 @@ export interface ISentence {
|
|
|
74
75
|
sentenceAssets: Array<IAsset>; // 语句携带的资源列表
|
|
75
76
|
subScene: Array<string>; // 语句包含子场景列表
|
|
76
77
|
inlineComment: string; // 行内注释
|
|
78
|
+
/**
|
|
79
|
+
* 本语句在原始场景文件中占据的行范围(0-based,含首尾)。
|
|
80
|
+
* 单行语句 startLine === endLine;多行语句 endLine 指向最后一条续行。
|
|
81
|
+
* 图形编辑器据此做「只替换被编辑语句所占的行」。
|
|
82
|
+
*/
|
|
83
|
+
startLine: number;
|
|
84
|
+
endLine: number;
|
|
85
|
+
/** 本条是多行语句被折叠掉的续行占位,仅用于补齐行数,不应展示给用户 */
|
|
86
|
+
isLineBreakHolder: boolean;
|
|
77
87
|
}
|
|
78
88
|
|
|
79
89
|
/**
|
package/src/sceneParser.ts
CHANGED
|
@@ -5,9 +5,12 @@ import {
|
|
|
5
5
|
ISentence,
|
|
6
6
|
} from './interface/sceneInterface';
|
|
7
7
|
import { scriptParser } from './scriptParser/scriptParser';
|
|
8
|
-
import uniqWith from 'lodash/uniqWith';
|
|
9
8
|
import { fileType } from './interface/assets';
|
|
10
9
|
import { ConfigMap } from './config/scriptConfig';
|
|
10
|
+
import {
|
|
11
|
+
isLineBreakPlaceholder,
|
|
12
|
+
sceneTextPreProcess,
|
|
13
|
+
} from './sceneTextPreProcessor';
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* 场景解析器
|
|
@@ -29,7 +32,9 @@ export const sceneParser = (
|
|
|
29
32
|
ADD_NEXT_ARG_LIST: commandType[],
|
|
30
33
|
SCRIPT_CONFIG_MAP: ConfigMap,
|
|
31
34
|
): IScene => {
|
|
32
|
-
|
|
35
|
+
// 预处理把多行语句折叠进它的首行,并用占位行补齐被折叠掉的行,
|
|
36
|
+
// 因此这里的行数与原始场景严格一致,「语句 index == 文件行号」始终成立。
|
|
37
|
+
const rawSentenceList = sceneTextPreProcess(rawScene).split('\n'); // 原始句子列表
|
|
33
38
|
|
|
34
39
|
// 去分号留到后面去做了,现在注释要单独处理
|
|
35
40
|
const rawSentenceListWithoutEmpty = rawSentenceList;
|
|
@@ -53,8 +58,10 @@ export const sceneParser = (
|
|
|
53
58
|
},
|
|
54
59
|
);
|
|
55
60
|
|
|
61
|
+
markMultilineRanges(sentenceList, rawSentenceList);
|
|
62
|
+
|
|
56
63
|
// 开始资源的预加载
|
|
57
|
-
assetsList =
|
|
64
|
+
assetsList = deduplicateAssets(assetsList);
|
|
58
65
|
assetsPrefetcher(assetsList);
|
|
59
66
|
|
|
60
67
|
return {
|
|
@@ -65,3 +72,45 @@ export const sceneParser = (
|
|
|
65
72
|
subSceneList: subSceneList, // 子场景列表
|
|
66
73
|
};
|
|
67
74
|
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 回填多行语句的行范围。
|
|
78
|
+
*
|
|
79
|
+
* 预处理后,一条多行语句的完整内容都落在它的首行,紧跟其后的若干占位行
|
|
80
|
+
* 就是被折叠掉的续行。这里把占位行标记出来,并把首行语句的 endLine
|
|
81
|
+
* 推到最后一条续行,图形编辑器据此按整个行范围替换语句。
|
|
82
|
+
*
|
|
83
|
+
* @param sentenceList 解析后的语句列表
|
|
84
|
+
* @param processedLines 预处理后的行,与 sentenceList 一一对应
|
|
85
|
+
*/
|
|
86
|
+
const markMultilineRanges = (
|
|
87
|
+
sentenceList: ISentence[],
|
|
88
|
+
processedLines: string[],
|
|
89
|
+
) => {
|
|
90
|
+
let headIndex = -1; // 最近一条非占位语句的下标,即当前多行语句的首行
|
|
91
|
+
for (let index = 0; index < sentenceList.length; index++) {
|
|
92
|
+
if (!isLineBreakPlaceholder(processedLines[index])) {
|
|
93
|
+
headIndex = index;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
sentenceList[index].isLineBreakHolder = true;
|
|
97
|
+
if (headIndex >= 0) {
|
|
98
|
+
sentenceList[headIndex].endLine = index;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const deduplicateAssets = (assetsList: IAsset[]): IAsset[] => {
|
|
104
|
+
const seenAssets = new Set<string>();
|
|
105
|
+
return assetsList.filter((asset) => {
|
|
106
|
+
if (!asset || typeof asset.url !== 'string' || asset.url === '') {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const assetKey = `${asset.type}:${asset.url}`;
|
|
110
|
+
if (seenAssets.has(assetKey)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
seenAssets.add(assetKey);
|
|
114
|
+
return true;
|
|
115
|
+
});
|
|
116
|
+
};
|
|
@@ -31,15 +31,11 @@ function sceneTextPreProcessPassOne(lines: string[]): string[] {
|
|
|
31
31
|
let thisLineIsMultiline = false;
|
|
32
32
|
|
|
33
33
|
for (const line of lines) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (shouldNotBeMultiline(line, lastLineIsMultiline)) {
|
|
41
|
-
thisLineIsMultiline = false;
|
|
42
|
-
}
|
|
34
|
+
// 续行需要接到上一行,所以场景的第一行永远不会是续行。
|
|
35
|
+
thisLineIsMultiline =
|
|
36
|
+
processedLines.length > 0 &&
|
|
37
|
+
canBeMultiline(line) &&
|
|
38
|
+
!shouldNotBeMultiline(line, lastLineIsMultiline);
|
|
43
39
|
|
|
44
40
|
if (thisLineIsMultiline) {
|
|
45
41
|
processedLines[processedLines.length - 1] += '\\';
|
|
@@ -111,7 +107,6 @@ function sceneTextPreProcessPassTwo(lines: string[]): string[] {
|
|
|
111
107
|
}
|
|
112
108
|
|
|
113
109
|
for (const line of lines) {
|
|
114
|
-
console.log(line);
|
|
115
110
|
if (line.endsWith('\\')) {
|
|
116
111
|
const trueLine = line.slice(0, -1);
|
|
117
112
|
|
|
@@ -139,9 +134,28 @@ function sceneTextPreProcessPassTwo(lines: string[]): string[] {
|
|
|
139
134
|
processedLines.push(line);
|
|
140
135
|
}
|
|
141
136
|
|
|
137
|
+
// 场景末行仍以 \ 结尾时循环里没有机会收尾,在这里把累积的内容补出去。
|
|
138
|
+
if (currentMultilineContent !== "") {
|
|
139
|
+
processedLines.push(currentMultilineContent, ...placeHolderLines);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
142
|
return processedLines;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* 占位行的前缀。占位行本身是一条注释,引擎会空跑掉;
|
|
147
|
+
* 它的作用是让预处理后的行数与原始场景一致,从而保持
|
|
148
|
+
* 「解析后语句 index == 文件行号」这一不变量。
|
|
149
|
+
*/
|
|
150
|
+
export const WEBGAL_LINE_BREAK_MARK = ';_WEBGAL_LINE_BREAK_';
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* 判断预处理后的某一行是否是占位行,即它是上一条多行语句折叠掉的续行。
|
|
154
|
+
*/
|
|
155
|
+
export function isLineBreakPlaceholder(processedLine: string): boolean {
|
|
156
|
+
return processedLine.startsWith(WEBGAL_LINE_BREAK_MARK);
|
|
157
|
+
}
|
|
158
|
+
|
|
145
159
|
/**
|
|
146
160
|
* Placeholder Line. Adding this line preserves the original number of lines
|
|
147
161
|
* in the scene text, so that it can be compatible with the graphical editor.
|
|
@@ -150,74 +164,5 @@ function sceneTextPreProcessPassTwo(lines: string[]): string[] {
|
|
|
150
164
|
* @returns The placeholder line
|
|
151
165
|
*/
|
|
152
166
|
function placeholderLine(content = "") {
|
|
153
|
-
return
|
|
167
|
+
return WEBGAL_LINE_BREAK_MARK + content;
|
|
154
168
|
}
|
|
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
|
-
// }
|
|
@@ -30,7 +30,7 @@ export function argsParser(
|
|
|
30
30
|
argValue = undefined;
|
|
31
31
|
}
|
|
32
32
|
// 判断是不是语音参数
|
|
33
|
-
if (argName.toLowerCase().match(/.ogg|.mp3|.wav/)) {
|
|
33
|
+
if (argName.toLowerCase().match(/.ogg|.mp3|.wav|.opus/)) {
|
|
34
34
|
returnArrayList.push({
|
|
35
35
|
key: 'vocal',
|
|
36
36
|
value: assetSetter(e, fileType.vocal),
|
|
@@ -40,7 +40,7 @@ export const scriptParser = (
|
|
|
40
40
|
const commentSplit = sentenceRaw.split(/(?<!\\);/);
|
|
41
41
|
let newSentenceRaw = commentSplit[0];
|
|
42
42
|
newSentenceRaw = newSentenceRaw.replaceAll('\\;',';');
|
|
43
|
-
const sentenceComment = commentSplit
|
|
43
|
+
const sentenceComment = commentSplit.slice(1).join(';');
|
|
44
44
|
if (newSentenceRaw.trim() === '') {
|
|
45
45
|
// 注释提前返回
|
|
46
46
|
return {
|
|
@@ -51,6 +51,9 @@ export const scriptParser = (
|
|
|
51
51
|
sentenceAssets: [], // 语句携带的资源列表
|
|
52
52
|
subScene: [], // 语句携带的子场景
|
|
53
53
|
inlineComment: '', // 行内注释
|
|
54
|
+
startLine: lineNumber,
|
|
55
|
+
endLine: lineNumber,
|
|
56
|
+
isLineBreakHolder: false,
|
|
54
57
|
};
|
|
55
58
|
}
|
|
56
59
|
// 截取命令
|
|
@@ -116,5 +119,9 @@ export const scriptParser = (
|
|
|
116
119
|
sentenceAssets: sentenceAssets, // 语句携带的资源列表
|
|
117
120
|
subScene: subScene, // 语句携带的子场景
|
|
118
121
|
inlineComment: sentenceComment.trim(), // 行内注释
|
|
122
|
+
// 单行语句的行范围就是自己,多行语句的 endLine 由 sceneParser 回填
|
|
123
|
+
startLine: lineNumber,
|
|
124
|
+
endLine: lineNumber,
|
|
125
|
+
isLineBreakHolder: false,
|
|
119
126
|
};
|
|
120
127
|
};
|