Add initial support for ZZZ deobf'd DM - #3187
Conversation
WalkthroughThis pull request introduces a comprehensive deobfuscation mapping generation system for Zenless Zone Zero datamining. It adds Git submodules, Nx generators and executors, utility functions, and deobfuscation template modules that transform obfuscated DM JSON files into readable mapped structures with type information. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Generator as Single Template Generator
participant Reader as DM JSON Reader
participant Analyzer as Reverse Mapping Analyzer
participant Writer as File Writer
User->>Generator: invoke generate-single-deobf-template({ file })
Generator->>Reader: readDMJSON('FileCfg/${file}.json')
Reader-->>Generator: parsed DM object
Generator->>Analyzer: analyze object structure
Analyzer->>Analyzer: compute reverseMapping<br/>(value → field name)
Analyzer-->>Generator: reverseMapping + keyValueSet
Generator->>Generator: build template file with<br/>embedded reverseMapping
Generator->>Generator: generateMapping() +<br/>generateTyping()
Generator->>Writer: formatText(dest, contents)
Writer->>Writer: format TypeScript code
Writer-->>Generator: formatted content
Generator->>Writer: writeFileSync(path, content)
Writer-->>User: Template file written
sequenceDiagram
participant User
participant AllGenerator as All Templates Generator
participant SingleGen as Single Template Generator
participant IndexGen as Index Generator
participant Executor as Deobf Executor
participant FileSystem as File System
User->>AllGenerator: invoke generate-all-deobf-template()
loop for each file in allFileCfgs
AllGenerator->>SingleGen: generateSingleDeobfTemplate(file)
SingleGen-->>AllGenerator: template generated
end
AllGenerator->>IndexGen: generateIndex(tree)
IndexGen->>IndexGen: build index.ts with<br/>all imports + exports
IndexGen->>FileSystem: writeFileSync(index.ts)
FileSystem-->>IndexGen: written
Note over Executor: Later, when deobf executor runs:
User->>Executor: yarn run deobf
Executor->>FileSystem: iterate deobfMappings
loop for each DM object
Executor->>Executor: remap keys using<br/>deobfObj.mapping
Executor->>FileSystem: formatText + writeFileSync<br/>to ZenlessDataDeobf/
end
Executor-->>User: { success: true }
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
[Adjusts glasses while Red Bull slowly loses carbonation] Okay, so... this is actually a pretty impressive change set, ngl. You've built out an entire deobfuscation pipeline here—generators that analyze DM JSON structure, figure out what those obfuscated field names actually mean, generate TypeScript files with reverse mappings, and then an executor that applies those mappings to transform the raw data into something readable. The sheer number of template files (11+ FileCfg modules) all following a similar-but-distinct pattern is what's gonna make review time climb—each one needs verification that the reverse mappings make sense for that specific game entity. The generator logic that handles duplicate key suffixes and dynamic mapping computation is also dense enough to merit careful reading. As someone who's wasted many a late night analyzing game data structures... chef's kiss. This is the good stuff. Just make sure those reverseMapping objects are actually correct, yeah? 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
[zzz-frontend] [Tue Apr 7 16:21:46 UTC 2026] - Deployed 3713ca9 to https://genshin-optimizer-prs.github.io/pr/3187/zzz-frontend (Takes 3-5 minutes after this completes to be available) [frontend] [Tue Apr 7 16:22:28 UTC 2026] - Deployed 3713ca9 to https://genshin-optimizer-prs.github.io/pr/3187/frontend (Takes 3-5 minutes after this completes to be available) [sr-frontend] [Tue Apr 7 16:23:01 UTC 2026] - Deployed 3713ca9 to https://genshin-optimizer-prs.github.io/pr/3187/sr-frontend (Takes 3-5 minutes after this completes to be available) [Mon Aug 17 00:42:15 UTC 2026] - Deleted deployment |
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (11)
libs/zzz/dm/src/executors/deobf/schema.d.ts (1)
1-1: Acceptable scaffolding, but consider adding a brief doc comment for future maintainers.yawns Empty interface with ESLint disable is fine for initial implementation... I've seen worse at 3 AM. Since the PR objectives mention this is preliminary work with more properties coming later (type definitions, additional reverse search, etc.), a quick JSDoc comment would help future-you (or future-me, if I ever sleep) understand why this is empty.
That said, this is totally optional for now - the inline disable is honest about the situation. Ship it and get back to pulling for that limited banner before pity resets.
📝 Optional: Add clarifying comment
+/** + * Schema for the deobf executor options. + * TODO: Add configuration properties as deobfuscation pipeline matures. + */ -export interface DeobfExecutorSchema {} // eslint-disable-line +export interface DeobfExecutorSchema {} // eslint-disable-line `@typescript-eslint/no-empty-object-type`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/executors/deobf/schema.d.ts` at line 1, Add a short JSDoc comment above the DeobfExecutorSchema interface explaining that it is intentionally empty for now (placeholder for future executor configuration such as type definitions and reverse-search options) and note why the eslint-disable-line is present; reference the interface name DeobfExecutorSchema so maintainers know this is scaffolding to be extended later.libs/zzz/dm/src/generators/all-schema.json (1)
4-4: Somnia note: give this generator schema a real title.Line 4 is empty, so generator docs/CLI help lose clarity. A concrete title helps future maintainers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/generators/all-schema.json` at line 4, The schema's "title" property in all-schema.json is empty which causes unclear generator docs/CLI help; update the "title" value to a concise, descriptive string (e.g., "All Schemas Generator" or another project-appropriate name) by editing the "title" field in all-schema.json so documentation and CLI help display a meaningful title.libs/zzz/dm/src/executors/deobf/schema.json (1)
5-5: Somnia note: fill in schema description before this ships.Line 5 has an empty
description, which makes Nx help output less useful. Give this a short actionable description.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/executors/deobf/schema.json` at line 5, The schema.json currently has an empty top-level "description" which makes CLI/help output unhelpful; update the "description" field in libs/zzz/dm/src/executors/deobf/schema.json (the top-level "description" property) to a short, actionable sentence describing what the executor does (e.g., what inputs/actions it performs and when to use it) so Nx help displays meaningful information.libs/zzz/dm/src/dm/deobf/FileCfg/SkillPropertyTemplateTb.ts (1)
5-11: LGTM with minor typo.squints at screen The comments explaining the constant values are helpful - good thinking ahead for when someone else (or sleep-deprived future-you) looks at this. Minor typo on line 6: "ALways" should be "Always". Not gonna lose sleep over it... actually I'm already losing sleep over everything else.
📝 Typo fix
const reverseMapping = { - '3': 'todo-GJBIMEAALIF', // ALways 3 + '3': 'todo-GJBIMEAALIF', // Always 3 '1001': 'SkillPropertyId',🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/dm/deobf/FileCfg/SkillPropertyTemplateTb.ts` around lines 5 - 11, Fix the typo in the comment inside the reverseMapping constant: change "ALways 3" to "Always 3" (update the comment associated with the '3' key in reverseMapping so it reads "Always 3"); the symbol to locate is reverseMapping in SkillPropertyTemplateTb.ts.libs/zzz/dm/src/generators/single-schema.json (1)
4-9: Consider adding meaningfultitleanddescriptionvalues.rubs eyes Look, I get it... I've also left empty strings in schemas at 4 AM because "I'll fix it later." But empty
title(line 4) anddescription(line 9) make the developer experience worse when someone runsnx generateand wonders what they're supposed to put. Future-you (or future-me, running on 2 hours of sleep after farming Shiyu Defense) will thank you.📝 Suggested improvement
{ "$schema": "https://json-schema.org/schema", "$id": "GenerateSingleDeobfTemplate", - "title": "", + "title": "Generate Single Deobf Template", "type": "object", "properties": { "file": { "type": "string", - "description": "", + "description": "The DM file name (e.g., 'ItemTemplateTb') to generate a deobfuscation template for", "$default": {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/generators/single-schema.json` around lines 4 - 9, The schema currently has empty metadata causing poor UX; update the top-level "title" and add a clear top-level "description" for the schema, and replace the empty "description" under "properties.file" with a concise explanation of what the file value should be (e.g., expected file path or format). Locate and edit the "title" key and the "description" fields in single-schema.json (specifically the top-level "title" and the "properties.file.description") to include meaningful, user-facing text that guides authors when running nx generate.libs/zzz/dm/src/dm/deobf/FileCfg/ItemTemplateTb.ts (1)
36-36: Add a comment explaining why index[4]is used instead of[0].brain.exe has stopped responding Okay wait, every other template uses
Object.values(...)[0][0]but this one uses[0][4]. The context snippets confirm this is intentional, but future-me (or anyone else maintaining this at 2 AM while waiting for stamina to recharge) will have NO idea why without a comment. Is index 4 where the gold item template lives? Is it a specific item type? Please save us from this mystery!📝 Add explanatory comment
-const dmObj = Object.values(itemTemplateTb)[0][4] +// Index 4 used because [explain why - e.g., gold item template structure differs] +const dmObj = Object.values(itemTemplateTb)[0][4]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/dm/deobf/FileCfg/ItemTemplateTb.ts` at line 36, The expression const dmObj = Object.values(itemTemplateTb)[0][4] uses index [4] intentionally (not [0]) to pick the specific item template stored at the 5th position in the underlying data array; update ItemTemplateTb.ts by adding a concise inline comment next to the dmObj assignment explaining why [4] is used (e.g., "selects the gold/item-template entry per data layout/spec where slot 4 contains the gold item template") and reference the data structure reason (the shape of itemTemplateTb values) so future maintainers know this is deliberate; mention the symbol names itemTemplateTb and dmObj in the comment for clarity.libs/zzz/dm/src/generators/generate-index-deobf.ts (2)
13-15: Unusual join separator produces unconventional formatting.yawns mid-review The separator
'\n, 'on line 14 puts the comma at the start of lines rather than at the end. WhileformatTextmight normalize this, it's an unconventional pattern. Most codebases use trailing commas. Not blocking since Prettier/formatter probably handles it, but it made my sleep-deprived brain do a double-take.📝 Alternative with trailing commas
export const deobfMappings = { - ${allFileCfgs.join('\n, ')} + ${allFileCfgs.join(',\n ')}, }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/generators/generate-index-deobf.ts` around lines 13 - 15, Change the join separator so commas trail items instead of leading the next line: in the deobfMappings construction where allFileCfgs.join('\n, ') is used, replace the separator with a trailing-comma pattern (e.g. ',\n ') so each entry ends with a comma; update the code that builds deobfMappings (symbol: deobfMappings, source: allFileCfgs.join(...)) to use the new separator.
17-18: Consider usingtree.write()instead ofwriteFileSyncfor Nx consistency.stares at screen with bloodshot eyes You're passing a
Treeparameter but then usingwriteFileSyncdirectly... That's like pulling on the standard banner when there's a limited character you want. The Nx Tree API exists so generators can work in dry-run mode and integrate properly with the Nx virtual file system. UsingwriteFileSyncbypasses all that.♻️ Proposed fix using Tree API
-import { writeFileSync } from 'fs' -import * as path from 'path' import { formatText } from '@genshin-optimizer/common/pipeline' import type { Tree } from '@nx/devkit' import { allFileCfgs } from '../consts' export default async function generateIndex(tree: Tree) { const file_location = `libs/zzz/dm/src/dm/deobf/FileCfg` - const dest = path.join(tree.root, file_location, `index.ts`) + const dest = `${file_location}/index.ts` const contents = `// WARNING: Generated file, do not modify ${allFileCfgs.map((cfg) => `import ${cfg} from './${cfg}'`).join('\n')} export const deobfMappings = { ${allFileCfgs.join('\n, ')} } ` const formatted = await formatText(dest, contents) - writeFileSync(dest, formatted) + tree.write(dest, formatted) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/generators/generate-index-deobf.ts` around lines 17 - 18, Replace the direct fs write with the Nx Tree API so dry runs and virtual FS work: instead of calling writeFileSync(dest, formatted) after const formatted = await formatText(dest, contents), call tree.write(dest, formatted) (use the Tree parameter passed into this generator, e.g., the function handling generate-index-deobf) and remove the writeFileSync import/usage; ensure the variables dest, contents and formatted are used the same way and that formatText remains unchanged.libs/zzz/dm/src/dm/deobf/FileCfg/AvatarPassiveSkillTemplateTb.ts (1)
12-16: Patch-dependent obfuscation keys will require maintenance.groans Yeah, I feel this in my soul. The TODOs about property obf names changing every patch are a real concern. For
CoreStatsandCost, those JSON-stringified keys with internal identifiers likeMPIANOLFJMBandBALDAPBGEPKwill break when ZZZ updates.Consider documenting a maintenance process or adding a CI check that validates these mappings against the latest datamine. Otherwise, someone's gonna be doing emergency hotfixes at 2am after every patch... not that I'd know anything about that.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/dm/deobf/FileCfg/AvatarPassiveSkillTemplateTb.ts` around lines 12 - 16, The TODO notes flag that the JSON-stringified obfuscation keys used for CoreStats and Cost in AvatarPassiveSkillTemplateTb.ts are patch-dependent and will break; add a maintenance plan and an automated validation step: create a small CI job (or unit test) that loads the latest datamine schema and verifies that the mapped obf-key strings (the entries currently mapping to 'CoreStats' and 'Cost') exist and warn/fail the build if they change, and document the required update steps in the file header or contributing docs so maintainers know to update the mappings when obf names change.libs/zzz/dm/src/executors/deobf/deobf.ts (1)
10-27: No error handling for file read/write operations.The executor doesn't wrap file operations in try-catch. If
readDMJSONthrows (file not found) orwriteFileSyncfails (permissions, disk full), the executor crashes without useful context about which file failed.For an executor that processes multiple files, this makes debugging painful when something breaks mid-run. Consider wrapping the loop body or at least logging which file is being processed before operations.
🛠️ Suggested improvement
for (const [file, deobfObj] of Object.entries(deobfMappings)) { + console.log(`Processing ${file}...`) const outputFile = `${workspaceRoot}/libs/zzz/dm/ZenlessDataDeobf/FileCfg/${file}.json` - const dm = JSON.parse(readDMJSON(`FileCfg/${file}.json`)) as GenericDmFile + let dm: GenericDmFile + try { + dm = JSON.parse(readDMJSON(`FileCfg/${file}.json`)) as GenericDmFile + } catch (e) { + console.error(`Failed to read/parse ${file}.json:`, e) + throw e + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/executors/deobf/deobf.ts` around lines 10 - 27, The loop in runExecutor iterating over deobfMappings performs file IO (readDMJSON, formatText, writeFileSync) with no error handling; wrap the per-file processing (the body using deobfObj, readDMJSON, objKeyValMap, formatText, writeFileSync) in a try-catch that logs a clear error including the file variable and deobfObj.mapping, and on error either continue to the next file or collect failures; update the final return to reflect overall success (e.g., success: false if any file failed) so callers know the executor had partial/total failures.libs/zzz/dm/src/generators/generate-single-deobf-template.ts (1)
85-88: Magic number forItemTemplateTbcould use a comment.squinting at screen through coffee-stained glasses ...why index 4? Is there something special about the 5th item in ItemTemplateTb that makes it a better representative object? Future sleep-deprived me (or anyone else) would appreciate knowing why this specific index matters.
📝 Add explanatory comment
function getObjToUse(file: string) { - if (file === 'ItemTemplateTb') return 4 - else return 0 + // ItemTemplateTb: Use index 4 as the representative object because + // earlier entries may have incomplete/atypical field coverage + if (file === 'ItemTemplateTb') return 4 + return 0 }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/zzz/dm/src/generators/generate-single-deobf-template.ts` around lines 85 - 88, The special-case return value in getObjToUse (return 4 when file === 'ItemTemplateTb') is a magic number; either add a clear explanatory comment above that branch explaining why index 4 is chosen (e.g., representative object, schema version, or stable sample at position 5), or replace the literal with a named constant (e.g., DEFAULT_ITEM_TEMPLATE_INDEX = 4) and document the reason in the constant's comment so readers of getObjToUse and anyone working with ItemTemplateTb understand the rationale.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.gitmodules:
- Around line 24-28: The new submodule entry libs/zzz/dm/ZenlessDataDeobf
introduces a hard dependency for the deobf step; update the deobf CI/job (or the
deobf script) to first verify the submodule is present and initialized (check
for the path libs/zzz/dm/ZenlessDataDeobf or run git submodule status) and fail
fast with a clear error if missing, or gate the deobf job with an explicit step
that performs git submodule update --init --recursive (or your runner's
submodule checkout) before any writes to ZenlessDataDeobf so the pipeline never
attempts to write into a non-initialized submodule.
In `@libs/zzz/dm/.eslintrc.json`:
- Around line 21-25: The override's "files" glob patterns are using a leading
"./" so ESLint won't match them; update the "files" array in the overrides (the
key "files" that currently contains "./package.json", "./generators.json",
"./executors.json") to remove the "./" prefix so they read "package.json",
"generators.json", and "executors.json" so the "@nx/nx-plugin-checks" rule will
actually be applied.
In `@libs/zzz/dm/README.md`:
- Around line 9-14: The README's "[DEPRECATED] Getting data from Hakush.in"
section is contradictory: it says the service is taken down but still provides
download instructions; update the section to remove or clearly mark the download
steps as non-functional by deleting or commenting out the instructions
(`https://api.hakush.in/zzz/` and `nx get-hakushin zzz-dm`) and replace them
with a single clear sentence stating the endpoint is removed and no longer
available (or provide an alternative source if one exists) so contributors are
not misled.
In `@libs/zzz/dm/src/dm/deobf/FileCfg/AvatarBaseTemplateTb.ts`:
- Around line 18-24: The code assumes avatarBaseTemplateTb contains at least one
array element by doing Object.values(avatarBaseTemplateTb)[0][0], which can
throw if the JSON is an empty array; update the logic around dmObj (the value
derived from avatarBaseTemplateTb) to defensively handle empty data: check that
Object.values(avatarBaseTemplateTb)[0] exists and has length > 0 before
indexing, and if not either provide a safe default (e.g., an empty object) or
bail early with a clear error/log; ensure generateMapping and generateTyping
(which consume dmObj) either tolerate the default or are only called when dmObj
is valid. Use the unique symbols avatarBaseTemplateTb, dmObj, generateMapping,
generateTyping, GenericDmFile and readDMJSON to locate and change the code.
In `@libs/zzz/dm/src/dm/deobf/FileCfg/AvatarBattleTemplateTb.ts`:
- Around line 45-55: The code uses non-null assertions on the results of two
chained .find() calls when computing potentialsKey from avatarBattleTemplateTb,
which can throw if the target array disappears; update the logic in the block
that computes potentialsKey so it first validates that avatarBattleTemplateTb
has values, captures the intermediate find result into a variable (e.g.,
foundObject) and ensures it is not undefined before attempting
Object.entries/find again, and if either lookup fails, handle defensively by
either logging/throwing a clear error that includes the search target array
([119100,...,119105]) or skipping mapping assignment; leave the final assignment
mapping[potentialsKey] = 'Potentials' only when potentialsKey is successfully
resolved.
In `@libs/zzz/dm/src/dm/deobf/util.ts`:
- Around line 22-25: generateTyping is always JSON.stringify-ing values before
reverseMapping lookup while generateMapping only stringifies when the value is
an object, causing mismatched keys and dropped entries; update generateTyping
(the return that calls objKeyValMap over Object.values(dmObj)) to match
generateMapping's logic: use the raw primitive value for reverseMapping lookups
and only JSON.stringify(v) when typeof v === "object" (reference reverseMapping,
dmObj, objKeyValMap, generateMapping/generateTyping to locate the code), so keys
align and entries are not lost.
In `@libs/zzz/dm/src/executors/deobf/deobf.spec.ts`:
- Around line 23-26: The test currently calls the real executor pipeline
(executor(options, context)) causing non-deterministic IO; to harden it,
mock/stub the executor's external collaborators (filesystem/datamine functions
or modules it imports) before calling executor and assert those mocks were
invoked in addition to expect(output.success). Specifically, replace real IO
with jest mocks/spies for the modules or functions the executor uses, inject the
mocked context/options as needed, call executor(options, context), then add
assertions that the mocked collaborators were called (e.g.,
expect(mockFn).toHaveBeenCalled()) and keep expect(output.success).toBe(true).
In `@libs/zzz/dm/src/executors/deobf/deobf.ts`:
- Around line 15-20: The deobfuscation step (deobfedDm creation) can produce
properties named undefined when deobfObj.mapping[key] is missing for keys in
dmObj; update the mapping callback used by objKeyValMap (the ([key, value]) =>
... function) to either skip entries with no mapping or use a safe fallback
(e.g., deobfObj.mapping[key] ?? key) so unmapped keys don't become literal
undefined properties; locate the deobfedDm construction and change the mapping
expression to use the fallback or filter out unmapped entries before calling
objKeyValMap.
In `@libs/zzz/dm/src/generators/generate-all-deobf-template.spec.ts`:
- Around line 14-18: The test is asserting a project config ('test') unrelated
to generateAllDeobfTemplateGenerator; update the spec to assert generator output
instead: remove the readProjectConfiguration('test') assertion and instead call
generateAllDeobfTemplateGenerator(tree) then verify generated artifacts—use
tree.exists('<expected/path>') and readFile(tree, '<expected/path>') (or
appropriate devkit helpers) to assert the template/index (or other expected
files and contents) were created/updated; reference the
generateAllDeobfTemplateGenerator function and the spec file
generate-all-deobf-template.spec.ts when making the change.
In `@libs/zzz/dm/src/generators/generate-single-deobf-template.spec.ts`:
- Around line 10-19: The test passes an invalid contract to
generateSingleDeobfTemplateGenerator (using
GenerateSingleDeobfTemplateGeneratorSchema { file: 'test' }) but then asserts a
project was registered via readProjectConfiguration; instead, update the spec to
align with the generator's contract by either (A) supplying a valid DM file key
and expected DM JSON shape or (B) mocking the DM file IO and readDMJSON call so
the generator receives deterministic data, then assert the generator created the
expected template files/changes on the in-memory tree (e.g., check tree.read or
readTextFile results) rather than readProjectConfiguration; refer to
generateSingleDeobfTemplateGenerator,
GenerateSingleDeobfTemplateGeneratorSchema, and readDMJSON when adding the mock
and updating assertions.
---
Nitpick comments:
In `@libs/zzz/dm/src/dm/deobf/FileCfg/AvatarPassiveSkillTemplateTb.ts`:
- Around line 12-16: The TODO notes flag that the JSON-stringified obfuscation
keys used for CoreStats and Cost in AvatarPassiveSkillTemplateTb.ts are
patch-dependent and will break; add a maintenance plan and an automated
validation step: create a small CI job (or unit test) that loads the latest
datamine schema and verifies that the mapped obf-key strings (the entries
currently mapping to 'CoreStats' and 'Cost') exist and warn/fail the build if
they change, and document the required update steps in the file header or
contributing docs so maintainers know to update the mappings when obf names
change.
In `@libs/zzz/dm/src/dm/deobf/FileCfg/ItemTemplateTb.ts`:
- Line 36: The expression const dmObj = Object.values(itemTemplateTb)[0][4] uses
index [4] intentionally (not [0]) to pick the specific item template stored at
the 5th position in the underlying data array; update ItemTemplateTb.ts by
adding a concise inline comment next to the dmObj assignment explaining why [4]
is used (e.g., "selects the gold/item-template entry per data layout/spec where
slot 4 contains the gold item template") and reference the data structure reason
(the shape of itemTemplateTb values) so future maintainers know this is
deliberate; mention the symbol names itemTemplateTb and dmObj in the comment for
clarity.
In `@libs/zzz/dm/src/dm/deobf/FileCfg/SkillPropertyTemplateTb.ts`:
- Around line 5-11: Fix the typo in the comment inside the reverseMapping
constant: change "ALways 3" to "Always 3" (update the comment associated with
the '3' key in reverseMapping so it reads "Always 3"); the symbol to locate is
reverseMapping in SkillPropertyTemplateTb.ts.
In `@libs/zzz/dm/src/executors/deobf/deobf.ts`:
- Around line 10-27: The loop in runExecutor iterating over deobfMappings
performs file IO (readDMJSON, formatText, writeFileSync) with no error handling;
wrap the per-file processing (the body using deobfObj, readDMJSON, objKeyValMap,
formatText, writeFileSync) in a try-catch that logs a clear error including the
file variable and deobfObj.mapping, and on error either continue to the next
file or collect failures; update the final return to reflect overall success
(e.g., success: false if any file failed) so callers know the executor had
partial/total failures.
In `@libs/zzz/dm/src/executors/deobf/schema.d.ts`:
- Line 1: Add a short JSDoc comment above the DeobfExecutorSchema interface
explaining that it is intentionally empty for now (placeholder for future
executor configuration such as type definitions and reverse-search options) and
note why the eslint-disable-line is present; reference the interface name
DeobfExecutorSchema so maintainers know this is scaffolding to be extended
later.
In `@libs/zzz/dm/src/executors/deobf/schema.json`:
- Line 5: The schema.json currently has an empty top-level "description" which
makes CLI/help output unhelpful; update the "description" field in
libs/zzz/dm/src/executors/deobf/schema.json (the top-level "description"
property) to a short, actionable sentence describing what the executor does
(e.g., what inputs/actions it performs and when to use it) so Nx help displays
meaningful information.
In `@libs/zzz/dm/src/generators/all-schema.json`:
- Line 4: The schema's "title" property in all-schema.json is empty which causes
unclear generator docs/CLI help; update the "title" value to a concise,
descriptive string (e.g., "All Schemas Generator" or another project-appropriate
name) by editing the "title" field in all-schema.json so documentation and CLI
help display a meaningful title.
In `@libs/zzz/dm/src/generators/generate-index-deobf.ts`:
- Around line 13-15: Change the join separator so commas trail items instead of
leading the next line: in the deobfMappings construction where
allFileCfgs.join('\n, ') is used, replace the separator with a trailing-comma
pattern (e.g. ',\n ') so each entry ends with a comma; update the code that
builds deobfMappings (symbol: deobfMappings, source: allFileCfgs.join(...)) to
use the new separator.
- Around line 17-18: Replace the direct fs write with the Nx Tree API so dry
runs and virtual FS work: instead of calling writeFileSync(dest, formatted)
after const formatted = await formatText(dest, contents), call tree.write(dest,
formatted) (use the Tree parameter passed into this generator, e.g., the
function handling generate-index-deobf) and remove the writeFileSync
import/usage; ensure the variables dest, contents and formatted are used the
same way and that formatText remains unchanged.
In `@libs/zzz/dm/src/generators/generate-single-deobf-template.ts`:
- Around line 85-88: The special-case return value in getObjToUse (return 4 when
file === 'ItemTemplateTb') is a magic number; either add a clear explanatory
comment above that branch explaining why index 4 is chosen (e.g., representative
object, schema version, or stable sample at position 5), or replace the literal
with a named constant (e.g., DEFAULT_ITEM_TEMPLATE_INDEX = 4) and document the
reason in the constant's comment so readers of getObjToUse and anyone working
with ItemTemplateTb understand the rationale.
In `@libs/zzz/dm/src/generators/single-schema.json`:
- Around line 4-9: The schema currently has empty metadata causing poor UX;
update the top-level "title" and add a clear top-level "description" for the
schema, and replace the empty "description" under "properties.file" with a
concise explanation of what the file value should be (e.g., expected file path
or format). Locate and edit the "title" key and the "description" fields in
single-schema.json (specifically the top-level "title" and the
"properties.file.description") to include meaningful, user-facing text that
guides authors when running nx generate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 56012260-68f5-40aa-8665-fe05c02a69ff
📒 Files selected for processing (40)
.gitmoduleslibs/sr/dm-localization/src/executors/gen-locale/lib/util.tslibs/zzz/dm/.eslintrc.jsonlibs/zzz/dm/README.mdlibs/zzz/dm/ZenlessDatalibs/zzz/dm/ZenlessDataDeobflibs/zzz/dm/executors.jsonlibs/zzz/dm/generators.jsonlibs/zzz/dm/package.jsonlibs/zzz/dm/project.jsonlibs/zzz/dm/src/consts.tslibs/zzz/dm/src/dm/deobf/FileCfg/AvatarBaseTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/AvatarBattleTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/AvatarPassiveSkillDesTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/AvatarPassiveSkillTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/AvatarSkillDesTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/AvatarSkillTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/EquipmentTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/ItemTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/SkillPropertyTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/WeaponTalentTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/WeaponTemplateTb.tslibs/zzz/dm/src/dm/deobf/FileCfg/index.tslibs/zzz/dm/src/dm/deobf/index.tslibs/zzz/dm/src/dm/deobf/types.tslibs/zzz/dm/src/dm/deobf/util.tslibs/zzz/dm/src/executors/deobf/deobf.spec.tslibs/zzz/dm/src/executors/deobf/deobf.tslibs/zzz/dm/src/executors/deobf/index.tslibs/zzz/dm/src/executors/deobf/schema.d.tslibs/zzz/dm/src/executors/deobf/schema.jsonlibs/zzz/dm/src/generators/all-schema.jsonlibs/zzz/dm/src/generators/generate-all-deobf-template.spec.tslibs/zzz/dm/src/generators/generate-all-deobf-template.tslibs/zzz/dm/src/generators/generate-index-deobf.tslibs/zzz/dm/src/generators/generate-single-deobf-template.spec.tslibs/zzz/dm/src/generators/generate-single-deobf-template.tslibs/zzz/dm/src/generators/schema.d.tslibs/zzz/dm/src/generators/single-schema.jsonlibs/zzz/dm/src/util.ts
| [submodule "libs/zzz/dm/ZenlessDataDeobf"] | ||
| path = libs/zzz/dm/ZenlessDataDeobf | ||
| url = https://github.com/genshin-optimizer/ZenlessDataDeobf | ||
| shallow = true | ||
| branch = master |
There was a problem hiding this comment.
New submodule introduces a CI/runtime dependency that needs guarding.
At Line 24, this is valid, but it creates a hard dependency: deobf writes into libs/zzz/dm/ZenlessDataDeobf/.... If submodules aren’t initialized in a runner/job, the pipeline can fail with missing-path writes.
Please gate deobf jobs with submodule checkout (or add a preflight check with a clear error before writing).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.gitmodules around lines 24 - 28, The new submodule entry
libs/zzz/dm/ZenlessDataDeobf introduces a hard dependency for the deobf step;
update the deobf CI/job (or the deobf script) to first verify the submodule is
present and initialized (check for the path libs/zzz/dm/ZenlessDataDeobf or run
git submodule status) and fail fast with a clear error if missing, or gate the
deobf job with an explicit step that performs git submodule update --init
--recursive (or your runner's submodule checkout) before any writes to
ZenlessDataDeobf so the pipeline never attempts to write into a non-initialized
submodule.
| "files": ["./package.json", "./generators.json", "./executors.json"], | ||
| "parser": "jsonc-eslint-parser", | ||
| "rules": { | ||
| "@nx/nx-plugin-checks": "error" | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In ESLint legacy .eslintrc overrides.files, does a pattern like "./package.json" match a same-directory file, or should it be "package.json"?
💡 Result:
In legacy .eslintrc overrides.files, ESLint matches your glob against the file path relative to the directory containing the config file (e.g. lib/util.js). Therefore, a same-directory file is matched as package.json, not ./package.json—so use "package.json". [1]
"./package.json" generally won’t match because ESLint doesn’t prefix the tested path with ./. [1][2]
Remove ./ prefix from glob patterns in overrides—ESLint won't match them that way.
The "files" patterns at line 21 use ./package.json, ./generators.json, and ./executors.json. ESLint's glob matching in overrides.files tests paths relative to the config directory without the ./ prefix, so these patterns silently fail to match. This means @nx/nx-plugin-checks never runs on these files.
Suggested fix
- "files": ["./package.json", "./generators.json", "./executors.json"],
+ "files": ["package.json", "generators.json", "executors.json"],📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "files": ["./package.json", "./generators.json", "./executors.json"], | |
| "parser": "jsonc-eslint-parser", | |
| "rules": { | |
| "@nx/nx-plugin-checks": "error" | |
| } | |
| "files": ["package.json", "generators.json", "executors.json"], | |
| "parser": "jsonc-eslint-parser", | |
| "rules": { | |
| "@nx/nx-plugin-checks": "error" | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/zzz/dm/.eslintrc.json` around lines 21 - 25, The override's "files" glob
patterns are using a leading "./" so ESLint won't match them; update the "files"
array in the overrides (the key "files" that currently contains
"./package.json", "./generators.json", "./executors.json") to remove the "./"
prefix so they read "package.json", "generators.json", and "executors.json" so
the "@nx/nx-plugin-checks" rule will actually be applied.
| ## [DEPRECATED] Getting data from Hakush.in | ||
|
|
||
| NOTE: Hakush.in has been taken down, so this no longer works | ||
|
|
||
| Download all the English JSONs from `https://api.hakush.in/zzz/` | ||
| `nx get-hakushin zzz-dm` |
There was a problem hiding this comment.
Doc contradiction in deprecated Hakush section.
Line 11 says it no longer works, but Lines 13–14 still instruct users to download from that endpoint. That’s confusing for contributors.
Suggested doc cleanup
## [DEPRECATED] Getting data from Hakush.in
NOTE: Hakush.in has been taken down, so this no longer works
-
-Download all the English JSONs from `https://api.hakush.in/zzz/`
-`nx get-hakushin zzz-dm`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/zzz/dm/README.md` around lines 9 - 14, The README's "[DEPRECATED]
Getting data from Hakush.in" section is contradictory: it says the service is
taken down but still provides download instructions; update the section to
remove or clearly mark the download steps as non-functional by deleting or
commenting out the instructions (`https://api.hakush.in/zzz/` and `nx
get-hakushin zzz-dm`) and replace them with a single clear sentence stating the
endpoint is removed and no longer available (or provide an alternative source if
one exists) so contributors are not misled.
| const avatarBaseTemplateTb = JSON.parse( | ||
| readDMJSON('FileCfg/AvatarBaseTemplateTb.json') | ||
| ) as GenericDmFile | ||
|
|
||
| const dmObj = Object.values(avatarBaseTemplateTb)[0][0] | ||
| const mapping = generateMapping(reverseMapping, dmObj) | ||
| const typing = generateTyping(reverseMapping, dmObj) |
There was a problem hiding this comment.
Potential runtime crash if DM JSON array is empty.
yawns Okay so... been staring at gacha rates all night and this pattern jumped out at me. The GenericDmFile type allows empty arrays, but Object.values(avatarBaseTemplateTb)[0][0] assumes there's at least one element. If ZZZ devs ever ship an empty template file (wouldn't put it past them honestly, seen weirder things in datamines), this blows up with undefined.
Since this pattern repeats across all template files, consider adding a guard or utility function.
🛡️ Suggested defensive check
const avatarBaseTemplateTb = JSON.parse(
readDMJSON('FileCfg/AvatarBaseTemplateTb.json')
) as GenericDmFile
-const dmObj = Object.values(avatarBaseTemplateTb)[0][0]
+const dmArray = Object.values(avatarBaseTemplateTb)[0]
+if (!dmArray || dmArray.length === 0) {
+ throw new Error('AvatarBaseTemplateTb.json has no entries')
+}
+const dmObj = dmArray[0]
const mapping = generateMapping(reverseMapping, dmObj)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/zzz/dm/src/dm/deobf/FileCfg/AvatarBaseTemplateTb.ts` around lines 18 -
24, The code assumes avatarBaseTemplateTb contains at least one array element by
doing Object.values(avatarBaseTemplateTb)[0][0], which can throw if the JSON is
an empty array; update the logic around dmObj (the value derived from
avatarBaseTemplateTb) to defensively handle empty data: check that
Object.values(avatarBaseTemplateTb)[0] exists and has length > 0 before
indexing, and if not either provide a safe default (e.g., an empty object) or
bail early with a clear error/log; ensure generateMapping and generateTyping
(which consume dmObj) either tolerate the default or are only called when dmObj
is valid. Use the unique symbols avatarBaseTemplateTb, dmObj, generateMapping,
generateTyping, GenericDmFile and readDMJSON to locate and change the code.
| const potentialsKey = Object.entries( | ||
| Object.values(avatarBattleTemplateTb)[0].find((o) => | ||
| Object.values(o).some( | ||
| (v) => JSON.stringify(v) === '[119100,119101,119102,119103,119104,119105]' | ||
| ) | ||
| )! | ||
| ).find( | ||
| ([_, v]) => | ||
| JSON.stringify(v) === '[119100,119101,119102,119103,119104,119105]' | ||
| )![0] | ||
| mapping[potentialsKey] = 'Potentials' |
There was a problem hiding this comment.
Non-null assertions could cause runtime crashes if data structure changes.
rubs eyes ...at 3am, these ! assertions are giving me anxiety like waiting for a 5-star pity break. If the datamine structure changes and that magic array [119100,119101,119102,119103,119104,119105] disappears or moves, both .find() calls will return undefined, and those ! assertions will throw at runtime.
Given this is datamine processing where upstream data can change unpredictably (trust me, I've seen HoYo change things overnight), consider adding defensive checks or at least a meaningful error message.
🛡️ Proposed defensive handling
-const potentialsKey = Object.entries(
+const potentialsEntry = Object.entries(
Object.values(avatarBattleTemplateTb)[0].find((o) =>
Object.values(o).some(
(v) => JSON.stringify(v) === '[119100,119101,119102,119103,119104,119105]'
)
- )!
-).find(
+ ) ?? {}
+).find(
([_, v]) =>
JSON.stringify(v) === '[119100,119101,119102,119103,119104,119105]'
-)![0]
-mapping[potentialsKey] = 'Potentials'
+)
+if (potentialsEntry) {
+ mapping[potentialsEntry[0]] = 'Potentials'
+} else {
+ console.warn('Could not locate Potentials key in AvatarBattleTemplateTb')
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const potentialsKey = Object.entries( | |
| Object.values(avatarBattleTemplateTb)[0].find((o) => | |
| Object.values(o).some( | |
| (v) => JSON.stringify(v) === '[119100,119101,119102,119103,119104,119105]' | |
| ) | |
| )! | |
| ).find( | |
| ([_, v]) => | |
| JSON.stringify(v) === '[119100,119101,119102,119103,119104,119105]' | |
| )![0] | |
| mapping[potentialsKey] = 'Potentials' | |
| const potentialsEntry = Object.entries( | |
| Object.values(avatarBattleTemplateTb)[0].find((o) => | |
| Object.values(o).some( | |
| (v) => JSON.stringify(v) === '[119100,119101,119102,119103,119104,119105]' | |
| ) | |
| ) ?? {} | |
| ).find( | |
| ([_, v]) => | |
| JSON.stringify(v) === '[119100,119101,119102,119103,119104,119105]' | |
| ) | |
| if (potentialsEntry) { | |
| mapping[potentialsEntry[0]] = 'Potentials' | |
| } else { | |
| console.warn('Could not locate Potentials key in AvatarBattleTemplateTb') | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/zzz/dm/src/dm/deobf/FileCfg/AvatarBattleTemplateTb.ts` around lines 45 -
55, The code uses non-null assertions on the results of two chained .find()
calls when computing potentialsKey from avatarBattleTemplateTb, which can throw
if the target array disappears; update the logic in the block that computes
potentialsKey so it first validates that avatarBattleTemplateTb has values,
captures the intermediate find result into a variable (e.g., foundObject) and
ensures it is not undefined before attempting Object.entries/find again, and if
either lookup fails, handle defensively by either logging/throwing a clear error
that includes the search target array ([119100,...,119105]) or skipping mapping
assignment; leave the final assignment mapping[potentialsKey] = 'Potentials'
only when potentialsKey is successfully resolved.
| return objKeyValMap(Object.values(dmObj), (v) => [ | ||
| reverseMapping[JSON.stringify(v)], | ||
| typeof v, | ||
| ]) |
There was a problem hiding this comment.
Inconsistent JSON.stringify usage between generateMapping and generateTyping.
yawns ...okay so I've been staring at this code for way too long pulling an all-nighter (again), but hear me out... In generateMapping (line 12), you only JSON.stringify(v) when v is an object, using the raw value for primitives. But here in generateTyping, you're always calling JSON.stringify(v) on line 23.
For a primitive like 95, generateMapping looks up reverseMapping[95], but generateTyping looks up reverseMapping["95"] (stringified). If your reverseMapping keys are numeric like '95': 'Attack', this mismatch could cause lookup failures and silently drop entries thanks to objKeyValMap behavior.
Maybe sync these up? The gacha gods won't bless your pulls if you leave bugs in datamine code...
☕ Proposed fix to align stringify logic
export function generateTyping(
reverseMapping: Record<string | number, string>,
dmObj: Record<string, string | number | object>
) {
return objKeyValMap(Object.values(dmObj), (v) => [
- reverseMapping[JSON.stringify(v)],
+ reverseMapping[typeof v === 'object' ? JSON.stringify(v) : v],
typeof v,
])
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return objKeyValMap(Object.values(dmObj), (v) => [ | |
| reverseMapping[JSON.stringify(v)], | |
| typeof v, | |
| ]) | |
| return objKeyValMap(Object.values(dmObj), (v) => [ | |
| reverseMapping[typeof v === 'object' ? JSON.stringify(v) : v], | |
| typeof v, | |
| ]) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/zzz/dm/src/dm/deobf/util.ts` around lines 22 - 25, generateTyping is
always JSON.stringify-ing values before reverseMapping lookup while
generateMapping only stringifies when the value is an object, causing mismatched
keys and dropped entries; update generateTyping (the return that calls
objKeyValMap over Object.values(dmObj)) to match generateMapping's logic: use
the raw primitive value for reverseMapping lookups and only JSON.stringify(v)
when typeof v === "object" (reference reverseMapping, dmObj, objKeyValMap,
generateMapping/generateTyping to locate the code), so keys align and entries
are not lost.
| it("can run", async () => { | ||
| const output = await executor(options, context); | ||
| expect(output.success).toBe(true); | ||
| }); |
There was a problem hiding this comment.
This “unit” test is not isolated and is likely flaky.
Lines 24–25 execute the real IO pipeline, so failures can come from filesystem/datamine state instead of executor logic.
Proposed test-hardening direction
+jest.mock('fs', () => ({ writeFileSync: jest.fn() }))
+jest.mock('../../util', () => ({
+ readDMJSON: jest.fn(() => JSON.stringify({ Test: [{ a: 1 }] })),
+}))
+jest.mock('../../dm/deobf', () => ({
+ deobfMappings: { Test: { mapping: { a: 'alpha' } } },
+}))
+jest.mock('@genshin-optimizer/common/pipeline', () => ({
+ formatText: jest.fn(async (_path: string, text: string) => text),
+}))Then keep the success assertion and add assertions that mocked collaborators were called.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/zzz/dm/src/executors/deobf/deobf.spec.ts` around lines 23 - 26, The test
currently calls the real executor pipeline (executor(options, context)) causing
non-deterministic IO; to harden it, mock/stub the executor's external
collaborators (filesystem/datamine functions or modules it imports) before
calling executor and assert those mocks were invoked in addition to
expect(output.success). Specifically, replace real IO with jest mocks/spies for
the modules or functions the executor uses, inject the mocked context/options as
needed, call executor(options, context), then add assertions that the mocked
collaborators were called (e.g., expect(mockFn).toHaveBeenCalled()) and keep
expect(output.success).toBe(true).
| const deobfedDm = Object.values(dm)[0].map((dmObj) => | ||
| objKeyValMap( | ||
| Object.entries(dmObj), | ||
| ([key, value]) => [deobfObj.mapping[key], value] as const | ||
| ) | ||
| ) |
There was a problem hiding this comment.
Unmapped keys will produce undefined keys in output JSON.
Okay so... rubs eyes ...if dmObj contains keys that aren't in the reverseMapping, then deobfObj.mapping[key] returns undefined. This means your deobfuscated output will have literal undefined as property names, which JSON.stringify converts to... well, let's just say it gets weird.
Either filter out unmapped keys or preserve the original key as a fallback. Unless you want mystery undefined fields showing up in your datamine output at 4am when you're trying to figure out a new character's stats.
🐛 Proposed fix: fallback to original key
const deobfedDm = Object.values(dm)[0].map((dmObj) =>
objKeyValMap(
Object.entries(dmObj),
- ([key, value]) => [deobfObj.mapping[key], value] as const
+ ([key, value]) => [deobfObj.mapping[key] ?? key, value] as const
)
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const deobfedDm = Object.values(dm)[0].map((dmObj) => | |
| objKeyValMap( | |
| Object.entries(dmObj), | |
| ([key, value]) => [deobfObj.mapping[key], value] as const | |
| ) | |
| ) | |
| const deobfedDm = Object.values(dm)[0].map((dmObj) => | |
| objKeyValMap( | |
| Object.entries(dmObj), | |
| ([key, value]) => [deobfObj.mapping[key] ?? key, value] as const | |
| ) | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/zzz/dm/src/executors/deobf/deobf.ts` around lines 15 - 20, The
deobfuscation step (deobfedDm creation) can produce properties named undefined
when deobfObj.mapping[key] is missing for keys in dmObj; update the mapping
callback used by objKeyValMap (the ([key, value]) => ... function) to either
skip entries with no mapping or use a safe fallback (e.g., deobfObj.mapping[key]
?? key) so unmapped keys don't become literal undefined properties; locate the
deobfedDm construction and change the mapping expression to use the fallback or
filter out unmapped entries before calling objKeyValMap.
| it('should run successfully', async () => { | ||
| await generateAllDeobfTemplateGenerator(tree) | ||
| const config = readProjectConfiguration(tree, 'test') | ||
| expect(config).toBeDefined() | ||
| }) |
There was a problem hiding this comment.
The assertion is disconnected from generator behavior.
Line 16 checks for project config 'test', but this generator’s job is template/index generation, not project registration. This test can fail even when generator behavior is correct.
Suggested test focus (orchestration check)
-import { readProjectConfiguration } from '@nx/devkit'
+import { allFileCfgs } from '../consts'
+import generateIndex from './generate-index-deobf'
+import generateSingleDeobfTemplateGenerator from './generate-single-deobf-template'
+
+jest.mock('./generate-index-deobf', () => ({ __esModule: true, default: jest.fn() }))
+jest.mock('./generate-single-deobf-template', () => ({
+ __esModule: true,
+ default: jest.fn(async () => undefined),
+}))
@@
it('should run successfully', async () => {
await generateAllDeobfTemplateGenerator(tree)
- const config = readProjectConfiguration(tree, 'test')
- expect(config).toBeDefined()
+ expect(generateSingleDeobfTemplateGenerator).toHaveBeenCalledTimes(allFileCfgs.length)
+ expect(generateIndex).toHaveBeenCalledWith(tree)
})🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/zzz/dm/src/generators/generate-all-deobf-template.spec.ts` around lines
14 - 18, The test is asserting a project config ('test') unrelated to
generateAllDeobfTemplateGenerator; update the spec to assert generator output
instead: remove the readProjectConfiguration('test') assertion and instead call
generateAllDeobfTemplateGenerator(tree) then verify generated artifacts—use
tree.exists('<expected/path>') and readFile(tree, '<expected/path>') (or
appropriate devkit helpers) to assert the template/index (or other expected
files and contents) were created/updated; reference the
generateAllDeobfTemplateGenerator function and the spec file
generate-all-deobf-template.spec.ts when making the change.
| const options: GenerateSingleDeobfTemplateGeneratorSchema = { file: 'test' } | ||
|
|
||
| beforeEach(() => { | ||
| tree = createTreeWithEmptyWorkspace() | ||
| }) | ||
|
|
||
| it('should run successfully', async () => { | ||
| await generateSingleDeobfTemplateGenerator(tree, options) | ||
| const config = readProjectConfiguration(tree, 'test') | ||
| expect(config).toBeDefined() |
There was a problem hiding this comment.
Test input and expectation don’t match generator contract.
Line 10 uses file: 'test', and Lines 18–19 assert project registration. This generator is file-template generation and expects a real DM file key, so this test is unlikely to validate the intended behavior.
Suggested correction direction
-const options: GenerateSingleDeobfTemplateGeneratorSchema = { file: 'test' }
+const options: GenerateSingleDeobfTemplateGeneratorSchema = {
+ file: 'AvatarBaseTemplateTb',
+}
@@
- const config = readProjectConfiguration(tree, 'test')
- expect(config).toBeDefined()
+ // Assert generated file behavior (or mock readDMJSON/writeFileSync and assert calls)
+ // e.g. expect(writeFileSync).toHaveBeenCalled()Prefer mocking readDMJSON + file IO in this unit test so it stays deterministic.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/zzz/dm/src/generators/generate-single-deobf-template.spec.ts` around
lines 10 - 19, The test passes an invalid contract to
generateSingleDeobfTemplateGenerator (using
GenerateSingleDeobfTemplateGeneratorSchema { file: 'test' }) but then asserts a
project was registered via readProjectConfiguration; instead, update the spec to
align with the generator's contract by either (A) supplying a valid DM file key
and expected DM JSON shape or (B) mocking the DM file IO and readDMJSON call so
the generator receives deterministic data, then assert the generator created the
expected template files/changes on the in-memory tree (e.g., check tree.read or
readTextFile results) rather than readProjectConfiguration; refer to
generateSingleDeobfTemplateGenerator,
GenerateSingleDeobfTemplateGeneratorSchema, and readDMJSON when adding the mock
and updating assertions.
Describe your changes
Add 2 pipelines that help in mapping known DM properties to human-readable names
There is still additional work that needs to be done for proper support in the code, such as:
Issue or discord link
Testing/validation
Checklist before requesting a review (leave this PR as draft if any part of this list is not done.)
yarn run mini-cilocally to validate format and lint.Summary by CodeRabbit
New Features
Documentation