@@ -6,10 +6,10 @@ const TypeChecker = require("../libs/TypeChecker.js");
66 * @class
77 */
88class Interface extends JavaLibraryScriptCore {
9- static _isDebugMode = false ;
9+ static _isDebugMode = true ;
1010
1111 /**
12- * 型定義とメゾットの強制実装
12+ * 型定義
1313 * @param {Function } TargetClass - 型定義を追加するクラス
1414 * @param {{[String]: {"args": Function[], "returns": Function[]}} } [newMethods] - 追加するメソッド群
1515 * @param {Object } [opt] - オプション
@@ -18,8 +18,6 @@ class Interface extends JavaLibraryScriptCore {
1818 * @static
1919 */
2020 static applyTo ( TargetClass , newDefs = { } , { inherit = true } = { } ) {
21- if ( ! this . _isDebugMode ) return ;
22-
2321 const proto = TargetClass . prototype ;
2422
2523 // 継承モードなら親の型定義をマージ
@@ -43,46 +41,80 @@ class Interface extends JavaLibraryScriptCore {
4341
4442 // 継承+新規定義マージ(子定義優先)
4543 Object . assign ( proto . __interfaceTypes , inheritedDefs , newDefs ) ;
44+ }
4645
47- for ( const methodName in proto . __interfaceTypes ) {
48- const def = proto . __interfaceTypes [ methodName ] ;
49- const original = proto [ methodName ] ;
50-
51- if ( typeof original !== "function" ) {
52- throw new Error ( `"${ TargetClass . name } " はメソッド "${ methodName } " を実装する必要があります` ) ;
53- }
46+ /**
47+ * 型定義とメゾットの強制実装
48+ * @param {Function } TargetClass - 型定義を追加するクラス
49+ * @param {{[String]: {"args": Function[], "returns": Function[]}} } [newMethods] - 追加するメソッド群
50+ * @param {Object } [opt] - オプション
51+ * @param {boolean } [opt.inherit=true] - 継承モード
52+ * @param {boolean } [opt.abstract=true] - 抽象クラス化
53+ * @returns {Function }
54+ * @static
55+ */
56+ static convert ( TargetClass , newDefs = { } , { inherit = true , abstract = true } = { } ) {
57+ this . applyTo ( TargetClass , newDefs , { inherit } ) ;
5458
55- proto [ methodName ] = function ( ...args ) {
56- // 引数チェック
57- const expectedArgs = def . args || [ ] ;
58- for ( let i = 0 ; i < expectedArgs . length ; i ++ ) {
59- if ( ! TypeChecker . matchType ( args [ i ] , expectedArgs [ i ] ) ) {
60- throw new TypeError ( `"${ TargetClass . name } .${ methodName } " 第${ i + 1 } 引数: ${ TypeChecker . typeNames ( expectedArgs [ i ] ) } を期待 → 実際: ${ TypeChecker . stringify ( args [ i ] ) } ` ) ;
59+ const interfaceClass = class extends TargetClass {
60+ constructor ( ...args ) {
61+ if ( abstract ) {
62+ if ( new . target === interfaceClass ) {
63+ throw new TypeError ( `Cannot instantiate abstract class ${ TargetClass . name } ` ) ;
6164 }
6265 }
66+ super ( ...args ) ;
67+
68+ if ( ! Interface . _isDebugMode ) return ;
69+
70+ const proto = Object . getPrototypeOf ( this ) ;
71+ const defs = proto . __interfaceTypes || { } ;
6372
64- const result = original . apply ( this , args ) ;
65- const ret = def . returns ;
66- const expectedReturn = TypeChecker . checkFunction ( ret ) ? ret ( args ) : ret ;
67-
68- const validate = ( val ) => {
69- if ( ! TypeChecker . matchType ( val , expectedReturn ) ) {
70- if ( expectedReturn === InterfaceTypeChecker . NO_RETURN ) {
71- throw new TypeError ( `"${ TargetClass . name } .${ methodName } " は戻り値を返してはいけません → 実際: ${ TypeChecker . stringify ( val ) } ` ) ;
72- } else {
73- throw new TypeError ( `"${ TargetClass . name } .${ methodName } " の戻り値: ${ TypeChecker . typeNames ( expectedReturn ) } を期待 → 実際: ${ TypeChecker . stringify ( val ) } ` ) ;
74- }
73+ for ( const methodName of Object . keys ( defs ) ) {
74+ const def = defs [ methodName ] ;
75+ const original = this [ methodName ] ;
76+
77+ if ( typeof original !== "function" ) {
78+ throw new Error ( `"${ this . constructor . name } " はメソッド "${ methodName } " を実装する必要があります` ) ;
7579 }
76- return val ;
77- } ;
7880
79- if ( result instanceof Promise ) {
80- return result . then ( validate ) ;
81- } else {
82- return validate ( result ) ;
81+ // ラップは一度だけ(重複防止)
82+ if ( ! original . __isWrapped ) {
83+ const wrapped = ( ...args ) => {
84+ // 引数チェック
85+ const expectedArgs = def . args || [ ] ;
86+ for ( let i = 0 ; i < expectedArgs . length ; i ++ ) {
87+ if ( ! TypeChecker . matchType ( args [ i ] , expectedArgs [ i ] ) ) {
88+ throw new TypeError ( `"${ this . constructor . name } .${ methodName } " 第${ i + 1 } 引数: ${ TypeChecker . typeNames ( expectedArgs [ i ] ) } を期待 → 実際: ${ TypeChecker . stringify ( args [ i ] ) } ` ) ;
89+ }
90+ }
91+
92+ const result = original . apply ( this , args ) ;
93+ const expectedReturn = TypeChecker . checkFunction ( def . returns ) ? def . returns ( args ) : def . returns ;
94+
95+ const validate = ( val ) => {
96+ if ( ! TypeChecker . matchType ( val , expectedReturn ) ) {
97+ if ( expectedReturn === TypeChecker . NoReturn ) {
98+ throw new TypeError ( `"${ this . constructor . name } .${ methodName } " は戻り値を返してはいけません → 実際: ${ TypeChecker . stringify ( val ) } ` ) ;
99+ } else {
100+ throw new TypeError ( `"${ this . constructor . name } .${ methodName } " の戻り値: ${ TypeChecker . typeNames ( expectedReturn ) } を期待 → 実際: ${ TypeChecker . stringify ( val ) } ` ) ;
101+ }
102+ }
103+ return val ;
104+ } ;
105+
106+ return result instanceof Promise ? result . then ( validate ) : validate ( result ) ;
107+ } ;
108+ wrapped . __isWrapped = true ;
109+ this [ methodName ] = wrapped ;
110+ }
83111 }
84- } ;
85- }
112+ }
113+ } ;
114+
115+ Object . defineProperty ( interfaceClass , "name" , { value : TargetClass . name } ) ;
116+
117+ return interfaceClass ;
86118 }
87119}
88120
0 commit comments