Skip to content

Commit

Permalink
Fix lang constants error message (#12)
Browse files Browse the repository at this point in the history
* chore update

* fix

* fix

* chabgeset
  • Loading branch information
takurinton authored Aug 20, 2024
1 parent b6a2a91 commit f28d5d9
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 56 deletions.
5 changes: 5 additions & 0 deletions .changeset/twelve-phones-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@takurinton/eslint-plugin-i18n": patch
---

Fix lang constants error message
18 changes: 15 additions & 3 deletions packages/i18n/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,13 @@ ruleTester.run("i18n/constants", constantsRule, {
{
messageId: "missing_key_value",
data: {
lang: "ja",
key: "Button.defaultProps",
},
},
{
messageId: "missing_key_value",
data: {
key: "Button.defaultProps.key",
},
},
],
Expand Down Expand Up @@ -168,7 +174,13 @@ ruleTester.run("i18n/constants", constantsRule, {
{
messageId: "missing_key_value",
data: {
lang: "ja",
key: "Button.defaultProps",
},
},
{
messageId: "missing_key_value",
data: {
key: "Button.defaultProps.key",
},
},
],
Expand Down Expand Up @@ -207,7 +219,7 @@ ruleTester.run("i18n/constants", constantsRule, {
{
messageId: "missing_key_value",
data: {
lang: "ja",
key: "Input.defaultProps",
},
},
],
Expand Down
48 changes: 24 additions & 24 deletions packages/i18n/src/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// @ts-nocheck
import { describe, it, expect } from "vitest";
import { TSESTree } from "@typescript-eslint/utils";
import { getProperties, haveSameKeys } from "../rules/utils";
import { getProperties, findMismatchedPropertiesKeys } from "../rules/utils";
import { AST_NODE_TYPES } from "@typescript-eslint/utils";

describe("getProperties", () => {
Expand Down Expand Up @@ -99,61 +99,61 @@ describe("getProperties", () => {
});
});

describe("haveSameKeys", () => {
describe("findMismatchedPropertiesKeys", () => {
it("should return true for maps with identical nested keys", () => {
const map = new Map<string, unknown>([
["obj1", { a: 1, b: { c: 2, d: 3 } }],
["obj2", { a: 10, b: { c: 20, d: 30 } }],
["obj1", { properties: { a: 1, b: { c: 2, d: 3 } } }],
["obj2", { properties: { a: 10, b: { c: 20, d: 30 } } }],
]);

const result = haveSameKeys(map);
expect(result).toBe(true);
const result = findMismatchedPropertiesKeys(map);
expect(result).toBe(null);
});

it("should return false for maps with different nested keys", () => {
const map = new Map<string, unknown>([
["obj1", { a: 1, b: { c: 2, d: 3 } }],
["obj2", { a: 10, b: { c: 20, e: 30 } }], // Different key "e"
["obj1", { properties: { a: 1, b: { c: 2, d: 3 } } }],
["obj2", { properties: { a: 10, b: { c: 20, e: 30 } } }], // Different key "e"
]);

const result = haveSameKeys(map);
expect(result).toBe(false);
const result = findMismatchedPropertiesKeys(map);
expect(result).toEqual(["b.d", "b.e"]);
});

it("should return false for maps with different top-level keys", () => {
const map = new Map<string, unknown>([
["obj1", { a: 1, b: 2 }],
["obj2", { a: 1, c: 2 }], // Different key "c"
["obj1", { properties: { a: 1, b: 2 } }],
["obj2", { properties: { a: 1, c: 2 } }], // Different key "c"
]);

const result = haveSameKeys(map);
expect(result).toBe(false);
const result = findMismatchedPropertiesKeys(map);
expect(result).toEqual(["b", "c"]);
});

it("should return true for empty maps", () => {
const map = new Map<string, unknown>();

const result = haveSameKeys(map);
expect(result).toBe(false);
const result = findMismatchedPropertiesKeys(map);
expect(result).toBe(null);
});

it("should return true for maps with identical simple keys", () => {
const map = new Map<string, unknown>([
["obj1", { a: 1, b: 2 }],
["obj2", { a: 3, b: 4 }],
["obj1", { properties: { a: 1, b: 2 } }],
["obj2", { properties: { a: 3, b: 4 } }],
]);

const result = haveSameKeys(map);
expect(result).toBe(true);
const result = findMismatchedPropertiesKeys(map);
expect(result).toBe(null);
});

it("should return false for maps where one object is empty", () => {
const map = new Map<string, unknown>([
["obj1", { a: 1, b: 2 }],
["obj2", {}],
["obj1", { properties: { a: 1, b: 2 } }],
["obj2", { properties: {} }],
]);

const result = haveSameKeys(map);
expect(result).toBe(false);
const result = findMismatchedPropertiesKeys(map);
expect(result).toEqual(["a", "b"]);
});
});
26 changes: 16 additions & 10 deletions packages/i18n/src/rules/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TSESLint } from "@typescript-eslint/utils";
import { MessageId, Options } from "./types";
import { messages } from "./messages";
import { getProperties, haveSameKeys } from "./utils";
import { getProperties, findMismatchedPropertiesKeys } from "./utils";

const LOCALE_FILE_NAME = "i18n/constants/locale";

Expand Down Expand Up @@ -122,15 +122,21 @@ export const constantsRule: TSESLint.RuleModule<MessageId, Options> = {
return;
}

if (!haveSameKeys(componentsMap)) {
context.report({
// 基本的にnullになることはない
loc: componentsMap.get(componentsKeys[0])?.loc ?? {
line: 1,
column: 0,
},
messageId: "missing_key_value",
});
const missmatchedKeys = findMismatchedPropertiesKeys(componentsMap);

if (missmatchedKeys !== null) {
for (const missmatchedKey of missmatchedKeys) {
context.report({
loc: componentsMap.get(componentsKeys[0])?.loc ?? {
line: 1,
column: 0,
},
messageId: "missing_key_value",
data: {
key: missmatchedKey,
},
});
}
}
},
};
Expand Down
3 changes: 2 additions & 1 deletion packages/i18n/src/rules/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { Messages } from "./types";

export const messages: Messages = {
// constants
missing_key_value: "keyまたはvalueが見つかりません",
missing_key_value:
"言語定数のプロパティが一致しません。{{ key }}が見つかりません。",

// defineLanguageConstantVariables
missing_language: "{{ lang }}の定数を定義してください",
Expand Down
54 changes: 36 additions & 18 deletions packages/i18n/src/rules/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,47 @@ export const getProperties = (
return null;
};

export const haveSameKeys = (map: Map<string, unknown>): boolean => {
const extractKeys = (obj: unknown): string[] => {
if (typeof obj !== "object" || obj === null) return [];

const keys = Object.keys(obj as object);
export const findMismatchedPropertiesKeys = (
map: Map<
string,
{ properties: unknown; loc: { line: number; column: number } }
>,
): string[] | null => {
const extractDeepestKeys = (obj: unknown, prefix = ""): string[] => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
const keys = Object.keys(obj);
return keys.flatMap((key) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const nestedKeys = extractKeys((obj as any)[key]);
return nestedKeys.length > 0
? nestedKeys.map((nestedKey) => `${key}.${nestedKey}`)
: key;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
const value = obj[key];
const newPrefix = prefix ? `${prefix}.${key}` : key;
if (typeof value === "object" && value !== null) {
const nestedKeys = extractDeepestKeys(
value as Record<string, unknown>,
newPrefix,
);
return nestedKeys.length > 0 ? nestedKeys : [newPrefix];
}
return [newPrefix];
});
};

const keysArray = Array.from(map.values()).map(extractKeys);
const keysArray = Array.from(map.values()).map((value) =>
extractDeepestKeys(value.properties),
);

if (keysArray.length === 0) return null;

if (keysArray.length === 0) return false;
const allKeys = new Set(keysArray.flat());
const mismatchedKeys: string[] = [];

const baseKeys = keysArray[0];
for (const key of allKeys) {
const isPresentInAll = keysArray.every((keys) => keys.includes(key));
if (!isPresentInAll) {
mismatchedKeys.push(key);
}
}

return keysArray.every(
(keys) =>
keys.length === baseKeys.length &&
keys.every((key) => baseKeys.includes(key)),
);
return mismatchedKeys.length > 0 ? mismatchedKeys : null;
};

0 comments on commit f28d5d9

Please sign in to comment.