mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Add typescript guideline and typescript-specific eslint plugins and fix issues (#31521)
1. Add some general guidelines how to write our typescript code 2. Add `@typescript-eslint/eslint-plugin`, general typescript rules 3. Add `eslint-plugin-deprecation` to detect deprecated code 4. Fix all new lint issues that came up
This commit is contained in:
		
							
								
								
									
										133
									
								
								.eslintrc.yaml
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								.eslintrc.yaml
									
									
									
									
									
								
							| @@ -13,6 +13,7 @@ parserOptions: | ||||
|   ecmaVersion: latest | ||||
|   project: true | ||||
|   extraFileExtensions: [".vue"] | ||||
|   parser: "@typescript-eslint/parser" # for vue plugin - https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser | ||||
|  | ||||
| settings: | ||||
|   import/extensions: [".js", ".ts"] | ||||
| @@ -24,7 +25,9 @@ settings: | ||||
| plugins: | ||||
|   - "@eslint-community/eslint-plugin-eslint-comments" | ||||
|   - "@stylistic/eslint-plugin-js" | ||||
|   - "@typescript-eslint/eslint-plugin" | ||||
|   - eslint-plugin-array-func | ||||
|   - eslint-plugin-deprecation | ||||
|   - eslint-plugin-github | ||||
|   - eslint-plugin-i | ||||
|   - eslint-plugin-no-jquery | ||||
| @@ -209,6 +212,123 @@ rules: | ||||
|   "@stylistic/js/wrap-iife": [2, inside] | ||||
|   "@stylistic/js/wrap-regex": [0] | ||||
|   "@stylistic/js/yield-star-spacing": [2, after] | ||||
|   "@typescript-eslint/adjacent-overload-signatures": [0] | ||||
|   "@typescript-eslint/array-type": [0] | ||||
|   "@typescript-eslint/await-thenable": [2] | ||||
|   "@typescript-eslint/ban-ts-comment": [2, {'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}] | ||||
|   "@typescript-eslint/ban-tslint-comment": [0] | ||||
|   "@typescript-eslint/ban-types": [2, {extendDefaults: true, types: {Function: false}}] | ||||
|   "@typescript-eslint/class-literal-property-style": [0] | ||||
|   "@typescript-eslint/class-methods-use-this": [0] | ||||
|   "@typescript-eslint/consistent-generic-constructors": [0] | ||||
|   "@typescript-eslint/consistent-indexed-object-style": [0] | ||||
|   "@typescript-eslint/consistent-return": [0] | ||||
|   "@typescript-eslint/consistent-type-assertions": [2, {assertionStyle: as, objectLiteralTypeAssertions: allow}] | ||||
|   "@typescript-eslint/consistent-type-definitions": [2, type] | ||||
|   "@typescript-eslint/consistent-type-exports": [2, {fixMixedExportsWithInlineTypeSpecifier: false}] | ||||
|   "@typescript-eslint/consistent-type-imports": [2, {prefer: type-imports, fixStyle: separate-type-imports, disallowTypeAnnotations: true}] | ||||
|   "@typescript-eslint/default-param-last": [0] | ||||
|   "@typescript-eslint/dot-notation": [0] | ||||
|   "@typescript-eslint/explicit-function-return-type": [0] | ||||
|   "@typescript-eslint/explicit-member-accessibility": [0] | ||||
|   "@typescript-eslint/explicit-module-boundary-types": [0] | ||||
|   "@typescript-eslint/init-declarations": [0] | ||||
|   "@typescript-eslint/max-params": [0] | ||||
|   "@typescript-eslint/member-ordering": [0] | ||||
|   "@typescript-eslint/method-signature-style": [0] | ||||
|   "@typescript-eslint/naming-convention": [0] | ||||
|   "@typescript-eslint/no-array-constructor": [2] | ||||
|   "@typescript-eslint/no-array-delete": [2] | ||||
|   "@typescript-eslint/no-base-to-string": [0] | ||||
|   "@typescript-eslint/no-confusing-non-null-assertion": [2] | ||||
|   "@typescript-eslint/no-confusing-void-expression": [0] | ||||
|   "@typescript-eslint/no-dupe-class-members": [0] | ||||
|   "@typescript-eslint/no-duplicate-enum-values": [2] | ||||
|   "@typescript-eslint/no-duplicate-type-constituents": [2, {ignoreUnions: true}] | ||||
|   "@typescript-eslint/no-dynamic-delete": [0] | ||||
|   "@typescript-eslint/no-empty-function": [0] | ||||
|   "@typescript-eslint/no-empty-interface": [0] | ||||
|   "@typescript-eslint/no-explicit-any": [0] | ||||
|   "@typescript-eslint/no-extra-non-null-assertion": [2] | ||||
|   "@typescript-eslint/no-extraneous-class": [0] | ||||
|   "@typescript-eslint/no-floating-promises": [0] | ||||
|   "@typescript-eslint/no-for-in-array": [2] | ||||
|   "@typescript-eslint/no-implied-eval": [2] | ||||
|   "@typescript-eslint/no-import-type-side-effects": [0] # dupe with consistent-type-imports | ||||
|   "@typescript-eslint/no-inferrable-types": [0] | ||||
|   "@typescript-eslint/no-invalid-this": [0] | ||||
|   "@typescript-eslint/no-invalid-void-type": [0] | ||||
|   "@typescript-eslint/no-loop-func": [0] | ||||
|   "@typescript-eslint/no-loss-of-precision": [2] | ||||
|   "@typescript-eslint/no-magic-numbers": [0] | ||||
|   "@typescript-eslint/no-meaningless-void-operator": [0] | ||||
|   "@typescript-eslint/no-misused-new": [2] | ||||
|   "@typescript-eslint/no-misused-promises": [2, {checksVoidReturn: {attributes: false, arguments: false}}] | ||||
|   "@typescript-eslint/no-mixed-enums": [0] | ||||
|   "@typescript-eslint/no-namespace": [2] | ||||
|   "@typescript-eslint/no-non-null-asserted-nullish-coalescing": [0] | ||||
|   "@typescript-eslint/no-non-null-asserted-optional-chain": [2] | ||||
|   "@typescript-eslint/no-non-null-assertion": [0] | ||||
|   "@typescript-eslint/no-redeclare": [0] | ||||
|   "@typescript-eslint/no-redundant-type-constituents": [2] | ||||
|   "@typescript-eslint/no-require-imports": [0] | ||||
|   "@typescript-eslint/no-restricted-imports": [0] | ||||
|   "@typescript-eslint/no-shadow": [0] | ||||
|   "@typescript-eslint/no-this-alias": [0] # handled by unicorn/no-this-assignment | ||||
|   "@typescript-eslint/no-unnecessary-boolean-literal-compare": [0] | ||||
|   "@typescript-eslint/no-unnecessary-condition": [0] | ||||
|   "@typescript-eslint/no-unnecessary-qualifier": [0] | ||||
|   "@typescript-eslint/no-unnecessary-template-expression": [0] | ||||
|   "@typescript-eslint/no-unnecessary-type-arguments": [0] | ||||
|   "@typescript-eslint/no-unnecessary-type-assertion": [2] | ||||
|   "@typescript-eslint/no-unnecessary-type-constraint": [2] | ||||
|   "@typescript-eslint/no-unsafe-argument": [0] | ||||
|   "@typescript-eslint/no-unsafe-assignment": [0] | ||||
|   "@typescript-eslint/no-unsafe-call": [0] | ||||
|   "@typescript-eslint/no-unsafe-declaration-merging": [2] | ||||
|   "@typescript-eslint/no-unsafe-enum-comparison": [2] | ||||
|   "@typescript-eslint/no-unsafe-member-access": [0] | ||||
|   "@typescript-eslint/no-unsafe-return": [0] | ||||
|   "@typescript-eslint/no-unsafe-unary-minus": [2] | ||||
|   "@typescript-eslint/no-unused-expressions": [0] | ||||
|   "@typescript-eslint/no-unused-vars": [2, {vars: all, args: all, caughtErrors: all, ignoreRestSiblings: false, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_}] | ||||
|   "@typescript-eslint/no-use-before-define": [0] | ||||
|   "@typescript-eslint/no-useless-constructor": [0] | ||||
|   "@typescript-eslint/no-useless-empty-export": [0] | ||||
|   "@typescript-eslint/no-var-requires": [2] | ||||
|   "@typescript-eslint/non-nullable-type-assertion-style": [0] | ||||
|   "@typescript-eslint/only-throw-error": [2] | ||||
|   "@typescript-eslint/parameter-properties": [0] | ||||
|   "@typescript-eslint/prefer-as-const": [2] | ||||
|   "@typescript-eslint/prefer-destructuring": [0] | ||||
|   "@typescript-eslint/prefer-enum-initializers": [0] | ||||
|   "@typescript-eslint/prefer-find": [2] | ||||
|   "@typescript-eslint/prefer-for-of": [2] | ||||
|   "@typescript-eslint/prefer-function-type": [2] | ||||
|   "@typescript-eslint/prefer-includes": [2] | ||||
|   "@typescript-eslint/prefer-literal-enum-member": [0] | ||||
|   "@typescript-eslint/prefer-namespace-keyword": [0] | ||||
|   "@typescript-eslint/prefer-nullish-coalescing": [0] | ||||
|   "@typescript-eslint/prefer-optional-chain": [2, {requireNullish: true}] | ||||
|   "@typescript-eslint/prefer-promise-reject-errors": [0] | ||||
|   "@typescript-eslint/prefer-readonly": [0] | ||||
|   "@typescript-eslint/prefer-readonly-parameter-types": [0] | ||||
|   "@typescript-eslint/prefer-reduce-type-parameter": [0] | ||||
|   "@typescript-eslint/prefer-regexp-exec": [0] | ||||
|   "@typescript-eslint/prefer-return-this-type": [0] | ||||
|   "@typescript-eslint/prefer-string-starts-ends-with": [2, {allowSingleElementEquality: always}] | ||||
|   "@typescript-eslint/promise-function-async": [0] | ||||
|   "@typescript-eslint/require-array-sort-compare": [0] | ||||
|   "@typescript-eslint/require-await": [0] | ||||
|   "@typescript-eslint/restrict-plus-operands": [2] | ||||
|   "@typescript-eslint/restrict-template-expressions": [0] | ||||
|   "@typescript-eslint/return-await": [0] | ||||
|   "@typescript-eslint/strict-boolean-expressions": [0] | ||||
|   "@typescript-eslint/switch-exhaustiveness-check": [0] | ||||
|   "@typescript-eslint/triple-slash-reference": [2] | ||||
|   "@typescript-eslint/typedef": [0] | ||||
|   "@typescript-eslint/unbound-method": [2] | ||||
|   "@typescript-eslint/unified-signatures": [2] | ||||
|   accessor-pairs: [2] | ||||
|   array-callback-return: [2, {checkForEach: true}] | ||||
|   array-func/avoid-reverse: [2] | ||||
| @@ -230,6 +350,7 @@ rules: | ||||
|   default-case-last: [2] | ||||
|   default-case: [0] | ||||
|   default-param-last: [0] | ||||
|   deprecation/deprecation: [2] | ||||
|   dot-notation: [0] | ||||
|   eqeqeq: [2] | ||||
|   for-direction: [2] | ||||
| @@ -321,7 +442,7 @@ rules: | ||||
|   multiline-comment-style: [2, separate-lines] | ||||
|   new-cap: [0] | ||||
|   no-alert: [0] | ||||
|   no-array-constructor: [2] | ||||
|   no-array-constructor: [0] # handled by @typescript-eslint/no-array-constructor | ||||
|   no-async-promise-executor: [0] | ||||
|   no-await-in-loop: [0] | ||||
|   no-bitwise: [0] | ||||
| @@ -365,7 +486,7 @@ rules: | ||||
|   no-global-assign: [2] | ||||
|   no-implicit-coercion: [2] | ||||
|   no-implicit-globals: [0] | ||||
|   no-implied-eval: [2] | ||||
|   no-implied-eval: [0] # handled by @typescript-eslint/no-implied-eval | ||||
|   no-import-assign: [2] | ||||
|   no-inline-comments: [0] | ||||
|   no-inner-declarations: [2] | ||||
| @@ -471,7 +592,7 @@ rules: | ||||
|   no-lone-blocks: [2] | ||||
|   no-lonely-if: [0] | ||||
|   no-loop-func: [0] | ||||
|   no-loss-of-precision: [2] | ||||
|   no-loss-of-precision: [0] # handled by @typescript-eslint/no-loss-of-precision | ||||
|   no-magic-numbers: [0] | ||||
|   no-misleading-character-class: [2] | ||||
|   no-multi-assign: [0] | ||||
| @@ -493,7 +614,7 @@ rules: | ||||
|   no-promise-executor-return: [0] | ||||
|   no-proto: [2] | ||||
|   no-prototype-builtins: [2] | ||||
|   no-redeclare: [2] | ||||
|   no-redeclare: [0] # must be disabled for typescript overloads | ||||
|   no-regex-spaces: [2] | ||||
|   no-restricted-exports: [0] | ||||
|   no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename] | ||||
| @@ -526,7 +647,7 @@ rules: | ||||
|   no-unused-expressions: [2] | ||||
|   no-unused-labels: [2] | ||||
|   no-unused-private-class-members: [2] | ||||
|   no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}] | ||||
|   no-unused-vars: [0] # handled by @typescript-eslint/no-unused-vars | ||||
|   no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}] | ||||
|   no-use-extend-native/no-use-extend-native: [2] | ||||
|   no-useless-backreference: [2] | ||||
| @@ -641,7 +762,7 @@ rules: | ||||
|   regexp/unicode-escape: [0] | ||||
|   regexp/use-ignore-case: [0] | ||||
|   require-atomic-updates: [0] | ||||
|   require-await: [0] | ||||
|   require-await: [0] # handled by @typescript-eslint/require-await | ||||
|   require-unicode-regexp: [0] | ||||
|   require-yield: [2] | ||||
|   sonarjs/cognitive-complexity: [0] | ||||
|   | ||||
| @@ -79,6 +79,22 @@ We use htmx for simple interactions. You can see an example for simple interacti | ||||
| Although mixing different frameworks is discouraged, | ||||
| it should also work if the mixing is necessary and the code is well-designed and maintainable. | ||||
|  | ||||
| ### Typescript | ||||
|  | ||||
| Gitea is in the process of migrating to type-safe Typescript. Here are some specific guidelines regarding Typescript in the codebase: | ||||
|  | ||||
| #### Use type aliases instead of interfaces | ||||
|  | ||||
| Prefer to use type aliases because they can represent any type and are generally more flexible to use than interfaces. | ||||
|  | ||||
| #### Use separate type imports | ||||
|  | ||||
| We use `verbatimModuleSyntax` so type and non-type imports from the same file must be split into two `import type` statements. This enables the typescript compiler to completely eliminate the type import statements during compilation. | ||||
|  | ||||
| #### Use `@ts-expect-error` instead of `@ts-ignore` | ||||
|  | ||||
| Both annotations should be avoided, but if you have to use them, use `@ts-expect-error` because it will not leave ineffective statements after the issue is fixed. | ||||
|  | ||||
| ### `async` Functions | ||||
|  | ||||
| Only mark a function as `async` if and only if there are `await` calls | ||||
|   | ||||
							
								
								
									
										230
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										230
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -69,11 +69,13 @@ | ||||
|         "@stoplight/spectral-cli": "6.11.1", | ||||
|         "@stylistic/eslint-plugin-js": "2.2.1", | ||||
|         "@stylistic/stylelint-plugin": "2.1.2", | ||||
|         "@typescript-eslint/eslint-plugin": "7.14.1", | ||||
|         "@typescript-eslint/parser": "7.14.1", | ||||
|         "@vitejs/plugin-vue": "5.0.5", | ||||
|         "eslint": "8.57.0", | ||||
|         "eslint-import-resolver-typescript": "3.6.1", | ||||
|         "eslint-plugin-array-func": "4.0.0", | ||||
|         "eslint-plugin-deprecation": "3.0.0", | ||||
|         "eslint-plugin-github": "5.0.1", | ||||
|         "eslint-plugin-i": "2.29.1", | ||||
|         "eslint-plugin-no-jquery": "3.0.1", | ||||
| @@ -2370,16 +2372,17 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/eslint-plugin": { | ||||
|       "version": "7.13.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", | ||||
|       "integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", | ||||
|       "version": "7.14.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz", | ||||
|       "integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@eslint-community/regexpp": "^4.10.0", | ||||
|         "@typescript-eslint/scope-manager": "7.13.1", | ||||
|         "@typescript-eslint/type-utils": "7.13.1", | ||||
|         "@typescript-eslint/utils": "7.13.1", | ||||
|         "@typescript-eslint/visitor-keys": "7.13.1", | ||||
|         "@typescript-eslint/scope-manager": "7.14.1", | ||||
|         "@typescript-eslint/type-utils": "7.14.1", | ||||
|         "@typescript-eslint/utils": "7.14.1", | ||||
|         "@typescript-eslint/visitor-keys": "7.14.1", | ||||
|         "graphemer": "^1.4.0", | ||||
|         "ignore": "^5.3.1", | ||||
|         "natural-compare": "^1.4.0", | ||||
| @@ -2431,7 +2434,7 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { | ||||
|     "node_modules/@typescript-eslint/scope-manager": { | ||||
|       "version": "7.14.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", | ||||
|       "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", | ||||
| @@ -2449,7 +2452,35 @@ | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { | ||||
|     "node_modules/@typescript-eslint/type-utils": { | ||||
|       "version": "7.14.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz", | ||||
|       "integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/typescript-estree": "7.14.1", | ||||
|         "@typescript-eslint/utils": "7.14.1", | ||||
|         "debug": "^4.3.4", | ||||
|         "ts-api-utils": "^1.3.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^18.18.0 || >=20.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "eslint": "^8.56.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "typescript": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/types": { | ||||
|       "version": "7.14.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", | ||||
|       "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", | ||||
| @@ -2463,7 +2494,7 @@ | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { | ||||
|     "node_modules/@typescript-eslint/typescript-estree": { | ||||
|       "version": "7.14.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", | ||||
|       "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", | ||||
| @@ -2492,7 +2523,30 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { | ||||
|     "node_modules/@typescript-eslint/utils": { | ||||
|       "version": "7.14.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", | ||||
|       "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@eslint-community/eslint-utils": "^4.4.0", | ||||
|         "@typescript-eslint/scope-manager": "7.14.1", | ||||
|         "@typescript-eslint/types": "7.14.1", | ||||
|         "@typescript-eslint/typescript-estree": "7.14.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^18.18.0 || >=20.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "eslint": "^8.56.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/visitor-keys": { | ||||
|       "version": "7.14.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", | ||||
|       "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", | ||||
| @@ -2510,148 +2564,12 @@ | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { | ||||
|       "version": "3.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", | ||||
|       "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", | ||||
|       "dev": true, | ||||
|       "license": "Apache-2.0", | ||||
|       "engines": { | ||||
|         "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://opencollective.com/eslint" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/scope-manager": { | ||||
|       "version": "7.13.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", | ||||
|       "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/types": "7.13.1", | ||||
|         "@typescript-eslint/visitor-keys": "7.13.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^18.18.0 || >=20.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/type-utils": { | ||||
|       "version": "7.13.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", | ||||
|       "integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/typescript-estree": "7.13.1", | ||||
|         "@typescript-eslint/utils": "7.13.1", | ||||
|         "debug": "^4.3.4", | ||||
|         "ts-api-utils": "^1.3.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^18.18.0 || >=20.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "eslint": "^8.56.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "typescript": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/types": { | ||||
|       "version": "7.13.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", | ||||
|       "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", | ||||
|       "dev": true, | ||||
|       "engines": { | ||||
|         "node": "^18.18.0 || >=20.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/typescript-estree": { | ||||
|       "version": "7.13.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", | ||||
|       "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/types": "7.13.1", | ||||
|         "@typescript-eslint/visitor-keys": "7.13.1", | ||||
|         "debug": "^4.3.4", | ||||
|         "globby": "^11.1.0", | ||||
|         "is-glob": "^4.0.3", | ||||
|         "minimatch": "^9.0.4", | ||||
|         "semver": "^7.6.0", | ||||
|         "ts-api-utils": "^1.3.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^18.18.0 || >=20.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "typescript": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/utils": { | ||||
|       "version": "7.13.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", | ||||
|       "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@eslint-community/eslint-utils": "^4.4.0", | ||||
|         "@typescript-eslint/scope-manager": "7.13.1", | ||||
|         "@typescript-eslint/types": "7.13.1", | ||||
|         "@typescript-eslint/typescript-estree": "7.13.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^18.18.0 || >=20.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "eslint": "^8.56.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/visitor-keys": { | ||||
|       "version": "7.13.1", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", | ||||
|       "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/types": "7.13.1", | ||||
|         "eslint-visitor-keys": "^3.4.3" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^18.18.0 || >=20.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/typescript-eslint" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { | ||||
|       "version": "3.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", | ||||
|       "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", | ||||
|       "dev": true, | ||||
|       "license": "Apache-2.0", | ||||
|       "engines": { | ||||
|         "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | ||||
|       }, | ||||
| @@ -5513,6 +5431,22 @@ | ||||
|         "eslint": ">=8.40.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/eslint-plugin-deprecation": { | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-3.0.0.tgz", | ||||
|       "integrity": "sha512-JuVLdNg/uf0Adjg2tpTyYoYaMbwQNn/c78P1HcccokvhtRphgnRjZDKmhlxbxYptppex03zO76f97DD/yQHv7A==", | ||||
|       "dev": true, | ||||
|       "license": "LGPL-3.0-or-later", | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/utils": "^7.0.0", | ||||
|         "ts-api-utils": "^1.3.0", | ||||
|         "tslib": "^2.3.1" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "eslint": "^8.0.0", | ||||
|         "typescript": "^4.2.4 || ^5.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/eslint-plugin-escompat": { | ||||
|       "version": "3.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/eslint-plugin-escompat/-/eslint-plugin-escompat-3.4.0.tgz", | ||||
|   | ||||
| @@ -68,11 +68,13 @@ | ||||
|     "@stoplight/spectral-cli": "6.11.1", | ||||
|     "@stylistic/eslint-plugin-js": "2.2.1", | ||||
|     "@stylistic/stylelint-plugin": "2.1.2", | ||||
|     "@typescript-eslint/eslint-plugin": "7.14.1", | ||||
|     "@typescript-eslint/parser": "7.14.1", | ||||
|     "@vitejs/plugin-vue": "5.0.5", | ||||
|     "eslint": "8.57.0", | ||||
|     "eslint-import-resolver-typescript": "3.6.1", | ||||
|     "eslint-plugin-array-func": "4.0.0", | ||||
|     "eslint-plugin-deprecation": "3.0.0", | ||||
|     "eslint-plugin-github": "5.0.1", | ||||
|     "eslint-plugin-i": "2.29.1", | ||||
|     "eslint-plugin-no-jquery": "3.0.1", | ||||
|   | ||||
| @@ -7,21 +7,21 @@ test.beforeAll(async ({browser}, workerInfo) => { | ||||
|  | ||||
| test('homepage', async ({page}) => { | ||||
|   const response = await page.goto('/'); | ||||
|   await expect(response?.status()).toBe(200); // Status OK | ||||
|   expect(response?.status()).toBe(200); // Status OK | ||||
|   await expect(page).toHaveTitle(/^Gitea: Git with a cup of tea\s*$/); | ||||
|   await expect(page.locator('.logo')).toHaveAttribute('src', '/assets/img/logo.svg'); | ||||
| }); | ||||
|  | ||||
| test('register', async ({page}, workerInfo) => { | ||||
|   const response = await page.goto('/user/sign_up'); | ||||
|   await expect(response?.status()).toBe(200); // Status OK | ||||
|   await page.type('input[name=user_name]', `e2e-test-${workerInfo.workerIndex}`); | ||||
|   await page.type('input[name=email]', `e2e-test-${workerInfo.workerIndex}@test.com`); | ||||
|   await page.type('input[name=password]', 'test123test123'); | ||||
|   await page.type('input[name=retype]', 'test123test123'); | ||||
|   expect(response?.status()).toBe(200); // Status OK | ||||
|   await page.locator('input[name=user_name]').fill(`e2e-test-${workerInfo.workerIndex}`); | ||||
|   await page.locator('input[name=email]').fill(`e2e-test-${workerInfo.workerIndex}@test.com`); | ||||
|   await page.locator('input[name=password]').fill('test123test123'); | ||||
|   await page.locator('input[name=retype]').fill('test123test123'); | ||||
|   await page.click('form button.ui.primary.button:visible'); | ||||
|   // Make sure we routed to the home page. Else login failed. | ||||
|   await expect(page.url()).toBe(`${workerInfo.project.use.baseURL}/`); | ||||
|   expect(page.url()).toBe(`${workerInfo.project.use.baseURL}/`); | ||||
|   await expect(page.locator('.secondary-nav span>img.ui.avatar')).toBeVisible(); | ||||
|   await expect(page.locator('.ui.positive.message.flash-success')).toHaveText('Account was successfully created. Welcome!'); | ||||
|  | ||||
| @@ -30,15 +30,15 @@ test('register', async ({page}, workerInfo) => { | ||||
|  | ||||
| test('login', async ({page}, workerInfo) => { | ||||
|   const response = await page.goto('/user/login'); | ||||
|   await expect(response?.status()).toBe(200); // Status OK | ||||
|   expect(response?.status()).toBe(200); // Status OK | ||||
|  | ||||
|   await page.type('input[name=user_name]', `user2`); | ||||
|   await page.type('input[name=password]', `password`); | ||||
|   await page.locator('input[name=user_name]').fill(`user2`); | ||||
|   await page.locator('input[name=password]').fill(`password`); | ||||
|   await page.click('form button.ui.primary.button:visible'); | ||||
|  | ||||
|   await page.waitForLoadState('networkidle'); // eslint-disable-line playwright/no-networkidle | ||||
|  | ||||
|   await expect(page.url()).toBe(`${workerInfo.project.use.baseURL}/`); | ||||
|   expect(page.url()).toBe(`${workerInfo.project.use.baseURL}/`); | ||||
|  | ||||
|   save_visual(page); | ||||
| }); | ||||
| @@ -50,7 +50,7 @@ test('logged in user', async ({browser}, workerInfo) => { | ||||
|   await page.goto('/'); | ||||
|  | ||||
|   // Make sure we routed to the home page. Else login failed. | ||||
|   await expect(page.url()).toBe(`${workerInfo.project.use.baseURL}/`); | ||||
|   expect(page.url()).toBe(`${workerInfo.project.use.baseURL}/`); | ||||
|  | ||||
|   save_visual(page); | ||||
| }); | ||||
|   | ||||
| @@ -14,7 +14,7 @@ export async function login_user(browser, workerInfo, user) { | ||||
|   // Route to login page | ||||
|   // Note: this could probably be done more quickly with a POST | ||||
|   const response = await page.goto('/user/login'); | ||||
|   await expect(response?.status()).toBe(200); // Status OK | ||||
|   expect(response?.status()).toBe(200); // Status OK | ||||
|  | ||||
|   // Fill out form | ||||
|   await page.type('input[name=user_name]', user); | ||||
| @@ -23,7 +23,7 @@ export async function login_user(browser, workerInfo, user) { | ||||
|  | ||||
|   await page.waitForLoadState('networkidle'); // eslint-disable-line playwright/no-networkidle | ||||
|  | ||||
|   await expect(page.url(), {message: `Failed to login user ${user}`}).toBe(`${workerInfo.project.use.baseURL}/`); | ||||
|   expect(page.url(), {message: `Failed to login user ${user}`}).toBe(`${workerInfo.project.use.baseURL}/`); | ||||
|  | ||||
|   // Save state | ||||
|   await context.storageState({path: `${ARTIFACTS_PATH}/state-${user}-${workerInfo.workerIndex}.json`}); | ||||
|   | ||||
| @@ -89,7 +89,9 @@ const sfc = { | ||||
|     // load job data and then auto-reload periodically | ||||
|     // need to await first loadJob so this.currentJobStepsStates is initialized and can be used in hashChangeListener | ||||
|     await this.loadJob(); | ||||
|     this.intervalID = setInterval(this.loadJob, 1000); | ||||
|     this.intervalID = setInterval(() => { | ||||
|       this.loadJob(); | ||||
|     }, 1000); | ||||
|     document.body.addEventListener('click', this.closeDropdown); | ||||
|     this.hashChangeListener(); | ||||
|     window.addEventListener('hashchange', this.hashChangeListener); | ||||
|   | ||||
| @@ -153,7 +153,7 @@ export function initRepoCodeView() { | ||||
|     }); | ||||
|  | ||||
|     $(window).on('hashchange', () => { | ||||
|       let m = rangeAnchorRegex.exec(window.location.hash.match); | ||||
|       let m = rangeAnchorRegex.exec(window.location.hash); | ||||
|       const $linesEls = $(getLineEls()); | ||||
|       let $first; | ||||
|       if (m) { | ||||
| @@ -170,7 +170,7 @@ export function initRepoCodeView() { | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
|       m = singleAnchorRegex.exec(window.location.hash.match); | ||||
|       m = singleAnchorRegex.exec(window.location.hash); | ||||
|       if (m) { | ||||
|         $first = $linesEls.filter(`[rel=L${m[2]}]`); | ||||
|         if ($first.length) { | ||||
|   | ||||
| @@ -55,8 +55,8 @@ export function filterRepoFilesWeighted(files, filter) { | ||||
|     const filterLower = filter.toLowerCase(); | ||||
|     // TODO: for large repo, this loop could be slow, maybe there could be one more limit: | ||||
|     // ... && filterResult.length < threshold * 20,  wait for more feedbacks | ||||
|     for (let i = 0; i < files.length; i++) { | ||||
|       const res = strSubMatch(files[i], filterLower); | ||||
|     for (const file of files) { | ||||
|       const res = strSubMatch(file, filterLower); | ||||
|       if (res.length > 1) { // length==1 means unmatched, >1 means having matched sub strings | ||||
|         filterResult.push({matchResult: res, matchWeight: calcMatchedWeight(res)}); | ||||
|       } | ||||
|   | ||||
| @@ -102,16 +102,16 @@ export function initRepoTopicBar() { | ||||
|  | ||||
|         if (res.topics) { | ||||
|           let found = false; | ||||
|           for (let i = 0; i < res.topics.length; i++) { | ||||
|           for (const {topic_name} of res.topics) { | ||||
|             // skip currently added tags | ||||
|             if (current_topics.includes(res.topics[i].topic_name)) { | ||||
|             if (current_topics.includes(topic_name)) { | ||||
|               continue; | ||||
|             } | ||||
|  | ||||
|             if (res.topics[i].topic_name.toLowerCase() === query.toLowerCase()) { | ||||
|             if (topic_name.toLowerCase() === query.toLowerCase()) { | ||||
|               found_query = true; | ||||
|             } | ||||
|             formattedResponse.results.push({description: res.topics[i].topic_name, 'data-value': res.topics[i].topic_name}); | ||||
|             formattedResponse.results.push({description: topic_name, 'data-value': topic_name}); | ||||
|             found = true; | ||||
|           } | ||||
|           formattedResponse.success = found; | ||||
|   | ||||
| @@ -270,7 +270,7 @@ export function replaceTextareaSelection(textarea, text) { | ||||
|  | ||||
|   textarea.contentEditable = 'true'; | ||||
|   try { | ||||
|     success = document.execCommand('insertText', false, text); | ||||
|     success = document.execCommand('insertText', false, text); // eslint-disable-line deprecation/deprecation | ||||
|   } catch { | ||||
|     success = false; | ||||
|   } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 silverwind
					silverwind