UNPKG

steam-user

Version:

Steam client for Individual and AnonUser Steam account types

176 lines (139 loc) 4.99 kB
const ChildProcess = require('child_process'); const FS = require('fs'); const Path = require('path'); const PBJS_BINARY_PATH = Path.join(__dirname, '..', 'node_modules', 'protobufjs-cli', 'bin', 'pbjs'); const PROTO_FILE_PATH = Path.join(__dirname, '..', 'protobufs', '%s.proto'); const DESTINATION_PATH = Path.join(__dirname, '..', 'protobufs', 'generated', '%s.json'); const PBJS_COMMAND_LINE = `node "${PBJS_BINARY_PATH}" --target json --out "${DESTINATION_PATH}" --keep-case "${PROTO_FILE_PATH}"`; const GENERATED_DIR = Path.join(__dirname, '..', 'protobufs', 'generated'); const OVERRIDE_TYPEDEF_TYPES = { Proto_CMsgClientLicenseList_License: { payment_method: 'EPaymentMethod', flags: 'ELicenseFlags', license_type: 'ELicenseType' } }; const GENERATED_FILE_HEADER = `/* eslint-disable */\n// Auto-generated by generate-protos script on ${(new Date()).toString()}\n\n`; let loader = GENERATED_FILE_HEADER; // eslint-disable-next-line loader += "const Schema = module.exports;\nconst {Root} = require('protobufjs');\n\n"; if (!FS.existsSync(GENERATED_DIR)) { FS.mkdirSync(GENERATED_DIR); } // First we want to delete the contents of the generated dir FS.readdirSync(GENERATED_DIR).forEach((filename) => { console.log(`Delete ${filename}`); FS.unlinkSync(Path.join(GENERATED_DIR, filename)); }); let typesFile = FS.openSync(Path.join(GENERATED_DIR, '_types.js'), 'w'); let documentedTypes = {}; // Some types might be defined in multiple proto files. Let's only include each type once. FS.writeSync(typesFile, GENERATED_FILE_HEADER); FS.readdirSync(__dirname + '/../protobufs').forEach((filename) => { if (!filename.match(/\.proto$/)) { return; } let filenameWithoutExtension = filename.replace('.proto', ''); let cmdLine = PBJS_COMMAND_LINE.replace(/%s/g, filenameWithoutExtension); console.log(cmdLine); ChildProcess.execSync(cmdLine); loader += `mergeObjects(Schema, Root.fromJSON(require('./${filenameWithoutExtension}.json')));\n`; let protoDefinition = require(Path.join(GENERATED_DIR, `${filenameWithoutExtension}.json`)); if (protoDefinition.nested) { FS.writeSync(typesFile, `///////////////////////////////////////////////\n// ${filenameWithoutExtension}.proto\n///////////////////////////////////////////////\n\n`); FS.writeSync(typesFile, writeTypedef(protoDefinition.nested)); } }); FS.closeSync(typesFile); console.log('Generating _load.js'); loader += `\n${mergeObjects.toString()}\n`; FS.writeFileSync(GENERATED_DIR + '/_load.js', loader); function mergeObjects(destinationObject, sourceObject) { for (let i in sourceObject) { if (Object.hasOwnProperty.call(sourceObject, i)) { destinationObject[i] = sourceObject[i]; } } } function writeTypedef(obj, namespace = '.') { let output = ''; for (let i in obj) { // skip options, nested messages, and enums if (i == 'options' || i == 'nested' || i == 'google' || obj[i].type || obj[i].values) { continue; } if (documentedTypes[namespace + i]) { // We already documented this type continue; } documentedTypes[namespace + i] = true; let resolvedName = 'Proto' + (namespace + i).replace(/\./g, '_'); output += `/**\n * @typedef {object} ${resolvedName}\n`; for (let j in obj[i].fields) { let type = protobufTypeToJsType(obj[i].fields[j].type); let name = j; if (type == 'number' && ['eresult', 'eResult', 'result'].includes(name)) { type = 'EResult'; } if (OVERRIDE_TYPEDEF_TYPES[resolvedName] && OVERRIDE_TYPEDEF_TYPES[resolvedName][j]) { type = OVERRIDE_TYPEDEF_TYPES[resolvedName][j]; } switch (obj[i].fields[j].rule) { case 'repeated': type += '[]'; break; case 'required': break; default: // optional // Does this field have a default value? if (obj[i].fields[j].options && !['undefined', 'string'].includes(typeof obj[i].fields[j].options.default)) { name = `[${name}=${obj[i].fields[j].options.default}]`; } else { name = `[${name}]`; } } output += ` * @property {${type}} ${name}\n`; } output += ' */\n\n'; // Do we have nested messages? if (obj[i].nested) { output += writeTypedef(obj[i].nested, namespace + i + '.'); } } return output; function protobufTypeToJsType(type) { switch (type) { case 'double': case 'float': case 'int32': case 'uint32': case 'sint32': case 'fixed32': case 'sfixed32': return 'number'; case 'int64': case 'uint64': case 'sint64': case 'fixed64': case 'sfixed64': // 64-bit numbers are represented as strings return 'string'; case 'bool': return 'boolean'; case 'string': return 'string'; case 'bytes': return 'Buffer'; default: if (type[0] == '.') { // It's another protobuf msg, or an enum if (type[1] == 'E') { // It's an enum return type.substring(1); } return 'Proto' + type.replace(/\./g, '_'); } throw new Error(`Unknown protobuf type ${type}`); } } }