@gi.ts/parser 4.0.0-beta.40 → 4.0.0-beta.42
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/package.json +3 -2
- package/src/gir-types.ts +2 -0
- package/src/parser.ts +32 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gi.ts/parser",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.42",
|
|
4
4
|
"description": "Parser for GObject Introspection XML files",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -29,9 +29,10 @@
|
|
|
29
29
|
"check": "tsc --noEmit"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"fast-xml-parser": "^5.
|
|
32
|
+
"fast-xml-parser": "^5.5.8"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
+
"@ts-for-gir/tsconfig": "^4.0.0-beta.42",
|
|
35
36
|
"typescript": "^5.9.3"
|
|
36
37
|
}
|
|
37
38
|
}
|
package/src/gir-types.ts
CHANGED
|
@@ -842,6 +842,8 @@ export interface GirCallbackElement extends PartOfModule, GirInfoElements {
|
|
|
842
842
|
"c:type"?: string;
|
|
843
843
|
/** Binary attribute, true if the callback can throw an error */
|
|
844
844
|
throws?: GirBoolean;
|
|
845
|
+
/** GObject compatible type name of the callback */
|
|
846
|
+
"glib:type-name"?: string;
|
|
845
847
|
};
|
|
846
848
|
|
|
847
849
|
/* Other elements a property can contain */
|
package/src/parser.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { XMLParser } from "fast-xml-parser";
|
|
2
2
|
import type { GirXML } from "./gir-types.ts";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* fast-xml-parser v5.5.5+ blocks "constructor" as a tag name to prevent
|
|
6
|
+
* prototype pollution. GIR files legitimately use <constructor> elements,
|
|
7
|
+
* so we rename it during parsing and restore it in post-processing.
|
|
8
|
+
*/
|
|
9
|
+
const CRITICAL_TAG_REPLACEMENTS: Record<string, string> = {
|
|
10
|
+
constructor: "__gir_constructor__",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const CRITICAL_TAG_RESTORATIONS: Record<string, string> = Object.fromEntries(
|
|
14
|
+
Object.entries(CRITICAL_TAG_REPLACEMENTS).map(([k, v]) => [v, k]),
|
|
15
|
+
);
|
|
16
|
+
|
|
4
17
|
// TODO: Treat properties that contain only one element like `repository`, 'namespace', 'package', ... as an object instead of an array
|
|
5
18
|
const isArrayProperty = [
|
|
6
19
|
"type",
|
|
@@ -11,7 +24,7 @@ const isArrayProperty = [
|
|
|
11
24
|
"parameters",
|
|
12
25
|
"return-value",
|
|
13
26
|
"class",
|
|
14
|
-
"
|
|
27
|
+
"__gir_constructor__",
|
|
15
28
|
"constructors",
|
|
16
29
|
"method",
|
|
17
30
|
"virtual-method",
|
|
@@ -64,6 +77,11 @@ const parser = new XMLParser({
|
|
|
64
77
|
parseTagValue: true,
|
|
65
78
|
parseAttributeValue: false,
|
|
66
79
|
trimValues: true,
|
|
80
|
+
processEntities: {
|
|
81
|
+
enabled: true,
|
|
82
|
+
maxTotalExpansions: 100_000,
|
|
83
|
+
},
|
|
84
|
+
transformTagName: (tagName: string) => CRITICAL_TAG_REPLACEMENTS[tagName] ?? tagName,
|
|
67
85
|
isArray: (name, _jpath, isLeafNode, _isAttribute) => {
|
|
68
86
|
// Restore previous behaviour...
|
|
69
87
|
if (isArrayProperty.includes(name)) {
|
|
@@ -74,17 +92,17 @@ const parser = new XMLParser({
|
|
|
74
92
|
});
|
|
75
93
|
|
|
76
94
|
/**
|
|
77
|
-
* Recursively
|
|
78
|
-
*
|
|
79
|
-
*
|
|
95
|
+
* Recursively post-processes the parsed XML tree:
|
|
96
|
+
* - Converts numeric string attributes to actual numbers
|
|
97
|
+
* - Restores tag names that were renamed to bypass fast-xml-parser's security checks
|
|
80
98
|
*/
|
|
81
|
-
function
|
|
99
|
+
function postProcessParsedXml(obj: unknown): unknown {
|
|
82
100
|
if (obj === null || typeof obj !== "object") {
|
|
83
101
|
return obj;
|
|
84
102
|
}
|
|
85
103
|
|
|
86
104
|
if (Array.isArray(obj)) {
|
|
87
|
-
return obj.map(
|
|
105
|
+
return obj.map(postProcessParsedXml);
|
|
88
106
|
}
|
|
89
107
|
|
|
90
108
|
const result = { ...obj } as Record<string, unknown>;
|
|
@@ -102,10 +120,15 @@ function transformNumericAttributes(obj: unknown): unknown {
|
|
|
102
120
|
}
|
|
103
121
|
}
|
|
104
122
|
|
|
105
|
-
// Recursively transform nested objects
|
|
123
|
+
// Recursively transform nested objects and restore renamed tag keys
|
|
106
124
|
for (const key in result) {
|
|
107
125
|
if (key !== "$" && result[key] !== null && typeof result[key] === "object") {
|
|
108
|
-
result[key] =
|
|
126
|
+
result[key] = postProcessParsedXml(result[key]);
|
|
127
|
+
}
|
|
128
|
+
const restoredKey = CRITICAL_TAG_RESTORATIONS[key];
|
|
129
|
+
if (restoredKey) {
|
|
130
|
+
result[restoredKey] = result[key];
|
|
131
|
+
delete result[key];
|
|
109
132
|
}
|
|
110
133
|
}
|
|
111
134
|
|
|
@@ -114,5 +137,5 @@ function transformNumericAttributes(obj: unknown): unknown {
|
|
|
114
137
|
|
|
115
138
|
export function parseGir(contents: string): GirXML {
|
|
116
139
|
const parsed = parser.parse(contents);
|
|
117
|
-
return
|
|
140
|
+
return postProcessParsedXml(parsed) as GirXML;
|
|
118
141
|
}
|