70 lines
2.1 KiB
JavaScript
70 lines
2.1 KiB
JavaScript
import ts from "typescript";
|
|
|
|
export function findDuplicateTranslationKeys(sourceText, fileName = "generatedTranslations.ts") {
|
|
const source = ts.createSourceFile(
|
|
fileName,
|
|
sourceText,
|
|
ts.ScriptTarget.Latest,
|
|
true,
|
|
ts.ScriptKind.TS
|
|
);
|
|
const findings = [];
|
|
|
|
function visit(node) {
|
|
if (
|
|
ts.isVariableDeclaration(node) &&
|
|
ts.isIdentifier(node.name) &&
|
|
node.name.text === "generatedTranslations" &&
|
|
node.initializer &&
|
|
ts.isObjectLiteralExpression(node.initializer)
|
|
) {
|
|
scanCatalog(node.initializer);
|
|
}
|
|
ts.forEachChild(node, visit);
|
|
}
|
|
|
|
function scanCatalog(catalog) {
|
|
for (const localeProperty of catalog.properties) {
|
|
if (!ts.isPropertyAssignment(localeProperty) || !ts.isObjectLiteralExpression(localeProperty.initializer)) {
|
|
continue;
|
|
}
|
|
const locale = propertyName(localeProperty.name);
|
|
const firstDeclarations = new Map();
|
|
for (const translationProperty of localeProperty.initializer.properties) {
|
|
if (!ts.isPropertyAssignment(translationProperty)) continue;
|
|
const key = propertyName(translationProperty.name);
|
|
if (!key) continue;
|
|
const first = firstDeclarations.get(key);
|
|
if (!first) {
|
|
firstDeclarations.set(key, translationProperty.name);
|
|
continue;
|
|
}
|
|
const duplicatePosition = source.getLineAndCharacterOfPosition(
|
|
translationProperty.name.getStart(source)
|
|
);
|
|
const firstPosition = source.getLineAndCharacterOfPosition(first.getStart(source));
|
|
findings.push(
|
|
`${fileName}:${duplicatePosition.line + 1}:${duplicatePosition.character + 1} ` +
|
|
`duplicate generated translation key ${JSON.stringify(key)} in locale ` +
|
|
`${JSON.stringify(locale)}; first declared at line ${firstPosition.line + 1}`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
visit(source);
|
|
return findings;
|
|
}
|
|
|
|
function propertyName(name) {
|
|
if (
|
|
ts.isIdentifier(name) ||
|
|
ts.isStringLiteral(name) ||
|
|
ts.isNumericLiteral(name) ||
|
|
ts.isNoSubstitutionTemplateLiteral(name)
|
|
) {
|
|
return name.text;
|
|
}
|
|
return "";
|
|
}
|