@godot-scene-web/tscn-parser 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tomás Fox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,116 @@
1
+ //#region ../core/dist/index.d.ts
2
+ //#region src/index.d.ts
3
+ type GodotDocumentKind = "scene" | "resource";
4
+ /** Renderer-neutral 3×3 linear RGB transform. */
5
+ interface GodotParseDiagnostic {
6
+ severity: "warning" | "error";
7
+ code: string;
8
+ message: string;
9
+ line?: number;
10
+ column?: number;
11
+ }
12
+ interface GodotResource {
13
+ type?: string;
14
+ header: GodotSectionHeader | null;
15
+ extResources: GodotExtResource[];
16
+ subResources: GodotSubResource[];
17
+ properties: Record<string, GodotVariant>;
18
+ diagnostics: GodotParseDiagnostic[];
19
+ }
20
+ interface GodotSceneState {
21
+ kind: "scene";
22
+ nodes: GodotSceneStateNode[];
23
+ connections: GodotSceneStateConnection[];
24
+ extResources: GodotExtResource[];
25
+ subResources: GodotSubResource[];
26
+ editableInstances: string[];
27
+ basePath?: string;
28
+ diagnostics: GodotParseDiagnostic[];
29
+ }
30
+ interface GodotSceneStateNode {
31
+ index: number;
32
+ siblingIndex?: number;
33
+ name: string;
34
+ type?: string;
35
+ parent?: string;
36
+ owner?: string;
37
+ instance?: GodotResourceRefValue;
38
+ instancePlaceholder?: string;
39
+ groups: string[];
40
+ properties: GodotOrderedProperty[];
41
+ }
42
+ interface GodotOrderedProperty {
43
+ name: string;
44
+ value: GodotVariant;
45
+ }
46
+ interface GodotSceneStateConnection {
47
+ signal?: string;
48
+ from?: string;
49
+ to?: string;
50
+ method?: string;
51
+ flags?: number;
52
+ binds?: GodotVariant[];
53
+ unbinds?: number;
54
+ }
55
+ interface GodotSectionHeader {
56
+ section: string;
57
+ attributes: Record<string, GodotVariant>;
58
+ }
59
+ interface GodotExtResource {
60
+ id: string;
61
+ type?: string;
62
+ path?: string;
63
+ uid?: string;
64
+ attributes: Record<string, GodotVariant>;
65
+ properties: Record<string, GodotVariant>;
66
+ }
67
+ interface GodotSubResource {
68
+ id: string;
69
+ type?: string;
70
+ attributes: Record<string, GodotVariant>;
71
+ properties: Record<string, GodotVariant>;
72
+ }
73
+ type GodotVariant = null | boolean | number | string | GodotStringNameVariant | GodotVectorVariant | GodotColorVariant | GodotRectVariant | GodotNodePathVariant | GodotResourceRefValue | GodotCallVariant | GodotVariant[] | {
74
+ [key: string]: GodotVariant;
75
+ };
76
+ interface GodotVectorVariant {
77
+ type: "Vector2" | "Vector2i" | "Vector3" | "Vector3i" | "Vector4" | "Vector4i";
78
+ args: number[];
79
+ }
80
+ interface GodotColorVariant {
81
+ type: "Color";
82
+ args: number[];
83
+ }
84
+ interface GodotStringNameVariant {
85
+ type: "StringName";
86
+ args: string[];
87
+ }
88
+ interface GodotRectVariant {
89
+ type: "Rect2" | "Rect2i";
90
+ args: number[];
91
+ }
92
+ interface GodotNodePathVariant {
93
+ type: "NodePath";
94
+ args: string[];
95
+ }
96
+ interface GodotResourceRefValue {
97
+ type: "ExtResource" | "SubResource";
98
+ id?: string;
99
+ path?: string;
100
+ }
101
+ interface GodotCallVariant {
102
+ type: string;
103
+ args: GodotVariant[];
104
+ }
105
+ //#endregion
106
+ //#region src/index.d.ts
107
+ interface ParseGodotTextOptions {
108
+ path?: string;
109
+ kind?: GodotDocumentKind;
110
+ }
111
+ declare function parseGodotTextScene(text: string, options?: ParseGodotTextOptions): GodotSceneState;
112
+ declare function parseGodotResource(text: string, options?: ParseGodotTextOptions): GodotResource;
113
+ declare function parseGodotValue(source: string, diagnostics?: GodotParseDiagnostic[], line?: number): GodotVariant;
114
+ //#endregion
115
+ export { ParseGodotTextOptions, parseGodotResource, parseGodotTextScene, parseGodotValue };
116
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":["GodotDocumentKind","ColorMatrix","rows","GodotParseDiagnostic","severity","code","message","line","column","GodotResource","GodotSectionHeader","GodotExtResource","GodotSubResource","GodotVariant","Record","type","header","extResources","subResources","properties","diagnostics","GodotSceneState","GodotSceneStateNode","GodotSceneStateConnection","kind","nodes","connections","editableInstances","basePath","GodotResourceRefValue","GodotOrderedProperty","index","siblingIndex","name","parent","owner","instance","instancePlaceholder","groups","value","signal","from","to","method","flags","binds","unbinds","section","attributes","id","path","uid","GodotNode","propertyEntries","GodotConnection","GodotEditable","GodotStringNameVariant","GodotVectorVariant","GodotColorVariant","GodotRectVariant","GodotNodePathVariant","GodotCallVariant","key","args","GodotRect","x","y","width","height","isColorValue","isRectValue","asNumber","asBoolean","asString","asVector2","asRect2","asResourceRef","decodeFromNativeValue","isGodotSceneState","godotNodePath","node","godotParentPath"],"sources":["../../core/dist/index.d.ts","../src/index.ts"],"mappings":";;KACKA,iBAAAA;;UAKKG,oBAAAA;EACRC,QAAAA;EACAC,IAAAA;EACAC,OAAAA;EACAC,IAAAA;EACAC,MAAAA;AAAAA;AAAAA,UAEQC,aAAAA;EACRM,IAAAA;EACAC,MAAAA,EAAQN,kBAAAA;EACRO,YAAAA,EAAcN,gBAAAA;EACdO,YAAAA,EAAcN,gBAAAA;EACdO,UAAAA,EAAYL,MAAAA,SAAeD,YAAAA;EAC3BO,WAAAA,EAAajB,oBAAAA;AAAAA;AAAAA,UAELkB,eAAAA;EACRG,IAAAA;EACAC,KAAAA,EAAOH,mBAAAA;EACPI,WAAAA,EAAaH,yBAAAA;EACbN,YAAAA,EAAcN,gBAAAA;EACdO,YAAAA,EAAcN,gBAAAA;EACde,iBAAAA;EACAC,QAAAA;EACAR,WAAAA,EAAajB,oBAAAA;AAAAA;AAAAA,UAELmB,mBAAAA;EACRS,KAAAA;EACAC,YAAAA;EACAC,IAAAA;EACAlB,IAAAA;EACAmB,MAAAA;EACAC,KAAAA;EACAC,QAAAA,GAAWP,qBAAAA;EACXQ,mBAAAA;EACAC,MAAAA;EACAnB,UAAAA,EAAYW,oBAAoB;AAAA;AAAA,UAExBA,oBAAAA;EACRG,IAAAA;EACAM,KAAAA,EAAO1B,YAAY;AAAA;AAAA,UAEXU,yBAAAA;EACRiB,MAAAA;EACAC,IAAAA;EACAC,EAAAA;EACAC,MAAAA;EACAC,KAAAA;EACAC,KAAAA,GAAQhC,YAAY;EACpBiC,OAAAA;AAAAA;AAAAA,UAEQpC,kBAAAA;EACRqC,OAAAA;EACAC,UAAAA,EAAYlC,MAAM,SAASD,YAAAA;AAAAA;AAAAA,UAEnBF,gBAAAA;EACRsC,EAAAA;EACAlC,IAAAA;EACAmC,IAAAA;EACAC,GAAAA;EACAH,UAAAA,EAAYlC,MAAAA,SAAeD,YAAAA;EAC3BM,UAAAA,EAAYL,MAAAA,SAAeD,YAAAA;AAAAA;AAAAA,UAEnBD,gBAAAA;EACRqC,EAAAA;EACAlC,IAAAA;EACAiC,UAAAA,EAAYlC,MAAAA,SAAeD,YAAAA;EAC3BM,UAAAA,EAAYL,MAAAA,SAAeD,YAAAA;AAAAA;AAAAA,KAsBxBA,YAAAA,sCAAkD2C,sBAAAA,GAAyBC,kBAAAA,GAAqBC,iBAAAA,GAAoBC,gBAAAA,GAAmBC,oBAAAA,GAAuB/B,qBAAAA,GAAwBgC,gBAAAA,GAAmBhD,YAAAA;EAAAA,CAC3MiD,GAAAA,WAAcjD,YAAAA;AAAAA;AAAAA,UAEP4C,kBAAAA;EACR1C,IAAAA;EACAgD,IAAI;AAAA;AAAA,UAEIL,iBAAAA;EACR3C,IAAAA;EACAgD,IAAI;AAAA;AAAA,UAEIP,sBAAAA;EACRzC,IAAAA;EACAgD,IAAI;AAAA;AAAA,UAEIJ,gBAAAA;EACR5C,IAAAA;EACAgD,IAAI;AAAA;AAAA,UAEIH,oBAAAA;EACR7C,IAAAA;EACAgD,IAAI;AAAA;AAAA,UAEIlC,qBAAAA;EACRd,IAAAA;EACAkC,EAAAA;EACAC,IAAAA;AAAAA;AAAAA,UAEQW,gBAAAA;EACR9C,IAAAA;EACAgD,IAAAA,EAAMlD,YAAY;AAAA;;;UCrFH,qBAAA;EACf,IAAA;EACA,IAAA,GAAO,iBAAiB;AAAA;AAAA,iBAGV,mBAAA,CACd,IAAA,UACA,OAAA,GAAS,qBAAA,GACR,eAAe;AAAA,iBAMF,kBAAA,CACd,IAAA,UACA,OAAA,GAAS,qBAAA,GACR,aAAa;AAAA,iBA4DA,eAAA,CACd,MAAA,UACA,WAAA,GAAa,oBAAA,IACb,IAAA,YACC,YAAY"}
package/dist/index.js ADDED
@@ -0,0 +1,604 @@
1
+ //#region src/index.ts
2
+ function parseGodotTextScene(text, options = {}) {
3
+ return godotSceneStateFromDocument(parseDocument(text, {
4
+ ...options,
5
+ kind: "scene"
6
+ }));
7
+ }
8
+ function parseGodotResource(text, options = {}) {
9
+ return godotResourceFromDocument(parseDocument(text, {
10
+ ...options,
11
+ kind: "resource"
12
+ }));
13
+ }
14
+ function parseDocument(text, options = {}) {
15
+ const kind = options.kind ?? "resource";
16
+ const diagnostics = [];
17
+ const document = {
18
+ kind,
19
+ header: null,
20
+ extResources: [],
21
+ subResources: [],
22
+ nodes: [],
23
+ connections: [],
24
+ editables: [],
25
+ properties: {},
26
+ diagnostics
27
+ };
28
+ let current = { kind: "document" };
29
+ const lines = text.replace(/^\uFEFF/, "").split(/\r?\n/);
30
+ for (let index = 0; index < lines.length; index += 1) {
31
+ const lineNumber = index + 1;
32
+ const logical = collectLogicalLine(lines, index);
33
+ index = logical.endIndex;
34
+ const line = stripLineComment(logical.raw).trim();
35
+ if (line.length === 0) continue;
36
+ if (line.startsWith("[") && line.endsWith("]")) {
37
+ current = parseSectionHeader(line.slice(1, -1), lineNumber, diagnostics, document);
38
+ continue;
39
+ }
40
+ const assignment = splitAssignment(line);
41
+ if (!assignment) {
42
+ diagnostics.push({
43
+ severity: "warning",
44
+ code: "godot_parser_unsupported_line",
45
+ message: "Unsupported Godot text line.",
46
+ line: lineNumber
47
+ });
48
+ continue;
49
+ }
50
+ const value = parseGodotValue(assignment.value, diagnostics, lineNumber);
51
+ assignProperty(document, current, assignment.key, value);
52
+ }
53
+ return document;
54
+ }
55
+ function parseGodotValue(source, diagnostics = [], line) {
56
+ const parser = new ValueParser(source, diagnostics, line);
57
+ const value = parser.parseValue();
58
+ parser.skipTrivia();
59
+ if (!parser.done()) diagnostics.push({
60
+ severity: "warning",
61
+ code: "godot_parser_trailing_value_text",
62
+ message: `Trailing text after Godot value: ${source.slice(parser.position)}`,
63
+ line
64
+ });
65
+ return value;
66
+ }
67
+ function parseSectionHeader(source, line, diagnostics, document) {
68
+ const [section = "", ...attributeParts] = splitHeaderParts(source);
69
+ const attributes = parseHeaderAttributes(attributeParts.join(" "), diagnostics, line);
70
+ switch (section) {
71
+ case "gd_scene":
72
+ case "gd_resource": {
73
+ const header = {
74
+ section,
75
+ attributes
76
+ };
77
+ document.header = header;
78
+ document.kind = section === "gd_scene" ? "scene" : "resource";
79
+ return {
80
+ kind: "header",
81
+ header
82
+ };
83
+ }
84
+ case "ext_resource": {
85
+ const resource = {
86
+ id: stringAttribute(attributes.id) ?? "",
87
+ type: stringAttribute(attributes.type),
88
+ path: stringAttribute(attributes.path),
89
+ uid: stringAttribute(attributes.uid),
90
+ attributes,
91
+ properties: {}
92
+ };
93
+ document.extResources.push(resource);
94
+ return {
95
+ kind: "ext_resource",
96
+ resource
97
+ };
98
+ }
99
+ case "sub_resource": {
100
+ const resource = {
101
+ id: stringAttribute(attributes.id) ?? "",
102
+ type: stringAttribute(attributes.type),
103
+ attributes,
104
+ properties: {}
105
+ };
106
+ document.subResources.push(resource);
107
+ return {
108
+ kind: "sub_resource",
109
+ resource
110
+ };
111
+ }
112
+ case "node": {
113
+ const node = {
114
+ name: stringAttribute(attributes.name) ?? "",
115
+ type: stringAttribute(attributes.type),
116
+ parent: stringAttribute(attributes.parent),
117
+ instance: resourceRefAttribute(attributes.instance),
118
+ attributes,
119
+ properties: {}
120
+ };
121
+ document.nodes.push(node);
122
+ return {
123
+ kind: "node",
124
+ node
125
+ };
126
+ }
127
+ case "connection": {
128
+ const connection = {
129
+ signal: stringAttribute(attributes.signal),
130
+ from: stringAttribute(attributes.from),
131
+ to: stringAttribute(attributes.to),
132
+ method: stringAttribute(attributes.method),
133
+ attributes
134
+ };
135
+ document.connections.push(connection);
136
+ return {
137
+ kind: "connection",
138
+ connection
139
+ };
140
+ }
141
+ case "editable": {
142
+ const editable = {
143
+ path: stringAttribute(attributes.path),
144
+ attributes
145
+ };
146
+ document.editables.push(editable);
147
+ return {
148
+ kind: "editable",
149
+ editable
150
+ };
151
+ }
152
+ case "resource": return { kind: "resource" };
153
+ default:
154
+ diagnostics.push({
155
+ severity: "warning",
156
+ code: "godot_parser_unknown_section",
157
+ message: `Unknown Godot text section: ${section}`,
158
+ line
159
+ });
160
+ return { kind: "document" };
161
+ }
162
+ }
163
+ function assignProperty(document, current, key, value) {
164
+ switch (current.kind) {
165
+ case "ext_resource":
166
+ current.resource.properties[key] = value;
167
+ break;
168
+ case "sub_resource":
169
+ current.resource.properties[key] = value;
170
+ break;
171
+ case "node":
172
+ current.node.properties[key] = value;
173
+ current.node.propertyEntries ??= [];
174
+ current.node.propertyEntries.push({
175
+ name: key,
176
+ value
177
+ });
178
+ break;
179
+ case "header":
180
+ current.header.attributes[key] = value;
181
+ break;
182
+ case "connection":
183
+ current.connection.attributes[key] = value;
184
+ break;
185
+ case "editable":
186
+ current.editable.attributes[key] = value;
187
+ break;
188
+ case "resource":
189
+ document.properties[key] = value;
190
+ break;
191
+ case "document":
192
+ document.properties[key] = value;
193
+ break;
194
+ }
195
+ }
196
+ function godotSceneStateFromDocument(document) {
197
+ const basePath = stringAttribute(document.header?.attributes.path);
198
+ return {
199
+ kind: "scene",
200
+ nodes: document.nodes.map(godotSceneStateNodeFromDocumentNode),
201
+ connections: document.connections.map(godotSceneStateConnectionFromDocumentConnection),
202
+ extResources: document.extResources,
203
+ subResources: document.subResources,
204
+ editableInstances: document.editables.map((editable) => editable.path).filter((path) => typeof path === "string"),
205
+ ...basePath ? { basePath } : {},
206
+ diagnostics: document.diagnostics
207
+ };
208
+ }
209
+ function godotResourceFromDocument(document) {
210
+ return {
211
+ type: stringAttribute(document.header?.attributes.type),
212
+ header: document.header,
213
+ extResources: document.extResources,
214
+ subResources: document.subResources,
215
+ properties: document.properties,
216
+ diagnostics: document.diagnostics
217
+ };
218
+ }
219
+ function godotSceneStateNodeFromDocumentNode(node, index) {
220
+ const owner = stringAttribute(node.attributes.owner);
221
+ const instancePlaceholder = stringAttribute(node.attributes.instance_placeholder) ?? stringAttribute(node.attributes.instancePlaceholder);
222
+ const siblingIndex = nodeIndexAttribute(node.attributes.index);
223
+ return {
224
+ index,
225
+ ...siblingIndex !== void 0 ? { siblingIndex } : {},
226
+ name: node.name,
227
+ ...node.type !== void 0 ? { type: node.type } : {},
228
+ parent: node.parent ?? ".",
229
+ ...owner !== void 0 ? { owner } : {},
230
+ ...node.instance !== void 0 ? { instance: node.instance } : {},
231
+ ...instancePlaceholder !== void 0 ? { instancePlaceholder } : {},
232
+ groups: stringArrayAttribute(node.attributes.groups),
233
+ properties: node.propertyEntries?.map((property) => ({ ...property })) ?? Object.entries(node.properties).map(([name, value]) => ({
234
+ name,
235
+ value
236
+ }))
237
+ };
238
+ }
239
+ function godotSceneStateConnectionFromDocumentConnection(connection) {
240
+ const flags = numberAttribute(connection.attributes.flags);
241
+ const binds = godotValueArrayAttribute(connection.attributes.binds);
242
+ const unbinds = numberAttribute(connection.attributes.unbinds);
243
+ return {
244
+ ...connection.signal !== void 0 ? { signal: connection.signal } : {},
245
+ ...connection.from !== void 0 ? { from: connection.from } : {},
246
+ ...connection.to !== void 0 ? { to: connection.to } : {},
247
+ ...connection.method !== void 0 ? { method: connection.method } : {},
248
+ ...flags !== void 0 ? { flags } : {},
249
+ ...binds !== void 0 ? { binds } : {},
250
+ ...unbinds !== void 0 ? { unbinds } : {}
251
+ };
252
+ }
253
+ function collectLogicalLine(lines, startIndex) {
254
+ const state = newOpenValueState();
255
+ const parts = [lines[startIndex] ?? ""];
256
+ scanOpenValue(parts[0], state);
257
+ let endIndex = startIndex;
258
+ while (isOpenValue(state) && endIndex + 1 < lines.length) {
259
+ endIndex += 1;
260
+ const line = lines[endIndex] ?? "";
261
+ parts.push(line);
262
+ scanOpenValue(`\n${line}`, state);
263
+ }
264
+ return {
265
+ raw: parts.join("\n"),
266
+ endIndex
267
+ };
268
+ }
269
+ function newOpenValueState() {
270
+ return {
271
+ quote: null,
272
+ escaped: false,
273
+ inComment: false,
274
+ squareDepth: 0,
275
+ curlyDepth: 0,
276
+ parenDepth: 0
277
+ };
278
+ }
279
+ function isOpenValue(state) {
280
+ return state.quote !== null || state.squareDepth > 0 || state.curlyDepth > 0 || state.parenDepth > 0;
281
+ }
282
+ function scanOpenValue(source, state) {
283
+ for (let index = 0; index < source.length; index += 1) {
284
+ const char = source[index];
285
+ if (state.inComment) {
286
+ if (char === "\n") state.inComment = false;
287
+ continue;
288
+ }
289
+ if (state.quote) {
290
+ if (state.escaped) state.escaped = false;
291
+ else if (char === "\\") state.escaped = true;
292
+ else if (char === state.quote) state.quote = null;
293
+ continue;
294
+ }
295
+ if (char === "\"" || char === "'") state.quote = char;
296
+ else if (char === ";") state.inComment = true;
297
+ else if (char === "[") state.squareDepth += 1;
298
+ else if (char === "]") state.squareDepth = Math.max(0, state.squareDepth - 1);
299
+ else if (char === "{") state.curlyDepth += 1;
300
+ else if (char === "}") state.curlyDepth = Math.max(0, state.curlyDepth - 1);
301
+ else if (char === "(") state.parenDepth += 1;
302
+ else if (char === ")") state.parenDepth = Math.max(0, state.parenDepth - 1);
303
+ }
304
+ }
305
+ function stripLineComment(line) {
306
+ let quote = null;
307
+ let escaped = false;
308
+ for (let index = 0; index < line.length; index += 1) {
309
+ const char = line[index];
310
+ if (quote) {
311
+ if (escaped) escaped = false;
312
+ else if (char === "\\") escaped = true;
313
+ else if (char === quote) quote = null;
314
+ continue;
315
+ }
316
+ if (char === "\"" || char === "'") quote = char;
317
+ else if (char === ";") return line.slice(0, index);
318
+ }
319
+ return line;
320
+ }
321
+ function splitAssignment(line) {
322
+ const index = line.indexOf("=");
323
+ if (index < 0) return null;
324
+ return {
325
+ key: line.slice(0, index).trim(),
326
+ value: line.slice(index + 1).trim()
327
+ };
328
+ }
329
+ function splitHeaderParts(source) {
330
+ const parts = [];
331
+ let quote = null;
332
+ let escaped = false;
333
+ let start = 0;
334
+ for (let index = 0; index < source.length; index += 1) {
335
+ const char = source[index];
336
+ if (quote) {
337
+ if (escaped) escaped = false;
338
+ else if (char === "\\") escaped = true;
339
+ else if (char === quote) quote = null;
340
+ continue;
341
+ }
342
+ if (char === "\"" || char === "'") quote = char;
343
+ else if (/\s/.test(char)) {
344
+ if (index > start) parts.push(source.slice(start, index));
345
+ start = index + 1;
346
+ }
347
+ }
348
+ if (start < source.length) parts.push(source.slice(start));
349
+ return parts;
350
+ }
351
+ function parseHeaderAttributes(source, diagnostics, line) {
352
+ const attributes = {};
353
+ const matches = [...source.matchAll(/([A-Za-z0-9_./-]+)=/g)];
354
+ for (let index = 0; index < matches.length; index += 1) {
355
+ const match = matches[index];
356
+ if (match.index === void 0) continue;
357
+ const key = match[1] ?? "";
358
+ const valueStart = match.index + match[0].length;
359
+ const valueEnd = matches[index + 1]?.index ?? source.length;
360
+ attributes[key] = parseGodotValue(source.slice(valueStart, valueEnd).trim(), diagnostics, line);
361
+ }
362
+ return attributes;
363
+ }
364
+ function stringAttribute(value) {
365
+ return typeof value === "string" ? value : void 0;
366
+ }
367
+ function numberAttribute(value) {
368
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
369
+ }
370
+ function nodeIndexAttribute(value) {
371
+ if (typeof value === "number" && Number.isInteger(value)) return value;
372
+ if (typeof value === "string" && /^-?\d+$/.test(value)) return Number(value);
373
+ }
374
+ function stringArrayAttribute(value) {
375
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
376
+ }
377
+ function godotValueArrayAttribute(value) {
378
+ return Array.isArray(value) ? value : void 0;
379
+ }
380
+ function resourceRefAttribute(value) {
381
+ if (typeof value === "object" && value !== null && "type" in value && (value.type === "ExtResource" || value.type === "SubResource") && "id" in value && typeof value.id === "string") return {
382
+ type: value.type,
383
+ id: value.id
384
+ };
385
+ }
386
+ var ValueParser = class {
387
+ source;
388
+ diagnostics;
389
+ line;
390
+ position = 0;
391
+ constructor(source, diagnostics, line) {
392
+ this.source = source;
393
+ this.diagnostics = diagnostics;
394
+ this.line = line;
395
+ }
396
+ parseValue() {
397
+ this.skipTrivia();
398
+ const char = this.peek();
399
+ if (char === "\"" || char === "'") return this.parseString();
400
+ if (char === "[") return this.parseArray();
401
+ if (char === "{") return this.parseDictionary();
402
+ if (char === "&") return this.parseStringName();
403
+ if (char === "-" || char === "+" || char === "." || isDigit(char)) return this.parseNumber();
404
+ const ident = this.parseIdentifier();
405
+ if (ident.length === 0) {
406
+ this.warn("godot_parser_empty_value", "Expected a Godot value.");
407
+ return null;
408
+ }
409
+ if (ident === "true") return true;
410
+ if (ident === "false") return false;
411
+ if (ident === "null" || ident === "nil") return null;
412
+ this.skipTrivia();
413
+ if (this.peek() === "(") return this.parseCall(ident);
414
+ return ident;
415
+ }
416
+ skipTrivia() {
417
+ while (!this.done() && /\s/.test(this.peek())) this.position += 1;
418
+ }
419
+ done() {
420
+ return this.position >= this.source.length;
421
+ }
422
+ peek() {
423
+ return this.source[this.position] ?? "";
424
+ }
425
+ parseString() {
426
+ const quote = this.peek();
427
+ this.position += 1;
428
+ let result = "";
429
+ let escaped = false;
430
+ while (!this.done()) {
431
+ const char = this.peek();
432
+ this.position += 1;
433
+ if (escaped) {
434
+ result += decodeEscape(char);
435
+ escaped = false;
436
+ } else if (char === "\\") escaped = true;
437
+ else if (char === quote) return result;
438
+ else result += char;
439
+ }
440
+ this.warn("godot_parser_unterminated_string", "Unterminated Godot string.");
441
+ return result;
442
+ }
443
+ parseArray() {
444
+ this.position += 1;
445
+ const values = [];
446
+ while (!this.done()) {
447
+ this.skipTrivia();
448
+ if (this.peek() === "]") {
449
+ this.position += 1;
450
+ return values;
451
+ }
452
+ values.push(this.parseValue());
453
+ this.skipTrivia();
454
+ if (this.peek() === ",") this.position += 1;
455
+ }
456
+ this.warn("godot_parser_unterminated_array", "Unterminated Godot array.");
457
+ return values;
458
+ }
459
+ parseDictionary() {
460
+ this.position += 1;
461
+ const result = {};
462
+ while (!this.done()) {
463
+ this.skipTrivia();
464
+ if (this.peek() === "}") {
465
+ this.position += 1;
466
+ return result;
467
+ }
468
+ const keyValue = this.parseValue();
469
+ this.skipTrivia();
470
+ if (this.peek() !== ":") {
471
+ this.warn("godot_parser_dictionary_colon_missing", "Expected ':' in Godot dictionary.");
472
+ return result;
473
+ }
474
+ this.position += 1;
475
+ const value = this.parseValue();
476
+ result[dictionaryKey(keyValue)] = value;
477
+ this.skipTrivia();
478
+ if (this.peek() === ",") this.position += 1;
479
+ }
480
+ this.warn("godot_parser_unterminated_dictionary", "Unterminated Godot dictionary.");
481
+ return result;
482
+ }
483
+ parseNumber() {
484
+ const start = this.position;
485
+ if (this.peek() === "+" || this.peek() === "-") this.position += 1;
486
+ while (isDigit(this.peek())) this.position += 1;
487
+ if (this.peek() === ".") {
488
+ this.position += 1;
489
+ while (isDigit(this.peek())) this.position += 1;
490
+ }
491
+ if (this.peek().toLowerCase() === "e") {
492
+ this.position += 1;
493
+ if (this.peek() === "+" || this.peek() === "-") this.position += 1;
494
+ while (isDigit(this.peek())) this.position += 1;
495
+ }
496
+ return Number(this.source.slice(start, this.position));
497
+ }
498
+ parseIdentifier() {
499
+ const start = this.position;
500
+ while (!this.done() && /[A-Za-z0-9_./:-]/.test(this.peek())) this.position += 1;
501
+ if (this.peek() === "[") {
502
+ this.position += 1;
503
+ while (!this.done() && this.peek() !== "]") {
504
+ if (!/[A-Za-z0-9_./:-]/.test(this.peek())) break;
505
+ this.position += 1;
506
+ }
507
+ if (this.peek() === "]") this.position += 1;
508
+ }
509
+ return this.source.slice(start, this.position);
510
+ }
511
+ parseStringName() {
512
+ this.position += 1;
513
+ if (this.peek() === "\"" || this.peek() === "'") return {
514
+ type: "StringName",
515
+ args: [this.parseString()]
516
+ };
517
+ this.warn("godot_parser_string_name_expected_string", "Expected quoted string after '&' StringName marker.");
518
+ return {
519
+ type: "StringName",
520
+ args: [""]
521
+ };
522
+ }
523
+ parseCall(name) {
524
+ this.position += 1;
525
+ const args = [];
526
+ while (!this.done()) {
527
+ this.skipTrivia();
528
+ if (this.peek() === ")") {
529
+ this.position += 1;
530
+ return callValue(name, args);
531
+ }
532
+ args.push(this.parseValue());
533
+ this.skipTrivia();
534
+ if (this.peek() === ",") this.position += 1;
535
+ }
536
+ this.warn("godot_parser_unterminated_call", `Unterminated Godot call ${name}(...).`);
537
+ return callValue(name, args);
538
+ }
539
+ warn(code, message) {
540
+ this.diagnostics.push({
541
+ severity: "warning",
542
+ code,
543
+ message,
544
+ line: this.line,
545
+ column: this.position + 1
546
+ });
547
+ }
548
+ };
549
+ function callValue(name, args) {
550
+ const numericArgs = args.map((arg) => typeof arg === "number" ? arg : NaN);
551
+ switch (name) {
552
+ case "Vector2":
553
+ case "Vector2i":
554
+ case "Vector3":
555
+ case "Vector3i":
556
+ case "Vector4":
557
+ case "Vector4i": return {
558
+ type: name,
559
+ args: numericArgs
560
+ };
561
+ case "Color": return {
562
+ type: "Color",
563
+ args: numericArgs
564
+ };
565
+ case "Rect2":
566
+ case "Rect2i": return {
567
+ type: name,
568
+ args: numericArgs
569
+ };
570
+ case "NodePath": return {
571
+ type: "NodePath",
572
+ args: [typeof args[0] === "string" ? args[0] : ""]
573
+ };
574
+ case "ExtResource":
575
+ case "SubResource": return {
576
+ type: name,
577
+ id: String(args[0] ?? "")
578
+ };
579
+ default: return {
580
+ type: name,
581
+ args
582
+ };
583
+ }
584
+ }
585
+ function decodeEscape(char) {
586
+ switch (char) {
587
+ case "n": return "\n";
588
+ case "r": return "\r";
589
+ case "t": return " ";
590
+ default: return char;
591
+ }
592
+ }
593
+ function dictionaryKey(value) {
594
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
595
+ if (value && typeof value === "object" && !Array.isArray(value) && "type" in value && value.type === "StringName" && "args" in value && Array.isArray(value.args) && typeof value.args[0] === "string") return value.args[0];
596
+ return JSON.stringify(value);
597
+ }
598
+ function isDigit(value) {
599
+ return value >= "0" && value <= "9";
600
+ }
601
+ //#endregion
602
+ export { parseGodotResource, parseGodotTextScene, parseGodotValue };
603
+
604
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type {\n GodotConnection,\n GodotDocumentKind,\n GodotEditable,\n GodotExtResource,\n GodotNode,\n GodotParseDiagnostic,\n GodotResource,\n GodotResourceRefValue,\n GodotSceneState,\n GodotSceneStateConnection,\n GodotSceneStateNode,\n GodotSectionHeader,\n GodotSubResource,\n GodotVariant,\n} from \"@godot-scene-web/core\";\n\ninterface ParsedDocument {\n kind: GodotDocumentKind;\n header: GodotSectionHeader | null;\n extResources: GodotExtResource[];\n subResources: GodotSubResource[];\n nodes: GodotNode[];\n connections: GodotConnection[];\n editables: GodotEditable[];\n properties: Record<string, GodotVariant>;\n diagnostics: GodotParseDiagnostic[];\n}\n\ntype CurrentSection =\n | { kind: \"header\"; header: GodotSectionHeader }\n | { kind: \"ext_resource\"; resource: GodotExtResource }\n | { kind: \"sub_resource\"; resource: GodotSubResource }\n | { kind: \"node\"; node: GodotNode }\n | { kind: \"connection\"; connection: GodotConnection }\n | { kind: \"editable\"; editable: GodotEditable }\n | { kind: \"resource\" }\n | { kind: \"document\" };\n\nexport interface ParseGodotTextOptions {\n path?: string;\n kind?: GodotDocumentKind;\n}\n\nexport function parseGodotTextScene(\n text: string,\n options: ParseGodotTextOptions = {},\n): GodotSceneState {\n return godotSceneStateFromDocument(\n parseDocument(text, { ...options, kind: \"scene\" }),\n );\n}\n\nexport function parseGodotResource(\n text: string,\n options: ParseGodotTextOptions = {},\n): GodotResource {\n return godotResourceFromDocument(\n parseDocument(text, { ...options, kind: \"resource\" }),\n );\n}\n\nfunction parseDocument(\n text: string,\n options: ParseGodotTextOptions = {},\n): ParsedDocument {\n const kind = options.kind ?? \"resource\";\n const diagnostics: GodotParseDiagnostic[] = [];\n const document: ParsedDocument = {\n kind,\n header: null,\n extResources: [],\n subResources: [],\n nodes: [],\n connections: [],\n editables: [],\n properties: {},\n diagnostics,\n };\n let current: CurrentSection = { kind: \"document\" };\n const lines = text.replace(/^\\uFEFF/, \"\").split(/\\r?\\n/);\n\n for (let index = 0; index < lines.length; index += 1) {\n const lineNumber = index + 1;\n const logical = collectLogicalLine(lines, index);\n index = logical.endIndex;\n const line = stripLineComment(logical.raw).trim();\n if (line.length === 0) {\n continue;\n }\n if (line.startsWith(\"[\") && line.endsWith(\"]\")) {\n current = parseSectionHeader(\n line.slice(1, -1),\n lineNumber,\n diagnostics,\n document,\n );\n continue;\n }\n const assignment = splitAssignment(line);\n if (!assignment) {\n diagnostics.push({\n severity: \"warning\",\n code: \"godot_parser_unsupported_line\",\n message: \"Unsupported Godot text line.\",\n line: lineNumber,\n });\n continue;\n }\n const value = parseGodotValue(assignment.value, diagnostics, lineNumber);\n assignProperty(document, current, assignment.key, value);\n }\n\n return document;\n}\n\nexport function parseGodotValue(\n source: string,\n diagnostics: GodotParseDiagnostic[] = [],\n line?: number,\n): GodotVariant {\n const parser = new ValueParser(source, diagnostics, line);\n const value = parser.parseValue();\n parser.skipTrivia();\n if (!parser.done()) {\n diagnostics.push({\n severity: \"warning\",\n code: \"godot_parser_trailing_value_text\",\n message: `Trailing text after Godot value: ${source.slice(parser.position)}`,\n line,\n });\n }\n return value;\n}\n\nfunction parseSectionHeader(\n source: string,\n line: number,\n diagnostics: GodotParseDiagnostic[],\n document: ParsedDocument,\n): CurrentSection {\n const [section = \"\", ...attributeParts] = splitHeaderParts(source);\n const attributes = parseHeaderAttributes(\n attributeParts.join(\" \"),\n diagnostics,\n line,\n );\n switch (section) {\n case \"gd_scene\":\n case \"gd_resource\": {\n const header = { section, attributes };\n document.header = header;\n document.kind = section === \"gd_scene\" ? \"scene\" : \"resource\";\n return { kind: \"header\", header };\n }\n case \"ext_resource\": {\n const id = stringAttribute(attributes.id) ?? \"\";\n const resource: GodotExtResource = {\n id,\n type: stringAttribute(attributes.type),\n path: stringAttribute(attributes.path),\n uid: stringAttribute(attributes.uid),\n attributes,\n properties: {},\n };\n document.extResources.push(resource);\n return { kind: \"ext_resource\", resource };\n }\n case \"sub_resource\": {\n const id = stringAttribute(attributes.id) ?? \"\";\n const resource: GodotSubResource = {\n id,\n type: stringAttribute(attributes.type),\n attributes,\n properties: {},\n };\n document.subResources.push(resource);\n return { kind: \"sub_resource\", resource };\n }\n case \"node\": {\n const node: GodotNode = {\n name: stringAttribute(attributes.name) ?? \"\",\n type: stringAttribute(attributes.type),\n parent: stringAttribute(attributes.parent),\n instance: resourceRefAttribute(attributes.instance),\n attributes,\n properties: {},\n };\n document.nodes.push(node);\n return { kind: \"node\", node };\n }\n case \"connection\": {\n const connection: GodotConnection = {\n signal: stringAttribute(attributes.signal),\n from: stringAttribute(attributes.from),\n to: stringAttribute(attributes.to),\n method: stringAttribute(attributes.method),\n attributes,\n };\n document.connections.push(connection);\n return { kind: \"connection\", connection };\n }\n case \"editable\": {\n const editable: GodotEditable = {\n path: stringAttribute(attributes.path),\n attributes,\n };\n document.editables.push(editable);\n return { kind: \"editable\", editable };\n }\n case \"resource\":\n return { kind: \"resource\" };\n default:\n diagnostics.push({\n severity: \"warning\",\n code: \"godot_parser_unknown_section\",\n message: `Unknown Godot text section: ${section}`,\n line,\n });\n return { kind: \"document\" };\n }\n}\n\nfunction assignProperty(\n document: ParsedDocument,\n current: CurrentSection,\n key: string,\n value: GodotVariant,\n): void {\n switch (current.kind) {\n case \"ext_resource\":\n current.resource.properties[key] = value;\n break;\n case \"sub_resource\":\n current.resource.properties[key] = value;\n break;\n case \"node\":\n current.node.properties[key] = value;\n current.node.propertyEntries ??= [];\n current.node.propertyEntries.push({ name: key, value });\n break;\n case \"header\":\n current.header.attributes[key] = value;\n break;\n case \"connection\":\n current.connection.attributes[key] = value;\n break;\n case \"editable\":\n current.editable.attributes[key] = value;\n break;\n case \"resource\":\n document.properties[key] = value;\n break;\n case \"document\":\n document.properties[key] = value;\n break;\n }\n}\n\nfunction godotSceneStateFromDocument(\n document: ParsedDocument,\n): GodotSceneState {\n const basePath = stringAttribute(document.header?.attributes.path);\n return {\n kind: \"scene\",\n nodes: document.nodes.map(godotSceneStateNodeFromDocumentNode),\n connections: document.connections.map(\n godotSceneStateConnectionFromDocumentConnection,\n ),\n extResources: document.extResources,\n subResources: document.subResources,\n editableInstances: document.editables\n .map((editable) => editable.path)\n .filter((path): path is string => typeof path === \"string\"),\n ...(basePath ? { basePath } : {}),\n diagnostics: document.diagnostics,\n };\n}\n\nfunction godotResourceFromDocument(document: ParsedDocument): GodotResource {\n return {\n type: stringAttribute(document.header?.attributes.type),\n header: document.header,\n extResources: document.extResources,\n subResources: document.subResources,\n properties: document.properties,\n diagnostics: document.diagnostics,\n };\n}\n\nfunction godotSceneStateNodeFromDocumentNode(\n node: GodotNode,\n index: number,\n): GodotSceneStateNode {\n const owner = stringAttribute(node.attributes.owner);\n const instancePlaceholder =\n stringAttribute(node.attributes.instance_placeholder) ??\n stringAttribute(node.attributes.instancePlaceholder);\n const siblingIndex = nodeIndexAttribute(node.attributes.index);\n return {\n index,\n ...(siblingIndex !== undefined ? { siblingIndex } : {}),\n name: node.name,\n ...(node.type !== undefined ? { type: node.type } : {}),\n parent: node.parent ?? \".\",\n ...(owner !== undefined ? { owner } : {}),\n ...(node.instance !== undefined ? { instance: node.instance } : {}),\n ...(instancePlaceholder !== undefined ? { instancePlaceholder } : {}),\n groups: stringArrayAttribute(node.attributes.groups),\n properties:\n node.propertyEntries?.map((property) => ({ ...property })) ??\n Object.entries(node.properties).map(([name, value]) => ({ name, value })),\n };\n}\n\nfunction godotSceneStateConnectionFromDocumentConnection(\n connection: GodotConnection,\n): GodotSceneStateConnection {\n const flags = numberAttribute(connection.attributes.flags);\n const binds = godotValueArrayAttribute(connection.attributes.binds);\n const unbinds = numberAttribute(connection.attributes.unbinds);\n return {\n ...(connection.signal !== undefined ? { signal: connection.signal } : {}),\n ...(connection.from !== undefined ? { from: connection.from } : {}),\n ...(connection.to !== undefined ? { to: connection.to } : {}),\n ...(connection.method !== undefined ? { method: connection.method } : {}),\n ...(flags !== undefined ? { flags } : {}),\n ...(binds !== undefined ? { binds } : {}),\n ...(unbinds !== undefined ? { unbinds } : {}),\n };\n}\n\nfunction collectLogicalLine(\n lines: string[],\n startIndex: number,\n): { raw: string; endIndex: number } {\n // Scan incrementally, carrying the open-value state across appended lines —\n // re-scanning the accumulated string per appended line is quadratic, which\n // dominated whole-document parse time on multi-line values (packed arrays,\n // animation tracks, shader code in .tres).\n const state = newOpenValueState();\n const parts = [lines[startIndex] ?? \"\"];\n scanOpenValue(parts[0], state);\n let endIndex = startIndex;\n while (isOpenValue(state) && endIndex + 1 < lines.length) {\n endIndex += 1;\n const line = lines[endIndex] ?? \"\";\n parts.push(line);\n scanOpenValue(`\\n${line}`, state);\n }\n return { raw: parts.join(\"\\n\"), endIndex };\n}\n\ninterface OpenValueState {\n quote: string | null;\n escaped: boolean;\n inComment: boolean;\n squareDepth: number;\n curlyDepth: number;\n parenDepth: number;\n}\n\nfunction newOpenValueState(): OpenValueState {\n return {\n quote: null,\n escaped: false,\n inComment: false,\n squareDepth: 0,\n curlyDepth: 0,\n parenDepth: 0,\n };\n}\n\nfunction isOpenValue(state: OpenValueState): boolean {\n return (\n state.quote !== null ||\n state.squareDepth > 0 ||\n state.curlyDepth > 0 ||\n state.parenDepth > 0\n );\n}\n\nfunction scanOpenValue(source: string, state: OpenValueState): void {\n for (let index = 0; index < source.length; index += 1) {\n const char = source[index];\n if (state.inComment) {\n if (char === \"\\n\") {\n state.inComment = false;\n }\n continue;\n }\n if (state.quote) {\n if (state.escaped) {\n state.escaped = false;\n } else if (char === \"\\\\\") {\n state.escaped = true;\n } else if (char === state.quote) {\n state.quote = null;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n state.quote = char;\n } else if (char === \";\") {\n state.inComment = true;\n } else if (char === \"[\") {\n state.squareDepth += 1;\n } else if (char === \"]\") {\n state.squareDepth = Math.max(0, state.squareDepth - 1);\n } else if (char === \"{\") {\n state.curlyDepth += 1;\n } else if (char === \"}\") {\n state.curlyDepth = Math.max(0, state.curlyDepth - 1);\n } else if (char === \"(\") {\n state.parenDepth += 1;\n } else if (char === \")\") {\n state.parenDepth = Math.max(0, state.parenDepth - 1);\n }\n }\n}\n\nfunction stripLineComment(line: string): string {\n let quote: string | null = null;\n let escaped = false;\n for (let index = 0; index < line.length; index += 1) {\n const char = line[index];\n if (quote) {\n if (escaped) {\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === quote) {\n quote = null;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n } else if (char === \";\") {\n return line.slice(0, index);\n }\n }\n return line;\n}\n\nfunction splitAssignment(line: string): { key: string; value: string } | null {\n const index = line.indexOf(\"=\");\n if (index < 0) {\n return null;\n }\n return {\n key: line.slice(0, index).trim(),\n value: line.slice(index + 1).trim(),\n };\n}\n\nfunction splitHeaderParts(source: string): string[] {\n const parts: string[] = [];\n let quote: string | null = null;\n let escaped = false;\n let start = 0;\n for (let index = 0; index < source.length; index += 1) {\n const char = source[index];\n if (quote) {\n if (escaped) {\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === quote) {\n quote = null;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n } else if (/\\s/.test(char)) {\n if (index > start) {\n parts.push(source.slice(start, index));\n }\n start = index + 1;\n }\n }\n if (start < source.length) {\n parts.push(source.slice(start));\n }\n return parts;\n}\n\nfunction parseHeaderAttributes(\n source: string,\n diagnostics: GodotParseDiagnostic[],\n line: number,\n): Record<string, GodotVariant> {\n const attributes: Record<string, GodotVariant> = {};\n const attrPattern = /([A-Za-z0-9_./-]+)=/g;\n const matches = [...source.matchAll(attrPattern)];\n for (let index = 0; index < matches.length; index += 1) {\n const match = matches[index];\n if (match.index === undefined) {\n continue;\n }\n const key = match[1] ?? \"\";\n const valueStart = match.index + match[0].length;\n const valueEnd = matches[index + 1]?.index ?? source.length;\n attributes[key] = parseGodotValue(\n source.slice(valueStart, valueEnd).trim(),\n diagnostics,\n line,\n );\n }\n return attributes;\n}\n\nfunction stringAttribute(value: GodotVariant | undefined): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction numberAttribute(value: GodotVariant | undefined): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined;\n}\n\n// Godot serializes the node header `index` as a quoted string (e.g. `index=\"3\"`),\n// so accept a numeric string as well as a bare number.\nfunction nodeIndexAttribute(\n value: GodotVariant | undefined,\n): number | undefined {\n if (typeof value === \"number\" && Number.isInteger(value)) {\n return value;\n }\n if (typeof value === \"string\" && /^-?\\d+$/.test(value)) {\n return Number(value);\n }\n return undefined;\n}\n\nfunction stringArrayAttribute(value: GodotVariant | undefined): string[] {\n return Array.isArray(value)\n ? value.filter((item): item is string => typeof item === \"string\")\n : [];\n}\n\nfunction godotValueArrayAttribute(\n value: GodotVariant | undefined,\n): GodotVariant[] | undefined {\n return Array.isArray(value) ? value : undefined;\n}\n\nfunction resourceRefAttribute(\n value: GodotVariant | undefined,\n): GodotResourceRefValue | undefined {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"type\" in value &&\n (value.type === \"ExtResource\" || value.type === \"SubResource\") &&\n \"id\" in value &&\n typeof value.id === \"string\"\n ) {\n const type = value.type;\n return { type, id: value.id };\n }\n return undefined;\n}\n\nclass ValueParser {\n position = 0;\n\n constructor(\n private readonly source: string,\n private readonly diagnostics: GodotParseDiagnostic[],\n private readonly line?: number,\n ) {}\n\n parseValue(): GodotVariant {\n this.skipTrivia();\n const char = this.peek();\n if (char === '\"' || char === \"'\") {\n return this.parseString();\n }\n if (char === \"[\") {\n return this.parseArray();\n }\n if (char === \"{\") {\n return this.parseDictionary();\n }\n if (char === \"&\") {\n return this.parseStringName();\n }\n if (char === \"-\" || char === \"+\" || char === \".\" || isDigit(char)) {\n return this.parseNumber();\n }\n const ident = this.parseIdentifier();\n if (ident.length === 0) {\n this.warn(\"godot_parser_empty_value\", \"Expected a Godot value.\");\n return null;\n }\n if (ident === \"true\") {\n return true;\n }\n if (ident === \"false\") {\n return false;\n }\n if (ident === \"null\" || ident === \"nil\") {\n return null;\n }\n this.skipTrivia();\n if (this.peek() === \"(\") {\n return this.parseCall(ident);\n }\n return ident;\n }\n\n skipTrivia(): void {\n while (!this.done() && /\\s/.test(this.peek())) {\n this.position += 1;\n }\n }\n\n done(): boolean {\n return this.position >= this.source.length;\n }\n\n peek(): string {\n return this.source[this.position] ?? \"\";\n }\n\n private parseString(): string {\n const quote = this.peek();\n this.position += 1;\n let result = \"\";\n let escaped = false;\n while (!this.done()) {\n const char = this.peek();\n this.position += 1;\n if (escaped) {\n result += decodeEscape(char);\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === quote) {\n return result;\n } else {\n result += char;\n }\n }\n this.warn(\"godot_parser_unterminated_string\", \"Unterminated Godot string.\");\n return result;\n }\n\n private parseArray(): GodotVariant[] {\n this.position += 1;\n const values: GodotVariant[] = [];\n while (!this.done()) {\n this.skipTrivia();\n if (this.peek() === \"]\") {\n this.position += 1;\n return values;\n }\n values.push(this.parseValue());\n this.skipTrivia();\n if (this.peek() === \",\") {\n this.position += 1;\n }\n }\n this.warn(\"godot_parser_unterminated_array\", \"Unterminated Godot array.\");\n return values;\n }\n\n private parseDictionary(): Record<string, GodotVariant> {\n this.position += 1;\n const result: Record<string, GodotVariant> = {};\n while (!this.done()) {\n this.skipTrivia();\n if (this.peek() === \"}\") {\n this.position += 1;\n return result;\n }\n const keyValue = this.parseValue();\n this.skipTrivia();\n if (this.peek() !== \":\") {\n this.warn(\n \"godot_parser_dictionary_colon_missing\",\n \"Expected ':' in Godot dictionary.\",\n );\n return result;\n }\n this.position += 1;\n const value = this.parseValue();\n result[dictionaryKey(keyValue)] = value;\n this.skipTrivia();\n if (this.peek() === \",\") {\n this.position += 1;\n }\n }\n this.warn(\n \"godot_parser_unterminated_dictionary\",\n \"Unterminated Godot dictionary.\",\n );\n return result;\n }\n\n private parseNumber(): number {\n const start = this.position;\n if (this.peek() === \"+\" || this.peek() === \"-\") {\n this.position += 1;\n }\n while (isDigit(this.peek())) {\n this.position += 1;\n }\n if (this.peek() === \".\") {\n this.position += 1;\n while (isDigit(this.peek())) {\n this.position += 1;\n }\n }\n if (this.peek().toLowerCase() === \"e\") {\n this.position += 1;\n if (this.peek() === \"+\" || this.peek() === \"-\") {\n this.position += 1;\n }\n while (isDigit(this.peek())) {\n this.position += 1;\n }\n }\n return Number(this.source.slice(start, this.position));\n }\n\n private parseIdentifier(): string {\n const start = this.position;\n while (!this.done() && /[A-Za-z0-9_./:-]/.test(this.peek())) {\n this.position += 1;\n }\n if (this.peek() === \"[\") {\n this.position += 1;\n while (!this.done() && this.peek() !== \"]\") {\n if (!/[A-Za-z0-9_./:-]/.test(this.peek())) {\n break;\n }\n this.position += 1;\n }\n if (this.peek() === \"]\") {\n this.position += 1;\n }\n }\n return this.source.slice(start, this.position);\n }\n\n private parseStringName(): GodotVariant {\n this.position += 1;\n if (this.peek() === '\"' || this.peek() === \"'\") {\n return { type: \"StringName\", args: [this.parseString()] };\n }\n this.warn(\n \"godot_parser_string_name_expected_string\",\n \"Expected quoted string after '&' StringName marker.\",\n );\n return { type: \"StringName\", args: [\"\"] };\n }\n\n private parseCall(name: string): GodotVariant {\n this.position += 1;\n const args: GodotVariant[] = [];\n while (!this.done()) {\n this.skipTrivia();\n if (this.peek() === \")\") {\n this.position += 1;\n return callValue(name, args);\n }\n args.push(this.parseValue());\n this.skipTrivia();\n if (this.peek() === \",\") {\n this.position += 1;\n }\n }\n this.warn(\n \"godot_parser_unterminated_call\",\n `Unterminated Godot call ${name}(...).`,\n );\n return callValue(name, args);\n }\n\n private warn(code: string, message: string): void {\n this.diagnostics.push({\n severity: \"warning\",\n code,\n message,\n line: this.line,\n column: this.position + 1,\n });\n }\n}\n\nfunction callValue(name: string, args: GodotVariant[]): GodotVariant {\n const numericArgs = args.map((arg) =>\n typeof arg === \"number\" ? arg : Number.NaN,\n );\n switch (name) {\n case \"Vector2\":\n case \"Vector2i\":\n case \"Vector3\":\n case \"Vector3i\":\n case \"Vector4\":\n case \"Vector4i\":\n return { type: name, args: numericArgs };\n case \"Color\":\n return { type: \"Color\", args: numericArgs };\n case \"Rect2\":\n case \"Rect2i\":\n return { type: name, args: numericArgs };\n case \"NodePath\":\n return {\n type: \"NodePath\",\n args: [typeof args[0] === \"string\" ? args[0] : \"\"],\n };\n case \"ExtResource\":\n case \"SubResource\":\n return { type: name, id: String(args[0] ?? \"\") };\n default:\n // Any other constructor (PackedVector2Array, Transform2D, …): keep the\n // engine-native `{ type, args }` shape with the constructor name as type.\n return { type: name, args };\n }\n}\n\nfunction decodeEscape(char: string): string {\n switch (char) {\n case \"n\":\n return \"\\n\";\n case \"r\":\n return \"\\r\";\n case \"t\":\n return \"\\t\";\n default:\n return char;\n }\n}\n\nfunction dictionaryKey(value: GodotVariant): string {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return String(value);\n }\n if (\n value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n \"type\" in value &&\n value.type === \"StringName\" &&\n \"args\" in value &&\n Array.isArray(value.args) &&\n typeof value.args[0] === \"string\"\n ) {\n return value.args[0];\n }\n return JSON.stringify(value);\n}\n\nfunction isDigit(value: string): boolean {\n return value >= \"0\" && value <= \"9\";\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@godot-scene-web/tscn-parser",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "description": "Parser for Godot .tscn and .tres text resources.",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "registry": "https://registry.npmjs.org/"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/tfoxy/godot-scene-web.git"
14
+ },
15
+ "homepage": "https://github.com/tfoxy/godot-scene-web#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/tfoxy/godot-scene-web/issues"
18
+ },
19
+ "sideEffects": false,
20
+ "exports": {
21
+ ".": {
22
+ "development": "./src/index.ts",
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ }
26
+ },
27
+ "main": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
+ "files": [
30
+ "dist",
31
+ "LICENSE"
32
+ ],
33
+ "devDependencies": {
34
+ "@godot-scene-web/core": "0.1.0"
35
+ },
36
+ "scripts": {
37
+ "build": "tsdown",
38
+ "typecheck": "tsc -p tsconfig.json --noEmit",
39
+ "test": "vitest run --root ../.. --config ../../vitest.config.ts packages/tscn-parser/test"
40
+ }
41
+ }