From a8c7ac06bbad3c5cb1c11940c385ea1d58dcc90f Mon Sep 17 00:00:00 2001 From: benmelz Date: Tue, 12 May 2026 10:31:09 -0400 Subject: [PATCH 1/6] add/configure oxlint --- eslint.config.js | 9 - oxlint.config.ts | 24 +++ package-lock.json | 444 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 5 +- 4 files changed, 447 insertions(+), 35 deletions(-) delete mode 100644 eslint.config.js create mode 100644 oxlint.config.ts diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index 19e4c14..0000000 --- a/eslint.config.js +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig, globalIgnores } from 'eslint/config' -import reactHooks from 'eslint-plugin-react-hooks' -import neostandard from 'neostandard' - -export default defineConfig([ - globalIgnores(['dist', 'coverage']), - ...neostandard({ env: ['browser'] }), - { extends: [reactHooks.configs['recommended-latest']] }, -]) diff --git a/oxlint.config.ts b/oxlint.config.ts new file mode 100644 index 0000000..3578fdc --- /dev/null +++ b/oxlint.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "oxlint" + +export default defineConfig( +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": [ + "eslint", + "unicorn", + "react", + "react-perf", + "oxc", + "import", + "promise", + "vitest" + ], + "categories": { + "correctness": "error", + "suspicious": "error", + "pedantic": "warn", + "perf": "error", + "restriction": "error" + } +} +); diff --git a/package-lock.json b/package-lock.json index 1bde7d8..0a3a43f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,10 +21,9 @@ "@testing-library/react": "*", "@vitest/coverage-v8": "*", "conventional-changelog-conventionalcommits": "*", - "eslint": "*", - "eslint-plugin-react-hooks": "5.2.0", "jsdom": "*", "neostandard": "*", + "oxlint": "*", "react-dom": "*", "semantic-release": "*", "vite": "*", @@ -448,6 +447,7 @@ "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", @@ -463,6 +463,7 @@ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@eslint/core": "^0.17.0" }, @@ -476,6 +477,7 @@ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -489,6 +491,7 @@ "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", @@ -513,6 +516,7 @@ "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -526,6 +530,7 @@ "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -536,6 +541,7 @@ "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" @@ -568,6 +574,7 @@ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=18.18.0" } @@ -578,6 +585,7 @@ "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" @@ -603,6 +611,7 @@ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=12.22" }, @@ -617,6 +626,7 @@ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=18.18" }, @@ -851,6 +861,329 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.64.0.tgz", + "integrity": "sha512-2r6Nq3XXGLHEXKkSj8JtmJ6N4gDw431DPFOg0ZoJHlNjnG6HVMm/ksQ10m0HJ8WBvwgMe1L50UHPaYZutCRPCw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.64.0.tgz", + "integrity": "sha512-ePJMpePgg7fBv+L/hVx1xXRU5/5gd5m0obLA6hPEfLXF3GjpR8idIDbY1dhQYhyz1ms2wdTccSboo6KEd2Oxtg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.64.0.tgz", + "integrity": "sha512-U4DMLQd10gJLuoSTLSGbfv3bGjTlUNsScm9Dgb8wwBqmCzidf1pE1pXV4doGNxqwH3KtVng1AGTINA0NvkGLvQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.64.0.tgz", + "integrity": "sha512-GoRIL48QWm4/TAvjN8pB1nAG+1/uqc9EdnWT9zqHeb6wsmjZtywj8VRe5aGW47Fdb64YtLOsdLqVxOvQuz98Wg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.64.0.tgz", + "integrity": "sha512-5dFkv4tkg7PxJJGS9/OjrJwjhuHczrd3OQOkRE0wHcLM+ncUnULtzEPWjqGOxTXxZnLWcB91bGiIznx89TVXyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.64.0.tgz", + "integrity": "sha512-jsBqMLl/uOL5+Kq/+BtK9FrmiNGUbx8SiyZXv+WlUxA45KuwcLu9BfiSIL3I3DBDgWM3yZizDITnTK9BcqNBQg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.64.0.tgz", + "integrity": "sha512-1lrj8At/Uuc9GhjrVFBQo0NEjfBrTkzpmtHIGAhNnIXqn1CAyGL+qrztUsXb2GIluJrpl9Q7qRLJOb/NqydacQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.64.0.tgz", + "integrity": "sha512-HpSQbubwh03mMhAdy2BYtad/fsY8vDFHDAb6bUwuCYg2VD3xCQgn6ArKcO0oZyLCheacKTv4PrF3Mfu5hgoE2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.64.0.tgz", + "integrity": "sha512-00QQ0h0Y7u0G69BgiH3+ky2aaq/QvkDL6DYok8htIuJHxybiux5aQ8jwmg8qIk9wha6UagUP2BAwAzbemcJbpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.64.0.tgz", + "integrity": "sha512-2GaimTV6EMW+s5HS0An3oGbQme3BgHswvfVdGk3EB57Xe9+/gyT+Qd7lNVzb3rtir52vbIPzXfaYArzs5b5zcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.64.0.tgz", + "integrity": "sha512-H46AtFb9wypjoVwGdlxrm0DsD809NGmtiK9HiyPKTxkSte2YjhC4S+00rOIrwCaxcyPiGid3Y3OMXp5KMAkGZw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.64.0.tgz", + "integrity": "sha512-HEgsidjjvvyzdg82icYkuFCf7REDV7B9JFwbIMbVwrKLBY0MrXX+bku3POn/hduZ2yW91IyVDUMq0Bf02KwXQw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.64.0.tgz", + "integrity": "sha512-Axvm8qryotmKN00P5w4JapaSjvP2LOSbdbBJiX+2SuHd3QzhW7TUc8skqgw+ahQZ5DmzEYeHCqauvW8f32Ns6Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.64.0.tgz", + "integrity": "sha512-cR60vSd7+m+KRZ3GQGfDxWwahW5RMXg0qlGvAluZr0fTUYvw0H9N9AXAF/M/PMqgytyqvVNmBAkJG9l7U30Y1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.64.0.tgz", + "integrity": "sha512-2u/aPZ9pEg7HnvZPDsHxUGNnrpr4qaHi+mCgLgpt+LYRzPrS4Px4wPfkIdRdr2GvKnaYyt+XSlto0Vm5sbStTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.64.0.tgz", + "integrity": "sha512-kfhkGfCdoXLSxEkrhDlJrvBYajGmq+ma4EMc53dsOWTq+rIBOlI0vTBmpZNnM5oH2LY/K/w1HAK+UQEgjgpVUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.64.0.tgz", + "integrity": "sha512-r/cNKBFieONoVu2bb1KkVouq9W+edDUgHumXJGphCRRj+U0xaD4nanrw8ZOqo0IsutPkEM4vCcGBpak6x5aXMg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.64.0.tgz", + "integrity": "sha512-tUw0xUUwEFVZbpJoeCblkv8SJA4Xz3CdXCJbAnBsiNLyxDrk2tLcxEAS6M73Q7hHHDg3OtwI8vZVK3t5RJt4Gw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.64.0.tgz", + "integrity": "sha512-9CBR+LO0JVST87fNTzzNxS5I29jIUO5gxT9i9+M3SDHHALElj9sY1Prf12tad3vIRC6OD7Ehtvvh+sn13vSwHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@pnpm/config.env-replace": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", @@ -1966,7 +2299,8 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/linkify-it": { "version": "5.0.0", @@ -2483,6 +2817,7 @@ "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4044,6 +4379,7 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -4138,6 +4474,7 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4322,19 +4659,6 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, "node_modules/eslint-plugin-react/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -4351,6 +4675,7 @@ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -4412,6 +4737,7 @@ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -4425,6 +4751,7 @@ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -4516,14 +4843,16 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -4553,6 +4882,7 @@ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "flat-cache": "^4.0.0" }, @@ -4579,6 +4909,7 @@ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -4626,6 +4957,7 @@ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" @@ -4639,7 +4971,8 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/for-each": { "version": "0.3.5", @@ -4915,6 +5248,7 @@ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -4949,6 +5283,7 @@ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -5281,6 +5616,7 @@ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.8.19" } @@ -5512,6 +5848,7 @@ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5568,6 +5905,7 @@ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -6049,7 +6387,8 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json-parse-better-errors": { "version": "1.0.2", @@ -6070,14 +6409,16 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json-with-bigint": { "version": "3.5.8", @@ -6133,6 +6474,7 @@ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "json-buffer": "3.0.1" } @@ -6152,6 +6494,7 @@ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -6482,6 +6825,7 @@ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -6538,7 +6882,8 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.uniqby": { "version": "4.7.0", @@ -9214,6 +9559,7 @@ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -9244,6 +9590,51 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oxlint": { + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.64.0.tgz", + "integrity": "sha512-Star3SNpWPeWFPw7kRXIhXUSn6fdiAl25q15CQzH/9WaOtG6e9CWTc25vNZOCr4PE1yEP1GtKJKIKglhj3OmEQ==", + "dev": true, + "license": "MIT", + "bin": { + "oxlint": "bin/oxlint" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.64.0", + "@oxlint/binding-android-arm64": "1.64.0", + "@oxlint/binding-darwin-arm64": "1.64.0", + "@oxlint/binding-darwin-x64": "1.64.0", + "@oxlint/binding-freebsd-x64": "1.64.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.64.0", + "@oxlint/binding-linux-arm-musleabihf": "1.64.0", + "@oxlint/binding-linux-arm64-gnu": "1.64.0", + "@oxlint/binding-linux-arm64-musl": "1.64.0", + "@oxlint/binding-linux-ppc64-gnu": "1.64.0", + "@oxlint/binding-linux-riscv64-gnu": "1.64.0", + "@oxlint/binding-linux-riscv64-musl": "1.64.0", + "@oxlint/binding-linux-s390x-gnu": "1.64.0", + "@oxlint/binding-linux-x64-gnu": "1.64.0", + "@oxlint/binding-linux-x64-musl": "1.64.0", + "@oxlint/binding-openharmony-arm64": "1.64.0", + "@oxlint/binding-win32-arm64-msvc": "1.64.0", + "@oxlint/binding-win32-ia32-msvc": "1.64.0", + "@oxlint/binding-win32-x64-msvc": "1.64.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=0.22.1" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + } + } + }, "node_modules/p-each-series": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", @@ -9305,6 +9696,7 @@ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -9321,6 +9713,7 @@ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -9482,6 +9875,7 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -9683,6 +10077,7 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8.0" } @@ -11536,6 +11931,7 @@ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -11797,6 +12193,7 @@ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "punycode": "^2.1.0" } @@ -12444,6 +12841,7 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index d429a03..b3b5c08 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ }, "scripts": { "build": "vite build", - "lint": "eslint", + "lint": "oxlint", "release": "semantic-release", "test": "vitest run" }, @@ -33,10 +33,9 @@ "@testing-library/react": "*", "@vitest/coverage-v8": "*", "conventional-changelog-conventionalcommits": "*", - "eslint": "*", - "eslint-plugin-react-hooks": "5.2.0", "jsdom": "*", "neostandard": "*", + "oxlint": "*", "react-dom": "*", "semantic-release": "*", "vite": "*", From 8a813cc22a716c998e9bb334678ea85127ad7b87 Mon Sep 17 00:00:00 2001 From: benmelz Date: Tue, 12 May 2026 10:34:52 -0400 Subject: [PATCH 2/6] add/configure oxfmt --- README.md | 26 +-- lib/index.js | 8 +- lib/useFetchResolver.js | 14 +- lib/useGtfsRealtime.js | 16 +- lib/useGtfsSchedule.js | 47 +++-- lib/useRefresh.js | 28 +-- oxfmt.config.ts | 6 + oxlint.config.ts | 35 ++-- package-lock.json | 382 ++++++++++++++++++++++++++++++++++ package.json | 7 +- release.config.js | 28 +-- test/index.test.js | 26 +-- test/setup.js | 16 +- test/useFetchResolver.test.js | 64 +++--- test/useGtfsRealtime.test.js | 90 ++++---- test/useGtfsSchedule.test.js | 84 ++++---- test/useRefresh.test.js | 72 +++---- vite.config.js | 26 +-- 18 files changed, 679 insertions(+), 296 deletions(-) create mode 100644 oxfmt.config.ts diff --git a/README.md b/README.md index 60c7220..1eed046 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,14 @@ Note that due to dependency constraints, this library must be processed by a bun * * The data is unzipped and its entries are parsed as CSV files internally. File names and properties are converted * from snake_case to camelCase (see the standard for structure). - * + * * Individual files are parsed asynchronously, and may be updated/made available at different times. Be careful to guard * against this when accessing your data. * * @example * * const scheduleData = useGtfsSchedule(yourResolver, 10000) - * + * * scheduleData?.routes.each(...) // improper * scheduleData?.routes?.each(...) // proper * @@ -47,7 +47,7 @@ Note that due to dependency constraints, this library must be processed by a bun * @param {Number} [retry=1000] - the time in ms to retry a refresh if the previous one failed. * @return {{}|undefined} parsed data if resolved, undefined if not. */ -export function useGtfsSchedule (resolve, timeout) { } +export function useGtfsSchedule(resolve, timeout) {} /** * A hook that resolves, parses and periodically refreshes GTFS Realtime data. @@ -60,7 +60,7 @@ export function useGtfsSchedule (resolve, timeout) { } * @param {Number} [retry=1000] - the time in ms to retry a refresh if the previous one failed. * @return {FeedMessage|undefined} parsed data if resolved, undefined if not. */ -export function useGtfsRealtime (resolve, timeout) { } +export function useGtfsRealtime(resolve, timeout) {} /** * A convenience hook that creates a simple GTFS data resolver using the fetch API. @@ -69,31 +69,31 @@ export function useGtfsRealtime (resolve, timeout) { } * return the raw response body as a Uint8Array. * * If any errors occur or if the response status is not OK, it will return undefined. - * + * * If you need to use a different API for retrieving your data, use more advanced fetch options or add side effects * when errors occur, it is reccommended that you write your own resolver. * * @param {string} url - the url to send requests to. * @return {Resolver} a simple fetch resolver. */ -export function useFetchResolver (url) { } +export function useFetchResolver(url) {} ``` ### Examples ```javascript -import { useFetchResolver, useGtfsRealtime, useGtfsSchedule } from 'gtfs-react-hooks' -import { useCallback } from 'react' +import { useFetchResolver, useGtfsRealtime, useGtfsSchedule } from "gtfs-react-hooks"; +import { useCallback } from "react"; export default function MyComponent() { // gtfs schedule data - const scheduleResolver = useFetchResolver('https://your-domain.com/gtfs_schedule.zip') - const gtfsSchedule = useGtfsSchedule(scheduleResolver, 1000 * 60 * 60 * 24) + const scheduleResolver = useFetchResolver("https://your-domain.com/gtfs_schedule.zip"); + const gtfsSchedule = useGtfsSchedule(scheduleResolver, 1000 * 60 * 60 * 24); // gtfs realtime data - const realtimeAlertsResolver = useFetchResolver('https://your-domain.com/gtfs-realtime-alerts') - const gtfsRealtimeAlerts = useGtfsRealtime(realtimeAlertsResolver, 1000 * 30) - + const realtimeAlertsResolver = useFetchResolver("https://your-domain.com/gtfs-realtime-alerts"); + const gtfsRealtimeAlerts = useGtfsRealtime(realtimeAlertsResolver, 1000 * 30); + // ... } ``` diff --git a/lib/index.js b/lib/index.js index 5218b0d..6e17fcf 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,5 @@ -import useFetchResolver from './useFetchResolver.js' -import useGtfsRealtime from './useGtfsRealtime.js' -import useGtfsSchedule from './useGtfsSchedule.js' +import useFetchResolver from "./useFetchResolver.js"; +import useGtfsRealtime from "./useGtfsRealtime.js"; +import useGtfsSchedule from "./useGtfsSchedule.js"; -export { useFetchResolver, useGtfsRealtime, useGtfsSchedule } +export { useFetchResolver, useGtfsRealtime, useGtfsSchedule }; diff --git a/lib/useFetchResolver.js b/lib/useFetchResolver.js index 954b43a..6a8dc17 100644 --- a/lib/useFetchResolver.js +++ b/lib/useFetchResolver.js @@ -1,16 +1,16 @@ -import { useCallback } from 'react' +import { useCallback } from "react"; -export default function useFetchResolver (url) { +export default function useFetchResolver(url) { return useCallback(async () => { try { - const response = await fetch(url) + const response = await fetch(url); if (response.status !== 200) { - return undefined + return undefined; } else { - return new Uint8Array(await response.arrayBuffer()) + return new Uint8Array(await response.arrayBuffer()); } } catch { - return undefined + return undefined; } - }, [url]) + }, [url]); } diff --git a/lib/useGtfsRealtime.js b/lib/useGtfsRealtime.js index 94dd0c1..95d1af5 100644 --- a/lib/useGtfsRealtime.js +++ b/lib/useGtfsRealtime.js @@ -1,14 +1,14 @@ -import GtfsRealtimeBindings from 'gtfs-realtime-bindings' -import { useMemo } from 'react' -import useRefresh from './useRefresh.js' +import GtfsRealtimeBindings from "gtfs-realtime-bindings"; +import { useMemo } from "react"; +import useRefresh from "./useRefresh.js"; -export default function useGtfsRealtime (resolve, timeout, retry = 1000) { - const realtimeUInt8Buffer = useRefresh(resolve, timeout, retry) +export default function useGtfsRealtime(resolve, timeout, retry = 1000) { + const realtimeUInt8Buffer = useRefresh(resolve, timeout, retry); return useMemo(() => { if (realtimeUInt8Buffer === undefined) { - return realtimeUInt8Buffer + return realtimeUInt8Buffer; } else { - return GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(realtimeUInt8Buffer) + return GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(realtimeUInt8Buffer); } - }, [realtimeUInt8Buffer]) + }, [realtimeUInt8Buffer]); } diff --git a/lib/useGtfsSchedule.js b/lib/useGtfsSchedule.js index 3a655dd..3dd78dc 100644 --- a/lib/useGtfsSchedule.js +++ b/lib/useGtfsSchedule.js @@ -1,41 +1,44 @@ -import { camelCase } from 'change-case' -import JSZip from 'jszip' -import Papa from 'papaparse' -import { useEffect, useRef, useState } from 'react' -import useRefresh from './useRefresh.js' +import { camelCase } from "change-case"; +import JSZip from "jszip"; +import Papa from "papaparse"; +import { useEffect, useRef, useState } from "react"; +import useRefresh from "./useRefresh.js"; -export default function useGtfsSchedule (resolve, timeout, retry = 1000) { - const rawScheduleData = useRefresh(resolve, timeout, retry) - const dataCache = useRef({}) - const [data, setData] = useState(undefined) +export default function useGtfsSchedule(resolve, timeout, retry = 1000) { + const rawScheduleData = useRefresh(resolve, timeout, retry); + const dataCache = useRef({}); + const [data, setData] = useState(undefined); useEffect(() => { if (rawScheduleData === undefined) { - setData(undefined) + setData(undefined); } else { JSZip.loadAsync(rawScheduleData).then((zip) => { for (const [filename, file] of Object.entries(zip.files)) { - file.async('text').then(parseCsv).then((json) => { - dataCache.current[camelCase(removeExtension(filename))] = json - setData({ ...dataCache.current }) - }) + file + .async("text") + .then(parseCsv) + .then((json) => { + dataCache.current[camelCase(removeExtension(filename))] = json; + setData({ ...dataCache.current }); + }); } - }) + }); } - }, [rawScheduleData]) - return data + }, [rawScheduleData]); + return data; } -async function parseCsv (csvString) { +async function parseCsv(csvString) { return new Promise((resolve, reject) => { Papa.parse(csvString, { header: true, transformHeader: camelCase, skipEmptyLines: true, complete: (result) => resolve(result.data), - }) - }) + }); + }); } -function removeExtension (filename) { - return filename.replace(/\.[^/.]+$/, '') +function removeExtension(filename) { + return filename.replace(/\.[^/.]+$/, ""); } diff --git a/lib/useRefresh.js b/lib/useRefresh.js index 8bd056e..7315d9a 100644 --- a/lib/useRefresh.js +++ b/lib/useRefresh.js @@ -1,27 +1,29 @@ -import { useCallback, useEffect, useState } from 'react' +import { useCallback, useEffect, useState } from "react"; -export default function useRefresh (resolve, timeout, retry) { - const [data, setData] = useState() - const refresh = useCallback(async () => { setData(await resolve()) }, [resolve]) +export default function useRefresh(resolve, timeout, retry) { + const [data, setData] = useState(); + const refresh = useCallback(async () => { + setData(await resolve()); + }, [resolve]); // resolve immediately on render useEffect(() => { - refresh() - }, [refresh]) + refresh(); + }, [refresh]); // resolve periodically according to retry if resolve failed previously useEffect(() => { if (data === undefined) { - const interval = setInterval(refresh, retry) - return () => clearInterval(interval) + const interval = setInterval(refresh, retry); + return () => clearInterval(interval); } - }, [data, refresh, retry]) + }, [data, refresh, retry]); // resolve periodically according to timeout useEffect(() => { - const interval = setInterval(refresh, timeout) - return () => clearInterval(interval) - }, [refresh, timeout]) + const interval = setInterval(refresh, timeout); + return () => clearInterval(interval); + }, [refresh, timeout]); - return data + return data; } diff --git a/oxfmt.config.ts b/oxfmt.config.ts new file mode 100644 index 0000000..d61d8e7 --- /dev/null +++ b/oxfmt.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "oxfmt"; + +export default defineConfig({ + $schema: "./node_modules/oxfmt/configuration_schema.json", + ignorePatterns: ["CHANGELOG.md"], +}); diff --git a/oxlint.config.ts b/oxlint.config.ts index 3578fdc..3c1864d 100644 --- a/oxlint.config.ts +++ b/oxlint.config.ts @@ -1,24 +1,13 @@ -import { defineConfig } from "oxlint" +import { defineConfig } from "oxlint"; -export default defineConfig( -{ - "$schema": "./node_modules/oxlint/configuration_schema.json", - "plugins": [ - "eslint", - "unicorn", - "react", - "react-perf", - "oxc", - "import", - "promise", - "vitest" - ], - "categories": { - "correctness": "error", - "suspicious": "error", - "pedantic": "warn", - "perf": "error", - "restriction": "error" - } -} -); +export default defineConfig({ + $schema: "./node_modules/oxlint/configuration_schema.json", + plugins: ["eslint", "unicorn", "react", "react-perf", "oxc", "import", "promise", "vitest"], + categories: { + correctness: "error", + suspicious: "error", + pedantic: "warn", + perf: "error", + restriction: "error", + }, +}); diff --git a/package-lock.json b/package-lock.json index 0a3a43f..b390971 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "conventional-changelog-conventionalcommits": "*", "jsdom": "*", "neostandard": "*", + "oxfmt": "*", "oxlint": "*", "react-dom": "*", "semantic-release": "*", @@ -861,6 +862,329 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@oxfmt/binding-android-arm-eabi": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.49.0.tgz", + "integrity": "sha512-HbifJ84prIh9+55CTPAU35JdRQrwg47y16cGerCC+iejSKOuHXYo2WDql6l7cQlzrYVtc3f4UWY+dBj2lRmOeA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-android-arm64": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.49.0.tgz", + "integrity": "sha512-Ef7SKJqAaH2d7E6eXZZa2OffIShbhFMxnGK0zd93p4qiyTJr75B0qf7lrPD+qQOwcf04BrjYJ0JUxq8d5+yZwg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-darwin-arm64": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.49.0.tgz", + "integrity": "sha512-8x5DN9CsFfb432sHa9NyqX5XisGUdA53LPEGSdv/VniS+v4uEOR8Orv7A9QSB98Xxgp0t6r31DzQA/wpIobGqQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-darwin-x64": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.49.0.tgz", + "integrity": "sha512-e0+DSVzk4ewhMVKNYDaRTmP81jNMBWR1X9al0cVKWS+hDM/dElNqD5zjTOCuLOZc4oOdp2Gx2ldrVL+yYo9TZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-freebsd-x64": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.49.0.tgz", + "integrity": "sha512-W+mjtYtrQvFbXT/uNT+221OBhGRZ8UqNsLxjTWsjZ4GsQnRdvRC/N2NCK86BcamWr7lsTxwpwN3PULnr78sgcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm-gnueabihf": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.49.0.tgz", + "integrity": "sha512-Rtv6UevV7czDlLqil+NZUe4d8gs8jQo/zScSpumwyf7I+fSdLc+hc8AF3MQC7ymxSMMD9+vfiqQlsIf7wOAzXA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm-musleabihf": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.49.0.tgz", + "integrity": "sha512-sBi+8C/Q/MdKa5FL8ibAUCdhFBGFH7HFN/Qoyd5xQbZ/0ky3NMPpKfIBpaH0lhK2dXkGLczVQUoZ+xuNSerCdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm64-gnu": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.49.0.tgz", + "integrity": "sha512-JIfWenFhlzx+O8YygyZhoHFzTsdgDhxhbDRnE2iJLnnM5pWKScFvPECO2vOlA7JqJ/9S1g3uzEKuRCkHFwTjvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm64-musl": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.49.0.tgz", + "integrity": "sha512-iNzkMPG18jPkwBOZ4/HEjwqfzAjq4RrUQ0CgId/fC1ENvYD5jLVAaU/gWgpiqP1ys07kxSsSggDd1fp3E7mQHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-ppc64-gnu": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.49.0.tgz", + "integrity": "sha512-BPHA/NN3LvoIXiid+iz3BHt5V0Rzx0tXAqRUovwE1NsbDaLG9e8mtv7evDGRIkVQacqTDBv0XL25THHsxSJosQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-riscv64-gnu": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.49.0.tgz", + "integrity": "sha512-3Eroshe+s69htC9JIL0+zLGQczLtRKezkMhwqQC21VC5Z/fuLvzLfbAOLgJLUq601H8gDYjy7deYycfOBjCvWg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-riscv64-musl": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.49.0.tgz", + "integrity": "sha512-fnaERGgsxGm0lKAmO72EYR4BA3qBnzBTJBTi6EtUMq1D4R7EexRBMU4voXnx4TXla3SEDl9x4uNp/18SbkPjGg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-s390x-gnu": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.49.0.tgz", + "integrity": "sha512-rBwasMl1Uul1MCCeTGEFKnOTL7VUxHf+634jWStrQAbzpBJgd5Yz5m4F7exVCsoI8PHn57dNjssXagXLCLB5yA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-x64-gnu": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.49.0.tgz", + "integrity": "sha512-BoC/F9xHe2y/deuBGA5Aw7bes07OD2gcL2wlpzTrfImR92vPP7S/k3LBTyspQZCNIVNdagkELcqKELwMLGIfAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-x64-musl": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.49.0.tgz", + "integrity": "sha512-umY6jFADAo/oztFKl8D/S6vSrG6oBpEskcentiRuz42kZVU2kfDXMWCYavxyZR2bwPjqkHpcHZ6EZFiH3Qj9ZA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-openharmony-arm64": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.49.0.tgz", + "integrity": "sha512-J85zQMiw2pXiGPK+OusmDvSnJ/dgpgN7VgmB2zOBtgS8F+nsOUfSg9ZEBrwbQscjZ7tkPbm38CG4VF5f53MsiA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-win32-arm64-msvc": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.49.0.tgz", + "integrity": "sha512-38K67XR++CoFFORDd4sMFwUVAnD6msYBdGTei+qvKGrRPO6S2PbrYPNL/eQQ1RgnnxOegNba0YQwg6uRkNcw6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-win32-ia32-msvc": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.49.0.tgz", + "integrity": "sha512-rXVe0HICwQF0dBgbQtBCoYf8x/SidPIdhyQl+iPuJlV7suV+qDv7yUEB3wQ4qC3nOeNxz287SwFXKzyr0kWgEg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-win32-x64-msvc": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.49.0.tgz", + "integrity": "sha512-gwWLwSEmBBfIK/Wh7GGd658161o4RKAvHWRaRQbJm571iQXGKfyr7UKsI1vsWvDlNLc30CxJDc8mMmCvJ/kczQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxlint/binding-android-arm-eabi": { "version": "1.64.0", "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.64.0.tgz", @@ -9590,6 +9914,54 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oxfmt": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.49.0.tgz", + "integrity": "sha512-IAHFMdlJSWe+oAr65dx22UvjCtV9DBMisAuLnKpDqMQrctzCkGnj3QRwNHm0d+uwSWPalsDF8ZYLz9rh6nH2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinypool": "2.1.0" + }, + "bin": { + "oxfmt": "bin/oxfmt" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxfmt/binding-android-arm-eabi": "0.49.0", + "@oxfmt/binding-android-arm64": "0.49.0", + "@oxfmt/binding-darwin-arm64": "0.49.0", + "@oxfmt/binding-darwin-x64": "0.49.0", + "@oxfmt/binding-freebsd-x64": "0.49.0", + "@oxfmt/binding-linux-arm-gnueabihf": "0.49.0", + "@oxfmt/binding-linux-arm-musleabihf": "0.49.0", + "@oxfmt/binding-linux-arm64-gnu": "0.49.0", + "@oxfmt/binding-linux-arm64-musl": "0.49.0", + "@oxfmt/binding-linux-ppc64-gnu": "0.49.0", + "@oxfmt/binding-linux-riscv64-gnu": "0.49.0", + "@oxfmt/binding-linux-riscv64-musl": "0.49.0", + "@oxfmt/binding-linux-s390x-gnu": "0.49.0", + "@oxfmt/binding-linux-x64-gnu": "0.49.0", + "@oxfmt/binding-linux-x64-musl": "0.49.0", + "@oxfmt/binding-openharmony-arm64": "0.49.0", + "@oxfmt/binding-win32-arm64-msvc": "0.49.0", + "@oxfmt/binding-win32-ia32-msvc": "0.49.0", + "@oxfmt/binding-win32-x64-msvc": "0.49.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, "node_modules/oxlint": { "version": "1.64.0", "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.64.0.tgz", @@ -11767,6 +12139,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinypool": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz", + "integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.0.0 || >=22.0.0" + } + }, "node_modules/tinyrainbow": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", diff --git a/package.json b/package.json index b3b5c08..e8a0f34 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "gtfs-react-hooks", - "description": "React hooks for fetching data from gtfs sources.", "version": "1.1.0", - "type": "module", + "description": "React hooks for fetching data from gtfs sources.", "files": [ "dist" ], + "type": "module", "main": "./dist/gtfs-react-hooks.js", "module": "./dist/gtfs-react-hooks.js", "exports": { @@ -15,6 +15,8 @@ }, "scripts": { "build": "vite build", + "fmt": "oxfmt", + "fmt:check": "oxfmt --check", "lint": "oxlint", "release": "semantic-release", "test": "vitest run" @@ -35,6 +37,7 @@ "conventional-changelog-conventionalcommits": "*", "jsdom": "*", "neostandard": "*", + "oxfmt": "*", "oxlint": "*", "react-dom": "*", "semantic-release": "*", diff --git a/release.config.js b/release.config.js index 07344e4..2468ece 100644 --- a/release.config.js +++ b/release.config.js @@ -1,25 +1,19 @@ export default { - branches: [ - 'main', - ], + branches: ["main"], plugins: [ - '@semantic-release/commit-analyzer', - '@semantic-release/release-notes-generator', - '@semantic-release/changelog', - '@semantic-release/npm', + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/changelog", + "@semantic-release/npm", [ - '@semantic-release/git', + "@semantic-release/git", { - assets: [ - 'package.json', - 'package-lock.json', - 'CHANGELOG.md', - ], + assets: ["package.json", "package-lock.json", "CHANGELOG.md"], // eslint-disable-next-line no-template-curly-in-string - message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}', + message: "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}", }, ], - '@semantic-release/github', + "@semantic-release/github", ], - preset: 'conventionalcommits', -} + preset: "conventionalcommits", +}; diff --git a/test/index.test.js b/test/index.test.js index b67f37e..dd38387 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,16 +1,16 @@ -import { describe, expect, it } from 'vitest' -import { useFetchResolver, useGtfsRealtime, useGtfsSchedule } from '../lib/index.js' +import { describe, expect, it } from "vitest"; +import { useFetchResolver, useGtfsRealtime, useGtfsSchedule } from "../lib/index.js"; -describe('entrypoint', () => { - it('exports a useGtfsRealtime hook', () => { - expect(useGtfsRealtime).toBeTypeOf('function') - }) +describe("entrypoint", () => { + it("exports a useGtfsRealtime hook", () => { + expect(useGtfsRealtime).toBeTypeOf("function"); + }); - it('exports a useGtfsSchedule hook', () => { - expect(useGtfsSchedule).toBeTypeOf('function') - }) + it("exports a useGtfsSchedule hook", () => { + expect(useGtfsSchedule).toBeTypeOf("function"); + }); - it('exports a useFetchResolver hook', () => { - expect(useFetchResolver).toBeTypeOf('function') - }) -}) + it("exports a useFetchResolver hook", () => { + expect(useFetchResolver).toBeTypeOf("function"); + }); +}); diff --git a/test/setup.js b/test/setup.js index 5626a86..794b455 100644 --- a/test/setup.js +++ b/test/setup.js @@ -1,12 +1,12 @@ -import { cleanup } from '@testing-library/react' -import { afterEach, beforeEach, vi } from 'vitest' +import { cleanup } from "@testing-library/react"; +import { afterEach, beforeEach, vi } from "vitest"; beforeEach(() => { - vi.useFakeTimers() -}) + vi.useFakeTimers(); +}); afterEach(() => { - cleanup() - vi.useRealTimers() - vi.clearAllMocks() -}) + cleanup(); + vi.useRealTimers(); + vi.clearAllMocks(); +}); diff --git a/test/useFetchResolver.test.js b/test/useFetchResolver.test.js index a762efc..a7ee790 100644 --- a/test/useFetchResolver.test.js +++ b/test/useFetchResolver.test.js @@ -1,43 +1,45 @@ -import { renderHook } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' -import useFetchResolver from '../lib/useFetchResolver.js' +import { renderHook } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; +import useFetchResolver from "../lib/useFetchResolver.js"; -describe('useFetchResolver', () => { - it('returns undefined when an error is raised', async () => { - const fetchMock = vi.fn(async () => { throw new Error() }) - vi.stubGlobal('fetch', fetchMock) +describe("useFetchResolver", () => { + it("returns undefined when an error is raised", async () => { + const fetchMock = vi.fn(async () => { + throw new Error(); + }); + vi.stubGlobal("fetch", fetchMock); - const { result } = renderHook(() => useFetchResolver('https://example.com')) - const data = await result.current() + const { result } = renderHook(() => useFetchResolver("https://example.com")); + const data = await result.current(); - expect(data).toEqual(undefined) - }) + expect(data).toEqual(undefined); + }); - it('returns undefined when the response is not a 200', async () => { - const fetchMock = vi.fn(async () => ({ status: 503 })) - vi.stubGlobal('fetch', fetchMock) + it("returns undefined when the response is not a 200", async () => { + const fetchMock = vi.fn(async () => ({ status: 503 })); + vi.stubGlobal("fetch", fetchMock); - const { result } = renderHook(() => useFetchResolver('https://example.com')) - const data = await result.current() + const { result } = renderHook(() => useFetchResolver("https://example.com")); + const data = await result.current(); - expect(data).toEqual(undefined) - }) + expect(data).toEqual(undefined); + }); - it('returns the raw response body as a Uint8Array when response is a 200', async () => { + it("returns the raw response body as a Uint8Array when response is a 200", async () => { const fetchMock = vi.fn(async () => { - const buffer = new ArrayBuffer(8) - const view = new Uint8Array(buffer) + const buffer = new ArrayBuffer(8); + const view = new Uint8Array(buffer); for (let i = 0; i < 8; i++) { - view[i] = i + view[i] = i; } - return { status: 200, arrayBuffer: async () => buffer } - }) - vi.stubGlobal('fetch', fetchMock) + return { status: 200, arrayBuffer: async () => buffer }; + }); + vi.stubGlobal("fetch", fetchMock); - const { result } = renderHook(() => useFetchResolver('https://example.com')) - const data = await result.current() + const { result } = renderHook(() => useFetchResolver("https://example.com")); + const data = await result.current(); - expect(data).toBeInstanceOf(Uint8Array) - expect(Array.from(data)).toEqual([0, 1, 2, 3, 4, 5, 6, 7]) - }) -}) + expect(data).toBeInstanceOf(Uint8Array); + expect(Array.from(data)).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + }); +}); diff --git a/test/useGtfsRealtime.test.js b/test/useGtfsRealtime.test.js index 3dc6268..1e0b0ce 100644 --- a/test/useGtfsRealtime.test.js +++ b/test/useGtfsRealtime.test.js @@ -1,60 +1,62 @@ -import { renderHook } from '@testing-library/react' -import fs from 'fs' -import GtfsRealtimeBindings from 'gtfs-realtime-bindings' -import { describe, expect, it, vi } from 'vitest' -import useGtfsRealtime from '../lib/useGtfsRealtime.js' +import { renderHook } from "@testing-library/react"; +import fs from "fs"; +import GtfsRealtimeBindings from "gtfs-realtime-bindings"; +import { describe, expect, it, vi } from "vitest"; +import useGtfsRealtime from "../lib/useGtfsRealtime.js"; -import parsedRealtime from './fixtures/realtime.json' -const rawRealtime = fs.readFileSync('test/fixtures/realtime.proto') +import parsedRealtime from "./fixtures/realtime.json"; +const rawRealtime = fs.readFileSync("test/fixtures/realtime.proto"); -describe('useGtfsRealtime', () => { - it('returns undefined when unresolved', () => { - const resolve = async () => rawRealtime - const { result } = renderHook(() => useGtfsRealtime(resolve, 1000)) +describe("useGtfsRealtime", () => { + it("returns undefined when unresolved", () => { + const resolve = async () => rawRealtime; + const { result } = renderHook(() => useGtfsRealtime(resolve, 1000)); - expect(result.current).toBeUndefined() - }) + expect(result.current).toBeUndefined(); + }); - it('returns undefined when resolved to undefined', async () => { - const resolve = vi.fn() - resolve.mockImplementationOnce(async () => rawRealtime) - const { result } = renderHook(() => useGtfsRealtime(resolve, 1000)) - await vi.waitFor(() => expect(result.current.toJSON()).toEqual(parsedRealtime)) + it("returns undefined when resolved to undefined", async () => { + const resolve = vi.fn(); + resolve.mockImplementationOnce(async () => rawRealtime); + const { result } = renderHook(() => useGtfsRealtime(resolve, 1000)); + await vi.waitFor(() => expect(result.current.toJSON()).toEqual(parsedRealtime)); - resolve.mockImplementationOnce(async () => undefined) - vi.advanceTimersByTime(1000) + resolve.mockImplementationOnce(async () => undefined); + vi.advanceTimersByTime(1000); - await vi.waitFor(() => expect(result.current).toBeUndefined()) - }) + await vi.waitFor(() => expect(result.current).toBeUndefined()); + }); - it('returns parsed realtime data when resolved to a Uint8Array', async () => { - const resolve = async () => rawRealtime - const { result } = renderHook(() => useGtfsRealtime(resolve, 1000)) + it("returns parsed realtime data when resolved to a Uint8Array", async () => { + const resolve = async () => rawRealtime; + const { result } = renderHook(() => useGtfsRealtime(resolve, 1000)); - await vi.waitFor(() => expect(result.current).toBeInstanceOf(GtfsRealtimeBindings.transit_realtime.FeedMessage)) - expect(result.current.toJSON()).toEqual(parsedRealtime) - }) + await vi.waitFor(() => + expect(result.current).toBeInstanceOf(GtfsRealtimeBindings.transit_realtime.FeedMessage), + ); + expect(result.current.toJSON()).toEqual(parsedRealtime); + }); - it('periodically re-resolves according to the given timeout and retry values', async () => { - const resolve = vi.fn() - resolve.mockImplementationOnce(async () => rawRealtime) - const { result } = renderHook(() => useGtfsRealtime(resolve, 5000, 1000)) + it("periodically re-resolves according to the given timeout and retry values", async () => { + const resolve = vi.fn(); + resolve.mockImplementationOnce(async () => rawRealtime); + const { result } = renderHook(() => useGtfsRealtime(resolve, 5000, 1000)); - await vi.waitFor(() => expect(result.current.toJSON()).toEqual(parsedRealtime)) - expect(resolve).toHaveBeenCalledTimes(1) + await vi.waitFor(() => expect(result.current.toJSON()).toEqual(parsedRealtime)); + expect(resolve).toHaveBeenCalledTimes(1); // create a problem and wait for the next regular refresh - resolve.mockImplementationOnce(async () => undefined) - vi.advanceTimersByTime(5000) + resolve.mockImplementationOnce(async () => undefined); + vi.advanceTimersByTime(5000); - await vi.waitFor(() => expect(result.current).toEqual(undefined)) - expect(resolve).toHaveBeenCalledTimes(2) + await vi.waitFor(() => expect(result.current).toEqual(undefined)); + expect(resolve).toHaveBeenCalledTimes(2); // fix problem and wait for the next retry refresh - resolve.mockImplementationOnce(async () => rawRealtime) - vi.advanceTimersByTime(1000) + resolve.mockImplementationOnce(async () => rawRealtime); + vi.advanceTimersByTime(1000); - await vi.waitFor(() => expect(result.current.toJSON()).toEqual(parsedRealtime)) - expect(resolve).toHaveBeenCalledTimes(3) - }) -}) + await vi.waitFor(() => expect(result.current.toJSON()).toEqual(parsedRealtime)); + expect(resolve).toHaveBeenCalledTimes(3); + }); +}); diff --git a/test/useGtfsSchedule.test.js b/test/useGtfsSchedule.test.js index 3bcd1b8..ad034e7 100644 --- a/test/useGtfsSchedule.test.js +++ b/test/useGtfsSchedule.test.js @@ -1,58 +1,58 @@ -import { renderHook } from '@testing-library/react' -import fs from 'fs' -import { describe, expect, it, vi } from 'vitest' -import useGtfsSchedule from '../lib/useGtfsSchedule.js' +import { renderHook } from "@testing-library/react"; +import fs from "fs"; +import { describe, expect, it, vi } from "vitest"; +import useGtfsSchedule from "../lib/useGtfsSchedule.js"; -import parsedSchedule from './fixtures/schedule.json' -const rawSchedule = fs.readFileSync('test/fixtures/schedule.zip') +import parsedSchedule from "./fixtures/schedule.json"; +const rawSchedule = fs.readFileSync("test/fixtures/schedule.zip"); -describe('useGtfsSchedule', () => { - it('returns undefined when unresolved', async () => { - const resolve = async () => rawSchedule - const { result } = renderHook(() => useGtfsSchedule(resolve, 1000)) +describe("useGtfsSchedule", () => { + it("returns undefined when unresolved", async () => { + const resolve = async () => rawSchedule; + const { result } = renderHook(() => useGtfsSchedule(resolve, 1000)); - expect(result.current).toBeUndefined() - }) + expect(result.current).toBeUndefined(); + }); - it('returns undefined when resolved to undefined', async () => { - const resolve = vi.fn() - resolve.mockImplementationOnce(async () => rawSchedule) - const { result } = renderHook(() => useGtfsSchedule(resolve, 1000)) - await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)) + it("returns undefined when resolved to undefined", async () => { + const resolve = vi.fn(); + resolve.mockImplementationOnce(async () => rawSchedule); + const { result } = renderHook(() => useGtfsSchedule(resolve, 1000)); + await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)); - resolve.mockImplementationOnce(async () => undefined) - vi.advanceTimersByTime(1000) + resolve.mockImplementationOnce(async () => undefined); + vi.advanceTimersByTime(1000); - await vi.waitFor(() => expect(result.current).toBeUndefined()) - }) + await vi.waitFor(() => expect(result.current).toBeUndefined()); + }); - it('returns parsed schedule data when resolved to a Uint8Array', async () => { - const resolve = async () => rawSchedule - const { result } = renderHook(() => useGtfsSchedule(resolve, 1000)) + it("returns parsed schedule data when resolved to a Uint8Array", async () => { + const resolve = async () => rawSchedule; + const { result } = renderHook(() => useGtfsSchedule(resolve, 1000)); - await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)) - }) + await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)); + }); - it('periodically re-resolves according to the given timeout and retry values', async () => { - const resolve = vi.fn() - resolve.mockImplementationOnce(async () => rawSchedule) - const { result } = renderHook(() => useGtfsSchedule(resolve, 5000, 1000)) + it("periodically re-resolves according to the given timeout and retry values", async () => { + const resolve = vi.fn(); + resolve.mockImplementationOnce(async () => rawSchedule); + const { result } = renderHook(() => useGtfsSchedule(resolve, 5000, 1000)); - await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)) - expect(resolve).toHaveBeenCalledTimes(1) + await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)); + expect(resolve).toHaveBeenCalledTimes(1); // create a problem and wait for the next regular refresh - resolve.mockImplementationOnce(async () => undefined) - vi.advanceTimersByTime(5000) + resolve.mockImplementationOnce(async () => undefined); + vi.advanceTimersByTime(5000); - await vi.waitFor(() => expect(result.current).toEqual(undefined)) - expect(resolve).toHaveBeenCalledTimes(2) + await vi.waitFor(() => expect(result.current).toEqual(undefined)); + expect(resolve).toHaveBeenCalledTimes(2); // fix problem and wait for the next retry refresh - resolve.mockImplementationOnce(async () => rawSchedule) - vi.advanceTimersByTime(1000) + resolve.mockImplementationOnce(async () => rawSchedule); + vi.advanceTimersByTime(1000); - await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)) - expect(resolve).toHaveBeenCalledTimes(3) - }) -}) + await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)); + expect(resolve).toHaveBeenCalledTimes(3); + }); +}); diff --git a/test/useRefresh.test.js b/test/useRefresh.test.js index 61009a7..72138d0 100644 --- a/test/useRefresh.test.js +++ b/test/useRefresh.test.js @@ -1,45 +1,45 @@ -import { renderHook } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' -import useRefresh from '../lib/useRefresh.js' - -describe('useRefresh', () => { - it('returns undefined when unresolved', async () => { - const resolve = async () => 'data' - const { result } = renderHook(() => useRefresh(resolve, 1000)) - expect(result.current).toBeUndefined() - }) - - it('returns resolution when resolved', async () => { - const resolve = async () => 'data' - const { result } = renderHook(() => useRefresh(resolve, 5000, 1000)) - await vi.waitFor(() => expect(result.current).toEqual('data')) - }) - - it('periodically re-resolves according to the given timeout and retry values', async () => { - const resolve = vi.fn() - resolve.mockImplementationOnce(async () => 'data') - const { result } = renderHook(() => useRefresh(resolve, 5000, 1000)) - - await vi.waitFor(() => expect(result.current).toEqual('data')) - expect(resolve).toHaveBeenCalledTimes(1) +import { renderHook } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; +import useRefresh from "../lib/useRefresh.js"; + +describe("useRefresh", () => { + it("returns undefined when unresolved", async () => { + const resolve = async () => "data"; + const { result } = renderHook(() => useRefresh(resolve, 1000)); + expect(result.current).toBeUndefined(); + }); + + it("returns resolution when resolved", async () => { + const resolve = async () => "data"; + const { result } = renderHook(() => useRefresh(resolve, 5000, 1000)); + await vi.waitFor(() => expect(result.current).toEqual("data")); + }); + + it("periodically re-resolves according to the given timeout and retry values", async () => { + const resolve = vi.fn(); + resolve.mockImplementationOnce(async () => "data"); + const { result } = renderHook(() => useRefresh(resolve, 5000, 1000)); + + await vi.waitFor(() => expect(result.current).toEqual("data")); + expect(resolve).toHaveBeenCalledTimes(1); // create a problem and wait for the next regular refresh - resolve.mockImplementationOnce(async () => undefined) - vi.advanceTimersByTime(5000) + resolve.mockImplementationOnce(async () => undefined); + vi.advanceTimersByTime(5000); - await vi.waitFor(() => expect(result.current).toEqual(undefined)) - expect(resolve).toHaveBeenCalledTimes(2) + await vi.waitFor(() => expect(result.current).toEqual(undefined)); + expect(resolve).toHaveBeenCalledTimes(2); // fix problem and wait for the next retry refresh - resolve.mockImplementationOnce(async () => 'data') - vi.advanceTimersByTime(1000) + resolve.mockImplementationOnce(async () => "data"); + vi.advanceTimersByTime(1000); - await vi.waitFor(() => expect(result.current).toEqual('data')) - expect(resolve).toHaveBeenCalledTimes(3) + await vi.waitFor(() => expect(result.current).toEqual("data")); + expect(resolve).toHaveBeenCalledTimes(3); // wait for the next regular refresh - vi.advanceTimersByTime(5000) + vi.advanceTimersByTime(5000); - expect(resolve).toHaveBeenCalledTimes(4) - }) -}) + expect(resolve).toHaveBeenCalledTimes(4); + }); +}); diff --git a/vite.config.js b/vite.config.js index a0763ed..3413856 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,30 +1,30 @@ -import { dirname, resolve } from 'node:path' -import { fileURLToPath } from 'node:url' -import { defineConfig } from 'vite' +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { defineConfig } from "vite"; -const __dirname = dirname(fileURLToPath(import.meta.url)) +const __dirname = dirname(fileURLToPath(import.meta.url)); export default defineConfig({ build: { lib: { - name: 'GtfsReactHooks', - entry: resolve(__dirname, 'lib/index.js'), - fileName: 'gtfs-react-hooks', - formats: ['es'], + name: "GtfsReactHooks", + entry: resolve(__dirname, "lib/index.js"), + fileName: "gtfs-react-hooks", + formats: ["es"], }, rollupOptions: { - external: ['change-case', 'jszip', 'gtfs-realtime-bindings', 'papaparse', 'react'], + external: ["change-case", "jszip", "gtfs-realtime-bindings", "papaparse", "react"], }, }, test: { - environment: 'jsdom', - setupFiles: ['./test/setup.js'], + environment: "jsdom", + setupFiles: ["./test/setup.js"], coverage: { enabled: true, - include: ['lib/**/*'], + include: ["lib/**/*"], thresholds: { 100: true, }, }, }, -}) +}); From b98dd223e874ffef6632aeda59b5f74f793fffde Mon Sep 17 00:00:00 2001 From: benmelz Date: Thu, 14 May 2026 10:50:40 -0400 Subject: [PATCH 3/6] lint lib code --- lib/useFetchResolver.js | 6 ++---- lib/useGtfsRealtime.js | 4 +--- lib/useGtfsSchedule.js | 40 ++++++++++++++++++++++++++-------------- oxlint.config.ts | 10 ++++++++-- 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/lib/useFetchResolver.js b/lib/useFetchResolver.js index 6a8dc17..ac5e951 100644 --- a/lib/useFetchResolver.js +++ b/lib/useFetchResolver.js @@ -4,13 +4,11 @@ export default function useFetchResolver(url) { return useCallback(async () => { try { const response = await fetch(url); - if (response.status !== 200) { - return undefined; - } else { + if (response.status === 200) { return new Uint8Array(await response.arrayBuffer()); } } catch { - return undefined; + // do nothing } }, [url]); } diff --git a/lib/useGtfsRealtime.js b/lib/useGtfsRealtime.js index 95d1af5..cf2c78f 100644 --- a/lib/useGtfsRealtime.js +++ b/lib/useGtfsRealtime.js @@ -5,9 +5,7 @@ import useRefresh from "./useRefresh.js"; export default function useGtfsRealtime(resolve, timeout, retry = 1000) { const realtimeUInt8Buffer = useRefresh(resolve, timeout, retry); return useMemo(() => { - if (realtimeUInt8Buffer === undefined) { - return realtimeUInt8Buffer; - } else { + if (realtimeUInt8Buffer !== undefined) { return GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(realtimeUInt8Buffer); } }, [realtimeUInt8Buffer]); diff --git a/lib/useGtfsSchedule.js b/lib/useGtfsSchedule.js index 3dd78dc..8620f67 100644 --- a/lib/useGtfsSchedule.js +++ b/lib/useGtfsSchedule.js @@ -7,38 +7,50 @@ import useRefresh from "./useRefresh.js"; export default function useGtfsSchedule(resolve, timeout, retry = 1000) { const rawScheduleData = useRefresh(resolve, timeout, retry); const dataCache = useRef({}); - const [data, setData] = useState(undefined); + const [data, setData] = useState(); useEffect(() => { if (rawScheduleData === undefined) { setData(undefined); } else { - JSZip.loadAsync(rawScheduleData).then((zip) => { - for (const [filename, file] of Object.entries(zip.files)) { - file - .async("text") - .then(parseCsv) - .then((json) => { - dataCache.current[camelCase(removeExtension(filename))] = json; - setData({ ...dataCache.current }); - }); - } - }); + JSZip.loadAsync(rawScheduleData) + .then((zip) => { + const parses = []; + for (const [filename, file] of Object.entries(zip.files)) { + const parse = file + .async("text") + .then(parseCsv) + .then((json) => { + dataCache.current[camelCase(removeExtension(filename))] = json; + setData({ ...dataCache.current }); + return json; + }) + .catch(() => { + // do nothing + }); + parses.push(parse); + } + return Promise.all(parses); + }) + .catch(() => { + // do nothing + }); } }, [rawScheduleData]); return data; } -async function parseCsv(csvString) { +function parseCsv(csvString) { return new Promise((resolve, reject) => { Papa.parse(csvString, { header: true, transformHeader: camelCase, skipEmptyLines: true, complete: (result) => resolve(result.data), + error: reject, }); }); } function removeExtension(filename) { - return filename.replace(/\.[^/.]+$/, ""); + return filename.replace(/\.[^/.]+$/u, ""); } diff --git a/oxlint.config.ts b/oxlint.config.ts index 3c1864d..b7ef0a8 100644 --- a/oxlint.config.ts +++ b/oxlint.config.ts @@ -2,12 +2,18 @@ import { defineConfig } from "oxlint"; export default defineConfig({ $schema: "./node_modules/oxlint/configuration_schema.json", - plugins: ["eslint", "unicorn", "react", "react-perf", "oxc", "import", "promise", "vitest"], + plugins: ["unicorn", "react", "react-perf", "oxc", "import", "promise", "vitest"], categories: { correctness: "error", - suspicious: "error", + suspicious: "warn", pedantic: "warn", perf: "error", restriction: "error", }, + rules: { + "no-undefined": "off", + "import/no-default-export": "off", + "oxc/no-async-await": "off", + "oxc/no-rest-spread-properties": "off", + }, }); From 9d863df49ef247f234f52d831672a9d84f1394f2 Mon Sep 17 00:00:00 2001 From: benmelz Date: Thu, 14 May 2026 11:48:16 -0400 Subject: [PATCH 4/6] lint test/config --- lib/useGtfsSchedule.js | 7 +------ oxlint.config.ts | 10 ++++++++++ test/useFetchResolver.test.js | 21 +++++++++------------ test/useGtfsRealtime.test.js | 18 ++++++++---------- test/useGtfsSchedule.test.js | 20 +++++++++----------- test/useRefresh.test.js | 14 ++++++-------- vite.config.js | 7 ++----- 7 files changed, 45 insertions(+), 52 deletions(-) diff --git a/lib/useGtfsSchedule.js b/lib/useGtfsSchedule.js index 8620f67..1c24d2a 100644 --- a/lib/useGtfsSchedule.js +++ b/lib/useGtfsSchedule.js @@ -12,6 +12,7 @@ export default function useGtfsSchedule(resolve, timeout, retry = 1000) { if (rawScheduleData === undefined) { setData(undefined); } else { + // oxlint-disable-next-line promise/catch-or-return JSZip.loadAsync(rawScheduleData) .then((zip) => { const parses = []; @@ -24,16 +25,10 @@ export default function useGtfsSchedule(resolve, timeout, retry = 1000) { setData({ ...dataCache.current }); return json; }) - .catch(() => { - // do nothing - }); parses.push(parse); } return Promise.all(parses); }) - .catch(() => { - // do nothing - }); } }, [rawScheduleData]); return data; diff --git a/oxlint.config.ts b/oxlint.config.ts index b7ef0a8..583676b 100644 --- a/oxlint.config.ts +++ b/oxlint.config.ts @@ -13,7 +13,17 @@ export default defineConfig({ rules: { "no-undefined": "off", "import/no-default-export": "off", + "import/no-relative-parent-imports": "off", "oxc/no-async-await": "off", "oxc/no-rest-spread-properties": "off", }, + overrides: [ + { + files: ["*.test.js"], + rules: { + "max-lines-per-function": "off", + "vitest/require-test-timeout": "off", + }, + }, + ], }); diff --git a/test/useFetchResolver.test.js b/test/useFetchResolver.test.js index a7ee790..5515e9b 100644 --- a/test/useFetchResolver.test.js +++ b/test/useFetchResolver.test.js @@ -4,9 +4,7 @@ import useFetchResolver from "../lib/useFetchResolver.js"; describe("useFetchResolver", () => { it("returns undefined when an error is raised", async () => { - const fetchMock = vi.fn(async () => { - throw new Error(); - }); + const fetchMock = vi.fn(() => Promise.reject()); vi.stubGlobal("fetch", fetchMock); const { result } = renderHook(() => useFetchResolver("https://example.com")); @@ -16,7 +14,7 @@ describe("useFetchResolver", () => { }); it("returns undefined when the response is not a 200", async () => { - const fetchMock = vi.fn(async () => ({ status: 503 })); + const fetchMock = vi.fn(() => Promise.resolve({ status: 503 })); vi.stubGlobal("fetch", fetchMock); const { result } = renderHook(() => useFetchResolver("https://example.com")); @@ -26,14 +24,13 @@ describe("useFetchResolver", () => { }); it("returns the raw response body as a Uint8Array when response is a 200", async () => { - const fetchMock = vi.fn(async () => { - const buffer = new ArrayBuffer(8); - const view = new Uint8Array(buffer); - for (let i = 0; i < 8; i++) { - view[i] = i; - } - return { status: 200, arrayBuffer: async () => buffer }; - }); + const buffer = new ArrayBuffer(8); + const bufferView = new Uint8Array(buffer); + for (let i = 0; i < 8; i += 1) bufferView[i] = i; + + const fetchMock = vi.fn(() => + Promise.resolve({ status: 200, arrayBuffer: () => Promise.resolve(buffer) }), + ); vi.stubGlobal("fetch", fetchMock); const { result } = renderHook(() => useFetchResolver("https://example.com")); diff --git a/test/useGtfsRealtime.test.js b/test/useGtfsRealtime.test.js index 1e0b0ce..6b099b6 100644 --- a/test/useGtfsRealtime.test.js +++ b/test/useGtfsRealtime.test.js @@ -1,6 +1,6 @@ import { renderHook } from "@testing-library/react"; -import fs from "fs"; import GtfsRealtimeBindings from "gtfs-realtime-bindings"; +import fs from "node:fs"; import { describe, expect, it, vi } from "vitest"; import useGtfsRealtime from "../lib/useGtfsRealtime.js"; @@ -9,27 +9,25 @@ const rawRealtime = fs.readFileSync("test/fixtures/realtime.proto"); describe("useGtfsRealtime", () => { it("returns undefined when unresolved", () => { - const resolve = async () => rawRealtime; - const { result } = renderHook(() => useGtfsRealtime(resolve, 1000)); + const { result } = renderHook(() => useGtfsRealtime(() => Promise.resolve(rawRealtime), 1000)); expect(result.current).toBeUndefined(); }); it("returns undefined when resolved to undefined", async () => { const resolve = vi.fn(); - resolve.mockImplementationOnce(async () => rawRealtime); + resolve.mockImplementationOnce(() => Promise.resolve(rawRealtime)); const { result } = renderHook(() => useGtfsRealtime(resolve, 1000)); await vi.waitFor(() => expect(result.current.toJSON()).toEqual(parsedRealtime)); - resolve.mockImplementationOnce(async () => undefined); + resolve.mockImplementationOnce(() => Promise.resolve()); vi.advanceTimersByTime(1000); await vi.waitFor(() => expect(result.current).toBeUndefined()); }); it("returns parsed realtime data when resolved to a Uint8Array", async () => { - const resolve = async () => rawRealtime; - const { result } = renderHook(() => useGtfsRealtime(resolve, 1000)); + const { result } = renderHook(() => useGtfsRealtime(() => Promise.resolve(rawRealtime), 1000)); await vi.waitFor(() => expect(result.current).toBeInstanceOf(GtfsRealtimeBindings.transit_realtime.FeedMessage), @@ -39,21 +37,21 @@ describe("useGtfsRealtime", () => { it("periodically re-resolves according to the given timeout and retry values", async () => { const resolve = vi.fn(); - resolve.mockImplementationOnce(async () => rawRealtime); + resolve.mockImplementationOnce(() => Promise.resolve(rawRealtime)); const { result } = renderHook(() => useGtfsRealtime(resolve, 5000, 1000)); await vi.waitFor(() => expect(result.current.toJSON()).toEqual(parsedRealtime)); expect(resolve).toHaveBeenCalledTimes(1); // create a problem and wait for the next regular refresh - resolve.mockImplementationOnce(async () => undefined); + resolve.mockImplementationOnce(() => Promise.resolve()); vi.advanceTimersByTime(5000); await vi.waitFor(() => expect(result.current).toEqual(undefined)); expect(resolve).toHaveBeenCalledTimes(2); // fix problem and wait for the next retry refresh - resolve.mockImplementationOnce(async () => rawRealtime); + resolve.mockImplementationOnce(() => Promise.resolve(rawRealtime)); vi.advanceTimersByTime(1000); await vi.waitFor(() => expect(result.current.toJSON()).toEqual(parsedRealtime)); diff --git a/test/useGtfsSchedule.test.js b/test/useGtfsSchedule.test.js index ad034e7..7b9219b 100644 --- a/test/useGtfsSchedule.test.js +++ b/test/useGtfsSchedule.test.js @@ -1,5 +1,5 @@ import { renderHook } from "@testing-library/react"; -import fs from "fs"; +import fs from "node:fs"; import { describe, expect, it, vi } from "vitest"; import useGtfsSchedule from "../lib/useGtfsSchedule.js"; @@ -7,49 +7,47 @@ import parsedSchedule from "./fixtures/schedule.json"; const rawSchedule = fs.readFileSync("test/fixtures/schedule.zip"); describe("useGtfsSchedule", () => { - it("returns undefined when unresolved", async () => { - const resolve = async () => rawSchedule; - const { result } = renderHook(() => useGtfsSchedule(resolve, 1000)); + it("returns undefined when unresolved", () => { + const { result } = renderHook(() => useGtfsSchedule(() => Promise.resolve(rawSchedule), 1000)); expect(result.current).toBeUndefined(); }); it("returns undefined when resolved to undefined", async () => { const resolve = vi.fn(); - resolve.mockImplementationOnce(async () => rawSchedule); + resolve.mockImplementationOnce(() => Promise.resolve(rawSchedule)); const { result } = renderHook(() => useGtfsSchedule(resolve, 1000)); await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)); - resolve.mockImplementationOnce(async () => undefined); + resolve.mockImplementationOnce(() => Promise.resolve()); vi.advanceTimersByTime(1000); await vi.waitFor(() => expect(result.current).toBeUndefined()); }); it("returns parsed schedule data when resolved to a Uint8Array", async () => { - const resolve = async () => rawSchedule; - const { result } = renderHook(() => useGtfsSchedule(resolve, 1000)); + const { result } = renderHook(() => useGtfsSchedule(() => Promise.resolve(rawSchedule), 1000)); await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)); }); it("periodically re-resolves according to the given timeout and retry values", async () => { const resolve = vi.fn(); - resolve.mockImplementationOnce(async () => rawSchedule); + resolve.mockImplementationOnce(() => Promise.resolve(rawSchedule)); const { result } = renderHook(() => useGtfsSchedule(resolve, 5000, 1000)); await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)); expect(resolve).toHaveBeenCalledTimes(1); // create a problem and wait for the next regular refresh - resolve.mockImplementationOnce(async () => undefined); + resolve.mockImplementationOnce(() => Promise.resolve()); vi.advanceTimersByTime(5000); await vi.waitFor(() => expect(result.current).toEqual(undefined)); expect(resolve).toHaveBeenCalledTimes(2); // fix problem and wait for the next retry refresh - resolve.mockImplementationOnce(async () => rawSchedule); + resolve.mockImplementationOnce(() => Promise.resolve(rawSchedule)); vi.advanceTimersByTime(1000); await vi.waitFor(() => expect(result.current).toEqual(parsedSchedule)); diff --git a/test/useRefresh.test.js b/test/useRefresh.test.js index 72138d0..00e14f5 100644 --- a/test/useRefresh.test.js +++ b/test/useRefresh.test.js @@ -3,35 +3,33 @@ import { describe, expect, it, vi } from "vitest"; import useRefresh from "../lib/useRefresh.js"; describe("useRefresh", () => { - it("returns undefined when unresolved", async () => { - const resolve = async () => "data"; - const { result } = renderHook(() => useRefresh(resolve, 1000)); + it("returns undefined when unresolved", () => { + const { result } = renderHook(() => useRefresh(() => Promise.resolve("data"), 1000)); expect(result.current).toBeUndefined(); }); it("returns resolution when resolved", async () => { - const resolve = async () => "data"; - const { result } = renderHook(() => useRefresh(resolve, 5000, 1000)); + const { result } = renderHook(() => useRefresh(() => Promise.resolve("data"), 5000, 1000)); await vi.waitFor(() => expect(result.current).toEqual("data")); }); it("periodically re-resolves according to the given timeout and retry values", async () => { const resolve = vi.fn(); - resolve.mockImplementationOnce(async () => "data"); + resolve.mockImplementationOnce(() => Promise.resolve("data")); const { result } = renderHook(() => useRefresh(resolve, 5000, 1000)); await vi.waitFor(() => expect(result.current).toEqual("data")); expect(resolve).toHaveBeenCalledTimes(1); // create a problem and wait for the next regular refresh - resolve.mockImplementationOnce(async () => undefined); + resolve.mockImplementationOnce(() => Promise.resolve()); vi.advanceTimersByTime(5000); await vi.waitFor(() => expect(result.current).toEqual(undefined)); expect(resolve).toHaveBeenCalledTimes(2); // fix problem and wait for the next retry refresh - resolve.mockImplementationOnce(async () => "data"); + resolve.mockImplementationOnce(() => Promise.resolve("data")); vi.advanceTimersByTime(1000); await vi.waitFor(() => expect(result.current).toEqual("data")); diff --git a/vite.config.js b/vite.config.js index 3413856..86d6963 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,14 +1,11 @@ -import { dirname, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; +import { resolve } from "node:path"; import { defineConfig } from "vite"; -const __dirname = dirname(fileURLToPath(import.meta.url)); - export default defineConfig({ build: { lib: { name: "GtfsReactHooks", - entry: resolve(__dirname, "lib/index.js"), + entry: resolve(import.meta.dirname, "lib/index.js"), fileName: "gtfs-react-hooks", formats: ["es"], }, From fb6e9fb8cbab2cd340cd5b45d716a83ec9ed0a4a Mon Sep 17 00:00:00 2001 From: benmelz Date: Thu, 14 May 2026 11:54:11 -0400 Subject: [PATCH 5/6] update workflows --- .github/actions/setup/action.yml | 15 --------------- .github/workflows/integrate.yml | 7 +++++-- 2 files changed, 5 insertions(+), 17 deletions(-) delete mode 100644 .github/actions/setup/action.yml diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml deleted file mode 100644 index cf2bf59..0000000 --- a/.github/actions/setup/action.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: setup -description: Set up repository -inputs: - environment: - description: Environment to set up repository for - required: true - default: development -runs: - using: composite - steps: - - uses: actions/setup-node@v6 - with: - node-version-file: .node-version - - run: npm ci - shell: bash diff --git a/.github/workflows/integrate.yml b/.github/workflows/integrate.yml index 705276c..72a035e 100644 --- a/.github/workflows/integrate.yml +++ b/.github/workflows/integrate.yml @@ -1,9 +1,12 @@ on: workflow_call: jobs: - eslint: + oxfmt: name: vite - uses: umts/.github/.github/workflows/eslint.yml@main + uses: umts/.github/.github/workflows/oxfmt.yml@main + oxlint: + name: vite + uses: umts/.github/.github/workflows/oxlint.yml@main vite: name: vite uses: umts/.github/.github/workflows/vite.yml@main From 6d5476d44d07d0d0364a263241f238394bdd90a8 Mon Sep 17 00:00:00 2001 From: benmelz Date: Thu, 14 May 2026 11:55:49 -0400 Subject: [PATCH 6/6] fmt --- lib/useGtfsSchedule.js | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/useGtfsSchedule.js b/lib/useGtfsSchedule.js index 1c24d2a..ad87efa 100644 --- a/lib/useGtfsSchedule.js +++ b/lib/useGtfsSchedule.js @@ -13,22 +13,21 @@ export default function useGtfsSchedule(resolve, timeout, retry = 1000) { setData(undefined); } else { // oxlint-disable-next-line promise/catch-or-return - JSZip.loadAsync(rawScheduleData) - .then((zip) => { - const parses = []; - for (const [filename, file] of Object.entries(zip.files)) { - const parse = file - .async("text") - .then(parseCsv) - .then((json) => { - dataCache.current[camelCase(removeExtension(filename))] = json; - setData({ ...dataCache.current }); - return json; - }) - parses.push(parse); - } - return Promise.all(parses); - }) + JSZip.loadAsync(rawScheduleData).then((zip) => { + const parses = []; + for (const [filename, file] of Object.entries(zip.files)) { + const parse = file + .async("text") + .then(parseCsv) + .then((json) => { + dataCache.current[camelCase(removeExtension(filename))] = json; + setData({ ...dataCache.current }); + return json; + }); + parses.push(parse); + } + return Promise.all(parses); + }); } }, [rawScheduleData]); return data;