diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 577d54a5..00000000 --- a/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -!.* -*-polyfill.* -dist diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 01103561..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,39 +0,0 @@ -/** @type {import('eslint').Linter.Config} */ -const config = { - root: true, - - env: { - node: true, - es2024: true - }, - - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - ecmaFeatures: { - impliedStrict: true - } - }, - - extends: ['eslint:recommended', 'prettier'], - - rules: { - 'no-var': 'error', - 'no-await-in-loop': 'error', - 'no-implicit-globals': ['error'], - 'no-unused-vars': ['error', { vars: 'local', argsIgnorePattern: '^_' }], - 'no-useless-rename': ['error'], - 'arrow-body-style': ['error', 'as-needed'], - 'no-lonely-if': 'error', - 'prefer-object-has-own': 'error', - 'prefer-exponentiation-operator': 'error', - 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }], - 'array-callback-return': ['error', { checkForEach: true, allowVoid: true }], - 'no-constant-binary-expression': 'error', // default in 'eslint:recommended' since v9 - 'no-constructor-return': 'error', - 'no-empty-static-block': 'error', // default in 'eslint:recommended' since v9 - 'no-unmodified-loop-condition': 'error' - } -}; - -module.exports = config; diff --git a/.prettierrc.mjs b/.prettierrc.js similarity index 100% rename from .prettierrc.mjs rename to .prettierrc.js diff --git a/babel.config.mjs b/babel.config.js similarity index 100% rename from babel.config.mjs rename to babel.config.js diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..a7653de3 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,90 @@ +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import Module from 'node:module'; + +import eslintJs from '@eslint/js'; +import prettierConfig from 'eslint-config-prettier'; +import globals from 'globals'; + +const require = Module.createRequire(import.meta.url); +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** @type {'module' | 'commonjs'} */ +const defaultSourceType = + require(join(__dirname, 'package.json')).type ?? 'commonjs'; + +/** @type {import('eslint').Linter.FlatConfig[]} */ +export default [ + eslintJs.configs.recommended, + prettierConfig, + + { + linterOptions: { + reportUnusedDisableDirectives: 'error' + }, + + languageOptions: { + sourceType: defaultSourceType, + parserOptions: { + ecmaFeatures: { + impliedStrict: true + } + }, + globals: { + ...globals.nodeBuiltin + } + }, + + rules: { + 'no-var': 'error', + 'no-await-in-loop': 'error', + 'no-implicit-globals': ['error'], + 'no-unused-vars': ['error', { vars: 'local', argsIgnorePattern: '^_' }], + 'no-useless-rename': ['error'], + 'arrow-body-style': ['error', 'as-needed'], + 'no-lonely-if': 'error', + 'prefer-object-has-own': 'error', + 'prefer-exponentiation-operator': 'error', + 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }], + 'array-callback-return': [ + 'error', + { checkForEach: true, allowVoid: true } + ], + 'no-constant-binary-expression': 'error', // default in 'eslint:recommended' since v9 + 'no-constructor-return': 'error', + 'no-empty-static-block': 'error', // default in 'eslint:recommended' since v9 + 'no-unmodified-loop-condition': 'error' + } + }, + + { + files: ['src/**/*'], + languageOptions: { + globals: { + ...globals.browser + } + } + }, + + { + // Why doesn't ESLint do this by default is beyond me. + files: ['**/*.cjs'], + languageOptions: { + sourceType: 'commonjs' + } + }, + + { + // Why doesn't ESLint do this by default is beyond me. + files: ['**/*.mjs'], + languageOptions: { + sourceType: 'module' + } + }, + + { + // `ignores` field must be in the very bottom config. + ignores: ['dist/**/*', '**/*-polyfill.*'] + } +]; diff --git a/package-lock.json b/package-lock.json index f2f537c3..799e2808 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@babel/core": "^7.24.3", "@babel/plugin-transform-runtime": "^7.24.3", "@babel/preset-env": "^7.24.3", + "@eslint/js": "^8.57.0", "@types/babel__core": "^7.20.5", "@webos-tools/cli": "^3.0.2", "babel-loader": "^9.1.3", @@ -28,6 +29,7 @@ "css-loader": "^6.10.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", + "globals": "^15.0.0", "husky": "^9.0.11", "lint-staged": "^15.2.2", "prettier": "^3.2.5", @@ -901,6 +903,15 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.24.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", @@ -1730,6 +1741,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { "version": "7.24.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", @@ -8993,12 +9013,15 @@ "dev": true }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.0.0.tgz", + "integrity": "sha512-m/C/yR4mjO6pXDTm9/R/SpYTAIyaUB4EOzcaaMEl7mds7Mshct9GfejiJNQGjHHbdMPey13Kpu4TMbYi9ex1pw==", "dev": true, "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globby": { diff --git a/package.json b/package.json index 4665a045..fede2397 100644 --- a/package.json +++ b/package.json @@ -2,17 +2,18 @@ "name": "youtube-webos", "version": "0.3.2", "description": "Ad-free YouTube app for webOS", + "type": "module", "main": "index.js", "scripts": { "build": "webpack --mode=production", "build:dev": "webpack --mode=development", "package": "ares-package -n dist", - "deploy": "node tools/deploy.mjs", + "deploy": "node tools/deploy.js", "launch": "ares-launch youtube.leanback.v4", - "manifest": "node tools/gen-manifest.js youtube.leanback.v4.manifest.json", - "version": "node tools/sync-version.js && git add assets/appinfo.json", + "manifest": "node tools/gen-manifest.cjs youtube.leanback.v4.manifest.json", + "version": "node tools/sync-version.cjs && git add assets/appinfo.json", "prepare": "husky install", - "lint": "eslint . --report-unused-disable-directives --max-warnings 0", + "lint": "eslint .", "prettier-check": "prettier --ignore-path .prettierignore --check ." }, "repository": "github:webosbrew/youtube-webos", @@ -30,6 +31,7 @@ "@babel/core": "^7.24.3", "@babel/plugin-transform-runtime": "^7.24.3", "@babel/preset-env": "^7.24.3", + "@eslint/js": "^8.57.0", "@types/babel__core": "^7.20.5", "@webos-tools/cli": "^3.0.2", "babel-loader": "^9.1.3", @@ -39,6 +41,7 @@ "css-loader": "^6.10.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", + "globals": "^15.0.0", "husky": "^9.0.11", "lint-staged": "^15.2.2", "prettier": "^3.2.5", diff --git a/src/.eslintrc.js b/src/.eslintrc.js deleted file mode 100644 index dfc11c26..00000000 --- a/src/.eslintrc.js +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-env node */ - -/** @type {import('eslint').Linter.Config} */ -const config = { - env: { - browser: true, - node: false - } -}; - -module.exports = config; diff --git a/tools/deploy.mjs b/tools/deploy.js similarity index 100% rename from tools/deploy.mjs rename to tools/deploy.js diff --git a/tools/gen-manifest.js b/tools/gen-manifest.cjs similarity index 100% rename from tools/gen-manifest.js rename to tools/gen-manifest.cjs diff --git a/tools/sync-version.js b/tools/sync-version.cjs similarity index 100% rename from tools/sync-version.js rename to tools/sync-version.cjs diff --git a/tsconfig.tooling.json b/tsconfig.tooling.json index b085334c..ffb86d4d 100644 --- a/tsconfig.tooling.json +++ b/tsconfig.tooling.json @@ -3,5 +3,5 @@ "compilerOptions": { "checkJs": true }, - "include": ["./*", "./.*", "./**/.eslintrc.js"] + "include": ["./*", "./.*"] } diff --git a/webpack.config.mjs b/webpack.config.js similarity index 92% rename from webpack.config.mjs rename to webpack.config.js index 9dc5f319..45f2b76a 100644 --- a/webpack.config.mjs +++ b/webpack.config.js @@ -25,6 +25,7 @@ const makeConfig = () => [ rules: [ { test: /\.(?:m|c)?js$/i, + loader: 'babel-loader', exclude: [ // Some module should not be transpiled by Babel @@ -35,6 +36,10 @@ const makeConfig = () => [ ], options: { cacheDirectory: true + }, + resolve: { + // File extension DON'T MATTER in a bundler. + fullySpecified: false } }, {