From 8b0f8f55c9709dcee2eee09b5be9491976278ede Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 11 Jun 2023 07:10:15 -0700 Subject: [PATCH] feat: fleshed out initial version of package --- README.md | 49 ++++----- package.json | 11 +- pnpm-lock.yaml | 189 ++++++++++++++++++++++------------- src/greet.test.ts | 44 -------- src/greet.ts | 13 --- src/index.ts | 17 +++- src/preprocess.test.ts | 27 +++++ src/preprocess.ts | 58 +++++++++++ src/printNodeWithBrackets.ts | 69 +++++++++++++ src/types.ts | 14 ++- vitest.config.ts | 2 +- 11 files changed, 327 insertions(+), 166 deletions(-) delete mode 100644 src/greet.test.ts delete mode 100644 src/greet.ts create mode 100644 src/preprocess.test.ts create mode 100644 src/preprocess.ts create mode 100644 src/printNodeWithBrackets.ts diff --git a/README.md b/README.md index fcecdbe..b9858ef 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ -All Contributors: 20 +All Contributors: 1 @@ -28,14 +28,28 @@ ## Usage +First install this package as a dev dependency in your package manager of choice: + ```shell -npm i prettier-plugin-curly +npm i prettier-plugin-curly -D +``` + +You'll then be able to list it as a [Prettier plugin](https://prettier.io/docs/en/plugins.html) in your [Prettier config](https://prettier.io/docs/en/configuration.html): + +```jsonc +{ + "plugins": ["prettier-plugin-packagejson"], + "useTabs": true +} ``` -```ts -import { greet } from "prettier-plugin-curly"; +As a result, Prettier will add `{}` curly brackets to control flow statements such as `for`, `if`, and `while`: -greet("Hello, world!"); +```diff +- if (abc) def; ++ if (abc) { ++ def; ++ } ``` ## Development @@ -52,30 +66,7 @@ Thanks! 💖 - - - - - - - - - - - - - - - - - - - - - - - - +
Anurag
Anurag

💻
Daniel Roe
Daniel Roe

💻
Dominik Nowik
Dominik Nowik

🔧 💻
Emerson
Emerson

💻
Jeff Wen
Jeff Wen

💻
Joe Previte
Joe Previte

🐛 💻
John Reilly
John Reilly

💻
Josh Goldberg
Josh Goldberg

🐛 💻 🚧 👀 🔧 📖 🚇 🖋 🤔 📆
Lars Kappert
Lars Kappert

💻
Navin Moorthy
Navin Moorthy

🐛 💻
NazCodeland
NazCodeland

💻
Orta Therox
Orta Therox

💻
Paul Esch-Laurent
Paul Esch-Laurent

💻
Promise Dash
Promise Dash

💻
Rebecca Stevens
Rebecca Stevens

💻 🚇
Ron Braha
Ron Braha

💻 🎨
Ron Jean-Francois
Ron Jean-Francois

💻 🚇
Sudhansu
Sudhansu

💻
Tung Bui (Leo)
Tung Bui (Leo)

💻
takanomedev
takanomedev

💻
Josh Goldberg
Josh Goldberg

🔧
diff --git a/package.json b/package.json index 08e1e37..b7bdf43 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,15 @@ "lint-staged": { "*": "prettier --ignore-unknown --write" }, + "dependencies": { + "@babel/parser": "^7.22.5", + "@babel/traverse": "^7.22.5" + }, "devDependencies": { + "@babel/types": "^7.22.5", + "@types/babel__traverse": "^7.20.1", "@types/eslint": "^8.37.0", + "@types/prettier": "^2.7.3", "@typescript-eslint/eslint-plugin": "^5.59.5", "@typescript-eslint/parser": "^5.59.5", "@vitest/coverage-istanbul": "^0.31.0", @@ -67,7 +74,6 @@ "markdownlint-cli": "^0.34.0", "npm-package-json-lint": "^6.4.0", "npm-package-json-lint-config-default": "^5.0.0", - "prettier": "^2.8.8", "prettier-plugin-packagejson": "^2.4.3", "release-it": "^15.10.3", "sentences-per-line": "^0.2.1", @@ -76,6 +82,9 @@ "vitest": "^0.31.0", "yaml-eslint-parser": "^1.2.2" }, + "peerDependencies": { + "prettier": "^2" + }, "packageManager": "pnpm@8.6.0", "engines": { "node": ">=18" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcbac08..b8a76e8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,10 +4,30 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +dependencies: + '@babel/parser': + specifier: ^7.22.5 + version: 7.22.5 + '@babel/traverse': + specifier: ^7.22.5 + version: 7.22.5 + prettier: + specifier: ^2.8.8 + version: 2.8.8 + devDependencies: + '@babel/types': + specifier: ^7.22.5 + version: 7.22.5 + '@types/babel__traverse': + specifier: ^7.20.1 + version: 7.20.1 '@types/eslint': specifier: ^8.37.0 version: 8.37.0 + '@types/prettier': + specifier: ^2.7.3 + version: 2.7.3 '@typescript-eslint/eslint-plugin': specifier: ^5.59.5 version: 5.59.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0)(typescript@5.0.4) @@ -89,12 +109,9 @@ devDependencies: npm-package-json-lint-config-default: specifier: ^5.0.0 version: 5.0.0(npm-package-json-lint@6.4.0) - prettier: - specifier: ^2.8.8 - version: 2.8.8 prettier-plugin-packagejson: specifier: ^2.4.3 - version: 2.4.3(prettier@2.8.8) + version: 2.4.3 release-it: specifier: ^15.10.3 version: 15.10.3 @@ -131,6 +148,12 @@ packages: '@babel/highlight': 7.18.6 dev: true + /@babel/code-frame@7.22.5: + resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.22.5 + /@babel/compat-data@7.20.10: resolution: {integrity: sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==} engines: {node: '>=6.9.0'} @@ -146,10 +169,10 @@ packages: '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.20.12) '@babel/helper-module-transforms': 7.20.11 '@babel/helpers': 7.20.7 - '@babel/parser': 7.20.7 + '@babel/parser': 7.22.5 '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.20.7 + '@babel/traverse': 7.22.5 + '@babel/types': 7.22.5 convert-source-map: 1.9.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -163,11 +186,20 @@ packages: resolution: {integrity: sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.7 + '@babel/types': 7.22.5 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 dev: true + /@babel/generator@7.22.5: + resolution: {integrity: sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.5 + '@jridgewell/gen-mapping': 0.3.2 + '@jridgewell/trace-mapping': 0.3.17 + jsesc: 2.5.2 + /@babel/helper-compilation-targets@7.20.7(@babel/core@7.20.12): resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} engines: {node: '>=6.9.0'} @@ -187,26 +219,28 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helper-function-name@7.19.0: - resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} + /@babel/helper-environment-visitor@7.22.5: + resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} + engines: {node: '>=6.9.0'} + + /@babel/helper-function-name@7.22.5: + resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.20.7 - '@babel/types': 7.20.7 - dev: true + '@babel/template': 7.22.5 + '@babel/types': 7.22.5 - /@babel/helper-hoist-variables@7.18.6: - resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.7 - dev: true + '@babel/types': 7.22.5 /@babel/helper-module-imports@7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.7 + '@babel/types': 7.22.5 dev: true /@babel/helper-module-transforms@7.20.11: @@ -219,8 +253,8 @@ packages: '@babel/helper-split-export-declaration': 7.18.6 '@babel/helper-validator-identifier': 7.19.1 '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.20.7 + '@babel/traverse': 7.22.5 + '@babel/types': 7.22.5 transitivePeerDependencies: - supports-color dev: true @@ -229,26 +263,35 @@ packages: resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.7 + '@babel/types': 7.22.5 dev: true /@babel/helper-split-export-declaration@7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.7 + '@babel/types': 7.22.5 dev: true - /@babel/helper-string-parser@7.19.4: - resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} + /@babel/helper-split-export-declaration@7.22.5: + resolution: {integrity: sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.5 + + /@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} dev: true + /@babel/helper-validator-identifier@7.22.5: + resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} + engines: {node: '>=6.9.0'} + /@babel/helper-validator-option@7.18.6: resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} engines: {node: '>=6.9.0'} @@ -259,8 +302,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.20.7 + '@babel/traverse': 7.22.5 + '@babel/types': 7.22.5 transitivePeerDependencies: - supports-color dev: true @@ -274,49 +317,62 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser@7.20.7: - resolution: {integrity: sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==} + /@babel/highlight@7.22.5: + resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.5 + chalk: 2.4.2 + js-tokens: 4.0.0 + + /@babel/parser@7.22.5: + resolution: {integrity: sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.20.7 - dev: true + '@babel/types': 7.22.5 /@babel/template@7.20.7: resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.7 - '@babel/types': 7.20.7 + '@babel/parser': 7.22.5 + '@babel/types': 7.22.5 dev: true - /@babel/traverse@7.20.12: - resolution: {integrity: sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==} + /@babel/template@7.22.5: + resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.7 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.19.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.20.7 - '@babel/types': 7.20.7 + '@babel/code-frame': 7.22.5 + '@babel/parser': 7.22.5 + '@babel/types': 7.22.5 + + /@babel/traverse@7.22.5: + resolution: {integrity: sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.5 + '@babel/generator': 7.22.5 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.5 + '@babel/parser': 7.22.5 + '@babel/types': 7.22.5 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true - /@babel/types@7.20.7: - resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==} + /@babel/types@7.22.5: + resolution: {integrity: sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.19.4 - '@babel/helper-validator-identifier': 7.19.1 + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.5 to-fast-properties: 2.0.0 - dev: true /@cspell/cspell-bundled-dicts@6.31.1: resolution: {integrity: sha512-rsIev+dk1Vd8H1OKZhNhXycIVsMfeWJaeW3QUi1l4oIoGwQfJVbs1ZPZPHE5cglzyHOW1jQNStXf34UKaC6siA==} @@ -881,28 +937,23 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.14 '@jridgewell/trace-mapping': 0.3.17 - dev: true /@jridgewell/resolve-uri@3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/sourcemap-codec@1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - dev: true /@jridgewell/trace-mapping@0.3.17: resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 - dev: true /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -1125,6 +1176,12 @@ packages: engines: {node: '>= 6'} dev: true + /@types/babel__traverse@7.20.1: + resolution: {integrity: sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==} + dependencies: + '@babel/types': 7.22.5 + dev: true + /@types/chai-subset@1.3.3: resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} dependencies: @@ -1176,6 +1233,10 @@ packages: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true + /@types/prettier@2.7.3: + resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} + dev: true + /@types/semver@7.3.13: resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} dev: true @@ -1540,7 +1601,6 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 - dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -1884,7 +1944,6 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1991,7 +2050,6 @@ packages: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 - dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -2002,7 +2060,6 @@ packages: /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -2309,7 +2366,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true /decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} @@ -2623,7 +2679,6 @@ packages: /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - dev: true /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} @@ -3354,7 +3409,6 @@ packages: /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - dev: true /globals@13.19.0: resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==} @@ -3444,7 +3498,6 @@ packages: /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} - dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -4020,7 +4073,7 @@ packages: engines: {node: '>=8'} dependencies: '@babel/core': 7.20.12 - '@babel/parser': 7.20.7 + '@babel/parser': 7.22.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -4103,7 +4156,6 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} @@ -4127,7 +4179,6 @@ packages: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true - dev: true /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -4701,7 +4752,6 @@ packages: /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -5213,7 +5263,7 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier-plugin-packagejson@2.4.3(prettier@2.8.8): + /prettier-plugin-packagejson@2.4.3: resolution: {integrity: sha512-kPeeviJiwy0BgOSk7No8NmzzXfW4R9FYWni6ziA5zc1kGVVrKnBzMZdu2TUhI+I7h8/5Htt3vARYOk7KKJTTNQ==} peerDependencies: prettier: '>= 1.16.0' @@ -5221,7 +5271,6 @@ packages: prettier: optional: true dependencies: - prettier: 2.8.8 sort-package-json: 2.4.1 synckit: 0.8.5 dev: true @@ -5230,7 +5279,7 @@ packages: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} hasBin: true - dev: true + dev: false /pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} @@ -5978,7 +6027,6 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 - dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -6069,7 +6117,6 @@ packages: /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} - dev: true /to-no-case@1.0.2: resolution: {integrity: sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==} diff --git a/src/greet.test.ts b/src/greet.test.ts deleted file mode 100644 index f729115..0000000 --- a/src/greet.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; - -import { greet } from "./greet.js"; - -const message = "Yay, testing!"; - -describe("greet", () => { - it("logs to the console once when message is provided as a string", () => { - const logger = vi.spyOn(console, "log").mockImplementation(() => undefined); - - greet(message); - - expect(logger).toHaveBeenCalledWith(message); - expect(logger).toHaveBeenCalledTimes(1); - }); - - it("logs to the console once when message is provided as an object", () => { - const logger = vi.spyOn(console, "log").mockImplementation(() => undefined); - - greet({ message }); - - expect(logger).toHaveBeenCalledWith(message); - expect(logger).toHaveBeenCalledTimes(1); - }); - - it("logs once when times is not provided in an object", () => { - const logger = vi.fn(); - - greet({ logger, message }); - - expect(logger).toHaveBeenCalledWith(message); - expect(logger).toHaveBeenCalledTimes(1); - }); - - it("logs a specified number of times when times is provided", () => { - const logger = vi.fn(); - const times = 7; - - greet({ logger, message, times }); - - expect(logger).toHaveBeenCalledWith(message); - expect(logger).toHaveBeenCalledTimes(7); - }); -}); diff --git a/src/greet.ts b/src/greet.ts deleted file mode 100644 index a0d3b4c..0000000 --- a/src/greet.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { GreetOptions } from "./types.js"; - -export function greet(options: GreetOptions | string) { - const { - logger = console.log.bind(console), - message, - times = 1, - } = typeof options === "string" ? { message: options } : options; - - for (let i = 0; i < times; i += 1) { - logger(message); - } -} diff --git a/src/index.ts b/src/index.ts index a39b40f..49ecc5f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,15 @@ -export * from "./greet.js"; -export * from "./types.js"; +import { parsers as babelParsers } from "prettier/parser-babel"; +import { parsers as typescriptParsers } from "prettier/parser-typescript"; + +import { preprocess } from "./preprocess.js"; + +export const parsers = { + babel: { + ...babelParsers.babel, + preprocess, + }, + typescript: { + ...typescriptParsers.typescript, + preprocess, + }, +}; diff --git a/src/preprocess.test.ts b/src/preprocess.test.ts new file mode 100644 index 0000000..2730882 --- /dev/null +++ b/src/preprocess.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, test } from "vitest"; + +import { preprocess } from "./preprocess.js"; + +describe("preprocess", () => { + test.each([ + [`do a; while (b);`, `do { a; } while (b)`], + [`do { a; } while (b);`, `do { a; } while (b);`], + [`for (; ; ) d;`, `for (; ; ) { d; }`], + [`for (; ; ) { d; }`, `for (; ; ) { d; }`], + [`for (a; b; c) d;`, `for (a; b; c) { d; }`], + [`for (a; b; c) { d; }`, `for (a; b; c) { d; }`], + [`for (const a in b) c;`, `for (const a in b) { c; }`], + [`for (const a in b) { c; }`, `for (const a in b) { c; }`], + [`for (const a of b) c;`, `for (const a of b) { c; }`], + [`for (const a of b) { c; }`, `for (const a of b) { c; }`], + [`if (a) b;`, `if (a) { b; }`], + [`if (a) { b; }`, `if (a) { b; }`], + [`while (a) b;`, `while (a) { b; }`], + [`while (a) { b; }`, `while (a) { b; }`], + ["while (a) c;", "while (a) { c; }"], + ["while (a) ;", "while (a) { ; }", "test.js"], + ["while (a) ;", "while (a) { ; }", "test.tsx"], + ])("%s becomes %s", (input, expected, filepath = "test.ts") => { + expect(preprocess(input, { filepath })).toBe(expected); + }); +}); diff --git a/src/preprocess.ts b/src/preprocess.ts new file mode 100644 index 0000000..010367a --- /dev/null +++ b/src/preprocess.ts @@ -0,0 +1,58 @@ +import { parse } from "@babel/parser"; +import traverse, { NodePath } from "@babel/traverse"; +import { Node } from "@babel/types"; +import { RequiredOptions } from "prettier"; + +import { printNodeWithBrackets } from "./printNodeWithBrackets.js"; +import { CollectibleNode } from "./types.js"; + +export function preprocess( + code: string, + options: Pick +) { + const ast = parse(code, { + // Note: these are a best-guess attempt to match most common syntax features. + // If users need to modify this list, we should probably add a plugin option. + plugins: [ + "decoratorAutoAccessors", + "decorators-legacy", + "importAssertions", + ...(/(?:js|x)$/.test(options.filepath) ? ["jsx" as const] : []), + "typescript", + ], + sourceType: "module", + }); + const collectedNodes: CollectibleNode[] = []; + + function createCollector(property: PropertyKey) { + return ({ + node, + }: NodePath>) => { + if (node[property].type !== "BlockStatement") { + collectedNodes.push(node); + } + }; + } + + traverse(ast, { + DoWhileStatement: createCollector("body"), + ForInStatement: createCollector("body"), + ForOfStatement: createCollector("body"), + ForStatement: createCollector("body"), + IfStatement: createCollector("consequent"), + WhileStatement: createCollector("body"), + }); + + let output = ""; + let lastEnd = 0; + + /* eslint-disable @typescript-eslint/no-non-null-assertion */ + for (const collectedNode of collectedNodes) { + output += code.slice(lastEnd, collectedNode.start!); + output += printNodeWithBrackets(code, collectedNode); + lastEnd = collectedNode.end!; + } + /* eslint-enable @typescript-eslint/no-non-null-assertion */ + + return output + code.slice(lastEnd); +} diff --git a/src/printNodeWithBrackets.ts b/src/printNodeWithBrackets.ts new file mode 100644 index 0000000..0e38321 --- /dev/null +++ b/src/printNodeWithBrackets.ts @@ -0,0 +1,69 @@ +import { CollectibleNode } from "./types.js"; + +export function printNodeWithBrackets(code: string, node: CollectibleNode) { + /* eslint-disable @typescript-eslint/no-non-null-assertion */ + switch (node.type) { + case "DoWhileStatement": + return [ + "do { ", + code.slice(node.body.start!, node.body.end!), + " } while (", + code.slice(node.test.start!, node.test.end!), + ")", + ].join(""); + + case "ForStatement": + return [ + "for (", + node.init && code.slice(node.init.start!, node.init.end!), + "; ", + node.test && code.slice(node.test.start!, node.test.end!), + "; ", + node.update && code.slice(node.update.start!, node.update.end!), + ") { ", + code.slice(node.body.start!, node.body.end!), + " }", + ] + .filter(Boolean) + .join(""); + + case "ForInStatement": + return [ + "for (", + code.slice(node.left.start!, node.left.end!), + " in ", + code.slice(node.right.start!, node.right.end!), + ") { ", + code.slice(node.body.start!, node.body.end!), + " }", + ].join(""); + + case "ForOfStatement": + return [ + "for (", + code.slice(node.left.start!, node.left.end!), + " of ", + code.slice(node.right.start!, node.right.end!), + ") { ", + code.slice(node.body.start!, node.body.end!), + " }", + ].join(""); + + case "IfStatement": + return [ + code.slice(node.start!, node.test.end!), + ") { ", + code.slice(node.consequent.start!, node.end!), + " }", + ].join(""); + + case "WhileStatement": + return [ + code.slice(node.start!, node.test.end!), + ") { ", + code.slice(node.body.start!, node.end!), + " }", + ].join(""); + } + /* eslint-enable @typescript-eslint/no-non-null-assertion */ +} diff --git a/src/types.ts b/src/types.ts index 4f16ae3..1ac45d5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,9 @@ -export interface GreetOptions { - logger?: (message: string) => void; - message: string; - times?: number; -} +import type * as babel from "@babel/types"; + +export type CollectibleNode = + | babel.DoWhileStatement + | babel.ForInStatement + | babel.ForOfStatement + | babel.ForStatement + | babel.IfStatement + | babel.WhileStatement; diff --git a/vitest.config.ts b/vitest.config.ts index 9b88e5c..2d8365e 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -5,7 +5,7 @@ export default defineConfig({ clearMocks: true, coverage: { all: true, - exclude: ["lib"], + exclude: ["lib", "src/index.ts"], include: ["src"], provider: "istanbul", reporter: ["html", "lcov"],