diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bd9343..3777a11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,27 +1,13 @@ name: CI on: push: - paths: - - ".github/workflows/ci.yml" - - ".github/workflows/release.yml" - - "hatch_build.py" - - "package.json" - - "pyproject.toml" - - "rollup.config.js" - - "run.ts" - - "src/**" - - "yt_dlp_ejs/**" + paths-ignore: + - 'README.md' + - 'LICENSE' pull_request: - paths: - - ".github/workflows/ci.yml" - - ".github/workflows/release.yml" - - "hatch_build.py" - - "package.json" - - "pyproject.toml" - - "rollup.config.js" - - "run.ts" - - "src/**" - - "yt_dlp_ejs/**" + paths-ignore: + - 'README.md' + - 'LICENSE' permissions: contents: read @@ -31,6 +17,56 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: + ruff-format: + name: Ruff format check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: astral-sh/ruff-action@v3 + with: + args: "check --output-format github" + + ruff-lint: + name: Ruff linting check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: astral-sh/ruff-action@v3 + with: + args: "format --check --diff" + + prettier: + name: Prettier check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Install Deno v2.x (latest) + uses: denoland/setup-deno@v2 + with: + deno-version: v2.x + - name: Install Deno requirements + run: | + deno install + - name: Run Prettier check + run: | + deno task fmt:check + + eslint: + name: ESLint check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Install Deno v2.x (latest) + uses: denoland/setup-deno@v2 + with: + deno-version: v2.x + - name: Install Deno requirements + run: | + deno install + - name: Run ESLint check + run: | + deno task lint + python_tests: name: Python tests runs-on: ubuntu-latest @@ -304,7 +340,17 @@ jobs: node --test all_passed: - needs: [deno_build, deno_tests, bun_build, bun_tests, node_build, node_tests] + needs: + - ruff-format + - ruff-lint + - prettier + - eslint + - deno_build + - deno_tests + - bun_build + - bun_tests + - node_build + - node_tests runs-on: ubuntu-latest steps: - name: All checks passed diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..2dc3b7e --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,14 @@ +import js from "@eslint/js"; +import globals from "globals"; +import tseslint from "typescript-eslint"; +import { defineConfig } from "eslint/config"; + +export default defineConfig([ + { + files: ["**/*.{js,mjs,cjs,ts,mts,cts}"], + plugins: { js }, + extends: ["js/recommended"], + languageOptions: { globals: globals.node }, + }, + tseslint.configs.recommended, +]); diff --git a/hatch_build.py b/hatch_build.py index 65a5285..09a40f3 100644 --- a/hatch_build.py +++ b/hatch_build.py @@ -28,12 +28,15 @@ class CustomBuildHook(BuildHookInterface): else: raise RuntimeError( "One of 'deno', 'bun', or 'npm' could not be found. " - "Please install one of them to proceed with the build.") + "Please install one of them to proceed with the build." + ) - build_data["force_include"].update({ - "dist/yt.solver.core.min.js": "yt_dlp_ejs/yt/solver/core.min.js", - "dist/yt.solver.lib.min.js": "yt_dlp_ejs/yt/solver/lib.min.js", - }) + build_data["force_include"].update( + { + "dist/yt.solver.core.min.js": "yt_dlp_ejs/yt/solver/core.min.js", + "dist/yt.solver.lib.min.js": "yt_dlp_ejs/yt/solver/lib.min.js", + } + ) def clean(self, versions): shutil.rmtree("node_modules", ignore_errors=True) diff --git a/package.json b/package.json index 1ebb0c0..89fe89d 100644 --- a/package.json +++ b/package.json @@ -3,21 +3,27 @@ "type": "module", "scripts": { "bundle": "rollup -c", - "fmt": "prettier --write \"src/**.ts\" \"package.json\" \"rollup.config.js\" \"run.ts\"" + "fmt": "prettier --write \"src/**.ts\" \"package.json\" \"rollup.config.js\" \"run.ts\" \"eslint.config.js\"", + "fmt:check": "prettier --check \"src/**.ts\" \"package.json\" \"rollup.config.js\" \"run.ts\" \"eslint.config.js\"", + "lint": "eslint src" }, "dependencies": { "astring": "1.9.0", "meriyah": "6.1.4" }, "devDependencies": { + "@eslint/js": "9.38.0", "@rollup/plugin-node-resolve": "16.0.3", "@rollup/plugin-sucrase": "5.0.2", "@rollup/plugin-terser": "0.4.4", - "rollup-plugin-license": "3.6.0", "@types/bun": "1.3.0", "@types/deno": "2.5.0", "@types/node": "24.8.1", + "eslint": "9.38.0", + "globals": "16.4.0", + "prettier": "3.6.2", "rollup": "4.52.5", - "prettier": "3.6.2" + "rollup-plugin-license": "3.6.0", + "typescript-eslint": "8.46.2" } } diff --git a/pyproject.toml b/pyproject.toml index 3e8e720..f3b4786 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,11 @@ classifiers = [ ] dependencies = [] +[dependency-groups] +dev = [ + "ruff>=0.14.1", +] + [project.urls] Documentation = "https://github.com/yt-dlp/ejs#readme" Issues = "https://github.com/yt-dlp/ejs/issues" @@ -51,3 +56,33 @@ packages = ["yt_dlp_ejs"] version-file = "yt_dlp_ejs/_version.py" [tool.hatch.build.targets.wheel.hooks.custom] + +[tool.ruff.lint] +select = [ + "C4", + "E", + "F", + "I", + "PLC", + "PLE", + "PLW", + "PYI", + "RET", + "RUF", + "SIM", + "TD", + "TID", + "W", +] +ignore = [ + "TD003", + "E402", + "E501", + "PLR09", +] + +[tool.ruff.lint.isort] +force-single-line = true + +[tool.ruff.lint.flake8-tidy-imports] +ban-relative-imports = "all" diff --git a/rollup.config.js b/rollup.config.js index d5c9d31..ea6cffc 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -31,7 +31,9 @@ function printHash() { for (const [fileName, assetInfo] of Object.entries(bundle)) { if (assetInfo.code) { try { - const digest = createHash("sha3-512").update(assetInfo.code).digest("hex"); + const digest = createHash("sha3-512") + .update(assetInfo.code) + .digest("hex"); console.log(`SHA3-512 for ${assetInfo.fileName}: ${digest}`); } catch (err) { console.error(`Error hashing ${fileName}:`, err.message); diff --git a/src/utils.ts b/src/utils.ts index a3553a0..9580668 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -25,7 +25,9 @@ export function matchesStructure( if ("anykey" in structure && Array.isArray(structure.anykey)) { // Handle `{ anykey: [a, b] }` const haystack = Array.isArray(obj) ? obj : Object.values(obj); - return structure.anykey.every(value => haystack.some((el) => matchesStructure(el, value))); + return structure.anykey.every((value) => + haystack.some((el) => matchesStructure(el, value)), + ); } for (const [key, value] of Object.entries(structure)) { if (!matchesStructure(obj[key as keyof typeof obj], value)) { diff --git a/src/yt/solver/test/io.ts b/src/yt/solver/test/io.ts index a7ae0aa..bbfd929 100644 --- a/src/yt/solver/test/io.ts +++ b/src/yt/solver/test/io.ts @@ -24,6 +24,7 @@ export async function getIO(): Promise { async function _getIO(): Promise { // Old Deno requires casting to any as globalThis lacks an index signature + // eslint-disable-next-line @typescript-eslint/no-explicit-any if ((globalThis as any).process?.release?.name === "node") { // Assume node compatibility const { access, readFile } = await import("node:fs/promises"); diff --git a/test/test_modules.py b/test/test_modules.py index 7549237..e98e65f 100644 --- a/test/test_modules.py +++ b/test/test_modules.py @@ -4,15 +4,21 @@ from pathlib import Path import yt_dlp_ejs.yt.solver BASE_PATH = Path(__file__).parent.parent -CORE_PATH = BASE_PATH / 'yt_dlp_ejs/yt/solver/core.min.js' -LIB_PATH = BASE_PATH / 'yt_dlp_ejs/yt/solver/lib.min.js' +CORE_PATH = BASE_PATH / "yt_dlp_ejs/yt/solver/core.min.js" +LIB_PATH = BASE_PATH / "yt_dlp_ejs/yt/solver/lib.min.js" class TestModules(unittest.TestCase): def test_yt_solver(self): - self.assertEqual(yt_dlp_ejs.yt.solver.core(), CORE_PATH.read_text(encoding='utf-8')) - self.assertEqual(yt_dlp_ejs.yt.solver.lib(), LIB_PATH.read_text(encoding='utf-8')) + self.assertEqual( + yt_dlp_ejs.yt.solver.core(), + CORE_PATH.read_text(encoding="utf-8"), + ) + self.assertEqual( + yt_dlp_ejs.yt.solver.lib(), + LIB_PATH.read_text(encoding="utf-8"), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/yt_dlp_ejs/__init__.py b/yt_dlp_ejs/__init__.py index ceb8d4d..9d7217e 100644 --- a/yt_dlp_ejs/__init__.py +++ b/yt_dlp_ejs/__init__.py @@ -1,7 +1,3 @@ from yt_dlp_ejs._version import version -from yt_dlp_ejs import yt -__all__ = [ - "version", - "yt" -] +__all__ = ["version"] diff --git a/yt_dlp_ejs/yt/__init__.py b/yt_dlp_ejs/yt/__init__.py index 2e3887a..e69de29 100644 --- a/yt_dlp_ejs/yt/__init__.py +++ b/yt_dlp_ejs/yt/__init__.py @@ -1,3 +0,0 @@ -from . import solver - -__all__ = ["solver"] \ No newline at end of file diff --git a/yt_dlp_ejs/yt/solver/__init__.py b/yt_dlp_ejs/yt/solver/__init__.py index 7e53f27..1bd323e 100644 --- a/yt_dlp_ejs/yt/solver/__init__.py +++ b/yt_dlp_ejs/yt/solver/__init__.py @@ -2,6 +2,7 @@ import importlib.resources import yt_dlp_ejs.yt.solver + def core() -> str: """ Read the contents of the JavaScript core solver bundle as string.