diff --git a/.gitignore b/.gitignore index 14ed705..c828dc9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules mochawesome-report +snapshots.d.ts +lib \ No newline at end of file diff --git a/.mocharc.json b/.mocharc.json index e71ef8f..fbe225a 100644 --- a/.mocharc.json +++ b/.mocharc.json @@ -2,6 +2,6 @@ "$schema": "https://json.schemastore.org/mocharc", "reporter": "mochawesome", "extension": [".ts"], - "require": ["ts-node/register"], + "require": ["./scripts/babel-register.js"], "timeout": 10000 } diff --git a/README.md b/README.md new file mode 100644 index 0000000..e893e87 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# babel-decorators + +Emit beautiful looking transpiled code for decorators like `tsc`. diff --git a/package.json b/package.json index c20b36c..4d81235 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,17 @@ { "name": "babel-decorators", - "version": "1.0.0", + "version": "0.1.0", "main": "index.js", "license": "MIT", "scripts": { - "test": "mocha test/**/*.ts" + "test": "mocha test/**/*.ts", + "postinstall": "mkdir -p lib; cd test/snapshots && ls | sed \"s/.*/'&'/\" | paste -sd '|' | sed -e \"s/^/export type Snapshot = /\" - > ../snapshots.d.ts" }, "devDependencies": { "@babel/core": "^7.14.8", + "@babel/plugin-transform-modules-commonjs": "^7.14.5", + "@babel/preset-typescript": "^7.14.5", + "@babel/register": "^7.14.5", "@babel/types": "^7.14.8", "@types/babel__core": "^7.1.15", "@types/chai": "^4.2.21", @@ -20,5 +24,13 @@ "prettier": "^2.3.2", "ts-node": "^10.1.0", "typescript": "^4.3.5" + }, + "prettier": { + "arrowParens": "avoid", + "tabWidth": 2, + "printWidth": 90, + "semi": false, + "singleQuote": false, + "trailingComma": "es5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ca8762..11a4ba9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2,6 +2,9 @@ lockfileVersion: 5.3 specifiers: '@babel/core': ^7.14.8 + '@babel/plugin-transform-modules-commonjs': ^7.14.5 + '@babel/preset-typescript': ^7.14.5 + '@babel/register': ^7.14.5 '@babel/types': ^7.14.8 '@types/babel__core': ^7.1.15 '@types/chai': ^4.2.21 @@ -17,6 +20,9 @@ specifiers: devDependencies: '@babel/core': 7.14.8 + '@babel/plugin-transform-modules-commonjs': 7.14.5_@babel+core@7.14.8 + '@babel/preset-typescript': 7.14.5_@babel+core@7.14.8 + '@babel/register': 7.14.5_@babel+core@7.14.8 '@babel/types': 7.14.8 '@types/babel__core': 7.1.15 '@types/chai': 4.2.21 @@ -76,6 +82,13 @@ packages: source-map: 0.5.7 dev: true + /@babel/helper-annotate-as-pure/7.14.5: + resolution: {integrity: sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.14.8 + dev: true + /@babel/helper-compilation-targets/7.14.5_@babel+core@7.14.8: resolution: {integrity: sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==} engines: {node: '>=6.9.0'} @@ -89,6 +102,23 @@ packages: semver: 6.3.0 dev: true + /@babel/helper-create-class-features-plugin/7.14.8_@babel+core@7.14.8: + resolution: {integrity: sha512-bpYvH8zJBWzeqi1o+co8qOrw+EXzQ/0c74gVmY205AWXy9nifHrOg77y+1zwxX5lXE7Icq4sPlSQ4O2kWBrteQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.14.8 + '@babel/helper-annotate-as-pure': 7.14.5 + '@babel/helper-function-name': 7.14.5 + '@babel/helper-member-expression-to-functions': 7.14.7 + '@babel/helper-optimise-call-expression': 7.14.5 + '@babel/helper-replace-supers': 7.14.5 + '@babel/helper-split-export-declaration': 7.14.5 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-function-name/7.14.5: resolution: {integrity: sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==} engines: {node: '>=6.9.0'} @@ -149,6 +179,11 @@ packages: '@babel/types': 7.14.8 dev: true + /@babel/helper-plugin-utils/7.14.5: + resolution: {integrity: sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-replace-supers/7.14.5: resolution: {integrity: sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==} engines: {node: '>=6.9.0'} @@ -211,6 +246,73 @@ packages: hasBin: true dev: true + /@babel/plugin-syntax-typescript/7.14.5_@babel+core@7.14.8: + resolution: {integrity: sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.14.8 + '@babel/helper-plugin-utils': 7.14.5 + dev: true + + /@babel/plugin-transform-modules-commonjs/7.14.5_@babel+core@7.14.8: + resolution: {integrity: sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.14.8 + '@babel/helper-module-transforms': 7.14.8 + '@babel/helper-plugin-utils': 7.14.5 + '@babel/helper-simple-access': 7.14.8 + babel-plugin-dynamic-import-node: 2.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-typescript/7.14.6_@babel+core@7.14.8: + resolution: {integrity: sha512-XlTdBq7Awr4FYIzqhmYY80WN0V0azF74DMPyFqVHBvf81ZUgc4X7ZOpx6O8eLDK6iM5cCQzeyJw0ynTaefixRA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.14.8 + '@babel/helper-create-class-features-plugin': 7.14.8_@babel+core@7.14.8 + '@babel/helper-plugin-utils': 7.14.5 + '@babel/plugin-syntax-typescript': 7.14.5_@babel+core@7.14.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/preset-typescript/7.14.5_@babel+core@7.14.8: + resolution: {integrity: sha512-u4zO6CdbRKbS9TypMqrlGH7sd2TAJppZwn3c/ZRLeO/wGsbddxgbPDUZVNrie3JWYLQ9vpineKlsrWFvO6Pwkw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.14.8 + '@babel/helper-plugin-utils': 7.14.5 + '@babel/helper-validator-option': 7.14.5 + '@babel/plugin-transform-typescript': 7.14.6_@babel+core@7.14.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/register/7.14.5_@babel+core@7.14.8: + resolution: {integrity: sha512-TjJpGz/aDjFGWsItRBQMOFTrmTI9tr79CHOK+KIvLeCkbxuOAk2M5QHjvruIMGoo9OuccMh5euplPzc5FjAKGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.14.8 + clone-deep: 4.0.1 + find-cache-dir: 2.1.0 + make-dir: 2.1.0 + pirates: 4.0.1 + source-map-support: 0.5.19 + dev: true + /@babel/template/7.14.5: resolution: {integrity: sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==} engines: {node: '>=6.9.0'} @@ -360,6 +462,12 @@ packages: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true + /babel-plugin-dynamic-import-node/2.3.3: + resolution: {integrity: sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==} + dependencies: + object.assign: 4.1.2 + dev: true + /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -403,6 +511,13 @@ packages: resolution: {integrity: sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==} dev: true + /call-bind/1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.1.1 + dev: true + /camelcase/5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -481,6 +596,15 @@ packages: wrap-ansi: 7.0.0 dev: true + /clone-deep/4.0.1: + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} + dependencies: + is-plain-object: 2.0.4 + kind-of: 6.0.3 + shallow-clone: 3.0.1 + dev: true + /color-convert/1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -506,6 +630,10 @@ packages: resolution: {integrity: sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==} dev: true + /commondir/1.0.1: + resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=} + dev: true + /concat-map/0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true @@ -566,6 +694,13 @@ packages: type-detect: 4.0.8 dev: true + /define-properties/1.1.3: + resolution: {integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==} + engines: {node: '>= 0.4'} + dependencies: + object-keys: 1.1.1 + dev: true + /diff/4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -614,6 +749,15 @@ packages: to-regex-range: 5.0.1 dev: true + /find-cache-dir/2.1.0: + resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} + engines: {node: '>=6'} + dependencies: + commondir: 1.0.1 + make-dir: 2.1.0 + pkg-dir: 3.0.0 + dev: true + /find-up/3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} @@ -658,6 +802,10 @@ packages: resolution: {integrity: sha512-xQVsnjJ/5pQtcKh+KjUoZGzVWn4uNkchxTF6Lwjr4Gf7nQr8fmUfhKJ62zE77+xQg9xnxi5KUps7XGs+VC986A==} dev: true + /function-bind/1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + /gensync/1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -672,6 +820,14 @@ packages: resolution: {integrity: sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=} dev: true + /get-intrinsic/1.1.1: + resolution: {integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.2 + dev: true + /glob-parent/5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -714,6 +870,18 @@ packages: engines: {node: '>=8'} dev: true + /has-symbols/1.0.2: + resolution: {integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==} + engines: {node: '>= 0.4'} + dev: true + + /has/1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: true + /he/1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -769,6 +937,13 @@ packages: engines: {node: '>=8'} dev: true + /is-plain-object/2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: true + /is-unicode-supported/0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -778,6 +953,11 @@ packages: resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} dev: true + /isobject/3.0.1: + resolution: {integrity: sha1-TkMekrEalzFjaqH5yNHMvP2reN8=} + engines: {node: '>=0.10.0'} + dev: true + /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true @@ -813,6 +993,11 @@ packages: graceful-fs: 4.2.6 dev: true + /kind-of/6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: true + /locate-path/3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} @@ -859,6 +1044,14 @@ packages: js-tokens: 4.0.0 dev: true + /make-dir/2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + dependencies: + pify: 4.0.1 + semver: 5.7.1 + dev: true + /make-error/1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} dev: true @@ -955,6 +1148,11 @@ packages: hasBin: true dev: true + /node-modules-regexp/1.0.0: + resolution: {integrity: sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=} + engines: {node: '>=0.10.0'} + dev: true + /node-releases/1.1.73: resolution: {integrity: sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==} dev: true @@ -969,6 +1167,21 @@ packages: engines: {node: '>=0.10.0'} dev: true + /object-keys/1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign/4.1.2: + resolution: {integrity: sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.3 + has-symbols: 1.0.2 + object-keys: 1.1.1 + dev: true + /once/1.4.0: resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} dependencies: @@ -1037,6 +1250,25 @@ packages: engines: {node: '>=8.6'} dev: true + /pify/4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + dev: true + + /pirates/4.0.1: + resolution: {integrity: sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==} + engines: {node: '>= 6'} + dependencies: + node-modules-regexp: 1.0.0 + dev: true + + /pkg-dir/3.0.0: + resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} + engines: {node: '>=6'} + dependencies: + find-up: 3.0.0 + dev: true + /prettier/2.3.2: resolution: {integrity: sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==} engines: {node: '>=10.13.0'} @@ -1081,6 +1313,11 @@ packages: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} dev: true + /semver/5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + dev: true + /semver/6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true @@ -1096,6 +1333,13 @@ packages: resolution: {integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=} dev: true + /shallow-clone/3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + dependencies: + kind-of: 6.0.3 + dev: true + /source-map-support/0.5.19: resolution: {integrity: sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==} dependencies: diff --git a/scripts/babel-register.js b/scripts/babel-register.js new file mode 100644 index 0000000..438dff8 --- /dev/null +++ b/scripts/babel-register.js @@ -0,0 +1,5 @@ +require("@babel/register")({ + extensions: [".js", ".jsx", ".ts", ".tsx"], + presets: ["@babel/preset-typescript"], + plugins: ["@babel/plugin-transform-modules-commonjs"], +}) diff --git a/scripts/build.js b/scripts/build.js new file mode 100755 index 0000000..59bc823 --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,18 @@ +#!/usr/bin/env node +const fs = require("fs") +const { format } = require("prettier") +const babel = require("@babel/core") + +// Main +const res = babel.transformFileSync("src/index.ts", { + presets: ["@babel/preset-typescript"], + plugins: ["@babel/plugin-transform-modules-commonjs"], +}) +fs.writeFileSync("lib/index.js", format(res.code, { parser: "babel" })) + +// package.json +const pkg = require("../package.json") +delete pkg.scripts +delete pkg.devDependencies +delete pkg.prettier +fs.writeFileSync("lib/package.json", JSON.stringify(pkg, null, 2)) diff --git a/src/index.ts b/src/index.ts index c09046c..ef62397 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,184 @@ -import type * as babel from "@babel/core"; +import type * as babel from "@babel/core" +import type * as t from "@babel/types" -export default ({ types: t }: typeof babel): babel.PluginObj => ({ - name: "tsc-dedent", - visitor: {}, -}); +interface State { + getTSLib(): t.ImportSpecifier[] + getParam(): t.Identifier + getDecorate(): t.Identifier +} + +export default ({ types: t }: typeof babel): babel.PluginObj => ({ + name: "tsc-decorators", + visitor: { + Program: { + enter(path, state) { + const getTSLib = once(() => { + const specifiers: t.ImportSpecifier[] = [] + const dec = t.importDeclaration(specifiers, t.stringLiteral("tslib")) + path.node.body.unshift(dec) + return specifiers + }) + + state.getTSLib = getTSLib + + const createGet = (name: string) => + once(() => { + const specifiers = getTSLib() + const localID = path.scope.hasBinding(name) + ? path.scope.generateUidIdentifier(name) + : t.identifier(name) + specifiers.push(t.importSpecifier(localID, t.identifier(name))) + return localID + }) + + const getParam = createGet("__param") + const getDecorate = createGet("__decorate") + + state.getParam = () => t.cloneNode(getParam()) + state.getDecorate = () => t.cloneNode(getDecorate()) + }, + }, + + ClassDeclaration(path, state) { + const modifiers: (t.Expression | t.Statement)[] = [] + const classDecorators: t.Expression[] = [] + const prefixes: t.Statement[] = [] + + const classID = path.node.id + + const isNamedExport = t.isExportNamedDeclaration(path.parent) + const isDefaultExport = t.isExportDefaultDeclaration(path.parent) + + if (path.node.decorators) { + classDecorators.push(...path.node.decorators.map(d => d.expression)) + path.node.decorators = [] + } + + for (const child of path.node.body.body) { + switch (child.type) { + case "ClassProperty": + if (!child.decorators) continue + modifiers.push( + t.callExpression(state.getDecorate(), [ + t.arrayExpression(child.decorators.map(d => d.expression)), + t.memberExpression(classID, t.identifier("prototype")), + t.isIdentifier(child.key) ? t.stringLiteral(child.key.name) : child.key, + t.unaryExpression("void", t.numericLiteral(0)), + ]) + ) + child.decorators = null + break + + case "ClassMethod": + { + const list: t.Expression[] = [] + if (child.decorators) { + list.push(...child.decorators.map(d => d.expression)) + child.decorators = null + } + + child.params.forEach((param, i) => { + pseudoAssert(!t.isTSParameterProperty(param)) + if (!param.decorators?.length) return + list.push( + ...param.decorators + .map(d => d.expression) + .map(e => + t.callExpression(state.getParam(), [t.numericLiteral(i), e]) + ) + ) + param.decorators = null + }) + + if (child.kind === "constructor") { + classDecorators.push(...list) + } else { + let key: t.Expression + if (child.computed) { + const newID = path.scope.generateUidIdentifier() + prefixes.push( + t.variableDeclaration("let", [t.variableDeclarator(newID)]) + ) + child.key = t.assignmentExpression("=", newID, child.key) + key = newID + } else if (t.isIdentifier(child.key)) { + key = t.stringLiteral(child.key.name) + } else { + key = child.key + } + + modifiers.push( + t.callExpression(state.getDecorate(), [ + t.arrayExpression(list), + t.memberExpression(classID, t.identifier("prototype")), + key, + t.nullLiteral(), + ]) + ) + } + } + break + } + } + + if (!classDecorators.length && !modifiers.length && !prefixes.length) return + + const replacees: t.Statement[] = prefixes.slice() + if (classDecorators.length) { + replacees.push( + t.variableDeclaration("let", [ + t.variableDeclarator(classID, { ...path.node, type: "ClassExpression" }), + ]) + ) + modifiers.push( + t.assignmentExpression( + "=", + classID, + t.callExpression(state.getDecorate(), [ + t.arrayExpression(classDecorators), + classID, + ]) + ) + ) + + if (isNamedExport) { + modifiers.push( + t.exportNamedDeclaration(undefined, [t.exportSpecifier(classID, classID)]) + ) + } else if (isDefaultExport) { + modifiers.push(t.exportDefaultDeclaration(classID)) + } + } else { + let node: t.Statement = path.node + if (isNamedExport) { + node = t.exportNamedDeclaration(node, [], null) + } else if (isDefaultExport) { + node = t.exportDefaultDeclaration(node) + } + replacees.push(node) + } + + replacees.push( + ...modifiers.map(e => (t.isStatement(e) ? e : t.expressionStatement(e))) + ) + const replacementTarget = isNamedExport || isDefaultExport ? path.parentPath : path + replacementTarget.replaceWithMultiple(replacees) + }, + }, +}) + +function pseudoAssert(condition: any): asserts condition {} + +const once = (fn: T): T => { + let called = false + let cache: any + return function (this: any) { + if (called) { + return cache + } else { + cache = fn.apply(this, arguments) + called = true + return cache + } + } as any +} diff --git a/test/index.ts b/test/index.ts index 9a10a2b..61abd7d 100644 --- a/test/index.ts +++ b/test/index.ts @@ -1,34 +1,53 @@ -import { describe, it } from "mocha"; -import { expect } from "chai"; -import { transform } from "@babel/core"; -import { format } from "prettier"; -import plugin from "../src/index"; +import { readFileSync } from "fs" +import { describe, it } from "mocha" +import { resolve } from "path" +import { expect } from "chai" +import { transform } from "@babel/core" +import { format } from "prettier" +import type { Snapshot } from "./snapshots" +import plugin from "../src/index" -const javascript = (code: TemplateStringsArray) => - transform(code[0], { +const canonize = (code: string) => + format(code, { parser: "babel" }).trim().split("\n").filter(Boolean).join("\n") + +const equal = (name: Snapshot) => { + const folder = resolve(__dirname, "snapshots", name) + const actual = readFileSync(resolve(folder, "input.txt"), "utf-8") + const expected = readFileSync(resolve(folder, "output.txt"), "utf-8") + const transformed = transform(actual, { parserOpts: { plugins: ["decorators-legacy", "typescript"], }, + babelrc: false, + configFile: false, plugins: [plugin], - })!.code!; + })!.code! + expect(canonize(transformed)).to.deep.equal(canonize(expected)) +} -const canonize = (code: string) => format(code, { parser: "babel" }).trim(); +describe("tsc-decorator", () => { + it("works with property decorators", () => { + equal("properties") + }) -const equal = (actual: string, expected: string) => { - actual = canonize(actual); - expected = canonize(expected); - expect(actual).to.deep.equal(expected); -}; + it("works with method decorators", () => { + equal("methods") + }) -describe("", () => { - it("should do nothing", () => { - equal( - javascript` - class A {} - `, - /* javascript */ ` - class A {} - ` - ); - }); -}); + it("works with parameter decorators", () => { + equal("params") + }) + + // https://github.com/babel/babel/issues/13591 + it.skip("works with computed property keys", () => { + equal("computedProperties") + }) + + it("works with class/consrtuctor decorators", () => { + equal("constructor") + }) + + it("does not interfere with export declarations", () => { + equal("exports") + }) +}) diff --git a/test/snapshots/.eslintignore b/test/snapshots/.eslintignore new file mode 100644 index 0000000..f59ec20 --- /dev/null +++ b/test/snapshots/.eslintignore @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/test/snapshots/computedProperties/input.txt b/test/snapshots/computedProperties/input.txt new file mode 100644 index 0000000..da9ef0c --- /dev/null +++ b/test/snapshots/computedProperties/input.txt @@ -0,0 +1,4 @@ +class A { + @decorator + [Symbol.iterator]() {} +} \ No newline at end of file diff --git a/test/snapshots/computedProperties/output.txt b/test/snapshots/computedProperties/output.txt new file mode 100644 index 0000000..cc4d032 --- /dev/null +++ b/test/snapshots/computedProperties/output.txt @@ -0,0 +1,5 @@ +let _a; +class A { + [_a = Symbol.iterator]() { } +} +__decorate([decorator], A.prototype, _a, null); \ No newline at end of file diff --git a/test/snapshots/constructor/input.txt b/test/snapshots/constructor/input.txt new file mode 100644 index 0000000..df344ed --- /dev/null +++ b/test/snapshots/constructor/input.txt @@ -0,0 +1,4 @@ +@classDecorator +class A { + @prop string: string; +} diff --git a/test/snapshots/constructor/output.txt b/test/snapshots/constructor/output.txt new file mode 100644 index 0000000..ea513bf --- /dev/null +++ b/test/snapshots/constructor/output.txt @@ -0,0 +1,8 @@ +import { __decorate } from "tslib"; + +let A = class A { + string: string; +} + +__decorate([prop], A.prototype, "string", void 0); +A = __decorate([classDecorator], A); diff --git a/test/snapshots/exports/input.txt b/test/snapshots/exports/input.txt new file mode 100644 index 0000000..7f4cebb --- /dev/null +++ b/test/snapshots/exports/input.txt @@ -0,0 +1,9 @@ +export class NormalDecorated { + @prop a: string +} + +@classDecorator +export class ClassDecorated {} + +@classDecorator +export default class DefaultExport {} \ No newline at end of file diff --git a/test/snapshots/exports/output.txt b/test/snapshots/exports/output.txt new file mode 100644 index 0000000..2ea7900 --- /dev/null +++ b/test/snapshots/exports/output.txt @@ -0,0 +1,15 @@ +import { __decorate } from "tslib"; + +export class NormalDecorated { + a: string; +} +__decorate([prop], NormalDecorated.prototype, "a", void 0); + +let ClassDecorated = class ClassDecorated {}; +ClassDecorated = __decorate([classDecorator], ClassDecorated); + +export { ClassDecorated }; + +let DefaultExport = class DefaultExport {}; +DefaultExport = __decorate([classDecorator], DefaultExport); +export default DefaultExport; diff --git a/test/snapshots/methods/input.txt b/test/snapshots/methods/input.txt new file mode 100644 index 0000000..3782156 --- /dev/null +++ b/test/snapshots/methods/input.txt @@ -0,0 +1,3 @@ +class A { + @dec method(): string {} +} diff --git a/test/snapshots/methods/output.txt b/test/snapshots/methods/output.txt new file mode 100644 index 0000000..3cfe9e5 --- /dev/null +++ b/test/snapshots/methods/output.txt @@ -0,0 +1,7 @@ +import { __decorate } from "tslib"; + +class A { + method(): string {} +} + +__decorate([dec], A.prototype, "method", null); \ No newline at end of file diff --git a/test/snapshots/params/input.txt b/test/snapshots/params/input.txt new file mode 100644 index 0000000..ebc4d42 --- /dev/null +++ b/test/snapshots/params/input.txt @@ -0,0 +1,6 @@ +import { __decorate } from "tslib" + +class A { + method1(skipped: string, @Arg() b: string) {} + method2(@Arg() a: string, @Arg() b: string) {} +} diff --git a/test/snapshots/params/output.txt b/test/snapshots/params/output.txt new file mode 100644 index 0000000..5b390a4 --- /dev/null +++ b/test/snapshots/params/output.txt @@ -0,0 +1,10 @@ +import { __param, __decorate as _decorate } from "tslib"; +import { __decorate } from "tslib"; + +class A { + method1(skipped: string, b: string) {} + method2(a: string, b: string) {} +} + +_decorate([__param(1, Arg())], A.prototype, "method1", null); +_decorate([__param(0, Arg()), __param(1, Arg())], A.prototype, "method2", null); diff --git a/test/snapshots/properties/input.txt b/test/snapshots/properties/input.txt new file mode 100644 index 0000000..4a62286 --- /dev/null +++ b/test/snapshots/properties/input.txt @@ -0,0 +1,4 @@ +class A { + @dec prop: string + @dec @dec2 prop2: string +} diff --git a/test/snapshots/properties/output.txt b/test/snapshots/properties/output.txt new file mode 100644 index 0000000..6a8edc3 --- /dev/null +++ b/test/snapshots/properties/output.txt @@ -0,0 +1,9 @@ +import { __decorate } from "tslib" + +class A { + prop: string; + prop2: string; +} + +__decorate([dec], A.prototype, "prop", void 0); +__decorate([dec, dec2], A.prototype, "prop2", void 0); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 26614e9..6996d5e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,7 @@ { "compilerOptions": { + "experimentalDecorators": true, + "checkJs": false, "strict": true, "noEmit": true }