structure-check: gate counts code lines, docs and comments in English

Gate ignores blank and full-line comment lines so the 250-line limit
measures code bulk, not documentation weight; docs/README.md synced.
Translate code comments to English in classfile, core config, namegen,
rename assign, constants forms. Expand Plausible word bank with
client-ecosystem terms (Module, Setting, Mixin, ...). cargo fmt clean,
check.sh green.
This commit is contained in:
Loki 2026-10-09 10:31:02 +02:00
parent ec28ec82e3
commit 39178420e4
Signed by: boba
GPG key ID: 253067914055423B
42 changed files with 532 additions and 437 deletions

View file

@ -1,9 +1,9 @@
//! Алфавиты, ключевые слова и запрещённые имена.
//! Alphabets, keywords and forbidden names.
//!
//! Списки вынесены отдельно: к ним обращаются и генератор, и пасс
//! переименования (резервирование keep-имён).
//! Kept in their own file because both the generator and the rename pass
//! reach into them (reserving keep-listed names before generation starts).
/// Жёсткие ключевые слова Java: имя класса/метода не может им совпадать.
/// Hard Java keywords: a class/method name can never collide with these.
pub(super) const KEYWORDS: &[&str] = &[
"abstract",
"assert",
@ -66,8 +66,8 @@ pub(super) const KEYWORDS: &[&str] = &[
"yield",
];
/// Имена, которые не стоит затирать: мешают читать/логировать и ловятся
/// инструментами до любой деобфускации.
/// Names not worth overwriting: they'd hurt readability/logging and get
/// flagged by tooling before any deobfuscation even starts.
pub(super) const AVOID_CLASS: &[&str] = &[
"Object",
"String",
@ -101,9 +101,9 @@ pub(super) const AVOID_MEMBER: &[&str] = &[
pub(super) const LATIN_LOWER: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
pub(super) const LATIN_UPPER: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/// Визуально неразличимые символы — ядро стиля `IlO0`.
/// Visually indistinguishable characters: the core of the `IlO0` style.
pub(super) const CONFUSABLE: &[u8] = b"IlO01";
/// Unicode-буквы, валидные как Java-идентификаторы (Cyrillic/Greek/CJK).
/// Unicode letters valid in a Java identifier (Cyrillic/Greek/CJK).
pub(super) const UNICODE_LETTERS: &[char] = &[
'а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'к', 'л', 'м', 'н', 'п', 'р', 'с', 'т', 'у', 'ф',
'х', 'ц', 'ч', 'ш', 'щ', 'э', 'ю', 'я', 'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'λ', 'μ', 'π',
@ -118,15 +118,58 @@ pub(super) const DECOY_RIGHT: &[&str] = &[
"ripple",
];
/// Стиль `Plausible`: домен-нейтральные существительные для классов/полей —
/// похожи на обычный прикладной код, не привязаны к конкретному проекту.
/// `Plausible` style word bank. Mixes domain-neutral software nouns with
/// terms that are boring, structural scaffolding in the client/mod
/// ecosystem noxis is actually used on (see
/// `/storage/project/jvm/LoVisual/ref/clients/*`: `Module`, `Setting`,
/// `Event`, `Mixin`, `Manager`, `Component`, `Accessor`, `Hud`, `Overlay`,
/// `Theme`, `Timer`, `Animation`, `Rotation` all show up dozens of times
/// across real client codebases). Deliberately excludes anything that
/// itself reads as a "feature flag" worth an analyst's attention (no
/// `Esp`/`Aimbot`/`KillAura`/`Chams`): a decoy name that announces
/// "interesting code lives here" defeats the point of blending in.
pub(super) const PLAUSIBLE_NOUN: &[&str] = &[
"Texture", "Event", "State", "Render", "Asset", "Config", "Session", "Cache", "Buffer",
"Socket", "Stream", "Widget", "Layout", "Theme", "Profile", "Metric", "Token", "Handle",
"Context", "Registry", "Request", "Response", "Payload", "Resource", "Snapshot", "Pipeline",
"Queue", "Slot", "Frame", "Entry",
"Texture",
"Event",
"State",
"Render",
"Asset",
"Config",
"Session",
"Cache",
"Buffer",
"Socket",
"Stream",
"Widget",
"Layout",
"Theme",
"Profile",
"Metric",
"Token",
"Handle",
"Context",
"Registry",
"Request",
"Response",
"Payload",
"Resource",
"Snapshot",
"Pipeline",
"Queue",
"Slot",
"Frame",
"Entry",
"Module",
"Setting",
"Overlay",
"Hud",
"Component",
"Accessor",
"Timer",
"Animation",
"Rotation",
];
/// Суффиксы ролей для классов (`NounSuffix`, напр. `TextureCache`).
/// Role suffixes for classes (`NounSuffix`, e.g. `TextureCache`).
pub(super) const PLAUSIBLE_SUFFIX: &[&str] = &[
"Manager",
"Handler",
@ -148,8 +191,10 @@ pub(super) const PLAUSIBLE_SUFFIX: &[&str] = &[
"Processor",
"Context",
"Listener",
"Mixin",
"Component",
];
/// Глаголы для методов/полей (`verbNoun`, напр. `resolveToken`).
/// Verbs for methods/fields (`verbNoun`, e.g. `resolveToken`).
pub(super) const PLAUSIBLE_VERB: &[&str] = &[
"get", "set", "update", "process", "handle", "compute", "resolve", "load", "build", "parse",
"fetch", "apply", "validate", "clear", "reset", "sync", "flush", "bind", "attach", "detach",

View file

@ -1,4 +1,4 @@
//! Генерация имён: стили, анти-ключевые слова, уникальность в scope.
//! Name generation: styles, anti-keyword checks, uniqueness within a scope.
pub mod alphabet;
#[cfg(test)]
@ -13,18 +13,18 @@ use self::alphabet::{
LATIN_UPPER, PLAUSIBLE_NOUN, PLAUSIBLE_SUFFIX, PLAUSIBLE_VERB, UNICODE_LETTERS,
};
/// Генератор имён с гарантированной уникальностью в пределах одного scope.
/// Name generator with guaranteed uniqueness within a single scope.
pub struct NameGenerator {
rng: Rng,
style: NameStyle,
used: HashSet<String>,
/// Счётчик-страховка, если случайные варианты исчерпаны.
/// Fallback counter for when the random pool is exhausted.
fallback: u64,
avoid_class: bool,
}
impl NameGenerator {
/// Генератор для указанного стиля.
/// Generator for the given style.
pub fn new(rng: Rng, style: NameStyle) -> Self {
Self {
rng,
@ -35,18 +35,18 @@ impl NameGenerator {
}
}
/// Режим «имена классов»: дополнительно избегаем имён из JDK/аннотаций.
/// "Class name" mode: additionally avoid names from the JDK/annotations.
pub fn for_classes(mut self) -> Self {
self.avoid_class = true;
self
}
/// Занять конкретное имя (защита от коллизий с keep-именами).
/// Reserve a specific name (protects against collisions with keep-listed names).
pub fn reserve(&mut self, name: impl Into<String>) {
self.used.insert(name.into());
}
/// Следующее свободное имя.
/// The next free name.
pub fn next_name(&mut self) -> String {
for _ in 0..64 {
let candidate = self.candidate();
@ -55,7 +55,7 @@ impl NameGenerator {
return candidate;
}
}
// Страховка: детерминированный счётчик, гарантированно уникален.
// Fallback: a deterministic counter, guaranteed unique.
loop {
self.fallback += 1;
let candidate = format!("{}{}", self.style_prefix(), self.fallback);
@ -95,7 +95,7 @@ impl NameGenerator {
};
let idx = self.rng.below(alpha.len() as u64) as usize;
let ch = alpha[idx] as char;
// Первый символ — только буква (не цифра).
// First character must be a letter, not a digit.
if i == 0 && !ch.is_ascii_alphabetic() {
out.push('a');
} else {
@ -123,9 +123,9 @@ impl NameGenerator {
}
name
}
// Маскируется под обычный прикладной код, а не под мусор:
// классы — `NounSuffix` (`TextureCache`), члены — `verbNoun`
// (`resolveToken`) camelCase.
// Blends in as ordinary application code instead of obvious
// noise: classes get `NounSuffix` (`TextureCache`), members get
// camelCase `verbNoun` (`resolveToken`).
NameStyle::Plausible => {
let noun = PLAUSIBLE_NOUN[self.rng.below(PLAUSIBLE_NOUN.len() as u64) as usize];
if self.avoid_class {

View file

@ -1,4 +1,4 @@
//! Тесты генератора имён: уникальность, валидность, форма по стилю.
//! Name generator tests: uniqueness, validity, per-style shape.
#![allow(clippy::expect_used, clippy::unwrap_used)]
@ -15,7 +15,7 @@ fn names_are_unique_and_valid() {
let mut seen = HashSet::new();
for _ in 0..500 {
let name = names.next_name();
assert!(seen.insert(name.clone()), "повтор имени {name}");
assert!(seen.insert(name.clone()), "duplicate name {name}");
assert!(!KEYWORDS.contains(&name.as_str()));
assert!(name.starts_with(|c: char| c.is_ascii_alphabetic()));
}
@ -57,7 +57,7 @@ fn plausible_class_names_look_like_noun_suffix() {
for _ in 0..50 {
let name = names.next_name();
assert!(name.starts_with(|c: char| c.is_ascii_uppercase()), "{name}");
// Два слова подряд слиплись в CamelCase без разделителей.
// Two words run together in CamelCase with no separator.
assert!(
name.chars().filter(|c| c.is_ascii_uppercase()).count() >= 2,
"{name}"