diff --git a/README.md b/README.md index df69c31..8ac2b37 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,14 @@ Formatting embedded HTML code doesn't require other plugins and uses the parsers Formatting embedded INI code requires [`prettier-plugin-ini`](https://github.com/kddnewton/prettier-plugin-ini) to be loaded as well. And [options](https://github.com/kddnewton/prettier-plugin-ini#configuration) supported by `prettier-plugin-ini` can therefore be used to further control the formatting behavior. +#### LaTeX + +| Option | Default | Description | +| :------------------------: | :----------------------------------------: | --------------------------------------------------------------------------------------------------- | +| `embeddedLatexIdentifiers` | [`[...]`](./src/embedded/latex/options.ts) | Tag or comment identifiers that make their subsequent template literals be identified as LaTeX code | + +Formatting embedded LaTeX code requires [`prettier-plugin-latex`](https://github.com/siefkenj/prettier-plugin-latex) to be loaded as well. + #### Markdown | Option | Default | Description | diff --git a/package-lock.json b/package-lock.json index 914f056..d3d1208 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "prettier": "^3.0.0", "prettier-plugin-glsl": ">=0.1.2 <1", "prettier-plugin-ini": "^1.1.0", + "prettier-plugin-latex": "^2.0.1", "prettier-plugin-organize-imports": "^3.2.4", "prettier-plugin-sql": ">=0.15.0 <1", "prettier-plugin-toml": "^2.0.1", @@ -2750,6 +2751,12 @@ "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, + "node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.12.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", @@ -2945,6 +2952,265 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/@unified-latex/unified-latex-builder": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-builder/-/unified-latex-builder-1.4.2.tgz", + "integrity": "sha512-XVJJiMPiUOus/ZHtdsK9RADVsihUswSjI7IT+UAufIrJdQiLq5WlPI5pq26/T9HuPlZll3Dm4pWo9dmh15a3KQ==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-ctan": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-ctan/-/unified-latex-ctan-1.4.2.tgz", + "integrity": "sha512-jJ4mVjt0mEhMx98uYKRfVh2VqMuF43mvFD0GSysTgZb31+GE4OvPSpjjTjVtrmVmWfXIeqtc6RyDpRGKCmenyQ==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-builder": "^1.4.2", + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-argspec": "^1.4.2", + "@unified-latex/unified-latex-util-arguments": "^1.4.2", + "@unified-latex/unified-latex-util-comments": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-pegjs": "^1.4.2", + "@unified-latex/unified-latex-util-print-raw": "^1.4.2", + "@unified-latex/unified-latex-util-render-info": "^1.4.2", + "@unified-latex/unified-latex-util-replace": "^1.4.2", + "@unified-latex/unified-latex-util-scan": "^1.4.2", + "@unified-latex/unified-latex-util-split": "^1.4.2", + "@unified-latex/unified-latex-util-trim": "^1.4.2", + "@unified-latex/unified-latex-util-visit": "^1.4.2", + "color": "^4.2.3" + } + }, + "node_modules/@unified-latex/unified-latex-prettier": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-prettier/-/unified-latex-prettier-2.4.2.tgz", + "integrity": "sha512-gMvlKGiGi9zOWVHXPhzeURhPYwPIJ7MBht42et/sVb4Z2wTjhcn+bU7kookT067ywOptVZNBgJw+iAgSORAd+w==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-ctan": "^1.4.1", + "@unified-latex/unified-latex-types": "^1.3.1", + "@unified-latex/unified-latex-util-align": "^1.4.0", + "@unified-latex/unified-latex-util-match": "^1.4.0", + "@unified-latex/unified-latex-util-parse": "^1.4.1", + "@unified-latex/unified-latex-util-pgfkeys": "^1.4.0", + "@unified-latex/unified-latex-util-print-raw": "^1.4.0", + "@unified-latex/unified-latex-util-trim": "^1.4.0", + "@unified-latex/unified-latex-util-visit": "^1.4.0", + "prettier": "^3.0.3", + "unified": "^10.1.2" + } + }, + "node_modules/@unified-latex/unified-latex-types": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-types/-/unified-latex-types-1.4.2.tgz", + "integrity": "sha512-aSUMXpdf2UOuCld9P6Ll3IRw7LcE3K0vvlJa2KVpUS1mJA7UDBJ5OOChwFKiPzl/I4NKWJq0LOIsb+54a5Vo5w==", + "dev": true + }, + "node_modules/@unified-latex/unified-latex-util-align": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-align/-/unified-latex-util-align-1.4.2.tgz", + "integrity": "sha512-JJGXaz0GLnYYaMNCafRydWbBl9ZEnKaUubUtUH//K2g9RSg/bHigP1Yo47u7g3fJSuNOFxMiNlZISmU+BnrmMA==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-pegjs": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-argspec": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-argspec/-/unified-latex-util-argspec-1.4.2.tgz", + "integrity": "sha512-u8lu0awTJ6o1a0xZOpIV3RXqlNuy3HyGb17BHEjRIzOLIyqgF5LsVH4OX4MwK5Kjh9GySUE+mDMNqO2b1czIfQ==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-util-pegjs": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-arguments": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-arguments/-/unified-latex-util-arguments-1.4.2.tgz", + "integrity": "sha512-u0yocEmQc8Nbjg0CvUhmfsOPPiXQjHwquPiEMvWqxEV31KGty7jDCq+vDs7rALvMCrgkOR0ugeNtfjAsKa11HA==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-builder": "^1.4.2", + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-argspec": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-render-info": "^1.4.2", + "@unified-latex/unified-latex-util-scan": "^1.4.2", + "@unified-latex/unified-latex-util-visit": "^1.4.2", + "unified": "^10.1.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-catcode": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-catcode/-/unified-latex-util-catcode-1.4.2.tgz", + "integrity": "sha512-05CooHT89eXBKjdUUO4KdOunRyfm1fb+ZyRgjD1kaJ3qxAF64KiyFapCgLPFDL98OyDjRYdELoU2GPzEHiP2xA==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-visit": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-comments": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-comments/-/unified-latex-util-comments-1.4.2.tgz", + "integrity": "sha512-90bbeaSZmgK9ueRno7fH25FNFmnkesLkIJtWjbBasdhMQWjI9jQtM3sgjDjMBHjFaNJSAiwm5cphGt4HhLy1BA==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-replace": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-environments": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-environments/-/unified-latex-util-environments-1.4.2.tgz", + "integrity": "sha512-Mcv+C3Lr0+jx0DKGJOnIPXkhVHPmX+mr1+IO97ZWCC6ibmT8BdkQ0CCN1lUg0pEtEC+JU7KzcoEBkMyS7ftEvQ==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-arguments": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-print-raw": "^1.4.2", + "@unified-latex/unified-latex-util-render-info": "^1.4.2", + "@unified-latex/unified-latex-util-visit": "^1.4.2", + "unified": "^10.1.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-match": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-match/-/unified-latex-util-match-1.4.2.tgz", + "integrity": "sha512-LEa1zE/hrZrUyGuA94AjTWN9/dIqGCdu/ETCT0eCD8jZmRTQPRnn/uKUEIXWTn5yvF6USYzM9Dx5w4pHaTUWaQ==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-print-raw": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-parse": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-parse/-/unified-latex-util-parse-1.4.2.tgz", + "integrity": "sha512-tTCIFnxfqS4xmPS/EENaEwjtf4ECiOSXStOm9MCt9EANgpxLR9qteLgagC5u7sFzvN6NHYYZDhe4XhcyRTvuRg==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-ctan": "^1.4.2", + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-arguments": "^1.4.2", + "@unified-latex/unified-latex-util-catcode": "^1.4.2", + "@unified-latex/unified-latex-util-environments": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-pegjs": "^1.4.2", + "@unified-latex/unified-latex-util-print-raw": "^1.4.2", + "@unified-latex/unified-latex-util-trim": "^1.4.2", + "@unified-latex/unified-latex-util-visit": "^1.4.2", + "unified": "^10.1.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-pegjs": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-pegjs/-/unified-latex-util-pegjs-1.4.2.tgz", + "integrity": "sha512-y0WSOpXRXx64dJ9mMLTe44ZzgRy+axNaZ6R0QgX6hc3IDnQph+gUZJG3sXgZCqZZBVV0/RGJOq9f804PZ9hKAg==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-pgfkeys": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-pgfkeys/-/unified-latex-util-pgfkeys-1.4.2.tgz", + "integrity": "sha512-+iu/HRxqfWMUlr/F4oN2YbA+nwERbhDJXCknsDWBtNUw2dxX35Vu0Ldq9wuTKdJA+q0Lw2xakfZ58lVPgtXVIw==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-pegjs": "^1.4.2", + "@unified-latex/unified-latex-util-print-raw": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-print-raw": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-print-raw/-/unified-latex-util-print-raw-1.4.2.tgz", + "integrity": "sha512-vOY48R72bEQDIIvW21gjFs+y/F+61UIq0UXUBnf4eyR7SWlQwuWt+rO1FTuT0faZJKXRZymB8c1oOLGQl+gWRQ==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-render-info": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-render-info/-/unified-latex-util-render-info-1.4.2.tgz", + "integrity": "sha512-b5vZqpgo3yyH3zDww3PRUDp8DiDEampBRZ3xX7nXbG/B26s4fydToDbMHP5Q9r5YD/hsjGEgHZzGeb96kV997w==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-visit": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-replace": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-replace/-/unified-latex-util-replace-1.4.2.tgz", + "integrity": "sha512-kUdd/M9guhSCQk485BIO7ysIeEENkq3wixVNPEViC1hxR5GjSXnPIqEX0IWTE3uwcPZzskuTiccYG+z46ELULg==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-split": "^1.4.2", + "@unified-latex/unified-latex-util-trim": "^1.4.2", + "@unified-latex/unified-latex-util-visit": "^1.4.2", + "unified": "^10.1.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-scan": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-scan/-/unified-latex-util-scan-1.4.2.tgz", + "integrity": "sha512-veoarQeQVW1A/oSRCH7RI7qz410MecmT1NjzptNz982ODxWT9SS42QSraxm80R4bVooMxjv8r2P5ShlH5u7uWQ==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-print-raw": "^1.4.2", + "trie-prefix-tree": "^1.5.1" + } + }, + "node_modules/@unified-latex/unified-latex-util-split": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-split/-/unified-latex-util-split-1.4.2.tgz", + "integrity": "sha512-IQpUheQpd+jE3fjbzsubhySL80hSRlxix/23/b5h4hwEeBOWU2epAnKG9pcWjvd7xefIH4cvtPvcuqnzry8kcQ==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-trim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-trim/-/unified-latex-util-trim-1.4.2.tgz", + "integrity": "sha512-uAxX03qGnCD+e3jtX3wcjDPvD0amGQeIwCsvBQ1ONhODInq+aBMxf6t1UGC2LpPCmJqAaLevP0pSR39Fzw8zLA==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2", + "@unified-latex/unified-latex-util-render-info": "^1.4.2", + "@unified-latex/unified-latex-util-visit": "^1.4.2", + "unified": "^10.1.2" + } + }, + "node_modules/@unified-latex/unified-latex-util-visit": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@unified-latex/unified-latex-util-visit/-/unified-latex-util-visit-1.4.2.tgz", + "integrity": "sha512-rGqiqiQsyywAZC6rBGteJYE0nSDw/AGddwZWB/KgWvN6VYXZEY8UeBQjcqf01CmaRC8hDXjYk6Pw+By5XfQ4fQ==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-types": "^1.4.2", + "@unified-latex/unified-latex-util-match": "^1.4.2" + } + }, "node_modules/@vitest/browser": { "version": "0.34.6", "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-0.34.6.tgz", @@ -3766,6 +4032,16 @@ "node": "*" } }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4288,6 +4564,19 @@ "url": "https://github.com/sponsors/fregante" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4306,6 +4595,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -5266,6 +5565,12 @@ "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", "dev": true }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, "node_modules/extsprintf": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", @@ -6522,6 +6827,29 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", @@ -12126,6 +12454,19 @@ "prettier": ">=2.3" } }, + "node_modules/prettier-plugin-latex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-latex/-/prettier-plugin-latex-2.0.1.tgz", + "integrity": "sha512-xIKGN0uWU+JwGHI92ixohngGLpy2nGQhYnmTtVue/jbw+K0fFPddQ3pMXx3fjtmmUhlbZisYXehJtcJ9Ford0g==", + "dev": true, + "dependencies": { + "@unified-latex/unified-latex-prettier": "^2.4.2", + "prettier": "^3.0.3" + }, + "engines": { + "node": ">= 18.0" + } + }, "node_modules/prettier-plugin-organize-imports": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz", @@ -13344,6 +13685,21 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + }, "node_modules/sirv": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", @@ -13979,6 +14335,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/trie-prefix-tree": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/trie-prefix-tree/-/trie-prefix-tree-1.5.1.tgz", + "integrity": "sha512-Jjvj/dA97wXnabG/NLJUgo4IQMj6vucH+Qxm7of/omfWSmZlPqdRU6Ta4GmQqCZH+n3/iYZUwfvUoEhB0Hs83Q==", + "dev": true + }, "node_modules/trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -13988,6 +14350,16 @@ "node": ">=8" } }, + "node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ts-api-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", @@ -14543,6 +14915,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unique-filename": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", @@ -14582,6 +14985,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/universal-user-agent": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", @@ -14722,6 +15138,36 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.2.tgz", diff --git a/package.json b/package.json index 912f8ef..5e0914b 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "prettier": "^3.0.0", "prettier-plugin-glsl": ">=0.1.2 <1", "prettier-plugin-ini": "^1.1.0", + "prettier-plugin-latex": "^2.0.1", "prettier-plugin-organize-imports": "^3.2.4", "prettier-plugin-sql": ">=0.15.0 <1", "prettier-plugin-toml": "^2.0.1", diff --git a/src/embedded/latex/embedded-language.ts b/src/embedded/latex/embedded-language.ts new file mode 100644 index 0000000..6d67a00 --- /dev/null +++ b/src/embedded/latex/embedded-language.ts @@ -0,0 +1,7 @@ +export const embeddedLanguage = "embeddedLatex"; + +declare module "../types.js" { + interface EmbeddedLanguagesHolder { + [embeddedLanguage]: void; + } +} diff --git a/src/embedded/latex/embedder.ts b/src/embedded/latex/embedder.ts new file mode 100644 index 0000000..e3cceda --- /dev/null +++ b/src/embedded/latex/embedder.ts @@ -0,0 +1,88 @@ +import type { Options } from "prettier"; +import { builders } from "prettier/doc"; +import type { Embedder } from "../../types.js"; +import { + preparePlaceholder, + printTemplateExpressions, + simpleRehydrateDoc, + throwIfPluginIsNotFound, +} from "../utils.js"; +import { embeddedLanguage } from "./embedded-language.js"; + +const { line, group, indent, softline } = builders; + +export const embedder: Embedder = async ( + textToDoc, + print, + path, + options, + { identifier, embeddedOverrideOptions }, +) => { + throwIfPluginIsNotFound("prettier-plugin-latex", options, identifier); + + options = { + ...options, + ...embeddedOverrideOptions, + }; + + const { node } = path; + + const { createPlaceholder, placeholderRegex } = preparePlaceholder(); + + const text = node.quasis + .map((quasi, index, { length }) => + index === length - 1 + ? quasi.value.cooked + : quasi.value.cooked + createPlaceholder(index), + ) + .join(""); + + const leadingWhitespaces = text.match(/^\s+/)?.[0] ?? ""; + const trailingWhitespaces = text.match(/\s+$/)?.[0] ?? ""; + + const trimmedText = text.slice( + leadingWhitespaces.length, + -trailingWhitespaces.length || undefined, + ); + + const expressionDocs = printTemplateExpressions(path, print); + + const doc = await textToDoc(trimmedText, { + ...options, + parser: "latex-parser", + }); + + const contentDoc = simpleRehydrateDoc(doc, placeholderRegex, expressionDocs); + + if (options.preserveEmbeddedExteriorWhitespaces?.includes(identifier)) { + // TODO: should we label the doc with { hug: false } ? + // https://github.com/prettier/prettier/blob/5cfb76ee50cf286cab267cf3cb7a26e749c995f7/src/language-js/embed/html.js#L88 + return group([ + "`", + leadingWhitespaces, + options.noEmbeddedMultiLineIndentation?.includes(identifier) + ? [group(contentDoc)] + : indent([group(contentDoc)]), + trailingWhitespaces, + "`", + ]); + } + + const leadingLineBreak = leadingWhitespaces.length ? line : softline; + const trailingLineBreak = trailingWhitespaces.length ? line : softline; + + return group([ + "`", + options.noEmbeddedMultiLineIndentation?.includes(identifier) + ? [leadingLineBreak, group(contentDoc)] + : indent([leadingLineBreak, group(contentDoc)]), + trailingLineBreak, + "`", + ]); +}; + +declare module "../types.js" { + interface EmbeddedEmbedders { + [embeddedLanguage]: typeof embedder; + } +} diff --git a/src/embedded/latex/index.ts b/src/embedded/latex/index.ts new file mode 100644 index 0000000..cee8055 --- /dev/null +++ b/src/embedded/latex/index.ts @@ -0,0 +1,3 @@ +export * from "./embedded-language.js"; +export * from "./embedder.js"; +export * from "./options.js"; diff --git a/src/embedded/latex/options.ts b/src/embedded/latex/options.ts new file mode 100644 index 0000000..f007c61 --- /dev/null +++ b/src/embedded/latex/options.ts @@ -0,0 +1,54 @@ +import type { CoreCategoryType, SupportOptions } from "prettier"; +import { + makeIdentifiersOptionName, + type AutocompleteStringList, + type StringListToInterfaceKey, +} from "../utils.js"; +import { embeddedLanguage } from "./embedded-language.js"; + +/** References: + * - https://github.com/github-linguist/linguist/blob/7ca3799b8b5f1acde1dd7a8dfb7ae849d3dfb4cd/lib/linguist/languages.yml#L6994 + */ +const DEFAULT_IDENTIFIERS = [ + "latex", + "tex", + "aux", + "cls", + "bbl", + "bib", + "toc", + "sty", +] as const; +type Identifiers = AutocompleteStringList; +type DefaultIdentifiersHolder = StringListToInterfaceKey< + typeof DEFAULT_IDENTIFIERS +>; + +const embeddedLanguageIdentifiers = makeIdentifiersOptionName(embeddedLanguage); + +export interface PrettierPluginDepsOptions {} + +export const options = { + [embeddedLanguageIdentifiers]: { + category: "Global", + type: "string", + array: true, + default: [{ value: [...DEFAULT_IDENTIFIERS] }], + description: + 'Specify embedded LaTeX language identifiers. This requires "prettier-plugin-latex".', + }, +} satisfies SupportOptions & Record; + +type Options = typeof options; + +declare module "../types.js" { + interface EmbeddedOptions extends Options {} + interface EmbeddedDefaultIdentifiersHolder extends DefaultIdentifiersHolder {} + interface PrettierPluginEmbedOptions { + [embeddedLanguageIdentifiers]?: Identifiers; + } +} + +declare module "prettier" { + export interface Options extends PrettierPluginDepsOptions {} +}