diff --git a/eslint.config.js b/eslint.config.js index acc9172..52c3cfe 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,13 +1,14 @@ -import { includeIgnoreFile } from '@eslint/compat' +import {includeIgnoreFile} from '@eslint/compat' import js from '@eslint/js' import json from '@eslint/json' import restrictedGlobals from 'confusing-browser-globals' -import tsdoc from 'eslint-plugin-tsdoc' +import prettier from 'eslint-plugin-prettier/recommended' import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' +import tsdoc from 'eslint-plugin-tsdoc' import globals from 'globals' -import tseslint from 'typescript-eslint' import path from 'node:path' +import tseslint from 'typescript-eslint' const gitignore = path.resolve(import.meta.dirname, '.gitignore') @@ -18,8 +19,6 @@ export default tseslint.config( { name: 'javascript basics', files: ['**/*.@(js|jsx|ts|tsx)'], - - plugins: {tsdoc}, extends: [js.configs.recommended], languageOptions: { @@ -32,9 +31,7 @@ export default tseslint.config( rules: { // eg, `open` is a global, but probably not really intended that way in our code 'no-restricted-globals': ['error', ...restrictedGlobals], - 'no-unused-vars': ['warn', { varsIgnorePattern: '(?:^_)' }], - - 'tsdoc/syntax': 'warn' + 'no-unused-vars': ['warn', {varsIgnorePattern: '(?:^_)'}], }, }, @@ -42,6 +39,7 @@ export default tseslint.config( name: 'typescript basics', files: ['**/*.@(ts|tsx)'], extends: [tseslint.configs.strictTypeChecked], + plugins: {tsdoc}, languageOptions: { parserOptions: { projectService: true, @@ -49,18 +47,16 @@ export default tseslint.config( }, }, rules: { - '@typescript-eslint/no-unused-vars': ['warn', { varsIgnorePattern: '(?:^_)' }], + '@typescript-eslint/no-unused-vars': ['warn', {varsIgnorePattern: '(?:^_)'}], '@typescript-eslint/no-unnecessary-condition': 'off', '@typescript-eslint/restrict-template-expressions': 'off', - } + 'tsdoc/syntax': 'warn', + }, }, { name: 'node files', - files: [ - 'src/server/**/*.@(js|jsx|ts|tsx)', - 'src/cmd/**/*.@(js|jsx|ts|tsx)' - ], + files: ['src/server/**/*.@(js|jsx|ts|tsx)', 'src/cmd/**/*.@(js|jsx|ts|tsx)'], languageOptions: { globals: { ...globals.es2024, @@ -73,9 +69,7 @@ export default tseslint.config( // mostly cribbed from preact's config, but that's not setup to handle eslint9 // https://github.com/preactjs/eslint-config-preact/blob/master/index.js name: 'client files', - files: [ - 'src/client/**/*.@(js|jsx|ts|tsx)', - ], + files: ['src/client/**/*.@(js|jsx|ts|tsx)'], languageOptions: { globals: { ...globals.es2024, @@ -96,7 +90,7 @@ export default tseslint.config( // preact / jsx rules 'react/no-deprecated': 2, 'react/react-in-jsx-scope': 0, // handled this automatically - 'react/display-name': [1, { ignoreTranspilerName: false }], + 'react/display-name': [1, {ignoreTranspilerName: false}], 'react/jsx-no-bind': [ 1, { @@ -109,10 +103,10 @@ export default tseslint.config( 'react/jsx-no-duplicate-props': 2, 'react/jsx-no-target-blank': 2, 'react/jsx-no-undef': 2, - 'react/jsx-tag-spacing': [2, { beforeSelfClosing: 'always' }], + 'react/jsx-tag-spacing': [2, {beforeSelfClosing: 'always'}], 'react/jsx-uses-react': 1, // debatable 'react/jsx-uses-vars': 2, - 'react/jsx-key': [2, { checkFragmentShorthand: true }], + 'react/jsx-key': [2, {checkFragmentShorthand: true}], 'react/self-closing-comp': 2, 'react/prefer-es6-class': 2, 'react/prefer-stateless-function': 1, @@ -143,14 +137,15 @@ export default tseslint.config( files: ['**/*.json'], ignores: ['package-lock.json'], - plugins: { json }, + plugins: {json}, language: 'json/json', - extends: [ - json.configs.recommended - ], + extends: [json.configs.recommended], }, { files: ['tsconfig.json'], language: 'json/jsonc', }, + + // prettier last, so it can turn everything off + prettier, ) diff --git a/jest.config.js b/jest.config.js index 1ede094..69eb9d9 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,6 @@ import globToRegexp from 'glob-to-regexp' import path from 'node:path' -import { fileURLToPath } from 'node:url' +import {fileURLToPath} from 'node:url' import gitignore from 'parse-gitignore' import * as tsjest from 'ts-jest' @@ -9,16 +9,13 @@ function gitignorePatterns() { const __dirname = path.dirname(__filename) const ignorefile = path.resolve(__dirname, '.gitignore') - const { patterns } = gitignore(ignorefile) - return patterns - .map(p => globToRegexp(p, { globstar: true }).source) + const {patterns} = gitignore(ignorefile) + return patterns.map((p) => globToRegexp(p, {globstar: true}).source) } export default { testMatch: ['/src/**/*.spec.{ts,tsx}'], - testPathIgnorePatterns: [ - ...gitignorePatterns(), - ], + testPathIgnorePatterns: [...gitignorePatterns()], cache: true, cacheDirectory: path.join(import.meta.dirname, '.jestcache'), @@ -33,18 +30,10 @@ export default { // use ts-jest preset for esm support // but we have to tell it to look at jsx files too, not just tsx - ...( - tsjest.createJsWithTsEsmPreset() - ), + ...tsjest.createJsWithTsEsmPreset(), // if node_modules are ESM, we need to _include_ them from - transformIgnorePatterns: [ - 'node_modules/(?!(nanoid|jose|preact|@preact)/)', - ], - - collectCoverageFrom: [ - 'src/**/*.{ts,tsx}', - '!src/**/*.spec.{ts,tsx}', - '!src/**/node_modules/**', - ], + transformIgnorePatterns: ['node_modules/(?!(nanoid|jose|preact|@preact)/)'], + + collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/*.spec.{ts,tsx}', '!src/**/node_modules/**'], } diff --git a/jest.setup.js b/jest.setup.js index 9eaba5c..992659a 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -1,4 +1,4 @@ -import { expect } from '@jest/globals' +import {expect} from '@jest/globals' // jest-dom matchers for better DOM assertions import '@testing-library/jest-dom' diff --git a/jsdoc.json b/jsdoc.json index 4eee847..0891ceb 100644 --- a/jsdoc.json +++ b/jsdoc.json @@ -4,9 +4,7 @@ "dictionaries": ["jsdoc"] }, "source": { - "include": [ - "src" - ], + "include": ["src"], "includePattern": ".+\\.js(doc)?$", "excludePattern": "(^|\\/|\\\\)_" }, @@ -16,9 +14,7 @@ "destination": "./docs/", "recurse": true }, - "plugins": [ - "plugins/markdown" - ], + "plugins": ["plugins/markdown"], "templates": { "referenceTitle": "skypod", "cleverLinks": true, diff --git a/package-lock.json b/package-lock.json index 9c6f82f..3f72ee5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,8 @@ "@types/ws": "^8.18.1", "confusing-browser-globals": "^1.0.11", "eslint": "^9.28.0", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.5.0", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-tsdoc": "^0.4.0", @@ -48,6 +50,8 @@ "jest-fixed-jsdom": "^0.0.9", "jsdom": "^26.1.0", "parse-gitignore": "^2.0.0", + "prettier": "^3.5.3", + "prettier-plugin-organize-imports": "^4.1.0", "tidy-jsdoc-fork": "github:lygaret/tidy-jsdoc", "ts-jest": "^29.4.0", "typescript": "^5.8.3", @@ -7082,6 +7086,53 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", + "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.0.tgz", + "integrity": "sha512-8qsOYwkkGrahrgoUv76NZi23koqXOGiiEzXMrT8Q7VcYaUISR+5MorIUxfWqYXN0fN/31WbSrxCxFkVQ43wwrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react": { "version": "7.37.5", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", @@ -7460,6 +7511,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", @@ -12687,6 +12745,52 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/prettier-plugin-organize-imports": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", + "integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "prettier": ">=2.0", + "typescript": ">=2.9", + "vue-tsc": "^2.1.0" + }, + "peerDependenciesMeta": { + "vue-tsc": { + "optional": true + } + } + }, "node_modules/pretty-format": { "version": "30.0.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.0.tgz", diff --git a/package.json b/package.json index 23bb12c..404cd3f 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,8 @@ "@types/ws": "^8.18.1", "confusing-browser-globals": "^1.0.11", "eslint": "^9.28.0", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.5.0", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-tsdoc": "^0.4.0", @@ -60,6 +62,8 @@ "jest-fixed-jsdom": "^0.0.9", "jsdom": "^26.1.0", "parse-gitignore": "^2.0.0", + "prettier": "^3.5.3", + "prettier-plugin-organize-imports": "^4.1.0", "tidy-jsdoc-fork": "github:lygaret/tidy-jsdoc", "ts-jest": "^29.4.0", "typescript": "^5.8.3", diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..c670295 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,14 @@ +/** + * @see https://prettier.io/docs/configuration + * @type {import("prettier").Config} + */ +export default { + printWidth: 100, + tabWidth: 2, + semi: false, + singleQuote: true, + trailingComma: 'all', + bracketSpacing: false, + + plugins: ['prettier-plugin-organize-imports'], +} diff --git a/src/client/components/messenger.tsx b/src/client/components/messenger.tsx index 6905881..671288d 100644 --- a/src/client/components/messenger.tsx +++ b/src/client/components/messenger.tsx @@ -1,38 +1,39 @@ -import { RealmConnection } from '#client/realm/connection.js' -import { IdentID } from '#common/protocol' -import { useState, useEffect, useCallback } from 'preact/hooks' +import {RealmConnection} from '#client/realm/connection.js' +import {IdentID} from '#common/protocol' +import {useCallback, useEffect, useState} from 'preact/hooks' export type MessengerProps = { realmConnection: RealmConnection } -export const Messenger: preact.FunctionComponent<{ webrtcManager: RealmConnection }> = (props) => { - const { webrtcManager } = props +export const Messenger: preact.FunctionComponent<{webrtcManager: RealmConnection}> = (props) => { + const {webrtcManager} = props const [messages, setMessages] = useState<[IdentID, string][]>([]) - const peerdata = useCallback((event: CustomEvent<{ remoteId: IdentID, data: unknown }>) => { - setMessages([...messages, [event.detail.remoteId, `${event.detail.data}`]]) - }, [messages]) + const peerdata = useCallback( + (event: CustomEvent<{remoteId: IdentID; data: unknown}>) => { + setMessages([...messages, [event.detail.remoteId, `${event.detail.data}`]]) + }, + [messages], + ) const sendMessage = useCallback(() => { - webrtcManager.broadcast('what\'s up friends?') + webrtcManager.broadcast("what's up friends?") }, [webrtcManager]) useEffect(() => { if (!webrtcManager) return - webrtcManager.addEventListener('peerdata', peerdata as ((event: Event) => void)) + webrtcManager.addEventListener('peerdata', peerdata as (event: Event) => void) return () => { - webrtcManager.removeEventListener('peerdata', peerdata as ((event: Event) => void)) + webrtcManager.removeEventListener('peerdata', peerdata as (event: Event) => void) } }, [webrtcManager, peerdata]) return (

Realm Messages

-
-        { JSON.stringify(messages, null, 2) }
-      
+
{JSON.stringify(messages, null, 2)}