mirror of
https://github.com/jellyfin/jellyfin-vue.git
synced 2024-11-23 05:59:55 +00:00
chore: finish monorepo setup
Signed-off-by: Fernando Fernández <ferferga@hotmail.com>
This commit is contained in:
parent
4c4cdbc9db
commit
cb89d94228
2
.github/workflows/__deploy.yml
vendored
2
.github/workflows/__deploy.yml
vendored
@ -22,7 +22,7 @@ env:
|
||||
|
||||
jobs:
|
||||
cf-pages:
|
||||
name: CloudFlare Pages 📃
|
||||
name: Cloudflare Pages 📃
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: ${{ inputs.branch == 'master' && 'Production' || 'Preview' }}
|
||||
|
2
.github/workflows/__job_messages.yml
vendored
2
.github/workflows/__job_messages.yml
vendored
@ -29,7 +29,7 @@ env:
|
||||
|
||||
jobs:
|
||||
cf_pages_msg:
|
||||
name: CloudFlare Pages deployment 📃🚀
|
||||
name: Cloudflare Pages deployment 📃🚀
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
9
.github/workflows/__quality_checks.yml
vendored
9
.github/workflows/__quality_checks.yml
vendored
@ -36,10 +36,9 @@ jobs:
|
||||
command:
|
||||
- lint
|
||||
- check:types
|
||||
- analyze:cycles
|
||||
defaults:
|
||||
run:
|
||||
working-directory: frontend
|
||||
include:
|
||||
- workspace: frontend
|
||||
command: analyze:cycles
|
||||
|
||||
steps:
|
||||
- name: Checkout ⬇️
|
||||
@ -59,7 +58,7 @@ jobs:
|
||||
run: npm ci --no-audit
|
||||
|
||||
- name: Run ${{ matrix.command }} ⚙️
|
||||
run: npm run ${{ matrix.command }}
|
||||
run: npm run ${{ matrix.command }} ${{ matrix.workspace && format('-w {0}', matrix.workspace) || '' }}
|
||||
|
||||
commits_checks:
|
||||
name: Commit linting 💬✅
|
||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -28,6 +28,9 @@
|
||||
"javascript",
|
||||
"typescript"
|
||||
],
|
||||
"eslint.options": {
|
||||
"flags": ["unstable_ts_config"]
|
||||
},
|
||||
"eslint.format.enable": true,
|
||||
"eslint.useFlatConfig": true,
|
||||
"eslint.workingDirectories": [
|
||||
|
@ -1,403 +0,0 @@
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
import unicorn from 'eslint-plugin-unicorn';
|
||||
import eslintImportX from 'eslint-plugin-import-x';
|
||||
import fileProgress from 'eslint-plugin-file-progress';
|
||||
import promise from 'eslint-plugin-promise';
|
||||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import vueScopedCSS from 'eslint-plugin-vue-scoped-css';
|
||||
import css from 'eslint-plugin-css';
|
||||
import vue from 'eslint-plugin-vue';
|
||||
import i18n from '@intlify/eslint-plugin-vue-i18n';
|
||||
import gitignore from 'eslint-config-flat-gitignore';
|
||||
import stylistic from '@stylistic/eslint-plugin';
|
||||
import sonarjs from 'eslint-plugin-sonarjs';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import jsonc from 'eslint-plugin-jsonc';
|
||||
import regexp from 'eslint-plugin-regexp';
|
||||
import { configs as dependConfigs } from 'eslint-plugin-depend';
|
||||
import unocss from '@unocss/eslint-config/flat';
|
||||
|
||||
const tsFiles = ['*.ts', '**/*.ts'];
|
||||
const vueFiles = ['*.vue', '**/*.vue'];
|
||||
const vueAndTsFiles = [...vueFiles, ...tsFiles];
|
||||
const CI_environment = process.env.CI ? 0 : 1;
|
||||
const jsoncRecommended = jsonc.configs['flat/recommended-with-json'];
|
||||
const eqeqeqConfig = ['error', 'always', { null: 'ignore' }];
|
||||
|
||||
/**
|
||||
* Util functions
|
||||
*/
|
||||
const flatArrayOfObjects = obj => Object.assign({}, ...obj);
|
||||
|
||||
export default tseslint.config(
|
||||
/** Global settings */
|
||||
{ ...js.configs.recommended,
|
||||
name: '(eslint) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
...unicorn.configs['flat/recommended'],
|
||||
name: '(unicorn) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
...dependConfigs['flat/recommended'],
|
||||
name: '(depend) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
...unocss,
|
||||
name: '(unocss) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
...stylistic.configs.customize({
|
||||
quotes: 'single',
|
||||
semi: true,
|
||||
commaDangle: 'never',
|
||||
braceStyle: '1tbs',
|
||||
arrowParens: false,
|
||||
blockSpacing: true
|
||||
}),
|
||||
name: '(@stylistic) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
name: 'Common settings',
|
||||
languageOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: 'module',
|
||||
globals: {
|
||||
...globals.browser
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
'no-empty': ['error', { allowEmptyCatch: true }],
|
||||
'no-extend-native': 'error',
|
||||
'curly': ['error', 'all'],
|
||||
'prefer-arrow-callback': 'error',
|
||||
'multiline-comment-style': 'error',
|
||||
'unicode-bom': ['error', 'never'],
|
||||
'eqeqeq': eqeqeqConfig,
|
||||
'@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
|
||||
'@stylistic/linebreak-style': ['error', 'unix'],
|
||||
'unicorn/import-style': 'off',
|
||||
'unicorn/filename-case': 'off',
|
||||
'unicorn/consistent-function-scoping': 'off',
|
||||
'unicorn/prevent-abbreviations': 'off',
|
||||
'unicorn/no-await-expression-member': 'off',
|
||||
/**
|
||||
* See https://github.com/jellyfin/jellyfin-vue/pull/2361
|
||||
*/
|
||||
'unicorn/explicit-length-check': 'off',
|
||||
'@stylistic/padding-line-between-statements': [
|
||||
'error',
|
||||
// Always require blank lines after import, except between imports
|
||||
{ blankLine: 'always', prev: 'import', next: '*' },
|
||||
{ blankLine: 'never', prev: 'import', next: 'import' },
|
||||
// Always require blank lines before and after every sequence of variable declarations and export
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: '*',
|
||||
next: ['const', 'let', 'var', 'export']
|
||||
},
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: ['const', 'let', 'var', 'export'],
|
||||
next: '*'
|
||||
},
|
||||
{
|
||||
blankLine: 'any',
|
||||
prev: ['const', 'let', 'var', 'export'],
|
||||
next: ['const', 'let', 'var', 'export']
|
||||
},
|
||||
{
|
||||
blankLine: 'any',
|
||||
prev: ['block-like'],
|
||||
next: '*'
|
||||
},
|
||||
// Always require blank lines before and after class declaration, if, do/while, switch, try
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: '*',
|
||||
next: ['if', 'class', 'for', 'do', 'while', 'switch', 'try']
|
||||
},
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: ['if', 'class', 'for', 'do', 'while', 'switch', 'try'],
|
||||
next: '*'
|
||||
},
|
||||
// Always require blank lines before return statements
|
||||
{ blankLine: 'always', prev: '*', next: 'return' }
|
||||
]
|
||||
}
|
||||
},
|
||||
/** Common TypeScript rules */
|
||||
{
|
||||
name: '(TypeScript & Vue) - Parser config',
|
||||
files: vueAndTsFiles,
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
warnOnUnsupportedTypeScriptVersion: false,
|
||||
extraFileExtensions: ['.vue']
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
...flatArrayOfObjects(tseslint.configs.strictTypeChecked),
|
||||
name: '(typescript-eslint) Extended config from plugin (strict type checking)',
|
||||
files: vueAndTsFiles
|
||||
},
|
||||
{
|
||||
...flatArrayOfObjects(tseslint.configs.stylisticTypeChecked),
|
||||
name: '(typescript-eslint) Extended config from plugin (stylistic type checking)',
|
||||
files: vueAndTsFiles
|
||||
},
|
||||
{
|
||||
...tseslint.configs.eslintRecommended,
|
||||
files: vueAndTsFiles,
|
||||
name: '(typescript-eslint) Extended config from plugin (ESLint rules with type checking)'
|
||||
},
|
||||
{
|
||||
...regexp.configs['flat/recommended'],
|
||||
name: '(regexp) Extended config from plugin',
|
||||
files: vueAndTsFiles
|
||||
},
|
||||
{
|
||||
...promise.configs['flat/recommended'],
|
||||
name: '(promise) Extended config from plugin',
|
||||
files: vueAndTsFiles
|
||||
},
|
||||
{
|
||||
name: '(promise) Custom config',
|
||||
files: vueAndTsFiles,
|
||||
rules: {
|
||||
'promise/prefer-await-to-callbacks': 'error',
|
||||
'promise/prefer-await-to-then': 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '(import) Custom config',
|
||||
// TODO: Remove .js after: https://github.com/eslint/eslint/pull/18134
|
||||
files: [...vueAndTsFiles, '**/*.js'],
|
||||
plugins: {
|
||||
'import-x': eslintImportX
|
||||
},
|
||||
rules: {
|
||||
'import-x/no-extraneous-dependencies': 'error',
|
||||
'import-x/order': 'error',
|
||||
'import-x/no-cycle': 'error',
|
||||
'import-x/no-nodejs-modules': 'error',
|
||||
'import-x/no-duplicates': ['error', { 'prefer-inline': true, 'considerQueryString': true }],
|
||||
// From the recommended preset
|
||||
'import-x/named': 'error',
|
||||
'import-x/export': 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: vueAndTsFiles,
|
||||
name: '(JSDoc) Custom config',
|
||||
plugins: {
|
||||
jsdoc
|
||||
},
|
||||
rules: {
|
||||
'jsdoc/require-hyphen-before-param-description': 'error',
|
||||
'jsdoc/require-description': 'error',
|
||||
'jsdoc/no-types': 'error',
|
||||
'jsdoc/require-jsdoc': 'error',
|
||||
'jsdoc/informative-docs': 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '(TypeScript & Vue) Custom config',
|
||||
files: vueAndTsFiles,
|
||||
rules: {
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
||||
'@typescript-eslint/restrict-template-expressions': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-dynamic-delete': 'off',
|
||||
'@typescript-eslint/no-import-type-side-effects': 'error',
|
||||
'@typescript-eslint/consistent-type-exports': 'error',
|
||||
'@typescript-eslint/explicit-member-accessibility': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': ['error', {
|
||||
prefer: 'type-imports',
|
||||
fixStyle: 'inline-type-imports'
|
||||
}],
|
||||
'@typescript-eslint/no-confusing-void-expression': ['error', { ignoreArrowShorthand: true }],
|
||||
'@typescript-eslint/no-empty-object-type': ['error', { allowInterfaces: 'with-single-extends' }],
|
||||
'vue/return-in-computed-property': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
...sonarjs.configs.recommended,
|
||||
name: '(sonarcloud) Extended config from plugin',
|
||||
files: vueAndTsFiles
|
||||
},
|
||||
/** SFC rules */
|
||||
...vue.configs['flat/recommended'].map((config) => {
|
||||
/**
|
||||
* Specified above, unnecessary to overwrite
|
||||
*/
|
||||
delete config.languageOptions?.globals;
|
||||
/**
|
||||
* DEPRECATED: See https://eslint.vuejs.org/rules/component-tags-order.html#vue-component-tags-order
|
||||
* TODO: Remove when it's removed from the recommended rules
|
||||
*/
|
||||
delete config.rules?.['vue/component-tags-order'];
|
||||
config.name = `(${config.name}) - Extended config from plugin`;
|
||||
|
||||
return config;
|
||||
}),
|
||||
{
|
||||
...flatArrayOfObjects(vueScopedCSS.configs['flat/recommended']),
|
||||
name: '(Vue - Scoped CSS) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
...css.configs['flat/recommended'],
|
||||
name: '(Vue - CSS) Extended config from plugin',
|
||||
files: [...vueFiles]
|
||||
},
|
||||
{
|
||||
name: '(Vue) Custom config',
|
||||
files: vueFiles,
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
parser: tseslint.parser
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
'vue/component-name-in-template-casing': [
|
||||
'error',
|
||||
'PascalCase',
|
||||
{
|
||||
registeredComponentsOnly: false
|
||||
}
|
||||
],
|
||||
'vue/define-macros-order': ['error', {
|
||||
order: ['defineOptions', 'defineProps', 'defineEmits', 'defineSlots']
|
||||
}],
|
||||
'vue/html-closing-bracket-newline': ['error', { multiline: 'never' }],
|
||||
'vue/block-order': ['error', {
|
||||
order: ['template', 'script:not([setup])', 'script[setup]']
|
||||
}],
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/eqeqeq': eqeqeqConfig
|
||||
}
|
||||
},
|
||||
{
|
||||
/* First index is just the plugin definition */
|
||||
...jsoncRecommended.at(0),
|
||||
...jsoncRecommended.at(1),
|
||||
name: '(JSON) Custom config',
|
||||
rules: {
|
||||
...jsoncRecommended.at(1).rules,
|
||||
...jsoncRecommended.at(2).rules,
|
||||
'jsonc/auto': 'error',
|
||||
'@stylistic/quotes': ['error', 'double'],
|
||||
'@stylistic/semi': 'off',
|
||||
'@stylistic/quote-props': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
/* First index is just the plugin definition */
|
||||
...i18n.configs['flat/recommended'].at(0),
|
||||
/* Last contains the rule definitions */
|
||||
...i18n.configs['flat/recommended'].at(-1),
|
||||
name: '(@intlify/vue-i18n) Extended config (plugin & settings)',
|
||||
settings: {
|
||||
'vue-i18n': {
|
||||
localeDir: 'locales/en.json',
|
||||
messageSyntaxVersion: '^9.0.0'
|
||||
}
|
||||
},
|
||||
files: vueAndTsFiles
|
||||
},
|
||||
{
|
||||
name: '(@intlify/vue-i18n) Custom config',
|
||||
files: vueAndTsFiles,
|
||||
rules: {
|
||||
'@intlify/vue-i18n/no-unused-keys': ['error', {
|
||||
extensions: ['.ts', '.vue', '.json'],
|
||||
enableFix: true
|
||||
}],
|
||||
'@intlify/vue-i18n/no-raw-text': ['error', {
|
||||
ignorePattern: '^[-#:()&.]+$'
|
||||
}],
|
||||
'@intlify/vue-i18n/no-duplicate-keys-in-locale': 'error',
|
||||
'@intlify/vue-i18n/no-dynamic-keys': 'error',
|
||||
'@intlify/vue-i18n/key-format-style': 'error'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* See the following:
|
||||
* - https://en.wikipedia.org/wiki/History_of_sentence_spacing#French_and_English_spacing
|
||||
* - https://docs.weblate.org/en/weblate-4.14.1/user/checks.html#check-punctuation-spacing
|
||||
*/
|
||||
{
|
||||
name: '(@intlify/vue-i18n - fr) Config exceptions for linguistic rules',
|
||||
files: ['locales/fr.json'],
|
||||
rules: {
|
||||
'no-irregular-whitespace': 'off'
|
||||
}
|
||||
},
|
||||
/** Settings for all the files that run in development */
|
||||
{
|
||||
name: 'Environment config - Node.js and development-related files',
|
||||
files: ['*.config.*', 'scripts/**/*.ts'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
...globals.nodeBuiltin
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
'import-x/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: true
|
||||
}
|
||||
],
|
||||
'import-x/no-nodejs-modules': 'off'
|
||||
}
|
||||
},
|
||||
/** Settings for WebWorkers (the pattern matches any file that ends in .worker.ts) */
|
||||
{
|
||||
name: 'Environment config - WebWorkers',
|
||||
files: ['**/*.worker.ts'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.worker
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
...stylistic.configs['disable-legacy'],
|
||||
name: 'Environment config - Disable legacy rules'
|
||||
},
|
||||
/**
|
||||
* Extra files to include and ignores that should override all the others
|
||||
*/
|
||||
{
|
||||
name: 'Environment config - Ignored files',
|
||||
ignores: [
|
||||
'**/.git',
|
||||
'types/global/routes.d.ts',
|
||||
'types/global/components.d.ts',
|
||||
...gitignore().ignores
|
||||
]
|
||||
},
|
||||
/** File progress plugin */
|
||||
{
|
||||
name: '(eslint) Linting progress report',
|
||||
settings: {
|
||||
progress: {
|
||||
successMessage: 'Linting done!'
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
'file-progress': fileProgress
|
||||
},
|
||||
rules: {
|
||||
'file-progress/activate': CI_environment
|
||||
}
|
||||
}
|
||||
);
|
11
frontend/eslint.config.ts
Normal file
11
frontend/eslint.config.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { Linter } from 'eslint';
|
||||
import { getBaseConfig, getTSVueConfig, getNodeFiles, unocss, getWorkerFiles } from '@jellyfin-vue/configs/eslint';
|
||||
|
||||
// TODO: Add missing rules for i18n and json
|
||||
export default [
|
||||
...getBaseConfig('@jellyfin-vue/frontend'),
|
||||
...getTSVueConfig(true, import.meta.dirname),
|
||||
...unocss,
|
||||
...getNodeFiles(),
|
||||
...getWorkerFiles()
|
||||
] satisfies Linter.Config[];
|
@ -8,8 +8,8 @@
|
||||
"scripts": {
|
||||
"analyze:bundle": "vite build --mode analyze:bundle",
|
||||
"analyze:cycles": "vite build --mode analyze:cycles",
|
||||
"lint": "eslint . --max-warnings=0 --cache --cache-location ../node_modules/.cache/eslint",
|
||||
"lint:fix": "eslint . --fix --max-warnings=0 --cache --cache-location ../node_modules/.cache/eslint",
|
||||
"lint": "eslint . --max-warnings=0 --flag unstable_ts_config",
|
||||
"lint:fix": "eslint . --fix --max-warnings=0 --flag unstable_ts_config",
|
||||
"lint:inspect": "eslint-config-inspector",
|
||||
"build": "vite build",
|
||||
"check": "npm run lint && npm run check:types",
|
||||
@ -47,45 +47,22 @@
|
||||
"vuetify": "3.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/config-inspector": "0.5.4",
|
||||
"@eslint/js": "9.10.0",
|
||||
"@iconify/json": "2.2.246",
|
||||
"@intlify/eslint-plugin-vue-i18n": "3.0.0",
|
||||
"@intlify/unplugin-vue-i18n": "4.0.0",
|
||||
"@jellyfin-vue/configs": "*",
|
||||
"@jellyfin-vue/vite-plugins": "*",
|
||||
"@rollup/plugin-virtual": "3.0.2",
|
||||
"@stylistic/eslint-plugin": "2.8.0",
|
||||
"@types/dompurify": "3.0.5",
|
||||
"@types/node": "22.5.4",
|
||||
"@types/sortablejs": "1.15.8",
|
||||
"@types/uuid": "10.0.0",
|
||||
"@unocss/eslint-config": "0.62.3",
|
||||
"@vitejs/plugin-vue": "5.1.3",
|
||||
"browserslist": "4.23.3",
|
||||
"eslint-config-flat-gitignore": "0.3.0",
|
||||
"eslint-plugin-css": "0.11.0",
|
||||
"eslint-plugin-depend": "0.11.0",
|
||||
"eslint-plugin-file-progress": "1.5.0",
|
||||
"eslint-plugin-import-x": "4.2.1",
|
||||
"eslint-plugin-jsdoc": "50.2.2",
|
||||
"eslint-plugin-jsonc": "2.16.0",
|
||||
"eslint-plugin-promise": "7.1.0",
|
||||
"eslint-plugin-regexp": "2.6.0",
|
||||
"eslint-plugin-sonarjs": "1.0.4",
|
||||
"eslint-plugin-unicorn": "55.0.0",
|
||||
"eslint-plugin-vue": "9.28.0",
|
||||
"eslint-plugin-vue-scoped-css": "2.8.1",
|
||||
"globals": "15.9.0",
|
||||
"lightningcss": "1.26.0",
|
||||
"typescript-eslint": "8.5.0",
|
||||
"unocss": "0.62.3",
|
||||
"unplugin-icons": "0.19.3",
|
||||
"unplugin-vue-components": "0.27.4",
|
||||
"unplugin-vue-router": "0.10.8",
|
||||
"vite": "5.4.6",
|
||||
"vite-plugin-vue-devtools": "7.4.4",
|
||||
"vue-eslint-parser": "9.4.3",
|
||||
"vue-tsc": "2.1.6"
|
||||
"vite-plugin-vue-devtools": "7.4.4"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@jellyfin-vue/configs/tsconfig.json",
|
||||
"extends": "@jellyfin-vue/configs/typescript/base.json",
|
||||
"compilerOptions": {
|
||||
"types": [
|
||||
"axios",
|
||||
|
@ -1,15 +1 @@
|
||||
import { defineConfig, presetUno } from 'unocss';
|
||||
|
||||
export default defineConfig({
|
||||
presets: [
|
||||
presetUno({
|
||||
prefix: 'uno-',
|
||||
preflight: false
|
||||
})
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
background: 'rgb(var(--j-color-background))'
|
||||
}
|
||||
}
|
||||
});
|
||||
export { defaultConfig as default } from '@jellyfin-vue/configs/unocss';
|
||||
|
334
package-lock.json
generated
334
package-lock.json
generated
@ -1,10 +1,9 @@
|
||||
{
|
||||
"name": "@jellyfin-vue",
|
||||
"name": "jellyfin-vue",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@jellyfin-vue",
|
||||
"license": "GPL-3.0-only",
|
||||
"workspaces": [
|
||||
"frontend",
|
||||
@ -12,8 +11,12 @@
|
||||
"packages/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"eslint": "9.10.0",
|
||||
"typescript": "5.6.2"
|
||||
"@eslint/config-inspector": "0.5.4",
|
||||
"@types/node": "22.5.4",
|
||||
"eslint": "9.12.0",
|
||||
"jiti": "2.3.3",
|
||||
"typescript": "5.6.2",
|
||||
"vue-tsc": "2.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.8.1 <21.0.0",
|
||||
@ -52,46 +55,23 @@
|
||||
"vuetify": "3.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/config-inspector": "0.5.4",
|
||||
"@eslint/js": "9.10.0",
|
||||
"@iconify/json": "2.2.246",
|
||||
"@intlify/eslint-plugin-vue-i18n": "3.0.0",
|
||||
"@intlify/unplugin-vue-i18n": "4.0.0",
|
||||
"@jellyfin-vue/configs": "*",
|
||||
"@jellyfin-vue/vite-plugins": "*",
|
||||
"@rollup/plugin-virtual": "3.0.2",
|
||||
"@stylistic/eslint-plugin": "2.8.0",
|
||||
"@types/dompurify": "3.0.5",
|
||||
"@types/node": "22.5.4",
|
||||
"@types/sortablejs": "1.15.8",
|
||||
"@types/uuid": "10.0.0",
|
||||
"@unocss/eslint-config": "0.62.3",
|
||||
"@vitejs/plugin-vue": "5.1.3",
|
||||
"browserslist": "4.23.3",
|
||||
"eslint-config-flat-gitignore": "0.3.0",
|
||||
"eslint-plugin-css": "0.11.0",
|
||||
"eslint-plugin-depend": "0.11.0",
|
||||
"eslint-plugin-file-progress": "1.5.0",
|
||||
"eslint-plugin-import-x": "4.2.1",
|
||||
"eslint-plugin-jsdoc": "50.2.2",
|
||||
"eslint-plugin-jsonc": "2.16.0",
|
||||
"eslint-plugin-promise": "7.1.0",
|
||||
"eslint-plugin-regexp": "2.6.0",
|
||||
"eslint-plugin-sonarjs": "1.0.4",
|
||||
"eslint-plugin-unicorn": "55.0.0",
|
||||
"eslint-plugin-vue": "9.28.0",
|
||||
"eslint-plugin-vue-scoped-css": "2.8.1",
|
||||
"globals": "15.9.0",
|
||||
"lightningcss": "1.26.0",
|
||||
"typescript-eslint": "8.5.0",
|
||||
"unocss": "0.62.3",
|
||||
"unplugin-icons": "0.19.3",
|
||||
"unplugin-vue-components": "0.27.4",
|
||||
"unplugin-vue-router": "0.10.8",
|
||||
"vite": "5.4.6",
|
||||
"vite-plugin-vue-devtools": "7.4.4",
|
||||
"vue-eslint-parser": "9.4.3",
|
||||
"vue-tsc": "2.1.6"
|
||||
"vite-plugin-vue-devtools": "7.4.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@ -729,9 +709,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz",
|
||||
"integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz",
|
||||
"integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1345,6 +1325,16 @@
|
||||
"eslint": "^8.50.0 || ^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/core": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz",
|
||||
"integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
|
||||
@ -1407,9 +1397,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz",
|
||||
"integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==",
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz",
|
||||
"integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -1427,9 +1417,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz",
|
||||
"integrity": "sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==",
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz",
|
||||
"integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@ -1445,6 +1435,30 @@
|
||||
"integrity": "sha512-p0fta2L9CMeTbC7rNYeKF0bcu+tUGb4NH5D/pHC0RUNW1I+rrBDXLoGYKaH4yNfxxMrsZ4k1fchgkCI4F9zIFQ==",
|
||||
"license": "OFL-1.1"
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz",
|
||||
"integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/node": {
|
||||
"version": "0.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz",
|
||||
"integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@humanfs/core": "^0.19.0",
|
||||
"@humanwhocodes/retry": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/module-importer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
||||
@ -1460,9 +1474,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/retry": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz",
|
||||
"integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
|
||||
"integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
@ -1673,9 +1687,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui/node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -2371,6 +2385,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz",
|
||||
@ -4472,29 +4493,32 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.10.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.10.0.tgz",
|
||||
"integrity": "sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==",
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz",
|
||||
"integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.11.0",
|
||||
"@eslint/config-array": "^0.18.0",
|
||||
"@eslint/core": "^0.6.0",
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
"@eslint/js": "9.10.0",
|
||||
"@eslint/plugin-kit": "^0.1.0",
|
||||
"@eslint/js": "9.12.0",
|
||||
"@eslint/plugin-kit": "^0.2.0",
|
||||
"@humanfs/node": "^0.16.5",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@humanwhocodes/retry": "^0.3.0",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
"@humanwhocodes/retry": "^0.3.1",
|
||||
"@types/estree": "^1.0.6",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"ajv": "^6.12.4",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
"debug": "^4.3.2",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^8.0.2",
|
||||
"eslint-visitor-keys": "^4.0.0",
|
||||
"espree": "^10.1.0",
|
||||
"eslint-scope": "^8.1.0",
|
||||
"eslint-visitor-keys": "^4.1.0",
|
||||
"espree": "^10.2.0",
|
||||
"esquery": "^1.5.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@ -4504,13 +4528,11 @@
|
||||
"ignore": "^5.2.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"is-path-inside": "^3.0.3",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"text-table": "^0.2.0"
|
||||
},
|
||||
"bin": {
|
||||
@ -4920,9 +4942,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz",
|
||||
"integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==",
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz",
|
||||
"integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
@ -4937,9 +4959,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-visitor-keys": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
|
||||
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz",
|
||||
"integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
@ -4964,43 +4986,12 @@
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||
"node_modules/eslint/node_modules/@types/estree": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "2.0.5",
|
||||
"run-parallel": "^1.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/@nodelib/fs.stat": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/@nodelib/fs.walk": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
||||
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.scandir": "2.1.5",
|
||||
"fastq": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/eslint/node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
@ -5128,15 +5119,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz",
|
||||
"integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==",
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz",
|
||||
"integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"acorn": "^8.12.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^4.0.0"
|
||||
"eslint-visitor-keys": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -5795,6 +5786,16 @@
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/importx/node_modules/jiti": {
|
||||
"version": "2.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.0.0-beta.2.tgz",
|
||||
"integrity": "sha512-c+PHQZakiQuMKbnhvrjZUvrK6E/AfmTOf4P+E3Y4FNVHcNMX9e/XrnbEvO+m4wS6ZjsvhHh/POQTlfy8uXFc0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
@ -5984,16 +5985,6 @@
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-path-inside": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
|
||||
"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
|
||||
@ -6069,9 +6060,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.0.0-beta.2.tgz",
|
||||
"integrity": "sha512-c+PHQZakiQuMKbnhvrjZUvrK6E/AfmTOf4P+E3Y4FNVHcNMX9e/XrnbEvO+m4wS6ZjsvhHh/POQTlfy8uXFc0A==",
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.3.3.tgz",
|
||||
"integrity": "sha512-EX4oNDwcXSivPrw2qKH2LB5PoFxEvgtv2JgwW0bU858HoLQ+kutSvjLMUqBd0PeJYEinLWhoI9Ol0eYMqj/wNQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@ -7062,9 +7053,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/package-json-from-dist": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
|
||||
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0"
|
||||
},
|
||||
@ -7122,13 +7113,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
|
||||
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.0.tgz",
|
||||
"integrity": "sha512-ZkDsAOcxsUMZ4Lz5fVciOehNcJ+Gb8gTzcA4yl3wnc273BAybYWrQ+Ks/OjCjSEpjvQkDSeZbybK9qj2VHHdGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"entities": "^4.4.0"
|
||||
"entities": "^4.5.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
@ -8095,9 +8086,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/string-width/node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -9761,9 +9752,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi/node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -9968,74 +9959,39 @@
|
||||
},
|
||||
"packages/configs": {
|
||||
"name": "@jellyfin-vue/configs",
|
||||
"version": "0.0.1"
|
||||
"version": "0.0.1",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.12.0",
|
||||
"@intlify/eslint-plugin-vue-i18n": "3.0.0",
|
||||
"@stylistic/eslint-plugin": "2.8.0",
|
||||
"@unocss/eslint-config": "0.62.3",
|
||||
"eslint-config-flat-gitignore": "0.3.0",
|
||||
"eslint-plugin-css": "0.11.0",
|
||||
"eslint-plugin-depend": "0.11.0",
|
||||
"eslint-plugin-file-progress": "1.5.0",
|
||||
"eslint-plugin-import-x": "4.2.1",
|
||||
"eslint-plugin-jsdoc": "50.2.2",
|
||||
"eslint-plugin-jsonc": "2.16.0",
|
||||
"eslint-plugin-promise": "7.1.0",
|
||||
"eslint-plugin-regexp": "2.6.0",
|
||||
"eslint-plugin-sonarjs": "1.0.4",
|
||||
"eslint-plugin-unicorn": "55.0.0",
|
||||
"eslint-plugin-vue": "9.28.0",
|
||||
"eslint-plugin-vue-scoped-css": "2.8.1",
|
||||
"find-up-simple": "1.0.0",
|
||||
"globals": "15.9.0",
|
||||
"typescript-eslint": "8.5.0",
|
||||
"unocss": "0.62.3",
|
||||
"vue-eslint-parser": "9.4.3"
|
||||
}
|
||||
},
|
||||
"packages/vite-plugins": {
|
||||
"name": "@jellyfin-vue/vite-plugins",
|
||||
"version": "0.0.1",
|
||||
"devDependencies": {
|
||||
"@jellyfin-vue/configs": "*",
|
||||
"rollup-plugin-visualizer": "5.12.0",
|
||||
"vite": "5.4.3"
|
||||
}
|
||||
},
|
||||
"packages/vite-plugins/node_modules/vite": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.3.tgz",
|
||||
"integrity": "sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
"rollup": "^4.20.0"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || >=20.0.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"lightningcss": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
"vite": "5.4.6"
|
||||
}
|
||||
},
|
||||
"packaging/tauri": {
|
||||
|
14
package.json
14
package.json
@ -1,5 +1,4 @@
|
||||
{
|
||||
"name": "@jellyfin-vue",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"homepage": "https://jellyfin.org/",
|
||||
@ -22,8 +21,17 @@
|
||||
"npm": ">=10.1.0",
|
||||
"yarn": "Yarn is not supported. Please use NPM."
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "npm run lint --workspaces",
|
||||
"lint:fix": "npm run lint:fix --workspaces",
|
||||
"check:types": "npm run check:types --workspaces"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "9.10.0",
|
||||
"typescript": "5.6.2"
|
||||
"@eslint/config-inspector": "0.5.4",
|
||||
"@types/node": "22.5.4",
|
||||
"eslint": "9.12.0",
|
||||
"jiti": "2.3.3",
|
||||
"typescript": "5.6.2",
|
||||
"vue-tsc": "2.1.6"
|
||||
}
|
||||
}
|
||||
|
8
packages/configs/eslint.config.ts
Normal file
8
packages/configs/eslint.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import type { Linter } from 'eslint';
|
||||
import { getBaseConfig } from './eslint/rules/base';
|
||||
import { getTSVueConfig } from './eslint/rules/typescript-vue';
|
||||
|
||||
export default [
|
||||
...getBaseConfig('@jellyfin-vue/configs'),
|
||||
...getTSVueConfig(false, import.meta.dirname)
|
||||
] satisfies Linter.Config[];
|
6
packages/configs/eslint/index.ts
Normal file
6
packages/configs/eslint/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export { getBaseConfig } from './rules/base';
|
||||
export { unocss } from './rules/unocss';
|
||||
export { getTSVueConfig } from './rules/typescript-vue';
|
||||
export { json } from './rules/json';
|
||||
export { getNodeFiles, getWorkerFiles } from './rules/env';
|
||||
export { i18n } from './rules/i18n';
|
147
packages/configs/eslint/rules/base.ts
Normal file
147
packages/configs/eslint/rules/base.ts
Normal file
@ -0,0 +1,147 @@
|
||||
import type { Linter } from 'eslint';
|
||||
/*
|
||||
* import { join } from 'node:path';
|
||||
* import { findUpSync } from 'find-up-simple';
|
||||
*/
|
||||
import unicorn from 'eslint-plugin-unicorn';
|
||||
// @ts-expect-error - No types available
|
||||
import js from '@eslint/js';
|
||||
import stylistic from '@stylistic/eslint-plugin';
|
||||
import { configs as dependConfigs } from 'eslint-plugin-depend';
|
||||
import gitignore from 'eslint-config-flat-gitignore';
|
||||
// @ts-expect-error - No types available
|
||||
import fileProgress from 'eslint-plugin-file-progress';
|
||||
import { eqeqeqConfig } from '../shared';
|
||||
|
||||
const CI_environment = process.env.CI ? 0 : 1;
|
||||
|
||||
/**
|
||||
* Gets ESLint's minimal configuration for the monorepo
|
||||
*
|
||||
* @param packageName - The name of the current package
|
||||
*/
|
||||
export function getBaseConfig(packageName: string): Linter.Config[] {
|
||||
return [
|
||||
/*
|
||||
* TODO: Wait for https://github.com/eslint/eslint/issues/19015
|
||||
* {
|
||||
* cache: true,
|
||||
* cacheLocation: join(findUpSync('node_modules', { type: 'directory' }) ?? '', '.cache/eslint', packageName.replace('/', '_')),
|
||||
* },
|
||||
*/
|
||||
{ ...js.configs.recommended,
|
||||
name: '(@jellyfin-vue/configs/eslint/base - eslint) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
...unicorn.configs['flat/recommended'],
|
||||
name: '(@jellyfin-vue/configs/eslint/base - unicorn) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
...dependConfigs['flat/recommended'],
|
||||
name: '(@jellyfin-vue/configs/eslint/base - depend) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
...stylistic.configs.customize({
|
||||
quotes: 'single',
|
||||
semi: true,
|
||||
commaDangle: 'never',
|
||||
braceStyle: '1tbs',
|
||||
arrowParens: false,
|
||||
blockSpacing: true
|
||||
}),
|
||||
name: '(@jellyfin-vue/configs/eslint/base - @stylistic) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
name: '(@jellyfin-vue/configs/eslint/base) Common settings',
|
||||
rules: {
|
||||
'no-empty': ['error', { allowEmptyCatch: true }],
|
||||
'no-extend-native': 'error',
|
||||
'curly': ['error', 'all'],
|
||||
'prefer-arrow-callback': 'error',
|
||||
'multiline-comment-style': 'error',
|
||||
'unicode-bom': ['error', 'never'],
|
||||
'eqeqeq': eqeqeqConfig,
|
||||
'@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
|
||||
'@stylistic/linebreak-style': ['error', 'unix'],
|
||||
'unicorn/import-style': 'off',
|
||||
'unicorn/filename-case': 'off',
|
||||
'unicorn/consistent-function-scoping': 'off',
|
||||
'unicorn/prevent-abbreviations': 'off',
|
||||
'unicorn/no-await-expression-member': 'off',
|
||||
/**
|
||||
* See https://github.com/jellyfin/jellyfin-vue/pull/2361
|
||||
*/
|
||||
'unicorn/explicit-length-check': 'off',
|
||||
'@stylistic/padding-line-between-statements': [
|
||||
'error',
|
||||
// Always require blank lines after import, except between imports
|
||||
{ blankLine: 'always', prev: 'import', next: '*' },
|
||||
{ blankLine: 'never', prev: 'import', next: 'import' },
|
||||
// Always require blank lines before and after every sequence of variable declarations and export
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: '*',
|
||||
next: ['const', 'let', 'var', 'export']
|
||||
},
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: ['const', 'let', 'var', 'export'],
|
||||
next: '*'
|
||||
},
|
||||
{
|
||||
blankLine: 'any',
|
||||
prev: ['const', 'let', 'var', 'export'],
|
||||
next: ['const', 'let', 'var', 'export']
|
||||
},
|
||||
{
|
||||
blankLine: 'any',
|
||||
prev: ['block-like'],
|
||||
next: '*'
|
||||
},
|
||||
// Always require blank lines before and after class declaration, if, do/while, switch, try
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: '*',
|
||||
next: ['if', 'class', 'for', 'do', 'while', 'switch', 'try']
|
||||
},
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: ['if', 'class', 'for', 'do', 'while', 'switch', 'try'],
|
||||
next: '*'
|
||||
},
|
||||
// Always require blank lines before return statements
|
||||
{ blankLine: 'always', prev: '*', next: 'return' }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
...stylistic.configs['disable-legacy'],
|
||||
name: '(@jellyfin-vue/configs/eslint/base) Disable stylistic legacy rules'
|
||||
},
|
||||
/**
|
||||
* Extra files to include and ignores that should override all the others
|
||||
*/
|
||||
{
|
||||
name: '(@jellyfin-vue/configs/eslint/base) Ignored files',
|
||||
ignores: [
|
||||
'**/.git',
|
||||
...gitignore().ignores
|
||||
]
|
||||
},
|
||||
/** File progress plugin */
|
||||
{
|
||||
name: '(@jellyfin-vue/configs/eslint/base) Linting progress report',
|
||||
settings: {
|
||||
progress: {
|
||||
successMessage: 'Linting done!'
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
'file-progress': fileProgress
|
||||
},
|
||||
rules: {
|
||||
'file-progress/activate': CI_environment
|
||||
}
|
||||
}
|
||||
];
|
||||
};
|
45
packages/configs/eslint/rules/env.ts
Normal file
45
packages/configs/eslint/rules/env.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import type { Linter } from 'eslint';
|
||||
import globals from 'globals';
|
||||
|
||||
/**
|
||||
* Gets the ESLint config from Node.js and development related files
|
||||
* @param files - Defaults to `*config.*` and files under `scripts` folder
|
||||
*/
|
||||
export function getNodeFiles(files = ['*.config.*', 'scripts/**/*.ts']): Linter.Config[] {
|
||||
return [{
|
||||
name: '(@jellyfin-vue/configs/eslint/env) Node.js and development-related files',
|
||||
files,
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
...globals.nodeBuiltin
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
'import-x/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: true
|
||||
}
|
||||
],
|
||||
'import-x/no-nodejs-modules': 'off'
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rules config for WebWorker files
|
||||
* @param files - Defaults to `*.worker.ts` files
|
||||
*/
|
||||
export function getWorkerFiles(files = ['**/*.worker.ts']): Linter.Config[] {
|
||||
return [{
|
||||
name: '(@jellyfin-vue/configs/eslint/env) WebWorkers',
|
||||
files,
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.worker
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
48
packages/configs/eslint/rules/i18n.ts
Normal file
48
packages/configs/eslint/rules/i18n.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import type { Linter } from 'eslint';
|
||||
import i18nPlugin from '@intlify/eslint-plugin-vue-i18n';
|
||||
import { vueAndTsFiles } from '../shared';
|
||||
|
||||
export const i18n = [
|
||||
{
|
||||
/* First index is just the plugin definition */
|
||||
...i18nPlugin.configs['flat/recommended'].at(0),
|
||||
/* Last contains the rule definitions */
|
||||
...i18nPlugin.configs['flat/recommended'].at(-1),
|
||||
name: '(@intlify/vue-i18n) Extended config (plugin & settings)',
|
||||
settings: {
|
||||
'vue-i18n': {
|
||||
localeDir: 'locales/en.json',
|
||||
messageSyntaxVersion: '^9.0.0'
|
||||
}
|
||||
},
|
||||
files: vueAndTsFiles
|
||||
},
|
||||
{
|
||||
name: '(@intlify/vue-i18n) Custom config',
|
||||
files: vueAndTsFiles,
|
||||
rules: {
|
||||
'@intlify/vue-i18n/no-unused-keys': ['error', {
|
||||
extensions: ['.ts', '.vue', '.json'],
|
||||
enableFix: true
|
||||
}],
|
||||
'@intlify/vue-i18n/no-raw-text': ['error', {
|
||||
ignorePattern: '^[-#:()&.]+$'
|
||||
}],
|
||||
'@intlify/vue-i18n/no-duplicate-keys-in-locale': 'error',
|
||||
'@intlify/vue-i18n/no-dynamic-keys': 'error',
|
||||
'@intlify/vue-i18n/key-format-style': 'error'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* See the following:
|
||||
* - https://en.wikipedia.org/wiki/History_of_sentence_spacing#French_and_English_spacing
|
||||
* - https://docs.weblate.org/en/weblate-4.14.1/user/checks.html#check-punctuation-spacing
|
||||
*/
|
||||
{
|
||||
name: '(@intlify/vue-i18n - fr) Config exceptions for linguistic rules',
|
||||
files: ['locales/fr.json'],
|
||||
rules: {
|
||||
'no-irregular-whitespace': 'off'
|
||||
}
|
||||
}
|
||||
] satisfies Linter.Config[];
|
21
packages/configs/eslint/rules/json.ts
Normal file
21
packages/configs/eslint/rules/json.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import type { Linter } from 'eslint';
|
||||
import jsonc from 'eslint-plugin-jsonc';
|
||||
|
||||
const jsoncRecommended = jsonc.configs['flat/recommended-with-json'];
|
||||
|
||||
export const json = [
|
||||
{
|
||||
/* First index is just the plugin definition */
|
||||
...jsoncRecommended.at(0),
|
||||
...jsoncRecommended.at(1),
|
||||
name: '(@jellyfin-vue/configs/eslint/json) - Custom config',
|
||||
rules: {
|
||||
...jsoncRecommended.at(1).rules,
|
||||
...jsoncRecommended.at(2).rules,
|
||||
'jsonc/auto': 'error',
|
||||
'@stylistic/quotes': ['error', 'double'],
|
||||
'@stylistic/semi': 'off',
|
||||
'@stylistic/quote-props': 'off'
|
||||
}
|
||||
}
|
||||
] satisfies Linter.Config[];
|
231
packages/configs/eslint/rules/typescript-vue.ts
Normal file
231
packages/configs/eslint/rules/typescript-vue.ts
Normal file
@ -0,0 +1,231 @@
|
||||
import type { Linter } from 'eslint';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import sonarjs from 'eslint-plugin-sonarjs';
|
||||
import regexp from 'eslint-plugin-regexp';
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
import eslintImportX from 'eslint-plugin-import-x';
|
||||
// @ts-expect-error - No types available
|
||||
import vueScopedCSS from 'eslint-plugin-vue-scoped-css';
|
||||
import css from 'eslint-plugin-css';
|
||||
// @ts-expect-error - No types available
|
||||
import vue from 'eslint-plugin-vue';
|
||||
// @ts-expect-error - No types available
|
||||
import promise from 'eslint-plugin-promise';
|
||||
import globals from 'globals';
|
||||
import vueParser from 'vue-eslint-parser';
|
||||
import { eqeqeqConfig, vueAndTsFiles, vueFiles, tsFiles } from '../shared';
|
||||
|
||||
/**
|
||||
* Util functions
|
||||
*/
|
||||
const flatArrayOfObjects = (obj: unknown[]) => Object.assign({}, ...obj);
|
||||
|
||||
/** Common TypeScript and Vue rules */
|
||||
const common = [
|
||||
{
|
||||
...flatArrayOfObjects(tseslint.configs.strictTypeChecked),
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - typescript-eslint) Extended config from plugin (strict type checking)'
|
||||
},
|
||||
{
|
||||
...flatArrayOfObjects(tseslint.configs.stylisticTypeChecked),
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - typescript-eslint) Extended config from plugin (stylistic type checking)'
|
||||
},
|
||||
{
|
||||
...tseslint.configs.eslintRecommended,
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - typescript-eslint) Extended config from plugin (ESLint rules with type checking)'
|
||||
},
|
||||
{
|
||||
...regexp.configs['flat/recommended'],
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - regexp) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
...promise.configs['flat/recommended'],
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - promise) Extended config from plugin'
|
||||
},
|
||||
{
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - promise) Custom config',
|
||||
rules: {
|
||||
'promise/prefer-await-to-callbacks': 'error',
|
||||
'promise/prefer-await-to-then': 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - import) Custom config',
|
||||
plugins: {
|
||||
'import-x': eslintImportX
|
||||
},
|
||||
rules: {
|
||||
'import-x/no-extraneous-dependencies': 'error',
|
||||
'import-x/order': 'error',
|
||||
'import-x/no-cycle': 'error',
|
||||
'import-x/no-nodejs-modules': 'error',
|
||||
'import-x/no-duplicates': ['error', { 'prefer-inline': true, 'considerQueryString': true }],
|
||||
// From the recommended preset
|
||||
'import-x/named': 'error',
|
||||
'import-x/export': 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - JSDoc) Custom config',
|
||||
plugins: {
|
||||
jsdoc
|
||||
},
|
||||
rules: {
|
||||
'jsdoc/require-hyphen-before-param-description': 'error',
|
||||
'jsdoc/require-description': 'error',
|
||||
'jsdoc/no-types': 'error',
|
||||
'jsdoc/require-jsdoc': 'error',
|
||||
'jsdoc/informative-docs': 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - TypeScript & Vue) Custom config',
|
||||
rules: {
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
||||
'@typescript-eslint/restrict-template-expressions': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-dynamic-delete': 'off',
|
||||
'@typescript-eslint/no-import-type-side-effects': 'error',
|
||||
'@typescript-eslint/consistent-type-exports': 'error',
|
||||
'@typescript-eslint/explicit-member-accessibility': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': ['error', {
|
||||
prefer: 'type-imports',
|
||||
fixStyle: 'inline-type-imports'
|
||||
}],
|
||||
'@typescript-eslint/no-confusing-void-expression': ['error', { ignoreArrowShorthand: true }],
|
||||
'@typescript-eslint/no-empty-object-type': ['error', { allowInterfaces: 'with-single-extends' }],
|
||||
'vue/return-in-computed-property': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
...sonarjs.configs.recommended,
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - sonarcloud) Extended config from plugin'
|
||||
}
|
||||
] satisfies Linter.Config[];
|
||||
|
||||
/** Vue SFC only rules */
|
||||
const vue_config = [
|
||||
...vue.configs['flat/recommended'].map((config) => {
|
||||
/**
|
||||
* Specified above, unnecessary to overwrite
|
||||
*/
|
||||
delete config.languageOptions?.globals;
|
||||
/**
|
||||
* DEPRECATED: See https://eslint.vuejs.org/rules/component-tags-order.html#vue-component-tags-order
|
||||
* TODO: Remove when it's removed from the recommended rules
|
||||
*/
|
||||
delete config.rules?.['vue/component-tags-order'];
|
||||
config.name = `(@jellyfin-vue/configs/eslint/typescript-vue - ${config.name}) - Extended config from plugin`;
|
||||
|
||||
return config;
|
||||
}),
|
||||
{
|
||||
...flatArrayOfObjects(vueScopedCSS.configs['flat/recommended']),
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - Vue Scoped CSS) Extended config from plugin',
|
||||
files: vueFiles
|
||||
},
|
||||
{
|
||||
...css.configs['flat/recommended'],
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - Vue CSS) Extended config from plugin',
|
||||
files: vueFiles
|
||||
},
|
||||
{
|
||||
name: '(Vue) Custom config',
|
||||
files: vueFiles,
|
||||
rules: {
|
||||
'vue/component-name-in-template-casing': [
|
||||
'error',
|
||||
'PascalCase',
|
||||
{
|
||||
registeredComponentsOnly: false
|
||||
}
|
||||
],
|
||||
'vue/define-macros-order': ['error', {
|
||||
order: ['defineOptions', 'defineProps', 'defineEmits', 'defineSlots']
|
||||
}],
|
||||
'vue/html-closing-bracket-newline': ['error', { multiline: 'never' }],
|
||||
'vue/block-order': ['error', {
|
||||
order: ['template', 'script:not([setup])', 'script[setup]']
|
||||
}],
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/eqeqeq': eqeqeqConfig,
|
||||
'vue/block-lang': ['error',
|
||||
{
|
||||
script: {
|
||||
lang: 'ts'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
}
|
||||
] satisfies Linter.Config[];
|
||||
|
||||
/**
|
||||
* Gets the base configuration for TypeScript files only or both Vue and TypeScript
|
||||
*
|
||||
* @param enableVue - Whether to apply the base config for Vue files
|
||||
* @returns
|
||||
*/
|
||||
export function getTSVueConfig(enableVue = true, tsconfigRootDir = import.meta.dirname): Linter.Config[] {
|
||||
const result = [
|
||||
...(enableVue ? vue_config : []),
|
||||
...common.map(conf => ({
|
||||
...conf, files: enableVue ? vueAndTsFiles : tsFiles
|
||||
}))] satisfies Linter.Config[];
|
||||
|
||||
const langOptions = {
|
||||
ecmaVersion: 2024,
|
||||
sourceType: 'module',
|
||||
globals: {
|
||||
...globals.browser
|
||||
}
|
||||
};
|
||||
|
||||
const sharedParserOptions = {
|
||||
projectService: true,
|
||||
tsconfigRootDir,
|
||||
warnOnUnsupportedTypeScriptVersion: false
|
||||
};
|
||||
|
||||
// Extracted from https://github.com/vuejs/eslint-config-typescript
|
||||
const base_vue_parser = {
|
||||
name: '(@jellyfin-vue/configs/eslint/typescript-vue - Vue) Extra parser configuration for typed linting',
|
||||
files: vueFiles,
|
||||
languageOptions: {
|
||||
...langOptions,
|
||||
parser: vueParser,
|
||||
parserOptions: {
|
||||
parser: tseslint.parser,
|
||||
...sharedParserOptions
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const base_ts_parser = {
|
||||
name: enableVue
|
||||
? '(@jellyfin-vue/configs/eslint/typescript-vue - TypeScript & Vue) Parser extra config'
|
||||
: '(@jellyfin-vue/configs/eslint/typescript-vue - TypeScript) Parser extra config',
|
||||
files: enableVue ? vueAndTsFiles : tsFiles,
|
||||
languageOptions: {
|
||||
...langOptions,
|
||||
parserOptions: {
|
||||
...sharedParserOptions,
|
||||
...(enableVue
|
||||
? {
|
||||
extraFileExtensions: ['.vue']
|
||||
}
|
||||
: {})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
result.push(base_ts_parser);
|
||||
|
||||
if (enableVue) {
|
||||
result.push(base_vue_parser);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
9
packages/configs/eslint/rules/unocss.ts
Normal file
9
packages/configs/eslint/rules/unocss.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import type { Linter } from 'eslint';
|
||||
import UnoPlugin from '@unocss/eslint-config/flat';
|
||||
|
||||
export const unocss = [
|
||||
{
|
||||
...UnoPlugin,
|
||||
name: '(unocss) Extended config from plugin'
|
||||
}
|
||||
] satisfies Linter.Config[];
|
7
packages/configs/eslint/shared.ts
Normal file
7
packages/configs/eslint/shared.ts
Normal file
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Shared variables between rules
|
||||
*/
|
||||
export const eqeqeqConfig = ['error', 'always', { null: 'ignore' }];
|
||||
export const tsFiles = ['*.ts', '**/*.ts'];
|
||||
export const vueFiles = ['*.vue', '**/*.vue'];
|
||||
export const vueAndTsFiles = [...vueFiles, ...tsFiles];
|
@ -1,9 +1,40 @@
|
||||
{
|
||||
"name": "@jellyfin-vue/configs",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./tsconfig.json": "./tsconfig.json",
|
||||
"./index.js": "./index.js"
|
||||
"./typescript/base.json": "./typescript/base.json",
|
||||
"./eslint": "./eslint/index.ts",
|
||||
"./unocss": "./unocss.ts"
|
||||
},
|
||||
"type": "module"
|
||||
"scripts": {
|
||||
"lint": "eslint . --max-warnings=0 --flag unstable_ts_config",
|
||||
"lint:fix": "eslint . --fix --max-warnings=0 --flag unstable_ts_config",
|
||||
"lint:inspect": "eslint-config-inspector",
|
||||
"check:types": "vue-tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.12.0",
|
||||
"@intlify/eslint-plugin-vue-i18n": "3.0.0",
|
||||
"@stylistic/eslint-plugin": "2.8.0",
|
||||
"@unocss/eslint-config": "0.62.3",
|
||||
"eslint-config-flat-gitignore": "0.3.0",
|
||||
"eslint-plugin-css": "0.11.0",
|
||||
"eslint-plugin-depend": "0.11.0",
|
||||
"eslint-plugin-file-progress": "1.5.0",
|
||||
"eslint-plugin-import-x": "4.2.1",
|
||||
"eslint-plugin-jsdoc": "50.2.2",
|
||||
"eslint-plugin-jsonc": "2.16.0",
|
||||
"eslint-plugin-promise": "7.1.0",
|
||||
"eslint-plugin-regexp": "2.6.0",
|
||||
"eslint-plugin-sonarjs": "1.0.4",
|
||||
"eslint-plugin-unicorn": "55.0.0",
|
||||
"eslint-plugin-vue": "9.28.0",
|
||||
"eslint-plugin-vue-scoped-css": "2.8.1",
|
||||
"find-up-simple": "1.0.0",
|
||||
"globals": "15.9.0",
|
||||
"typescript-eslint": "8.5.0",
|
||||
"unocss": "0.62.3",
|
||||
"vue-eslint-parser": "9.4.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,10 @@
|
||||
{
|
||||
"extends": "./typescript/base.json",
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleResolution": "Bundler",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"useDefineForClassFields": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"noErrorTruncation": true,
|
||||
"experimentalDecorators": true,
|
||||
"removeComments": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "../node_modules/.cache/tsconfig.tsbuildinfo",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"baseUrl": "."
|
||||
},
|
||||
"vueCompilerOptions": {
|
||||
"strictTemplates": true,
|
||||
"htmlAttributes": ["aria-*", "data-*"],
|
||||
"fallthroughAttributes": true
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
"include": [
|
||||
"eslint/**/*.ts",
|
||||
"*.ts"
|
||||
]
|
||||
}
|
||||
|
34
packages/configs/typescript/base.json
Normal file
34
packages/configs/typescript/base.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleResolution": "Bundler",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"useDefineForClassFields": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"noErrorTruncation": true,
|
||||
"experimentalDecorators": true,
|
||||
"removeComments": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "../../../node_modules/.cache/tsconfig.tsbuildinfo",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
},
|
||||
"vueCompilerOptions": {
|
||||
"strictTemplates": true,
|
||||
"htmlAttributes": ["aria-*", "data-*"],
|
||||
"fallthroughAttributes": true
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
15
packages/configs/unocss.ts
Normal file
15
packages/configs/unocss.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { defineConfig, presetUno } from 'unocss';
|
||||
|
||||
export const defaultConfig = defineConfig({
|
||||
presets: [
|
||||
presetUno({
|
||||
prefix: 'uno-',
|
||||
preflight: false
|
||||
})
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
background: 'rgb(var(--j-color-background))'
|
||||
}
|
||||
}
|
||||
});
|
8
packages/vite-plugins/eslint.config.ts
Normal file
8
packages/vite-plugins/eslint.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import type { Linter } from 'eslint';
|
||||
import { getBaseConfig, getTSVueConfig, getNodeFiles } from '@jellyfin-vue/configs/eslint';
|
||||
|
||||
export default [
|
||||
...getBaseConfig('@jellyfin-vue/vite-plugins'),
|
||||
...getTSVueConfig(false, import.meta.dirname),
|
||||
...getNodeFiles()
|
||||
] satisfies Linter.Config[];
|
@ -3,8 +3,15 @@
|
||||
"version": "0.0.1",
|
||||
"exports": "./index.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"lint": "eslint . --max-warnings=0 --flag unstable_ts_config",
|
||||
"lint:fix": "eslint . --fix --max-warnings=0 --flag unstable_ts_config",
|
||||
"lint:inspect": "eslint-config-inspector",
|
||||
"check:types": "vue-tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jellyfin-vue/configs": "*",
|
||||
"rollup-plugin-visualizer": "5.12.0",
|
||||
"vite": "5.4.3"
|
||||
"vite": "5.4.6"
|
||||
}
|
||||
}
|
||||
|
9
packages/vite-plugins/tsconfig.json
Normal file
9
packages/vite-plugins/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "@jellyfin-vue/configs/typescript/base.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "."
|
||||
},
|
||||
"include": [
|
||||
"*.ts"
|
||||
]
|
||||
}
|
@ -12,6 +12,7 @@ ENV COMMIT_HASH=$COMMIT_HASH
|
||||
|
||||
COPY package.json package-lock.json .npmrc /app/
|
||||
COPY frontend /app/frontend
|
||||
COPY packages /app/packages
|
||||
WORKDIR /app/frontend
|
||||
|
||||
# Build client
|
||||
|
@ -6,7 +6,10 @@
|
||||
"start": "npm run gen-icon && tauri dev",
|
||||
"gen-icon": "tauri icon ../../frontend/public/icon.svg",
|
||||
"build": "npm run gen-icon && tauri build",
|
||||
"clean": "git clean -fxd"
|
||||
"clean": "git clean -fxd",
|
||||
"lint": "true",
|
||||
"lint:fix": "true",
|
||||
"check:types": "true"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jellyfin-vue/frontend": "*"
|
||||
|
Loading…
Reference in New Issue
Block a user