From 019c2d5fc091ca47c061e971df552ca37ded71e9 Mon Sep 17 00:00:00 2001 From: uncenter <47499684+uncenter@users.noreply.github.com> Date: Thu, 11 Jul 2024 15:40:05 -0400 Subject: [PATCH] refactor: switch from prettier to biome (#102) --- .github/workflows/build.yml | 6 +- .github/workflows/check.yml | 30 ++++++++ .github/workflows/release-please.yml | 4 +- .prettierignore | 2 - .prettierrc | 14 ---- .vscode/settings.json | 5 ++ biome.json | 69 ++++++++++++++++++ package.json | 4 +- pnpm-lock.yaml | 101 ++++++++++++++++++++++++--- renovate.json | 5 +- src/entries/content/index.ts | 2 +- src/entries/content/lib.ts | 41 ++++++----- src/entries/popup/main.ts | 31 +++----- src/types.ts | 2 +- wxt.config.ts | 29 +++----- 15 files changed, 244 insertions(+), 101 deletions(-) create mode 100644 .github/workflows/check.yml delete mode 100644 .prettierignore delete mode 100644 .prettierrc create mode 100644 .vscode/settings.json create mode 100644 biome.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 823a38d..b1fe8de 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: 'recursive' + submodules: "recursive" - name: Setup pnpm uses: pnpm/action-setup@v3 @@ -23,10 +23,10 @@ jobs: with: cache: pnpm cache-dependency-path: pnpm-lock.yaml - node-version-file: '.nvmrc' + node-version-file: ".nvmrc" - name: Install dependencies - run: pnpm install --frozen-lockfile + run: pnpm install - name: Build and zip run: | diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..5cebe38 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,30 @@ +name: Check + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v3 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + node-version-file: ".nvmrc" + + - name: Install dependencies + run: pnpm install + + - name: Check files with Biome + run: | + pnpm biome ci --reporter=github diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 4e7948b..a032925 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -37,10 +37,10 @@ jobs: with: cache: pnpm cache-dependency-path: pnpm-lock.yaml - node-version-file: '.nvmrc' + node-version-file: ".nvmrc" - name: Install dependencies - run: pnpm install --frozen-lockfile + run: pnpm install - name: Build and zip run: | diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 6b2e3cb..0000000 --- a/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -pnpm-lock.yaml -vscode-icons/ diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 6104491..0000000 --- a/.prettierrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "semi": true, - "singleQuote": true, - "useTabs": true, - "overrides": [ - { - "files": "**/*.{yml,yaml,md}", - "options": { - "useTabs": false, - "tabWidth": 2 - } - } - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..58e9fb5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "prettier.enable": false, + "biome.enabled": true, + "editor.defaultFormatter": "biomejs.biome" +} diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..aad824c --- /dev/null +++ b/biome.json @@ -0,0 +1,69 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignore": ["vscode-icons/**"] + }, + "formatter": { + "enabled": true, + "formatWithErrors": false, + "indentStyle": "tab", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 80, + "attributePosition": "auto", + "ignore": ["pnpm-lock.yaml"] + }, + "organizeImports": { "enabled": true }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedImports": "warn", + "noUnusedVariables": "warn", + "useArrayLiterals": "error" + }, + "style": { + "noNegationElse": "error", + "useCollapsedElseIf": "error", + "useConsistentArrayType": { + "level": "error", + "options": { + "syntax": "generic" + } + }, + "useForOf": "error" + }, + "suspicious": { + "useAwait": "error" + }, + "complexity": { + "useSimplifiedLogicExpression": "error" + } + } + }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "double", + "quoteProperties": "asNeeded", + "trailingCommas": "all", + "semicolons": "always", + "arrowParentheses": "always", + "bracketSpacing": true, + "bracketSameLine": false, + "quoteStyle": "single", + "attributePosition": "auto" + } + }, + "overrides": [ + { + "include": ["**/*.{yml,yaml,md}"], + "formatter": { "indentStyle": "space", "indentWidth": 2 } + } + ] +} diff --git a/package.json b/package.json index 4b7c2ab..02117ad 100644 --- a/package.json +++ b/package.json @@ -10,15 +10,15 @@ "webext-permission-toggle": "5.1.0" }, "devDependencies": { + "@biomejs/biome": "1.8.3", "@humanfs/node": "0.16.3", "@humanfs/types": "0.13.0", "jiti": "1.21.6", - "prettier": "3.3.1", "svgo": "3.2.0", "wxt": "0.18.11" }, "scripts": { - "format": "prettier --write .", + "check": "biome check", "dev": "wxt", "dev:firefox": "wxt --browser firefox", "build": "wxt build", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d63d8e..c8e0d7d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,6 +21,9 @@ importers: specifier: 5.1.0 version: 5.1.0 devDependencies: + '@biomejs/biome': + specifier: 1.8.3 + version: 1.8.3 '@humanfs/node': specifier: 0.16.3 version: 0.16.3 @@ -30,9 +33,6 @@ importers: jiti: specifier: 1.21.6 version: 1.21.6 - prettier: - specifier: 3.3.1 - version: 3.3.1 svgo: specifier: 3.2.0 version: 3.2.0 @@ -81,6 +81,59 @@ packages: resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==} engines: {node: '>=6.9.0'} + '@biomejs/biome@1.8.3': + resolution: {integrity: sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@1.8.3': + resolution: {integrity: sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@1.8.3': + resolution: {integrity: sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@1.8.3': + resolution: {integrity: sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@1.8.3': + resolution: {integrity: sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@1.8.3': + resolution: {integrity: sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@1.8.3': + resolution: {integrity: sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@1.8.3': + resolution: {integrity: sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@1.8.3': + resolution: {integrity: sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + '@catppuccin/palette@1.2.0': resolution: {integrity: sha512-R5fxLcU47mRcsdQkXZBNfxt7SdEqLGWb1qhEKBrnYfEB4ZWOQRBEow4e78PKxaFUECBNOs6uEkwvwxFL9FmQqQ==} @@ -1680,11 +1733,6 @@ packages: resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} engines: {node: ^10 || ^12 || >=14} - prettier@3.3.1: - resolution: {integrity: sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==} - engines: {node: '>=14'} - hasBin: true - process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -2282,6 +2330,41 @@ snapshots: '@babel/helper-validator-identifier': 7.24.6 to-fast-properties: 2.0.0 + '@biomejs/biome@1.8.3': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 1.8.3 + '@biomejs/cli-darwin-x64': 1.8.3 + '@biomejs/cli-linux-arm64': 1.8.3 + '@biomejs/cli-linux-arm64-musl': 1.8.3 + '@biomejs/cli-linux-x64': 1.8.3 + '@biomejs/cli-linux-x64-musl': 1.8.3 + '@biomejs/cli-win32-arm64': 1.8.3 + '@biomejs/cli-win32-x64': 1.8.3 + + '@biomejs/cli-darwin-arm64@1.8.3': + optional: true + + '@biomejs/cli-darwin-x64@1.8.3': + optional: true + + '@biomejs/cli-linux-arm64-musl@1.8.3': + optional: true + + '@biomejs/cli-linux-arm64@1.8.3': + optional: true + + '@biomejs/cli-linux-x64-musl@1.8.3': + optional: true + + '@biomejs/cli-linux-x64@1.8.3': + optional: true + + '@biomejs/cli-win32-arm64@1.8.3': + optional: true + + '@biomejs/cli-win32-x64@1.8.3': + optional: true + '@catppuccin/palette@1.2.0': {} '@devicefarmer/adbkit-logcat@2.1.3': {} @@ -3747,8 +3830,6 @@ snapshots: picocolors: 1.0.1 source-map-js: 1.2.0 - prettier@3.3.1: {} - process-nextick-args@2.0.1: {} promise-toolbox@0.21.0: diff --git a/renovate.json b/renovate.json index 1241db4..d10197c 100644 --- a/renovate.json +++ b/renovate.json @@ -1,8 +1,5 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended", - ":semanticCommitTypeAll(chore)" - ], + "extends": ["config:recommended", ":semanticCommitTypeAll(chore)"], "rangeStrategy": "bump" } diff --git a/src/entries/content/index.ts b/src/entries/content/index.ts index 269e9bf..e50d564 100644 --- a/src/entries/content/index.ts +++ b/src/entries/content/index.ts @@ -4,7 +4,7 @@ import { observe } from 'selector-observer'; import { SELECTORS } from '@/constants'; import { flavor } from '@/storage'; -import { replaceIconInRow, injectStyles } from './lib'; +import { injectStyles, replaceIconInRow } from './lib'; export default defineContentScript({ // Make sure this value is updated in wxt.config.ts as well. diff --git a/src/entries/content/lib.ts b/src/entries/content/lib.ts index 8a7efe4..c450877 100644 --- a/src/entries/content/lib.ts +++ b/src/entries/content/lib.ts @@ -1,8 +1,8 @@ import type { IconName } from '@/types'; +import { getAssociations } from '@/associations'; import { ATTRIBUTE_PREFIX, SELECTORS } from '@/constants'; import { flavor, monochrome, specificFolders } from '@/storage'; -import { getAssociations } from '@/associations'; import { createStylesElement } from '@/utils'; import { flavors } from '@catppuccin/palette'; @@ -36,7 +36,7 @@ async function createIconElement( fileName: string, originalIcon: HTMLElement, ): Promise { - let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); if (await monochrome.getValue()) { svg.innerHTML = icons[iconName].replaceAll( /var\(--ctp-\w+\)/g, @@ -88,7 +88,7 @@ export async function replaceIcon(icon: HTMLElement, row: HTMLElement) { const isOpen = isDir && icon.classList.contains('octicon-file-directory-open-fill'); - const fileExtensions: string[] = []; + const fileExtensions: Array = []; // Avoid doing an explosive combination of extensions for very long filenames // (most file systems do not allow files > 255 length) with lots of `.` characters // https://github.com/microsoft/vscode/issues/116199 @@ -108,7 +108,7 @@ export async function replaceIcon(icon: HTMLElement, row: HTMLElement) { await replaceElementWithIcon( icon, - isOpen ? ((iconName + '_open') as IconName) : iconName, + isOpen ? (`${iconName}_open` as IconName) : iconName, fileName, ); } @@ -139,10 +139,10 @@ export async function replaceElementWithIcon( if ( icon.parentElement.classList.contains('PRIVATE_TreeView-directory-icon') ) { - let companion = await createIconElement( + const companion = await createIconElement( (iconName.includes('_open') ? iconName.replace('_open', '') - : iconName + '_open') as IconName, + : `${iconName}_open`) as IconName, fileName, icon, ); @@ -153,7 +153,7 @@ export async function replaceElementWithIcon( async function findIconMatch( fileName: string, - fileExtensions: string[], + fileExtensions: Array, isDir: boolean, isSubmodule: boolean, ): Promise { @@ -174,19 +174,18 @@ async function findIconMatch( } return '_folder'; - } else { - if (fileName in associations.fileNames) - return associations.fileNames[fileName]; - if (fileName.toLowerCase() in associations.fileNames) - return associations.fileNames[fileName.toLowerCase()]; - - for (const ext of fileExtensions) { - if (ext in associations.fileExtensions) - return associations.fileExtensions[ext]; - if (ext in associations.languageIds) - return associations.languageIds[ext]; - } - - return '_file'; } + + if (fileName in associations.fileNames) + return associations.fileNames[fileName]; + if (fileName.toLowerCase() in associations.fileNames) + return associations.fileNames[fileName.toLowerCase()]; + + for (const ext of fileExtensions) { + if (ext in associations.fileExtensions) + return associations.fileExtensions[ext]; + if (ext in associations.languageIds) return associations.languageIds[ext]; + } + + return '_file'; } diff --git a/src/entries/popup/main.ts b/src/entries/popup/main.ts index ce69bd3..c9c4239 100644 --- a/src/entries/popup/main.ts +++ b/src/entries/popup/main.ts @@ -2,13 +2,13 @@ import './styles.css'; import type { Associations, Flavor, IconName } from '@/types'; +import { icons } from '@/constants'; import { + customAssociations, flavor, monochrome, specificFolders, - customAssociations, } from '@/storage'; -import { icons } from '@/constants'; import { createStylesElement } from '@/utils'; import { flavorEntries } from '@catppuccin/palette'; @@ -55,15 +55,12 @@ async function init() { const associations = await customAssociations.getValue(); for (const [key, el] of Object.entries({ - fileExtensions: document.querySelector( - 'ul#associations-file-extensions', - ), + fileExtensions: document.querySelector('ul#associations-file-extensions'), fileNames: document.querySelector('ul#associations-file-names'), folderNames: document.querySelector('ul#associations-folder-names'), - } as Record) as [ - keyof Associations, - HTMLUListElement, - ][]) { + } as Record) as Array< + [keyof Associations, HTMLUListElement] + >) { for (const [association, icon] of Object.entries(associations[key])) { const li = document.createElement('li'); const inputA = document.createElement('input'); @@ -71,7 +68,7 @@ async function init() { const del = document.createElement('button'); del.className = 'delete'; - del.innerHTML = icons['x']; + del.innerHTML = icons.x; inputA.value = association; inputA.setAttribute('required', 'true'); @@ -113,7 +110,7 @@ async function init() { const del = document.createElement('button'); del.className = 'delete'; - del.innerHTML = icons['x']; + del.innerHTML = icons.x; inputA.setAttribute('required', 'true'); inputB.setAttribute('required', 'true'); @@ -139,11 +136,7 @@ async function init() { associations[key][inputA.value] = inputB.value as IconName; await customAssociations.setValue(associations); } - if ( - !addedEmpty && - inputA.checkValidity() && - inputB.checkValidity() - ) { + if (!addedEmpty && inputA.checkValidity() && inputB.checkValidity()) { addEmpty(); addedEmpty = true; } @@ -153,11 +146,7 @@ async function init() { associations[key][inputA.value] = inputB.value as IconName; await customAssociations.setValue(associations); } - if ( - !addedEmpty && - inputA.checkValidity() && - inputB.checkValidity() - ) { + if (!addedEmpty && inputA.checkValidity() && inputB.checkValidity()) { addEmpty(); addedEmpty = true; } diff --git a/src/types.ts b/src/types.ts index fc94da2..f3f455b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import icons from '@/icons.json'; +import type icons from '@/icons.json'; export type Flavor = 'latte' | 'frappe' | 'macchiato' | 'mocha'; diff --git a/wxt.config.ts b/wxt.config.ts index b8111e4..81eba8f 100644 --- a/wxt.config.ts +++ b/wxt.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'wxt'; +import { join } from 'node:path'; import { hfs } from '@humanfs/node'; -import { join } from 'path'; import { optimize } from 'svgo'; import jiti from 'jiti'; @@ -19,36 +19,25 @@ export default defineConfig({ // Make sure to update in src/entries/content/index.ts as well. content_scripts: [ { - matches: [ - '*://codeberg.org/*', - '*://github.com/*', - '*://gitlab.com/*', - ], + matches: ['*://codeberg.org/*', '*://github.com/*', '*://gitlab.com/*'], run_at: 'document_start', js: ['content-scripts/content.js'], }, ], - homepage_url: - 'https://github.com/catppuccin/github-file-explorer-icons', + homepage_url: 'https://github.com/catppuccin/github-file-explorer-icons', }, hooks: { 'build:before': async () => { - const ICON_DIR = join( - __dirname, - './vscode-icons/icons/css-variables/', - ); + const ICON_DIR = join(__dirname, './vscode-icons/icons/css-variables/'); const icons = {}; for await (const entry of hfs.list(ICON_DIR)) { icons[entry.name.replace('.svg', '')] = await hfs .text(join(ICON_DIR, entry.name)) .then((text) => { - return optimize( - text.replaceAll('--vscode-ctp', '--ctp'), - { - js2svg: { useShortTags: false }, - }, - ) + return optimize(text.replaceAll('--vscode-ctp', '--ctp'), { + js2svg: { useShortTags: false }, + }) .data.replace( '', '', @@ -65,8 +54,8 @@ export default defineConfig({ await hfs.write( join(__dirname, './src/associations.json'), JSON.stringify( - jiti(__dirname)('./vscode-icons/src/defaults/index.ts') - .defaultConfig.associations, + jiti(__dirname)('./vscode-icons/src/defaults/index.ts').defaultConfig + .associations, ), ); },