il2cppdump-mermaid
Version:
A small script to generate mermaid code from [Il2CppInspector](https://github.com/djkaty/Il2CppInspector) generated code that help you understand the relations
133 lines (105 loc) • 3.36 kB
JavaScript
import glob from 'glob';
import * as fs from 'fs';
import { default as scramjet } from 'scramjet';
const { StringStream } = scramjet;
// Namespace relations
import * as namespace_parser from './namespace_relations.js';
async function getNamespaceRelationsFromFile(file_path) {
if(file_path.includes('global.cs')) {
return null;
}
const lines = [];
const stream = StringStream
.pipeline(fs.createReadStream(file_path))
.lines()
.while(line => {
lines.push(line.trim());
return !line.startsWith('namespace');
});
await stream.run();
const result = namespace_parser.parse(lines.join('\n'));
return `%% ${file_path}
${result}
`;
}
// Class relations
import * as class_parser from './class_relations.js';
function inferIsInterfaceFromName(name) {
return name.startsWith("I") && name.length > 2 && name.substr(0, 2) === name.substr(0,2).toUpperCase();
}
function normalizeGeneric(name) {
return name.replace(/[<>]/g, '~').replace(/~([ ,\w]*)~~/, '_$1_~');
}
function normalizeClassName(name) {
return name.replace(/\./g, '_');
}
async function getClassRelationsFromFile(file_path) {
const lines = await StringStream
.pipeline(fs.createReadStream(file_path))
.lines()
.filter(line => line.includes(' class ') && !line.includes("where T"))
.map(line => line.trim())
.map(line => {
try {
return class_parser.parse(line);
} catch(err) {
console.warn(line);
return null;
}
})
.filter(Boolean)
.map(def => {
const {
access_modifier,
modifier,
class_name: original_class_name,
inheritances
} = def;
const possible_parent = inheritances && inheritances[0];
const parent = possible_parent
&& !inferIsInterfaceFromName(possible_parent)
&& normalizeGeneric(normalizeClassName(possible_parent));
const class_name = normalizeGeneric(normalizeClassName(original_class_name));
const class_def = `class ${class_name}`;
const inherit_def = parent && `${class_name} --|> ${parent}`
const interface_defs = inheritances
.filter(inferIsInterfaceFromName)
.map(normalizeGeneric)
.map(name => `${class_name} ..|> ${name}`)
const defs = [
// class_def,
inherit_def,
...interface_defs
].filter(Boolean);
return defs.join('\n')
})
.filter(Boolean)
.toArray();
return `%% ${file_path}
${lines.join('\n')}
`;
}
const output_type_handler = {
namespace: getNamespaceRelationsFromFile,
class: getClassRelationsFromFile
};
const output_type = process.argv[2] || 'namespace';
if(!Object.keys(output_type_handler).includes(output_type)) {
throw new Error(`Invalid output type, must be one of ${Object.keys(output_type_handler).join(', ')}`);
}
glob("**/*.cs", {}, async (err, files) => {
const processed = await Promise.all(
files.map(output_type_handler[output_type]).filter(Boolean)
);
fs.writeFileSync(
`${output_type}_relations.md`,
`%% Generated by il2cppdump-mermaid
%% Author - [Houdou](https://github.com/Houdou)
classDiagram
direction LR
`+
processed.join('\n'),
'utf8'
);
});