Skip to content

Commit be1e431

Browse files
committed
⚡️ utilとlibsに分離
1 parent f8bdd31 commit be1e431

File tree

5 files changed

+126
-122
lines changed

5 files changed

+126
-122
lines changed

index.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
(function (w) {
22
const loadList = [
33
// それぞれのライブラリをロード
4-
"dynamicEnum.js",
5-
"interface.js",
4+
// libs
5+
"libs/TypeChecker.js",
6+
7+
// util
8+
"util/dynamicEnum.js",
9+
"util/interface.js",
610
];
711

812
const eventName = "javaLibraryScriptLoad";

interface.js

Lines changed: 0 additions & 120 deletions
This file was deleted.

libs/TypeChecker.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
class TypeChecker {
2+
static matchType(value, expected) {
3+
if (Array.isArray(expected)) return expected.some((e) => this.checkType(value, e));
4+
return this.checkType(value, expected);
5+
}
6+
7+
static checkType(value, expected) {
8+
if (expected === null) return value === null;
9+
if (expected === undefined) return value === undefined;
10+
if (expected === String || expected === Number || expected === Boolean || expected === Symbol || expected === Function || expected === BigInt) return typeof value === expected.name.toLowerCase();
11+
if (expected === Object) return typeof value === "object" && value !== null && !Array.isArray(value);
12+
if (expected === Array) return Array.isArray(value);
13+
// ----- DynamicEnum対応
14+
if (expected instanceof _DynamicEnumCore) {
15+
// DynamicEnumの場合
16+
return expected.has(value?.name);
17+
}
18+
if (expected === _EnumItem) return value instanceof _EnumItem;
19+
// -----
20+
if (typeof expected === "function") return value instanceof expected;
21+
return false;
22+
}
23+
24+
static typeNames(expected) {
25+
if (Array.isArray(expected)) return expected.map((t) => t?.name || TypeChecker.__iface_stringify(t)).join(" | ");
26+
return expected?.name || TypeChecker.__iface_stringify(expected);
27+
}
28+
29+
static stringify(value) {
30+
if (value === null || value === undefined) {
31+
return String(value);
32+
}
33+
if (typeof value === "object") {
34+
if (value?.toString() !== "[object Object]") {
35+
return String(value);
36+
}
37+
try {
38+
const jsonString = JSON.stringify(
39+
value,
40+
(key, val) => {
41+
if (val && typeof val === "object") {
42+
const size = Object.keys(val).length;
43+
// オブジェクトが大きすぎる場合は省略表示
44+
if (size > 5) {
45+
return `Object with ${size} properties`;
46+
}
47+
}
48+
return val;
49+
},
50+
0
51+
);
52+
// JSON.stringifyエラー時にfallback
53+
if (jsonString === undefined) {
54+
return "Object is too large to display or contains circular references";
55+
}
56+
57+
return jsonString.length > 1000 ? "Object is too large to display" : jsonString; // 文字数が多すぎる場合は省略
58+
} catch (e) {
59+
return `[オブジェクト表示エラー: ${e.message}]`; // サークル参照等のエラー防止
60+
}
61+
}
62+
return String(value); // それ以外の型はそのまま文字列に変換
63+
}
64+
}
File renamed without changes.

util/interface.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
class Interface {
2+
static _isDebugMode = false;
3+
4+
static methodTypes = {};
5+
6+
constructor() {
7+
if (new.target === Interface) {
8+
throw new Error("Interfaceは直接インスタンス化できません。継承して使ってください。");
9+
}
10+
11+
if (!Interface._isDebugMode) return;
12+
13+
const CLASS_REG = /^\s*class\s+/;
14+
15+
const cls = this.constructor;
16+
const typeDefs = cls.methodTypes || {};
17+
18+
for (const method in typeDefs) {
19+
const def = typeDefs[method];
20+
if (typeof this[method] !== "function") {
21+
throw new Error(`"${cls.name}" はメソッド "${method}" を実装する必要があります`);
22+
}
23+
24+
const originalMethod = this[method].bind(this);
25+
26+
this[method] = (...args) => {
27+
// 引数チェック
28+
const expectedArgs = def.args || [];
29+
for (let i = 0; i < expectedArgs.length; i++) {
30+
if (!TypeChecker.matchType(args[i], expectedArgs[i])) {
31+
throw new TypeError(`"${cls.name}.${method}" 第${i + 1}引数: ${TypeChecker.typeNames(expectedArgs[i])} を期待 → 実際: ${TypeChecker.stringify(args[i])}`);
32+
}
33+
}
34+
35+
const result = originalMethod(...args);
36+
37+
// 戻り値型を動的に取得
38+
const ret = def.returns;
39+
const expectedReturn = typeof ret === "function" && !CLASS_REG.test(ret.toString()) ? ret(args) : ret;
40+
41+
const validate = (val) => {
42+
if (!TypeChecker.matchType(val, expectedReturn)) {
43+
throw new TypeError(`"${cls.name}.${method}" の戻り値: ${TypeChecker.typeNames(expectedReturn)} を期待 → 実際: ${TypeChecker.stringify(val)}`);
44+
}
45+
return val;
46+
};
47+
48+
if (result instanceof Promise) {
49+
return result.then(validate);
50+
} else {
51+
return validate(result);
52+
}
53+
};
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)