discord-protos 1.0.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/src/parse.js ADDED
@@ -0,0 +1,212 @@
1
+ if (!getModules) {
2
+ var filterMap = (arr, callback) => arr.filter(callback).map(callback)
3
+
4
+ function getModules(str) {
5
+ webpackChunkdiscord_app.push([["discord-protos"], {}, r => cache=Object.values(r.c)]);
6
+
7
+ return filterMap(cache, x => Object.values(x.exports||{}).find(v=>v && v[str]))
8
+ }
9
+ }
10
+
11
+ // Map the type ints to their names
12
+ const REAL_TYPES = {
13
+ 1: "double",
14
+ 2: "float",
15
+ 3: "int64",
16
+ 4: "uint64",
17
+ 5: "int32",
18
+ 6: "fixed64",
19
+ 8: "bool",
20
+ 9: "string",
21
+ 12: "bytes",
22
+ 13: "uint32",
23
+ };
24
+
25
+ function parseType(field) {
26
+ // We extract the actual field if possible
27
+ if (typeof field === "function") {
28
+ field = field();
29
+ // If it's a real type, we just return it
30
+ } else if (typeof field === "number") {
31
+ return [REAL_TYPES[field], []];
32
+ }
33
+
34
+ var type,
35
+ structs = [];
36
+
37
+ // The kind gives us clues on how to find the type
38
+ switch (field.kind) {
39
+ case "message":
40
+ type = field.T().typeName;
41
+ if (type.startsWith("discord")) {
42
+ type = parseName(type);
43
+ }
44
+ break;
45
+ case "scalar":
46
+ type = REAL_TYPES[field.T];
47
+ break;
48
+ case "map":
49
+ type = `map<${parseType(field.K)[0]}, ${parseType(field.V)[0]}>`;
50
+ break;
51
+ case "enum":
52
+ type = parseName(field.T()[0]);
53
+ break;
54
+ default:
55
+ throw new Error(`Unknown field type: ${field?.kind || field}`);
56
+ }
57
+
58
+ // Now we lazily discover any protos in the fields
59
+ for (let t of [field.T, field.K, field.V]) {
60
+ t = t?.T || t;
61
+
62
+ if (
63
+ typeof t === "function" &&
64
+ (!t().typeName || t().typeName.startsWith("discord_protos"))
65
+ ) {
66
+ t = t();
67
+ if (Array.isArray(t)) {
68
+ structs.push(parseEnum(t));
69
+ } else {
70
+ const extraStruct = parseProto(t);
71
+ structs.push(...(extraStruct.structs || []));
72
+ delete extraStruct.structs;
73
+ structs.push(extraStruct);
74
+ }
75
+ }
76
+ }
77
+
78
+ return [type, structs];
79
+ }
80
+
81
+ function parseName(name) {
82
+ return name.split(".").slice(-1)[0];
83
+ }
84
+
85
+ function flattenField(field) {
86
+ const [type, structs] = parseType(field);
87
+ return [
88
+ {
89
+ number: field.no,
90
+ name: field.name,
91
+ kind: field.kind,
92
+ type: type,
93
+ optional: field.opt,
94
+ repeated: Boolean(field.repeat),
95
+ },
96
+ structs,
97
+ ];
98
+ }
99
+
100
+ function parseEnum(enun) {
101
+ const [name, data] = enun;
102
+ return {
103
+ name: parseName(name),
104
+ kind: "enum",
105
+ values: Object.entries(data)
106
+ .filter(([k, _]) => isNaN(Number(k)))
107
+ .map(([k, v]) => ({
108
+ name: k,
109
+ value: v,
110
+ })),
111
+ };
112
+ }
113
+
114
+ function parseProto(proto) {
115
+ const fields = [];
116
+ const structs = [];
117
+ proto.fields.forEach(function (field) {
118
+ const [f, s] = flattenField(field);
119
+ fields.push(f);
120
+ structs.push(...s);
121
+ });
122
+
123
+ const seen = new Set();
124
+ return {
125
+ name: parseName(proto.typeName),
126
+ kind: "message",
127
+ fields: fields,
128
+ structs: structs.filter((v) =>
129
+ seen.has(v.name) ? false : seen.add(v.name),
130
+ ),
131
+ };
132
+ }
133
+
134
+ function extractProtos() {
135
+ const results = {};
136
+ for (const proto of getModules("typeName")) {
137
+ if (!proto.typeName.includes("Settings")) {
138
+ continue;
139
+ }
140
+ const name = parseName(proto.typeName);
141
+ console.log(`Parsing ${name}...`);
142
+ results[name] = parseProto(proto);
143
+ }
144
+ return results;
145
+ }
146
+
147
+ function createProtoField(field) {
148
+ return `${
149
+ field.optional ? "optional " : field.repeated ? "repeated " : ""
150
+ }${field.type} ${field.name} = ${field.number};`;
151
+ }
152
+
153
+ function createProtoFile(proto) {
154
+ const lines = [
155
+ `syntax = "proto3";\n`,
156
+ `package discord_protos.discord_users.v1.${proto.name};\n`,
157
+ `message ${proto.name} {`,
158
+ ];
159
+
160
+ proto.structs.forEach((struct) => {
161
+ lines.push(` ${struct.kind} ${struct.name} {`);
162
+
163
+ switch (struct.kind) {
164
+ case "enum":
165
+ struct.values.forEach((value) => {
166
+ lines.push(
167
+ ` ${value.name.toUpperCase()} = ${value.value};`,
168
+ );
169
+ });
170
+ break;
171
+ case "message":
172
+ struct.fields.forEach((field) => {
173
+ lines.push(` ${createProtoField(field)}`);
174
+ });
175
+ break;
176
+ default:
177
+ throw new Error(`Unknown struct kind: ${struct.kind}`);
178
+ }
179
+
180
+ lines.push(` }\n`);
181
+ });
182
+
183
+ proto.fields.forEach((field) => {
184
+ lines.push(` ${createProtoField(field)}`);
185
+ });
186
+
187
+ // Check if we're using the funny Google well-knowns and insert an import statement (I love Discord)
188
+ if (lines.some((line) => line.includes("google.protobuf"))) {
189
+ lines.splice(
190
+ 1,
191
+ 0,
192
+ `import "google/protobuf/wrappers.proto";\nimport "google/protobuf/timestamp.proto";\n`,
193
+ );
194
+ }
195
+
196
+ lines.push("}\n");
197
+ return lines.join("\n");
198
+ }
199
+
200
+ const protos = extractProtos();
201
+ for (const [key, proto] of Object.entries(protos)) {
202
+ const data = createProtoFile(proto);
203
+ protos[key].data = data;
204
+ if (window.DiscordNative?.fileManager) {
205
+ window.DiscordNative.fileManager.saveWithDialog(
206
+ data,
207
+ `${proto.name}.proto`,
208
+ );
209
+ } else {
210
+ console.log(data);
211
+ }
212
+ }