diff --git a/.eslintrc.json b/.eslintrc.json index 9eac8d7..01f066d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -22,7 +22,7 @@ "no-this-before-super": "warn", "no-undef": "warn", "no-unreachable": "warn", - "no-unused-vars": "warn", + "no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], "constructor-super": "warn", "valid-typeof": "warn", "indent": [ diff --git a/.github/workflows/release-prettier.yml b/.github/workflows/release-prettier.yml new file mode 100644 index 0000000..31e7cbf --- /dev/null +++ b/.github/workflows/release-prettier.yml @@ -0,0 +1,42 @@ +name: Release Prettier Plugin + +on: + push: + branches: + - main + paths: + - 'prettier-plugin-blits/**' + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '20' + + - name: Install Dependencies + run: npm install + + - name: Install monorepo dependencies + run: npm install --workspaces + + - name: Run Tests + run: npm run test --workspace=prettier-plugin-blits + + - name: Read package.json + run: | + plugin_name=$(node -p "require('./prettier-plugin-blits/package.json').name") + plugin_version=$(node -p "require('./prettier-plugin-blits/package.json').version") + echo "PLUGIN_NAME=$plugin_name" >> $GITHUB_ENV + echo "PLUGIN_VERSION=$plugin_version" >> $GITHUB_ENV + + - name: Create GitHub Pre Release + run: | + gh auth login --with-token <<< "${{ secrets.GITHUB_TOKEN }}" + gh release create prettier-v${{ env.PLUGIN_VERSION }} --prerelease -t "prettier-plugin-blits v${{ env.PLUGIN_VERSION }}" -n "Version ${{ env.PLUGIN_VERSION }} of ${{ env.PLUGIN_NAME }}" diff --git a/package-lock.json b/package-lock.json index 027215a..6218195 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,23 @@ } }, "eslint-plugin-blits": { - "extraneous": true + "name": "@lightningjs/eslint-plugin-blits", + "version": "0.1.0", + "extraneous": true, + "license": "Apache-2.0", + "devDependencies": { + "eslint": "^9.26.0", + "eslint-config-prettier": "^10.1.3", + "eslint-plugin-prettier": "^5.4.0", + "globals": "^16.1.0", + "prettier": "^3.5.3" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.0 || ^9.0.0" + } }, "node_modules/@azu/format-text": { "version": "1.0.2", @@ -595,6 +611,10 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lightningjs/prettier-plugin-blits": { + "resolved": "prettier-plugin-blits", + "link": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -1069,9 +1089,7 @@ } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.12.6", "dev": true, "license": "MIT", "dependencies": { @@ -1085,16 +1103,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "dev": true, @@ -2194,9 +2202,7 @@ } }, "node_modules/flatted": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz", - "integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==", + "version": "3.3.3", "dev": true, "license": "ISC" }, @@ -3097,9 +3103,7 @@ } }, "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "version": "3.1.2", "dev": true, "license": "ISC", "dependencies": { @@ -3967,13 +3971,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, "node_modules/simple-concat": { "version": "1.0.1", "dev": true, @@ -4560,6 +4557,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "prettier-plugin-blits": { + "name": "@lightningjs/prettier-plugin-blits", + "version": "0.1.0", + "license": "Apache-2.0", + "devDependencies": { + "prettier": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "prettier": ">=3.0.0" + } + }, + "prettier-plugin-blits/node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "vscode-extension": { "name": "lightning-blits", "version": "1.6.0", @@ -4822,6 +4849,14 @@ "node": ">=16" } }, + "vscode-extension/node_modules/ansi-colors": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "vscode-extension/node_modules/binary-extensions": { "version": "2.3.0", "dev": true, @@ -5180,6 +5215,70 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "vscode-extension/node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "vscode-extension/node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "vscode-extension/node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "vscode-extension/node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "vscode-extension/node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "vscode-extension/node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "vscode-extension/node_modules/mocha": { "version": "10.7.3", "dev": true, @@ -5214,6 +5313,17 @@ "node": ">= 14.0.0" } }, + "vscode-extension/node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "vscode-extension/node_modules/mocha/node_modules/glob": { "version": "8.1.0", "dev": true, @@ -5232,6 +5342,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "vscode-extension/node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "vscode-extension/node_modules/mocha/node_modules/minimatch": { "version": "5.1.6", "dev": true, @@ -5445,6 +5563,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "vscode-extension/node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, "vscode-extension/node_modules/serialize-javascript": { "version": "6.0.2", "dev": true, @@ -5606,6 +5729,36 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "vscode-extension/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "vscode-extension/node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "vscode-extension/node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, "vscode-extension/node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "dev": true, diff --git a/prettier-plugin-blits/CHANGELOG.md b/prettier-plugin-blits/CHANGELOG.md new file mode 100644 index 0000000..554370e --- /dev/null +++ b/prettier-plugin-blits/CHANGELOG.md @@ -0,0 +1,16 @@ +# Change Log + +## v1.0.0 + +- First release of `@lightningjs/prettier-plugin-blits` +- Formats Blits template strings inside `Blits.Component()` and `Blits.Application()` +- Adds `blitsWrapAttributes` to wrap long attribute lists across multiple lines +- Adds `blitsClosingBacktick` to control where the closing backtick is placed +- Adds `blitsClosingBracketSameLine` to keep the closing `>` on the last attribute line in multiline tags +- Adds `blitsPreserveBlankLines` to preserve blank lines between sibling elements +- Adds `blitsNormalizeComments` to normalize HTML comment spacing +- Adds `blitsTrimAttributeValues` to trim leading and trailing whitespace in attribute values +- Adds `blitsSelfClosingTags` to collapse empty tags to self-closing form +- Adds `blitsCollapseSingleElement` to collapse eligible single-element multiline templates +- Preserves escape sequences in attribute values correctly +- Preserves multiline template structure by default diff --git a/prettier-plugin-blits/README.md b/prettier-plugin-blits/README.md new file mode 100644 index 0000000..3128ab4 --- /dev/null +++ b/prettier-plugin-blits/README.md @@ -0,0 +1,250 @@ +# Prettier Plugin for Blits + +Formats the `template` string inside `Blits.Component()` and `Blits.Application()` calls, in JavaScript and TypeScript files. + +## Requirements + +- Node.js 18+ +- Prettier 3.x + +## Installation + +```bash +npm install --save-dev @lightningjs/prettier-plugin-blits +``` + +### If you use a `.prettierrc` + +Add the plugin to your Prettier config. If you already use other plugins, just include this one in the same list: + +```json +{ + "plugins": ["@lightningjs/prettier-plugin-blits"], + "blitsWrapAttributes": true, + "blitsClosingBacktick": "newline", + "blitsPreserveBlankLines": true +} +``` + +### If you run Prettier through ESLint + +If your setup uses `eslint-plugin-prettier`, add the plugin to the inline Prettier options in your ESLint config: + +```js +// .eslintrc.cjs +rules: { + 'prettier/prettier': [ + 'error', + { + singleQuote: true, + semi: false, + // ... your other prettier options + plugins: ['@lightningjs/prettier-plugin-blits'], + // you can change plugin options like this + blitsWrapAttributes: true, + blitsClosingBacktick: 'newline', + blitsPreserveBlankLines: true, + }, + ], +} +``` + +> `eslint-plugin-prettier` v5+ is required for Prettier 3. If you are upgrading from Prettier 2, also update `eslint-plugin-prettier` to `^5.0.0` and `eslint-config-prettier` to `^9.0.0`. + +### If you use a `prettier.config.js` + +```js +export default { + plugins: ['@lightningjs/prettier-plugin-blits'], + // you can change plugin options like this + blitsWrapAttributes: true, + blitsClosingBacktick: 'newline', + blitsPreserveBlankLines: true, +} +``` + +For CommonJS projects: + +```js +module.exports = { + plugins: ['@lightningjs/prettier-plugin-blits'], + // you can change plugin options like this + blitsWrapAttributes: true, + blitsClosingBacktick: 'newline', + blitsPreserveBlankLines: true, +} +``` + +## What the plugin formats + +### Where it applies + +The plugin only touches the value of the `template` property inside `Blits.Component()` or `Blits.Application()`. Everything else in the file is still handled by Prettier as usual. + +Template literals with `${...}` interpolations are left alone. + +### Inline vs multi-line + +Short templates that fit within `printWidth` stay on one line: + +```js +template: `` +``` + +Longer templates expand to multiple lines by default, with the content indented: + +```js +template: ` + + + +` +``` + +### Attribute wrapping + +When a tag and its attributes fit within `printWidth`, they stay on one line. If they do not fit, each attribute moves to its own line: + +```js +// fits on one line — stays inline + + +// too long — each attribute on its own line + +``` + +### Children + +Child elements are indented relative to their parent using your configured `tabWidth`: + +```js +template: ` + + + + + +` +``` + +### Blank lines + +Blank lines between sibling elements are preserved. If there are several in a row, they are collapsed to a single blank line: + +```js +template: ` + + + + + + +