Prepare scanner branch for merge

This commit is contained in:
AzuTear
2026-07-09 08:44:50 +02:00
parent f791d1464c
commit 8b73c01e46
69 changed files with 6700 additions and 3773 deletions
@@ -16,22 +16,71 @@ export class ScannerLearningRepository implements ScannerLearningRepositoryPort
return {
ok: true,
path: this.filePath,
rules: parsed && typeof parsed === "object" ? parsed : { textReplacements: {} },
rules: parsed && typeof parsed === "object" ? parsed : emptyRules(),
};
} catch {
return { ok: true, path: this.filePath, rules: { textReplacements: {} } };
return { ok: true, path: this.filePath, rules: emptyRules() };
}
}
async save(rules: ScannerLearningRules): Promise<ScannerLearningSaveResult> {
const current = await this.load();
const nextTextReplacements = {
...((current.rules as { textReplacements?: Record<string, string> })?.textReplacements ?? {}),
...((rules as { textReplacements?: Record<string, string> })?.textReplacements ?? {}),
};
const payload: ScannerLearningRules = { textReplacements: nextTextReplacements };
const payload: ScannerLearningRules = mergeRules(current.rules, rules);
await fs.mkdir(path.dirname(this.filePath), { recursive: true });
await fs.writeFile(this.filePath, JSON.stringify(payload, null, 2), "utf8");
return { ok: true, path: this.filePath, rules: payload, total: Object.keys(nextTextReplacements).length };
return { ok: true, path: this.filePath, rules: payload, total: countRules(payload) };
}
}
function emptyRules(): ScannerLearningRules {
return {
textReplacements: {},
fieldAliases: {},
constrainedFixes: {},
cropAdjustments: {},
uiProfileAdjustments: {},
};
}
function mergeRules(current: ScannerLearningRules, incoming: ScannerLearningRules): ScannerLearningRules {
return {
textReplacements: {
...(current.textReplacements ?? {}),
...(incoming.textReplacements ?? {}),
},
fieldAliases: mergeNested(current.fieldAliases, incoming.fieldAliases),
constrainedFixes: {
...(current.constrainedFixes ?? {}),
...(incoming.constrainedFixes ?? {}),
},
cropAdjustments: {
...(current.cropAdjustments ?? {}),
...(incoming.cropAdjustments ?? {}),
},
uiProfileAdjustments: {
...(current.uiProfileAdjustments ?? {}),
...(incoming.uiProfileAdjustments ?? {}),
},
};
}
function mergeNested(
current: Record<string, Record<string, string>> | undefined,
incoming: Record<string, Record<string, string>> | undefined,
) {
const merged: Record<string, Record<string, string>> = {};
for (const [field, values] of Object.entries(current ?? {})) merged[field] = { ...(values ?? {}) };
for (const [field, values] of Object.entries(incoming ?? {})) merged[field] = { ...(merged[field] ?? {}), ...(values ?? {}) };
return merged;
}
function countRules(rules: ScannerLearningRules) {
const fieldAliases = Object.values(rules.fieldAliases ?? {}).reduce((sum, aliases) => sum + Object.keys(aliases ?? {}).length, 0);
return (
Object.keys(rules.textReplacements ?? {}).length
+ fieldAliases
+ Object.keys(rules.constrainedFixes ?? {}).length
+ Object.keys(rules.cropAdjustments ?? {}).length
+ Object.keys(rules.uiProfileAdjustments ?? {}).length
);
}