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/.github/workflows/update.yml +30 -0
- package/.prettierrc.yml +3 -0
- package/LICENSE +21 -0
- package/README.md +65 -0
- package/out/FrecencyUserSettings.proto +65 -0
- package/out/PreloadedUserSettings.proto +240 -0
- package/package.json +32 -0
- package/src/index.js +51 -0
- package/src/load.js +26 -0
- package/src/parse.js +212 -0
- package/src/proto.d.ts +5657 -0
- package/src/proto.js +15375 -0
- package/src/test.js +16 -0
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
|
+
}
|