commit 06967e23c9c8f9817ec1e9b826003284d9c3675d Author: crusader Date: Wed May 16 15:57:12 2018 +0900 ing diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..981da4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/dist-server +/tmp +/out-tsc + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +testem.log +/typings + +# e2e +/e2e/*.js +/e2e/*.map + +# System Files +.DS_Store +Thumbs.db + +yarn.lock \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..aefa44c --- /dev/null +++ b/.npmignore @@ -0,0 +1,3 @@ +tsconfig.json +tslint.json +src \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..004c24c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,489 @@ +{ + "name": "@loafer/core", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/node": { + "version": "8.0.58", + "resolved": "https://nexus.loafle.net/repository/npm-all/@types/node/-/node-8.0.58.tgz", + "integrity": "sha512-V746iUU7eHNdzQipoACuguDlVhC7IHK8CES1jSkuFt352wwA84BCWPXaGekBd7R5XdNK5ReHONDVKxlL9IreAw==", + "dev": true + }, + "@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "dev": true + }, + "@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://nexus.loafle.net/repository/npm-all/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://nexus.loafle.net/repository/npm-all/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://nexus.loafle.net/repository/npm-all/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://nexus.loafle.net/repository/npm-all/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/buffer-from/-/buffer-from-1.0.0.tgz", + "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://nexus.loafle.net/repository/npm-all/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.15.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://nexus.loafle.net/repository/npm-all/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://nexus.loafle.net/repository/npm-all/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://nexus.loafle.net/repository/npm-all/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://nexus.loafle.net/repository/npm-all/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://nexus.loafle.net/repository/npm-all/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://nexus.loafle.net/repository/npm-all/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.11.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/js-yaml/-/js-yaml-3.11.0.tgz", + "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "make-error": { + "version": "1.3.4", + "resolved": "https://nexus.loafle.net/repository/npm-all/make-error/-/make-error-1.3.4.tgz", + "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://nexus.loafle.net/repository/npm-all/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://nexus.loafle.net/repository/npm-all/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://nexus.loafle.net/repository/npm-all/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "reflect-metadata": { + "version": "0.1.12", + "resolved": "https://nexus.loafle.net/repository/npm-all/reflect-metadata/-/reflect-metadata-0.1.12.tgz", + "integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==" + }, + "resolve": { + "version": "1.7.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/resolve/-/resolve-1.7.1.tgz", + "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.6", + "resolved": "https://nexus.loafle.net/repository/npm-all/source-map-support/-/source-map-support-0.5.6.tgz", + "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", + "dev": true, + "requires": { + "buffer-from": "1.0.0", + "source-map": "0.6.1" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://nexus.loafle.net/repository/npm-all/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "ts-node": { + "version": "4.0.2", + "resolved": "https://nexus.loafle.net/repository/npm-all/ts-node/-/ts-node-4.0.2.tgz", + "integrity": "sha512-mg7l6ON8asjnfzkTi1LFWKaOGHl5Jf1+5ij0MQ502YfC6+4FBgh/idJgw9aN9kei1Rf4/pmFpNuFE1YbcQdOTA==", + "dev": true, + "requires": { + "arrify": "1.0.1", + "chalk": "2.4.1", + "diff": "3.5.0", + "make-error": "1.3.4", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "source-map-support": "0.5.6", + "tsconfig": "7.0.0", + "v8flags": "3.1.0", + "yn": "2.0.0" + } + }, + "tsconfig": { + "version": "7.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "requires": { + "@types/strip-bom": "3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1" + } + }, + "tslib": { + "version": "1.9.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "dev": true + }, + "tslint": { + "version": "5.9.1", + "resolved": "https://nexus.loafle.net/repository/npm-all/tslint/-/tslint-5.9.1.tgz", + "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "builtin-modules": "1.1.1", + "chalk": "2.4.1", + "commander": "2.15.1", + "diff": "3.5.0", + "glob": "7.1.2", + "js-yaml": "3.11.0", + "minimatch": "3.0.4", + "resolve": "1.7.1", + "semver": "5.5.0", + "tslib": "1.9.0", + "tsutils": "2.27.0" + } + }, + "tsutils": { + "version": "2.27.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/tsutils/-/tsutils-2.27.0.tgz", + "integrity": "sha512-JcyX25oM9pFcb3zh60OqG1St8p/uSqC5Bgipdo3ieacB/Ao4dPhm7hAtKT9NrEu23CyYrrgJPV3CqYfo+/+T4w==", + "dev": true, + "requires": { + "tslib": "1.9.0" + } + }, + "typescript": { + "version": "2.5.3", + "resolved": "https://nexus.loafle.net/repository/npm-all/typescript/-/typescript-2.5.3.tgz", + "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", + "dev": true + }, + "v8flags": { + "version": "3.1.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/v8flags/-/v8flags-3.1.0.tgz", + "integrity": "sha512-0m69VIK2dudEf2Ub0xwLQhZkDZu85OmiOpTw+UGDt56ibviYICHziM/3aE+oVg7IjGPp0c83w3eSVqa+lYZ9UQ==", + "dev": true, + "requires": { + "homedir-polyfill": "1.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://nexus.loafle.net/repository/npm-all/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://nexus.loafle.net/repository/npm-all/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..820e9d5 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "@loafer/core", + "description": "Core module of loafer", + "version": "0.0.3", + "license": "MIT", + "private": false, + "repository": { + "type": "git", + "url": "https://git.loafle.net/loafer/typescript/core.git" + }, + "publishConfig": { + "registry": "https://nexus.loafle.net/repository/npm-loafle/" + }, + "keywords": [], + "author": "Loafle ", + "scripts": { + "compile": "npm run clean && tsc -p .", + "watch": "tsc -w -p .", + "clean": "rm -rf dist" + }, + "dependencies": { + "reflect-metadata": "^0.1.12" + }, + "devDependencies": { + "@types/node": "~8.0.0", + "ts-node": "~4.0.1", + "tslint": "~5.9.1", + "typescript": "~2.5.3" + } +} diff --git a/src/error.ts b/src/error.ts new file mode 100644 index 0000000..e1e727b --- /dev/null +++ b/src/error.ts @@ -0,0 +1,6 @@ +export class IllegalArgumentError extends Error { + public constructor(message?: string) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..ad66f68 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,2 @@ +export * from './error'; +export * from './type'; diff --git a/src/reflect/AccessibleObject.ts b/src/reflect/AccessibleObject.ts new file mode 100644 index 0000000..5e31fab --- /dev/null +++ b/src/reflect/AccessibleObject.ts @@ -0,0 +1,64 @@ +import { + Type, +} from '../type'; + +import { + TypeUtil, +} from '../util/TypeUtil'; + +import { AnnotatedElement } from './AnnotatedElement'; +import { Annotation } from './Annotation'; + +export abstract class AccessibleObject implements AnnotatedElement { + private _annotations: Map, Annotation>; + + protected constructor() { + this._annotations = new Map(); + } + + public _addAnnotation(annotation: AnnotationType): void { + this._annotations.set(TypeUtil.getType(annotation), annotation); + } + + public isAnnotationPresent(annotationClass: Type): boolean { + return null !== this.getAnnotation(annotationClass); + } + + public getOwnAnnotation(annotationClass: Type): AnnotationType | undefined { + return this._annotations.get(annotationClass); + } + + public getOwnAnnotations(): Map, Annotation> { + return this._annotations; + } + + public getOwnAnnotationsByType(annotationClass: Type) + : AnnotationType[] | undefined { + if (0 === this._annotations.size) { + return undefined; + } + const results: AnnotationType[] = []; + for (const classType of Array.from(this._annotations.keys())) { + if (classType === annotationClass) { + results.push(this._annotations.get(classType)); + } + } + if (0 === results.length) { + return undefined; + } + return results; + } + + public getAnnotation(annotationClass: Type): AnnotationType | undefined { + return this.getOwnAnnotation(annotationClass); + } + + public getAnnotations(): Map, Annotation> { + return this.getOwnAnnotations(); + } + + public getAnnotationsByType(annotationClass: Type) + : AnnotationType[] | undefined { + return this.getOwnAnnotationsByType(annotationClass); + } +} diff --git a/src/reflect/AnnotatedElement.ts b/src/reflect/AnnotatedElement.ts new file mode 100644 index 0000000..3cd1663 --- /dev/null +++ b/src/reflect/AnnotatedElement.ts @@ -0,0 +1,17 @@ +import { + Type, +} from '../type'; + +import { Annotation } from './Annotation'; + +export interface AnnotatedElement { + _addAnnotation(annotation: AnnotationType): void; + + isAnnotationPresent(annotationClass: Type): boolean; + getOwnAnnotation(annotationClass: Type): AnnotationType | undefined; + getOwnAnnotations(): Map, Annotation>; + getOwnAnnotationsByType(annotationClass: Type): AnnotationType[] | undefined; + getAnnotation(annotationClass: Type): AnnotationType | undefined; + getAnnotations(): Map, Annotation>; + getAnnotationsByType(annotationClass: Type): AnnotationType[] | undefined; +} diff --git a/src/reflect/Annotation.ts b/src/reflect/Annotation.ts new file mode 100644 index 0000000..7155b2d --- /dev/null +++ b/src/reflect/Annotation.ts @@ -0,0 +1,7 @@ +export abstract class Annotation { + public readonly attribute: Attribute; + + public constructor(attribute?: Attribute) { + this.attribute = attribute; + } +} diff --git a/src/reflect/Class.ts b/src/reflect/Class.ts new file mode 100644 index 0000000..da1c2bc --- /dev/null +++ b/src/reflect/Class.ts @@ -0,0 +1,228 @@ +import { + Type, + PropertyKeyType, +} from '../type'; + +import { + TypeUtil, +} from '../util/TypeUtil'; + +import { AccessibleObject } from './AccessibleObject'; +import { Annotation } from './Annotation'; +import { SystemClassRegistry } from './ClassRegistry'; +import { Constructor } from './Constructor'; +import { Field } from './Field'; +import { Method } from './Method'; +import { Metadata } from './Metadata'; + + + +export class Class extends AccessibleObject { + private _type: Type; + private _constructor: Constructor; + private _fields: Map; + private _methods: Map; + + /** + * forClass + */ + public static forType(type: Type): Class | undefined { + return SystemClassRegistry.get(type); + } + + /** + * _defineClass + */ + public static _defineClass(type: Type): Class { + let clazz: Class = Class.forType(type); + if (undefined === clazz) { + clazz = new Class(type); + SystemClassRegistry.set(type, clazz); + } + + if (null === clazz._constructor) { + const parameterTypes = Metadata.getOwnParamTypes(type); + if (undefined !== parameterTypes) { + clazz._constructor = new Constructor(clazz, parameterTypes); + } + } + + return clazz; + } + + private constructor(type: Type) { + super(); + this._type = type; + this._fields = new Map(); + this._methods = new Map(); + } + + /** + * _defineField + */ + public _defineConstructor(parameterTypes: any[]): Constructor { + let cons: Constructor = this._constructor; + if (undefined === cons) { + cons = new Constructor(this, parameterTypes); + this._constructor = cons; + } + return cons; + } + + /** + * _defineField + */ + public _defineField(propertyKey: PropertyKeyType, propertyType: any): Field { + let field: Field = this._fields.get(propertyKey); + if (undefined === field) { + field = new Field(this, propertyKey, propertyType); + this._fields.set(propertyKey, field); + } + return field; + } + + /** + * _defineMethod + */ + public _defineMethod(propertyKey: PropertyKeyType, parameterTypes: any[], returnType: any): Method { + let method: Method = this._methods.get(propertyKey); + if (undefined === method) { + method = new Method(this, propertyKey, parameterTypes, returnType); + this._methods.set(propertyKey, method); + } + return method; + } + + public getType(): Type { + return this._type; + } + + public getConstructor(): Constructor { + if (undefined === this._constructor) { + this._constructor = new Constructor(this, undefined); + } + return this._constructor; + } + + public getOwnField(propertyKey: PropertyKeyType): Field | undefined { + return this._fields.get(propertyKey); + } + + public getOwnFields(): Map { + return this._fields; + } + + public getField(propertyKey: PropertyKeyType): Field | undefined { + const fields = this.getFields(); + + return fields.get(propertyKey); + } + + public getFields(): Map { + const fields: Map = new Map(); + + const types = TypeUtil.ancestorsOf(this._type); + if (null === types || 0 === types.length) { + return fields; + } + for (let i = 0; i < types.length; i++) { + const tType = types[i]; + const tClazz = Class.forType(tType); + if (undefined === tClazz) { + continue; + } + + tClazz.getOwnFields().forEach((value: Field, key: PropertyKeyType): void => { + fields.set(key, value); + }); + } + + return fields; + } + + public getOwnMethod(propertyKey: PropertyKeyType): Method | undefined { + return this._methods.get(propertyKey); + } + + public getOwnMethods(): Map { + return this._methods; + } + + public getMethod(propertyKey: PropertyKeyType): Method | undefined { + const methods = this.getMethods(); + + return methods.get(propertyKey); + } + + public getMethods(): Map { + const methods: Map = new Map(); + + const types = TypeUtil.ancestorsOf(this._type); + if (null === types || 0 === types.length) { + return methods; + } + for (let i = 0; i < types.length; i++) { + const tClazzType = types[i]; + const tClazz = Class.forType(tClazzType); + if (undefined === tClazz) { + continue; + } + + tClazz.getOwnMethods().forEach((value: Method, key: PropertyKeyType): void => { + methods.set(key, value); + }); + } + + return methods; + } + + public getAnnotation(annotationClass: Type): AnnotationType | undefined { + const annotations = this.getAnnotations(); + + return annotations.get(annotationClass); + } + + public getAnnotations(): Map, Annotation> { + const annotations: Map, Annotation> = new Map(); + + const types = TypeUtil.ancestorsOf(this._type); + if (null === types || 0 === types.length) { + return annotations; + } + for (let i = 0; i < types.length; i++) { + const tClazzType = types[i]; + const tClazz = Class.forType(tClazzType); + if (undefined === tClazz) { + continue; + } + + tClazz.getOwnAnnotations().forEach((value: Annotation, key: Type): void => { + annotations.set(key, value); + }); + } + + return annotations; + } + + public getAnnotationsByType(annotationClass: Type) + : AnnotationType[] | undefined { + const annotations = this.getAnnotations(); + if (0 === annotations.size) { + return undefined; + } + const results: AnnotationType[] = []; + for (const classType of Array.from(annotations.keys())) { + if (classType === annotationClass) { + results.push(annotations.get(classType)); + } + } + if (0 === results.length) { + return undefined; + } + return results; + } + + public getName(): string { + return this._type.name; + } +} diff --git a/src/reflect/ClassRegistry.ts b/src/reflect/ClassRegistry.ts new file mode 100644 index 0000000..b559da1 --- /dev/null +++ b/src/reflect/ClassRegistry.ts @@ -0,0 +1,12 @@ +import { Type } from '../type'; +import { Registry } from '../util/Registry'; + +import { Class } from './Class'; + +export class ClassRegistry extends Registry, Class> { + public constructor(parent?: ClassRegistry) { + super(parent); + } +} + +export const SystemClassRegistry = new ClassRegistry(); diff --git a/src/reflect/Constructor.ts b/src/reflect/Constructor.ts new file mode 100644 index 0000000..1ae6bfe --- /dev/null +++ b/src/reflect/Constructor.ts @@ -0,0 +1,22 @@ +import { + TypeUtil, +} from '../util/TypeUtil'; + +import { Class } from './Class'; +import { Executable } from './Executable'; + +export class Constructor extends Executable { + private _rawConstructor: Function; + + public constructor(declaringClazz: Class, parameterTypes?: any[]) { + super(declaringClazz, CONSTRUCTOR_NAME, parameterTypes); + this._rawConstructor = TypeUtil.getPrototype(declaringClazz.getType())[CONSTRUCTOR_NAME]; + } + + public newInstance(...args: any[]): any { + const ctor = this.getDeclaringClass().getType(); + return new (ctor.bind.apply(ctor, [null].concat(args)))(); + } +} + +const CONSTRUCTOR_NAME = 'constructor'; diff --git a/src/reflect/Executable.ts b/src/reflect/Executable.ts new file mode 100644 index 0000000..8f4cc01 --- /dev/null +++ b/src/reflect/Executable.ts @@ -0,0 +1,75 @@ +import { + PropertyKeyType, +} from '../type'; + +import { + TypeUtil, +} from '../util/TypeUtil'; + +import { AccessibleObject } from './AccessibleObject'; +import { Class } from './Class'; +import { Member } from './Member'; +import { Parameter } from './Parameter'; + +export abstract class Executable extends AccessibleObject implements Member { + private _clazz: Class; + private _name: PropertyKeyType; + private _parameters: Parameter[]; + + protected constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes?: any[]) { + super(); + + this._clazz = declaringClazz; + this._name = name; + + if (undefined === parameterTypes) { + return; + } + + const parameterNames = TypeUtil.getParameterNames(declaringClazz.getType(), name); + this._parameters = []; + + for (let i = 0; i < parameterTypes.length; i++) { + const parameterType = parameterTypes[i]; + const parameterName = parameterNames[i]; + const parameter: Parameter = new Parameter(this, parameterType, parameterName, i); + this._parameters.push(parameter); + } + } + + public getDeclaringClass(): Class { + return this._clazz; + } + + public getName(): PropertyKeyType { + return this._name; + } + + /** + * getParameterCount + */ + public getParameterCount(): number { + if (null === this._parameters) { + return 0; + } + return this._parameters.length; + } + /** + * getParameters + */ + public getParameters(): Parameter[] | undefined { + return this._parameters; + } + /** + * getParameter + */ + public getParameter(index: number): Parameter | undefined { + if (null === this._parameters) { + return undefined; + } + if (0 > index || this._parameters.length <= index) { + return undefined; + } + return this._parameters[index]; + } +} diff --git a/src/reflect/Field.ts b/src/reflect/Field.ts new file mode 100644 index 0000000..9e0cbbe --- /dev/null +++ b/src/reflect/Field.ts @@ -0,0 +1,33 @@ +import { + PropertyKeyType, +} from '../type'; + +import { AccessibleObject } from './AccessibleObject'; +import { Class } from './Class'; +import { Member } from './Member'; + +export class Field extends AccessibleObject implements Member { + private _clazz: Class; + private _name: PropertyKeyType; + private _type: any; + + public constructor(declaringClazz: Class, name: PropertyKeyType, fieldType: any) { + super(); + this._clazz = declaringClazz; + this._name = name; + this._type = fieldType; + } + + public getDeclaringClass(): Class { + return this._clazz; + } + + public getName(): PropertyKeyType { + return this._name; + } + + public getType(): any { + return this._type; + } + +} diff --git a/src/reflect/Member.ts b/src/reflect/Member.ts new file mode 100644 index 0000000..f3b045f --- /dev/null +++ b/src/reflect/Member.ts @@ -0,0 +1,10 @@ +import { + PropertyKeyType, +} from '../type'; + +import { Class } from './Class'; + +export interface Member { + getDeclaringClass(): Class; + getName(): PropertyKeyType; +} diff --git a/src/reflect/Metadata.ts b/src/reflect/Metadata.ts new file mode 100644 index 0000000..caab825 --- /dev/null +++ b/src/reflect/Metadata.ts @@ -0,0 +1,521 @@ +import { + MetadataKeyType, + PropertyKeyType, +} from '../type'; + +import { TypeUtil } from '../util/TypeUtil'; + + +export class Metadata { + /** + * Gets the metadata value for the provided metadata key on the target object or its prototype chain. + * @param key A key used to store and retrieve metadata. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns The metadata value for the metadata key if found; otherwise, `undefined`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // constructor + * result = Metadata.get("custom:annotation", Example); + * + * // property (on constructor) + * result = Metadata.get("custom:annotation", Example, "staticProperty"); + * + * // property (on prototype) + * result = Metadata.get("custom:annotation", Example.prototype, "property"); + * + * // method (on constructor) + * result = Metadata.get("custom:annotation", Example, "staticMethod"); + * + * // method (on prototype) + * result = Metadata.get("custom:annotation", Example.prototype, "method"); + * ``` + * + */ + public static get(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): any { + return Reflect.getMetadata(key, TypeUtil.getType(target), propertyKey); + } + + /** + * Gets the metadata value for the provided metadata key on the target object or its prototype chain. + * @param key A key used to store and retrieve metadata. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns The metadata value for the metadata key if found; otherwise, `undefined`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // constructor + * result = Metadata.getOwn("custom:annotation", Example); + * + * // property (on constructor) + * result = Metadata.getOwn("custom:annotation", Example, "staticProperty"); + * + * // property (on prototype) + * result = Metadata.getOwn("custom:annotation", Example.prototype, "property"); + * + * // method (on constructor) + * result = Metadata.getOwn("custom:annotation", Example, "staticMethod"); + * + * // method (on prototype) + * result = Metadata.getOwn("custom:annotation", Example.prototype, "method"); + * ``` + * + */ + public static getOwn(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): any { + return Reflect.getOwnMetadata(key, TypeUtil.getType(target), propertyKey); + } + + /** + * Gets the metadata value for the provided metadata DESIGN_TYPE on the target object or its prototype chain. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns The metadata value for the metadata key if found; otherwise, `undefined`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // on contructor + * result = Metadata.getType(Example); + * + * // property (on constructor) + * result = Metadata.getType(Example, "staticProperty"); + * + * // method (on constructor) + * result = Metadata.getType(Example, "staticMethod"); + * ``` + * + */ + public static getType(target: any, propertyKey?: PropertyKeyType): any { + return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey); + } + + /** + * Gets the metadata value for the provided metadata DESIGN_TYPE on the target object or its prototype chain. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns The metadata value for the metadata key if found; otherwise, `undefined`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // on contructor + * result = Metadata.getOwnType(Example); + * + * // property (on constructor) + * result = Metadata.getOwnType(Example, "staticProperty"); + * + * // method (on constructor) + * result = Metadata.getOwnType(Example, "staticMethod"); + * ``` + * + */ + public static getOwnType(target: any, propertyKey?: PropertyKeyType): any { + return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey); + } + + /** + * Gets the metadata value for the provided metadata DESIGN_RETURN_TYPE on the target object or its prototype chain. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns The metadata value for the metadata key if found; otherwise, `undefined`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // on contructor + * result = Metadata.getReturnType(Example); + * + * // property (on constructor) + * result = Metadata.getReturnType(Example, "staticProperty"); + * + * // method (on constructor) + * result = Metadata.getReturnType(Example, "staticMethod"); + * ``` + * + */ + public static getReturnType(target: any, propertyKey?: PropertyKeyType): any { + return Reflect.getMetadata(DESIGN_RETURN_TYPE, target, propertyKey); + } + + /** + * Gets the metadata value for the provided metadata DESIGN_RETURN_TYPE on the target object or its prototype chain. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns The metadata value for the metadata key if found; otherwise, `undefined`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // on contructor + * result = Metadata.getOwnReturnType(Example); + * + * // property (on constructor) + * result = Metadata.getOwnReturnType(Example, "staticProperty"); + * + * // method (on constructor) + * result = Metadata.getOwnReturnType(Example, "staticMethod"); + * ``` + * + */ + public static getOwnReturnType(target: any, propertyKey?: PropertyKeyType): any { + return Reflect.getOwnMetadata(DESIGN_RETURN_TYPE, target, propertyKey); + } + + /** + * Gets a value indicating whether the target object or its prototype chain has the provided metadata key defined. + * @param key A key used to store and retrieve metadata. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns `true` if the metadata key was defined on the target object or its prototype chain; otherwise, `false`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // constructor + * result = Metadata.has("custom:annotation", Example); + * + * // property (on constructor) + * result = Metadata.has("custom:annotation", Example, "staticProperty"); + * + * // property (on prototype) + * result = Metadata.has("custom:annotation", Example.prototype, "property"); + * + * // method (on constructor) + * result = Metadata.has("custom:annotation", Example, "staticMethod"); + * + * // method (on prototype) + * result = Metadata.has("custom:annotation", Example.prototype, "method"); + * ``` + * + */ + public static has(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean { + return Reflect.hasMetadata(key, TypeUtil.getType(target), propertyKey); + } + + /** + * Gets a value indicating whether the target object or its prototype chain has the provided metadata key defined. + * @param key A key used to store and retrieve metadata. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns `true` if the metadata key was defined on the target object or its prototype chain; otherwise, `false`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // constructor + * result = Metadata.has("custom:annotation", Example); + * + * // property (on constructor) + * result = Metadata.hasOwn("custom:annotation", Example, "staticProperty"); + * + * // property (on prototype) + * result = Metadata.hasOwn("custom:annotation", Example.prototype, "property"); + * + * // method (on constructor) + * result = Metadata.hasOwn("custom:annotation", Example, "staticMethod"); + * + * // method (on prototype) + * result = Metadata.hasOwn("custom:annotation", Example.prototype, "method"); + * ``` + * + */ + public static hasOwn(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean { + return Reflect.hasOwnMetadata(key, TypeUtil.getType(target), propertyKey); + } + + /** + * Deletes the metadata entry from the target object with the provided key. + * @param key A key used to store and retrieve metadata. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns `true` if the metadata entry was found and deleted; otherwise, false. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // constructor + * result = Metadata.delete("custom:annotation", Example); + * + * // property (on constructor) + * result = Metadata.delete("custom:annotation", Example, "staticProperty"); + * + * // property (on prototype) + * result = Metadata.delete("custom:annotation", Example.prototype, "property"); + * + * // method (on constructor) + * result = Metadata.delete("custom:annotation", Example, "staticMethod"); + * + * // method (on prototype) + * result = Metadata.delete("custom:annotation", Example.prototype, "method"); + * ``` + * + */ + public static delete(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean { + return Reflect.deleteMetadata(key, TypeUtil.getType(target), propertyKey); + } + + /** + * Set the metadata value for the provided metadata DESIGN_PARAM_TYPES on the target object or its prototype chain. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @param value A value that contains attached metadata. + * @returns The metadata value for the metadata key if found; otherwise, `undefined`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // on contructor + * result = Metadata.setParamTypes(Example, undefined, [Object]); + * + * // property (on constructor) + * result = Metadata.setParamTypes(Example, "staticProperty", [Object]); + * + * // property (on prototype) + * result = Metadata.setParamTypes(Example.prototype, "property", [Object]); + * + * // method (on constructor) + * result = Metadata.setParamTypes(Example, "staticMethod", [Object]); + * + * // method (on prototype) + * result = Metadata.setParamTypes(Example.prototype, "method", [Object]); + * ``` + * + */ + public static setParamTypes(target: any, propertyKey: PropertyKeyType, value: any): void { + return this.set(DESIGN_PARAM_TYPES, value, target.prototype, propertyKey); + } + + /** + * Get all metadata for a metadataKey. + * @param metadataKey + */ + public static getTargetsFromPropertyKey = (metadataKey: MetadataKeyType): any[] => + PROPERTIES.has(metadataKey) ? PROPERTIES.get(metadataKey) || [] : [] + + /** + * Define a unique metadata entry on the target. + * @param key A key used to store and retrieve metadata. + * @param value A value that contains attached metadata. + * @param target The target object on which to define metadata. + * @param propertyKey The property key for the target. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // constructor + * Reflect.defineMetadata("custom:annotation", options, Example); + * + * // property (on constructor) + * Reflect.defineMetadata("custom:annotation", Number, Example, "staticProperty"); + * + * // property (on prototype) + * Reflect.defineMetadata("custom:annotation", Number, Example.prototype, "property"); + * + * // method (on constructor) + * Reflect.defineMetadata("custom:annotation", Number, Example, "staticMethod"); + * + * // method (on prototype) + * Reflect.defineMetadata("custom:annotation", Number, Example.prototype, "method"); + * + * // decorator factory as metadata-producing annotation. + * function MyAnnotation(options): PropertyDecorator { + * return (target, key) => Reflect.defineMetadata("custom:annotation", options, target, key); + * } + * ``` + * + */ + public static set(key: MetadataKeyType, value: any, target: any, propertyKey?: PropertyKeyType): void { + + const targets: any[] = PROPERTIES.has(key) ? PROPERTIES.get(key) || [] : []; + const classConstructor = TypeUtil.getType(target); + + if (targets.indexOf(classConstructor) === -1) { + targets.push(classConstructor); + PROPERTIES.set(key, targets); + } + + Reflect.defineMetadata(key, value, TypeUtil.getType(target), propertyKey); + } + + /** + * Gets the metadata value for the provided metadata DESIGN_PARAM_TYPES on the target object or its prototype chain. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns The metadata value for the metadata key if found; otherwise, `undefined`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // on contructor + * result = Metadata.getParamTypes(Example); + * + * // property (on constructor) + * result = Metadata.getParamTypes(Example, "staticProperty"); + * + * // method (on constructor) + * result = Metadata.getParamTypes(Example, "staticMethod"); + * ``` + * + */ + public static getParamTypes(target: any, propertyKey?: PropertyKeyType): any[] { + return Reflect.getMetadata(DESIGN_PARAM_TYPES, target, propertyKey); + } + + /** + * Gets the metadata value for the provided metadata DESIGN_PARAM_TYPES on the target object or its prototype chain. + * @param target The target object on which the metadata is defined. + * @param propertyKey The property key for the target. + * @returns The metadata value for the metadata key if found; otherwise, `undefined`. + * @example + * + * ```typescript + * class Example { + * // property declarations are not part of ES6, though they are valid in TypeScript: + * // static staticProperty; + * // property; + * + * static staticMethod(p) { } + * method(p) { } + * } + * + * // on contructor + * result = Metadata.getParamTypes(Example); + * + * // property (on constructor) + * result = Metadata.getParamTypes(Example, "staticProperty"); + * + * // method (on constructor) + * result = Metadata.getParamTypes(Example, "staticMethod"); + * ``` + * + */ + public static getOwnParamTypes(target: any, propertyKey?: PropertyKeyType): any[] { + return Reflect.getOwnMetadata(DESIGN_PARAM_TYPES, target, propertyKey); + } +} + + +/** + * Metadata key + * @private + * @type {string} + */ +const DESIGN_PARAM_TYPES = 'design:paramtypes'; +/** + * Metadata key + * @private + * @type {string} + */ +const DESIGN_TYPE = 'design:type'; +/** + * Metadata key + * @private + * @type {string} + */ +const DESIGN_RETURN_TYPE = 'design:returntype'; +/** + * Properties collections + * @private + * @type {string} + */ +const PROPERTIES: Map = new Map(); diff --git a/src/reflect/Method.ts b/src/reflect/Method.ts new file mode 100644 index 0000000..82997c6 --- /dev/null +++ b/src/reflect/Method.ts @@ -0,0 +1,29 @@ +import { + PropertyKeyType, +} from '../type'; + +import { + TypeUtil, +} from '../util/TypeUtil'; + +import { Class } from './Class'; +import { Executable } from './Executable'; + +export class Method extends Executable { + private _returnType: any; + private _rawMethod: Function; + + public constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes: any[], returnType: any) { + super(declaringClazz, name, parameterTypes); + this._returnType = returnType; + this._rawMethod = TypeUtil.getPrototype(declaringClazz.getType())[name]; + } + + public getReturnType(): any { + return this._returnType; + } + + public invoke(instance: Object, ...args: any[]): any { + return this._rawMethod.apply(instance, args); + } +} diff --git a/src/reflect/Parameter.ts b/src/reflect/Parameter.ts new file mode 100644 index 0000000..19d515a --- /dev/null +++ b/src/reflect/Parameter.ts @@ -0,0 +1,33 @@ +import { AccessibleObject } from './AccessibleObject'; +import { Executable } from './Executable'; + +export class Parameter extends AccessibleObject { + private _executable: Executable; + private _type: any; + private _index: number; + private _name: string; + + public constructor(executable: Executable, parameterType: any, name: string, index: number) { + super(); + this._executable = executable; + this._type = parameterType; + this._name = name; + this._index = index; + } + + public getDeclaringExecutable(): Executable { + return this._executable; + } + + public getType(): any { + return this._type; + } + + public getName(): string { + return this._name; + } + + public getIndex(): number { + return this._index; + } +} diff --git a/src/reflect/index.ts b/src/reflect/index.ts new file mode 100644 index 0000000..0dbbe0f --- /dev/null +++ b/src/reflect/index.ts @@ -0,0 +1,12 @@ +export * from './AccessibleObject'; +export * from './AnnotatedElement'; +export * from './Annotation'; +export * from './Class'; +export * from './Constructor'; + +export * from './Executable'; +export * from './Field'; +export * from './Member'; +export * from './Metadata'; +export * from './Method'; +export * from './Parameter'; diff --git a/src/type.ts b/src/type.ts new file mode 100644 index 0000000..e1683d4 --- /dev/null +++ b/src/type.ts @@ -0,0 +1,16 @@ +export declare const Type: FunctionConstructor; +export declare function isType(v: any): v is Type; +export interface Type extends Function { + new (...args: any[]): T; +} + +export declare type IdentityType = T | symbol; +export declare type PropertyKeyType = IdentityType; +export declare type MetadataKeyType = IdentityType; + +export enum PrimitiveType { + ANY = 'any', + STRING = 'string', + NUMBER = 'number', + BOOLEAN = 'boolean', +} diff --git a/src/util/AnnotationUtil.ts b/src/util/AnnotationUtil.ts new file mode 100644 index 0000000..c070cb3 --- /dev/null +++ b/src/util/AnnotationUtil.ts @@ -0,0 +1,39 @@ +import { Class, Annotation } from '../reflect'; +import { Type } from '../type'; + +export abstract class AnnotationUtils { + public static hasAnnotation(type: Type, annotationClass: Type): boolean { + const annotation = AnnotationUtils.getAnnotation(type, annotationClass); + if (undefined !== annotation) { + return true; + } + return false; + } + + public static getAnnotation(type: Type, annotationClass: Type): T | undefined { + const clazz = Class.forType(type); + if (undefined === clazz) { + return undefined; + } + + const annotations = clazz.getAnnotations(); + if (0 === annotations.size) { + return undefined; + } + + for (const annonClassType of Array.from(annotations.keys())) { + if (annonClassType === annotationClass) { + return annotations.get(annonClassType); + } + const annotation = AnnotationUtils.getAnnotation(annonClassType, annotationClass); + if (undefined !== annotation) { + return annotation; + } + } + + return undefined; + } + + + +} diff --git a/src/util/Registry.ts b/src/util/Registry.ts new file mode 100644 index 0000000..1e0428d --- /dev/null +++ b/src/util/Registry.ts @@ -0,0 +1,66 @@ +export abstract class Registry { + private _parent: Registry; + private _map: Map; + + protected constructor(parent?: Registry) { + this._parent = parent; + this._map = new Map(); + } + + public get parent(): Registry | undefined { + return this._parent; + } + + public get size(): number { + return this._map.size; + } + + public get(key: K): V | undefined { + let v = this._map.get(key); + if (undefined === v && undefined !== this._parent) { + v = this._parent.get(key); + } + + return v; + } + + public has(key: K): boolean { + let exist = this._map.has(key); + if (!exist && undefined !== this._parent) { + exist = this._parent.has(key); + } + return exist; + } + + public set(key: K, value: V): void { + this._map.set(key, value); + } + + public entries(): IterableIterator<[K, V]> { + return this._map.entries(); + } + + public keys(): IterableIterator { + return this._map.keys(); + } + + public values(): IterableIterator { + return this._map.values(); + } + + public clear(): void { + this._map.clear(); + } + + public delete(key: K): boolean { + let result = this._map.delete(key); + if (!result && undefined !== this._parent) { + result = this._parent.delete(key); + } + return result; + } + + public forEach(callback: (vlaue: V, key: K, map: Map) => void, thisArg?: any): void { + this._map.forEach(callback, thisArg); + } +} diff --git a/src/util/TypeUtil.ts b/src/util/TypeUtil.ts new file mode 100644 index 0000000..2161fd4 --- /dev/null +++ b/src/util/TypeUtil.ts @@ -0,0 +1,407 @@ +import { + Type, + PrimitiveType, + PropertyKeyType, +} from '../type'; + + +export class TypeUtil { + /** + * Get the provide constructor. + * @param target + */ + public static getContructor(target: any): Type { + return typeof target === 'function' ? target : target.constructor; + } + + /** + * Get the provide constructor if target is an instance. + * @param target + * @returns {*} + */ + public static getType(target: any): Type { + return target.prototype ? target : target.constructor; + } + + /** + * Get the provide prototype if target is an instance. + * @param target + * @returns {*} + */ + public static getPrototype(target: any): Object { + return typeof target === 'function' ? target.prototype : target; + } + + /** + * + * @param target + * @returns {symbol} + */ + public static getTypeOrSymbol(target: any): any { + return typeof target === 'symbol' ? target : TypeUtil.getType(target); + } + + /** + * Return true if the given obj is a primitive. + * @param target + * @returns {boolean} + */ + public static isPrimitiveOrPrimitiveType(target: any): boolean { + return TypeUtil.isString(target) + || TypeUtil.isNumber(target) + || TypeUtil.isBoolean(target); + } + + /** + * + * @param target + * @returns {PrimitiveType} + */ + public static primitiveOf(target: any): PrimitiveType { + if (TypeUtil.isString(target)) { + return PrimitiveType.STRING; + } + if (TypeUtil.isNumber(target)) { + return PrimitiveType.NUMBER; + } + if (TypeUtil.isBoolean(target)) { + return PrimitiveType.BOOLEAN; + } + return PrimitiveType.ANY; + } + + /** + * + * @param target + * @returns {boolean} + */ + public static isString(target: any): boolean { + return typeof target === 'string' || target instanceof String || target === String; + } + + /** + * + * @param target + * @returns {boolean} + */ + public static isNumber(target: any): boolean { + return typeof target === 'number' || target instanceof Number || target === Number; + } + + /** + * + * @param target + * @returns {boolean} + */ + public static isBoolean(target: any): boolean { + return typeof target === 'boolean' || target instanceof Boolean || target === Boolean; + } + + /** + * + * @param target + * @returns {Boolean} + */ + public static isArray(target: any): boolean { + return Array.isArray(target); + } + + /** + * Return true if the clazz is an array. + * @param target + * @returns {boolean} + */ + public static isArrayOrArrayType(target: any): boolean { + if (target === Array) { + return true; + } + return TypeUtil.isArray(target); + } + + /** + * Return true if the target. + * @param target + * @returns {boolean} + */ + public static isCollection(target: any): boolean { + return TypeUtil.isArrayOrArrayType(target) + || target === Map + || target instanceof Map + || target === Set + || target instanceof Set + || target === WeakMap + || target instanceof WeakMap + || target === WeakSet + || target instanceof WeakSet; + } + + /** + * + * @param target + * @returns {boolean} + */ + public static isDate(target: any): boolean { + return target === Date || target instanceof Date; + } + + /** + * + * @param target + * @returns {boolean} + */ + public static isMethod(target: any, propertyKey: PropertyKeyType): boolean { + if (typeof(target[propertyKey]) === undefined) { + return false; + } + return typeof target[propertyKey] === 'function'; + } + + /** + * + * @param target + * @returns {boolean} + */ + public static isObject(target: any): boolean { + return target === Object; + } + + /** + * + * @param target + * @returns {boolean} + */ + public static isType(target: any): boolean { + return !TypeUtil.isPrimitiveOrPrimitiveType(target) + && !TypeUtil.isObject(target) + && !TypeUtil.isDate(target) + && target !== undefined + && !TypeUtil.isPromise(target); + } + + /** + * Return true if the value is an empty string, null or undefined. + * @param value + * @returns {boolean} + */ + public static isEmpty(value: any): boolean { + return value === '' || value === null || value === undefined; + } + + /** + * Get object name + */ + public static nameOf(obj: any): string { + switch (typeof obj) { + default: + return '' + obj; + case 'symbol': + return TypeUtil.nameOfSymbol(obj); + case 'function': + return TypeUtil.nameOfType(obj); + } + } + + /** + * Get the provide name. + * @param target + */ + public static nameOfType(target: any): string { + return typeof target === 'function' + ? target.name + : target.constructor.name; + } + /** + * Get symbol name. + * @param sym + */ + public static nameOfSymbol(sym: symbol): string { + return sym.toString().replace('Symbol(', '').replace(')', ''); + } + /** + * + * @param out + * @param obj + * @param {{[p: string]: (collection: any[], value: any) => any}} reducers + * @returns {any} + */ + public static deepExtends(out: any, obj: any, reducers: { [key: string]: (collection: any[], value: any) => any } = {}): any { + + if (obj === undefined || obj === null) { + return obj; + } + + if (TypeUtil.isPrimitiveOrPrimitiveType(obj) || typeof obj === 'symbol' || typeof obj === 'function') { + return obj; + } + + if (TypeUtil.isArrayOrArrayType(obj)) { + out = out || []; + } else { + out = out || {}; + } + + const defaultReducer = reducers.default ? reducers.default : (collection: any[], value: any) => { + collection.push(value); + return collection; + }; + const set = (key: string | number, value: any) => { + if (TypeUtil.isArrayOrArrayType(obj)) { + out.push(value); + } else { + out[key] = value; + } + }; + + Object.keys(obj).forEach(key => { + let value = obj[key]; + + if (value === undefined || value === null) { + return; + } + + if (value === '' && out[key] !== '') { + return; + } + + if (TypeUtil.isPrimitiveOrPrimitiveType(value) || typeof value === 'function') { + set(key, value); + return; + } + + if (TypeUtil.isArrayOrArrayType(value)) { + + value = value.map((v: any) => TypeUtil.deepExtends(undefined, v)); + + set(key, [] + .concat(out[key] || [], value) + .reduce((collection: any[], v: any) => + reducers[key] ? reducers[key](collection, v) : defaultReducer(collection, v), + [])); + return; + } + + // Object + if (TypeUtil.isArrayOrArrayType(obj)) { + set(key, TypeUtil.deepExtends(undefined, value, reducers)); + } else { + set(key, TypeUtil.deepExtends(out[key], value, reducers)); + } + }); + + if (TypeUtil.isArrayOrArrayType(out)) { + out.reduce((collection: any[], value: any) => defaultReducer(collection, value), []); + } + + return out; + } + + /** + * + * @param target + * @returns {boolean} + */ + public static isPromise(target: any): boolean { + return target === Promise || target instanceof Promise; + } + + /** + * + * @param target + * @returns {any} + */ + public static getInheritedType(target: Type): Type { + return Object.getPrototypeOf(target); + } + + /** + * + * @param target + * @param {PropertyKeyType} propertyKey + * @returns {PropertyDescriptor} + */ + public static descriptorOf(target: any, propertyKey: PropertyKeyType): PropertyDescriptor { + return Object.getOwnPropertyDescriptor(target && target.prototype || target, propertyKey); + } + + /** + * + * @param target + * @param {PropertyKeyType} propertyKey + * @returns {string[]} + */ + public static getParameterNames(target: any, propertyKey: PropertyKeyType): string[] { + const rawType = TypeUtil.getPrototype(target); + const fn: Function = rawType[propertyKey]; + + const code = fn.toString() + .replace(COMMENTS, '') + .replace(FAT_ARROWS, '') + .replace(DEFAULT_PARAMS, ''); + + const result = code.slice(code.indexOf('(') + 1, code.indexOf(')')).match(/([^\s,]+)/g); + + return result === null + ? [] + : result; + } + + /** + * + * @param target + * @returns {Array} + */ + public static ancestorsOf(target: Type): Type[] { + const classes: Type[] = []; + + let currentTarget = TypeUtil.getType(target); + + while (TypeUtil.nameOf(currentTarget) !== '') { + classes.unshift(currentTarget); + currentTarget = TypeUtil.getInheritedType(currentTarget); + } + + return classes; + } + + /** + * + * @param target + * @param {string} name + * @param {Function} callback + */ + public static applyBefore(target: any, name: string, callback: Function): void { + const original = target[name]; + target[name] = function (...args: any[]): any { + callback(...args); + return original.apply(this, args); + }; + } + + /** + * + * @param {Promise} promise + * @param {number} time + * @returns {Promise} + */ + public static promiseTimeout(promise: Promise, time: number = 1000): Promise<{ ok: boolean, response: any }> { + const timeout = (p: Promise, t: number) => new Promise((resolve) => { + p.then((response) => { + resolve(); + return response; + }); + setTimeout(() => resolve({ok: false}), t); + }); + + promise = promise.then((response) => ({ok: true, response})); + + return Promise.race([ + promise, + timeout(promise, time), + ]); + } + +} + +const COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; +const DEFAULT_PARAMS = /=[^,]+/mg; +const FAT_ARROWS = /=>.*$/mg; diff --git a/src/util/index.ts b/src/util/index.ts new file mode 100644 index 0000000..d289752 --- /dev/null +++ b/src/util/index.ts @@ -0,0 +1,3 @@ +export * from './AnnotationUtil'; +export * from './Registry'; +export * from './TypeUtil'; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..750d32e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,46 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./src", + "outDir": "./dist", + "sourceMap": true, + "declaration": true, + "newLine": "LF", + "moduleResolution": "node", + + /* Strict Type-Checking Options */ + // "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, + // "strictNullChecks": true /* Enable strict null checks. */, + // "strictFunctionTypes": true /* Enable strict checking of function types. */, + // "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */, + // "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */, + // "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */, + + /* Additional Checks */ + "noUnusedLocals": true /* Report errors on unused locals. */, + "noUnusedParameters": true /* Report errors on unused parameters. */, + "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, + "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, + + /* Debugging Options */ + "traceResolution": false /* Report module resolution log messages. */, + "listEmittedFiles": false /* Print names of generated files part of the compilation. */, + "listFiles": false /* Print names of files part of the compilation. */, + "pretty": true /* Stylize errors and messages using color and context. */, + + /* Experimental Options */ + "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, + "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, + + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "types": [ + "reflect-metadata", + ], + "lib": [ + "es2015", "es2016", "es2017", "dom" + ] + } +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..b954a5d --- /dev/null +++ b/tslint.json @@ -0,0 +1,34 @@ +{ + "extends": ["tslint:latest", "tslint-config-prettier", "tslint-immutable"], + "rules": { + "interface-name": [true, "never-prefix"], + // TODO: allow devDependencies only in **/*.spec.ts files: + // waiting on https://github.com/palantir/tslint/pull/3708 + "no-implicit-dependencies": [true, "dev"], + + /* tslint-immutable rules */ + // Recommended built-in rules + "no-var-keyword": true, + "no-parameter-reassignment": true, + "typedef": [true, "call-signature"], + + // Immutability rules + "readonly-keyword": true, + "readonly-array": true, + "no-let": true, + "no-object-mutation": true, + "no-delete": true, + "no-method-signature": true, + + // Functional style rules + "no-this": true, + "no-class": true, + "no-mixed-interface": true, + "no-expression-statement": [ + true, + { "ignore-prefix": ["console.", "process.exit"] } + ], + "no-if-statement": true + /* end tslint-immutable rules */ + } +}