This run took 102 seconds.
From 4992fae13e233a9fed3f54d1369f22d76556535e Mon Sep 17 00:00:00 2001
From: libraryupgrader <tools.libraryupgrader@tools.wmflabs.org>
Date: Mon, 4 May 2026 03:53:52 +0000
Subject: [PATCH] build: Updating dependencies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
composer:
* mediawiki/mediawiki-codesniffer: 50.0.0 → 51.0.0
npm:
* eslint-config-wikimedia: 0.32.3 → 0.32.4
Change-Id: Ic19d34190c1d25914c9a38415e7f77525e97b604
---
composer.json | 2 +-
package-lock.json | 795 ++++++++++++++++++++---------------
package.json | 2 +-
resources/uw.LicenseGroup.js | 2 -
resources/uw.units.js | 2 +-
5 files changed, 451 insertions(+), 352 deletions(-)
diff --git a/composer.json b/composer.json
index ea87f4b..0c86e21 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"require-dev": {
- "mediawiki/mediawiki-codesniffer": "50.0.0",
+ "mediawiki/mediawiki-codesniffer": "51.0.0",
"mediawiki/mediawiki-phan-config": "0.20.0",
"mediawiki/minus-x": "2.0.1",
"php-parallel-lint/php-console-highlighter": "1.0.0",
diff --git a/package-lock.json b/package-lock.json
index 4be23e1..34c2c42 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,7 +6,7 @@
"": {
"name": "UploadWizard",
"devDependencies": {
- "eslint-config-wikimedia": "0.32.3",
+ "eslint-config-wikimedia": "0.32.4",
"grunt": "1.6.2",
"grunt-banana-checker": "0.13.0",
"grunt-contrib-watch": "1.1.0",
@@ -221,19 +221,32 @@
}
},
"node_modules/@es-joy/jsdoccomment": {
- "version": "0.76.0",
- "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.76.0.tgz",
- "integrity": "sha512-g+RihtzFgGTx2WYCuTHbdOXJeAlGnROws0TeALx9ow/ZmOROOZkVg5wp/B44n0WJgI4SQFP1eWM2iRPlU2Y14w==",
+ "version": "0.86.0",
+ "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz",
+ "integrity": "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.8",
- "@typescript-eslint/types": "^8.46.0",
- "comment-parser": "1.4.1",
- "esquery": "^1.6.0",
- "jsdoc-type-pratt-parser": "~6.10.0"
+ "@typescript-eslint/types": "^8.58.0",
+ "comment-parser": "1.4.6",
+ "esquery": "^1.7.0",
+ "jsdoc-type-pratt-parser": "~7.2.0"
},
"engines": {
- "node": ">=20.11.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": {
+ "version": "8.59.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz",
+ "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==",
+ "dev": true,
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@es-joy/resolve.exports": {
@@ -246,11 +259,10 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
- "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.4.3"
},
@@ -386,9 +398,9 @@
}
},
"node_modules/@mdn/browser-compat-data": {
- "version": "5.7.6",
- "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
- "integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
+ "version": "6.1.5",
+ "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-6.1.5.tgz",
+ "integrity": "sha512-PzdZZzRhcXvKB0begee28n5lvwAcinGKYuLZOVxHAZm+n7y01ddEGfdS1ZXRuVcV+ndG6mSEAE8vgudom5UjYg==",
"dev": true
},
"node_modules/@nodelib/fs.scandir": {
@@ -588,20 +600,19 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz",
- "integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz",
+ "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
"dev": true,
"dependencies": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/type-utils": "8.46.0",
- "@typescript-eslint/utils": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "graphemer": "^1.4.0",
- "ignore": "^7.0.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/type-utils": "8.54.0",
+ "@typescript-eslint/utils": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "ignore": "^7.0.5",
"natural-compare": "^1.4.0",
- "ts-api-utils": "^2.1.0"
+ "ts-api-utils": "^2.4.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -611,7 +622,7 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "@typescript-eslint/parser": "^8.46.0",
+ "@typescript-eslint/parser": "^8.54.0",
"eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
@@ -626,16 +637,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz",
- "integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz",
+ "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "debug": "^4.3.4"
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -650,14 +661,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.0.tgz",
- "integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz",
+ "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==",
"dev": true,
"dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.46.0",
- "@typescript-eslint/types": "^8.46.0",
- "debug": "^4.3.4"
+ "@typescript-eslint/tsconfig-utils": "^8.54.0",
+ "@typescript-eslint/types": "^8.54.0",
+ "debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -671,13 +682,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz",
- "integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz",
+ "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0"
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -688,9 +699,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz",
- "integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz",
+ "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -704,16 +715,16 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz",
- "integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz",
+ "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0",
- "@typescript-eslint/utils": "8.46.0",
- "debug": "^4.3.4",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0",
+ "@typescript-eslint/utils": "8.54.0",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.4.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -728,9 +739,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz",
- "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz",
+ "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -741,21 +752,20 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz",
- "integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz",
+ "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/project-service": "8.46.0",
- "@typescript-eslint/tsconfig-utils": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/project-service": "8.54.0",
+ "@typescript-eslint/tsconfig-utils": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "debug": "^4.4.3",
+ "minimatch": "^9.0.5",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.4.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -769,9 +779,9 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
- "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
+ "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
@@ -793,15 +803,15 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.0.tgz",
- "integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz",
+ "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==",
"dev": true,
"dependencies": {
- "@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0"
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -816,12 +826,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz",
- "integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz",
+ "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "8.46.0",
+ "@typescript-eslint/types": "8.54.0",
"eslint-visitor-keys": "^4.2.1"
},
"engines": {
@@ -867,11 +877,10 @@
"dev": true
},
"node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
- "license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@@ -1000,6 +1009,12 @@
"@mdn/browser-compat-data": "^5.6.19"
}
},
+ "node_modules/ast-metadata-inferer/node_modules/@mdn/browser-compat-data": {
+ "version": "5.7.6",
+ "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
+ "integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
+ "dev": true
+ },
"node_modules/astral-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
@@ -1306,9 +1321,9 @@
}
},
"node_modules/comment-parser": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz",
- "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==",
+ "version": "1.4.6",
+ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz",
+ "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==",
"dev": true,
"engines": {
"node": ">= 12.0.0"
@@ -1690,13 +1705,13 @@
}
},
"node_modules/enhanced-resolve": {
- "version": "5.18.3",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
- "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
+ "version": "5.21.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.0.tgz",
+ "integrity": "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
+ "tapable": "^2.3.3"
},
"engines": {
"node": ">=10.13.0"
@@ -1866,46 +1881,47 @@
}
},
"node_modules/eslint-config-wikimedia": {
- "version": "0.32.3",
- "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.32.3.tgz",
- "integrity": "sha512-Ekz2/ozpCCjQl3VbC6dW7ChqoW7FRilLDxmJ+FJOZhIxxzZSZR5QqQOAGWSZAlG1ONkZbYV/TPwGLWZcrNxyaA==",
+ "version": "0.32.4",
+ "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.32.4.tgz",
+ "integrity": "sha512-zcHJYss2vo8HK5PzkFuaV9mzaSGRuhA+jFGoQ4rNIwWz0usZsuQ2LYpkKxrbCVX1CbV0PzG+jJ6p0cLI+G37JQ==",
"dev": true,
"dependencies": {
"@stylistic/eslint-plugin": "^3.1.0",
- "@typescript-eslint/eslint-plugin": "8.46.0",
- "@typescript-eslint/parser": "8.46.0",
+ "@typescript-eslint/eslint-plugin": "8.54.0",
+ "@typescript-eslint/parser": "8.54.0",
"browserslist-config-wikimedia": "^0.7.0",
- "eslint": "^8.57.0",
- "eslint-plugin-compat": "^6.0.2",
+ "eslint-plugin-compat": "^6.1.0",
"eslint-plugin-es-x": "^8.7.0",
- "eslint-plugin-jest": "^29.0.1",
- "eslint-plugin-jsdoc": "61.3.0",
+ "eslint-plugin-jest": "^29.12.2",
+ "eslint-plugin-jsdoc": "^62.9.0",
"eslint-plugin-json-es": "^1.6.0",
- "eslint-plugin-mediawiki": "^0.8.2",
+ "eslint-plugin-mediawiki": "^0.8.3",
"eslint-plugin-mocha": "^10.5.0",
- "eslint-plugin-n": "^17.23.1",
- "eslint-plugin-no-jquery": "^3.1.1",
- "eslint-plugin-qunit": "^8.2.5",
- "eslint-plugin-security": "^3.0.1",
+ "eslint-plugin-n": "^17.24.0",
+ "eslint-plugin-no-jquery": "^4.0.0",
+ "eslint-plugin-qunit": "^8.2.6",
+ "eslint-plugin-security": "^4.0.0",
"eslint-plugin-unicorn": "^56.0.1",
"eslint-plugin-vue": "^9.33.0",
- "eslint-plugin-wdio": "^9.16.2",
+ "eslint-plugin-wdio": "9.23.0",
"eslint-plugin-yml": "^1.19.0"
},
"engines": {
"node": ">=20 <25"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0"
}
},
"node_modules/eslint-plugin-compat": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.0.2.tgz",
- "integrity": "sha512-1ME+YfJjmOz1blH0nPZpHgjMGK4kjgEeoYqGCqoBPQ/mGu/dJzdoP0f1C8H2jcWZjzhZjAMccbM/VdXhPORIfA==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.2.1.tgz",
+ "integrity": "sha512-gLKqUH+lQcCL+HzsROUjBDvakc5Zaga51Y4ZAkPCXc41pzKBfyluqTr2j8zOx8QQQb7zyglu1LVoL5aSNWf2SQ==",
"dev": true,
"dependencies": {
- "@mdn/browser-compat-data": "^5.5.35",
+ "@mdn/browser-compat-data": "^6.1.1",
"ast-metadata-inferer": "^0.8.1",
- "browserslist": "^4.24.2",
- "caniuse-lite": "^1.0.30001687",
+ "browserslist": "^4.25.2",
"find-up": "^5.0.0",
"globals": "^15.7.0",
"lodash.memoize": "^4.1.2",
@@ -1915,7 +1931,7 @@
"node": ">=18.x"
},
"peerDependencies": {
- "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
+ "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0"
}
},
"node_modules/eslint-plugin-compat/node_modules/globals": {
@@ -1981,57 +1997,57 @@
}
},
"node_modules/eslint-plugin-jsdoc": {
- "version": "61.3.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-61.3.0.tgz",
- "integrity": "sha512-E4m/5J5lrasd63Z74q4CCZ4PFnywnnrcvA7zZ98802NPhrZKKTp5NH+XAT+afcjXp2ps2/OQF5gPSWCT2XFCJg==",
+ "version": "62.9.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.9.0.tgz",
+ "integrity": "sha512-PY7/X4jrVgoIDncUmITlUqK546Ltmx/Pd4Hdsu4CvSjryQZJI2mEV4vrdMufyTetMiZ5taNSqvK//BTgVUlNkA==",
"dev": true,
"dependencies": {
- "@es-joy/jsdoccomment": "~0.76.0",
+ "@es-joy/jsdoccomment": "~0.86.0",
"@es-joy/resolve.exports": "1.2.0",
"are-docs-informative": "^0.0.2",
- "comment-parser": "1.4.1",
+ "comment-parser": "1.4.6",
"debug": "^4.4.3",
"escape-string-regexp": "^4.0.0",
- "espree": "^10.4.0",
- "esquery": "^1.6.0",
+ "espree": "^11.2.0",
+ "esquery": "^1.7.0",
"html-entities": "^2.6.0",
"object-deep-merge": "^2.0.0",
"parse-imports-exports": "^0.2.4",
- "semver": "^7.7.3",
+ "semver": "^7.7.4",
"spdx-expression-parse": "^4.0.0",
"to-valid-identifier": "^1.0.0"
},
"engines": {
- "node": ">=20.11.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
+ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0"
}
},
"node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true,
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-plugin-jsdoc/node_modules/espree": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
- "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+ "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
"dev": true,
"dependencies": {
- "acorn": "^8.15.0",
+ "acorn": "^8.16.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.2.1"
+ "eslint-visitor-keys": "^5.0.1"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
@@ -2051,9 +2067,9 @@
}
},
"node_modules/eslint-plugin-mediawiki": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.8.2.tgz",
- "integrity": "sha512-ydYrpkzm8IVVDQA96QPF3HnFd2xjkIEh7gixD2gvOqUbUZF0p36LtpWXOFAlPWAvHLePWbNNTD5ovd3d4hEtog==",
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.8.3.tgz",
+ "integrity": "sha512-RQKZd40C1taMDk5N9+aFLEBGBB95RNG7Gc54EsJ8pHsJu8//nIdpxNFWPtQz6RNxz6pZUXBnMCxzkMOLM3Mm1w==",
"dev": true,
"dependencies": {
"upath": "^2.0.1"
@@ -2080,9 +2096,9 @@
}
},
"node_modules/eslint-plugin-n": {
- "version": "17.23.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.23.1.tgz",
- "integrity": "sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==",
+ "version": "17.24.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.24.0.tgz",
+ "integrity": "sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.5.0",
@@ -2154,31 +2170,34 @@
}
},
"node_modules/eslint-plugin-no-jquery": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
- "integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-4.0.0.tgz",
+ "integrity": "sha512-ZR631D3qIQfgjKOAcgvYa5cB8xdTvFXAD5MbK5x5WltLSwFxmGnoaTXNtnptFU7py07ALrIe5dZRYncu4RD/Ug==",
"dev": true,
"peerDependencies": {
- "eslint": ">=8.0.0"
+ "eslint": ">=8.0.0 <9.0.0"
}
},
"node_modules/eslint-plugin-qunit": {
- "version": "8.2.5",
- "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-8.2.5.tgz",
- "integrity": "sha512-qr7RJCYImKQjB+39q4q46i1l7p1V3joHzBE5CAYfxn5tfVFjrnjn/tw7q/kDyweU9kAIcLul0Dx/KWVUCb3BgA==",
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-8.2.6.tgz",
+ "integrity": "sha512-S1jC/DIW9J8VtNX4uG1vlf5FZVrfQFlcuiYmvTHR2IICUhubHqpWA5o+qS1tujh+81Gs39omKV2D4OXfbSJE5g==",
"dev": true,
"dependencies": {
- "eslint-utils": "^3.0.0",
+ "@eslint-community/eslint-utils": "^4.4.0",
"requireindex": "^1.2.0"
},
"engines": {
"node": "^16.0.0 || ^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=8.38.0"
}
},
"node_modules/eslint-plugin-security": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.1.tgz",
- "integrity": "sha512-XjVGBhtDZJfyuhIxnQ/WMm385RbX3DBu7H1J7HNNhmB2tnGxMeqVSnYv79oAj992ayvIBZghsymwkYFS6cGH4Q==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-4.0.0.tgz",
+ "integrity": "sha512-tfuQT8K/Li1ZxhFzyD8wPIKtlzZxqBcPr9q0jFMQ77wWAbKBVEhaMPVQRTMTvCMUDhwBe5vPVqQPwAGk/ASfxQ==",
"dev": true,
"dependencies": {
"safe-regex": "^2.1.1"
@@ -2258,9 +2277,9 @@
}
},
"node_modules/eslint-plugin-wdio": {
- "version": "9.16.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-9.16.2.tgz",
- "integrity": "sha512-qkqsPgxN70OnUPWMjmzJbSbvm2+Q087JIGss53/OFI4Y46xKlV5VLhLiYealaAibAiXmnfWKd0tERjZAzVL87A==",
+ "version": "9.23.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-9.23.0.tgz",
+ "integrity": "sha512-8tcpupzp2Qmv+uSfhzeHi42LVA9PyjkpMBPclSIkPxBfXpj4fMrejwAHu1PROh1OmJN1VQcGQUTWvSzyRcV2vA==",
"dev": true,
"engines": {
"node": ">=18.20.0"
@@ -2405,9 +2424,9 @@
}
},
"node_modules/esquery": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
- "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
"dev": true,
"dependencies": {
"estraverse": "^5.1.0"
@@ -2765,9 +2784,9 @@
}
},
"node_modules/get-tsconfig": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
- "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
+ "version": "4.14.0",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz",
+ "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==",
"dev": true,
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
@@ -3562,9 +3581,9 @@
"dev": true
},
"node_modules/jsdoc-type-pratt-parser": {
- "version": "6.10.0",
- "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-6.10.0.tgz",
- "integrity": "sha512-+LexoTRyYui5iOhJGn13N9ZazL23nAHGkXsa1p/C8yeq79WRfLBag6ZZ0FQG2aRoc9yfo59JT9EYCQonOkHKkQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.2.0.tgz",
+ "integrity": "sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==",
"dev": true,
"engines": {
"node": ">=20.0.0"
@@ -4944,9 +4963,9 @@
"dev": true
},
"node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -5572,9 +5591,9 @@
"dev": true
},
"node_modules/tapable": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
- "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
"dev": true,
"engines": {
"node": ">=6"
@@ -5613,6 +5632,51 @@
"ms": "^2.1.1"
}
},
+ "node_modules/tinyglobby": {
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+ "dev": true,
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -5642,9 +5706,9 @@
}
},
"node_modules/ts-api-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
- "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
"dev": true,
"engines": {
"node": ">=18.12"
@@ -6170,16 +6234,24 @@
"dev": true
},
"@es-joy/jsdoccomment": {
- "version": "0.76.0",
- "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.76.0.tgz",
- "integrity": "sha512-g+RihtzFgGTx2WYCuTHbdOXJeAlGnROws0TeALx9ow/ZmOROOZkVg5wp/B44n0WJgI4SQFP1eWM2iRPlU2Y14w==",
+ "version": "0.86.0",
+ "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz",
+ "integrity": "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw==",
"dev": true,
"requires": {
"@types/estree": "^1.0.8",
- "@typescript-eslint/types": "^8.46.0",
- "comment-parser": "1.4.1",
- "esquery": "^1.6.0",
- "jsdoc-type-pratt-parser": "~6.10.0"
+ "@typescript-eslint/types": "^8.58.0",
+ "comment-parser": "1.4.6",
+ "esquery": "^1.7.0",
+ "jsdoc-type-pratt-parser": "~7.2.0"
+ },
+ "dependencies": {
+ "@typescript-eslint/types": {
+ "version": "8.59.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz",
+ "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==",
+ "dev": true
+ }
}
},
"@es-joy/resolve.exports": {
@@ -6189,9 +6261,9 @@
"dev": true
},
"@eslint-community/eslint-utils": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
- "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
"dev": true,
"requires": {
"eslint-visitor-keys": "^3.4.3"
@@ -6285,9 +6357,9 @@
}
},
"@mdn/browser-compat-data": {
- "version": "5.7.6",
- "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
- "integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
+ "version": "6.1.5",
+ "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-6.1.5.tgz",
+ "integrity": "sha512-PzdZZzRhcXvKB0begee28n5lvwAcinGKYuLZOVxHAZm+n7y01ddEGfdS1ZXRuVcV+ndG6mSEAE8vgudom5UjYg==",
"dev": true
},
"@nodelib/fs.scandir": {
@@ -6434,20 +6506,19 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz",
- "integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz",
+ "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
"dev": true,
"requires": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/type-utils": "8.46.0",
- "@typescript-eslint/utils": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "graphemer": "^1.4.0",
- "ignore": "^7.0.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/type-utils": "8.54.0",
+ "@typescript-eslint/utils": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "ignore": "^7.0.5",
"natural-compare": "^1.4.0",
- "ts-api-utils": "^2.1.0"
+ "ts-api-utils": "^2.4.0"
},
"dependencies": {
"ignore": {
@@ -6459,87 +6530,86 @@
}
},
"@typescript-eslint/parser": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz",
- "integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz",
+ "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
"dev": true,
"requires": {
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "debug": "^4.3.4"
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "debug": "^4.4.3"
}
},
"@typescript-eslint/project-service": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.0.tgz",
- "integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz",
+ "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==",
"dev": true,
"requires": {
- "@typescript-eslint/tsconfig-utils": "^8.46.0",
- "@typescript-eslint/types": "^8.46.0",
- "debug": "^4.3.4"
+ "@typescript-eslint/tsconfig-utils": "^8.54.0",
+ "@typescript-eslint/types": "^8.54.0",
+ "debug": "^4.4.3"
}
},
"@typescript-eslint/scope-manager": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz",
- "integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz",
+ "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0"
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0"
}
},
"@typescript-eslint/tsconfig-utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz",
- "integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz",
+ "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==",
"dev": true,
"requires": {}
},
"@typescript-eslint/type-utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz",
- "integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz",
+ "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0",
- "@typescript-eslint/utils": "8.46.0",
- "debug": "^4.3.4",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0",
+ "@typescript-eslint/utils": "8.54.0",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.4.0"
}
},
"@typescript-eslint/types": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz",
- "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz",
+ "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz",
- "integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz",
+ "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==",
"dev": true,
"requires": {
- "@typescript-eslint/project-service": "8.46.0",
- "@typescript-eslint/tsconfig-utils": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/project-service": "8.54.0",
+ "@typescript-eslint/tsconfig-utils": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "debug": "^4.4.3",
+ "minimatch": "^9.0.5",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.4.0"
},
"dependencies": {
"brace-expansion": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
- "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
+ "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0"
@@ -6557,24 +6627,24 @@
}
},
"@typescript-eslint/utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.0.tgz",
- "integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz",
+ "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==",
"dev": true,
"requires": {
- "@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0"
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0"
}
},
"@typescript-eslint/visitor-keys": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz",
- "integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz",
+ "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "8.46.0",
+ "@typescript-eslint/types": "8.54.0",
"eslint-visitor-keys": "^4.2.1"
},
"dependencies": {
@@ -6605,9 +6675,9 @@
"dev": true
},
"acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true
},
"acorn-jsx": {
@@ -6696,6 +6766,14 @@
"dev": true,
"requires": {
"@mdn/browser-compat-data": "^5.6.19"
+ },
+ "dependencies": {
+ "@mdn/browser-compat-data": {
+ "version": "5.7.6",
+ "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
+ "integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
+ "dev": true
+ }
}
},
"astral-regex": {
@@ -6909,9 +6987,9 @@
"dev": true
},
"comment-parser": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz",
- "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==",
+ "version": "1.4.6",
+ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz",
+ "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==",
"dev": true
},
"concat-map": {
@@ -7201,13 +7279,13 @@
}
},
"enhanced-resolve": {
- "version": "5.18.3",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
- "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
+ "version": "5.21.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.0.tgz",
+ "integrity": "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
+ "tapable": "^2.3.3"
}
},
"entities": {
@@ -7356,43 +7434,41 @@
}
},
"eslint-config-wikimedia": {
- "version": "0.32.3",
- "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.32.3.tgz",
- "integrity": "sha512-Ekz2/ozpCCjQl3VbC6dW7ChqoW7FRilLDxmJ+FJOZhIxxzZSZR5QqQOAGWSZAlG1ONkZbYV/TPwGLWZcrNxyaA==",
+ "version": "0.32.4",
+ "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.32.4.tgz",
+ "integrity": "sha512-zcHJYss2vo8HK5PzkFuaV9mzaSGRuhA+jFGoQ4rNIwWz0usZsuQ2LYpkKxrbCVX1CbV0PzG+jJ6p0cLI+G37JQ==",
"dev": true,
"requires": {
"@stylistic/eslint-plugin": "^3.1.0",
- "@typescript-eslint/eslint-plugin": "8.46.0",
- "@typescript-eslint/parser": "8.46.0",
+ "@typescript-eslint/eslint-plugin": "8.54.0",
+ "@typescript-eslint/parser": "8.54.0",
"browserslist-config-wikimedia": "^0.7.0",
- "eslint": "^8.57.0",
- "eslint-plugin-compat": "^6.0.2",
+ "eslint-plugin-compat": "^6.1.0",
"eslint-plugin-es-x": "^8.7.0",
- "eslint-plugin-jest": "^29.0.1",
- "eslint-plugin-jsdoc": "61.3.0",
+ "eslint-plugin-jest": "^29.12.2",
+ "eslint-plugin-jsdoc": "^62.9.0",
"eslint-plugin-json-es": "^1.6.0",
- "eslint-plugin-mediawiki": "^0.8.2",
+ "eslint-plugin-mediawiki": "^0.8.3",
"eslint-plugin-mocha": "^10.5.0",
- "eslint-plugin-n": "^17.23.1",
- "eslint-plugin-no-jquery": "^3.1.1",
- "eslint-plugin-qunit": "^8.2.5",
- "eslint-plugin-security": "^3.0.1",
+ "eslint-plugin-n": "^17.24.0",
+ "eslint-plugin-no-jquery": "^4.0.0",
+ "eslint-plugin-qunit": "^8.2.6",
+ "eslint-plugin-security": "^4.0.0",
"eslint-plugin-unicorn": "^56.0.1",
"eslint-plugin-vue": "^9.33.0",
- "eslint-plugin-wdio": "^9.16.2",
+ "eslint-plugin-wdio": "9.23.0",
"eslint-plugin-yml": "^1.19.0"
}
},
"eslint-plugin-compat": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.0.2.tgz",
- "integrity": "sha512-1ME+YfJjmOz1blH0nPZpHgjMGK4kjgEeoYqGCqoBPQ/mGu/dJzdoP0f1C8H2jcWZjzhZjAMccbM/VdXhPORIfA==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.2.1.tgz",
+ "integrity": "sha512-gLKqUH+lQcCL+HzsROUjBDvakc5Zaga51Y4ZAkPCXc41pzKBfyluqTr2j8zOx8QQQb7zyglu1LVoL5aSNWf2SQ==",
"dev": true,
"requires": {
- "@mdn/browser-compat-data": "^5.5.35",
+ "@mdn/browser-compat-data": "^6.1.1",
"ast-metadata-inferer": "^0.8.1",
- "browserslist": "^4.24.2",
- "caniuse-lite": "^1.0.30001687",
+ "browserslist": "^4.25.2",
"find-up": "^5.0.0",
"globals": "^15.7.0",
"lodash.memoize": "^4.1.2",
@@ -7428,42 +7504,42 @@
}
},
"eslint-plugin-jsdoc": {
- "version": "61.3.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-61.3.0.tgz",
- "integrity": "sha512-E4m/5J5lrasd63Z74q4CCZ4PFnywnnrcvA7zZ98802NPhrZKKTp5NH+XAT+afcjXp2ps2/OQF5gPSWCT2XFCJg==",
+ "version": "62.9.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.9.0.tgz",
+ "integrity": "sha512-PY7/X4jrVgoIDncUmITlUqK546Ltmx/Pd4Hdsu4CvSjryQZJI2mEV4vrdMufyTetMiZ5taNSqvK//BTgVUlNkA==",
"dev": true,
"requires": {
- "@es-joy/jsdoccomment": "~0.76.0",
+ "@es-joy/jsdoccomment": "~0.86.0",
"@es-joy/resolve.exports": "1.2.0",
"are-docs-informative": "^0.0.2",
- "comment-parser": "1.4.1",
+ "comment-parser": "1.4.6",
"debug": "^4.4.3",
"escape-string-regexp": "^4.0.0",
- "espree": "^10.4.0",
- "esquery": "^1.6.0",
+ "espree": "^11.2.0",
+ "esquery": "^1.7.0",
"html-entities": "^2.6.0",
"object-deep-merge": "^2.0.0",
"parse-imports-exports": "^0.2.4",
- "semver": "^7.7.3",
+ "semver": "^7.7.4",
"spdx-expression-parse": "^4.0.0",
"to-valid-identifier": "^1.0.0"
},
"dependencies": {
"eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true
},
"espree": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
- "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+ "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
"dev": true,
"requires": {
- "acorn": "^8.15.0",
+ "acorn": "^8.16.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.2.1"
+ "eslint-visitor-keys": "^5.0.1"
}
}
}
@@ -7479,9 +7555,9 @@
}
},
"eslint-plugin-mediawiki": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.8.2.tgz",
- "integrity": "sha512-ydYrpkzm8IVVDQA96QPF3HnFd2xjkIEh7gixD2gvOqUbUZF0p36LtpWXOFAlPWAvHLePWbNNTD5ovd3d4hEtog==",
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.8.3.tgz",
+ "integrity": "sha512-RQKZd40C1taMDk5N9+aFLEBGBB95RNG7Gc54EsJ8pHsJu8//nIdpxNFWPtQz6RNxz6pZUXBnMCxzkMOLM3Mm1w==",
"dev": true,
"requires": {
"upath": "^2.0.1"
@@ -7499,9 +7575,9 @@
}
},
"eslint-plugin-n": {
- "version": "17.23.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.23.1.tgz",
- "integrity": "sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==",
+ "version": "17.24.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.24.0.tgz",
+ "integrity": "sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.5.0",
@@ -7544,26 +7620,26 @@
}
},
"eslint-plugin-no-jquery": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
- "integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-4.0.0.tgz",
+ "integrity": "sha512-ZR631D3qIQfgjKOAcgvYa5cB8xdTvFXAD5MbK5x5WltLSwFxmGnoaTXNtnptFU7py07ALrIe5dZRYncu4RD/Ug==",
"dev": true,
"requires": {}
},
"eslint-plugin-qunit": {
- "version": "8.2.5",
- "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-8.2.5.tgz",
- "integrity": "sha512-qr7RJCYImKQjB+39q4q46i1l7p1V3joHzBE5CAYfxn5tfVFjrnjn/tw7q/kDyweU9kAIcLul0Dx/KWVUCb3BgA==",
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-8.2.6.tgz",
+ "integrity": "sha512-S1jC/DIW9J8VtNX4uG1vlf5FZVrfQFlcuiYmvTHR2IICUhubHqpWA5o+qS1tujh+81Gs39omKV2D4OXfbSJE5g==",
"dev": true,
"requires": {
- "eslint-utils": "^3.0.0",
+ "@eslint-community/eslint-utils": "^4.4.0",
"requireindex": "^1.2.0"
}
},
"eslint-plugin-security": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.1.tgz",
- "integrity": "sha512-XjVGBhtDZJfyuhIxnQ/WMm385RbX3DBu7H1J7HNNhmB2tnGxMeqVSnYv79oAj992ayvIBZghsymwkYFS6cGH4Q==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-4.0.0.tgz",
+ "integrity": "sha512-tfuQT8K/Li1ZxhFzyD8wPIKtlzZxqBcPr9q0jFMQ77wWAbKBVEhaMPVQRTMTvCMUDhwBe5vPVqQPwAGk/ASfxQ==",
"dev": true,
"requires": {
"safe-regex": "^2.1.1"
@@ -7618,9 +7694,9 @@
}
},
"eslint-plugin-wdio": {
- "version": "9.16.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-9.16.2.tgz",
- "integrity": "sha512-qkqsPgxN70OnUPWMjmzJbSbvm2+Q087JIGss53/OFI4Y46xKlV5VLhLiYealaAibAiXmnfWKd0tERjZAzVL87A==",
+ "version": "9.23.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-9.23.0.tgz",
+ "integrity": "sha512-8tcpupzp2Qmv+uSfhzeHi42LVA9PyjkpMBPclSIkPxBfXpj4fMrejwAHu1PROh1OmJN1VQcGQUTWvSzyRcV2vA==",
"dev": true
},
"eslint-plugin-yml": {
@@ -7688,9 +7764,9 @@
"dev": true
},
"esquery": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
- "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
"dev": true,
"requires": {
"estraverse": "^5.1.0"
@@ -7969,9 +8045,9 @@
}
},
"get-tsconfig": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
- "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
+ "version": "4.14.0",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz",
+ "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==",
"dev": true,
"requires": {
"resolve-pkg-maps": "^1.0.0"
@@ -8569,9 +8645,9 @@
"dev": true
},
"jsdoc-type-pratt-parser": {
- "version": "6.10.0",
- "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-6.10.0.tgz",
- "integrity": "sha512-+LexoTRyYui5iOhJGn13N9ZazL23nAHGkXsa1p/C8yeq79WRfLBag6ZZ0FQG2aRoc9yfo59JT9EYCQonOkHKkQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.2.0.tgz",
+ "integrity": "sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==",
"dev": true
},
"jsdoc-wmf-theme": {
@@ -9576,9 +9652,9 @@
"dev": true
},
"semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"dev": true
},
"shebang-command": {
@@ -10008,9 +10084,9 @@
}
},
"tapable": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
- "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
"dev": true
},
"text-table": {
@@ -10044,6 +10120,31 @@
}
}
},
+ "tinyglobby": {
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+ "dev": true,
+ "requires": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "dependencies": {
+ "fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "requires": {}
+ },
+ "picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true
+ }
+ }
+ },
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -10064,9 +10165,9 @@
}
},
"ts-api-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
- "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
"dev": true,
"requires": {}
},
diff --git a/package.json b/package.json
index 0f5882c..fb8a802 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"test": "grunt test"
},
"devDependencies": {
- "eslint-config-wikimedia": "0.32.3",
+ "eslint-config-wikimedia": "0.32.4",
"grunt": "1.6.2",
"grunt-banana-checker": "0.13.0",
"grunt-contrib-watch": "1.1.0",
diff --git a/resources/uw.LicenseGroup.js b/resources/uw.LicenseGroup.js
index fb8b802..395baac 100644
--- a/resources/uw.LicenseGroup.js
+++ b/resources/uw.LicenseGroup.js
@@ -161,7 +161,6 @@
options.push( option );
} );
- // eslint-disable-next-line mediawiki/class-doc
return new OO.ui.RadioSelectWidget( { items: options, classes: classes } );
};
@@ -194,7 +193,6 @@
options.push( option );
} );
- // eslint-disable-next-line mediawiki/class-doc
return new OO.ui.CheckboxMultiselectWidget( { items: options, classes: classes } );
};
diff --git a/resources/uw.units.js b/resources/uw.units.js
index 0b2caeb..dace9d3 100644
--- a/resources/uw.units.js
+++ b/resources/uw.units.js
@@ -19,7 +19,7 @@
i++;
}
// Messages are documented above (scaleMsgKeys)
- // eslint-disable-next-line mediawiki/msg-doc
+
return mw.message( scaleMsgKeys[ i ], size.toFixed( i > 1 ? 2 : 0 ) ).text();
}
};
--
2.47.3
$ date
--- stdout ---
Mon May 4 03:52:25 UTC 2026
--- end ---
$ git clone file:///srv/git/mediawiki-extensions-UploadWizard.git /src/repo --depth=1 -b master
--- stderr ---
Cloning into '/src/repo'...
--- stdout ---
--- end ---
$ git config user.name libraryupgrader
--- stdout ---
--- end ---
$ git config user.email tools.libraryupgrader@tools.wmflabs.org
--- stdout ---
--- end ---
$ git submodule update --init
--- stdout ---
--- end ---
$ grr init
--- stdout ---
Installed commit-msg hook.
--- end ---
$ git show-ref refs/heads/master
--- stdout ---
fe7f6073ea52b210bd8e397bce9b36cb527da621 refs/heads/master
--- end ---
$ /usr/bin/npm audit --json
--- stdout ---
{
"auditReportVersion": 2,
"vulnerabilities": {
"gaze": {
"name": "gaze",
"severity": "high",
"isDirect": false,
"via": [
"globule"
],
"effects": [
"grunt-contrib-watch"
],
"range": ">=0.4.0",
"nodes": [
"node_modules/gaze"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
},
"globule": {
"name": "globule",
"severity": "high",
"isDirect": false,
"via": [
"minimatch"
],
"effects": [
"gaze"
],
"range": "*",
"nodes": [
"node_modules/globule"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
},
"grunt-contrib-watch": {
"name": "grunt-contrib-watch",
"severity": "high",
"isDirect": true,
"via": [
"gaze"
],
"effects": [],
"range": ">=0.5.0",
"nodes": [
"node_modules/grunt-contrib-watch"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
},
"minimatch": {
"name": "minimatch",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1113459,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch has a ReDoS via repeated wildcards with non-matching literal in pattern",
"url": "https://github.com/advisories/GHSA-3ppc-4f35-3m26",
"severity": "high",
"cwe": [
"CWE-1333"
],
"cvss": {
"score": 0,
"vectorString": null
},
"range": "<3.1.3"
},
{
"source": 1113538,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adjacent GLOBSTAR segments",
"url": "https://github.com/advisories/GHSA-7r86-cg39-jmmj",
"severity": "high",
"cwe": [
"CWE-407"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<3.1.3"
},
{
"source": 1113546,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions",
"url": "https://github.com/advisories/GHSA-23c5-xmqv-rm74",
"severity": "high",
"cwe": [
"CWE-1333"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<3.1.4"
}
],
"effects": [
"globule"
],
"range": "<=3.1.3",
"nodes": [
"node_modules/minimatch"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
}
},
"metadata": {
"vulnerabilities": {
"info": 0,
"low": 0,
"moderate": 0,
"high": 4,
"critical": 0,
"total": 4
},
"dependencies": {
"prod": 1,
"dev": 498,
"optional": 0,
"peer": 1,
"peerOptional": 0,
"total": 498
}
}
}
--- end ---
$ /usr/bin/composer install
--- stderr ---
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 37 installs, 0 updates, 0 removals
- Locking composer/pcre (3.3.2)
- Locking composer/semver (3.4.4)
- Locking composer/spdx-licenses (1.5.10)
- Locking composer/xdebug-handler (3.0.5)
- Locking danog/advanced-json-rpc (v3.2.3)
- Locking dealerdirect/phpcodesniffer-composer-installer (v1.2.0)
- Locking doctrine/deprecations (1.1.6)
- Locking mediawiki/mediawiki-codesniffer (v50.0.0)
- Locking mediawiki/mediawiki-phan-config (0.20.0)
- Locking mediawiki/minus-x (2.0.1)
- Locking mediawiki/phan-taint-check-plugin (9.1.0)
- Locking netresearch/jsonmapper (v5.0.1)
- Locking phan/phan (6.0.2)
- Locking phan/tolerant-php-parser (v0.2.0)
- Locking phan/var_representation_polyfill (0.1.4)
- Locking php-parallel-lint/php-console-color (v1.0.1)
- Locking php-parallel-lint/php-console-highlighter (v1.0.0)
- Locking php-parallel-lint/php-parallel-lint (v1.4.0)
- Locking phpcsstandards/phpcsextra (1.4.0)
- Locking phpcsstandards/phpcsutils (1.2.2)
- Locking phpdocumentor/reflection-common (2.2.0)
- Locking phpdocumentor/reflection-docblock (6.0.3)
- Locking phpdocumentor/type-resolver (2.0.0)
- Locking phpstan/phpdoc-parser (2.3.2)
- Locking psr/container (2.0.2)
- Locking psr/log (3.0.2)
- Locking sabre/event (6.1.0)
- Locking squizlabs/php_codesniffer (3.13.5)
- Locking symfony/console (v8.0.9)
- Locking symfony/deprecation-contracts (v3.6.0)
- Locking symfony/polyfill-ctype (v1.37.0)
- Locking symfony/polyfill-intl-grapheme (v1.37.0)
- Locking symfony/polyfill-intl-normalizer (v1.37.0)
- Locking symfony/polyfill-mbstring (v1.37.0)
- Locking symfony/service-contracts (v3.6.1)
- Locking symfony/string (v8.0.8)
- Locking webmozart/assert (2.3.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 37 installs, 0 updates, 0 removals
0 [>---------------------------] 0 [->--------------------------]
- Installing squizlabs/php_codesniffer (3.13.5): Extracting archive
- Installing dealerdirect/phpcodesniffer-composer-installer (v1.2.0): Extracting archive
- Installing composer/pcre (3.3.2): Extracting archive
- Installing phpcsstandards/phpcsutils (1.2.2): Extracting archive
- Installing phpcsstandards/phpcsextra (1.4.0): Extracting archive
- Installing symfony/polyfill-mbstring (v1.37.0): Extracting archive
- Installing composer/spdx-licenses (1.5.10): Extracting archive
- Installing composer/semver (3.4.4): Extracting archive
- Installing mediawiki/mediawiki-codesniffer (v50.0.0): Extracting archive
- Installing symfony/polyfill-intl-normalizer (v1.37.0): Extracting archive
- Installing symfony/polyfill-intl-grapheme (v1.37.0): Extracting archive
- Installing symfony/polyfill-ctype (v1.37.0): Extracting archive
- Installing symfony/string (v8.0.8): Extracting archive
- Installing symfony/deprecation-contracts (v3.6.0): Extracting archive
- Installing psr/container (2.0.2): Extracting archive
- Installing symfony/service-contracts (v3.6.1): Extracting archive
- Installing symfony/console (v8.0.9): Extracting archive
- Installing sabre/event (6.1.0): Extracting archive
- Installing phan/var_representation_polyfill (0.1.4): Extracting archive
- Installing phan/tolerant-php-parser (v0.2.0): Extracting archive
- Installing netresearch/jsonmapper (v5.0.1): Extracting archive
- Installing webmozart/assert (2.3.0): Extracting archive
- Installing phpstan/phpdoc-parser (2.3.2): Extracting archive
- Installing phpdocumentor/reflection-common (2.2.0): Extracting archive
- Installing doctrine/deprecations (1.1.6): Extracting archive
- Installing phpdocumentor/type-resolver (2.0.0): Extracting archive
- Installing phpdocumentor/reflection-docblock (6.0.3): Extracting archive
- Installing danog/advanced-json-rpc (v3.2.3): Extracting archive
- Installing psr/log (3.0.2): Extracting archive
- Installing composer/xdebug-handler (3.0.5): Extracting archive
- Installing phan/phan (6.0.2): Extracting archive
- Installing mediawiki/phan-taint-check-plugin (9.1.0): Extracting archive
- Installing mediawiki/mediawiki-phan-config (0.20.0): Extracting archive
- Installing mediawiki/minus-x (2.0.1): Extracting archive
- Installing php-parallel-lint/php-console-color (v1.0.1): Extracting archive
- Installing php-parallel-lint/php-console-highlighter (v1.0.0): Extracting archive
- Installing php-parallel-lint/php-parallel-lint (v1.4.0): Extracting archive
0/35 [>---------------------------] 0%
28/35 [======================>-----] 80%
35/35 [============================] 100%
1 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
16 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
--- stdout ---
PHP CodeSniffer Config installed_paths set to ../../mediawiki/mediawiki-codesniffer,../../phpcsstandards/phpcsextra,../../phpcsstandards/phpcsutils
--- end ---
Upgrading n:eslint-config-wikimedia from 0.32.3 -> 0.32.4
$ /usr/bin/npm install
--- stderr ---
npm WARN deprecated @humanwhocodes/config-array@0.13.0: Use @eslint/config-array instead
npm WARN deprecated @humanwhocodes/object-schema@2.0.3: Use @eslint/object-schema instead
npm WARN deprecated glob@7.1.7: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
npm WARN deprecated eslint@8.57.1: This version is no longer supported. Please see https://eslint.org/version-support for other options.
--- stdout ---
added 503 packages, and audited 504 packages in 7s
118 packages are looking for funding
run `npm fund` for details
4 high severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
--- end ---
$ package-lock-lint /src/repo/package-lock.json
--- stdout ---
Checking /src/repo/package-lock.json
--- end ---
$ /usr/bin/npm install grunt-eslint@24.3.0 --save-exact
--- stdout ---
up to date, audited 504 packages in 2s
118 packages are looking for funding
run `npm fund` for details
4 high severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
--- end ---
$ package-lock-lint /src/repo/package-lock.json
--- stdout ---
Checking /src/repo/package-lock.json
--- end ---
$ ./node_modules/.bin/eslint . --fix
--- stdout ---
/src/repo/resources/controller/uw.controller.Deed.js
47:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/controller/uw.controller.Details.js
164:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/controller/uw.controller.Tutorial.js
61:3 warning Prefer .then to .done no-jquery/no-done-fail
61:3 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/details/uw.CategoriesDetailsWidget.js
213:34 warning Prefer .then to .fail no-jquery/no-done-fail
242:36 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/details/uw.DateDetailsWidget.js
16:31 warning OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true mediawiki/no-unlabeled-buttonwidget
/src/repo/resources/details/uw.LocationDetailsWidget.js
25:20 warning OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true mediawiki/no-unlabeled-buttonwidget
67:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/details/uw.SingleLanguageInputWidget.js
45:23 warning OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true mediawiki/no-unlabeled-buttonwidget
/src/repo/resources/details/uw.StatementWidget.js
70:1 warning The type 'dataValues.DataValue' is undefined jsdoc/no-undefined-types
105:1 warning The type 'datamodel.StatementList' is undefined jsdoc/no-undefined-types
117:1 warning The type 'datamodel.StatementList' is undefined jsdoc/no-undefined-types
131:1 warning The type 'dataValues.DataValue' is undefined jsdoc/no-undefined-types
132:1 warning The type 'datamodel.Statement' is undefined jsdoc/no-undefined-types
145:1 warning The type 'datamodel.StatementList' is undefined jsdoc/no-undefined-types
/src/repo/resources/details/uw.TitleDetailsWidget.js
112:1 warning Missing JSDoc @param "thorough" type jsdoc/require-param-type
161:30 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
215:27 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
217:21 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/mw.DestinationChecker.js
14:3 warning Found more than one @return declaration jsdoc/require-returns
14:3 warning Found more than one @return declaration jsdoc/require-returns-check
35:3 warning Found more than one @return declaration jsdoc/require-returns
35:3 warning Found more than one @return declaration jsdoc/require-returns-check
80:3 warning Found more than one @return declaration jsdoc/require-returns
80:3 warning Found more than one @return declaration jsdoc/require-returns-check
/src/repo/resources/mw.FlickrChecker.js
4:1 warning Missing JSDoc @param "ui" type jsdoc/require-param-type
5:1 warning Missing JSDoc @param "selectButton" type jsdoc/require-param-type
212:1 warning The type 'getPhotos' is undefined jsdoc/no-undefined-types
226:17 warning 'data' is already declared in the upper scope on line 219 column 15 no-shadow
246:1 warning The type 'getCollection' is undefined jsdoc/no-undefined-types
304:45 warning 'data' is already declared in the upper scope on line 293 column 15 no-shadow
314:1 warning The type 'getPhotos' is undefined jsdoc/no-undefined-types
331:1 warning The type 'getPhotos' is undefined jsdoc/no-undefined-types
375:10 warning Prefer .then to .fail no-jquery/no-done-fail
468:5 warning Prefer .then to .done no-jquery/no-done-fail
519:10 warning Prefer .then to .fail no-jquery/no-done-fail
581:4 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/mw.UploadWizard.js
4:1 warning Missing JSDoc @param "uw" type jsdoc/require-param-type
9:1 warning Missing JSDoc @param "config" type jsdoc/require-param-type
112:16 warning 'steps' is already declared in the upper scope on line 86 column 10 no-shadow
/src/repo/resources/mw.UploadWizardDeedChooser.js
32:42 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
40:17 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
44:21 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/mw.UploadWizardDetails.js
498:5 warning Prefer .then to .done no-jquery/no-done-fail
678:1 warning Missing JSDoc @param "thorough" type jsdoc/require-param-type
715:4 warning Prefer .then to .done no-jquery/no-done-fail
935:3 warning JSDoc @return declaration present but return expression not available in function jsdoc/require-returns-check
/src/repo/resources/mw.UploadWizardLicenseInput.js
50:20 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
/src/repo/resources/mw.UploadWizardUpload.js
380:3 warning Prefer .then to .done no-jquery/no-done-fail
380:3 warning Prefer .then to .fail no-jquery/no-done-fail
445:3 warning Prefer .then to .done no-jquery/no-done-fail
445:3 warning Prefer .then to .fail no-jquery/no-done-fail
766:3 warning Prefer .then to .done no-jquery/no-done-fail
766:3 warning Prefer .then to .fail no-jquery/no-done-fail
774:6 warning Prefer .then to .done no-jquery/no-done-fail
777:7 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/mw.UploadWizardUploadInterface.js
215:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/transports/mw.FormDataTransport.js
166:5 warning Prefer .then to .done no-jquery/no-done-fail
167:6 warning Prefer .then to .done no-jquery/no-done-fail
167:6 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Deed.js
51:3 warning Prefer .then to .done no-jquery/no-done-fail
86:5 warning Prefer .then to .done no-jquery/no-done-fail
108:6 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Details.js
108:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Thanks.js
150:3 warning Prefer .then to .done no-jquery/no-done-fail
180:4 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
/src/repo/resources/ui/steps/uw.ui.Tutorial.js
126:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Upload.js
334:6 warning Prefer .then to .done no-jquery/no-done-fail
344:3 warning Prefer .then to .done no-jquery/no-done-fail
528:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/uw.ui.Step.js
111:3 warning Prefer .then to .done no-jquery/no-done-fail
120:3 warning Prefer .then to .done no-jquery/no-done-fail
166:12 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
180:7 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
197:5 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/ui/uw.ui.Wizard.js
141:25 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/uw.LicenseGroup.js
148:48 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
180:56 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
617:3 warning Prefer .then to .done no-jquery/no-done-fail
617:3 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/uw.ValidationMessageElement.js
92:10 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
92:10 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
/src/repo/tests/qunit/controller/uw.controller.Details.test.js
127:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/tests/qunit/transports/mw.FormDataTransport.test.js
142:3 warning Prefer .then to .fail no-jquery/no-done-fail
175:10 warning Prefer .then to .done no-jquery/no-done-fail
194:10 warning Prefer .then to .done no-jquery/no-done-fail
214:3 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/tests/qunit/uw.ConcurrentQueue.test.js
54:5 warning Prefer .then to .fail no-jquery/no-done-fail
✖ 89 problems (0 errors, 89 warnings)
--- end ---
$ ./node_modules/.bin/eslint . -f json
--- stdout ---
[{"filePath":"/src/repo/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/.stylelintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/Gruntfile.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/composer.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/extension.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/jsdoc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/package-lock.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/package.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Deed.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":47,"column":3,"nodeType":"CallExpression","endLine":49,"endColumn":69}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Deed step controller.\n\t *\n\t * @class\n\t * @extends uw.controller.Step\n\t * @param {mw.Api} api\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.controller.Deed = function UWControllerDeed( api, config ) {\n\t\tuw.controller.Step.call(\n\t\t\tthis,\n\t\t\tnew uw.ui.Deed(),\n\t\t\tapi,\n\t\t\tconfig\n\t\t);\n\n\t\tthis.stepName = 'deeds';\n\t};\n\tOO.inheritClass( uw.controller.Deed, uw.controller.Step );\n\n\tuw.controller.Deed.prototype.moveNext = function () {\n\t\tconst deedChoosers = this.getUniqueDeedChoosers( this.uploads );\n\n\t\tif ( deedChoosers.length === 0 ) {\n\t\t\tuw.controller.Step.prototype.moveNext.call( this );\n\t\t\treturn;\n\t\t}\n\n\t\tthis.validate( true )\n\t\t\t.always( () => this.ui.updateErrorSummary() )\n\t\t\t.done( () => uw.controller.Step.prototype.moveNext.call( this ) );\n\t};\n\n\tuw.controller.Deed.prototype.unload = function () {\n\t\tconst deedChoosers = this.getUniqueDeedChoosers( this.uploads );\n\t\tuw.controller.Step.prototype.unload.call( this );\n\n\t\t// serialize the first deed so we can use it to pre-populate the choices if someone is\n\t\t// uploading files in batches\n\t\tthis.uploadedDeedSerialization =\n\t\t\tdeedChoosers[ Object.keys( deedChoosers )[ 0 ] ].getSerialized();\n\n\t\tdeedChoosers.forEach( ( deedChooser ) => {\n\t\t\tdeedChooser.remove();\n\t\t} );\n\t};\n\n\t/**\n\t * Move to this step.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t */\n\tuw.controller.Deed.prototype.load = function ( uploads ) {\n\t\t// select \"provide same information for all files\" by default\n\t\tlet defaultDeedInterface = 'common';\n\t\tconst localUploads = uploads.filter( ( upload ) => {\n\t\t\t\tlet deed;\n\t\t\t\tif ( upload.file.fromURL ) {\n\t\t\t\t\t// external uploads should get a custom deed...\n\t\t\t\t\tdeed = new uw.deed.Custom( this.config, upload );\n\t\t\t\t\tupload.deedChooser = new mw.UploadWizardDeedChooser(\n\t\t\t\t\t\tthis.config,\n\t\t\t\t\t\t{ [ deed.name ]: deed },\n\t\t\t\t\t\t[ upload ]\n\t\t\t\t\t);\n\t\t\t\t\tupload.deedChooser.selectDeed( deed );\n\t\t\t\t\t// ... and be filtered out of the list for which to select a license\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t} ),\n\t\t\t// figure out how many unique deed choosers there were, so\n\t\t\t// we can restore the same (common/individual) interface\n\t\t\tuniqueExistingDeedChoosers = this.getUniqueDeedChoosers( localUploads ),\n\t\t\t// grab a serialized copy of previous deeds' details (if any)\n\t\t\tserializedDeeds = localUploads.reduce( ( map, upload ) => {\n\t\t\t\tif ( upload.deedChooser ) {\n\t\t\t\t\tmap[ upload.getFilename() ] = upload.deedChooser.getSerialized();\n\t\t\t\t}\n\t\t\t\treturn map;\n\t\t\t}, {} ),\n\t\t\tshowDeed = localUploads.length > 0,\n\t\t\tfromStepName = uploads[ 0 ].state;\n\n\t\tuw.controller.Step.prototype.load.call( this, uploads );\n\n\t\t// If all of the uploads are from URLs, then we know the licenses\n\t\t// already, we don't need this step.\n\t\tif ( !showDeed ) {\n\t\t\t// this is a bit of a hack: when images from flickr are uploaded, we\n\t\t\t// don't get to choose the license anymore, and this step will be\n\t\t\t// skipped ... but we could reach this step from either direction\n\t\t\tif ( fromStepName === 'details' ) {\n\t\t\t\tthis.movePrevious();\n\t\t\t} else {\n\t\t\t\tthis.moveNext();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst multiDeedRadio = new OO.ui.RadioSelectWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-source-multiple' ],\n\t\t\titems: [\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: mw.message(\n\t\t\t\t\t\t'mwe-upwiz-source-multiple-label-common',\n\t\t\t\t\t\tlocalUploads.length,\n\t\t\t\t\t\tmw.user\n\t\t\t\t\t).parseDom(),\n\t\t\t\t\tdata: 'common'\n\t\t\t\t} ),\n\t\t\t\tnew OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: mw.message(\n\t\t\t\t\t\t'mwe-upwiz-source-multiple-label-individual',\n\t\t\t\t\t\tlocalUploads.length,\n\t\t\t\t\t\tmw.user\n\t\t\t\t\t).parseDom(),\n\t\t\t\t\tdata: 'individual'\n\t\t\t\t} )\n\t\t\t]\n\t\t} );\n\n\t\t// if we have multiple uploads, also give them the option to set\n\t\t// licenses individually\n\t\tif ( localUploads.length > 1 && this.shouldShowIndividualDeed( this.config ) ) {\n\t\t\tthis.ui.showMultiDeedRadio( multiDeedRadio );\n\n\t\t\tif ( uniqueExistingDeedChoosers.length > 1 ) {\n\t\t\t\t// we also had more than 1 deed in the past, so default\n\t\t\t\t// to loading the individual deed selection\n\t\t\t\tdefaultDeedInterface = 'individual';\n\t\t\t}\n\t\t}\n\n\t\t// wire up handler to toggle common/individual deed selection forms\n\t\tmultiDeedRadio.on( 'select', ( selectedOption ) => {\n\t\t\tif ( selectedOption.getData() === 'common' ) {\n\t\t\t\tthis.loadCommon( localUploads );\n\t\t\t} else if ( selectedOption.getData() === 'individual' ) {\n\t\t\t\tthis.loadIndividual( localUploads );\n\t\t\t}\n\t\t\tthis.emit( 'change' );\n\t\t} );\n\n\t\tmultiDeedRadio.selectItemByData( defaultDeedInterface );\n\n\t\t// restore serialized data (if any)\n\t\tuploads.forEach( ( upload ) => {\n\t\t\tif ( serializedDeeds[ upload.getFilename() ] ) {\n\t\t\t\tupload.deedChooser.setSerialized( serializedDeeds[ upload.getFilename() ] );\n\t\t\t} else if ( this.uploadedDeedSerialization ) {\n\t\t\t\tupload.deedChooser.setSerialized( this.uploadedDeedSerialization );\n\t\t\t}\n\t\t} );\n\t};\n\n\t/**\n\t * Loads the deed form for providing information for a single file, or multiple\n\t * files all at once.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t */\n\tuw.controller.Deed.prototype.loadCommon = function ( uploads ) {\n\t\tconst deeds = this.getLicensingDeeds( uploads ),\n\t\t\tdeedChooser = new mw.UploadWizardDeedChooser(\n\t\t\t\tthis.config,\n\t\t\t\tdeeds,\n\t\t\t\tuploads\n\t\t\t);\n\n\t\tuploads.forEach( ( upload ) => {\n\t\t\tupload.deedChooser = deedChooser;\n\t\t} );\n\n\t\tthis.ui.showCommonForm( deedChooser );\n\n\t\t// reveal next button when deed has been chosen\n\t\tdeedChooser.on( 'choose', this.enableNextIfAllDeedsChosen.bind( this ) );\n\t\tthis.enableNextIfAllDeedsChosen();\n\n\t\t// aggregate change events within\n\t\tdeedChooser.on( 'choose', () => this.emit( 'change' ) );\n\t\tObject.keys( deeds ).forEach( ( name ) => {\n\t\t\tdeeds[ name ].on( 'change', () => this.emit( 'change' ) );\n\t\t} );\n\t};\n\n\t/**\n\t * Loads the deed form for providing individual license information per file.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t */\n\tuw.controller.Deed.prototype.loadIndividual = function ( uploads ) {\n\t\tuploads.forEach( ( upload ) => {\n\t\t\tconst deeds = this.getLicensingDeeds( uploads ),\n\t\t\t\tdeedChooser = new mw.UploadWizardDeedChooser(\n\t\t\t\t\tthis.config,\n\t\t\t\t\tdeeds,\n\t\t\t\t\t[ upload ]\n\t\t\t\t);\n\n\t\t\tupload.deedChooser = deedChooser;\n\n\t\t\t// reveal next button when deeds for all files have been chosen\n\t\t\tdeedChooser.on( 'choose', this.enableNextIfAllDeedsChosen.bind( this ) );\n\n\t\t\t// aggregate change events within\n\t\t\tdeedChooser.on( 'choose', () => this.emit( 'change' ) );\n\t\t\tObject.keys( deeds ).forEach( ( name ) => {\n\t\t\t\tdeeds[ name ].on( 'change', () => this.emit( 'change' ) );\n\t\t\t} );\n\t\t} );\n\n\t\tthis.ui.showIndividualForm( this.getUniqueDeedChoosers( uploads ) );\n\n\t\tthis.enableNextIfAllDeedsChosen();\n\t};\n\n\t/**\n\t * Check whether we should give the user the option to choose licenses for\n\t * individual files on the details step.\n\t *\n\t * @private\n\t * @param {Object} config\n\t * @return {boolean}\n\t */\n\tuw.controller.Deed.prototype.shouldShowIndividualDeed = function ( config ) {\n\t\tlet ownWork;\n\t\tif ( config.licensing.ownWorkDefault === 'choice' ) {\n\t\t\treturn true;\n\t\t} else if ( config.licensing.ownWorkDefault === 'own' ) {\n\t\t\townWork = config.licensing.ownWork;\n\t\t\treturn ownWork.licenses.length > 1;\n\t\t} else {\n\t\t\treturn true; // TODO: might want to have similar behaviour here\n\t\t}\n\t};\n\n\t/**\n\t * Get the own work and third party licensing deeds if they are needed.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t * @return {mw.deed.Abstract[]}\n\t */\n\tuw.controller.Deed.prototype.getLicensingDeeds = function ( uploads ) {\n\t\tconst deeds = {};\n\t\tlet doOwnWork = false,\n\t\t\tdoThirdParty = false;\n\n\t\tif ( this.config.licensing.ownWorkDefault === 'choice' ) {\n\t\t\tdoOwnWork = doThirdParty = true;\n\t\t} else if ( this.config.licensing.ownWorkDefault === 'own' ) {\n\t\t\tdoOwnWork = true;\n\t\t} else {\n\t\t\tdoThirdParty = true;\n\t\t}\n\n\t\tif ( doOwnWork ) {\n\t\t\tconst deed = new uw.deed.OwnWork( this.config, uploads, this.api );\n\t\t\tdeeds[ deed.name ] = deed;\n\t\t}\n\t\tif ( doThirdParty ) {\n\t\t\tconst deed = new uw.deed.ThirdParty( this.config, uploads, this.api );\n\t\t\tdeeds[ deed.name ] = deed;\n\t\t}\n\n\t\treturn deeds;\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t * @return {mw.UploadWizardDeedChooser[]}\n\t */\n\tuw.controller.Deed.prototype.getUniqueDeedChoosers = function ( uploads ) {\n\t\treturn uploads.reduce( ( uniques, upload ) => {\n\t\t\tif ( upload.deedChooser && !uniques.includes( upload.deedChooser ) ) {\n\t\t\t\tuniques.push( upload.deedChooser );\n\t\t\t}\n\t\t\treturn uniques;\n\t\t}, [] );\n\t};\n\n\t/**\n\t * Checks deeds for validity.\n\t *\n\t * @param {boolean} thorough\n\t * @return {jQuery.Promise<uw.ValidationStatus>}\n\t */\n\tuw.controller.Deed.prototype.validate = function ( thorough ) {\n\t\tconst deedChoosers = this.getUniqueDeedChoosers( this.uploads ),\n\t\t\tdeedPromises = this.getUniqueDeedChoosers( this.uploads ).map( ( deedChooser ) => deedChooser.validate( thorough ) ),\n\t\t\tmergedPromise = uw.ValidationStatus.mergePromises( ...deedPromises );\n\n\t\treturn mergedPromise.then(\n\t\t\t( status ) => {\n\t\t\t\tif ( thorough !== true ) {\n\t\t\t\t\treturn status;\n\t\t\t\t}\n\n\t\t\t\t// if (and only if) deed choosers are selected, we'll validate their contents\n\t\t\t\tconst fieldPromises = [];\n\t\t\t\tdeedChoosers.forEach( ( deedChooser ) => {\n\t\t\t\t\tdeedChooser.deed.getFields().forEach( ( fieldLayout ) => {\n\t\t\t\t\t\tfieldPromises.push( fieldLayout.validate( thorough ) );\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t\treturn uw.ValidationStatus.mergePromises( mergedPromise, ...fieldPromises );\n\t\t\t}\n\t\t);\n\t};\n\n\t/**\n\t * Enable/disable the next button based on whether all deeds have been chosen.\n\t */\n\tuw.controller.Deed.prototype.enableNextIfAllDeedsChosen = function () {\n\t\t// Note: wrapping this inside setTimeout to ensure this is added\n\t\t// at the end of the call stack; otherwise, due to how this is all\n\t\t// set up, timing can be unpredictable: when re-loading the form\n\t\t// after coming back from a later step, this ends being called more\n\t\t// than once - both uninitialized (where it should not be visible),\n\t\t// and initialized (after resetting the serialized state), where\n\t\t// the event handlers end up invoking this.\n\t\t// Stuffing this inside a setTimeout helps ensure that things\n\t\t// actually execute in the order they're supposed to; i.e. the order\n\t\t// they've been called in.\n\t\tsetTimeout( () => {\n\t\t\tthis.validate( false ).always( ( status ) => {\n\t\t\t\tthis.ui.updateErrorSummary();\n\t\t\t\tthis.ui.toggleNext( status.getErrors().length === 0 );\n\t\t\t} );\n\t\t} );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Details.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":164,"column":3,"nodeType":"CallExpression","endLine":169,"endColumn":7}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":156,"column":56,"nodeType":"CallExpression","endLine":156,"endColumn":85,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the details step in the wizard.\n\t *\n\t * @class\n\t * @extends uw.controller.Step\n\t * @param {mw.Api} api\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.controller.Details = function UWControllerDetails( api, config ) {\n\t\tuw.controller.Step.call(\n\t\t\tthis,\n\t\t\tnew uw.ui.Details()\n\t\t\t\t.on( 'start-details', this.startDetails.bind( this ) )\n\t\t\t\t.on( 'finalize-details-after-removal', this.moveNext.bind( this ) ),\n\t\t\tapi,\n\t\t\tconfig\n\t\t);\n\n\t\tthis.stepName = 'details';\n\t\tthis.finishState = 'complete';\n\n\t\tthis.queue = new uw.ConcurrentQueue( {\n\t\t\tcount: this.config.maxSimultaneousConnections,\n\t\t\taction: this.transitionOne.bind( this )\n\t\t} );\n\t};\n\n\tOO.inheritClass( uw.controller.Details, uw.controller.Step );\n\n\t/**\n\t * Move to this step.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads List of uploads being carried forward.\n\t */\n\tuw.controller.Details.prototype.load = function ( uploads ) {\n\t\tuw.controller.Step.prototype.load.call( this, uploads );\n\n\t\t// make sure queue is empty before starting this step\n\t\tthis.queue.abortExecuting();\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\t// get existing details\n\t\t\tconst serialized = upload.details ? upload.details.getSerialized() : null;\n\n\t\t\tthis.createDetails( upload );\n\t\t\tupload.details.attach();\n\t\t\tupload.details.on( 'change', () => this.emit( 'change' ) );\n\n\t\t\t// restore earlier details (user may have started inputting details,\n\t\t\t// then went back some steps, and now got here again)\n\t\t\tif ( serialized ) {\n\t\t\t\tupload.details.setSerialized( serialized );\n\t\t\t}\n\t\t} );\n\n\t\t// Show the widget allowing to copy selected metadata if there's more than one successful upload\n\t\tif ( this.config.copyMetadataFeature ) {\n\t\t\tthis.addCopyMetadataFeature();\n\t\t}\n\t};\n\n\tuw.controller.Details.prototype.moveNext = function () {\n\t\tthis.removeErrorUploads();\n\n\t\tuw.controller.Step.prototype.moveNext.call( this );\n\t};\n\n\tuw.controller.Details.prototype.addCopyMetadataFeature = function () {\n\t\t// uploads can only be edited when they're in a certain state:\n\t\t// a flat out upload failure or a completed upload can not be edited\n\t\tconst invalidStates = [ 'aborted', 'error', 'complete' ],\n\t\t\tinvalids = this.getUploadStatesCount( invalidStates ),\n\t\t\tvalids = this.uploads.length - invalids;\n\n\t\t// no point in having this feature if there's no target to copy to\n\t\tif ( valids < 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet first;\n\t\t// The first upload is not necessarily the one we want to copy from\n\t\t// E.g. the first upload could've gone through successfully, but the\n\t\t// rest failed because of abusefilter (or another recoverable error), in\n\t\t// which case we'll want the \"copy\" feature to appear below the 2nd\n\t\t// upload (or the first not-yet-completed not flat-out-failed upload)\n\t\tthis.uploads.some( ( upload ) => {\n\t\t\tif ( upload && !invalidStates.includes( upload.state ) ) {\n\t\t\t\tfirst = upload;\n\t\t\t\treturn true; // Break Array.some loop\n\t\t\t}\n\t\t\treturn false;\n\t\t} );\n\n\t\t// could not find a source upload to copy from\n\t\tif ( !first ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.copyMetadataWidget = new uw.CopyMetadataWidget( {\n\t\t\tcopyFrom: first,\n\t\t\t// Include the \"source\" upload in the targets too\n\t\t\tcopyTo: this.uploads,\n\t\t\tcaptionsAvailable: this.config.wikibase.enabled && this.config.wikibase.captions\n\t\t} );\n\t\tthis.copyMetadataField = new uw.FieldLayout( this.copyMetadataWidget, {\n\t\t\tlabel: $( '<span>' ).append(\n\t\t\t\tnew OO.ui.IconWidget( { icon: 'expand' } ).$element,\n\t\t\t\tnew OO.ui.IconWidget( { icon: 'collapse' } ).$element,\n\t\t\t\t' ',\n\t\t\t\tmw.msg( 'mwe-upwiz-copy-metadata-text' )\n\t\t\t),\n\t\t\tclasses: [\n\t\t\t\t'mwe-upwiz-fieldLayout-additional-info', 'mwe-upwiz-copyMetadataWidget',\n\t\t\t\t'mwe-upwiz-fieldLayout-additional-info-clickable'\n\t\t\t]\n\t\t} );\n\t\tthis.copyMetadataWidget.$element.makeCollapsible( {\n\t\t\tcollapsed: true,\n\t\t\t$customTogglers: this.copyMetadataField.$element.find( '.oo-ui-fieldLayout-header' )\n\t\t} );\n\t\t// the field isn't actually required, but we want to hide the \"optional\" text\n\t\tthis.copyMetadataField.setRequired( true );\n\n\t\tfirst.details.$form.append( this.copyMetadataField.$element );\n\t};\n\n\tuw.controller.Details.prototype.removeCopyMetadataFeature = function () {\n\t\tif ( this.copyMetadataField ) {\n\t\t\tthis.copyMetadataField.$element.remove();\n\t\t}\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Details.prototype.createDetails = function ( upload ) {\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\tupload.details = new mw.UploadWizardDetails( upload, $( '#mwe-upwiz-macro-files' ) );\n\t};\n\n\t/**\n\t * Start details submit.\n\t * TODO move the rest of the logic here from mw.UploadWizard\n\t */\n\tuw.controller.Details.prototype.startDetails = function () {\n\t\tthis.validate( true )\n\t\t\t.always( () => this.updateErrorSummary() )\n\t\t\t.done( () => {\n\t\t\t\tthis.ui.hideEndButtons();\n\t\t\t\tthis.submit();\n\t\t\t} );\n\t};\n\n\t/**\n\t * Check details for validity.\n\t *\n\t * @param {boolean} thorough\n\t * @return {jQuery.Promise<uw.ValidationStatus>}\n\t */\n\tuw.controller.Details.prototype.validate = function ( thorough ) {\n\t\tconst titles = [],\n\t\t\tfieldPromises = [];\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\t// Seen this title before?\n\t\t\tlet title = upload.details.getTitle();\n\t\t\tif ( title ) {\n\t\t\t\ttitle = title.getName() + '.' + mw.Title.normalizeExtension( title.getExtension() );\n\t\t\t\tupload.details.titleDetails.setIsDuplicate( title in titles );\n\t\t\t\ttitles[ title ] = true;\n\t\t\t}\n\n\t\t\tupload.details.getAllFields().forEach( ( fieldLayout ) => {\n\t\t\t\tfieldPromises.push( fieldLayout.validate( thorough ) );\n\t\t\t} );\n\t\t} );\n\n\t\treturn uw.ValidationStatus.mergePromises( ...fieldPromises );\n\t};\n\n\tuw.controller.Details.prototype.canTransition = function ( upload ) {\n\t\treturn (\n\t\t\tuw.controller.Step.prototype.canTransition.call( this, upload ) &&\n\t\t\tupload.state === this.stepName\n\t\t);\n\t};\n\n\t/**\n\t * Perform this step's changes on one upload.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t * @return {jQuery.Promise}\n\t */\n\tuw.controller.Details.prototype.transitionOne = function ( upload ) {\n\t\treturn upload.details.submit();\n\t};\n\n\t/**\n\t * Perform this step's changes on all uploads.\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tuw.controller.Details.prototype.transitionAll = function () {\n\t\tconst deferred = $.Deferred();\n\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\tif ( this.canTransition( upload ) ) {\n\t\t\t\tthis.queue.addItem( upload );\n\t\t\t}\n\t\t} );\n\n\t\tthis.queue.on( 'complete', deferred.resolve );\n\t\tthis.queue.startExecuting();\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Submit details to the API.\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tuw.controller.Details.prototype.submit = function () {\n\t\tthis.uploads.forEach( ( upload ) => {\n\t\t\t// Clear error state\n\t\t\tif ( upload.state === 'error' || upload.state === 'recoverable-error' ) {\n\t\t\t\tupload.state = this.stepName;\n\t\t\t}\n\n\t\t\t// Set details view to have correct title\n\t\t\tupload.details.setVisibleTitle( upload.details.getTitle().getMain() );\n\t\t} );\n\n\t\t// Disable edit interface\n\t\tthis.ui.disableEdits();\n\t\tthis.removeCopyMetadataFeature();\n\n\t\treturn this.transitionAll().then( () => {\n\t\t\tif ( this.showNext() ) {\n\t\t\t\tthis.moveNext();\n\t\t\t}\n\t\t} );\n\t};\n\n\t/**\n\t * Show errors, warnings & notices in the form.\n\t * See UI class for more.\n\t */\n\tuw.controller.Details.prototype.updateErrorSummary = function () {\n\t\tthis.ui.enableEdits();\n\n\t\tthis.removeCopyMetadataFeature();\n\t\tthis.addCopyMetadataFeature();\n\n\t\tthis.ui.updateErrorSummary();\n\t};\n\n\t/**\n\t * Handler for when an upload is removed.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.controller.Details.prototype.removeUpload = function ( upload ) {\n\t\tuw.controller.Step.prototype.removeUpload.call( this, upload );\n\n\t\tthis.queue.removeItem( upload );\n\n\t\tif ( upload.details && upload.details.$div ) {\n\t\t\tupload.details.$div.remove();\n\t\t}\n\n\t\tif ( this.uploads.length === 0 ) {\n\t\t\t// If we have no more uploads, go to the \"Upload\" step. (This will go to \"Thanks\" step,\n\t\t\t// which will skip itself in load() because there are no uploads left.)\n\t\t\tthis.moveNext();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.removeCopyMetadataFeature();\n\t\t// Make sure we still have more multiple uploads adding the\n\t\t// copy feature again\n\t\tif ( this.config.copyMetadataFeature ) {\n\t\t\tthis.addCopyMetadataFeature();\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Step.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Thanks.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Tutorial.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":61,"column":3,"nodeType":"CallExpression","endLine":67,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":61,"column":3,"nodeType":"CallExpression","endLine":69,"endColumn":6}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\n\t/**\n\t * Tutorial step controller.\n\t *\n\t * @class\n\t * @extends uw.controller.Step\n\t * @param {mw.Api} api\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.controller.Tutorial = function UWControllerTutorial( api, config ) {\n\t\tthis.skipPreference = Boolean( mw.user.options.get( 'upwiz_skiptutorial' ) );\n\t\tthis.newSkipPreference = this.skipPreference;\n\t\tthis.skipped = false;\n\n\t\tuw.controller.Step.call(\n\t\t\tthis,\n\t\t\tnew uw.ui.Tutorial()\n\t\t\t\t.on( 'skip-tutorial-click', ( skipped ) => {\n\t\t\t\t\t// indicate that the skip preference has changed, so we can\n\t\t\t\t\t// alter the preference when we move to another step\n\t\t\t\t\tthis.newSkipPreference = skipped;\n\t\t\t\t\tthis.emit( 'change' );\n\t\t\t\t} ),\n\t\t\tapi,\n\t\t\tconfig\n\t\t);\n\n\t\tthis.stepName = 'tutorial';\n\n\t\tthis.ui.setSelected( this.skipPreference );\n\t};\n\n\tOO.inheritClass( uw.controller.Tutorial, uw.controller.Step );\n\n\t/**\n\t * Set the skip tutorial user preference via the options API\n\t *\n\t * @param {boolean} skip\n\t */\n\tuw.controller.Tutorial.prototype.setSkipPreference = function ( skip ) {\n\t\tconst allowCloseWindow = mw.confirmCloseWindow();\n\n\t\tthis.api.postWithToken( 'options', {\n\t\t\taction: 'options',\n\t\t\tchange: skip ? 'upwiz_skiptutorial=1' : 'upwiz_skiptutorial'\n\t\t} ).done( () => {\n\t\t\tallowCloseWindow.release();\n\t\t\tthis.skipPreference = skip;\n\t\t} ).fail( ( code, err ) => {\n\t\t\tmw.notify( err.textStatus );\n\t\t} );\n\t};\n\n\tuw.controller.Tutorial.prototype.load = function ( uploads ) {\n\t\t// tutorial can be skipped via preference, or config (e.g. campaign config)\n\t\tconst shouldSkipTutorial = this.skipPreference || ( this.config.tutorial && this.config.tutorial.skip );\n\n\t\tuw.controller.Step.prototype.load.call( this, uploads );\n\n\t\t// we only want to skip the tutorial once - if we come back to it, we\n\t\t// don't want it to get auto-skipped again\n\t\tif ( !this.skipped && shouldSkipTutorial ) {\n\t\t\tthis.skipped = true;\n\t\t\tthis.moveNext();\n\t\t}\n\t};\n\n\tuw.controller.Tutorial.prototype.moveNext = function () {\n\t\tuw.controller.Step.prototype.moveNext.call( this );\n\t};\n\n\tuw.controller.Tutorial.prototype.unload = function () {\n\t\tif ( this.skipPreference !== this.newSkipPreference ) {\n\t\t\tthis.setSkipPreference( this.newSkipPreference );\n\t\t}\n\n\t\tuw.controller.Step.prototype.unload.call( this );\n\t};\n\n\tuw.controller.Tutorial.prototype.hasData = function () {\n\t\treturn false;\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.Upload.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/controller/uw.controller.base.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/dialog/uw.deed.dialog.PatentDialog.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/dialog/uw.deed.dialog.base.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.Abstract.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.Custom.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.OwnWork.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.ThirdParty.js","messages":[],"suppressedMessages":[{"ruleId":"no-undef","severity":2,"message":"'dataValues' is not defined.","line":364,"column":5,"nodeType":"Identifier","messageId":"undef","endLine":364,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'dataValues' is not defined.","line":376,"column":6,"nodeType":"Identifier","messageId":"undef","endLine":376,"endColumn":16,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'dataValues' is not defined.","line":387,"column":6,"nodeType":"Identifier","messageId":"undef","endLine":387,"endColumn":16,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/deed/uw.deed.base.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.CampaignDetailsWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.CategoriesDetailsWidget.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":213,"column":34,"nodeType":"CallExpression","endLine":226,"endColumn":54},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":242,"column":36,"nodeType":"CallExpression","endLine":252,"endColumn":56}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\tconst NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;\n\n\t/**\n\t * @constructor\n\t * @param {Object} [config] Configuration options\n\t * @param {mw.Api} [config.api] Instance of mw.Api (or subclass thereof) to use for queries\n\t * @param {number} [config.searchLimit=50] Maximum number of category search results to load\n\t * @param {number} [config.subLimit=500] Maximum number of sub-categories to load\n\t */\n\tuw.CategoriesDetailsWidget = function MWCategoryMultiselectWidget( config ) {\n\t\t// Config initialization\n\t\tconfig = Object.assign( {\n\t\t\tsearchLimit: 50,\n\t\t\tsubLimit: 500,\n\t\t\tclasses: [ 'mwe-upwiz-categoriesDetailsWidget' ]\n\t\t}, config );\n\t\tthis.searchLimit = config.searchLimit;\n\t\tthis.subLimit = config.subLimit;\n\n\t\t// Parent constructor\n\t\tuw.CategoriesDetailsWidget.super.call( this, $.extend( true, {}, config, {\n\t\t\tmenu: {\n\t\t\t\tfilterFromInput: false,\n\t\t\t\twidth: '100%'\n\t\t\t},\n\t\t\t// This allows the user to both select non-existent categories, and prevents the selector from\n\t\t\t// being wiped from #onMenuItemsChange when we change the available options in the dropdown\n\t\t\tallowArbitrary: true\n\t\t} ) );\n\n\t\t// Mixin constructors\n\t\tOO.ui.mixin.PendingElement.call( this, Object.assign( {}, config, { $pending: this.$handle } ) );\n\n\t\t// Initialize\n\t\tthis.api = config.api || new mw.Api();\n\n\t\tthis.cacheSearch = {};\n\t\tthis.cacheChildren = {};\n\n\t\t// Event handler to call the autocomplete methods\n\t\tthis.input.$input.on(\n\t\t\t'change input cut paste',\n\t\t\tOO.ui.debounce( () => this.updateMenuItems(\n\t\t\t\tthis.searchCategories( this.input.$input.val().trim() ),\n\t\t\t\tthis.input.$input.val().trim()\n\t\t\t), 100 )\n\t\t);\n\n\t\t// Keep only valid titles\n\t\tconst categories = ( mw.UploadWizard.config.defaults.categories || [] ).filter( ( cat ) => !!mw.Title.makeTitle( NS_CATEGORY, cat ) );\n\t\tthis.setValue( categories );\n\t};\n\tOO.inheritClass( uw.CategoriesDetailsWidget, OO.ui.MenuTagMultiselectWidget );\n\tOO.mixinClass( uw.CategoriesDetailsWidget, OO.ui.mixin.PendingElement );\n\tOO.mixinClass( uw.CategoriesDetailsWidget, uw.ValidatableElement );\n\n\tuw.CategoriesDetailsWidget.prototype.updateMenuItems = function ( results, input ) {\n\t\tconst arrowParent = document.documentElement.dir === 'ltr' ? '←' : '→';\n\t\tconst arrowChildren = document.documentElement.dir === 'ltr' ? '→' : '←';\n\n\t\tthis.getMenu().clearItems();\n\n\t\tthis.pushPending();\n\n\t\tresults\n\t\t\t.then( ( items ) => {\n\t\t\t\tconst menu = this.getMenu();\n\n\t\t\t\t// Never show the menu if the input lost focus in the meantime\n\t\t\t\tif ( !this.input.$input.is( ':focus' ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tmenu\n\t\t\t\t\t// menu should already have been cleared, but since this is an async callback,\n\t\t\t\t\t// let's clear it once more to ensure no race conditions\n\t\t\t\t\t.clearItems()\n\t\t\t\t\t.addItems(\n\t\t\t\t\t\titems\n\t\t\t\t\t\t\t.filter( ( data ) => {\n\t\t\t\t\t\t\t\t// Sense-check\n\t\t\t\t\t\t\t\tconst title = mw.Title.newFromText( data.title, NS_CATEGORY );\n\t\t\t\t\t\t\t\treturn title !== null;\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.map( ( data ) => {\n\t\t\t\t\t\t\t\t// clone data to avoid modifying the original object, as that will\n\t\t\t\t\t\t\t\t// be passed forward to the subcategory handler\n\t\t\t\t\t\t\t\tconst menuData = Object.assign( {}, data );\n\t\t\t\t\t\t\t\tconst title = mw.Title.newFromText( menuData.title, NS_CATEGORY );\n\n\t\t\t\t\t\t\t\t// ensure title is properly escaped; we'll be inserting it unescaped\n\t\t\t\t\t\t\t\t// (some will get additional HTML) later on\n\t\t\t\t\t\t\t\tlet text = title.getMainText();\n\t\t\t\t\t\t\t\ttext = $( '<span>' ).text( text ).html();\n\n\t\t\t\t\t\t\t\tif ( menuData.parent ) {\n\t\t\t\t\t\t\t\t\t// indicate that this navigates to the parent category\n\t\t\t\t\t\t\t\t\tmenuData.handler = () => this.updateMenuItems(\n\t\t\t\t\t\t\t\t\t\tmenuData.parent.results,\n\t\t\t\t\t\t\t\t\t\tmenuData.parent.input\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\ttext = arrowParent;\n\t\t\t\t\t\t\t\t} else if ( menuData.current ) {\n\t\t\t\t\t\t\t\t\t// indicate that this is the current category (and clicking it\n\t\t\t\t\t\t\t\t\t// will not navigate to its subcategories, but select it instead)\n\t\t\t\t\t\t\t\t\ttext = $( '<span>' ).addClass( 'mwe-upwiz-categories-category-title' ).text( text )[ 0 ].outerHTML;\n\t\t\t\t\t\t\t\t\ttext = mw.message( 'mwe-upwiz-categories-current', text ).text();\n\t\t\t\t\t\t\t\t} else if ( menuData.categoryinfo.subcats > 0 ) {\n\t\t\t\t\t\t\t\t\t// indicate that the category has subcategories\n\t\t\t\t\t\t\t\t\tmenuData.handler = () => this.updateMenuItems(\n\t\t\t\t\t\t\t\t\t\tthis.getSubCategories( title.getMainText() ).then( ( subcategories ) => {\n\t\t\t\t\t\t\t\t\t\t\tconst navigation = [\n\t\t\t\t\t\t\t\t\t\t\t\t// upwards navigation, back to parent\n\t\t\t\t\t\t\t\t\t\t\t\tObject.assign( {}, data, { parent: { results: results, input: input } } ),\n\t\t\t\t\t\t\t\t\t\t\t\t// current category selector (i.e. allow selection despite it having subcats)\n\t\t\t\t\t\t\t\t\t\t\t\tObject.assign( {}, data, { current: true } )\n\t\t\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t\t\t\treturn navigation.concat( subcategories );\n\t\t\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\t\t\ttitle.getMainText()\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\ttext = $( '<span>' ).addClass( 'mwe-upwiz-categories-category-title' ).text( text )[ 0 ].outerHTML + ' ' + arrowChildren;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn new OO.ui.MenuOptionWidget( {\n\t\t\t\t\t\t\t\t\tdata: menuData,\n\t\t\t\t\t\t\t\t\tlabel: new OO.ui.HtmlSnippet( text ),\n\t\t\t\t\t\t\t\t\tselected: !menuData.parent && this.getItems().some( ( item ) => item.data === title.getMainText() )\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t)\n\t\t\t\t\t.toggle( true );\n\t\t\t} )\n\t\t\t.always( this.popPending.bind( this ) );\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.clearInput = function () {\n\t\tuw.CategoriesDetailsWidget.super.prototype.clearInput.call( this );\n\t\t// Abort all pending requests, we won't need their results\n\t\tthis.api.abort();\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.onMenuChoose = function ( menuItem, selected ) {\n\t\t// some menu items are not meant for selection, but for navigation; those should not\n\t\t// result in tags being added!\n\t\tconst data = menuItem.getData();\n\t\tif ( data.handler ) {\n\t\t\tdata.handler();\n\t\t\treturn;\n\t\t}\n\n\t\tuw.CategoriesDetailsWidget.super.prototype.onMenuChoose.call( this, menuItem, selected );\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.titleFromData = function ( data ) {\n\t\treturn mw.Title.newFromText(\n\t\t\t// manual input is string (just category name; selection from menu is object)\n\t\t\ttypeof data === 'string' ? data : data.title,\n\t\t\tNS_CATEGORY\n\t\t);\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.isAllowedData = function ( data ) {\n\t\tconst title = this.titleFromData( data );\n\t\tif ( !title ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn uw.CategoriesDetailsWidget.super.prototype.isAllowedData.call( this, data );\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.findItemFromData = function ( data ) {\n\t\tconst title = this.titleFromData( data );\n\t\tif ( !title ) {\n\t\t\treturn null;\n\t\t}\n\t\treturn OO.ui.mixin.GroupElement.prototype.findItemFromData.call( this, title.getMainText() );\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.createTagItemWidget = function ( data ) {\n\t\tconst title = this.titleFromData( data );\n\n\t\tconst widget = new mw.widgets.CategoryTagItemWidget( {\n\t\t\tapiUrl: this.api.apiUrl || undefined,\n\t\t\ttitle: title\n\t\t} );\n\t\twidget.setMissing = ( missing ) => {\n\t\t\twidget.constructor.prototype.setMissing.call( widget, missing );\n\t\t\t// Aggregate 'change' event\n\t\t\tthis.emit( 'change' );\n\t\t};\n\n\t\treturn widget;\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.searchCategories = function ( input ) {\n\t\tconst cacheKey = input;\n\n\t\t// Abort all pending requests, we won't need their results\n\t\tthis.api.abort();\n\n\t\tif ( input.trim() === '' ) {\n\t\t\treturn $.Deferred().resolve( [] ).promise();\n\t\t}\n\n\t\t// Check cache\n\t\tif ( Object.prototype.hasOwnProperty.call( this.cacheSearch, cacheKey ) ) {\n\t\t\treturn this.cacheSearch[ cacheKey ];\n\t\t}\n\n\t\tthis.cacheSearch[ cacheKey ] = this.api.get( {\n\t\t\tformatversion: 2,\n\t\t\taction: 'query',\n\t\t\tgenerator: 'prefixsearch',\n\t\t\tgpsnamespace: NS_CATEGORY,\n\t\t\tgpslimit: this.searchLimit,\n\t\t\tgpssearch: input,\n\t\t\tprop: 'categoryinfo'\n\t\t} )\n\t\t\t.then( ( res ) => Object.keys( res && res.query && res.query.pages || [] )\n\t\t\t\t.map( ( key ) => res.query.pages[ key ] )\n\t\t\t\t.sort( ( a, b ) => a.index > b.index )\n\t\t\t)\n\t\t\t.fail( () => delete this.cacheSearch[ cacheKey ] );\n\n\t\treturn this.cacheSearch[ cacheKey ];\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.getSubCategories = function ( input ) {\n\t\tconst cacheKey = input;\n\n\t\t// Abort all pending requests, we won't need their results\n\t\tthis.api.abort();\n\n\t\t// Check cache\n\t\tif ( Object.prototype.hasOwnProperty.call( this.cacheChildren, cacheKey ) ) {\n\t\t\treturn this.cacheChildren[ cacheKey ];\n\t\t}\n\n\t\tthis.cacheChildren[ cacheKey ] = this.api.get( {\n\t\t\tformatversion: 2,\n\t\t\taction: 'query',\n\t\t\tgenerator: 'categorymembers',\n\t\t\tgcmnamespace: NS_CATEGORY,\n\t\t\tgcmlimit: this.subLimit,\n\t\t\tgcmtitle: mw.Title.newFromText( input, NS_CATEGORY ).getPrefixedDb(),\n\t\t\tprop: 'categoryinfo'\n\t\t} )\n\t\t\t.then( ( res ) => Object.keys( res && res.query && res.query.pages || [] ).map( ( key ) => res.query.pages[ key ] ) )\n\t\t\t.fail( () => delete this.cacheChildren[ cacheKey ] );\n\n\t\treturn this.cacheChildren[ cacheKey ];\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.validate = function () {\n\t\tconst status = new uw.ValidationStatus(),\n\t\t\tmissing = this.getItems().filter( ( item ) => item.missing );\n\n\t\tif ( missing.length > 0 ) {\n\t\t\tstatus.addWarning( mw.message( 'mwe-upwiz-categories-missing', missing.length ) );\n\t\t}\n\n\t\treturn status.resolve();\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.getWikiText = function () {\n\t\tlet hiddenCats = [];\n\t\tif ( mw.UploadWizard.config.autoAdd.categories ) {\n\t\t\thiddenCats = hiddenCats.concat( mw.UploadWizard.config.autoAdd.categories );\n\t\t}\n\t\tif ( mw.UploadWizard.config.trackingCategory ) {\n\t\t\tif ( mw.UploadWizard.config.trackingCategory.all ) {\n\t\t\t\thiddenCats.push( mw.UploadWizard.config.trackingCategory.all );\n\t\t\t}\n\t\t\tif ( mw.UploadWizard.config.trackingCategory.campaign ) {\n\t\t\t\thiddenCats.push( mw.UploadWizard.config.trackingCategory.campaign );\n\t\t\t}\n\t\t}\n\t\t// Keep only valid titles\n\t\thiddenCats = hiddenCats.filter( ( cat ) => !!mw.Title.makeTitle( NS_CATEGORY, cat ) );\n\n\t\tlet missingCatsWikiText = null;\n\t\tif (\n\t\t\ttypeof mw.UploadWizard.config.missingCategoriesWikiText === 'string' &&\n\t\t\tmw.UploadWizard.config.missingCategoriesWikiText.length > 0\n\t\t) {\n\t\t\tmissingCatsWikiText = mw.UploadWizard.config.missingCategoriesWikiText;\n\t\t}\n\n\t\tconst categories = this.getItems().map( ( item ) => item.data );\n\n\t\t// add all categories\n\t\tlet wikiText = categories.concat( hiddenCats )\n\t\t\t.map( ( cat ) => '[[' + mw.Title.makeTitle( NS_CATEGORY, cat ).getPrefixedText() + ']]' )\n\t\t\t.join( '\\n' );\n\n\t\t// if so configured, and there are no user-visible categories, add warning\n\t\tif ( missingCatsWikiText !== null && categories.length === 0 ) {\n\t\t\twikiText += '\\n\\n' + missingCatsWikiText;\n\t\t}\n\n\t\treturn wikiText;\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\tvalue: this.getItems().map( ( item ) => item.data )\n\t\t};\n\t};\n\n\tuw.CategoriesDetailsWidget.prototype.setSerialized = function ( serialized ) {\n\t\tthis.setValue( serialized.value );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.DateDetailsWidget.js","messages":[{"ruleId":"mediawiki/no-unlabeled-buttonwidget","severity":1,"message":"OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true.","line":16,"column":31,"nodeType":"NewExpression","messageId":"noLabel","endLine":20,"endColumn":6}],"suppressedMessages":[{"ruleId":"no-unused-vars","severity":2,"message":"'thorough' is defined but never used.","line":129,"column":55,"nodeType":"Identifier","messageId":"unusedVar","endLine":129,"endColumn":63,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A date field in UploadWizard's \"Details\" step form.\n\t *\n\t * @extends uw.DetailsWidget\n\t * @class\n\t * @param {Object} config Configuration options\n\t * @param {mw.UploadWizardUpload} config.upload\n\t */\n\tuw.DateDetailsWidget = function UWDateDetailsWidget( config ) {\n\t\tuw.DateDetailsWidget.super.call( this );\n\n\t\tthis.upload = config.upload;\n\t\tthis.prefilled = false;\n\t\tthis.calendarButtonWidget = new OO.ui.ButtonWidget( {\n\t\t\ticon: 'calendar',\n\t\t\tflags: [ 'progressive' ],\n\t\t\ttitle: mw.msg( 'mwe-upwiz-calendar-date' )\n\t\t} );\n\n\t\tthis.dateInputWidget = new OO.ui.TextInputWidget( {\n\t\t\tclasses: [ 'mwe-date' ],\n\t\t\tplaceholder: mw.msg( 'mwe-upwiz-select-date' )\n\t\t} );\n\n\t\tthis.calendar = new mw.widgets.CalendarWidget( {\n\t\t\tlazyInitOnToggle: true\n\t\t} );\n\t\tthis.calendar.toggle( false );\n\t\t// clicking the calendar icon toggles the calendar on/off,\n\t\t// clicking the input field always closes it\n\t\tthis.calendarButtonWidget.on( 'click', () => this.calendar.toggle( !this.calendar.visible ) );\n\t\tthis.dateInputWidget.on( 'click', () => this.calendar.toggle( false ) );\n\t\t// selecting a date from the calendar writes that date into the input field;\n\t\t// when anything changes in the input (either manual input or calendar selection),\n\t\t// the calendar closes & change event is emitted (but only once every 500ms)\n\t\tthis.calendar.on( 'change', ( value ) => {\n\t\t\tthis.dateInputWidget.setValue( value );\n\t\t} );\n\t\tthis.dateInputWidget.on( 'change', () => {\n\t\t\tthis.calendar.toggle( false );\n\t\t} );\n\t\tthis.dateInputWidget.on( 'change', OO.ui.debounce( ( value ) => {\n\t\t\tthis.emit( 'change', value );\n\t\t}, 500 ) );\n\n\t\tthis.$element\n\t\t\t.addClass( 'mwe-upwiz-dateDetailsWidget' )\n\t\t\t.append(\n\t\t\t\tthis.calendarButtonWidget.$element,\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mw-widget-dateInputWidget' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-dateDetailsWidget-date' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tthis.dateInputWidget.$element,\n\t\t\t\t\t\tthis.calendar.$element\n\t\t\t\t\t\t\t.addClass( 'mw-widget-dateInputWidget-calendar' )\n\t\t\t\t\t)\n\t\t\t);\n\t};\n\tOO.inheritClass( uw.DateDetailsWidget, uw.DetailsWidget );\n\tOO.mixinClass( uw.StatementWidget, uw.ValidatableElement );\n\n\t/**\n\t * Tell whether the date input field was prefilled\n\t * with a value extracted from the upload's metadata.\n\t *\n\t * @param {boolean} prefilled Whether the date is prefilled\n\t */\n\tuw.DateDetailsWidget.prototype.setPrefilled = function ( prefilled ) {\n\t\tthis.prefilled = prefilled;\n\t};\n\n\t/**\n\t * Parse user input into a Wikibase date\n\t * via the `wbparsevalue` API endpoint.\n\t * See https://www.wikidata.org/w/api.php?action=help&modules=wbparsevalue\n\t * and https://www.wikidata.org/wiki/Help:Dates.\n\t *\n\t * @return {jQuery.Promise} Promise with the API response\n\t */\n\tuw.DateDetailsWidget.prototype.parseDate = function () {\n\t\tconst userInput = this.dateInputWidget.getValue(),\n\t\t\t// Handle input that includes time:\n\t\t\t// it typically comes from the upload's EXIF metadata,\n\t\t\t// but might also be inserted by the user.\n\t\t\t// The Wikibase value parser won't accept it,\n\t\t\t// since dates with precision higher than day aren't supported.\n\t\t\t// See https://phabricator.wikimedia.org/T57755.\n\t\t\t// The API would return an opaque\n\t\t\t// 'wikibase-validator-malformed-value' error code:\n\t\t\t// avoid this by stripping time (in standard format)\n\t\t\tuserInputWithoutTime = userInput.replace( /\\D\\d\\d:\\d\\d:\\d\\d/, '' ),\n\t\t\tparams = {\n\t\t\t\taction: 'wbparsevalue',\n\t\t\t\tdatatype: 'time',\n\t\t\t\tvalidate: true,\n\t\t\t\toptions: JSON.stringify(\n\t\t\t\t\t{ lang: mw.config.get( 'wgUserLanguage' ) }\n\t\t\t\t),\n\t\t\t\tvalues: userInputWithoutTime\n\t\t\t};\n\n\t\treturn this.upload.api.get( params );\n\t};\n\n\t/**\n\t * Gets the selected license(s). The returned value will be a license\n\t * key => license props map, as defined in UploadWizard.config.php.\n\t *\n\t * @return {Object}\n\t */\n\tuw.DateDetailsWidget.prototype.getLicenses = function () {\n\t\tif ( this.upload.deedChooser && this.upload.deedChooser.deed && this.upload.deedChooser.deed.licenseInput ) {\n\t\t\treturn this.upload.deedChooser.deed.licenseInput.getLicenses();\n\t\t}\n\n\t\t// no license has been selected yet\n\t\t// this could happen when uploading multiple files and selecting to\n\t\t// provide copyright information for each file individually\n\t\treturn {};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\t// eslint-disable-next-line no-unused-vars\n\tuw.DateDetailsWidget.prototype.validate = function ( thorough ) {\n\t\tconst status = new uw.ValidationStatus(),\n\t\t\ttrimmedInput = this.dateInputWidget.getValue().trim(),\n\t\t\tinputDate = new Date( trimmedInput ),\n\t\t\tnow = new Date(),\n\t\t\tlicenses = this.getLicenses(),\n\t\t\t// Timestamps: milliseconds\n\t\t\tutc14 = 14 * 60 * 60 * 1000, // 14 hours in milliseconds\n\t\t\t// Dates: years, months, days\n\t\t\told95 = new Date( now.getFullYear() - 95 ), // Only the year is relevant\n\t\t\told70 = new Date( now.getFullYear() - 70, now.getMonth(), now.getDate() ),\n\t\t\told100 = new Date( now.getFullYear() - 100, now.getMonth(), now.getDate() );\n\n\t\tlet promise = $.Deferred().resolve().promise();\n\n\t\tif ( this.parseDateValidation ) {\n\t\t\tthis.parseDateValidation.abort();\n\t\t}\n\n\t\t// Blank\n\t\tif ( trimmedInput === '' ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-date-blank' ) );\n\t\t\t// Date in the future.\n\t\t\t// We don't really know what timezone this datetime is in. It could be the user's timezone, or\n\t\t\t// it could be the camera's timezone for data imported from EXIF, and we don't know what\n\t\t\t// timezone that is. UTC+14 is the highest timezone that currently exists, so assume that to\n\t\t\t// avoid giving false errors.\n\t\t} else if ( inputDate.getTime() > now.getTime() + utc14 ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-postdate' ) );\n\t\t\t// License mismatch.\n\t\t\t// Public domain work in the U.S.: it must've been created at least 95 years ago.\n\t\t} else if ( 'pd-us' in licenses && inputDate >= old95 ) {\n\t\t\tstatus.addError(\n\t\t\t\tmw.message(\n\t\t\t\t\t'mwe-upwiz-error-date-license-mismatch',\n\t\t\t\t\tmw.message( licenses[ 'pd-us' ].msg ).parseDom()\n\t\t\t\t)\n\t\t\t);\n\t\t} else if ( 'pd-us-generic' in licenses && inputDate >= old95 ) {\n\t\t\tstatus.addError(\n\t\t\t\tmw.message(\n\t\t\t\t\t'mwe-upwiz-error-date-license-mismatch',\n\t\t\t\t\tmw.message( licenses[ 'pd-us-generic' ].msg ).parseDom()\n\t\t\t\t)\n\t\t\t);\n\t\t\t// The author died 70 years ago: the date should reflect that\n\t\t} else if ( 'pd-old-70' in licenses && inputDate > old70 ) {\n\t\t\tstatus.addError(\n\t\t\t\tmw.message(\n\t\t\t\t\t'mwe-upwiz-error-date-license-mismatch',\n\t\t\t\t\tmw.message( licenses[ 'pd-old-70' ].msg ).parseDom()\n\t\t\t\t)\n\t\t\t);\n\t\t\t// The author died 100 years ago: the date should reflect that\n\t\t} else if ( 'pd-old-100' in licenses && inputDate > old100 ) {\n\t\t\tstatus.addError(\n\t\t\t\tmw.message(\n\t\t\t\t\t'mwe-upwiz-error-date-license-mismatch',\n\t\t\t\t\tmw.message( licenses[ 'pd-old-100' ].msg ).parseDom()\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\t// Unlikely license.\n\t\tif (\n\t\t\t// The `Date` constructor returns `NaN` if it couldn't parse the date.\n\t\t\t!isNaN( inputDate.valueOf() ) &&\n\t\t\t// It's unlikely for public-domain images to have been published today\n\t\t\tnow.toISOString().slice( 0, 10 ) === inputDate.toISOString().slice( 0, 10 )\n\t\t) {\n\t\t\t// Public-domain licenses that likely mean\n\t\t\t// the image date is some time in the past.\n\t\t\t[ 'pd-usgov', 'pd-usgov-nasa', 'pd-art' ].forEach( ( warnLicense ) => {\n\t\t\t\tif ( warnLicense in licenses ) {\n\t\t\t\t\tconst license = licenses[ warnLicense ];\n\t\t\t\t\tconst licenseMsg = mw.message(\n\t\t\t\t\t\tlicense.msg,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tlicense.url ? license.url : '#missing license URL'\n\t\t\t\t\t);\n\t\t\t\t\tstatus.addWarning(\n\t\t\t\t\t\tmw.message(\n\t\t\t\t\t\t\t'mwe-upwiz-error-date-license-unlikely',\n\t\t\t\t\t\t\tlicenseMsg.parseDom()\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tif ( this.prefilled ) {\n\t\t\tstatus.addNotice( mw.message( 'mwe-upwiz-warning-date-prefilled' ) );\n\t\t}\n\n\t\tif ( this.dateInputWidget.getValue().trim() !== '' ) {\n\t\t\tthis.parseDateValidation = this.parseDate();\n\t\t\tpromise = this.parseDateValidation.then(\n\t\t\t\t( data ) => {\n\t\t\t\t\tconst dayPrecision = 11;\n\t\t\t\t\tif ( data.results && data.results[ 0 ] && data.results[ 0 ].value.precision < dayPrecision ) {\n\t\t\t\t\t\tstatus.addNotice( mw.message( 'mwe-upwiz-notice-date-imprecise' ) );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t( code ) => {\n\t\t\t\t\t// warn on failures, except when the failure is http (request aborted\n\t\t\t\t\t// or network issues)\n\t\t\t\t\tif ( code !== 'http' ) {\n\t\t\t\t\t\tstatus.addNotice( mw.message( 'mwe-upwiz-notice-date-imprecise' ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\treturn promise.then( () => status.getErrors().length === 0 ? status.resolve() : status.reject() );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.DateDetailsWidget.prototype.getWikiText = function () {\n\t\treturn this.dateInputWidget.getValue().trim();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.DateDetailsWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\tprefilled: this.prefilled,\n\t\t\tvalue: this.dateInputWidget.getValue()\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} serialized\n\t * @param {boolean} serialized.prefilled Whether the date is prefilled\n\t * @param {string} serialized.value Date value for the given mode\n\t */\n\tuw.DateDetailsWidget.prototype.setSerialized = function ( serialized ) {\n\t\t// select the given date in the input widget\n\t\tthis.calendar.setDate( serialized.value );\n\t\t// update the input widget last, at the end of the call stack (i.e.\n\t\t// after the calendar's change event has been emitted/handled), to\n\t\t// ensure the date input widget has the actual value, which may have\n\t\t// more precision (hours, minutes, seconds) than the calendar value\n\t\tsetTimeout( () => {\n\t\t\tthis.prefilled = serialized.prefilled;\n\t\t\tthis.dateInputWidget.setValue( serialized.value );\n\t\t} );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.LanguageDropdownWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.LocationDetailsWidget.js","messages":[{"ruleId":"mediawiki/no-unlabeled-buttonwidget","severity":1,"message":"OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true.","line":25,"column":20,"nodeType":"NewExpression","messageId":"noLabel","endLine":33,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":67,"column":3,"nodeType":"CallExpression","endLine":70,"endColumn":6}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A set of location fields in UploadWizard's \"Details\" step form.\n\t *\n\t * @extends uw.DetailsWidget\n\t * @class\n\t * @param {Object} [config] Configuration options\n\t * @param {string} [config.latitudeKey]\n\t * @param {string} [config.longitudeKey]\n\t * @param {string} [config.headingKey]\n\t * @param {string} [config.templateName]\n\t */\n\tuw.LocationDetailsWidget = function UWLocationDetailsWidget( config ) {\n\t\tthis.config = config || {};\n\n\t\tuw.LocationDetailsWidget.super.call( this );\n\n\t\tthis.$element.addClass( 'mwe-upwiz-locationDetailsWidget' );\n\n\t\tthis.latitudeInput = new OO.ui.TextInputWidget();\n\t\tthis.longitudeInput = new OO.ui.TextInputWidget();\n\t\tthis.headingInput = new OO.ui.TextInputWidget();\n\t\tthis.$map = $( '<div>' ).css( { width: 500, height: 300 } );\n\t\tthis.mapButton = new OO.ui.PopupButtonWidget( {\n\t\t\ticon: 'mapPin',\n\t\t\ttitle: mw.message( 'mwe-upwiz-location-button' ).text(),\n\t\t\tpopup: {\n\t\t\t\t$content: this.$map,\n\t\t\t\twidth: 500,\n\t\t\t\theight: 300\n\t\t\t}\n\t\t} );\n\n\t\tthis.$element.append(\n\t\t\tnew OO.ui.FieldLayout( this.latitudeInput, {\n\t\t\t\talign: 'top',\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-location-lat' ).text()\n\t\t\t} ).$element,\n\t\t\tnew OO.ui.FieldLayout( this.longitudeInput, {\n\t\t\t\talign: 'top',\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-location-lon' ).text()\n\t\t\t} ).$element\n\t\t);\n\n\t\tif ( this.config.headingKey ) {\n\t\t\tthis.$element.append(\n\t\t\t\tnew OO.ui.FieldLayout( this.headingInput, {\n\t\t\t\t\talign: 'top',\n\t\t\t\t\tlabel: mw.message( 'mwe-upwiz-location-heading' ).text()\n\t\t\t\t} ).$element\n\t\t\t);\n\t\t}\n\n\t\tthis.mapButton.setDisabled( true );\n\t\tthis.$element.append( this.mapButton.$element );\n\n\t\t// Aggregate 'change' events\n\t\tthis.latitudeInput.connect( this, { change: [ 'emit', 'change' ] } );\n\t\tthis.longitudeInput.connect( this, { change: [ 'emit', 'change' ] } );\n\t\tthis.headingInput.connect( this, { change: [ 'emit', 'change' ] } );\n\n\t\tthis.mapButton.connect( this, { click: 'onMapButtonClick' } );\n\t\tthis.connect( this, { change: 'onChange' } );\n\n\t\tthis.mapButton.toggle( false );\n\t\tmw.loader.using( [ 'ext.kartographer.box', 'ext.kartographer.editing' ] ).done( () => {\n\t\t\t// Kartographer is installed and we'll be able to show the map. Display the button.\n\t\t\tthis.mapButton.toggle( true );\n\t\t} );\n\t};\n\tOO.inheritClass( uw.LocationDetailsWidget, uw.DetailsWidget );\n\tOO.mixinClass( uw.LocationDetailsWidget, uw.ValidatableElement );\n\n\t/**\n\t * @private\n\t */\n\tuw.LocationDetailsWidget.prototype.onChange = function () {\n\t\tthis.validate().then(\n\t\t\t() => this.mapButton.setDisabled( false ),\n\t\t\t() => this.mapButton.setDisabled( true )\n\t\t);\n\t};\n\n\t/**\n\t * @private\n\t */\n\tuw.LocationDetailsWidget.prototype.onMapButtonClick = function () {\n\t\tconst latitude = this.normalizeCoordinate( this.latitudeInput.getValue() ),\n\t\t\tlongitude = this.normalizeCoordinate( this.longitudeInput.getValue() );\n\n\t\t// Disable clipping because it doesn't play nicely with the map\n\t\tthis.mapButton.getPopup().toggleClipping( false );\n\n\t\tif ( !this.map ) {\n\t\t\tthis.map = require( 'ext.kartographer.box' ).map( {\n\t\t\t\tcontainer: this.$map[ 0 ]\n\t\t\t} );\n\t\t}\n\t\trequire( 'ext.kartographer.editing' ).getKartographerLayer( this.map ).setGeoJSON( {\n\t\t\ttype: 'Feature',\n\t\t\tproperties: {},\n\t\t\tgeometry: { type: 'Point', coordinates: [ longitude, latitude ] }\n\t\t} );\n\t\tthis.map.setView( [ latitude, longitude ], 9 );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.LocationDetailsWidget.prototype.validate = function () {\n\t\tconst status = new mw.uploadWizard.ValidationStatus(),\n\t\t\tlatInput = this.latitudeInput.getValue(),\n\t\t\tlonInput = this.longitudeInput.getValue(),\n\t\t\theadInput = this.headingInput.getValue(),\n\t\t\tlatNum = this.normalizeCoordinate( latInput ),\n\t\t\tlonNum = this.normalizeCoordinate( lonInput ),\n\t\t\theadNum = parseFloat( headInput );\n\n\t\t// input is invalid if the coordinates are out of bounds, or if the\n\t\t// coordinates that were derived from the input are 0, without a 0 even\n\t\t// being present in the input\n\t\tif ( latInput || lonInput ) {\n\t\t\tif ( latNum > 90 || latNum < -90 || ( latNum === 0 && !latInput.includes( '0' ) ) || isNaN( latNum ) ) {\n\t\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-latitude' ) );\n\t\t\t}\n\n\t\t\tif ( lonNum > 180 || lonNum < -180 || ( lonNum === 0 && !lonInput.includes( '0' ) ) || isNaN( lonNum ) ) {\n\t\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-longitude' ) );\n\t\t\t}\n\t\t}\n\n\t\tif ( headInput !== '' && ( headInput > 360 || headInput < 0 || isNaN( headNum ) ) ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-heading' ) );\n\t\t}\n\n\t\treturn status.getErrors().length === 0 ? status.resolve() : status.reject();\n\t};\n\n\t/**\n\t * Set up the input fields.\n\t *\n\t * @param {string} [lat] Latitude value to set.\n\t * @param {string} [lon] Longitude value to set.\n\t * @param {string} [head] Heading value to set.\n\t * @private\n\t */\n\tuw.LocationDetailsWidget.prototype.setupInputs = function ( lat, lon, head ) {\n\t\tif ( lat !== undefined ) {\n\t\t\tthis.latitudeInput.setValue( lat );\n\t\t}\n\n\t\tif ( lon !== undefined ) {\n\t\t\tthis.longitudeInput.setValue( lon );\n\t\t}\n\n\t\tif ( head !== undefined ) {\n\t\t\tthis.headingInput.setValue( head );\n\t\t}\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.LocationDetailsWidget.prototype.getWikiText = function () {\n\t\tconst latInput = this.latitudeInput.getValue(),\n\t\t\tlonInput = this.longitudeInput.getValue(),\n\t\t\theadInput = this.headingInput.getValue(),\n\t\t\tlatNum = this.normalizeCoordinate( latInput ),\n\t\t\tlonNum = this.normalizeCoordinate( lonInput ),\n\t\t\theadNum = parseFloat( headInput );\n\n\t\t// input is invalid if the coordinates are out of bounds, or if the\n\t\t// coordinates that were derived from the input are 0, without a 0 even\n\t\t// being present in the input\n\t\tif ( latNum !== 0 || latInput.includes( '0' ) || lonNum !== 0 || lonInput.includes( '0' ) ) {\n\t\t\t// {{Location}} or {{Object location}}\n\t\t\tconst locationParts = [ '{{' + this.config.templateName, latNum, lonNum ];\n\n\t\t\tif ( !isNaN( headNum ) ) {\n\t\t\t\tlocationParts.push( 'heading:' + headNum );\n\t\t\t}\n\n\t\t\treturn locationParts.join( '|' ) + '}}';\n\t\t}\n\n\t\treturn '';\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.LocationDetailsWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\t[ this.config.latitudeKey ]: this.latitudeInput.getValue(),\n\t\t\t[ this.config.longitudeKey ]: this.longitudeInput.getValue(),\n\t\t\t[ this.config.headingKey ]: this.headingInput.getValue()\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} serialized\n\t * @param {string} serialized.latitude Latitude value\n\t * @param {string} serialized.longitude Longitude value\n\t * @param {string} serialized.heading Heading value\n\t */\n\tuw.LocationDetailsWidget.prototype.setSerialized = function ( serialized ) {\n\t\tthis.setupInputs(\n\t\t\tserialized[ this.config.latitudeKey ],\n\t\t\tserialized[ this.config.longitudeKey ],\n\t\t\tserialized[ this.config.headingKey ]\n\t\t);\n\t};\n\n\t/**\n\t * Interprets a wide variety of coordinate input formats, it'll return the\n\t * coordinate in decimal degrees.\n\t *\n\t * Formats understood include:\n\t * - degrees minutes seconds: 40° 26' 46\" S\n\t * - degrees decimal minutes: 40° 26.767' S\n\t * - decimal degrees: 40.446° S\n\t * - decimal degrees exact value: -40.446\n\t *\n\t * This code is shared with the Kartographer extension. Please consider updating both when you\n\t * touch this.\n\t *\n\t * @param {string} input\n\t * @return {number|NaN} NaN when normalization was not possible\n\t */\n\tuw.LocationDetailsWidget.prototype.normalizeCoordinate = function ( input ) {\n\t\tconst sign = input.match( /[sw]/i ) ? -1 : 1;\n\n\t\t// fix commonly used character alternatives\n\t\tlet value = input.trim()\n\t\t\t.replace( /−/g, '-' )\n\t\t\t.replace( /\\s*[,.]\\s*/g, '.' );\n\n\t\t// convert degrees, minutes, seconds (or degrees & decimal minutes) to\n\t\t// decimal degrees\n\t\t// there can be a lot of variation in the notation, so let's only\n\t\t// focus on \"groups of digits\" (and not whether e.g. ″ or \" is used)\n\t\tconst parts = value.match( /^\\D*(-?\\d{1,3}\\b[\\d.]*)[^\\d.]+(\\d{1,2}\\b[\\d.]*)(?:[^\\d.]+(\\d{1,2}\\b[\\d.]*))?\\D*$/ );\n\t\tif ( parts ) {\n\t\t\tvalue = parts[ 1 ] * 1 + parts[ 2 ] / 60 + ( parts[ 3 ] || 0 ) / 3600;\n\t\t} else {\n\t\t\tvalue = value.replace( /[^-\\d.]+/g, '' ) * 1;\n\t\t\tif ( Math.abs( value ) > 360 ) {\n\t\t\t\treturn NaN;\n\t\t\t}\n\t\t}\n\n\t\t// Round to 6 decimal places, this approx. corresponds to a precision of 0.1 meter or less\n\t\treturn Math.round( sign * value * 1000000 ) / 1000000;\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.MultipleLanguageInputWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.OtherDetailsWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.SingleLanguageInputWidget.js","messages":[{"ruleId":"mediawiki/no-unlabeled-buttonwidget","severity":1,"message":"OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true.","line":45,"column":23,"nodeType":"NewExpression","messageId":"noLabel","endLine":50,"endColumn":6}],"suppressedMessages":[{"ruleId":"new-cap","severity":2,"message":"A constructor name should not start with a lowercase letter.","line":44,"column":36,"nodeType":"NewExpression","messageId":"lower","endLine":44,"endColumn":58,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-unused-vars","severity":2,"message":"'thorough' is defined but never used.","line":150,"column":63,"nodeType":"Identifier","messageId":"unusedVar","endLine":150,"endColumn":71,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * A single language input field in UploadWizard's \"Details\" step form.\n\t *\n\t * @extends uw.DetailsWidget\n\t * @class\n\t * @param {Object} config\n\t * @param {Object} config.languages { langcode: text } map of languages\n\t * @param {Object} [config.defaultLanguage]\n\t * @param {boolean} [config.removable=true]\n\t * @param {mw.Message} [config.remove] Title text for remove icon\n\t * @param {number} [config.minLength=0] Minimum input length\n\t * @param {number} [config.maxLength=99999] Maximum input length\n\t */\n\tuw.SingleLanguageInputWidget = function UWSingleLanguageInputWidget( config ) {\n\t\tthis.config = Object.assign( {\n\t\t\tinputWidgetConstructor: OO.ui.MultilineTextInputWidget.bind( null, {\n\t\t\t\tclasses: [ 'mwe-upwiz-singleLanguageInputWidget-text' ],\n\t\t\t\tautosize: true\n\t\t\t} ),\n\t\t\tremovable: true,\n\t\t\tremove: mw.message( '' ),\n\t\t\tminLength: 0,\n\t\t\tmaxLength: 99999\n\t\t}, config );\n\n\t\tuw.SingleLanguageInputWidget.super.call( this );\n\t\tuw.ValidationMessageElement.call( this );\n\n\t\tif ( mw.loader.getState( 'ext.uls.mediawiki' ) === 'ready' ) {\n\t\t\tthis.languageSelector = new uw.UlsWidget( {\n\t\t\t\tlanguages: config.languages,\n\t\t\t\tclasses: [ 'mwe-upwiz-singleLanguageInputWidget-language' ]\n\t\t\t} );\n\t\t} else {\n\t\t\tthis.languageSelector = new uw.LanguageDropdownWidget( {\n\t\t\t\tlanguages: config.languages,\n\t\t\t\tclasses: [ 'mwe-upwiz-singleLanguageInputWidget-language' ]\n\t\t\t} );\n\t\t}\n\n\t\t// eslint-disable-next-line new-cap\n\t\tthis.textInput = new this.config.inputWidgetConstructor();\n\t\tthis.removeButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-singleLanguageInputWidget-removeItem' ],\n\t\t\ticon: 'trash',\n\t\t\tframed: false,\n\t\t\ttitle: this.config.remove.exists() ? this.config.remove.text() : ''\n\t\t} );\n\n\t\tthis.removeButton.connect( this, {\n\t\t\tclick: 'onRemoveClick'\n\t\t} );\n\n\t\tthis.setLanguage( config.defaultLanguage || this.getDefaultLanguage() );\n\t\tthis.languageSelector.on( 'select', () => {\n\t\t\tthis.textInput.$input.attr( 'lang', this.languageSelector.getValue() );\n\t\t} );\n\t\tthis.languageSelector.connect( this, { select: [ 'emit', 'select' ] } );\n\t\t// Aggregate 'change' event\n\t\t// (but do not flash warnings in the user's face while they're typing)\n\t\tthis.textInput.on( 'change', OO.ui.debounce( this.emit.bind( this, 'change' ), 500 ) );\n\n\t\t// Note: ValidationMessageElement will append messages after this.$body\n\t\tthis.$body = $( '<div>' ).addClass( 'mwe-upwiz-singleLanguageInputWidget-body' ).append(\n\t\t\tthis.languageSelector.getElement(),\n\t\t\t// remove button will be hidden with CSS if it's not meant to be removable\n\t\t\tthis.removeButton.$element,\n\t\t\tthis.textInput.$element\n\t\t);\n\t\tthis.$element.addClass( 'mwe-upwiz-singleLanguageInputWidget' ).append( this.$body );\n\t\tthis.setRemovable( this.config.removable );\n\t};\n\tOO.inheritClass( uw.SingleLanguageInputWidget, uw.DetailsWidget );\n\tOO.mixinClass( uw.SingleLanguageInputWidget, uw.ValidatableElement );\n\n\t/**\n\t * Handle remove button click events.\n\t *\n\t * @private\n\t */\n\tuw.SingleLanguageInputWidget.prototype.onRemoveClick = function () {\n\t\tconst element = this.getElementGroup();\n\n\t\tif ( element && typeof element.removeItems === 'function' ) {\n\t\t\telement.removeItems( [ this ] );\n\t\t}\n\t};\n\n\t/**\n\t * Check if the given language code can be used for inputs.\n\t * If not, try finding a similar language code that can be.\n\t *\n\t * @public\n\t * @param {string} code Language code\n\t * @param {string} [fallback] Language code to use when there's nothing close,\n\t * defaults to result of #getDefaultLanguage\n\t * @return {string|null}\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getClosestAllowedLanguage = function ( code, fallback ) {\n\t\t// Is this still needed?\n\t\tif ( code === 'nan' || code === 'minnan' ) {\n\t\t\tcode = 'zh-min-nan';\n\t\t}\n\t\tif ( this.config.languages[ code ] ) {\n\t\t\treturn code;\n\t\t}\n\t\tif ( code.includes( '-' ) ) {\n\t\t\treturn this.getClosestAllowedLanguage( code.slice( 0, code.lastIndexOf( '-' ) ), fallback );\n\t\t}\n\t\treturn arguments.length > 1 ? fallback : this.getDefaultLanguage();\n\t};\n\n\t/**\n\t * Get the default language to use for inputs.\n\t *\n\t * Choose a reasonable default based on user preferences and wiki config.\n\t *\n\t * @public\n\t * @return {string}\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getDefaultLanguage = function () {\n\t\tif ( this.defaultLanguage !== undefined ) {\n\t\t\treturn this.defaultLanguage;\n\t\t}\n\n\t\tlet defaultLanguage = this.getClosestAllowedLanguage( mw.config.get( 'wgUserLanguage' ), null ) ||\n\t\t\tthis.getClosestAllowedLanguage( mw.config.get( 'wgContentLanguage' ), null ) ||\n\t\t\tthis.getClosestAllowedLanguage( 'en', null ) ||\n\t\t\tObject.keys( this.config.languages )[ 0 ];\n\n\t\t// Logic copied from MediaWiki:UploadForm.js\n\t\t// Per request from Portuguese and Brazilian users, treat Brazilian Portuguese as Portuguese.\n\t\tif ( defaultLanguage === 'pt-br' ) {\n\t\t\tdefaultLanguage = 'pt';\n\t\t// this was also in UploadForm.js, but without the heartwarming justification\n\t\t} else if ( defaultLanguage === 'en-gb' ) {\n\t\t\tdefaultLanguage = 'en';\n\t\t}\n\n\t\tthis.defaultLanguage = defaultLanguage;\n\t\treturn defaultLanguage;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\t// eslint-disable-next-line no-unused-vars\n\tuw.SingleLanguageInputWidget.prototype.validate = function ( thorough ) {\n\t\tconst status = new mw.uploadWizard.ValidationStatus(),\n\t\t\ttext = this.textInput.getValue().trim();\n\n\t\tif ( text.length !== 0 && text.length < this.config.minLength ) {\n\t\t\t// Empty input is allowed\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-too-short', this.config.minLength ) );\n\t\t}\n\t\tif ( text.length > this.config.maxLength ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-too-long', this.config.maxLength ) );\n\t\t}\n\n\t\treturn status.getErrors().length === 0 ? status.resolve() : status.reject();\n\t};\n\n\t/**\n\t * @param {Object} languages\n\t */\n\tuw.SingleLanguageInputWidget.prototype.updateLanguages = function ( languages ) {\n\t\tthis.languageSelector.updateLanguages( languages );\n\t};\n\n\t/**\n\t * @return {string} language code\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getLanguage = function () {\n\t\treturn this.languageSelector.getValue();\n\t};\n\n\t/**\n\t * @param {string} value language code\n\t */\n\tuw.SingleLanguageInputWidget.prototype.setLanguage = function ( value ) {\n\t\tthis.languageSelector.setValue( value );\n\t\tthis.textInput.$input.attr( 'lang', value );\n\t\tthis.textInput.$input.attr( 'spellcheck', '' );\n\t};\n\n\t/**\n\t * @return {string} text input\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getText = function () {\n\t\treturn this.textInput.getValue().trim();\n\t};\n\n\t/**\n\t * @param {string} value text input\n\t */\n\tuw.SingleLanguageInputWidget.prototype.setText = function ( value ) {\n\t\tthis.textInput.setValue( value );\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getWikiText = function () {\n\t\tlet language = this.getLanguage();\n\t\tconst text = this.getText();\n\n\t\tif ( !text ) {\n\t\t\treturn '';\n\t\t}\n\n\t\tif ( mw.UploadWizard.config.languageTemplateFixups[ language ] ) {\n\t\t\tlanguage = mw.UploadWizard.config.languageTemplateFixups[ language ];\n\t\t}\n\n\t\treturn '{{' + language + '|1=' + mw.Escaper.escapeForTemplate( text ) + '}}';\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.SingleLanguageInputWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\tlanguage: this.languageSelector.getValue(),\n\t\t\ttext: this.textInput.getValue(),\n\t\t\tremovable: this.config.removable\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} serialized\n\t * @param {string} serialized.language Language code\n\t * @param {string} serialized.text Text\n\t * @param {boolean} serialized.removable\n\t */\n\tuw.SingleLanguageInputWidget.prototype.setSerialized = function ( serialized ) {\n\t\tthis.setLanguage( serialized.language );\n\t\tthis.setText( serialized.text );\n\t\tthis.setRemovable( serialized.removable );\n\t};\n\n\t/**\n\t * @param {boolean} removable\n\t */\n\tuw.SingleLanguageInputWidget.prototype.setRemovable = function ( removable ) {\n\t\tthis.config.removable = !!removable;\n\t\tthis.$element.toggleClass( 'mwe-upwiz-singleLanguageInputWidget-removable', this.config.removable );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.StatementWidget.js","messages":[{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'dataValues.DataValue' is undefined.","line":70,"column":1,"nodeType":"Block","endLine":70,"endColumn":1},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'datamodel.StatementList' is undefined.","line":105,"column":1,"nodeType":"Block","endLine":105,"endColumn":1},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'datamodel.StatementList' is undefined.","line":117,"column":1,"nodeType":"Block","endLine":117,"endColumn":1},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'dataValues.DataValue' is undefined.","line":131,"column":1,"nodeType":"Block","endLine":131,"endColumn":1},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'datamodel.Statement' is undefined.","line":132,"column":1,"nodeType":"Block","endLine":132,"endColumn":1},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'datamodel.StatementList' is undefined.","line":145,"column":1,"nodeType":"Block","endLine":145,"endColumn":1}],"suppressedMessages":[{"ruleId":"no-unused-vars","severity":2,"message":"'thorough' is defined but never used.","line":93,"column":53,"nodeType":"Identifier","messageId":"unusedVar","endLine":93,"endColumn":61,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * @constructor\n\t * @param {Object} config Configuration options\n\t * @param {string} config.propertyId Property ID (e.g. P180 id of `depicts` property)\n\t */\n\tuw.StatementWidget = function UWStatementWidget( config ) {\n\t\tconst EntityInputWidget =\n\t\t\tmw.loader.require( 'wikibase.mediainfo.statements' ).inputs.EntityInputWidget,\n\t\t\tFormatValueElement =\n\t\t\t\tmw.loader.require( 'wikibase.mediainfo.base' ).FormatValueElement;\n\n\t\tthis.propertyId = config.propertyId;\n\t\tthis.datamodel = mw.loader.require( 'wikibase.datamodel' );\n\t\tthis.formatValueElement = new FormatValueElement();\n\t\tthis.placeholder = config.placeholder;\n\n\t\tuw.StatementWidget.super.call( this, config );\n\t\tthis.$element.addClass( 'mwe-upwiz-statementWidget' );\n\n\t\tthis.input = new EntityInputWidget( {\n\t\t\tisQualifier: false,\n\t\t\ttype: 'wikibase-entityid',\n\t\t\tdisabled: false,\n\t\t\thideSnakTypeWidget: true,\n\t\t\t$overlay: true,\n\t\t\ticon: '',\n\t\t\tlabel: '',\n\t\t\tplaceholder: this.placeholder\n\t\t} );\n\t\tthis.input.$element.addClass( 'mwe-upwiz-statement-input' );\n\t\tthis.$element.append( this.input.$element );\n\t\tthis.input.connect( this, { add: 'addTagFromInput' } );\n\t\tthis.input.connect( this, { focus: 'onFocus' } );\n\t\tthis.input.connect( this, { blur: 'onBlur' } );\n\n\t\tOO.ui.mixin.GroupWidget.call( this, config );\n\t\tthis.setGroupElement( this.$element );\n\t\tthis.aggregate( {\n\t\t\tremove: 'itemRemove',\n\t\t\tchange: [ 'emit', 'change' ]\n\t\t} );\n\t\tthis.connect( this, {\n\t\t\titemRemove: 'onTagRemove'\n\t\t} );\n\t};\n\n\tOO.inheritClass( uw.StatementWidget, OO.ui.Widget );\n\tOO.mixinClass( uw.StatementWidget, OO.ui.mixin.GroupWidget );\n\tOO.mixinClass( uw.StatementWidget, uw.ValidatableElement );\n\n\tuw.StatementWidget.prototype.onFocus = function () {\n\t\tthis.$element.addClass( 'mwe-upwiz-statementWidget-active' );\n\t};\n\n\tuw.StatementWidget.prototype.onBlur = function () {\n\t\tthis.input.clear();\n\t\tthis.$element.removeClass( 'mwe-upwiz-statementWidget-active' );\n\t};\n\n\t/**\n\t * Receives a DataValue from the input widget and uses it to create a new Tag\n\t */\n\tuw.StatementWidget.prototype.addTagFromInput = function () {\n\t\tthis.addTag( this.input.getData() );\n\t};\n\n\t/**\n\t * @param {dataValues.DataValue} dataValue\n\t */\n\tuw.StatementWidget.prototype.addTag = function ( dataValue ) {\n\t\tconst data = this.createStatement( dataValue );\n\n\t\tthis.formatValueElement.formatValue(\n\t\t\tdataValue, 'text/plain', null, this.propertyId\n\t\t).then( ( label ) => {\n\t\t\tif ( this.findItemFromData( data ) === null ) {\n\t\t\t\tconst tag = new OO.ui.TagItemWidget( {\n\t\t\t\t\tlabel: label, data: data\n\t\t\t\t} );\n\t\t\t\tthis.addItems( [ tag ] );\n\t\t\t\tthis.updateInputSize();\n\t\t\t}\n\t\t\tthis.input.clear();\n\t\t} );\n\t};\n\n\t/**\n\t * @inheritDoc\n\t */\n\t// eslint-disable-next-line no-unused-vars\n\tuw.StatementWidget.prototype.validate = function ( thorough ) {\n\t\tconst status = new uw.ValidationStatus(),\n\t\t\tmaxDepicts = 3;\n\n\t\tif ( this.getItems().length > maxDepicts ) {\n\t\t\tstatus.addNotice( mw.message( 'mwe-upwiz-statements-too-many-items', maxDepicts ) );\n\t\t}\n\n\t\treturn status.resolve();\n\t};\n\n\t/**\n\t * @param {datamodel.StatementList} data\n\t */\n\tuw.StatementWidget.prototype.setData = function ( data ) {\n\t\tconst statements = data.toArray();\n\n\t\tstatements.forEach( ( statement ) => {\n\t\t\tconst dataValue = statement.getClaim().getMainSnak().getValue();\n\t\t\tthis.addTag( dataValue );\n\t\t} );\n\t};\n\n\t/**\n\t * @param {datamodel.StatementList} data\n\t */\n\tuw.StatementWidget.prototype.resetData = function ( data ) {\n\t\tthis.clearItems();\n\t\tthis.setData( data );\n\t};\n\n\tuw.StatementWidget.prototype.onTagRemove = function ( tag ) {\n\t\tconst item = this.findItemFromData( tag.getData() );\n\t\tthis.removeItems( [ item ] );\n\t\tthis.updateInputSize();\n\t};\n\n\t/**\n\t * @param {dataValues.DataValue} dataValue\n\t * @return {datamodel.Statement}\n\t */\n\tuw.StatementWidget.prototype.createStatement = function ( dataValue ) {\n\t\tconst snak = new this.datamodel.PropertyValueSnak( this.propertyId, dataValue, null );\n\n\t\treturn new this.datamodel.Statement(\n\t\t\tnew this.datamodel.Claim(\n\t\t\t\tsnak\n\t\t\t)\n\t\t);\n\t};\n\n\t/**\n\t * @return {datamodel.StatementList}\n\t */\n\tuw.StatementWidget.prototype.getStatementList = function () {\n\t\treturn new this.datamodel.StatementList(\n\t\t\tthis.getItems().map( ( item ) => item.getData() )\n\t\t);\n\t};\n\n\t/**\n\t * Copied (more or less) from OO.ui.TagMultiselectWidget\n\t *\n\t * Update the dimensions of the text input field to encompass all available area.\n\t * This is especially relevant for when the input is at the edge of a line\n\t * and should get smaller. The usual operation (as an inline-block with min-width)\n\t * does not work in that case, pushing the input downwards to the next line.\n\t *\n\t * @private\n\t */\n\tuw.StatementWidget.prototype.updateInputSize = function () {\n\t\tconst containerWidth = this.$element.width();\n\n\t\tlet tagsWidth = 0;\n\t\tthis.input.$element.detach();\n\t\tthis.getItems().forEach( ( item ) => {\n\t\t\ttagsWidth += item.$element.outerWidth();\n\t\t} );\n\t\tlet newWidth = containerWidth - tagsWidth - 20;\n\n\t\t// if the new width is too narrow, expand to the container size instead (forces input onto\n\t\t// a new line)\n\t\tif ( this.placeholderWidth === undefined ) {\n\t\t\t// FIXME - calculate this rather than setting an arbitrary value\n\t\t\tthis.placeholderWidth = 200;\n\t\t}\n\t\tif ( newWidth < this.placeholderWidth ) {\n\t\t\tnewWidth = containerWidth;\n\t\t}\n\n\t\tthis.input.$element.width( newWidth );\n\t\tthis.$group.append( this.input.$element );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.TitleDetailsWidget.js","messages":[{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"thorough\" type.","line":112,"column":1,"nodeType":"Block","endLine":112,"endColumn":1},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":161,"column":30,"nodeType":"CallExpression","endLine":161,"endColumn":80},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":215,"column":27,"nodeType":"CallExpression","endLine":215,"endColumn":62},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":217,"column":21,"nodeType":"CallExpression","endLine":217,"endColumn":55}],"suppressedMessages":[{"ruleId":"no-unused-vars","severity":2,"message":"'thorough' is defined but never used.","line":116,"column":56,"nodeType":"Identifier","messageId":"unusedVar","endLine":116,"endColumn":64,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\tconst NS_FILE = mw.config.get( 'wgNamespaceIds' ).file,\n\t\tbyteLength = require( 'mediawiki.String' ).byteLength;\n\n\t/**\n\t * A title field in UploadWizard's \"Details\" step form.\n\t *\n\t * @class\n\t * @extends uw.DetailsWidget\n\t * @param {Object} [config]\n\t */\n\tuw.TitleDetailsWidget = function UWTitleDetailsWidget( config ) {\n\t\tconfig = config || {};\n\t\tuw.TitleDetailsWidget.super.call( this );\n\n\t\tthis.config = config;\n\t\tthis.extension = config.extension;\n\t\t// We wouldn't want or use any of mw.widgets.TitleInputWidget functionality.\n\t\tthis.titleInput = new OO.ui.TextInputWidget( {\n\t\t\tclasses: [ 'mwe-title', 'mwe-upwiz-titleDetailsWidget-title' ],\n\t\t\t// Add 1 character to the text input limit,\n\t\t\t// or the user will never see the error message if they reach the max title length.\n\t\t\tmaxLength: config.maxLength + 1\n\t\t} );\n\n\t\t// Aggregate 'change' event (with delay)\n\t\tthis.titleInput.on( 'change', OO.ui.debounce( this.emit.bind( this, 'change' ), 500 ) );\n\n\t\tthis.$element.addClass( 'mwe-upwiz-titleDetailsWidget' );\n\t\tthis.$element.append(\n\t\t\tthis.titleInput.$element\n\t\t);\n\n\t\tthis.isDuplicate = false;\n\t\tthis.on( 'change', () => {\n\t\t\tthis.isDuplicate = false;\n\t\t} );\n\t};\n\tOO.inheritClass( uw.TitleDetailsWidget, uw.DetailsWidget );\n\tOO.mixinClass( uw.TitleDetailsWidget, uw.ValidatableElement );\n\n\t/**\n\t * Reliably turn input into a MediaWiki title that is located in the 'File:' namespace.\n\t * Also applies file-specific checks ($wgIllegalFileChars).\n\t *\n\t * var title = uw.TitleDetailsWidget.static.makeTitleInFileNS( 'filename.ext' );\n\t *\n\t * @static\n\t * @param {string} filename Desired file name; optionally with 'File:' namespace prefixed\n\t * @return {mw.Title|null}\n\t */\n\tuw.TitleDetailsWidget.static.makeTitleInFileNS = function ( filename ) {\n\t\tlet mwTitle = mw.Title.newFromText( filename, NS_FILE );\n\t\tconst illegalFileChars = new RegExp( '[' + mw.config.get( 'wgIllegalFileChars', '' ) + ']' );\n\t\tif ( mwTitle && mwTitle.getNamespaceId() !== NS_FILE ) {\n\t\t\t// Force file namespace\n\t\t\tmwTitle = mw.Title.makeTitle( NS_FILE, filename );\n\t\t}\n\t\tif ( mwTitle && ( illegalFileChars.test( mwTitle.getMainText() ) || mwTitle.fragment !== null ) ) {\n\t\t\t// Consider the title invalid if it contains characters disallowed in file names\n\t\t\tmwTitle = null;\n\t\t}\n\t\treturn mwTitle;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TitleDetailsWidget.prototype.pushPending = function () {\n\t\tthis.titleInput.pushPending();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TitleDetailsWidget.prototype.popPending = function () {\n\t\tthis.titleInput.popPending();\n\t};\n\n\t/**\n\t * Get a mw.Title object for current input.\n\t *\n\t * @return {mw.Title|null}\n\t */\n\tuw.TitleDetailsWidget.prototype.getTitle = function () {\n\t\treturn this.buildTitleFromInput( this.titleInput.getValue() );\n\t};\n\n\t/**\n\t * Get a mw.Title object for a given value.\n\t *\n\t * @param {string} value\n\t * @return {mw.Title}\n\t */\n\tuw.TitleDetailsWidget.prototype.buildTitleFromInput = function ( value ) {\n\t\tvalue = value.trim();\n\t\tif ( !value ) {\n\t\t\treturn null;\n\t\t}\n\t\tconst extRegex = new RegExp( '\\\\.' + this.extension + '$', 'i' );\n\t\tconst cleaned = value.replace( extRegex, '' ).replace( /\\.+$/g, '' ).trim();\n\t\tconst title = uw.TitleDetailsWidget.static.makeTitleInFileNS( cleaned + '.' + this.extension );\n\t\treturn title;\n\t};\n\n\tuw.TitleDetailsWidget.prototype.setIsDuplicate = function ( isDuplicate ) {\n\t\tthis.isDuplicate = !!isDuplicate;\n\t};\n\n\t/**\n\t * @param thorough\n\t * @return {jQuery.Promise<uw.ValidationStatus>}\n\t */\n\t// eslint-disable-next-line no-unused-vars\n\tuw.TitleDetailsWidget.prototype.validate = function ( thorough ) {\n\t\tconst status = new uw.ValidationStatus(),\n\t\t\tvalue = this.titleInput.getValue().trim(),\n\t\t\ttitle = this.buildTitleFromInput( value ),\n\t\t\t// max title length is dependent on DB column size and is bytes rather than characters\n\t\t\tlength = byteLength( value ),\n\t\t\t// ... however MIN title length is easier for users to understand expressed in\n\t\t\t// characters rather than bytes\n\t\t\tcharLength = value.length;\n\n\t\tif ( value === '' ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-title-blank' ) );\n\t\t\treturn status.reject();\n\t\t}\n\n\t\tif ( this.config.minLength && charLength < this.config.minLength ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-title-too-few-characters', this.config.minLength ) );\n\t\t\treturn status.reject();\n\t\t}\n\n\t\tif ( this.config.maxLength && length > this.config.maxLength ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-title-too-long', this.config.maxLength ) );\n\t\t\treturn status.reject();\n\t\t}\n\n\t\tif ( !title ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-title-invalid' ) );\n\t\t\treturn status.reject();\n\t\t}\n\n\t\tif ( this.isDuplicate ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-title-duplicate' ) );\n\t\t\treturn status.reject();\n\t\t}\n\n\t\treturn mw.DestinationChecker.checkTitle( title.getPrefixedText() )\n\t\t\t.then( ( result ) => {\n\t\t\t\tthis.processDestinationCheck( result ).forEach( ( error ) => status.addError( error ) );\n\n\t\t\t\tif ( result.blacklist.unavailable ) {\n\t\t\t\t\t// We don't have a title blacklist, so just check for some likely undesirable patterns.\n\t\t\t\t\t// Messages:\n\t\t\t\t\t// mwe-upwiz-error-title-invalid, mwe-upwiz-error-title-senselessimagename,\n\t\t\t\t\t// mwe-upwiz-error-title-thumbnail, mwe-upwiz-error-title-extension,\n\t\t\t\t\tmw.QuickTitleChecker.checkTitle( title.getNameText() )\n\t\t\t\t\t\t.map( ( errorCode ) => mw.message( 'mwe-upwiz-error-title-' + errorCode ) )\n\t\t\t\t\t\t.forEach( ( error ) => status.addError( error ) );\n\t\t\t\t}\n\n\t\t\t\treturn status.getErrors().length === 0 ? status.resolve() : status.reject();\n\t\t\t} );\n\t};\n\n\t/**\n\t * Process the result of a destination filename check, return array of mw.Messages objects\n\t * representing errors.\n\t *\n\t * @private\n\t * @param {Object} result Result to process, output from mw.DestinationChecker\n\t * @return {mw.Message[]} Error messages\n\t */\n\tuw.TitleDetailsWidget.prototype.processDestinationCheck = function ( result ) {\n\t\tif ( result.unique.isUnique && result.blacklist.notBlacklisted && !result.unique.isProtected ) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Something is wrong with this title.\n\t\tconst errors = [];\n\n\t\tlet titleString;\n\t\ttry {\n\t\t\ttitleString = result.unique.title || result.title;\n\t\t\ttitleString = uw.TitleDetailsWidget.static.makeTitleInFileNS( titleString ).getPrefixedText();\n\t\t} catch ( e ) {\n\t\t\t// Unparseable result? This shouldn't happen, we checked for that earlier...\n\t\t\terrors.push( mw.message( 'mwe-upwiz-error-title-invalid' ) );\n\t\t\treturn errors;\n\t\t}\n\n\t\tif ( !result.unique.isUnique ) {\n\t\t\t// result is NOT unique\n\t\t\tif ( result.unique.href ) {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-fileexists-replace-on-page-v2' ) );\n\t\t\t} else {\n\t\t\t\terrors.push( mw.message( 'mwe-upwiz-fileexists-replace-no-link', titleString ) );\n\t\t\t}\n\t\t} else if ( result.unique.isProtected ) {\n\t\t\terrors.push( mw.message( 'mwe-upwiz-error-title-protected' ) );\n\t\t} else {\n\t\t\t// check whether we have a custom error message for this blacklist reason\n\t\t\tlet messageKey = 'mwe-upwiz-blacklisted-details-' + result.blacklist.blacklistMessage;\n\t\t\tif ( !mw.message( messageKey ).exists() ) {\n\t\t\t\tmessageKey = 'mwe-upwiz-blacklisted-details';\n\t\t\t}\n\n\t\t\tconst messageParams = [\n\t\t\t\tmessageKey,\n\t\t\t\ttitleString,\n\t\t\t\tfunction () {\n\t\t\t\t\tconst titleMessage = mw.message( messageKey + '-title' ),\n\t\t\t\t\t\ttitle = titleMessage.exists() ? titleMessage.text() : '',\n\t\t\t\t\t\ttextMessage = mw.message( messageKey + '-text' ),\n\t\t\t\t\t\ttext = textMessage.exists() ? textMessage.parseDom() : result.blacklist.blacklistReason;\n\n\t\t\t\t\tif ( typeof text === 'object' ) {\n\t\t\t\t\t\t// T407157: Links created by jqueryMsg don't open in a new tab, but we don't want the user to\n\t\t\t\t\t\t// lose their progress when clicking on a link. Therefore, we manually fix this here.\n\t\t\t\t\t\ttext.find( 'a' ).attr( 'target', '_blank' );\n\t\t\t\t\t}\n\n\t\t\t\t\tmw.errorDialog( text, title );\n\t\t\t\t}\n\t\t\t];\n\n\t\t\t// feedback request for titleblacklist\n\t\t\tif ( mw.UploadWizard.config.blacklistIssuesPage !== undefined && mw.UploadWizard.config.blacklistIssuesPage !== '' ) {\n\t\t\t\tmessageParams[ 0 ] = 'mwe-upwiz-blacklisted-details-feedback';\n\t\t\t\tmessageParams.push( () => {\n\t\t\t\t\tconst feedback = new mw.Feedback( {\n\t\t\t\t\t\ttitle: new mw.Title( mw.UploadWizard.config.blacklistIssuesPage ),\n\t\t\t\t\t\tdialogTitleMessageKey: 'mwe-upwiz-feedback-title'\n\t\t\t\t\t} );\n\t\t\t\t\tfeedback.launch( {\n\t\t\t\t\t\tmessage: mw.message( 'mwe-upwiz-feedback-blacklist-line-intro', result.blacklist.blacklistLine ).text(),\n\t\t\t\t\t\tsubject: mw.message( 'mwe-upwiz-feedback-blacklist-subject', titleString ).text()\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\terrors.push( mw.message.apply( mw, messageParams ) );\n\t\t}\n\n\t\treturn errors;\n\t};\n\n\t/**\n\t * @inheritdoc\n\t */\n\tuw.TitleDetailsWidget.prototype.getWikiText = function () {\n\t\treturn this.titleInput.getValue().trim();\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @return {Object} See #setSerialized\n\t */\n\tuw.TitleDetailsWidget.prototype.getSerialized = function () {\n\t\treturn {\n\t\t\ttitle: this.titleInput.getValue()\n\t\t};\n\t};\n\n\t/**\n\t * @inheritdoc\n\t * @param {Object} serialized\n\t * @param {string} serialized.language Title language code\n\t * @param {string} serialized.title Title text\n\t */\n\tuw.TitleDetailsWidget.prototype.setSerialized = function ( serialized ) {\n\t\tconst titleInput = this.titleInput,\n\t\t\ttitle = serialized.title;\n\n\t\ttitleInput.setValue( title );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/details/uw.UlsWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/handlers/mw.ApiUploadFormDataHandler.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/handlers/mw.ApiUploadHandler.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/handlers/mw.ApiUploadPostHandler.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/jquery.arrowSteps/jquery.arrowSteps.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/jquery/jquery.morphCrossfade.js","messages":[],"suppressedMessages":[{"ruleId":"no-jquery/no-animate","severity":2,"message":"Prefer CSS transitions to .animate","line":108,"column":6,"nodeType":"CallExpression","endLine":110,"endColumn":9,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-animate","severity":2,"message":"Prefer CSS transitions to .animate","line":116,"column":5,"nodeType":"CallExpression","endLine":121,"endColumn":8,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-animate","severity":2,"message":"Prefer CSS transitions to .animate","line":123,"column":5,"nodeType":"CallExpression","endLine":123,"endColumn":54,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.DestinationChecker.js","messages":[{"ruleId":"jsdoc/require-returns","severity":1,"message":"Found more than one @return declaration.","line":14,"column":3,"nodeType":"Block","endLine":23,"endColumn":6},{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"Found more than one @return declaration.","line":14,"column":3,"nodeType":"Block","endLine":23,"endColumn":6},{"ruleId":"jsdoc/require-returns","severity":1,"message":"Found more than one @return declaration.","line":35,"column":3,"nodeType":"Block","endLine":45,"endColumn":6},{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"Found more than one @return declaration.","line":35,"column":3,"nodeType":"Block","endLine":45,"endColumn":6},{"ruleId":"jsdoc/require-returns","severity":1,"message":"Found more than one @return declaration.","line":80,"column":3,"nodeType":"Block","endLine":91,"endColumn":6},{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"Found more than one @return declaration.","line":80,"column":3,"nodeType":"Block","endLine":91,"endColumn":6}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\n\t/**\n\t * @class\n\t */\n\tmw.DestinationChecker = {\n\n\t\tapi: new mw.Api(),\n\n\t\t// cached results from uniqueness api calls\n\t\tcachedResult: {},\n\t\tcachedBlacklist: {},\n\n\t\t/**\n\t\t * Check title for validity.\n\t\t *\n\t\t * @param {string} title Title to check\n\t\t * @return {jQuery.Promise}\n\t\t * @return {Function} return.done\n\t\t * @return {string} return.done.title The title that was passed in\n\t\t * @return {Object|boolean} return.done.blacklist See #checkBlacklist\n\t\t * @return {Object|boolean} return.done.unique See #checkUnique\n\t\t */\n\t\tcheckTitle: function ( title ) {\n\t\t\treturn $.when(\n\t\t\t\tthis.checkUnique( title ),\n\t\t\t\tthis.checkBlacklist( title )\n\t\t\t).then( ( unique, blacklist ) => ( {\n\t\t\t\tunique: unique,\n\t\t\t\tblacklist: blacklist,\n\t\t\t\ttitle: title\n\t\t\t} ) );\n\t\t},\n\n\t\t/**\n\t\t * Async check if a title is in the titleblacklist.\n\t\t *\n\t\t * @param {string} title Title to check against the blacklist\n\t\t * @return {jQuery.Promise}\n\t\t * @return {Function} return.done\n\t\t * @return {boolean} return.done.notBlacklisted\n\t\t * @return {string} [return.done.blacklistReason] See mw.Api#isBlacklisted\n\t\t * @return {string} [return.done.blacklistMessage] See mw.Api#isBlacklisted\n\t\t * @return {string} [return.done.blacklistLine] See mw.Api#isBlacklisted\n\t\t */\n\t\tcheckBlacklist: function ( title ) {\n\t\t\t/**\n\t\t\t * Process result of a TitleBlacklist API call.\n\t\t\t *\n\t\t\t * @private\n\t\t\t * @param {Object|boolean} blacklistResult `false` if not blacklisted, object if blacklisted\n\t\t\t * @return {Object}\n\t\t\t */\n\t\t\tconst blacklistResultProcessor = ( blacklistResult ) => {\n\t\t\t\tlet result;\n\n\t\t\t\tif ( blacklistResult === false ) {\n\t\t\t\t\tresult = { notBlacklisted: true };\n\t\t\t\t} else {\n\t\t\t\t\tresult = {\n\t\t\t\t\t\tnotBlacklisted: false,\n\t\t\t\t\t\tblacklistReason: blacklistResult.reason,\n\t\t\t\t\t\tblacklistMessage: blacklistResult.message,\n\t\t\t\t\t\tblacklistLine: blacklistResult.line\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tthis.cachedBlacklist[ title ] = result;\n\t\t\t\treturn result;\n\t\t\t};\n\n\t\t\tif ( this.cachedBlacklist[ title ] !== undefined ) {\n\t\t\t\treturn $.Deferred().resolve( this.cachedBlacklist[ title ] );\n\t\t\t}\n\n\t\t\t// it's not blacklisted, because the API isn't even available\n\t\t\treturn mw.loader.using( 'mediawiki.api.titleblacklist' ).then( () => this.api.isBlacklisted( title ).then( blacklistResultProcessor ), () => $.Deferred().resolve( { notBlacklisted: true, unavailable: true } ) );\n\t\t},\n\n\t\t/**\n\t\t * Async check if a filename is unique. Can be attached to a field's change() event\n\t\t * This is a more abstract version of AddMedia/UploadHandler.js::doDestCheck\n\t\t *\n\t\t * @param {string} title Title to check for uniqueness\n\t\t * @return {jQuery.Promise}\n\t\t * @return {Function} return.done\n\t\t * @return {boolean} return.done.isUnique\n\t\t * @return {boolean} [return.done.isProtected]\n\t\t * @return {Object} [return.done.img] Image info\n\t\t * @return {string} [return.done.href] URL to file description page\n\t\t */\n\t\tcheckUnique: function ( title ) {\n\t\t\tconst NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;\n\n\t\t\tconst titleObj = mw.Title.newFromText( title );\n\t\t\tconst ext = mw.Title.normalizeExtension( titleObj.getExtension() || '' );\n\t\t\t// Strip namespace and file extension\n\t\t\tconst prefix = titleObj.getNameText();\n\n\t\t\t/**\n\t\t\t * Process result of a an imageinfo API call.\n\t\t\t *\n\t\t\t * @private\n\t\t\t * @param {Object} data API result\n\t\t\t * @return {Object}\n\t\t\t */\n\t\t\tconst checkUniqueProcessor = ( data ) => {\n\t\t\t\tlet result, protection, pageId, ntitle, ntitleObj, img;\n\n\t\t\t\tresult = { isUnique: true };\n\n\t\t\t\tif ( data.query && data.query.pages ) {\n\t\t\t\t\t// The API will check for files with that filename.\n\t\t\t\t\t// If no file found: a page with a key of -1 and no imageinfo\n\t\t\t\t\t// If file found on another repository, such as when the wiki is using InstantCommons: page with a key of -1, plus imageinfo\n\t\t\t\t\t// If file found on this repository: page with some positive numeric key\n\t\t\t\t\tif ( data.query.pages[ -1 ] && !data.query.pages[ -1 ].imageinfo ) {\n\t\t\t\t\t\tprotection = data.query.pages[ -1 ].protection;\n\t\t\t\t\t\tif ( protection && protection.length > 0 ) {\n\t\t\t\t\t\t\tprotection.forEach( ( val ) => {\n\t\t\t\t\t\t\t\tif ( !mw.config.get( 'wgUserGroups' ).includes( val.level ) ) {\n\t\t\t\t\t\t\t\t\tresult = {\n\t\t\t\t\t\t\t\t\t\tisUnique: true,\n\t\t\t\t\t\t\t\t\t\tisProtected: true\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// No conflict found on any repository this wiki uses\n\t\t\t\t\t\t\tresult = { isUnique: true };\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor ( pageId in data.query.pages ) {\n\t\t\t\t\t\t\tif ( !Object.prototype.hasOwnProperty.call( data.query.pages, pageId ) ) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tntitle = data.query.pages[ pageId ].title;\n\t\t\t\t\t\t\tntitleObj = mw.Title.newFromText( ntitle );\n\t\t\t\t\t\t\tif ( ntitleObj.getNameText() !== prefix ) {\n\t\t\t\t\t\t\t\t// It's a different file name entirely\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif ( ext !== mw.Title.normalizeExtension( ntitleObj.getExtension() || '' ) ) {\n\t\t\t\t\t\t\t\t// It's a different extension, that's fine (e.g. to upload a SVG version of a PNG file)\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Conflict found, this filename is NOT unique\n\n\t\t\t\t\t\t\tif ( !data.query.pages[ pageId ].imageinfo ) {\n\t\t\t\t\t\t\t\t// This means that there's a page, but it's not a file. Well,\n\t\t\t\t\t\t\t\t// we should really report that anyway, but we shouldn't process\n\t\t\t\t\t\t\t\t// it like a file, and we should defer to other entries that may be files.\n\t\t\t\t\t\t\t\tresult = {\n\t\t\t\t\t\t\t\t\tisUnique: false,\n\t\t\t\t\t\t\t\t\ttitle: ntitle,\n\t\t\t\t\t\t\t\t\timg: null,\n\t\t\t\t\t\t\t\t\thref: null\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\timg = data.query.pages[ pageId ].imageinfo[ 0 ];\n\n\t\t\t\t\t\t\tresult = {\n\t\t\t\t\t\t\t\tisUnique: false,\n\t\t\t\t\t\t\t\timg: img,\n\t\t\t\t\t\t\t\ttitle: ntitle,\n\t\t\t\t\t\t\t\thref: img.descriptionurl\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t};\n\n\t\t\tif ( this.cachedResult[ title ] !== undefined ) {\n\t\t\t\treturn $.Deferred().resolve( this.cachedResult[ title ] );\n\t\t\t}\n\n\t\t\t// Setup the request -- will return thumbnail data if it finds one\n\t\t\t// XXX do not use iiurlwidth as it will create a thumbnail\n\t\t\treturn $.when(\n\t\t\t\t// Checks for exact matches on this wiki and foreign file repos\n\t\t\t\tthis.api.get( {\n\t\t\t\t\taction: 'query',\n\t\t\t\t\ttitles: title,\n\t\t\t\t\tprop: 'info|imageinfo',\n\t\t\t\t\tinprop: 'protection',\n\t\t\t\t\tiiprop: 'url|mime|size',\n\t\t\t\t\tiiurlwidth: 150\n\t\t\t\t} ).then( checkUniqueProcessor ),\n\t\t\t\t// Checks for matches with different versions of the file extension on this wiki only\n\t\t\t\tthis.api.get( {\n\t\t\t\t\taction: 'query',\n\t\t\t\t\tgenerator: 'allpages',\n\t\t\t\t\tgapnamespace: NS_FILE,\n\t\t\t\t\tgapprefix: prefix,\n\t\t\t\t\tprop: 'info|imageinfo',\n\t\t\t\t\tinprop: 'protection',\n\t\t\t\t\tiiprop: 'url|mime|size',\n\t\t\t\t\tiiurlwidth: 150\n\t\t\t\t} ).then( checkUniqueProcessor )\n\t\t\t).then( ( exact, fuzzy ) => {\n\t\t\t\tlet result;\n\t\t\t\tif ( !exact.isUnique || exact.isProtected ) {\n\t\t\t\t\tresult = exact;\n\t\t\t\t} else if ( !fuzzy.isUnique || fuzzy.isProtected ) {\n\t\t\t\t\tresult = fuzzy;\n\t\t\t\t} else {\n\t\t\t\t\tresult = { isUnique: true };\n\t\t\t\t}\n\n\t\t\t\tthis.cachedResult[ title ] = result;\n\t\t\t\treturn result;\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Clears the result cache\n\t\t */\n\t\tclearCache: function () {\n\t\t\tthis.cachedResult = {};\n\t\t}\n\n\t};\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.Escaper.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.FlickrChecker.js","messages":[{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"ui\" type.","line":4,"column":1,"nodeType":"Block","endLine":4,"endColumn":1},{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"selectButton\" type.","line":5,"column":1,"nodeType":"Block","endLine":5,"endColumn":1},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'getPhotos' is undefined.","line":212,"column":1,"nodeType":"Block","endLine":212,"endColumn":1},{"ruleId":"no-shadow","severity":1,"message":"'data' is already declared in the upper scope on line 219 column 15.","line":226,"column":17,"nodeType":"Identifier","messageId":"noShadow","endLine":226,"endColumn":21},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'getCollection' is undefined.","line":246,"column":1,"nodeType":"Block","endLine":246,"endColumn":1},{"ruleId":"no-shadow","severity":1,"message":"'data' is already declared in the upper scope on line 293 column 15.","line":304,"column":45,"nodeType":"Identifier","messageId":"noShadow","endLine":304,"endColumn":49},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'getPhotos' is undefined.","line":314,"column":1,"nodeType":"Block","endLine":314,"endColumn":1},{"ruleId":"jsdoc/no-undefined-types","severity":1,"message":"The type 'getPhotos' is undefined.","line":331,"column":1,"nodeType":"Block","endLine":331,"endColumn":1},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":375,"column":10,"nodeType":"CallExpression","endLine":506,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":468,"column":5,"nodeType":"CallExpression","endLine":477,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":519,"column":10,"nodeType":"CallExpression","endLine":594,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":581,"column":4,"nodeType":"CallExpression","endLine":586,"endColumn":7}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":99,"column":3,"nodeType":"CallExpression","endLine":99,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":108,"column":4,"nodeType":"CallExpression","endLine":108,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'api_key' is not in camel case.","line":174,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":174,"endColumn":11,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'user_id' is not in camel case.","line":202,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":202,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'group_id' is not in camel case.","line":228,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":228,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'user_id' is not in camel case.","line":229,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":229,"endColumn":13,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'group_id' is not in camel case.","line":235,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":235,"endColumn":13,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":267,"column":7,"nodeType":"CallExpression","endLine":267,"endColumn":49,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photoset_id' is not in camel case.","line":270,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":270,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'user_id' is not in camel case.","line":297,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":297,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'collection_id' is not in camel case.","line":301,"column":9,"nodeType":"Identifier","messageId":"notCamelCase","endLine":301,"endColumn":22,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":306,"column":5,"nodeType":"CallExpression","endLine":306,"endColumn":28,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'gallery_id' is not in camel case.","line":324,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":324,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photoset_id' is not in camel case.","line":338,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":338,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'per_page' is not in camel case.","line":358,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":358,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":445,"column":4,"nodeType":"CallExpression","endLine":445,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":463,"column":5,"nodeType":"CallExpression","endLine":463,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":465,"column":5,"nodeType":"CallExpression","endLine":465,"endColumn":35,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":467,"column":5,"nodeType":"CallExpression","endLine":467,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":490,"column":5,"nodeType":"CallExpression","endLine":490,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":493,"column":5,"nodeType":"CallExpression","endLine":493,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'skip_invisible' is not in camel case.","line":495,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":495,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photo_id' is not in camel case.","line":521,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":521,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_content'.","line":542,"column":47,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":542,"endColumn":67,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_content'.","line":556,"column":18,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":556,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_content'.","line":582,"column":46,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":582,"endColumn":72,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'path_alias' is not in camel case.","line":608,"column":34,"nodeType":"Identifier","messageId":"notCamelCase","endLine":608,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'path_alias' is not in camel case.","line":609,"column":3,"nodeType":"Identifier","messageId":"notCamelCase","endLine":609,"endColumn":13,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'path_alias' is not in camel case.","line":611,"column":76,"nodeType":"Identifier","messageId":"notCamelCase","endLine":611,"endColumn":86,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'path_alias' is not in camel case.","line":611,"column":90,"nodeType":"Identifier","messageId":"notCamelCase","endLine":611,"endColumn":100,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-support","severity":1,"message":"$.support is not allowed","line":655,"column":3,"nodeType":"MemberExpression","endLine":655,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photo_id' is not in camel case.","line":694,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":694,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_content'.","line":696,"column":39,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":696,"endColumn":70,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'photo_id' is not in camel case.","line":713,"column":4,"nodeType":"Identifier","messageId":"notCamelCase","endLine":713,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":12,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/* eslint-disable camelcase, no-underscore-dangle */\n\n/**\n * @param ui\n * @param selectButton\n * @class\n */\nmw.FlickrChecker = function ( ui, selectButton ) {\n\tthis.ui = ui;\n\tthis.imageUploads = [];\n\tthis.apiUrl = mw.UploadWizard.config.flickrApiUrl;\n\tthis.apiKey = mw.UploadWizard.config.flickrApiKey;\n\tthis.selectButton = selectButton;\n};\n\n/**\n * Static list of all Flickr upload filenames.\n * Used to avoid name conflicts. Filenames are not removed when an upload is cancelled, so this can\n * contain fakes. Since we only use the list to choose an ugly but more unique file format on conflict,\n * and never refuse an upload based on it, that is not really a problem.\n *\n * @type {Object}\n */\nmw.FlickrChecker.fileNames = {};\n\n/**\n * Cache for Flickr blacklist lookups.\n * Resolves to a hash whose keys are the blacklisted Flickr NSIDs.\n * Use `FlickrChecker.getBlacklist()` instead of accessing this directly.\n *\n * @type {jQuery.Promise}\n */\nmw.FlickrChecker.blacklist = null;\n\n/**\n * Cache for Flickr license lookups.\n *\n * @type {jQuery.Promise}\n */\nmw.FlickrChecker.licensePromise = null;\n\n/**\n * Flickr licenses.\n */\nmw.FlickrChecker.licenseList = [];\n\n// Map each Flickr license name to the equivalent templates.\n// These are the current Flickr license names as of July 2, 2025.\n// Live list at http://api.flickr.com/services/rest/?&method=flickr.photos.licenses.getInfo&api_key=...\nmw.FlickrChecker.licenseMaps = {\n\t'All Rights Reserved': 'invalid',\n\t'CC BY 2.0': '{{cc-by-2.0}}{{flickrreview}}',\n\t'CC BY-ND 2.0': 'invalid',\n\t'CC BY-NC-ND 2.0': 'invalid',\n\t'CC BY-NC 2.0': 'invalid',\n\t'CC BY-NC-SA 2.0': 'invalid',\n\t'CC BY-SA 2.0': '{{cc-by-sa-2.0}}{{flickrreview}}',\n\t'No known copyright restrictions': '{{Flickr-no known copyright restrictions}}{{flickrreview}}',\n\t'United States Government Work': '{{PD-USGov}}{{flickrreview}}',\n\t'Public Domain Dedication (CC0)': '{{cc-zero}}{{flickrreview}}',\n\t'Public Domain Mark': '{{PD-US}}{{flickrreview}}',\n\t'CC BY 4.0': '{{cc-by-4.0}}{{flickrreview}}',\n\t'CC BY-ND 4.0': 'invalid',\n\t'CC BY-NC-ND 4.0': 'invalid',\n\t'CC BY-NC 4.0': 'invalid',\n\t'CC BY-NC-SA 4.0': 'invalid',\n\t'CC BY-SA 4.0': '{{cc-by-sa-4.0}}{{flickrreview}}',\n\t// the following are old flickr license names from 2011, preserved here just in case\n\t'Attribution License': '{{cc-by-2.0}}{{flickrreview}}',\n\t'Attribution-NoDerivs License': 'invalid',\n\t'Attribution-NonCommercial-NoDerivs License': 'invalid',\n\t'Attribution-NonCommercial License': 'invalid',\n\t'Attribution-NonCommercial-ShareAlike License': 'invalid',\n\t'Attribution-ShareAlike License': '{{cc-by-sa-2.0}}{{flickrreview}}'\n};\n\nmw.FlickrChecker.prototype = {\n\t/**\n\t * If a photo is from Flickr, retrieve its license. If the license is valid, display the license\n\t * to the user, hide the normal license selection interface, and set it as the deed for the upload.\n\t * If the license is not valid, alert the user with an error message. If no recognized license is\n\t * retrieved, do nothing. Note that the license look-up system is fragile on purpose. If Flickr\n\t * changes the name associated with a license ID, it's better for the lookup to fail than to use\n\t * an incorrect license.\n\t *\n\t * @param {string} flickrInputUrl The source URL to check\n\t */\n\tcheckFlickr: function ( flickrInputUrl ) {\n\t\tlet photoIdMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/[^/]+\\/([0-9]+)/ );\n\t\tconst albumIdMatches = flickrInputUrl.match( /flickr\\.com\\/photos\\/[^/]+\\/(sets|albums)\\/([0-9]+)/ );\n\t\tconst userCollectionMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/[^/]+\\/collections\\/?([0-9]+)?/ );\n\t\tconst userPhotostreamMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/([^/]+)/ );\n\t\tconst groupPoolMatches = flickrInputUrl.match( /flickr\\.com\\/groups\\/[^/]+(?:\\/pool\\/([^/]+))?/ );\n\t\tconst userGalleryMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/[^/]+\\/galleries\\/([0-9]+)/ );\n\t\tconst userFavoritesMatches = flickrInputUrl.match( /flickr\\.com\\/(?:x\\/t\\/[^/]+\\/)?photos\\/([^/]+)\\/favorites/ );\n\n\t\tthis.$spinner = $.createSpinner( { size: 'large', type: 'block' } );\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( '#mwe-upwiz-flickr-select-list-container' ).after( this.$spinner );\n\n\t\tif ( photoIdMatches === null ) {\n\t\t\t// try static urls\n\t\t\tphotoIdMatches = flickrInputUrl.match( /static\\.?flickr\\.com\\/[^/]+\\/([0-9]+)_/ );\n\t\t}\n\t\tif ( albumIdMatches || photoIdMatches || userCollectionMatches || userPhotostreamMatches ||\n\t\t\tgroupPoolMatches || userGalleryMatches || userFavoritesMatches ) {\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$( '#mwe-upwiz-upload-add-flickr-container' ).hide();\n\t\t\tthis.imageUploads = [];\n\t\t\tif ( albumIdMatches && albumIdMatches[ 2 ] > 0 ) {\n\t\t\t\tthis.getPhotoset( albumIdMatches, flickrInputUrl );\n\t\t\t} else if ( photoIdMatches && photoIdMatches[ 1 ] > 0 ) {\n\t\t\t\tthis.getPhoto( photoIdMatches, flickrInputUrl );\n\t\t\t} else if ( userCollectionMatches ) {\n\t\t\t\tthis.getCollection( userCollectionMatches, flickrInputUrl );\n\t\t\t} else if ( userFavoritesMatches && userFavoritesMatches[ 1 ] ) {\n\t\t\t\tthis.getPhotostream( 'favorites', userPhotostreamMatches, flickrInputUrl );\n\t\t\t} else if ( userGalleryMatches && userGalleryMatches[ 1 ] ) {\n\t\t\t\tthis.getGallery( flickrInputUrl );\n\t\t\t} else if ( userPhotostreamMatches && userPhotostreamMatches[ 1 ] ) {\n\t\t\t\tthis.getPhotostream( 'stream', flickrInputUrl );\n\t\t\t} else if ( groupPoolMatches ) {\n\t\t\t\tthis.getGroupPool( groupPoolMatches, flickrInputUrl );\n\t\t\t}\n\t\t} else {\n\t\t\t// XXX show user the message that the URL entered was not valid\n\t\t\tmw.errorDialog( mw.msg( 'mwe-upwiz-url-invalid', 'Flickr' ) );\n\t\t\tthis.$spinner.remove();\n\t\t\tthis.ui.flickrInterfaceReset();\n\t\t}\n\t},\n\n\t/**\n\t * Returns a suggested filename for the image.\n\t * Usually the filename is just the Flickr title plus an extension, but in case of name conflicts\n\t * or empty title a unique filename is generated.\n\t *\n\t * @param {string} title image title on Flickr\n\t * @param {number} id image id on Flickr\n\t * @param {string} ownername owner name on Flickr\n\t * @return {string}\n\t */\n\tgetFilenameFromItem: function ( title, id, ownername ) {\n\t\tlet fileName;\n\n\t\tif ( title === '' ) {\n\t\t\tfileName = ownername + ' - ' + id + '.jpg';\n\t\t} else if ( mw.FlickrChecker.fileNames[ title + '.jpg' ] ) {\n\t\t\tfileName = title + ' - ' + id + '.jpg';\n\t\t} else {\n\t\t\tfileName = title + '.jpg';\n\t\t}\n\n\t\treturn fileName;\n\t},\n\n\t/**\n\t * Reserves a filename; used by `mw.FlickrChecker.getFileNameFromItem()` which tries to\n\t * avoid returning a filename which is already reserved.\n\t * This works even when the filename was reserved in a different FlickrChecker instance.\n\t *\n\t * @param {string} fileName\n\t */\n\treserveFileName: function ( fileName ) {\n\t\tmw.FlickrChecker.fileNames[ fileName ] = true;\n\t},\n\n\t/**\n\t * @param {Object} params\n\t * @return {jQuery.Promise} a promise with the response data\n\t */\n\tflickrRequest: function ( params ) {\n\t\tparams = Object.assign( {\n\t\t\tapi_key: this.apiKey,\n\t\t\tformat: 'json',\n\t\t\tnojsoncallback: 1\n\t\t}, params );\n\t\treturn $.getJSON( this.apiUrl, params );\n\t},\n\n\t/*\n\t * Retrieves a list of photos in photostream and displays it.\n\t * @see {@link getPhotos}\n\t * @param {string} mode may be: 'favorites' - user's favorites are retrieved,\n\t * or 'stream' - user's photostream is retrieved\n\t * @param {string} url URL to get the user from.\n\t * @return {jQuery.Promise}\n\t */\n\tgetPhotostream: function ( mode, url ) {\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.urls.lookupUser',\n\t\t\turl: url\n\t\t} ).then( ( data ) => {\n\t\t\tlet method;\n\t\t\tif ( mode === 'stream' ) {\n\t\t\t\tmethod = 'flickr.people.getPublicPhotos';\n\t\t\t} else if ( mode === 'favorites' ) {\n\t\t\t\tmethod = 'flickr.favorites.getPublicList';\n\t\t\t}\n\t\t\treturn this.getPhotos( 'photos', {\n\t\t\t\tmethod: method,\n\t\t\t\tuser_id: data.user.id\n\t\t\t} );\n\t\t} );\n\t},\n\n\t/**\n\t * Retrieves a list of photos in group pool and displays it.\n\t *\n\t * @param {Object} groupPoolMatches Groups in the input URL\n\t * @param {string} url The URL from which to get the group.\n\t * @see {@link getPhotos}\n\t * @return {jQuery.Promise}\n\t */\n\tgetGroupPool: function ( groupPoolMatches, url ) {\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.urls.lookupGroup',\n\t\t\turl: url\n\t\t} ).then( ( data ) => {\n\t\t\tconst gid = data.group.id;\n\n\t\t\tif ( groupPoolMatches[ 1 ] ) { // URL contains a user ID\n\t\t\t\treturn this.flickrRequest( {\n\t\t\t\t\tmethod: 'flickr.urls.lookupUser',\n\t\t\t\t\turl: 'http://www.flickr.com/photos/' + groupPoolMatches[ 1 ]\n\t\t\t\t} ).then( ( data ) => this.getPhotos( 'photos', {\n\t\t\t\t\tmethod: 'flickr.groups.pools.getPhotos',\n\t\t\t\t\tgroup_id: gid,\n\t\t\t\t\tuser_id: data.user.id\n\t\t\t\t} ) );\n\t\t\t}\n\n\t\t\treturn this.getPhotos( 'photos', {\n\t\t\t\tmethod: 'flickr.groups.pools.getPhotos',\n\t\t\t\tgroup_id: gid\n\t\t\t} );\n\t\t} );\n\t},\n\n\t/**\n\t * Constructs an unordered list of sets in the collection.\n\t *\n\t * @param {boolean} appendId True if you want to append\n\t * id=\"mwe-upwiz-files-collection-chooser\"; false otherwise\n\t * @param {Object} data The retrieved data\n\t * @see {@link getCollection}\n\t * @return {jQuery}\n\t */\n\tbuildCollectionLinks: function ( appendId, data ) {\n\t\tconst $elem = $( '<ul>' );\n\t\tif ( appendId ) {\n\t\t\t$elem.attr( 'id', 'mwe-upwiz-files-collection-chooser' );\n\t\t}\n\t\tdata.collection.forEach( ( value ) => {\n\t\t\tconst $li = $( '<li>' );\n\t\t\t$li.append( value.title );\n\t\t\tif ( value.collection !== undefined ) {\n\t\t\t\t$li.append( this.buildCollectionLinks( false, value ) );\n\t\t\t}\n\t\t\tif ( value.set !== undefined ) {\n\t\t\t\tconst $ul = $( '<ul>' );\n\t\t\t\tvalue.set.forEach( ( value2 ) => {\n\t\t\t\t\tconst $link = $( '<a>' ).attr( { href: '#', role: 'button', 'data-id': value2.id } );\n\t\t\t\t\t$link.append( value2.title );\n\t\t\t\t\t$link.on( 'click', () => {\n\t\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t\t$( '#mwe-upwiz-files-collection-chooser' ).remove();\n\t\t\t\t\t\tthis.getPhotos( 'photoset', {\n\t\t\t\t\t\t\tmethod: 'flickr.photosets.getPhotos',\n\t\t\t\t\t\t\tphotoset_id: $link.data( 'id' )\n\t\t\t\t\t\t} );\n\t\t\t\t\t} );\n\t\t\t\t\t$ul.append( $( '<li>' ).append( $link ) );\n\t\t\t\t} );\n\t\t\t\t$li.append( $ul );\n\t\t\t}\n\t\t\t$elem.append( $li );\n\t\t} );\n\t\treturn $elem;\n\t},\n\n\t/**\n\t * Retrieves a list of sets in a collection and displays it.\n\t *\n\t * @param {Object} userCollectionMatches Result of this.url.match\n\t * @param {string} url URL with which to look up the user.\n\t * @return {jQuery.Promise}\n\t */\n\tgetCollection: function ( userCollectionMatches, url ) {\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.urls.lookupUser',\n\t\t\turl: url\n\t\t} ).then( ( data ) => {\n\t\t\tconst req = {\n\t\t\t\tmethod: 'flickr.collections.getTree',\n\t\t\t\textras: 'license, url_sq, owner_name, original_format, date_taken, geo',\n\t\t\t\tuser_id: data.user.id\n\t\t\t};\n\n\t\t\tif ( userCollectionMatches[ 1 ] ) {\n\t\t\t\treq.collection_id = userCollectionMatches[ 1 ];\n\t\t\t}\n\n\t\t\treturn this.flickrRequest( req ).then( ( data ) => {\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-files' ).append( this.buildCollectionLinks( true, data.collections ) );\n\t\t\t} );\n\t\t} );\n\t},\n\n\t/**\n\t * Retrieves a list of photos in gallery and displays it.\n\t *\n\t * @see {@link getPhotos}\n\t * @param {string} url URL with which to look up the gallery information.\n\t * @return {jQuery.Promise}\n\t */\n\tgetGallery: function ( url ) {\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.urls.lookupGallery',\n\t\t\turl: url\n\t\t} ).then( ( data ) => this.getPhotos( 'photos', {\n\t\t\tmethod: 'flickr.galleries.getPhotos',\n\t\t\tgallery_id: data.gallery.id\n\t\t} ) );\n\t},\n\n\t/**\n\t * Retrieves a list of photos in photoset and displays it.\n\t *\n\t * @see {@link getPhotos}\n\t * @param {Object} albumIdMatches Result of this.url.match\n\t * @return {jQuery.Promise}\n\t */\n\tgetPhotoset: function ( albumIdMatches ) {\n\t\treturn this.getPhotos( 'photoset', {\n\t\t\tmethod: 'flickr.photosets.getPhotos',\n\t\t\tphotoset_id: albumIdMatches[ 2 ]\n\t\t} );\n\t},\n\n\t/**\n\t * Retrieves a list of photos and displays it.\n\t *\n\t * @param {string} mode may be: 'photoset' - for use with photosets,\n\t * or 'photos' - for use with everything else (the parameter is used\n\t * to determine how the properties in retrieved JSON are named)\n\t * @param {Object} options options to pass to the API call; especially API method\n\t * and some \"***_id\"s (photoset_id, etc.)\n\t * @return {jQuery.Promise}\n\t */\n\tgetPhotos: function ( mode, options ) {\n\t\tthis.selectButton.setLabel( mw.message( 'mwe-upwiz-select-flickr' ).text() );\n\t\tthis.selectButton.setDisabled( true );\n\n\t\tconst req = Object.assign( {}, options, {\n\t\t\textras: 'license, url_sq, owner_name, original_format, date_taken, geo, path_alias',\n\t\t\tper_page: '500'\n\t\t} );\n\n\t\tconst flickrPromise = this.flickrRequest( req ).then( ( data ) => {\n\t\t\tlet photoset;\n\t\t\tif ( mode === 'photoset' ) {\n\t\t\t\tphotoset = data.photoset;\n\t\t\t} else if ( mode === 'photos' ) {\n\t\t\t\tphotoset = data.photos;\n\t\t\t}\n\t\t\tif ( !photoset ) {\n\t\t\t\t$.Deferred().reject( mw.msg( 'mwe-upwiz-url-invalid', 'Flickr' ) );\n\t\t\t}\n\t\t\treturn photoset;\n\t\t} );\n\n\t\t// would be better to use isBlacklisted(), but didn't find a nice way of combining it with $.each\n\t\treturn $.when( flickrPromise, this.getBlacklist() ).then( ( photoset, blacklist ) => {\n\t\t\tlet sourceURL;\n\t\t\tconst checkboxes = [];\n\t\t\tconst checkboxesWidget = new OO.ui.CheckboxMultiselectWidget();\n\t\t\tlet x = 0;\n\n\t\t\tthis.$spinner.remove();\n\n\t\t\tphotoset.photo.forEach( ( item, i ) => {\n\t\t\t\tconst license = this.checkLicense( item.license );\n\t\t\t\tconst licenseValue = license.licenseValue;\n\t\t\t\tif ( licenseValue === 'invalid' ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet ownerId;\n\t\t\t\tif ( mode === 'photoset' ) {\n\t\t\t\t\townerId = photoset.owner;\n\t\t\t\t\tsourceURL = 'https://www.flickr.com/photos/' + photoset.owner + '/' + item.id + '/';\n\t\t\t\t} else if ( mode === 'photos' ) {\n\t\t\t\t\townerId = item.owner;\n\t\t\t\t\tsourceURL = 'https://www.flickr.com/photos/' + item.owner + '/' + item.id + '/';\n\t\t\t\t}\n\n\t\t\t\tif ( ownerId in blacklist || item.pathalias in blacklist ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Limit to maximum of 500 valid images\n\t\t\t\t// (Flickr's API returns a maximum of 500 images anyway.)\n\t\t\t\tif ( x++ >= 500 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst fileName = this.getFilenameFromItem( item.title, item.id, item.ownername );\n\n\t\t\t\tconst flickrUpload = {\n\t\t\t\t\tname: fileName,\n\t\t\t\t\turl: '',\n\t\t\t\t\ttype: 'JPEG',\n\t\t\t\t\tfromURL: true,\n\t\t\t\t\tsource: 'flickr',\n\t\t\t\t\tlicenseValue: licenseValue,\n\t\t\t\t\tlicenseMessage: license.licenseMessage,\n\t\t\t\t\tlicenseName: license.licenseName,\n\t\t\t\t\tphotoId: item.id,\n\t\t\t\t\tlocation: {\n\t\t\t\t\t\tlatitude: item.latitude,\n\t\t\t\t\t\tlongitude: item.longitude\n\t\t\t\t\t},\n\t\t\t\t\tauthor: item.ownername,\n\t\t\t\t\tdate: item.datetaken,\n\t\t\t\t\toriginalFormat: item.originalformat,\n\t\t\t\t\tsourceURL: sourceURL,\n\t\t\t\t\tindex: i\n\t\t\t\t};\n\t\t\t\t// Adding all the Photoset files which have a valid license with the required info to an array so that they can be referenced later\n\t\t\t\tthis.imageUploads[ i ] = flickrUpload;\n\t\t\t\tthis.reserveFileName( fileName );\n\n\t\t\t\t// setting up the thumbnail previews in the Selection list\n\t\t\t\tif ( item.url_sq ) {\n\t\t\t\t\tcheckboxes.push( new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\t\t\tdata: i,\n\t\t\t\t\t\tlabel: $( '<img class=\"lazy-thumbnail\" data-original=\"' + item.url_sq + '\">' )\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t} );\n\t\t\tcheckboxesWidget.addItems( checkboxes );\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$( '#mwe-upwiz-flickr-select-list' ).append( checkboxesWidget.$element );\n\t\t\t// Set up checkboxes\n\t\t\tcheckboxesWidget.on( 'select', () => {\n\t\t\t\tconst selectedCount = checkboxesWidget.findSelectedItems().length;\n\t\t\t\t// If at least one item is selected, activate the upload button\n\t\t\t\tthis.selectButton.setDisabled( selectedCount === 0 );\n\t\t\t\t// Limit the number of selectable images\n\t\t\t\tcheckboxesWidget.getItems().forEach( ( checkbox ) => {\n\t\t\t\t\tif ( !checkbox.isSelected() ) {\n\t\t\t\t\t\tcheckbox.setDisabled( selectedCount >= mw.UploadWizard.config.maxFlickrUploads );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\t\t// Set up action for 'Upload selected images' button\n\t\t\tthis.selectButton.on( 'click', () => {\n\t\t\t\tconst uploads = [];\n\t\t\t\tthis.$spinner = $.createSpinner( { size: 'large', type: 'block' } );\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-flickr-select-list-container' ).hide();\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-upload-ctrls' ).show();\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-flickr-select-list-container' ).after( this.$spinner );\n\t\t\t\t$.when.apply( $, checkboxesWidget.findSelectedItemsData().map( ( image ) => {\n\t\t\t\t\tuploads.push( this.imageUploads[ image ] );\n\t\t\t\t\t// For each image, load the description and URL to upload from\n\t\t\t\t\treturn $.when(\n\t\t\t\t\t\tthis.setUploadDescription( this.imageUploads[ image ] ),\n\t\t\t\t\t\tthis.setImageURL( image )\n\t\t\t\t\t);\n\t\t\t\t} ) ).done( () => {\n\t\t\t\t\tthis.ui.emit( 'files-added', uploads );\n\t\t\t\t} ).always( () => {\n\t\t\t\t\t// We'll only bind this once, since that selectButton could be\n\t\t\t\t\t// reused later, with a different flickr set (it is not destroyed)\n\t\t\t\t\tthis.selectButton.off( 'click' );\n\t\t\t\t\tthis.$spinner.remove();\n\t\t\t\t\tthis.ui.flickrInterfaceDestroy();\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\tif ( this.imageUploads.length === 0 ) {\n\t\t\t\treturn $.Deferred().reject( mw.msg( 'mwe-upwiz-license-photoset-invalid' ) );\n\t\t\t} else {\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( '#mwe-upwiz-flickr-select-list-container' ).show();\n\t\t\t\t// Lazy-load images\n\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t$( 'img.lazy-thumbnail' ).lazyload( {\n\t\t\t\t\t// jQuery considers all images without 'src' to not be ':visible'\n\t\t\t\t\tskip_invisible: false\n\t\t\t\t} );\n\t\t\t\t// Trigger initial update (HACK)\n\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t$( window ).triggerHandler( 'resize' );\n\t\t\t\t} );\n\t\t\t}\n\t\t} ).fail( ( message ) => {\n\t\t\tmw.errorDialog( message, mw.msg( 'mwe-upwiz-license-photoset-invalid-title' ) );\n\t\t\tthis.$spinner.remove();\n\t\t\tthis.ui.flickrInterfaceReset();\n\t\t} );\n\t},\n\n\t/**\n\t * Get a single photo from Flickr.\n\t *\n\t * @param {Object} photoIdMatches Result of matching input URL against a regex\n\t * for photo IDs.\n\t * @return {jQuery.Promise}\n\t */\n\tgetPhoto: function ( photoIdMatches ) {\n\t\tconst photoId = photoIdMatches[ 1 ];\n\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.photos.getInfo',\n\t\t\tphoto_id: photoId\n\t\t} ).then( ( data ) => {\n\t\t\tif ( !data.photo ) {\n\t\t\t\treturn $.Deferred().reject( mw.msg( 'mwe-upwiz-url-invalid', 'Flickr' ) );\n\t\t\t}\n\t\t\treturn data.photo;\n\t\t} ).then( ( photo ) => {\n\t\t\tconst isBlacklistedPromise = this.isBlacklisted( photo.owner.nsid, photo.owner.path_alias );\n\t\t\treturn isBlacklistedPromise.then( ( isBlacklisted ) => {\n\t\t\t\tif ( isBlacklisted ) {\n\t\t\t\t\treturn $.Deferred().reject( mw.msg( 'mwe-upwiz-user-blacklisted', 'Flickr' ) );\n\t\t\t\t} else {\n\t\t\t\t\treturn photo;\n\t\t\t\t}\n\t\t\t} );\n\t\t} ).then( ( photo ) => {\n\t\t\tconst license = this.checkLicense( photo.license );\n\t\t\tif ( license.licenseValue === 'invalid' ) {\n\t\t\t\treturn $.Deferred().reject( license.licenseMessage );\n\t\t\t}\n\n\t\t\tconst fileName = this.getFilenameFromItem( photo.title._content, photo.id,\n\t\t\t\tphoto.owner.username );\n\n\t\t\t// if owner doesn't have a real name, use username\n\t\t\tlet photoAuthor;\n\t\t\tif ( photo.owner.realname !== '' ) {\n\t\t\t\tphotoAuthor = photo.owner.realname;\n\t\t\t} else {\n\t\t\t\tphotoAuthor = photo.owner.username;\n\t\t\t}\n\t\t\t// get the URL of the photo page\n\t\t\tlet sourceURL;\n\t\t\tphoto.urls.url.forEach( ( url ) => {\n\t\t\t\tif ( url.type === 'photopage' ) {\n\t\t\t\t\tsourceURL = url._content;\n\t\t\t\t\t// break each loop\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tconst flickrUpload = {\n\t\t\t\tname: fileName,\n\t\t\t\turl: '',\n\t\t\t\ttype: 'JPEG',\n\t\t\t\tfromURL: true,\n\t\t\t\tsource: 'flickr',\n\t\t\t\tlicenseValue: license.licenseValue,\n\t\t\t\tlicenseMessage: license.licenseMessage,\n\t\t\t\tlicenseName: license.licenseName,\n\t\t\t\tauthor: photoAuthor,\n\t\t\t\toriginalFormat: photo.originalformat,\n\t\t\t\tdate: photo.dates.taken,\n\t\t\t\tlocation: photo.location,\n\t\t\t\tphotoId: photo.id,\n\t\t\t\tsourceURL: sourceURL\n\t\t\t};\n\n\t\t\tthis.imageUploads.push( flickrUpload );\n\t\t\tthis.reserveFileName( fileName );\n\n\t\t\t$.when(\n\t\t\t\tthis.setUploadDescription( flickrUpload, photo.description._content ),\n\t\t\t\tthis.setImageURL( 0 )\n\t\t\t).done( () => {\n\t\t\t\tthis.ui.emit( 'files-added', [ flickrUpload ] );\n\t\t\t} ).always( () => {\n\t\t\t\tthis.$spinner.remove();\n\t\t\t\tthis.ui.flickrInterfaceDestroy();\n\t\t\t} );\n\t\t} ).fail( ( message ) => {\n\t\t\tmw.errorDialog( message, mw.msg( 'mwe-upwiz-license-external-invalid-title' ) );\n\t\t\tthis.$spinner.remove();\n\t\t\tthis.ui.flickrInterfaceReset();\n\t\t} );\n\t},\n\n\t/**\n\t * Checks a user against the blacklist. Both the NSID and the path_alias (if it exists) MUST be\n\t * supplied, as the blacklist will probably only contain one of them. (Users don't have a\n\t * path_alias in the beginning, and must set it manually; if it does not exist, it can be left\n\t * undefined, or an empty string can be supplied (which is what the Flickr API usually returns\n\t * as the path_alias for such users).\n\t *\n\t * @param {string} nsid Flickr NSID of the author\n\t * @param {string} [path_alias] Flickr username of the author (the unchangeable one, in the URL)\n\t * @return {jQuery.Promise} a promise which resolves to a boolean - true if the user is blacklisted\n\t */\n\tisBlacklisted: function ( nsid, path_alias ) {\n\t\tpath_alias = String( path_alias );\n\t\t// the blacklist should never contain the empty string, but better safe then sorry\n\t\treturn this.getBlacklist().then( ( blacklist ) => ( nsid in blacklist || path_alias && path_alias in blacklist ) );\n\t},\n\n\t/**\n\t * Returns a promise for the Flickr user blacklist.\n\t * The promise resolves to a hash with the blacklisted NSIDs/path_alias-es as its keys.\n\t * (path_alias is the username that appears in the URL.)\n\t * The blacklist will usually contain the path_alias or the NSID of the user, but not both;\n\t * it is the caller's responsibility to check against both of them.\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tgetBlacklist: function () {\n\t\tconst api = new mw.Api();\n\t\tif ( !mw.FlickrChecker.blacklist ) {\n\t\t\tmw.FlickrChecker.blacklist = api.get( {\n\t\t\t\taction: 'flickrblacklist',\n\t\t\t\tlist: 1,\n\t\t\t\tformat: 'json'\n\t\t\t} ).then( ( data ) => {\n\t\t\t\tconst blacklist = {};\n\t\t\t\tif ( data.flickrblacklist && data.flickrblacklist.list ) {\n\t\t\t\t\tdata.flickrblacklist.list.forEach( ( username ) => {\n\t\t\t\t\t\tblacklist[ username ] = true;\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\treturn blacklist;\n\t\t\t} );\n\t\t}\n\t\treturn mw.FlickrChecker.blacklist;\n\t},\n\n\t/**\n\t * Retrieve the list of all current Flickr licenses and store it in an array (`mw.FlickrChecker.licenseList`)\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tgetLicenses: function () {\n\t\tif ( mw.FlickrChecker.licensePromise ) {\n\t\t\treturn mw.FlickrChecker.licensePromise;\n\t\t}\n\n\t\t// Workaround for http://bugs.jquery.com/ticket/8283\n\t\t// eslint-disable-next-line no-jquery/no-support\n\t\t$.support.cors = true;\n\t\tmw.FlickrChecker.licensePromise = this.flickrRequest( {\n\t\t\tmethod: 'flickr.photos.licenses.getInfo'\n\t\t} ).then( ( data ) => {\n\t\t\tif ( typeof data.licenses !== 'undefined' ) {\n\t\t\t\tdata.licenses.license.forEach( ( value ) => {\n\t\t\t\t\tmw.FlickrChecker.licenseList[ value.id ] = value.name;\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\treturn mw.FlickrChecker.licensePromise;\n\t},\n\n\t/**\n\t * @param {Object} upload\n\t * @param {string} description\n\t * @return {jQuery.Promise}\n\t */\n\tsetUploadDescription: function ( upload, description ) {\n\t\tif ( description !== undefined ) {\n\t\t\t// If a Flickr description has a | character in it, it will\n\t\t\t// mess up the MediaWiki description. Escape them.\n\t\t\tupload.description = description.replace( /\\|/g, '|' );\n\t\t\treturn $.Deferred().resolve();\n\t\t} else {\n\t\t\treturn this.setImageDescription( upload );\n\t\t}\n\t},\n\n\t/**\n\t * @param {Object} upload\n\t * @return {jQuery.Promise}\n\t */\n\tsetImageDescription: function ( upload ) {\n\t\tconst photoId = upload.photoId;\n\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.photos.getInfo',\n\t\t\tphoto_id: photoId\n\t\t} ).then( ( data ) => {\n\t\t\tthis.setUploadDescription( upload, data.photo.description._content );\n\t\t} );\n\t},\n\n\t/**\n\t * Retrieve the URL of the largest version available on Flickr and set that\n\t * as the upload URL.\n\t *\n\t * @param {number} index Index of the image for which we need to set the URL\n\t * @return {jQuery.Promise}\n\t */\n\tsetImageURL: function ( index ) {\n\t\tconst upload = this.imageUploads[ index ];\n\t\tconst photoId = upload.photoId;\n\n\t\treturn this.flickrRequest( {\n\t\t\tmethod: 'flickr.photos.getSizes',\n\t\t\tphoto_id: photoId\n\t\t} ).then( ( data ) => {\n\t\t\tlet nameParts;\n\n\t\t\tif (\n\t\t\t\ttypeof data.sizes !== 'undefined' &&\n\t\t\t\ttypeof data.sizes.size !== 'undefined' &&\n\t\t\t\tdata.sizes.size.length > 0\n\t\t\t) {\n\t\t\t\t// Flickr always returns the largest version as the final size.\n\t\t\t\t// TODO: Make this less fragile by actually comparing sizes.\n\t\t\t\tconst largestSize = data.sizes.size.pop();\n\t\t\t\t// Flickr provides the original format for images coming from pro users, hence we need to change the default JPEG to this format\n\t\t\t\tif ( largestSize.label === 'Original' ) {\n\t\t\t\t\tupload.type = upload.originalFormat;\n\n\t\t\t\t\tnameParts = upload.name.split( '.' );\n\t\t\t\t\tif ( nameParts.length > 1 ) {\n\t\t\t\t\t\tnameParts.pop();\n\t\t\t\t\t}\n\t\t\t\t\tupload.name = nameParts.join( '.' ) + '.' + upload.originalFormat;\n\t\t\t\t}\n\t\t\t\tupload.url = largestSize.source;\n\t\t\t} else {\n\t\t\t\tmw.errorDialog( mw.msg( 'mwe-upwiz-error-no-image-retrieved', 'Flickr' ) );\n\t\t\t\tthis.$spinner.remove();\n\t\t\t\tthis.ui.flickrInterfaceReset();\n\t\t\t\treturn $.Deferred().reject();\n\t\t\t}\n\t\t} );\n\t},\n\n\tcheckLicense: function ( licenseId ) {\n\t\t// The returned data.photo.license is just an ID that we use to look up the license name\n\t\tconst licenseName = mw.FlickrChecker.licenseList[ licenseId ];\n\t\t// Use the license name to retrieve the template values\n\t\tconst licenseValue = mw.FlickrChecker.licenseMaps[ licenseName ];\n\n\t\t// Set the license message to show the user.\n\t\tlet licenseMessage;\n\t\tif ( licenseValue === 'invalid' ) {\n\t\t\tlicenseMessage = mw.message( 'mwe-upwiz-license-external-invalid', 'Flickr', licenseName ).parseDom();\n\t\t} else {\n\t\t\tlicenseMessage = mw.msg( 'mwe-upwiz-license-external', 'Flickr', licenseName );\n\t\t}\n\n\t\treturn {\n\t\t\tlicenseName: licenseName,\n\t\t\tlicenseMessage: licenseMessage,\n\t\t\tlicenseValue: licenseValue\n\t\t};\n\t}\n};\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.GroupProgressBar.js","messages":[],"suppressedMessages":[{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeIn","line":51,"column":4,"nodeType":"CallExpression","endLine":51,"endColumn":70,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeOut","line":121,"column":4,"nodeType":"CallExpression","endLine":121,"endColumn":71,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.QuickTitleChecker.js","messages":[],"suppressedMessages":[{"ruleId":"no-control-regex","severity":2,"message":"Unexpected control character(s) in regular expression: \\x00, \\x1f.","line":30,"column":4,"nodeType":"Literal","messageId":"unexpected","endLine":30,"endColumn":17,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizard.js","messages":[{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"uw\" type.","line":4,"column":1,"nodeType":"Block","endLine":4,"endColumn":1},{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"config\" type.","line":9,"column":1,"nodeType":"Block","endLine":9,"endColumn":1},{"ruleId":"no-shadow","severity":1,"message":"'steps' is already declared in the upper scope on line 86 column 10.","line":112,"column":16,"nodeType":"Identifier","messageId":"noShadow","endLine":112,"endColumn":21}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Object that represents the entire multi-step Upload Wizard\n *\n * @param uw\n */\n( function ( uw ) {\n\n\t/**\n\t * @param config\n\t * @class\n\t */\n\tmw.UploadWizard = function ( config ) {\n\t\tthis.api = this.getApi( { ajax: { timeout: 0 } } );\n\n\t\t// making a sort of global for now, should be done by passing in config or fragments of config\n\t\t// when needed elsewhere\n\t\tmw.UploadWizard.config = config;\n\t\t// Shortcut for local references\n\t\tthis.config = config;\n\n\t\tthis.steps = {};\n\n\t\tconst maxSimPref = mw.user.options.get( 'upwiz_maxsimultaneous' );\n\n\t\tif ( maxSimPref !== 'default' ) {\n\t\t\tconfig.maxSimultaneousConnections = Math.max( 1, maxSimPref );\n\t\t}\n\n\t\tthis.maxSimultaneousConnections = config.maxSimultaneousConnections;\n\n\t\tif ( mw.loader.getState( 'ext.uls.mediawiki' ) !== null ) {\n\t\t\tmw.loader.load( 'ext.uls.mediawiki' );\n\t\t}\n\t};\n\n\tmw.UploadWizard.DEBUG = true;\n\n\tmw.UploadWizard.userAgent = 'UploadWizard';\n\n\tmw.UploadWizard.prototype = {\n\t\t/**\n\t\t * Create the basic interface to make an upload in this div\n\t\t *\n\t\t * @param {string} selector\n\t\t */\n\t\tcreateInterface: function ( selector ) {\n\t\t\tthis.ui = new uw.ui.Wizard( selector );\n\n\t\t\tconst promise = this.initialiseSteps();\n\n\t\t\tif (\n\t\t\t\tthis.config.wikibase.enabled &&\n\t\t\t\t// .depicts is for backward compatibility\n\t\t\t\t( this.config.wikibase.statements || this.config.wikibase.depicts )\n\t\t\t) {\n\t\t\t\t// mediainfo has a couple of widgets that we'll be using, but they're not\n\t\t\t\t// necessarily a hard dependency for UploadWizard\n\t\t\t\t// let's just attempt to load them - if not available we'll just do without\n\t\t\t\tpromise.then( () => {\n\t\t\t\t\t// disable wikibase until its components are loaded - this is just a safeguard\n\t\t\t\t\t// against the 'details' page being loaded with captions/depicts before\n\t\t\t\t\t// the wikibase components have loaded\n\t\t\t\t\tthis.config.wikibase.enabled = false;\n\t\t\t\t\treturn mw.loader.using( [\n\t\t\t\t\t\t'wikibase.mediainfo.statements',\n\t\t\t\t\t\t'wikibase.datamodel',\n\t\t\t\t\t\t'wikibase.mediainfo.base'\n\t\t\t\t\t] ).then( () => {\n\t\t\t\t\t\tthis.config.wikibase.enabled = true;\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tpromise.then( ( steps ) => {\n\t\t\t\t// \"select\" the first step - highlight, make it visible, hide all others\n\t\t\t\tsteps.tutorial.load( [] );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Initialise the steps in the wizard\n\t\t *\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tinitialiseSteps: function () {\n\t\t\tconst steps = {};\n\n\t\t\tsteps.tutorial = new uw.controller.Tutorial( this.api, this.config );\n\t\t\tsteps.file = new uw.controller.Upload( this.api, this.config );\n\t\t\tsteps.deeds = new uw.controller.Deed( this.api, this.config );\n\t\t\tsteps.details = new uw.controller.Details( this.api, this.config );\n\t\t\tsteps.thanks = new uw.controller.Thanks( this.api, Object.assign(\n\t\t\t\t{ showInBreadcrumb: false },\n\t\t\t\tthis.config\n\t\t\t) );\n\n\t\t\tsteps.tutorial.setNextStep( steps.file );\n\n\t\t\tsteps.file.setPreviousStep( steps.tutorial );\n\t\t\tsteps.file.setNextStep( steps.deeds );\n\n\t\t\tsteps.deeds.setPreviousStep( steps.file );\n\t\t\tsteps.deeds.setNextStep( steps.details );\n\n\t\t\tsteps.details.setPreviousStep( steps.deeds );\n\t\t\tsteps.details.setNextStep( steps.thanks );\n\n\t\t\t// thanks doesn't need a \"previous\" step, there's no undoing uploads!\n\t\t\tsteps.thanks.setNextStep( steps.file );\n\n\t\t\treturn $.Deferred().resolve( steps ).promise()\n\t\t\t\t.always( ( steps ) => {\n\t\t\t\t\tthis.steps = steps;\n\t\t\t\t\tthis.ui.initialiseSteps( steps );\n\t\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * mw.Api's ajax calls are not very consistent in their error handling.\n\t\t * As long as the response comes back, the response will be fine: it'll\n\t\t * get rejected with the error details there. However, if no response\n\t\t * comes back for whatever reason, things can get confusing.\n\t\t * I'll monkeypatch around such cases so that we can always rely on the\n\t\t * error response the way we want it to be.\n\t\t *\n\t\t * TODO: Instead of this monkeypatching, we could call api.getErrorMessage()\n\t\t * in the error handlers to get nice messages.\n\t\t *\n\t\t * @param {Object} options\n\t\t * @return {mw.Api}\n\t\t */\n\t\tgetApi: function ( options ) {\n\t\t\tconst api = new mw.Api( options );\n\n\t\t\tapi.ajax = function ( parameters, ajaxOptions ) {\n\t\t\t\tObject.assign( parameters, {\n\t\t\t\t\terrorformat: 'html',\n\t\t\t\t\terrorlang: mw.config.get( 'wgUserLanguage' ),\n\t\t\t\t\terrorsuselocal: 1,\n\t\t\t\t\tformatversion: 2\n\t\t\t\t} );\n\n\t\t\t\tconst original = mw.Api.prototype.ajax.apply( this, [ parameters, ajaxOptions ] );\n\n\t\t\t\t// we'll attach a default error handler that makes sure error\n\t\t\t\t// output is always, reliably, in the same format\n\t\t\t\tconst override = original.then(\n\t\t\t\t\tnull, // done handler - doesn't need overriding\n\t\t\t\t\t( code, result ) => { // fail handler\n\t\t\t\t\t\tlet response = { errors: [ {\n\t\t\t\t\t\t\tcode: code,\n\t\t\t\t\t\t\thtml: result.textStatus || mw.message( 'api-clientside-error-invalidresponse' ).parse()\n\t\t\t\t\t\t} ] };\n\n\t\t\t\t\t\tif ( result.errors && result.errors[ 0 ] ) {\n\t\t\t\t\t\t\t// in case of success-but-has-errors, we have a valid result\n\t\t\t\t\t\t\tresponse = result;\n\t\t\t\t\t\t} else if ( result && result.textStatus === 'timeout' ) {\n\t\t\t\t\t\t\t// in case of $.ajax.fail(), there is no response json\n\t\t\t\t\t\t\tresponse.errors[ 0 ].html = mw.message( 'api-clientside-error-timeout' ).parse();\n\t\t\t\t\t\t} else if ( result && result.textStatus === 'parsererror' ) {\n\t\t\t\t\t\t\tresponse.errors[ 0 ].html = mw.message( 'api-error-parsererror' ).parse();\n\t\t\t\t\t\t} else if ( code === 'http' && result && result.xhr && result.xhr.status === 0 ) {\n\t\t\t\t\t\t\t// failed to even connect to server\n\t\t\t\t\t\t\tresponse.errors[ 0 ].html = mw.message( 'api-clientside-error-noconnect' ).parse();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn $.Deferred().reject( code, response, response );\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\t/*\n\t\t\t\t * After attaching (.then) our error handler, a new promise is\n\t\t\t\t * returned. The original promise had an 'abort' method, which\n\t\t\t\t * we'll also want to make use of...\n\t\t\t\t */\n\t\t\t\treturn override.promise( { abort: original.abort } );\n\t\t\t};\n\n\t\t\treturn api;\n\t\t}\n\t};\n\n\t/**\n\t * Helper method to put a thumbnail somewhere.\n\t *\n\t * @param {string|jQuery} selector String representing a jQuery selector, or a jQuery object\n\t * @param {HTMLCanvasElement|HTMLImageElement|null} image\n\t */\n\tmw.UploadWizard.placeThumbnail = function ( selector, image ) {\n\t\tif ( image === null ) {\n\t\t\t$( selector ).addClass( 'mwe-upwiz-file-preview-broken' );\n\t\t\treturn;\n\t\t}\n\n\t\t$( selector )\n\t\t\t.css( { background: 'none' } )\n\t\t\t.prepend(\n\t\t\t\t$( '<a>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-thumbnail-link' )\n\t\t\t\t\t.append( image )\n\t\t\t);\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardDeedChooser.js","messages":[{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":32,"column":42,"nodeType":"ObjectExpression","endLine":32,"endColumn":89},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":40,"column":17,"nodeType":"CallExpression","endLine":40,"endColumn":86},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":44,"column":21,"nodeType":"CallExpression","endLine":47,"endColumn":5}],"suppressedMessages":[{"ruleId":"no-unused-vars","severity":2,"message":"'thorough' is defined but never used.","line":94,"column":61,"nodeType":"Identifier","messageId":"unusedVar","endLine":94,"endColumn":69,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":131,"column":3,"nodeType":"CallExpression","endLine":131,"endColumn":29,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":157,"column":3,"nodeType":"CallExpression","endLine":157,"endColumn":29,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\n\t/**\n\t * Interface widget to choose among various deeds -- for instance, if own work, or not own work, or other such cases.\n\t *\n\t * @class\n\t * @mixes OO.EventEmitter\n\t * @param {Object} config The UW config\n\t * @param {Object} deeds Keyed object of UploadWizardDeed items\n\t * @param {mw.UploadWizardUpload[]} uploads Uploads that this applies to (this is just to make deleting and plurals work)\n\t */\n\tmw.UploadWizardDeedChooser = function ( config, deeds, uploads ) {\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.uploads = uploads;\n\t\tthis.deeds = deeds;\n\n\t\t// Name for radio button set\n\t\tmw.UploadWizardDeedChooser.prototype.widgetCount++;\n\t\tthis.name = 'deedChooser' + mw.UploadWizardDeedChooser.prototype.widgetCount.toString();\n\n\t\tthis.onLayoutReady = function () {};\n\n\t\tconst $radioContainer = $( '<div>' ).addClass( 'mwe-upwiz-deed-radios' );\n\t\tconst $formContainer = $( '<div>' ).addClass( 'mwe-upwiz-deed-forms' );\n\t\tthis.$element = $( '<div>' ).addClass( 'mwe-upwiz-deeds-container' ).append(\n\t\t\t$radioContainer, $formContainer\n\t\t);\n\n\t\tObject.keys( this.deeds ).forEach( ( name ) => {\n\t\t\tconst deed = this.deeds[ name ],\n\t\t\t\tradio = new OO.ui.RadioSelectWidget( { classes: [ 'mwe-upwiz-deed-radio-' + name ] } ),\n\t\t\t\toption = new OO.ui.RadioOptionWidget(),\n\t\t\t\t// Separate the radio option from its form\n\t\t\t\t$deedRadio = $( '<div>' ).addClass( 'mwe-upwiz-deed-option-title' ).append(\n\t\t\t\t\t$( '<span>' ).addClass( 'mwe-upwiz-deed-header' ).append(\n\t\t\t\t\t\tradio.$element\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\t$deedForm = $( '<div>' ).addClass( 'mwe-upwiz-deed mwe-upwiz-deed-' + deed.name ).append(\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-deed-form' )\n\t\t\t\t).hide();\n\n\t\t\toption.setLabel( mw.message(\n\t\t\t\t'mwe-upwiz-source-' + deed.name + '-label',\n\t\t\t\tthis.uploads.length\n\t\t\t).text() );\n\n\t\t\tradio.addItems( [ option ] );\n\n\t\t\t// Set the name attribute manually. We can't use RadioInputWidget which has\n\t\t\t// a name config because they don't emit change events. Ideally we would use\n\t\t\t// one RadioSelectWidget and not have to set this property.\n\t\t\tradio.items[ 0 ].radio.$input.attr( 'name', this.name );\n\n\t\t\t// Append intermediate containers\n\t\t\t$radioContainer.append( $deedRadio );\n\t\t\t$formContainer.append( $deedForm );\n\n\t\t\tdeed.setFormFields( $deedForm.find( '.mwe-upwiz-deed-form' ) );\n\n\t\t\tif ( Object.keys( this.deeds ).length === 1 ) {\n\t\t\t\tthis.onLayoutReady = this.selectDeed.bind( this, deed );\n\t\t\t} else {\n\t\t\t\tif ( config.licensing.defaultType === deed.name ) {\n\t\t\t\t\tthis.onLayoutReady = this.selectDeed.bind( this, deed );\n\t\t\t\t}\n\t\t\t\tradio.on( 'choose', () => {\n\t\t\t\t\tthis.selectDeed( deed );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\t// Deselect all deeds\n\t\tObject.keys( this.deeds ).forEach( ( name ) => {\n\t\t\tthis.deselectDeedInterface( name );\n\t\t} );\n\t};\n\tOO.mixinClass( mw.UploadWizardDeedChooser, OO.EventEmitter );\n\tOO.mixinClass( mw.UploadWizardDeedChooser, mw.uploadWizard.ValidatableElement );\n\n\t/**\n\t * How many deed choosers there are (important for creating unique ids, element names)\n\t */\n\tmw.UploadWizardDeedChooser.prototype.widgetCount = 0;\n\n\t/**\n\t * Check if this form is filled out correctly.\n\t *\n\t * @param {boolean} thorough\n\t * @return {jQuery.Promise<mw.uploadWizard.ValidationStatus>}\n\t */\n\t// eslint-disable-next-line no-unused-vars\n\tmw.UploadWizardDeedChooser.prototype.validate = function ( thorough ) {\n\t\tconst status = new mw.uploadWizard.ValidationStatus();\n\t\tif ( !this.deed ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-deeds-require-selection' ) );\n\t\t}\n\t\treturn status.getErrors().length === 0 ? status.resolve() : status.reject();\n\t};\n\n\t/**\n\t * Uploads this deed controls\n\t */\n\tmw.UploadWizardDeedChooser.prototype.uploads = [];\n\n\tmw.UploadWizardDeedChooser.prototype.selectDeed = function ( deed ) {\n\t\tthis.choose( deed );\n\t\tthis.selectDeedInterface( deed.name );\n\t};\n\n\tmw.UploadWizardDeedChooser.prototype.choose = function ( deed ) {\n\t\tthis.deed = deed;\n\t\tthis.emit( 'choose' );\n\t};\n\n\t/**\n\t * From the deed choices, make a choice fade to the background a bit, hide the extended form\n\t *\n\t * @param {string} deedName\n\t */\n\tmw.UploadWizardDeedChooser.prototype.deselectDeedInterface = function ( deedName ) {\n\t\tconst $deedRadio = this.$element.find( '.mwe-upwiz-deed-radio-' + deedName + ' input' ),\n\t\t\t$deedForm = this.$element.find( '.mwe-upwiz-deed.mwe-upwiz-deed-' + deedName );\n\n\t\t$deedRadio.prop( 'checked', false );\n\t\t$deedForm.removeClass( 'selected' );\n\t\t// Prevent validation of deselected deeds by disabling all form inputs\n\t\t// TODO: Use a tag selector\n\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t$deedForm.find( ':input' ).prop( 'disabled', true );\n\t\t$deedForm.hide();\n\t};\n\n\t/**\n\t * From the deed choice page, show a particular deed\n\t *\n\t * @param {string} deedName\n\t */\n\tmw.UploadWizardDeedChooser.prototype.selectDeedInterface = function ( deedName ) {\n\t\tconst $deedRadio = this.$element.find( '.mwe-upwiz-deed-radio-' + deedName + ' input' ),\n\t\t\t$deedForm = this.$element.find( '.mwe-upwiz-deed.mwe-upwiz-deed-' + deedName );\n\n\t\t// deselect all other deeds\n\t\tObject.keys( this.deeds ).forEach( ( name ) => {\n\t\t\tif ( name === deedName ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.deselectDeedInterface( name );\n\t\t} );\n\n\t\t$deedRadio.prop( 'checked', true );\n\t\t$deedForm.addClass( 'selected' );\n\t\t// (Re-)enable all form inputs\n\t\t// TODO: Use a tag selector\n\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t$deedForm.find( ':input' ).prop( 'disabled', false );\n\t\t$deedForm.show();\n\t};\n\n\tmw.UploadWizardDeedChooser.prototype.remove = function () {\n\t\tObject.keys( this.deeds ).forEach( ( name ) => {\n\t\t\tthis.deeds[ name ].unload();\n\t\t} );\n\n\t\tthis.$element.remove();\n\t};\n\n\t/**\n\t * @return {Object}\n\t */\n\tmw.UploadWizardDeedChooser.prototype.getSerialized = function () {\n\t\treturn this.deed ? this.deed.getSerialized() : {};\n\t};\n\n\t/**\n\t * @param {Object} serialized\n\t */\n\tmw.UploadWizardDeedChooser.prototype.setSerialized = function ( serialized ) {\n\t\tlet deed;\n\n\t\tif ( serialized.name && serialized.name in this.deeds ) {\n\t\t\tdeed = this.deeds[ serialized.name ];\n\t\t\tdeed.setSerialized( serialized );\n\t\t\tthis.selectDeed( deed );\n\t\t}\n\t};\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardDetails.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":498,"column":5,"nodeType":"CallExpression","endLine":504,"endColumn":8},{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"thorough\" type.","line":678,"column":1,"nodeType":"Block","endLine":678,"endColumn":1},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":715,"column":4,"nodeType":"CallExpression","endLine":717,"endColumn":7},{"ruleId":"jsdoc/require-returns-check","severity":1,"message":"JSDoc @return declaration present but return expression not available in function.","line":935,"column":3,"nodeType":"Block","endLine":943,"endColumn":6}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":272,"column":24,"nodeType":"CallExpression","endLine":272,"endColumn":57,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":287,"column":7,"nodeType":"CallExpression","endLine":287,"endColumn":24,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":296,"column":24,"nodeType":"CallExpression","endLine":296,"endColumn":57,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":387,"column":26,"nodeType":"CallExpression","endLine":387,"endColumn":59,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":402,"column":9,"nodeType":"CallExpression","endLine":402,"endColumn":26,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":411,"column":26,"nodeType":"CallExpression","endLine":411,"endColumn":59,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":1197,"column":6,"nodeType":"CallExpression","endLine":1197,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":1199,"column":6,"nodeType":"CallExpression","endLine":1199,"endColumn":37,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'dataValues' is not defined.","line":1323,"column":37,"nodeType":"Identifier","messageId":"undef","endLine":1323,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'dataValues' is not defined.","line":1335,"column":12,"nodeType":"Identifier","messageId":"undef","endLine":1335,"endColumn":22,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\tconst NS_FILE = mw.config.get( 'wgNamespaceIds' ).file;\n\n\t/**\n\t * Object that represents the Details (step 2) portion of the UploadWizard\n\t * n.b. each upload gets its own details.\n\t *\n\t * @class\n\t * @param {mw.UploadWizardUpload} upload\n\t * @param {jQuery} $containerDiv The `div` to put the interface into\n\t */\n\tmw.UploadWizardDetails = function ( upload, $containerDiv ) {\n\t\tthis.upload = upload;\n\t\tthis.$containerDiv = $containerDiv;\n\t\tthis.api = upload.api;\n\n\t\tthis.mainFields = [];\n\n\t\tthis.structuredDataSubmissionErrors = false;\n\n\t\tthis.$div = $( '<div>' ).addClass( 'mwe-upwiz-info-file filled' );\n\n\t\tOO.EventEmitter.call( this );\n\t};\n\n\tmw.UploadWizardDetails.prototype = {\n\n\t\t// Has this details object been attached to the DOM already?\n\t\tisAttached: false,\n\n\t\t// Build the interface and attach all elements - do this on demand\n\t\tbuildInterface: function () {\n\t\t\tconst config = mw.UploadWizard.config,\n\t\t\t\tcaptionsAvailable = config.wikibase.enabled && config.wikibase.captions,\n\t\t\t\t// the following only end up getting used if statements are enabled\n\t\t\t\tdataTypesMap = mw.config.get( 'wbDataTypes' ) || {},\n\t\t\t\tdefaultProperties = mw.config.get( 'wbmiDefaultProperties' ) || [],\n\t\t\t\tpropertyTypes = mw.config.get( 'wbmiPropertyTypes' ) || {},\n\t\t\t\tpropertyDataValuesTypes = [],\n\t\t\t\tstatementFields = {};\n\n\t\t\tthis.propertyTitles = Object.assign(\n\t\t\t\t{},\n\t\t\t\tmw.config.get( 'wbmiPropertyTitles' ) || {},\n\t\t\t\tmw.config.get( 'upwizPropertyTitles' ) || {}\n\t\t\t);\n\t\t\tthis.dateProperty = config.wikibase.properties.date || '';\n\n\t\t\tthis.$thumbnailDiv = $( '<div>' ).addClass( 'mwe-upwiz-thumbnail' );\n\n\t\t\tthis.$dataDiv = $( '<div>' ).addClass( 'mwe-upwiz-data' );\n\n\t\t\t//\n\t\t\t// Title\n\t\t\t//\n\t\t\tthis.titleDetails = new uw.TitleDetailsWidget( {\n\t\t\t\t// Normalize file extension, e.g. 'JPEG' to 'jpg'\n\t\t\t\textension: mw.Title.normalizeExtension( this.upload.title.getExtension() ),\n\t\t\t\tminLength: config.minTitleLength,\n\t\t\t\tmaxLength: config.maxTitleLength\n\t\t\t} );\n\t\t\tthis.titleDetails.on( 'change', () => this.emit( 'change' ) );\n\t\t\tthis.titleDetailsField = new uw.FieldLayout( this.titleDetails, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-title' ).text(),\n\t\t\t\trequired: true\n\t\t\t} );\n\t\t\tthis.mainFields.push( this.titleDetailsField );\n\n\t\t\t//\n\t\t\t// Captions\n\t\t\t//\n\t\t\tthis.captionsDetails = new uw.MultipleLanguageInputWidget( {\n\t\t\t\tinputWidgetConstructor: OO.ui.TextInputWidget.bind( null, {\n\t\t\t\t\tclasses: [ 'mwe-upwiz-singleLanguageInputWidget-text' ]\n\t\t\t\t} ),\n\t\t\t\trequired: true,\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-caption-add' ),\n\t\t\t\terrorBlank: mw.message( 'mwe-upwiz-error-caption-blank' ),\n\t\t\t\tremove: mw.message( 'mwe-upwiz-remove-caption' ),\n\t\t\t\tminLength: config.minCaptionLength,\n\t\t\t\tmaxLength: config.maxCaptionLength\n\t\t\t} );\n\t\t\tthis.captionsDetails.on( 'change', () => this.emit( 'change' ) );\n\t\t\tthis.captionsDetailsField = new uw.FieldLayout( this.captionsDetails, {\n\t\t\t\trequired: true,\n\t\t\t\tclasses: [ 'mwe-upwiz-caption' ],\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-caption' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-caption' ).text()\n\t\t\t} );\n\t\t\tif ( captionsAvailable ) {\n\t\t\t\tthis.mainFields.push( this.captionsDetailsField );\n\t\t\t}\n\n\t\t\t//\n\t\t\t// Descriptions\n\t\t\t//\n\t\t\t// Description is not required if a campaign provides alternative wikitext fields,\n\t\t\t// which are assumed to function like a description\n\t\t\tconst descriptionRequired = !(\n\t\t\t\tconfig.fields &&\n\t\t\t\tconfig.fields.length &&\n\t\t\t\tconfig.fields[ 0 ].wikitext\n\t\t\t);\n\t\t\t// Main widget\n\t\t\tthis.descriptionsDetails = new uw.MultipleLanguageInputWidget( {\n\t\t\t\t// if captions are available then the default is to copy them to descriptions,\n\t\t\t\t// so the descriptions field itself is not required\n\t\t\t\trequired: descriptionRequired && !captionsAvailable,\n\t\t\t\tclasses: [ 'mwe-upwiz-caption' ],\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-desc-add' ),\n\t\t\t\terrorBlank: mw.message( 'mwe-upwiz-error-description-blank' ),\n\t\t\t\tremove: mw.message( 'mwe-upwiz-remove-description' ),\n\t\t\t\tminLength: config.minDescriptionLength,\n\t\t\t\tmaxLength: config.maxDescriptionLength\n\t\t\t} );\n\t\t\tthis.descriptionsDetails.on( 'change', () => this.emit( 'change' ) );\n\n\t\t\t// Checkbox telling whether descriptions must be identical to captions.\n\t\t\t// If selected, hide descriptions. This is the default behavior.\n\t\t\tthis.descriptionSameAsCaptionCheckbox = new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-description-same-as-caption' ).text(),\n\t\t\t\t// set it as selected only when we have captions in the first place,\n\t\t\t\t// otherwise there will be nothing to copy from\n\t\t\t\t// note that in such case, this checkbox should not be displayed,\n\t\t\t\t// but we may still check its value when extracting data\n\t\t\t\tselected: captionsAvailable\n\t\t\t} );\n\t\t\tthis.descriptionSameAsCaption = new OO.ui.CheckboxMultiselectWidget( {\n\t\t\t\tclasses: [ 'mwe-upwiz-description-same-as-caption-checkbox' ],\n\t\t\t\titems: [ this.descriptionSameAsCaptionCheckbox ]\n\t\t\t} );\n\t\t\tthis.descriptionSameAsCaptionCheckbox.on( 'change', () => {\n\t\t\t\tthis.descriptionsDetails.$element.toggle(\n\t\t\t\t\t!this.descriptionSameAsCaptionCheckbox.isSelected()\n\t\t\t\t);\n\t\t\t\t// if descriptions are entered separately rather than being copied\n\t\t\t\t// from captions, they become required (unless they are not, e.g.\n\t\t\t\t// when a campaign provides alternatives) & captions turn optional\n\t\t\t\tthis.descriptionsDetails.setRequired( descriptionRequired && !this.descriptionSameAsCaptionCheckbox.isSelected() );\n\t\t\t\tthis.captionsDetails.setRequired( this.descriptionSameAsCaptionCheckbox.isSelected() );\n\t\t\t\tthis.emit( 'change' );\n\t\t\t} );\n\n\t\t\t// Descriptions are fickle; they are required (unless, as described earlier,\n\t\t\t// a campaign provides alternatives), but are not necessarily visible:\n\t\t\t// they default to being hidden and automatically being copied over from\n\t\t\t// captions. Unless captions aren't even available, in which case they\n\t\t\t// need to be on display after all...\n\t\t\t// uw.FieldLayout doesn't currently lend itself to having additional content\n\t\t\t// between the title and the validated element (descriptionsDetails in this\n\t\t\t// case), and I'd rather avoid reaching into descriptionsDetails to\n\t\t\t// conditionally insert the \"copy\" nodes in the right place.\n\t\t\t// We also can't stick the title to the \"copy\" field, because that's not\n\t\t\t// even guaranteed to be something that is supported.\n\t\t\t// Best I can think of would be to combine both of these in another,\n\t\t\t// separate widget; there's a little complication in forwarding the error\n\t\t\t// handling between uw.FieldLayout (or rather, uw.ValidationMessageElement)\n\t\t\t// and the actual widget (descriptionsDetails), but I guess that's what\n\t\t\t// this comment is for!\n\t\t\tthis.descriptionsWidget = new OO.ui.Widget();\n\t\t\tthis.descriptionsWidget.$element.append(\n\t\t\t\t// only show checkbox to copy from captions if captions are enabled)\n\t\t\t\tcaptionsAvailable ? this.descriptionSameAsCaption.$element : null,\n\t\t\t\t// toggle visibility of descriptions based on availability of captions\n\t\t\t\tthis.descriptionsDetails.$element.toggle( !( captionsAvailable ) )\n\t\t\t);\n\t\t\t// if something changes within this widget, then let this widget\n\t\t\t// itself propagate the change event, to trigger input validation\n\t\t\t// that is managed by uw.FieldLayout (or rather, uw.ValidationMessageElement)\n\t\t\tthis.descriptionSameAsCaption.connect( this.descriptionsWidget, { change: [ 'emit', 'change' ] } );\n\t\t\tthis.descriptionsDetails.connect( this.descriptionsWidget, { change: [ 'emit', 'change' ] } );\n\t\t\t// forward validation checks between the combined widget & descriptionsDetails\n\t\t\tthis.descriptionsWidget.validate = ( thorough ) => this.descriptionsDetails.validate( thorough );\n\n\t\t\tthis.descriptionsDetailsField = new uw.FieldLayout( this.descriptionsWidget, {\n\t\t\t\trequired: descriptionRequired,\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-desc' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-description' ).text()\n\t\t\t} );\n\t\t\tthis.mainFields.push( this.descriptionsDetailsField );\n\n\t\t\t//\n\t\t\t// Date\n\t\t\t//\n\t\t\tthis.dateDetails = new uw.DateDetailsWidget( { upload: this.upload } );\n\t\t\tthis.dateDetails.on( 'change', () => this.emit( 'change' ) );\n\t\t\tthis.dateDetailsField = new uw.FieldLayout( this.dateDetails, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-date-created' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-date' ).text(),\n\t\t\t\trequired: true\n\t\t\t} );\n\t\t\t// The date isn't prefilled anymore if the user changed its value\n\t\t\tthis.dateDetails.on( 'change', () => this.dateDetails.setPrefilled( false ) );\n\t\t\tthis.mainFields.push( this.dateDetailsField );\n\n\t\t\t//\n\t\t\t// Additional information\n\t\t\t//\n\t\t\t// This is a field set: fields will be added later\n\t\t\tthis.additionalInfoFieldset = new OO.ui.FieldsetLayout( {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-additional-info' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-additional-info' ).text(),\n\t\t\t\thelpInline: true,\n\t\t\t\tclasses: [ 'mwe-upwiz-fieldsetLayout' ]\n\t\t\t} );\n\n\t\t\t//\n\t\t\t// TODO improve location: https://phabricator.wikimedia.org/T361052\n\t\t\t//\n\t\t\tthis.locationInput = new uw.LocationDetailsWidget( {\n\t\t\t\ttemplateName: 'Location', // {{Location}}\n\t\t\t\tlatitudeKey: 'latitude',\n\t\t\t\tlongitudeKey: 'longitude',\n\t\t\t\theadingKey: 'heading'\n\t\t\t} );\n\t\t\tthis.locationInput.on( 'change', () => this.emit( 'change' ) );\n\t\t\tthis.locationInputField = new uw.FieldLayout( this.locationInput, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-location' ).text(),\n\t\t\t\tclasses: [ 'mwe-upwiz-fieldLayout-additional-info' ]\n\t\t\t} );\n\t\t\tthis.objectLocationInput = new uw.LocationDetailsWidget( {\n\t\t\t\ttemplateName: 'Object location', // {{Object location}}\n\t\t\t\tlatitudeKey: 'objectLatitude',\n\t\t\t\tlongitudeKey: 'objectLongitude',\n\t\t\t\theadingKey: ''\n\t\t\t} );\n\t\t\tthis.objectLocationInputField = new uw.FieldLayout( this.objectLocationInput, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-location-object' ).text(),\n\t\t\t\tclasses: [ 'mwe-upwiz-fieldLayout-additional-info' ]\n\t\t\t} );\n\n\t\t\t//\n\t\t\t// Categories\n\t\t\t//\n\t\t\tthis.categoriesDetails = new uw.CategoriesDetailsWidget( {\n\t\t\t\tplaceholder: mw.message( 'mwe-upwiz-categories-placeholder' )\n\t\t\t} );\n\t\t\tthis.categoriesDetails.on( 'change', () => this.emit( 'change' ) );\n\t\t\tthis.categoriesDetailsField = new uw.FieldLayout( this.categoriesDetails, {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-categories' ).text(),\n\t\t\t\thelp: mw.message( 'mwe-upwiz-tooltip-categories-v2' ).text(),\n\t\t\t\tclasses: [ 'mwe-upwiz-fieldLayout-additional-info' ]\n\t\t\t} );\n\t\t\tif ( OO.ui.isMobile() ) {\n\t\t\t\tthis.categoriesDetails.menu.$element.on( 'scroll', () => {\n\t\t\t\t\t// hide the software keyboard, leaving more space for autocomplete menu\n\t\t\t\t\t// (note: the more obvious thing to do would be blurring the input field,\n\t\t\t\t\t// but that would also trigger this widget to automatically convert any\n\t\t\t\t\t// input into a category tag)\n\t\t\t\t\tthis.categoriesDetails.input.$input[ 0 ].inputMode = 'none';\n\t\t\t\t} );\n\t\t\t\tthis.categoriesDetails.input.$input.on( 'focus mousedown keypress', () => {\n\t\t\t\t\t// while scrolling the autocomplete results, we changed the input mode\n\t\t\t\t\t// to get rid of the software keyboard; now that the user is interacting\n\t\t\t\t\t// we need to make sure they're able to)\n\t\t\t\t\tthis.categoriesDetails.input.$input[ 0 ].inputMode = 'text';\n\t\t\t\t} );\n\t\t\t\tthis.categoriesDetails.input.$input.on( 'mousedown', () => {\n\t\t\t\t\t// mobile devices tend to auto-zoom to input when focused (for small\n\t\t\t\t\t// enough font sizes), but we'd actually prefer they don't in this case,\n\t\t\t\t\t// as we will be adding the categories selection menu to the input,\n\t\t\t\t\t// and such zoom may interfere with the user's ability to see/interact\n\t\t\t\t\t// with that\n\t\t\t\t\t// the way we're going to accomplish this is a bit of a hack: we'll\n\t\t\t\t\t// temporarily disable user-scalable in the viewport meta tag on mousedown\n\t\t\t\t\t// (at which point the auto-zoom is not yet triggered), then reinstated\n\t\t\t\t\t// the original viewport content later on in the click lifecycle, so it\n\t\t\t\t\t// once again becomes available for the users to zoom in/out themselves\n\t\t\t\t\t// if they wish\n\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\tconst $viewport = $( 'head meta[name=\"viewport\"]' );\n\t\t\t\t\tconst viewportContent = $viewport.attr( 'content' );\n\t\t\t\t\tif ( viewportContent ) {\n\t\t\t\t\t\t// keep track of original content; then quickly swap out user-scalable\n\t\t\t\t\t\t$viewport.data( 'content', viewportContent );\n\t\t\t\t\t\t$viewport.attr( 'content', viewportContent.replace( /user-scalable=(1|yes)/, 'user-scalable=0' ) );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tthis.categoriesDetails.input.$input.on( 'focus', () => {\n\t\t\t\t\t// stop existing animations & scroll categories input to top\n\t\t\t\t\t// (mobile devices tend to center the input when focused, but\n\t\t\t\t\t// since we want to add a menu to it, we'd rather have it up top\n\t\t\t\t\t// to allow for more space to show the menu\n\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t\t$( 'html, body' )\n\t\t\t\t\t\t\t.stop()\n\t\t\t\t\t\t\t.animate( {\n\t\t\t\t\t\t\t\tscrollTop: this.categoriesDetails.input.$input.eq( 0 ).offset().top - 50\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t} );\n\n\t\t\t\t\t// restore original viewport content\n\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\tconst $viewport = $( 'head meta[name=\"viewport\"]' );\n\t\t\t\t\tconst viewportContentOriginal = $viewport.data( 'content' );\n\t\t\t\t\tif ( viewportContentOriginal ) {\n\t\t\t\t\t\t$viewport.attr( 'content', viewportContentOriginal );\n\t\t\t\t\t\t$viewport.removeData( 'content' );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t//\n\t\t\t// Any other information\n\t\t\t//\n\t\t\tthis.otherDetails = new uw.OtherDetailsWidget();\n\t\t\tthis.otherDetails.on( 'change', () => this.emit( 'change' ) );\n\t\t\tthis.otherDetailsField = new uw.FieldLayout( this.otherDetails, {\n\t\t\t\tlabel: $( '<span>' ).append(\n\t\t\t\t\tnew OO.ui.IconWidget( { icon: 'expand' } ).$element,\n\t\t\t\t\tnew OO.ui.IconWidget( { icon: 'collapse' } ).$element,\n\t\t\t\t\t' ',\n\t\t\t\t\tmw.message( 'mwe-upwiz-other-v2', mw.user ).escaped()\n\t\t\t\t),\n\t\t\t\tclasses: [\n\t\t\t\t\t'mwe-upwiz-fieldLayout-additional-info',\n\t\t\t\t\t'mwe-upwiz-fieldLayout-additional-info-clickable'\n\t\t\t\t]\n\t\t\t} );\n\t\t\tthis.otherDetails.$element.makeCollapsible( {\n\t\t\t\tcollapsed: true,\n\t\t\t\t$customTogglers: this.otherDetailsField.$element.find( '.oo-ui-fieldLayout-header' )\n\t\t\t} );\n\t\t\t// Expand collapsed sections if the fields within were changed (e.g. by metadata copier)\n\t\t\tthis.otherDetails.on( 'change', () => {\n\t\t\t\tthis.otherDetails.$element.data( 'mw-collapsible' ).expand();\n\t\t\t} );\n\n\t\t\tthis.mainFields.push( this.categoriesDetailsField );\n\t\t\tthis.mainFields.push( this.locationInputField );\n\t\t\tthis.mainFields.push( this.objectLocationInputField );\n\t\t\tthis.mainFields.push( this.otherDetailsField );\n\n\t\t\t//\n\t\t\t// Structured data - Main subjects AKA depicts\n\t\t\t//\n\t\t\tthis.statementWidgets = {};\n\t\t\tif ( config.wikibase.enabled && config.wikibase.statements ) {\n\t\t\t\tObject.keys( propertyTypes ).forEach( ( propertyId ) => {\n\t\t\t\t\tpropertyDataValuesTypes[ propertyId ] = dataTypesMap[ propertyTypes[ propertyId ] ].dataValueType;\n\t\t\t\t} );\n\n\t\t\t\t( config.defaults.statements || [] ).forEach( ( data ) => {\n\t\t\t\t\tif ( !defaultProperties.includes( data.propertyId ) ) {\n\t\t\t\t\t\tdefaultProperties.push( data.propertyId );\n\t\t\t\t\t}\n\t\t\t\t\tpropertyDataValuesTypes[ data.propertyId ] = data.dataType;\n\t\t\t\t} );\n\n\t\t\t\tdefaultProperties.forEach( ( propertyId ) => {\n\t\t\t\t\t// only wikibase-entityid types are supported\n\t\t\t\t\tif ( propertyDataValuesTypes[ propertyId ] !== 'wikibase-entityid' ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst widget = this.createStatementWidget( propertyId );\n\t\t\t\t\twidget.input.input.lookupMenu.$element.addClass( 'mwe-upwiz-statements-menu' );\n\t\t\t\t\twidget.on( 'change', () => this.emit( 'change' ) );\n\t\t\t\t\tif ( OO.ui.isMobile() ) {\n\t\t\t\t\t\twidget.input.input.lookupMenu.$element.on( 'scroll', () => {\n\t\t\t\t\t\t\t// hide the software keyboard, leaving more space for autocomplete menu\n\t\t\t\t\t\t\t// (note: the more obvious thing to do would be blurring the input field,\n\t\t\t\t\t\t\t// but that would also trigger this widget to hide the menu)\n\t\t\t\t\t\t\twidget.input.input.$input[ 0 ].inputMode = 'none';\n\t\t\t\t\t\t} );\n\t\t\t\t\t\twidget.input.input.$input.on( 'focus mousedown keypress', () => {\n\t\t\t\t\t\t\t// while scrolling the autocomplete results, we changed the input mode\n\t\t\t\t\t\t\t// to get rid of the software keyboard; now that the user is interacting\n\t\t\t\t\t\t\t// we need to make sure they're able to)\n\t\t\t\t\t\t\twidget.input.input.$input[ 0 ].inputMode = 'text';\n\t\t\t\t\t\t} );\n\t\t\t\t\t\twidget.input.input.$input.on( 'mousedown', () => {\n\t\t\t\t\t\t\t// mobile devices tend to auto-zoom to input when focused (for small\n\t\t\t\t\t\t\t// enough font sizes), but we'd actually prefer they don't in this case,\n\t\t\t\t\t\t\t// as we will be adding the statement selection menu to the input,\n\t\t\t\t\t\t\t// and such zoom may interfere with the user's ability to see/interact\n\t\t\t\t\t\t\t// with that\n\t\t\t\t\t\t\t// the way we're going to accomplish this is a bit of a hack: we'll\n\t\t\t\t\t\t\t// temporarily disable user-scalable in the viewport meta tag on mousedown\n\t\t\t\t\t\t\t// (at which point the auto-zoom is not yet triggered), then reinstated\n\t\t\t\t\t\t\t// the original viewport content later on in the click lifecycle, so it\n\t\t\t\t\t\t\t// once again becomes available for the users to zoom in/out themselves\n\t\t\t\t\t\t\t// if they wish\n\t\t\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t\t\tconst $viewport = $( 'head meta[name=\"viewport\"]' );\n\t\t\t\t\t\t\tconst viewportContent = $viewport.attr( 'content' );\n\t\t\t\t\t\t\tif ( viewportContent ) {\n\t\t\t\t\t\t\t\t// keep track of original content; then quickly swap out user-scalable\n\t\t\t\t\t\t\t\t$viewport.data( 'content', viewportContent );\n\t\t\t\t\t\t\t\t$viewport.attr( 'content', viewportContent.replace( /user-scalable=(1|yes)/, 'user-scalable=0' ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t\twidget.input.input.$input.on( 'focus', () => {\n\t\t\t\t\t\t\t// stop existing animations & scroll statement input to top\n\t\t\t\t\t\t\t// (mobile devices tend to center the input when focused, but\n\t\t\t\t\t\t\t// since we want to add a menu to it, we'd rather have it up top\n\t\t\t\t\t\t\t// to allow for more space to show the menu\n\t\t\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t\t\t\t$( 'html, body' )\n\t\t\t\t\t\t\t\t\t.stop()\n\t\t\t\t\t\t\t\t\t.animate( {\n\t\t\t\t\t\t\t\t\t\tscrollTop: widget.input.input.$input.eq( 0 ).offset().top - 50\n\t\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t\t// restore original viewport content\n\t\t\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t\t\tconst $viewport = $( 'head meta[name=\"viewport\"]' );\n\t\t\t\t\t\t\tconst viewportContentOriginal = $viewport.data( 'content' );\n\t\t\t\t\t\t\tif ( viewportContentOriginal ) {\n\t\t\t\t\t\t\t\t$viewport.attr( 'content', viewportContentOriginal );\n\t\t\t\t\t\t\t\t$viewport.removeData( 'content' );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\n\t\t\t\t\tstatementFields[ propertyId ] = new uw.FieldLayout( widget, {\n\t\t\t\t\t\t// unknown labels will get filled in later on\n\t\t\t\t\t\tlabel: this.propertyTitles[ propertyId ] || propertyId,\n\t\t\t\t\t\tclasses: [ 'mwe-upwiz-fieldLayout-additional-info' ]\n\t\t\t\t\t} );\n\n\t\t\t\t\tthis.additionalInfoFieldset.addItems( [ statementFields[ propertyId ] ] );\n\t\t\t\t\tthis.statementWidgets[ propertyId ] = widget;\n\t\t\t\t\tthis.mainFields.push( statementFields[ propertyId ] );\n\n\t\t\t\t\t// properties without a specified title default to their property id,\n\t\t\t\t\t// but we'll grab the property label from Wikibase and update the\n\t\t\t\t\t// field's label once we have it\n\t\t\t\t\tif ( !( propertyId in this.propertyTitles ) ) {\n\t\t\t\t\t\tthis.getPropertyLabel( propertyId ).then( ( text ) => {\n\t\t\t\t\t\t\tstatementFields[ propertyId ].setLabel( text );\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tthis.additionalInfoFieldset.addItems(\n\t\t\t\t[\n\t\t\t\t\tthis.categoriesDetailsField,\n\t\t\t\t\tthis.locationInputField,\n\t\t\t\t\tthis.objectLocationInputField,\n\t\t\t\t\tthis.otherDetailsField\n\t\t\t\t]\n\t\t\t);\n\n\t\t\tthis.$form = $( '<form id=\"mwe-upwiz-detailsform' + this.upload.index + '\"></form>' ).addClass( 'detailsForm' );\n\t\t\tthis.$form.append(\n\t\t\t\tthis.titleDetailsField.$element,\n\t\t\t\tcaptionsAvailable ? this.captionsDetailsField.$element : null,\n\t\t\t\tthis.descriptionsDetailsField.$element,\n\t\t\t\tthis.dateDetailsField.$element,\n\t\t\t\tthis.additionalInfoFieldset.$element\n\t\t\t);\n\n\t\t\tthis.$form.on( 'submit', ( e ) => {\n\t\t\t\t// Prevent actual form submission\n\t\t\t\te.preventDefault();\n\t\t\t} );\n\n\t\t\t//\n\t\t\t// Campaigns\n\t\t\t//\n\t\t\tthis.campaignDetailsFields = [];\n\t\t\tconfig.fields.forEach( ( field ) => {\n\t\t\t\tlet customDetails, customDetailsField;\n\n\t\t\t\tif ( field.wikitext ) {\n\t\t\t\t\tcustomDetails = new uw.CampaignDetailsWidget( field );\n\t\t\t\t\tcustomDetailsField = new uw.FieldLayout( customDetails, {\n\t\t\t\t\t\tlabel: $( $.parseHTML( field.label ) ),\n\t\t\t\t\t\trequired: !!field.required\n\t\t\t\t\t} );\n\n\t\t\t\t\tif ( field.initialValue ) {\n\t\t\t\t\t\tcustomDetails.setSerialized( { value: field.initialValue } );\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.$form.append( customDetailsField.$element );\n\t\t\t\t\tthis.campaignDetailsFields.push( customDetailsField );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\t//\n\t\t\t// Remove upload button\n\t\t\t//\n\t\t\tthis.removeCtrl = new OO.ui.ButtonWidget( {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-remove' ).text(),\n\t\t\t\ttitle: mw.message( 'mwe-upwiz-remove-upload' ).text(),\n\t\t\t\tclasses: [ 'mwe-upwiz-remove-upload' ],\n\t\t\t\tflags: 'destructive',\n\t\t\t\ticon: 'trash',\n\t\t\t\tframed: false\n\t\t\t} ).on( 'click', () => {\n\t\t\t\tOO.ui.confirm( mw.message( 'mwe-upwiz-license-confirm-remove' ).text(), {\n\t\t\t\t\ttitle: mw.message( 'mwe-upwiz-license-confirm-remove-title' ).text()\n\t\t\t\t} ).done( ( confirmed ) => {\n\t\t\t\t\tif ( confirmed ) {\n\t\t\t\t\t\tthis.upload.emit( 'remove-upload' );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\tthis.$thumbnailDiv.append( this.removeCtrl.$element );\n\n\t\t\tthis.statusMessage = new OO.ui.MessageWidget( { inline: true } );\n\t\t\tthis.statusMessage.toggle( false );\n\t\t\tthis.$spinner = $.createSpinner( { size: 'small', type: 'inline' } );\n\t\t\tthis.$spinner.hide();\n\t\t\tthis.$indicator = $( '<div>' ).addClass( 'mwe-upwiz-file-indicator' ).append(\n\t\t\t\tthis.$spinner,\n\t\t\t\tthis.statusMessage.$element\n\t\t\t);\n\n\t\t\tthis.$submittingDiv = $( '<div>' ).addClass( 'mwe-upwiz-submitting' )\n\t\t\t\t.append(\n\t\t\t\t\tthis.$indicator,\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-details-texts' ).append(\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-visible-file-filename-text' ),\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-status-line' )\n\t\t\t\t\t)\n\t\t\t\t);\n\n\t\t\tthis.$dataDiv.append(\n\t\t\t\tthis.$form,\n\t\t\t\tthis.$submittingDiv\n\t\t\t).morphCrossfader();\n\n\t\t\tthis.$div.append(\n\t\t\t\tthis.$thumbnailDiv,\n\t\t\t\tthis.$dataDiv\n\t\t\t);\n\n\t\t\tconst searchParams = new URLSearchParams( location.search );\n\t\t\tconst captionlang = searchParams.get( 'captionlang' );\n\t\t\tif ( config.defaults.caption || captionlang ) {\n\t\t\t\tthis.captionsDetails.setSerialized( {\n\t\t\t\t\tinputs: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: config.defaults.caption || ''\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t} );\n\t\t\t\tthis.captionsDetails.getItems()[ 0 ].fieldWidget.setLanguage(\n\t\t\t\t\tcaptionlang ?\n\t\t\t\t\t\tthis.captionsDetails.getItems()[ 0 ].fieldWidget.getClosestAllowedLanguage( captionlang ) :\n\t\t\t\t\t\tthis.captionsDetails.getItems()[ 0 ].fieldWidget.getDefaultLanguage()\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst descriptionlang = searchParams.get( 'descriptionlang' );\n\t\t\tif ( config.defaults.description || descriptionlang ) {\n\t\t\t\tthis.descriptionSameAsCaptionCheckbox.setSelected( false );\n\t\t\t\tthis.descriptionsDetails.setSerialized( {\n\t\t\t\t\tinputs: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: config.defaults.description || ''\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t} );\n\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].fieldWidget.setLanguage(\n\t\t\t\t\tdescriptionlang ?\n\t\t\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].fieldWidget.getClosestAllowedLanguage( descriptionlang ) :\n\t\t\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].fieldWidget.getDefaultLanguage()\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.populate();\n\n\t\t\tthis.interfaceBuilt = true;\n\n\t\t\tif ( this.savedSerialData ) {\n\t\t\t\tthis.setSerialized( this.savedSerialData );\n\t\t\t\tthis.savedSerialData = undefined;\n\t\t\t}\n\t\t},\n\n\t\tcreateStatementWidget: function ( propertyId, dataType, data ) {\n\t\t\tconst propertyPlaceholders = mw.config.get( 'upwizPropertyPlaceholders' ) || {};\n\n\t\t\treturn new uw.StatementWidget( {\n\t\t\t\tpropertyId: propertyId,\n\t\t\t\ttype: dataType,\n\t\t\t\tclasses: [ 'wbmi-statement-input' ],\n\t\t\t\tdata: data,\n\t\t\t\tplaceholder: propertyId in propertyPlaceholders ? propertyPlaceholders[ propertyId ] : ''\n\t\t\t} );\n\t\t},\n\n\t\tgetStatementProperties: function () {\n\t\t\tconst properties = [];\n\t\t\tfor ( const propertyId in this.statementWidgets ) {\n\t\t\t\tproperties.push( {\n\t\t\t\t\tid: propertyId,\n\t\t\t\t\tlabel: this.propertyTitles[ propertyId ]\n\t\t\t\t} );\n\t\t\t}\n\t\t\treturn properties;\n\t\t},\n\n\t\tgetPropertyLabel: function ( propertyId ) {\n\t\t\tconst FormatValueElement = mw.loader.require( 'wikibase.mediainfo.base' ).FormatValueElement,\n\t\t\t\tformatValueElement = new FormatValueElement(),\n\t\t\t\tdatamodel = require( 'wikibase.datamodel' );\n\n\t\t\t// Format the label & capitalize\n\t\t\treturn formatValueElement.formatValue(\n\t\t\t\tnew datamodel.EntityId( propertyId ),\n\t\t\t\t'text/plain'\n\t\t\t).then( ( text ) => text.charAt( 0 ).toUpperCase() + text.slice( 1 ) );\n\t\t},\n\n\t\t/*\n\t\t * Append the div for this details object to the DOM.\n\t\t * We need to ensure that we add divs in the right order\n\t\t * (the order in which the user selected files).\n\t\t *\n\t\t * Will only append once.\n\t\t */\n\t\tattach: function () {\n\t\t\tconst $window = $( window );\n\n\t\t\tconst maybeBuild = () => {\n\t\t\t\tif ( !this.interfaceBuilt && $window.scrollTop() + $window.height() + 1000 >= this.$div.offset().top ) {\n\t\t\t\t\tthis.buildInterface();\n\t\t\t\t\t$window.off( 'scroll', maybeBuild );\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tif ( !this.isAttached ) {\n\t\t\t\tthis.$containerDiv.append( this.$div );\n\n\t\t\t\tif ( $window.scrollTop() + $window.height() + 1000 >= this.$div.offset().top ) {\n\t\t\t\t\tthis.buildInterface();\n\t\t\t\t} else {\n\t\t\t\t\t$window.on( 'scroll', maybeBuild );\n\t\t\t\t}\n\n\t\t\t\tthis.isAttached = true;\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Get file page title for this upload.\n\t\t *\n\t\t * @return {mw.Title|null}\n\t\t */\n\t\tgetTitle: function () {\n\t\t\t// title will not be set until we've actually submitted the file\n\t\t\tif ( this.title === undefined ) {\n\t\t\t\treturn this.titleDetails.getTitle();\n\t\t\t}\n\n\t\t\t// once the file has been submitted, we'll have confirmation on\n\t\t\t// the filename and trust the authoritative source over own input\n\t\t\treturn this.title;\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t *\n\t\t * @return {uw.FieldLayout[]}\n\t\t */\n\t\tgetAllFields: function () {\n\t\t\treturn [].concat(\n\t\t\t\tthis.mainFields,\n\t\t\t\tthis.upload.deedChooser.deed ? this.upload.deedChooser.deed.getFields() : [],\n\t\t\t\tthis.campaignDetailsFields\n\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Check all the fields for validity.\n\t\t *\n\t\t * @param thorough\n\t\t * @return {jQuery.Promise<mw.uploadWizard.ValidationStatus>}\n\t\t */\n\t\tvalidate: function ( thorough ) {\n\t\t\tconst fieldPromises = this.getAllFields()\n\t\t\t\t.filter( ( fieldLayout ) => !!fieldLayout.fieldWidget.validate )\n\t\t\t\t.map( ( fieldLayout ) => fieldLayout.fieldWidget.validate( thorough ) );\n\n\t\t\treturn mw.uploadWizard.ValidationStatus.mergePromises( ...fieldPromises );\n\t\t},\n\n\t\t/**\n\t\t * Get a thumbnail caption for this upload (basically, the first caption).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tgetThumbnailCaption: function () {\n\t\t\tlet captions = [];\n\t\t\tif ( mw.UploadWizard.config.wikibase.enabled && mw.UploadWizard.config.wikibase.captions ) {\n\t\t\t\tcaptions = this.captionsDetails.getSerialized().inputs;\n\t\t\t} else {\n\t\t\t\tcaptions = this.descriptionsDetails.getSerialized().inputs;\n\t\t\t}\n\n\t\t\tif ( captions.length > 0 ) {\n\t\t\t\treturn mw.Escaper.escapeForTemplate( captions[ 0 ].text.trim() );\n\t\t\t} else {\n\t\t\t\treturn '';\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Pull some info into the form ( for instance, extracted from EXIF, desired filename )\n\t\t */\n\t\tpopulate: function () {\n\t\t\tconst $thumbnailDiv = this.$thumbnailDiv;\n\t\t\t// This must match the CSS dimensions of .mwe-upwiz-thumbnail\n\t\t\tthis.upload.getThumbnail( 230 ).done( ( thumb ) => {\n\t\t\t\tmw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );\n\t\t\t} );\n\t\t\tthis.prefillDate();\n\t\t\tthis.prefillTitle();\n\t\t\tthis.prefillDescription();\n\t\t\tthis.prefillLocation();\n\t\t},\n\n\t\t/**\n\t\t * Check if we got an EXIF date back and enter it into the details\n\t\t * XXX We ought to be using date + time here...\n\t\t * EXIF examples tend to be in ISO 8601, but the separators are sometimes things like colons, and they have lots of trailing info\n\t\t * (which we should actually be using, such as time and timezone)\n\t\t */\n\t\tprefillDate: function () {\n\t\t\tconst yyyyMmDdRegex = /^(\\d\\d\\d\\d)[:/-](\\d\\d)[:/-](\\d\\d)\\D.*/,\n\t\t\t\ttimeRegex = /\\D(\\d\\d):(\\d\\d):(\\d\\d)/;\n\n\t\t\t// XXX surely we have this function somewhere already\n\t\t\tfunction pad( n ) {\n\t\t\t\treturn ( n < 10 ? '0' : '' ) + String( n );\n\t\t\t}\n\n\t\t\tfunction getSensibleTime( date ) {\n\t\t\t\tlet str = '';\n\n\t\t\t\tstr += pad( date.getHours() ) + ':';\n\t\t\t\tstr += pad( date.getMinutes() ) + ':';\n\t\t\t\tstr += pad( date.getSeconds() );\n\n\t\t\t\treturn str;\n\t\t\t}\n\n\t\t\t// If not own work, don't prefill\n\t\t\tif ( this.upload.deedChooser.deed.name === 'thirdparty' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet dateObj;\n\t\t\tif ( this.upload.imageinfo.metadata ) {\n\t\t\t\tconst metadata = this.upload.imageinfo.metadata;\n\t\t\t\t[ 'datetimeoriginal', 'datetimedigitized', 'datetime', 'date' ].some( ( propName ) => {\n\t\t\t\t\tconst dateInfo = metadata[ propName ];\n\t\t\t\t\tif ( dateInfo ) {\n\t\t\t\t\t\tconst matches = dateInfo.trim().match( yyyyMmDdRegex );\n\t\t\t\t\t\tif ( matches ) {\n\t\t\t\t\t\t\tconst timeMatches = dateInfo.trim().match( timeRegex );\n\t\t\t\t\t\t\tif ( timeMatches ) {\n\t\t\t\t\t\t\t\tdateObj = new Date( parseInt( matches[ 1 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( matches[ 2 ], 10 ) - 1,\n\t\t\t\t\t\t\t\t\tparseInt( matches[ 3 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( timeMatches[ 1 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( timeMatches[ 2 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( timeMatches[ 3 ], 10 ) );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdateObj = new Date( parseInt( matches[ 1 ], 10 ),\n\t\t\t\t\t\t\t\t\tparseInt( matches[ 2 ], 10 ) - 1,\n\t\t\t\t\t\t\t\t\tparseInt( matches[ 3 ], 10 ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true; // break from Array.some\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// If we don't have EXIF lets try other sources - Flickr\n\t\t\tif ( dateObj === undefined && this.upload.file !== undefined && this.upload.file.date !== undefined ) {\n\t\t\t\tconst dateTimeRegex = /^\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d/;\n\t\t\t\tconst matches = this.upload.file.date.match( dateTimeRegex );\n\t\t\t\tif ( matches ) {\n\t\t\t\t\tthis.dateDetails.setSerialized( {\n\t\t\t\t\t\tprefilled: true,\n\t\t\t\t\t\tvalue: this.upload.file.date\n\t\t\t\t\t} );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if we don't have EXIF or other metadata, just don't put a date in.\n\t\t\t// XXX if we have FileAPI, it might be clever to look at file attrs, saved\n\t\t\t// in the upload object for use here later, perhaps\n\t\t\tif ( dateObj === undefined ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet dateStr = dateObj.getFullYear() + '-' + pad( dateObj.getMonth() + 1 ) + '-' + pad( dateObj.getDate() );\n\n\t\t\t// Add the time\n\t\t\t// If the date but not the time is set in EXIF data, we'll get a bogus\n\t\t\t// time value of '00:00:00'.\n\t\t\t// FIXME: Check for missing time value earlier rather than blacklisting\n\t\t\t// a potentially legitimate time value.\n\t\t\tconst sensibleTime = getSensibleTime( dateObj );\n\t\t\tif ( sensibleTime !== '00:00:00' ) {\n\t\t\t\tdateStr += ' ' + sensibleTime;\n\t\t\t}\n\n\t\t\t// ok by now we should definitely have a dateObj and a date string\n\t\t\tthis.dateDetails.setSerialized( {\n\t\t\t\tprefilled: true,\n\t\t\t\tvalue: dateStr\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Set the title of the thing we just uploaded, visibly\n\t\t */\n\t\tprefillTitle: function () {\n\t\t\tthis.titleDetails.setSerialized( {\n\t\t\t\ttitle: this.upload.title.getNameText()\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Prefill the image description if we have a description\n\t\t *\n\t\t * Note that this is not related to specifying the description from the query\n\t\t * string (that happens earlier). This is for when we have retrieved a\n\t\t * description from an upload_by_url upload (e.g. Flickr transfer)\n\t\t * or from the metadata.\n\t\t */\n\t\tprefillDescription: function () {\n\t\t\tif (\n\t\t\t\tthis.descriptionsDetails.getWikiText() === '' &&\n\t\t\t\tthis.upload.file !== undefined\n\t\t\t) {\n\t\t\t\tconst m = this.upload.imageinfo.metadata;\n\t\t\t\tlet descText = this.upload.file.description ||\n\t\t\t\t\t( m && m.imagedescription && m.imagedescription[ 0 ] && m.imagedescription[ 0 ].value );\n\n\t\t\t\tif ( descText ) {\n\t\t\t\t\t// strip out any HTML tags\n\t\t\t\t\tdescText = descText.replace( /<[^>]+>/g, '' );\n\t\t\t\t\t// & and \" are escaped by Flickr, so we need to unescape\n\t\t\t\t\tdescText = descText.replace( /&/g, '&' ).replace( /"/g, '\"' );\n\n\t\t\t\t\tthis.descriptionSameAsCaptionCheckbox.setSelected( false );\n\t\t\t\t\tthis.descriptionsDetails.setSerialized( {\n\t\t\t\t\t\tinputs: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttext: descText.trim()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t} );\n\t\t\t\t\t// The language is probably wrong in many cases...\n\t\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].fieldWidget.setLanguage(\n\t\t\t\t\t\tthis.descriptionsDetails.getItems()[ 0 ].fieldWidget.getClosestAllowedLanguage( mw.config.get( 'wgContentLanguage' ) )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Prefill location input from image info and metadata\n\t\t *\n\t\t * As of MediaWiki 1.18, the exif parser translates the rational GPS data tagged by the camera\n\t\t * to decimal format. Let's just use that.\n\t\t */\n\t\tprefillLocation: function () {\n\t\t\tconst m = this.upload.imageinfo.metadata,\n\t\t\t\tvalues = {};\n\n\t\t\tif ( mw.UploadWizard.config.defaults.lat ) {\n\t\t\t\tvalues.latitude = mw.UploadWizard.config.defaults.lat;\n\t\t\t}\n\t\t\tif ( mw.UploadWizard.config.defaults.lon ) {\n\t\t\t\tvalues.longitude = mw.UploadWizard.config.defaults.lon;\n\t\t\t}\n\t\t\tif ( mw.UploadWizard.config.defaults.heading ) {\n\t\t\t\tvalues.heading = mw.UploadWizard.config.defaults.heading;\n\t\t\t}\n\n\t\t\tif ( m ) {\n\t\t\t\tlet dir = m.gpsimgdirection || m.gpsdestbearing;\n\n\t\t\t\tif ( dir ) {\n\t\t\t\t\tif ( /^\\d+\\/\\d+$/.test( dir ) ) {\n\t\t\t\t\t\t// Apparently it can take the form \"x/y\" instead of\n\t\t\t\t\t\t// a decimal value. Mighty silly, but let's save it.\n\t\t\t\t\t\tdir = dir.split( '/' );\n\t\t\t\t\t\tdir = parseInt( dir[ 0 ], 10 ) / parseInt( dir[ 1 ], 10 );\n\t\t\t\t\t}\n\n\t\t\t\t\tvalues.heading = dir;\n\t\t\t\t}\n\n\t\t\t\t// Prefill useful stuff only\n\t\t\t\tif ( Number( m.gpslatitude ) && Number( m.gpslongitude ) ) {\n\t\t\t\t\tvalues.latitude = m.gpslatitude;\n\t\t\t\t\tvalues.longitude = m.gpslongitude;\n\t\t\t\t} else if (\n\t\t\t\t\tthis.upload.file &&\n\t\t\t\t\tthis.upload.file.location &&\n\t\t\t\t\tthis.upload.file.location.latitude &&\n\t\t\t\t\tthis.upload.file.location.longitude\n\t\t\t\t) {\n\t\t\t\t\tvalues.latitude = this.upload.file.location.latitude;\n\t\t\t\t\tvalues.longitude = this.upload.file.location.longitude;\n\t\t\t\t}\n\t\t\t\tif ( Number( m.gpsdestlatitude ) && Number( m.gpsdestlongitude ) ) {\n\t\t\t\t\tvalues.objectLatitude = m.gpsdestlatitude;\n\t\t\t\t\tvalues.objectLongitude = m.gpsdestlongitude;\n\t\t\t\t} else if (\n\t\t\t\t\tthis.upload.file &&\n\t\t\t\t\tthis.upload.file.objectLocation &&\n\t\t\t\t\tthis.upload.file.objectLocation.objectLatitude &&\n\t\t\t\t\tthis.upload.file.objectLocation.objectLongitude\n\t\t\t\t) {\n\t\t\t\t\tvalues.objectLatitude = this.upload.file.objectLocation.objectLatitude;\n\t\t\t\t\tvalues.objectLongitude = this.upload.file.objectLocation.objectLongitude;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.locationInput.setSerialized( values );\n\t\t\tthis.objectLocationInput.setSerialized( values );\n\t\t\tthis.objectLocationInputField.$element.toggle( Boolean( values.objectLatitude && values.objectLongitude ) );\n\t\t},\n\n\t\t/**\n\t\t * Get a machine-readable representation of the current state of the upload details. It can be\n\t\t * passed to #setSerialized to restore this state (or to set it for another instance of the same\n\t\t * class).\n\t\t *\n\t\t * Note that this doesn't include custom deed's state.\n\t\t *\n\t\t * @return {Object.<string,Object>}\n\t\t */\n\t\tgetSerialized: function () {\n\t\t\tif ( !this.interfaceBuilt ) {\n\t\t\t\t// We don't have the interface yet, but it'll get filled out as\n\t\t\t\t// needed.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttitle: this.titleDetails.getSerialized(),\n\t\t\t\tcaption: this.captionsDetails.getSerialized(),\n\t\t\t\tdescription: this.descriptionSameAsCaptionCheckbox.isSelected() ? undefined : this.descriptionsDetails.getSerialized(),\n\t\t\t\tdate: this.dateDetails.getSerialized(),\n\t\t\t\tcategories: this.categoriesDetails.getSerialized(),\n\t\t\t\tstatements: this.serializeStatements(),\n\t\t\t\tlocation: this.locationInput.getSerialized(),\n\t\t\t\tobjectLocation: this.objectLocationInput.getSerialized(),\n\t\t\t\tother: this.otherDetails.getSerialized(),\n\t\t\t\tcampaigns: this.campaignDetailsFields.map( ( field ) => field.fieldWidget.getSerialized() )\n\t\t\t};\n\t\t},\n\n\t\tserializeStatements: function () {\n\t\t\tconst serialized = {};\n\t\t\tfor ( const propertyId in this.statementWidgets ) {\n\t\t\t\tserialized[ propertyId ] = this.statementWidgets[ propertyId ].getStatementList();\n\t\t\t}\n\t\t\treturn serialized;\n\t\t},\n\n\t\tsetStatementsFromSerialized: function ( serialized ) {\n\t\t\tfor ( const propertyId in serialized ) {\n\t\t\t\tthis.statementWidgets[ propertyId ].resetData( serialized[ propertyId ] );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Set the state of this widget from machine-readable representation, as returned by\n\t\t * #getSerialized.\n\t\t *\n\t\t * Fields from the representation can be omitted to keep the current value.\n\t\t *\n\t\t * @param {Object.<string,Object>} [serialized]\n\t\t */\n\t\tsetSerialized: function ( serialized ) {\n\t\t\tlet i;\n\n\t\t\tif ( !this.interfaceBuilt ) {\n\t\t\t\t// There's no interface yet! Don't load the data, just keep it\n\t\t\t\t// around.\n\t\t\t\tif ( serialized === undefined ) {\n\t\t\t\t\t// Note: This will happen if we \"undo\" a copy operation while\n\t\t\t\t\t// some of the details interfaces aren't loaded.\n\t\t\t\t\tthis.savedSerialData = undefined;\n\t\t\t\t} else {\n\t\t\t\t\tthis.savedSerialData = $.extend( true,\n\t\t\t\t\t\tthis.savedSerialData || {},\n\t\t\t\t\t\tserialized\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( serialized === undefined ) {\n\t\t\t\t// This is meaningless if the interface is already built.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( serialized.title ) {\n\t\t\t\tthis.titleDetails.setSerialized( serialized.title );\n\t\t\t}\n\t\t\tif ( serialized.caption ) {\n\t\t\t\tthis.captionsDetails.setSerialized( serialized.caption );\n\t\t\t}\n\t\t\tif ( serialized.description ) {\n\t\t\t\tthis.descriptionsDetails.setSerialized( serialized.description );\n\t\t\t\tthis.descriptionSameAsCaptionCheckbox.setSelected( false );\n\t\t\t}\n\t\t\tif ( serialized.date ) {\n\t\t\t\tthis.dateDetails.setSerialized( serialized.date );\n\t\t\t}\n\t\t\tif ( serialized.categories ) {\n\t\t\t\tthis.categoriesDetails.setSerialized( serialized.categories );\n\t\t\t}\n\t\t\tif ( serialized.statements ) {\n\t\t\t\tthis.setStatementsFromSerialized( serialized.statements );\n\t\t\t}\n\t\t\tif ( serialized.location ) {\n\t\t\t\tthis.locationInput.setSerialized( serialized.location );\n\t\t\t}\n\t\t\tif ( serialized.objectLocation ) {\n\t\t\t\tthis.objectLocationInput.setSerialized( serialized.objectLocation );\n\t\t\t}\n\t\t\tif ( serialized.other ) {\n\t\t\t\tthis.otherDetails.setSerialized( serialized.other );\n\t\t\t}\n\t\t\tif ( serialized.campaigns ) {\n\t\t\t\tfor ( i = 0; i < this.campaignDetailsFields.length; i++ ) {\n\t\t\t\t\tthis.campaignDetailsFields[ i ].fieldWidget.setSerialized( serialized.campaigns[ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Convert entire details for this file into wikiText, which will then be posted to the file\n\t\t *\n\t\t * This function assumes that all input is valid.\n\t\t *\n\t\t * @return {string} wikitext representing all details\n\t\t */\n\t\tgetWikiText: function () {\n\t\t\tlet wikiText = '';\n\n\t\t\t// https://commons.wikimedia.org/wiki/Template:Information\n\t\t\t// can we be more slick and do this with maps, applys, joins?\n\t\t\tconst information = {\n\t\t\t\t// {{lang|description in lang}}* (required)\n\t\t\t\tdescription: '',\n\t\t\t\t// holds {{Prompt}} template ... gets unset if it has no value\n\t\t\t\t'Other fields 1': '',\n\t\t\t\t// YYYY, YYYY-MM, or YYYY-MM-DD (required) use jquery but allow editing, then double check for sensible date.\n\t\t\t\tdate: '',\n\t\t\t\t// {{own}} or wikitext (optional)\n\t\t\t\tsource: '',\n\t\t\t\t// any wikitext, but particularly {{Creator:Name Surname}} (required)\n\t\t\t\tauthor: '',\n\t\t\t\t// leave blank unless OTRS pending; by default will be \"see below\" (optional)\n\t\t\t\tpermission: '',\n\t\t\t\t// pipe separated list, other versions (optional)\n\t\t\t\t'other versions': ''\n\t\t\t};\n\n\t\t\tif ( this.descriptionSameAsCaptionCheckbox.isSelected() ) {\n\t\t\t\tinformation.description = this.captionsDetails.getWikiText();\n\t\t\t} else {\n\t\t\t\tinformation.description = this.descriptionsDetails.getWikiText();\n\t\t\t}\n\n\t\t\tconst deed = this.upload.deedChooser.deed;\n\t\t\tif ( deed.getAiPromptWikitext() ) {\n\t\t\t\tinformation[ 'Other fields 1' ] = deed.getAiPromptWikitext();\n\t\t\t} else {\n\t\t\t\tdelete information[ 'Other fields 1' ];\n\t\t\t}\n\n\t\t\tthis.campaignDetailsFields.forEach( ( layout ) => {\n\t\t\t\tinformation.description += layout.fieldWidget.getWikiText();\n\t\t\t} );\n\n\t\t\tinformation.date = this.dateDetails.getWikiText();\n\n\t\t\tinformation.source = deed.getSourceWikiText( this.upload );\n\n\t\t\tinformation.author = deed.getAuthorWikiText( this.upload );\n\n\t\t\tlet info = '';\n\n\t\t\tfor ( const key in information ) {\n\t\t\t\tif ( Object.prototype.hasOwnProperty.call( information, key ) ) {\n\t\t\t\t\tinfo += '|' + key.replace( /:/g, '_' );\n\t\t\t\t\tinfo += '=' + mw.Escaper.escapeForTemplate( information[ key ] ) + '\\n';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twikiText += '=={{int:filedesc}}==\\n';\n\t\t\twikiText += '{{Information\\n' + info + '}}\\n';\n\n\t\t\twikiText += this.locationInput.getWikiText() + '\\n';\n\t\t\twikiText += this.objectLocationInput.getWikiText() + '\\n';\n\n\t\t\t// add an \"anything else\" template if needed\n\t\t\twikiText += this.otherDetails.getWikiText() + '\\n\\n';\n\n\t\t\t// add licensing information\n\t\t\twikiText += '\\n=={{int:license-header}}==\\n';\n\t\t\twikiText += deed.getLicenseWikiText( this.upload ) + '\\n\\n';\n\n\t\t\tif ( mw.UploadWizard.config.autoAdd.wikitext !== undefined ) {\n\t\t\t\twikiText += mw.UploadWizard.config.autoAdd.wikitext + '\\n';\n\t\t\t}\n\n\t\t\t// add parameters for list callback bot\n\t\t\t// this cue will be used to supplement a wiki page with an image thumbnail\n\t\t\tif ( $( '#imgPicker' + this.upload.index ).prop( 'checked' ) ) {\n\t\t\t\twikiText += '\\n<!-- WIKIPAGE_UPDATE_PARAMS ' +\n\t\t\t\t\tmw.UploadWizard.config.defaults.objref +\n\t\t\t\t\t' -->\\n';\n\t\t\t}\n\n\t\t\t// templates for other options\n\t\t\twikiText += deed.getTemplateOptionsWikiText() + '\\n\\n';\n\n\t\t\t// categories\n\t\t\twikiText += '\\n' + this.categoriesDetails.getWikiText();\n\n\t\t\t// sanitize wikitext if TextCleaner is defined (MediaWiki:TextCleaner.js)\n\t\t\tif ( typeof window.TextCleaner !== 'undefined' && typeof window.TextCleaner.sanitizeWikiText === 'function' ) {\n\t\t\t\twikiText = window.TextCleaner.sanitizeWikiText( wikiText, true );\n\t\t\t}\n\n\t\t\t// remove too many newlines in a row\n\t\t\twikiText = wikiText.replace( /\\n{3,}/g, '\\n\\n' );\n\n\t\t\treturn wikiText;\n\t\t},\n\n\t\t/**\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsubmit: function () {\n\t\t\tthis.$containerDiv.find( 'form' ).trigger( 'submit' );\n\n\t\t\tthis.upload.title = this.getTitle();\n\t\t\tthis.upload.state = 'submitting-details';\n\t\t\tthis.setStatus( mw.message( 'mwe-upwiz-submitting-details' ).text() );\n\t\t\tthis.showIndicator( 'progress' );\n\n\t\t\tconst wikitext = this.getWikiText();\n\t\t\tlet promise = this.submitWikiText( wikitext );\n\n\t\t\tif ( mw.UploadWizard.config.wikibase.enabled ) {\n\t\t\t\tpromise = promise\n\t\t\t\t\t.then( () => {\n\t\t\t\t\t\t// just work out the mediainfo entity id from the page id\n\t\t\t\t\t\tconst status = mw.message( 'mwe-upwiz-submitting-structured-data' );\n\t\t\t\t\t\tthis.setStatus( status.text() );\n\t\t\t\t\t\treturn this.getMediaInfoEntityId(); // (T208545)\n\t\t\t\t\t} )\n\t\t\t\t\t// submit structured data to wikibase\n\t\t\t\t\t.then( this.submitStructuredData.bind( this ) );\n\t\t\t}\n\n\t\t\treturn promise.then( () => {\n\t\t\t\t// FIXME - structuredDataSubmissionErrors gets set to true in the catch block of\n\t\t\t\t// postStructuredData which executes AFTER this, and so the error never gets\n\t\t\t\t// displayed\n\t\t\t\tif ( this.structuredDataSubmissionErrors ) {\n\t\t\t\t\tlet errorString = '<strong>' + mw.message(\n\t\t\t\t\t\t'mwe-upwiz-error-submit-structured-data'\n\t\t\t\t\t).parse() + '</strong>';\n\n\t\t\t\t\terrorString += '<strong>' + mw.message(\n\t\t\t\t\t\t'mwe-upwiz-error-submit-structured-data-remedy',\n\t\t\t\t\t\tthis.upload.imageinfo.canonicaltitle\n\t\t\t\t\t).parse() + '</strong>';\n\n\t\t\t\t\tthis.upload.state = 'sdc-api-error';\n\t\t\t\t\tthis.showError(\n\t\t\t\t\t\t'sd-fail',\n\t\t\t\t\t\terrorString\n\t\t\t\t\t);\n\t\t\t\t\t// If there is a structured data error, then details for how to deal with it are\n\t\t\t\t\t// in the errorString above, no need to show anything else\n\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t$( '#mwe-upwiz-details-warning-count' ).hide();\n\t\t\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t\t\t$( '.mwe-upwiz-remove-upload' ).hide();\n\t\t\t\t\t// Remove the beforeunload warning, as the image is now as uploaded\n\t\t\t\t\t// as it's going to get\n\t\t\t\t\t$( window ).off( 'beforeunload' );\n\t\t\t\t} else {\n\t\t\t\t\tthis.showIndicator( 'success' );\n\t\t\t\t\tthis.setStatus( mw.message( 'mwe-upwiz-published' ).text() );\n\t\t\t\t}\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tgetMediaInfoEntityId: function () {\n\t\t\tif ( this.mediaInfoEntityId !== undefined ) {\n\t\t\t\treturn $.Deferred().resolve( this.mediaInfoEntityId ).promise();\n\t\t\t}\n\n\t\t\treturn this.upload.api.get( {\n\t\t\t\taction: 'query',\n\t\t\t\tprop: 'info',\n\t\t\t\ttitles: this.getTitle().getPrefixedDb()\n\t\t\t} ).then( ( result ) => {\n\t\t\t\tlet message;\n\n\t\t\t\tif ( result.query.pages[ 0 ].missing ) {\n\t\t\t\t\t// page doesn't exist (yet)\n\t\t\t\t\tmessage = mw.message( 'mwe-upwiz-error-pageprops-missing-page' ).parse();\n\t\t\t\t\treturn $.Deferred().reject( 'pageprops-missing-page', { errors: [ { html: message } ] } ).promise();\n\t\t\t\t}\n\n\t\t\t\t// FIXME: This just fetches the pageid and then hard-codes knowing that M+pageid is what we need\n\t\t\t\tthis.mediaInfoEntityId = 'M' + result.query.pages[ 0 ].pageid;\n\t\t\t\treturn this.mediaInfoEntityId;\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Post wikitext as edited here, to the file\n\t\t *\n\t\t * This function is only called if all input seems valid (which doesn't mean that we can't get\n\t\t * an error, see #processError).\n\t\t *\n\t\t * @param {string} wikiText\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsubmitWikiText: function ( wikiText ) {\n\t\t\tconst tags = [ 'uploadwizard' ],\n\t\t\t\tdeed = this.upload.deedChooser.deed,\n\t\t\t\tconfig = mw.UploadWizard.config;\n\t\t\tlet comment = '';\n\n\t\t\tthis.firstPoll = Date.now();\n\n\t\t\tif ( this.upload.file.source ) {\n\t\t\t\ttags.push( 'uploadwizard-' + this.upload.file.source );\n\t\t\t}\n\n\t\t\tif ( deed.name === 'ownwork' ) {\n\t\t\t\t// This message does not have any parameters, so there's nothing to substitute\n\t\t\t\tcomment = config.uploadComment.ownWork;\n\t\t\t} else {\n\t\t\t\tmw.messages.set(\n\t\t\t\t\t'mwe-upwiz-upload-comment-third-party',\n\t\t\t\t\tconfig.uploadComment.thirdParty\n\t\t\t\t);\n\t\t\t\tcomment = mw.message(\n\t\t\t\t\t'mwe-upwiz-upload-comment-third-party',\n\t\t\t\t\tdeed.getAuthorWikiText(),\n\t\t\t\t\tdeed.getSourceWikiText()\n\t\t\t\t).plain();\n\t\t\t}\n\n\t\t\tconst params = {\n\t\t\t\taction: 'upload',\n\t\t\t\tfilekey: this.upload.fileKey,\n\t\t\t\tfilename: this.getTitle().getMain(),\n\t\t\t\tcomment: comment,\n\t\t\t\ttags: config.CanAddTags ? tags : [],\n\t\t\t\t// we can ignore upload warnings here, we've already checked\n\t\t\t\t// when stashing the file\n\t\t\t\t// not ignoring warnings would prevent us from uploading a file\n\t\t\t\t// that is a duplicate of something in a foreign repo\n\t\t\t\tignorewarnings: true,\n\t\t\t\ttext: wikiText\n\t\t\t};\n\n\t\t\t// Only enable async publishing if file is larger than 10MiB\n\t\t\tif ( this.upload.transportWeight > 10 * 1024 * 1024 ) {\n\t\t\t\tparams.async = true;\n\t\t\t}\n\n\t\t\treturn this.submitWikiTextInternal( params );\n\t\t},\n\n\t\t/**\n\t\t * @param {string} entityId\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsubmitStructuredData: function ( entityId ) {\n\t\t\tlet promise = $.Deferred().resolve().promise();\n\t\t\tconst config = mw.UploadWizard.config,\n\t\t\t\tdata = {},\n\t\t\t\twbDataModel = mw.loader.require( 'wikibase.datamodel' ),\n\t\t\t\twbSerialization = mw.loader.require( 'wikibase.serialization' ),\n\t\t\t\twbSerializer = new wbSerialization.StatementSerializer();\n\n\t\t\tconst labels = this.prepareLabelsData();\n\t\t\tconst statements = this.prepareStatementsData();\n\n\t\t\tif ( !config.wikibase.enabled ) {\n\t\t\t\treturn promise;\n\t\t\t}\n\n\t\t\tif ( config.wikibase.captions && Object.keys( labels ).length !== 0 ) {\n\t\t\t\tdata.labels = labels;\n\t\t\t}\n\n\t\t\tif ( config.wikibase.statements && statements.length !== 0 ) {\n\t\t\t\tdata.claims = statements;\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line no-undef\n\t\t\tif ( this.dateProperty !== '' && dataValues ) {\n\t\t\t\tpromise = promise\n\t\t\t\t\t.then( () => this.dateDetails.parseDate() )\n\t\t\t\t\t.then(\n\t\t\t\t\t\t( response ) => {\n\t\t\t\t\t\t\tconst date = response.results[ 0 ].value;\n\t\t\t\t\t\t\tconst dateStatement = wbSerializer.serialize(\n\t\t\t\t\t\t\t\tnew wbDataModel.Statement(\n\t\t\t\t\t\t\t\t\tnew wbDataModel.Claim(\n\t\t\t\t\t\t\t\t\t\tnew wbDataModel.PropertyValueSnak(\n\t\t\t\t\t\t\t\t\t\t\tthis.dateProperty,\n\t\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\t\t\t\t\t\t\t\tdataValues.TimeValue.newFromJSON( date )\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tdata.claims = data.claims ? data.claims.concat( dateStatement ) : [ dateStatement ];\n\t\t\t\t\t\t},\n\t\t\t\t\t\t( errorCode ) => {\n\t\t\t\t\t\t\tmw.log.warn(\n\t\t\t\t\t\t\t\t'uw.DateDetailsWidget::parseDate> ' +\n\t\t\t\t\t\t\t\t'Parsing into a Wikibase date failed. Reason: ' +\n\t\t\t\t\t\t\t\terrorCode\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t// Parsing failed: don't add the date statement,\n\t\t\t\t\t\t\t// but convert back to a resolved promise to keep\n\t\t\t\t\t\t\t// the chain going\n\t\t\t\t\t\t\treturn $.Deferred().resolve().promise();\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn promise.then(\n\t\t\t\t() => {\n\t\t\t\t\tif ( Object.keys( data ).length > 0 ) {\n\t\t\t\t\t\treturn this.postStructuredData( entityId, JSON.stringify( data ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\t\t},\n\n\t\tprepareLabelsData: function () {\n\t\t\tconst captions = this.captionsDetails.getValues(),\n\t\t\t\tlanguages = Object.keys( captions ),\n\t\t\t\tlabels = {};\n\t\t\tfor ( let i = 0; i < languages.length; i++ ) {\n\t\t\t\tlabels[ languages[ i ] ] = {\n\t\t\t\t\tlanguage: languages[ i ],\n\t\t\t\t\tvalue: captions[ languages[ i ] ]\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn labels;\n\t\t},\n\n\t\tprepareStatementsData: function () {\n\t\t\tlet claims = [];\n\t\t\tconst wikibaseSerialization = mw.loader.require( 'wikibase.serialization' ),\n\t\t\t\tstatementListSerializer = new wikibaseSerialization.StatementListSerializer(),\n\t\t\t\tdeed = this.upload.deedChooser.deed;\n\t\t\tfor ( const propertyId in this.statementWidgets ) {\n\t\t\t\tclaims = claims.concat(\n\t\t\t\t\tstatementListSerializer.serialize(\n\t\t\t\t\t\tthis.statementWidgets[ propertyId ].getStatementList()\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst sourceSD = deed.getStructuredDataFromSource();\n\t\t\tif ( sourceSD ) {\n\t\t\t\tclaims = claims.concat( sourceSD );\n\t\t\t}\n\t\t\treturn claims;\n\t\t},\n\n\t\t/**\n\t\t * @param {string} id\n\t\t * @param {string} data\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tpostStructuredData: function ( id, data ) {\n\t\t\tconst config = mw.UploadWizard.config,\n\t\t\t\tparams = {\n\t\t\t\t\taction: 'wbeditentity',\n\t\t\t\t\tid: id,\n\t\t\t\t\tdata: data,\n\t\t\t\t\t// baserevid is intentionally left blank: SD can be submitted\n\t\t\t\t\t// without baserevid just fine - baserevid is to prevent edit conflicts,\n\t\t\t\t\t// and this is a new upload so there should be none\n\t\t\t\t\tbaserevid: undefined\n\t\t\t\t},\n\t\t\t\tajaxOptions = { url: config.wikibase.api };\n\n\t\t\treturn this.upload.api.postWithEditToken(\n\t\t\t\tparams, ajaxOptions\n\t\t\t).catch( () => {\n\t\t\t\tthis.structuredDataSubmissionErrors = true;\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Perform the API call with given parameters (which is expected to publish this file) and\n\t\t * handle the result.\n\t\t *\n\t\t * @param {Object} params API call parameters\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsubmitWikiTextInternal: function ( params ) {\n\t\t\tconst apiPromise = this.upload.api.postWithEditToken( params );\n\n\t\t\treturn apiPromise\n\t\t\t\t// process the successful (in terms of HTTP status...) API call first:\n\t\t\t\t// there may be warnings or other issues with the upload that need\n\t\t\t\t// to be dealt with\n\t\t\t\t.then( this.validateWikiTextSubmitResult.bind( this, params ) )\n\t\t\t\t// making it here means the upload is a success, or it would've been\n\t\t\t\t// rejected by now (either by HTTP status code, or in validateWikiTextSubmitResult)\n\t\t\t\t.then( ( result ) => {\n\t\t\t\t\tthis.title = mw.Title.makeTitle( 6, result.upload.filename );\n\t\t\t\t\tthis.upload.extractImageInfo( result.upload.imageinfo );\n\t\t\t\t\tthis.upload.thisProgress = 1.0;\n\t\t\t\t\tthis.upload.state = 'complete';\n\t\t\t\t\treturn result;\n\t\t\t\t} )\n\t\t\t\t// uh-oh - something went wrong!\n\t\t\t\t.catch( ( code, result ) => {\n\t\t\t\t\tthis.upload.state = 'error';\n\t\t\t\t\tthis.processError( code, result );\n\t\t\t\t\treturn $.Deferred().reject( code, result );\n\t\t\t\t} )\n\t\t\t\t.promise( { abort: apiPromise.abort } );\n\t\t},\n\n\t\t/**\n\t\t * Validates the result of a submission & returns a resolved promise with\n\t\t * the API response if all went well, or rejects with error code & error\n\t\t * message as you would expect from failed mediawiki API calls.\n\t\t *\n\t\t * @param {Object} params What we passed to the API that caused this response.\n\t\t * @param {Object} result API result of an upload or status check.\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tvalidateWikiTextSubmitResult: function ( params, result ) {\n\t\t\tlet warnings = null;\n\t\t\tlet ignoreTheseWarnings = false;\n\t\t\tconst deferred = $.Deferred();\n\n\t\t\tif ( result && result.upload && result.upload.result === 'Poll' ) {\n\t\t\t\t// if async publishing takes longer than 10 minutes give up\n\t\t\t\tif ( ( Date.now() - this.firstPoll ) > 10 * 60 * 1000 ) {\n\t\t\t\t\treturn deferred.reject( 'server-error', { errors: [ {\n\t\t\t\t\t\tcode: 'server-error',\n\t\t\t\t\t\thtml: 'Unknown server error'\n\t\t\t\t\t} ] } );\n\t\t\t\t} else {\n\t\t\t\t\tif ( result.upload.stage === undefined ) {\n\t\t\t\t\t\treturn deferred.reject( 'no-stage', { errors: [ {\n\t\t\t\t\t\t\tcode: 'no-stage',\n\t\t\t\t\t\t\thtml: 'Unable to check file\\'s status'\n\t\t\t\t\t\t} ] } );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Messages that can be returned:\n\t\t\t\t\t\t// * mwe-upwiz-queued\n\t\t\t\t\t\t// * mwe-upwiz-publish\n\t\t\t\t\t\t// * mwe-upwiz-assembling\n\t\t\t\t\t\tthis.setStatus( mw.message( 'mwe-upwiz-' + result.upload.stage ).text() );\n\t\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\t\tif ( this.upload.state !== 'aborted' ) {\n\t\t\t\t\t\t\t\tthis.submitWikiTextInternal( {\n\t\t\t\t\t\t\t\t\taction: 'upload',\n\t\t\t\t\t\t\t\t\tcheckstatus: true,\n\t\t\t\t\t\t\t\t\tfilekey: this.upload.fileKey\n\t\t\t\t\t\t\t\t} ).then( deferred.resolve, deferred.reject );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdeferred.resolve( 'aborted' );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, 3000 );\n\n\t\t\t\t\t\treturn deferred.promise();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( result && result.upload && result.upload.warnings ) {\n\t\t\t\twarnings = result.upload.warnings;\n\t\t\t}\n\t\t\tlet existingFile;\n\t\t\tif ( warnings && warnings.exists ) {\n\t\t\t\texistingFile = warnings.exists;\n\t\t\t} else if ( warnings && warnings[ 'exists-normalized' ] ) {\n\t\t\t\texistingFile = warnings[ 'exists-normalized' ];\n\t\t\t\tconst existingFileExt = mw.Title.normalizeExtension( existingFile.split( '.' ).pop() );\n\t\t\t\tconst ourFileExt = mw.Title.normalizeExtension( this.getTitle().getExtension() );\n\n\t\t\t\tif ( existingFileExt !== ourFileExt ) {\n\t\t\t\t\tdelete warnings[ 'exists-normalized' ];\n\t\t\t\t\tignoreTheseWarnings = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( warnings && warnings[ 'was-deleted' ] ) {\n\t\t\t\tdelete warnings[ 'was-deleted' ];\n\t\t\t\tignoreTheseWarnings = true;\n\t\t\t}\n\t\t\tfor ( const wx in warnings ) {\n\t\t\t\tif ( Object.prototype.hasOwnProperty.call( warnings, wx ) ) {\n\t\t\t\t\t// if there are other warnings, deal with those first\n\t\t\t\t\tignoreTheseWarnings = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( result && result.upload && result.upload.imageinfo ) {\n\t\t\t\treturn $.Deferred().resolve( result );\n\t\t\t} else if ( ignoreTheseWarnings ) {\n\t\t\t\tparams.ignorewarnings = 1;\n\t\t\t\treturn this.submitWikiTextInternal( params );\n\t\t\t} else if ( result && result.upload && result.upload.warnings ) {\n\t\t\t\tlet code, message;\n\t\t\t\tif ( warnings.thumb || warnings[ 'thumb-name' ] ) {\n\t\t\t\t\tcode = 'error-title-thumbnail';\n\t\t\t\t\tmessage = mw.message( 'mwe-upwiz-error-title-thumbnail' ).parse();\n\t\t\t\t} else if ( warnings.badfilename ) {\n\t\t\t\t\tcode = 'title-invalid';\n\t\t\t\t\tmessage = mw.message( 'mwe-upwiz-error-title-invalid' ).parse();\n\t\t\t\t} else if ( warnings[ 'bad-prefix' ] ) {\n\t\t\t\t\tcode = 'title-senselessimagename';\n\t\t\t\t\tmessage = mw.message( 'mwe-upwiz-error-title-senselessimagename' ).parse();\n\t\t\t\t} else if ( existingFile ) {\n\t\t\t\t\tconst existingFileUrl = mw.config.get( 'wgServer' ) + mw.Title.makeTitle( NS_FILE, existingFile ).getUrl();\n\t\t\t\t\tcode = 'api-warning-exists';\n\t\t\t\t\tmessage = mw.message( 'mwe-upwiz-api-warning-exists', existingFileUrl ).parse();\n\t\t\t\t} else if ( warnings.duplicate ) {\n\t\t\t\t\tcode = 'upload-error-duplicate';\n\t\t\t\t\tmessage = mw.message( 'mwe-upwiz-upload-error-duplicate' ).parse();\n\t\t\t\t} else if ( warnings[ 'duplicate-archive' ] !== undefined ) {\n\t\t\t\t\t// warnings[ 'duplicate-archive' ] may be '' (empty string) for revdeleted files\n\t\t\t\t\tif ( this.upload.handler.isIgnoredWarning( 'duplicate-archive' ) ) {\n\t\t\t\t\t\t// We already told the interface to ignore this warning, so\n\t\t\t\t\t\t// let's steamroll over it and re-call this handler.\n\t\t\t\t\t\tparams.ignorewarnings = true;\n\t\t\t\t\t\treturn this.submitWikiTextInternal( params );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// This should _never_ happen, but just in case....\n\t\t\t\t\t\tcode = 'upload-error-duplicate-archive';\n\t\t\t\t\t\tmessage = mw.message( 'mwe-upwiz-upload-error-duplicate-archive' ).parse();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst warningsKeys = Object.keys( warnings );\n\t\t\t\t\tcode = 'unknown-warning';\n\t\t\t\t\tmessage = mw.message( 'api-error-unknown-warning', warningsKeys.join( ', ' ) ).parse();\n\t\t\t\t}\n\n\t\t\t\treturn $.Deferred().reject( code, { errors: [ { html: message } ] } );\n\t\t\t} else {\n\t\t\t\treturn $.Deferred().reject( 'this-info-missing', result );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Create a recoverable error -- show the form again, and highlight the problematic field.\n\t\t *\n\t\t * @param {string} code\n\t\t * @param {string} html Error message to show.\n\t\t */\n\t\trecoverFromError: function ( code, html ) {\n\t\t\tthis.upload.state = 'recoverable-error';\n\t\t\tthis.$dataDiv.morphCrossfade( '.detailsForm' );\n\t\t\tthis.titleDetailsField.setErrors( [ { code: code, html: html } ] );\n\t\t},\n\n\t\t/**\n\t\t * Show error state, possibly using a recoverable error form\n\t\t *\n\t\t * @param {string} code Error code\n\t\t * @param {string} html Error message\n\t\t */\n\t\tshowError: function ( code, html ) {\n\t\t\tthis.showIndicator( 'error' );\n\t\t\tthis.setStatus( Object.assign( html ) );\n\t\t},\n\n\t\t/**\n\t\t * Decide how to treat various errors\n\t\t *\n\t\t * @param {string} code Error code\n\t\t * @param {Object} result Result from ajax call\n\t\t */\n\t\tprocessError: function ( code, result ) {\n\t\t\tconst recoverable = [\n\t\t\t\t'abusefilter-disallowed',\n\t\t\t\t'abusefilter-warning',\n\t\t\t\t'spamblacklist',\n\t\t\t\t'fileexists-shared-forbidden',\n\t\t\t\t'protectedpage',\n\t\t\t\t'titleblacklist-forbidden',\n\n\t\t\t\t// below are not actual API errors, but recoverable warnings that have\n\t\t\t\t// been discovered in validateWikiTextSubmitResult and fabricated to resemble\n\t\t\t\t// API errors and end up here to be dealt with\n\t\t\t\t'error-title-thumbnail',\n\t\t\t\t'title-invalid',\n\t\t\t\t'title-senselessimagename',\n\t\t\t\t'api-warning-exists',\n\t\t\t\t'upload-error-duplicate',\n\t\t\t\t'upload-error-duplicate',\n\t\t\t\t'upload-error-duplicate-archive',\n\t\t\t\t'unknown-warning'\n\t\t\t];\n\n\t\t\tif ( code === 'badtoken' ) {\n\t\t\t\tthis.api.badToken( 'csrf' );\n\t\t\t\t// TODO Automatically try again instead of requiring the user to bonk the button\n\t\t\t}\n\n\t\t\tif ( code === 'ratelimited' ) {\n\t\t\t\t// None of the remaining uploads is going to succeed, and every failed one is going to\n\t\t\t\t// ping the rate limiter again.\n\t\t\t\tthis.upload.wizard.steps.details.queue.abortExecuting();\n\t\t\t} else if ( code === 'http' && result && result.exception === 'abort' ) {\n\t\t\t\t// This upload has just been aborted because an earlier one got the 'ratelimited' error.\n\t\t\t\t// This could potentially also come up when an upload is removed by the user, but in that\n\t\t\t\t// case the UI is invisible anyway, so whatever.\n\t\t\t\tcode = 'ratelimited';\n\t\t\t}\n\n\t\t\tif ( recoverable.includes( code ) ) {\n\t\t\t\tthis.recoverFromError( code, result.errors[ 0 ].html );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.showError( code, result.errors[ 0 ].html );\n\t\t},\n\n\t\tsetStatus: function ( s ) {\n\t\t\tconst $statusLine = this.$div.find( '.mwe-upwiz-file-status-line' );\n\t\t\tif ( typeof s === 'object' ) {\n\t\t\t\t$statusLine.html( s );\n\t\t\t} else {\n\t\t\t\t$statusLine.text( s );\n\t\t\t}\n\t\t\t$statusLine.show();\n\t\t},\n\n\t\t// TODO: De-duplicate with code form mw.UploadWizardUploadInterface.js\n\t\tshowIndicator: function ( status ) {\n\t\t\tconst progress = status === 'progress';\n\t\t\tthis.$spinner.toggle( progress );\n\t\t\tthis.statusMessage.toggle( status && !progress ).setType( status );\n\t\t\tthis.$indicator.toggleClass( 'mwe-upwiz-file-indicator-visible', !!status );\n\t\t},\n\n\t\tsetVisibleTitle: function ( s ) {\n\t\t\t$( this.$submittingDiv )\n\t\t\t\t.find( '.mwe-upwiz-visible-file-filename-text' )\n\t\t\t\t.text( s );\n\t\t}\n\t};\n\tOO.mixinClass( mw.UploadWizardDetails, OO.EventEmitter );\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardLicenseInput.js","messages":[{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":50,"column":20,"nodeType":"CallExpression","endLine":50,"endColumn":98}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Create a group of radio buttons for licenses. N.B. the licenses are named after the templates they invoke.\n * Note that this is very anti-MVC. The values are held only in the actual form elements themselves.\n *\n * @class\n * @extends OO.ui.Widget\n * @param {Object} config Configuration. Must have following properties:\n * @param {string} config.type Whether inclusive or exclusive license allowed (\"and\"|\"or\")\n * @param {string[]} config.licenses Template string names (matching keys in mw.UploadWizard.config.licenses)\n * @param {Object[]} [config.licenseGroups] Groups of licenses, with more explanation\n * @param {string} [config.special] Indicates, don't put licenses here, instead use a special widget\n * @param {number} count Number of the things we are licensing (it matters to some texts)\n * @param {mw.Api} api API object, used for wikitext previews\n */\nmw.UploadWizardLicenseInput = function ( config, count, api ) {\n\tmw.UploadWizardLicenseInput.super.call( this );\n\tOO.ui.mixin.GroupElement.call( this );\n\n\tthis.count = count;\n\tthis.api = api;\n\n\tif (\n\t\tconfig.type === undefined ||\n\t\t( config.licenses === undefined && config.licenseGroups === undefined )\n\t) {\n\t\tthrow new Error( 'improper initialization' );\n\t}\n\n\tthis.type = config.type === 'or' ? 'radio' : 'checkbox';\n\n\tthis.defaults = [];\n\tif ( config.defaults ) {\n\t\tthis.defaults = config.defaults instanceof Array ? config.defaults : [ config.defaults ];\n\t}\n\n\t// create inputs and licenses from config\n\tif ( config.licenseGroups === undefined ) {\n\t\tconst group = new mw.uploadWizard.LicenseGroup( config, this.type, this.api, this.count );\n\t\tconst groupField = new mw.uploadWizard.FieldLayout( group, {} );\n\t\tgroup.connect( groupField, { change: [ 'emit', 'change' ] } );\n\n\t\tthis.addItems( [ groupField ] );\n\t\tthis.$element.append( this.$group );\n\t} else {\n\t\tconst options = config.licenseGroups.map( ( groupConfig ) => {\n\t\t\tconst classes = [ 'mwe-upwiz-deed-license-group-head', 'mwe-upwiz-deed-license-group-' + groupConfig.head ];\n\n\t\t\tconst $icons = $( '<span>' );\n\t\t\t( groupConfig.icons || [] ).forEach( ( icon ) => {\n\t\t\t\t$icons.append( $( '<span>' ).addClass( 'mwe-upwiz-license-icon mwe-upwiz-' + icon + '-icon' ) );\n\t\t\t} );\n\n\t\t\t// 'url' can be either a single (string) url, or an array of (string) urls;\n\t\t\t// hence this convoluted variable-length parameters assembly...\n\t\t\tconst labelParams = [ groupConfig.head, this.count ].concat( groupConfig.url ).concat( $icons );\n\t\t\tconst label = groupConfig.head && mw.message.apply( mw.message, labelParams ).parseDom() || '';\n\t\t\tconst labelExtraParams = [ groupConfig[ 'head-extra' ], this.count ].concat( groupConfig.url ).concat( $icons );\n\t\t\tconst labelExtra = groupConfig[ 'head-extra' ] && mw.message.apply( mw.message, labelExtraParams ).parseDom() || '';\n\n\t\t\tif ( this.type === 'radio' ) {\n\t\t\t\treturn new OO.ui.RadioOptionWidget( {\n\t\t\t\t\tlabel: $( '<span>' )\n\t\t\t\t\t\t.append( label )\n\t\t\t\t\t\t.append( $( '<span>' ).addClass( 'mwe-upwiz-label-extra' ).append( labelExtra ) )\n\t\t\t\t\t\t.contents(),\n\t\t\t\t\tclasses: classes\n\t\t\t\t} );\n\t\t\t} else { // if ( this.type === 'checkbox' ) {\n\t\t\t\treturn new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\t\tlabel: $( '<span>' )\n\t\t\t\t\t\t.append( label )\n\t\t\t\t\t\t.append( $( '<span>' ).addClass( 'mwe-upwiz-label-extra' ).append( labelExtra ) )\n\t\t\t\t\t\t.contents(),\n\t\t\t\t\tclasses: classes\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t\tthis.widget = this.type === 'radio' ? new OO.ui.RadioSelectWidget() : new OO.ui.CheckboxMultiselectWidget();\n\t\tthis.widget.addItems( options );\n\n\t\tconst groupFields = config.licenseGroups.map( ( groupConfig ) => {\n\t\t\tconst group = new mw.uploadWizard.LicenseGroup(\n\t\t\t\tgroupConfig,\n\t\t\t\t// group config can override overall type; e.g. a single group can be \"and\", while\n\t\t\t\t// the rest of the config can be \"or\"\n\t\t\t\t( groupConfig.type || config.type ) === 'or' ? 'radio' : 'checkbox',\n\t\t\t\tthis.api,\n\t\t\t\tthis.count\n\t\t\t);\n\n\t\t\tconst groupField = new mw.uploadWizard.FieldLayout( group, {} );\n\t\t\tgroupField.$element.addClass( 'mwe-upwiz-deed-subgroup' );\n\t\t\tgroup.connect( groupField, { change: [ 'emit', 'change' ] } );\n\n\t\t\treturn groupField;\n\t\t} );\n\t\tthis.addItems( groupFields );\n\n\t\t// link option to the groups they're associated with, so we can easily move from\n\t\t// one to the other when they need to be interacted with\n\t\tgroupFields.forEach( ( groupField, i ) => {\n\t\t\tgroupField.option = options[ i ];\n\t\t} );\n\n\t\tthis.$element.append(\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'mwe-upwiz-deed-license-group-container' )\n\t\t\t\t.append( this.widget.$group )\n\t\t);\n\n\t\tthis.widget.on( 'select', ( selectedOption, isSelected ) => {\n\t\t\tthis.emit( 'change' );\n\n\t\t\t// radios don't have a second 'selected' arg; they're always true\n\t\t\tisSelected = isSelected || true;\n\n\t\t\t// radio groups won't fire events for group that got deselected\n\t\t\t// (as a results of a new one being selected), so we'll iterate\n\t\t\t// all groups to remove no-longer-active ones\n\t\t\tthis.getItems().forEach( ( groupField ) => {\n\t\t\t\tconst group = groupField.fieldWidget,\n\t\t\t\t\toption = groupField.option,\n\t\t\t\t\tdefaultLicenses = ( group.config.defaults || [] ).reduce( ( defaults, license ) => {\n\t\t\t\t\t\tdefaults[ license ] = true;\n\t\t\t\t\t\treturn defaults;\n\t\t\t\t\t}, {} );\n\n\t\t\t\tif ( !option.isSelected() ) {\n\t\t\t\t\t// collapse & nix any inputs that may have been selected in groups that\n\t\t\t\t\t// are no longer active/selected\n\t\t\t\t\tgroupField.$element.detach();\n\t\t\t\t\tgroup.setValue( {} );\n\t\t\t\t} else {\n\t\t\t\t\t// attach group license selector\n\t\t\t\t\toption.$label.append( groupField.$element );\n\n\t\t\t\t\t// check the defaults (insofar they exist) for newly selected groups;\n\t\t\t\t\t// ignore groups that had already been selected to ensure existing\n\t\t\t\t\t// user input is not tampered with\n\t\t\t\t\tif (\n\t\t\t\t\t\tisSelected &&\n\t\t\t\t\t\toption === selectedOption &&\n\t\t\t\t\t\tObject.keys( group.getValue() ).length <= 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tgroup.setValue( defaultLicenses );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\tthis.aggregate( { change: 'change' } );\n\n};\nOO.inheritClass( mw.UploadWizardLicenseInput, OO.ui.Widget );\nOO.mixinClass( mw.UploadWizardLicenseInput, OO.ui.mixin.GroupElement );\nOO.mixinClass( mw.UploadWizardLicenseInput, mw.uploadWizard.ValidatableElement );\n\nObject.assign( mw.UploadWizardLicenseInput.prototype, {\n\tunload: function () {\n\t\tthis.getItems().forEach( ( groupField ) => {\n\t\t\tgroupField.fieldWidget.unload();\n\t\t} );\n\t},\n\n\t/**\n\t * Sets the value(s) of a license input. This is a little bit klugey because it relies on an inverted dict, and in some\n\t * cases we are now letting license inputs create multiple templates.\n\t *\n\t * @memberof mw.UploadWizardLicenseInput\n\t * @param {Object} values License-key to boolean values, e.g. { 'cc_by_sa_30': true, gfdl: true, 'flickrreview|cc_by_sa_30': false }\n\t * @param {string} [groupName] Name of group, when values are only relevant to this group\n\t */\n\tsetValues: function ( values, groupName ) {\n\t\tconst selectedGroups = [];\n\n\t\tthis.getItems().forEach( ( groupField ) => {\n\t\t\tconst group = groupField.fieldWidget;\n\t\t\tif ( groupName === undefined || group.getGroup() === groupName ) {\n\t\t\t\tgroup.setValue( values );\n\t\t\t\tif ( Object.keys( group.getValue() ).length > 0 ) {\n\t\t\t\t\tselectedGroups.push( group );\n\t\t\t\t}\n\t\t\t} else if ( this.type === 'radio' ) {\n\t\t\t\t// when we're dealing with radio buttons and there are changes in another\n\t\t\t\t// group, then we'll need to clear out this group...\n\t\t\t\tgroup.setValue( {} );\n\t\t\t}\n\t\t} );\n\n\t\tif ( selectedGroups.length > 1 && this.type === 'radio' ) {\n\t\t\t// leave the last one alone - that one can remain selected\n\t\t\tselectedGroups.pop();\n\n\t\t\t// if we've selected things in multiple groups (= when the group was not defined,\n\t\t\t// which is basically only when dealing with defaults, from config or user\n\t\t\t// preferences), we need to make sure we're left with only 1 selected radio in\n\t\t\t// 1 group\n\t\t\t// in that case, we're only going to select the *last* occurrence, which is what\n\t\t\t// a browser would do when trying to find/select a radio that occurs twice\n\t\t\tselectedGroups.forEach( ( group ) => {\n\t\t\t\tgroup.setValue( {} );\n\t\t\t} );\n\t\t}\n\n\t\t// in the case of multiple option groups (with a parent radio/check to expand/collapse),\n\t\t// we need to make sure the parent option and expanded state match the state of the\n\t\t// group - when the group has things that are selected, it must be active\n\t\tthis.getItems().forEach( ( groupField ) => {\n\t\t\tconst group = groupField.fieldWidget,\n\t\t\t\toption = groupField.option,\n\t\t\t\tselected = Object.keys( group.getValue() ).length > 0;\n\n\t\t\tif ( !option ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\toption.setSelected( selected );\n\t\t\tif ( selected ) {\n\t\t\t\toption.$element.append( groupField.$element );\n\t\t\t\t// there's an event listener bound to respond to changes when an option\n\t\t\t\t// is selected, but that in only triggered by manual (user) selection;\n\t\t\t\t// we're programmatically updating values here, and need to make sure\n\t\t\t\t// it also responds to these\n\t\t\t\tthis.widget.emit( 'select', option, true );\n\t\t\t} else {\n\t\t\t\tgroupField.$element.detach();\n\t\t\t}\n\t\t} );\n\t},\n\n\t/**\n\t * Set the default configured licenses\n\t *\n\t * @memberof mw.UploadWizardLicenseInput\n\t */\n\tsetDefaultValues: function () {\n\t\tconst values = {};\n\t\tthis.defaults.forEach( ( license ) => {\n\t\t\tvalues[ license ] = true;\n\t\t} );\n\t\tthis.setValues( values );\n\t},\n\n\t/**\n\t * Gets the selected license(s). The returned value will be a license\n\t * key => license props map, as defined in UploadWizard.config.php.\n\t *\n\t * @memberof mw.UploadWizardLicenseInput\n\t * @return {Object}\n\t */\n\tgetLicenses: function () {\n\t\tconst licenses = {};\n\n\t\tthis.getItems().forEach( ( groupField ) => {\n\t\t\tconst group = groupField.fieldWidget,\n\t\t\t\tlicenseNames = Object.keys( group.getValue() );\n\n\t\t\tlicenseNames.forEach( ( name ) => {\n\t\t\t\tlicenses[ name ] = mw.UploadWizard.config.licenses[ name ] || {};\n\t\t\t} );\n\t\t} );\n\n\t\treturn licenses;\n\t},\n\n\t/**\n\t * Gets the wikitext associated with all selected inputs. Some inputs also have associated textareas so we append their contents too.\n\t *\n\t * @memberof mw.UploadWizardLicenseInput\n\t * @return {string} of wikitext (empty string if no inputs set)\n\t */\n\tgetWikiText: function () {\n\t\treturn this.getItems().map( ( groupField ) => groupField.fieldWidget.getWikiText() ).join( '' ).trim();\n\t},\n\n\t/**\n\t * See mw.uploadWizard.DetailsWidget\n\t *\n\t * @memberof mw.UploadWizardLicenseInput\n\t * @param {boolean} thorough\n\t * @return {jQuery.Promise<mw.uploadWizard.ValidationStatus>}\n\t */\n\tvalidate: function ( thorough ) {\n\t\t// Gather errors from each item\n\t\tconst status = new mw.uploadWizard.ValidationStatus(),\n\t\t\tselectedGroupPromises = this.getItems()\n\t\t\t\t.reduce( ( promises, groupField ) => {\n\t\t\t\t\t// validate all fields; allowing previously invalid subgroups to be re-validated\n\t\t\t\t\t// (e.g. clearing out errors), even when they're not selected\n\t\t\t\t\tconst promise = groupField.validate( thorough );\n\t\t\t\t\t// but only use the validation result of the selected groups (or the only available\n\t\t\t\t\t// group if there is no choice)\n\t\t\t\t\tif ( groupField.option === undefined || groupField.option.isSelected() ) {\n\t\t\t\t\t\tpromises.push( promise );\n\t\t\t\t\t}\n\t\t\t\t\treturn promises;\n\t\t\t\t}, [] );\n\n\t\tif ( thorough !== true ) {\n\t\t\t// `thorough` is the strict checks executed on submit, but we don't want errors\n\t\t\t// to change/display every change event\n\t\t\treturn status.resolve();\n\t\t}\n\n\t\tif ( selectedGroupPromises.length === 0 ) {\n\t\t\tstatus.addError( mw.message( 'mwe-upwiz-deeds-require-selection' ) );\n\t\t}\n\n\t\treturn mw.uploadWizard.ValidationStatus.mergePromises( ...selectedGroupPromises ).then(\n\t\t\t// license groups are valid\n\t\t\t() => status.getErrors().length === 0 ? status.resolve() : status.reject(),\n\t\t\t// there was an error in one of the license groups; we'll still want\n\t\t\t// to reject, but those child messages need not be added into this status\n\t\t\t// object, since they'll already be displayed within those child widgets\n\t\t\t() => status.reject()\n\t\t);\n\t},\n\n\t/**\n\t * @memberof mw.UploadWizardLicenseInput\n\t * @return {Object}\n\t */\n\tgetSerialized: function () {\n\t\tconst values = {};\n\n\t\tthis.getItems().forEach( ( groupField ) => {\n\t\t\tconst group = groupField.fieldWidget;\n\t\t\tconst groupName = group.getGroup();\n\t\t\tconst value = group.getValue();\n\n\t\t\tif ( Object.keys( value ).length > 0 ) {\n\t\t\t\t// $.extend just in case there are multiple groups with the same name...\n\t\t\t\tvalues[ groupName ] = Object.assign( {}, values[ groupName ] || {}, value );\n\t\t\t}\n\t\t} );\n\n\t\treturn values;\n\t},\n\n\t/**\n\t * @memberof mw.UploadWizardLicenseInput\n\t * @param {Object} serialized\n\t */\n\tsetSerialized: function ( serialized ) {\n\t\tObject.keys( serialized ).forEach( ( groupName ) => {\n\t\t\tthis.setValues( serialized[ groupName ], groupName );\n\t\t} );\n\t}\n\n} );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardPage.js","messages":[],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":32,"column":3,"nodeType":"CallExpression","endLine":32,"endColumn":28,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":35,"column":8,"nodeType":"CallExpression","endLine":35,"endColumn":29,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":43,"column":4,"nodeType":"CallExpression","endLine":43,"endColumn":33,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardUpload.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":380,"column":3,"nodeType":"CallExpression","endLine":380,"endColumn":36},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":380,"column":3,"nodeType":"CallExpression","endLine":380,"endColumn":48},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":445,"column":3,"nodeType":"CallExpression","endLine":445,"endColumn":36},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":445,"column":3,"nodeType":"CallExpression","endLine":445,"endColumn":48},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":766,"column":3,"nodeType":"CallExpression","endLine":768,"endColumn":26},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":766,"column":3,"nodeType":"CallExpression","endLine":780,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":774,"column":6,"nodeType":"CallExpression","endLine":774,"endColumn":65},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":777,"column":7,"nodeType":"CallExpression","endLine":777,"endColumn":66}],"suppressedMessages":[{"ruleId":"no-unused-vars","severity":2,"message":"'uw' is defined but never used.","line":11,"column":14,"nodeType":"Identifier","messageId":"unusedVar","endLine":11,"endColumn":16,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-underscore-dangle","severity":2,"message":"Unexpected dangling '_' in '_binary_data'.","line":234,"column":6,"nodeType":"MemberExpression","messageId":"unexpectedUnderscore","endLine":234,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier '_binary_data' is not in camel case.","line":234,"column":11,"nodeType":"Identifier","messageId":"notCamelCase","endLine":234,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":8,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Represents the upload -- in its local and remote state. (Possibly those could be separate objects too...)\n * This is our 'model' object if we are thinking MVC. Needs to be better factored, lots of feature envy with the UploadWizard\n * states:\n * 'new' 'transporting' 'transported' 'metadata' 'stashed' 'details' 'submitting-details' 'complete' 'error'\n * should fork this into two -- local and remote, e.g. filename\n *\n * @param uw\n */\n// eslint-disable-next-line no-unused-vars\n( function ( uw ) {\n\t/**\n\t * Constructor for objects representing uploads. The workhorse of this entire extension.\n\t *\n\t * The upload knows nothing of other uploads. It manages its own interface, and transporting its own data, to\n\t * the server.\n\t *\n\t * Upload objects are usually created without a file, they are just associated with a form.\n\t * There is an \"empty\" fileInput which is invisibly floating above certain buttons in the interface, like \"Add a file\". When\n\t * this fileInput gets a file, this upload becomes 'filled'.\n\t *\n\t * @class\n\t * @mixes OO.EventEmitter\n\t * @param {uw.controller.Step} controller\n\t * @param {File} file\n\t */\n\tmw.UploadWizardUpload = function MWUploadWizardUpload( controller, file ) {\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.index = mw.UploadWizardUpload.prototype.count;\n\t\tmw.UploadWizardUpload.prototype.count++;\n\n\t\tthis.controller = controller;\n\t\tthis.api = controller.api;\n\t\tthis.file = file;\n\t\tthis.state = 'new';\n\t\tthis.imageinfo = {};\n\t\tthis.title = undefined;\n\t\tthis.thumbnailPromise = {};\n\n\t\tthis.fileKey = undefined;\n\n\t\t// this should be moved to the interface, if we even keep this\n\t\tthis.transportWeight = 1; // default all same\n\n\t\t// details\n\t\tthis.ui = new mw.UploadWizardUploadInterface( this )\n\t\t\t.connect( this, {\n\t\t\t\t/*\n\t\t\t\t * This may be confusing!\n\t\t\t\t * This object also has a `remove` method, which will also be\n\t\t\t\t * called when an upload is removed. But an upload can be\n\t\t\t\t * removed for multiple reasons (one being clicking the \"remove\"\n\t\t\t\t * button, which triggers this event - but another could be\n\t\t\t\t * removing faulty uploads).\n\t\t\t\t * To simplify things, we'll always initiate the remove from the\n\t\t\t\t * controllers, so we'll relay this event to the controllers,\n\t\t\t\t * which will then eventually come back to call `remove` on this\n\t\t\t\t * object.\n\t\t\t\t */\n\t\t\t\t'upload-removed': [ 'emit', 'remove-upload' ]\n\t\t\t} );\n\n\t\tif ( file.licenseName ) {\n\t\t\tthis.ui.setLicenseText( file.licenseName );\n\t\t}\n\t};\n\n\tOO.mixinClass( mw.UploadWizardUpload, OO.EventEmitter );\n\n\t// Upload handler\n\tmw.UploadWizardUpload.prototype.uploadHandler = null;\n\n\t// increments with each upload\n\tmw.UploadWizardUpload.prototype.count = 0;\n\n\t/**\n\t * start\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tmw.UploadWizardUpload.prototype.start = function () {\n\t\tthis.setTransportProgress( 0.0 );\n\n\t\t// handler -- usually ApiUploadFormDataHandler\n\t\tthis.handler = this.getUploadHandler();\n\t\treturn this.handler.start();\n\t};\n\n\t/**\n\t * Remove this upload. n.b. we trigger a removeUpload this is usually triggered from\n\t */\n\tmw.UploadWizardUpload.prototype.remove = function () {\n\t\t// remove the div that passed along the trigger\n\t\tthis.ui.$div.remove();\n\n\t\tthis.state = 'aborted';\n\t};\n\n\t/**\n\t * Wear our current progress, for observing processes to see\n\t *\n\t * @param {number} fraction\n\t */\n\tmw.UploadWizardUpload.prototype.setTransportProgress = function ( fraction ) {\n\t\tif ( this.state === 'aborted' ) {\n\t\t\t// We shouldn't be transporting anything anymore.\n\t\t\treturn;\n\t\t}\n\t\tthis.state = 'transporting';\n\t\tthis.transportProgress = fraction;\n\t\tthis.ui.$div.trigger( 'transportProgressEvent' );\n\t};\n\n\t/**\n\t * Stop the upload -- we have failed for some reason\n\t *\n\t * @param {string} code Error code from API\n\t * @param {string} html Error message\n\t * @param {jQuery} [$additionalStatus]\n\t */\n\tmw.UploadWizardUpload.prototype.setError = function ( code, html, $additionalStatus ) {\n\t\tif ( this.state === 'aborted' ) {\n\t\t\t// There's no point in reporting an error anymore.\n\t\t\treturn;\n\t\t}\n\t\tthis.state = 'error';\n\t\tthis.transportProgress = 0;\n\t\tthis.ui.showError( code, html, $additionalStatus );\n\t};\n\n\t/**\n\t * Called from any upload success condition\n\t *\n\t * @param {Object} result -- result of AJAX call\n\t */\n\tmw.UploadWizardUpload.prototype.setSuccess = function ( result ) {\n\t\tthis.state = 'transported';\n\t\tthis.transportProgress = 1;\n\n\t\tthis.ui.setStatus( 'mwe-upwiz-getting-metadata' );\n\n\t\tthis.extractUploadInfo( result.upload );\n\t\tthis.state = 'stashed';\n\t\tthis.ui.showStashed();\n\n\t\tthis.emit( 'success' );\n\t\t// check all uploads, if they're complete, show the next button\n\t\t// TODO Make wizard connect to 'success' event\n\t\tthis.controller.showNext();\n\t};\n\n\t/**\n\t * Get just the filename.\n\t *\n\t * @return {string}\n\t */\n\tmw.UploadWizardUpload.prototype.getFilename = function () {\n\t\tif ( this.file.fileName ) {\n\t\t\treturn this.file.fileName;\n\t\t} else {\n\t\t\t// this property has a different name in FF vs Chrome.\n\t\t\treturn this.file.name;\n\t\t}\n\t};\n\n\t/**\n\t * Get the basename of a path.\n\t * For error conditions, returns the empty string.\n\t *\n\t * @return {string} basename\n\t */\n\tmw.UploadWizardUpload.prototype.getBasename = function () {\n\t\tconst path = this.getFilename();\n\n\t\tif ( path === undefined || path === null ) {\n\t\t\treturn '';\n\t\t}\n\n\t\t// find index of last path separator in the path, add 1. (If no separator found, yields 0)\n\t\t// then take the entire string after that.\n\t\treturn path.slice( Math.max( path.lastIndexOf( '/' ), path.lastIndexOf( '\\\\' ) ) + 1 );\n\t};\n\n\t/**\n\t * Sanitize and set the title of the upload.\n\t *\n\t * @param {string} title Unsanitized title.\n\t */\n\tmw.UploadWizardUpload.prototype.setTitle = function ( title ) {\n\t\tthis.title = mw.Title.newFromFileName( title );\n\t};\n\n\t/**\n\t * Extract some JPEG metadata that we need to render thumbnails (EXIF rotation mostly).\n\t *\n\t * For JPEGs, we use the JsJpegMeta library in core to extract metadata,\n\t * including EXIF tags. This is done asynchronously once each file has been\n\t * read.\n\t *\n\t * For all other file types, we don't need or want to run this, and this function does nothing.\n\t *\n\t * @private\n\t * @return {jQuery.Promise} A promise, resolved when we're done\n\t */\n\tmw.UploadWizardUpload.prototype.extractMetadataFromJpegMeta = function () {\n\t\tconst deferred = $.Deferred();\n\t\tif ( this.file && this.file.type === 'image/jpeg' ) {\n\t\t\tconst binReader = new FileReader();\n\t\t\tbinReader.onerror = () => {\n\t\t\t\tdeferred.resolve();\n\t\t\t};\n\t\t\tbinReader.onload = () => {\n\t\t\t\tlet binStr, arr, i, meta;\n\t\t\t\tif ( binReader.result === null ) {\n\t\t\t\t\t// Contrary to documentation, this sometimes fires for unsuccessful loads (T136235)\n\t\t\t\t\tdeferred.resolve();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif ( typeof binReader.result === 'string' ) {\n\t\t\t\t\tbinStr = binReader.result;\n\t\t\t\t} else {\n\t\t\t\t\t// Array buffer; convert to binary string for the library.\n\t\t\t\t\tarr = new Uint8Array( binReader.result );\n\t\t\t\t\tbinStr = '';\n\t\t\t\t\tfor ( i = 0; i < arr.byteLength; i++ ) {\n\t\t\t\t\t\tbinStr += String.fromCharCode( arr[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst jpegmeta = require( 'mediawiki.libs.jpegmeta' );\n\t\t\t\t\tmeta = jpegmeta( binStr, this.file.fileName );\n\t\t\t\t\t// eslint-disable-next-line camelcase, no-underscore-dangle\n\t\t\t\t\tmeta._binary_data = null;\n\t\t\t\t} catch ( e ) {\n\t\t\t\t\tmeta = null;\n\t\t\t\t}\n\t\t\t\tthis.extractMetadataFromJpegMetaCallback( meta );\n\t\t\t\tdeferred.resolve();\n\t\t\t};\n\t\t\tif ( 'readAsBinaryString' in binReader ) {\n\t\t\t\tbinReader.readAsBinaryString( this.file );\n\t\t\t} else if ( 'readAsArrayBuffer' in binReader ) {\n\t\t\t\tbinReader.readAsArrayBuffer( this.file );\n\t\t\t}\n\t\t} else {\n\t\t\tdeferred.resolve();\n\t\t}\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Map fields from jpegmeta's metadata return into our format (which is more like the imageinfo returned from the API\n\t *\n\t * @param {Object} meta As returned by jpegmeta\n\t */\n\tmw.UploadWizardUpload.prototype.extractMetadataFromJpegMetaCallback = function ( meta ) {\n\t\tlet pixelHeightDim, pixelWidthDim, degrees;\n\n\t\tif ( meta !== undefined && meta !== null && typeof meta === 'object' ) {\n\t\t\tif ( this.imageinfo.metadata === undefined ) {\n\t\t\t\tthis.imageinfo.metadata = {};\n\t\t\t}\n\t\t\tif ( meta.tiff && meta.tiff.Orientation ) {\n\t\t\t\tthis.imageinfo.metadata.orientation = meta.tiff.Orientation.value;\n\t\t\t}\n\t\t\tif ( meta.general ) {\n\t\t\t\tpixelHeightDim = 'height';\n\t\t\t\tpixelWidthDim = 'width';\n\t\t\t\t// this must be called after orientation is set above. If no orientation set, defaults to 0\n\t\t\t\tdegrees = this.getOrientationDegrees();\n\n\t\t\t\t// jpegmeta reports pixelHeight & width\n\t\t\t\tif ( degrees === 90 || degrees === 270 ) {\n\t\t\t\t\tpixelHeightDim = 'width';\n\t\t\t\t\tpixelWidthDim = 'height';\n\t\t\t\t}\n\t\t\t\tif ( meta.general.pixelHeight ) {\n\t\t\t\t\tthis.imageinfo[ pixelHeightDim ] = meta.general.pixelHeight.value;\n\t\t\t\t}\n\t\t\t\tif ( meta.general.pixelWidth ) {\n\t\t\t\t\tthis.imageinfo[ pixelWidthDim ] = meta.general.pixelWidth.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Accept the result from a successful API upload transport, and fill our own info\n\t *\n\t * @param {Object} resultUpload The JSON object from a successful API upload result.\n\t */\n\tmw.UploadWizardUpload.prototype.extractUploadInfo = function ( resultUpload ) {\n\t\tif ( resultUpload.filekey ) {\n\t\t\tthis.fileKey = resultUpload.filekey;\n\t\t}\n\n\t\tif ( resultUpload.imageinfo ) {\n\t\t\tthis.extractImageInfo( resultUpload.imageinfo );\n\t\t} else if ( resultUpload.stashimageinfo ) {\n\t\t\tthis.extractImageInfo( resultUpload.stashimageinfo );\n\t\t}\n\n\t};\n\n\t/**\n\t * Extract image info into our upload object\n\t * Image info is obtained from various different API methods\n\t * This may overwrite metadata obtained from FileReader.\n\t *\n\t * @param {Object} imageinfo JSON object obtained from API result.\n\t */\n\tmw.UploadWizardUpload.prototype.extractImageInfo = function ( imageinfo ) {\n\t\tfor ( const key in imageinfo ) {\n\t\t\t// we get metadata as list of key-val pairs; convert to object for easier lookup. Assuming that EXIF fields are unique.\n\t\t\tif ( key === 'metadata' ) {\n\t\t\t\tif ( this.imageinfo.metadata === undefined ) {\n\t\t\t\t\tthis.imageinfo.metadata = {};\n\t\t\t\t}\n\t\t\t\tif ( imageinfo.metadata && imageinfo.metadata.length ) {\n\t\t\t\t\timageinfo.metadata.forEach( ( pair ) => {\n\t\t\t\t\t\tif ( pair !== undefined ) {\n\t\t\t\t\t\t\tthis.imageinfo.metadata[ pair.name.toLowerCase() ] = pair.value;\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.imageinfo[ key ] = imageinfo[ key ];\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Get information about stashed images\n\t *\n\t * See API documentation for prop=stashimageinfo for what 'props' can contain\n\t *\n\t * @param {Function} callback Called with null if failure, with imageinfo data structure if success\n\t * @param {Array} props Properties to extract\n\t * @param {number} [width] Width of thumbnail. Will force 'url' to be added to props\n\t * @param {number} [height] Height of thumbnail. Will force 'url' to be added to props\n\t */\n\tmw.UploadWizardUpload.prototype.getStashImageInfo = function ( callback, props, width, height ) {\n\t\tconst params = {\n\t\t\tprop: 'stashimageinfo',\n\t\t\tsiifilekey: this.fileKey,\n\t\t\tsiiprop: props.join( '|' )\n\t\t};\n\n\t\tfunction ok( data ) {\n\t\t\tif ( !data || !data.query || !data.query.stashimageinfo ) {\n\t\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getStashImageInfo> No data?' );\n\t\t\t\tcallback( null );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcallback( data.query.stashimageinfo );\n\t\t}\n\n\t\tfunction err( code ) {\n\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getStashImageInfo> ' + code );\n\t\t\tcallback( null );\n\t\t}\n\n\t\tif ( props === undefined ) {\n\t\t\tprops = [];\n\t\t}\n\n\t\tif ( width !== undefined || height !== undefined ) {\n\t\t\tif ( !props.includes( 'url' ) ) {\n\t\t\t\tprops.push( 'url' );\n\t\t\t}\n\t\t\tif ( width !== undefined ) {\n\t\t\t\tparams.siiurlwidth = width;\n\t\t\t}\n\t\t\tif ( height !== undefined ) {\n\t\t\t\tparams.siiurlheight = height;\n\t\t\t}\n\t\t}\n\n\t\tthis.api.get( params ).done( ok ).fail( err );\n\t};\n\n\t/**\n\t * Get information about published images\n\t * (There is some overlap with getStashedImageInfo, but it's different at every stage so it's clearer to have separate functions)\n\t * See API documentation for prop=imageinfo for what 'props' can contain\n\t *\n\t * @param {Function} callback Called with null if failure, with imageinfo data structure if success\n\t * @param {Array} props Properties to extract\n\t * @param {number} [width] Width of thumbnail. Will force 'url' to be added to props\n\t * @param {number} [height] Height of thumbnail. Will force 'url' to be added to props\n\t */\n\tmw.UploadWizardUpload.prototype.getImageInfo = function ( callback, props, width, height ) {\n\t\tconst requestedTitle = this.title.getPrefixedText();\n\n\t\tfunction ok( data ) {\n\t\t\tlet found;\n\n\t\t\tif ( data && data.query && data.query.pages ) {\n\t\t\t\tfound = false;\n\t\t\t\tObject.keys( data.query.pages ).forEach( ( pageId ) => {\n\t\t\t\t\tconst page = data.query.pages[ pageId ];\n\t\t\t\t\tif ( page.title && page.title === requestedTitle && page.imageinfo ) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tcallback( page.imageinfo );\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tif ( found ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getImageInfo> No data matching ' + requestedTitle + ' ?' );\n\t\t\tcallback( null );\n\t\t}\n\n\t\tfunction err( code ) {\n\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getImageInfo> ' + code );\n\t\t\tcallback( null );\n\t\t}\n\n\t\tif ( props === undefined ) {\n\t\t\tprops = [];\n\t\t}\n\n\t\tconst params = {\n\t\t\tprop: 'imageinfo',\n\t\t\ttitles: requestedTitle,\n\t\t\tiiprop: props.join( '|' )\n\t\t};\n\n\t\tif ( width !== undefined || height !== undefined ) {\n\t\t\tif ( !props.includes( 'url' ) ) {\n\t\t\t\tprops.push( 'url' );\n\t\t\t}\n\t\t\tif ( width !== undefined ) {\n\t\t\t\tparams.iiurlwidth = width;\n\t\t\t}\n\t\t\tif ( height !== undefined ) {\n\t\t\t\tparams.iiurlheight = height;\n\t\t\t}\n\t\t}\n\n\t\tthis.api.get( params ).done( ok ).fail( err );\n\t};\n\n\t/**\n\t * Get the upload handler per browser capabilities\n\t *\n\t * @return {mw.ApiUploadFormDataHandler|mw.ApiUploadPostHandler} upload handler object\n\t */\n\tmw.UploadWizardUpload.prototype.getUploadHandler = function () {\n\t\tlet constructor; // must be the name of a function in 'mw' namespace\n\n\t\tif ( !this.uploadHandler ) {\n\t\t\tconstructor = 'ApiUploadFormDataHandler';\n\t\t\tif ( mw.UploadWizard.config.debug ) {\n\t\t\t\tmw.log( 'mw.UploadWizard::getUploadHandler> ' + constructor );\n\t\t\t}\n\t\t\tif ( this.file.fromURL ) {\n\t\t\t\tconstructor = 'ApiUploadPostHandler';\n\t\t\t}\n\t\t\tthis.uploadHandler = new mw[ constructor ]( this, this.api );\n\t\t}\n\t\treturn this.uploadHandler;\n\t};\n\n\t/**\n\t * Explicitly fetch a thumbnail for a stashed upload of the desired width.\n\t *\n\t * @private\n\t * @param {number} width Desired width of thumbnail\n\t * @param {number} height Maximum height of thumbnail\n\t * @return {jQuery.Promise} Promise resolved with a HTMLImageElement, or null if thumbnail\n\t * couldn't be generated\n\t */\n\tmw.UploadWizardUpload.prototype.getApiThumbnail = function ( width, height ) {\n\t\tconst deferred = $.Deferred();\n\n\t\tfunction thumbnailPublisher( thumbnails ) {\n\t\t\tif ( thumbnails === null ) {\n\t\t\t\t// the api call failed somehow, no thumbnail data.\n\t\t\t\tdeferred.resolve( null );\n\t\t\t} else {\n\t\t\t\t// ok, the api callback has returned us information on where the thumbnail(s) ARE, but that doesn't mean\n\t\t\t\t// they are actually there yet. Keep trying to set the source ( which should trigger \"error\" or \"load\" event )\n\t\t\t\t// on the image. If it loads publish the event with the image. If it errors out too many times, give up and publish\n\t\t\t\t// the event with a null.\n\t\t\t\tthumbnails.forEach( ( thumb ) => {\n\t\t\t\t\tif ( thumb.thumberror || ( !( thumb.thumburl && thumb.thumbwidth && thumb.thumbheight ) ) ) {\n\t\t\t\t\t\tmw.log.warn( 'mw.UploadWizardUpload::getThumbnail> Thumbnail error or missing information' );\n\t\t\t\t\t\tdeferred.resolve( null );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// try to load this image with exponential backoff\n\t\t\t\t\t// if the delay goes past 8 seconds, it gives up and publishes the event with null\n\t\t\t\t\tlet timeoutMs = 100;\n\t\t\t\t\tconst image = document.createElement( 'img' );\n\t\t\t\t\timage.width = thumb.thumbwidth;\n\t\t\t\t\timage.height = thumb.thumbheight;\n\n\t\t\t\t\t// executing this should cause a .load() or .error() event on the image\n\t\t\t\t\tfunction setSrc() {\n\t\t\t\t\t\t// IE 11 and Opera 12 will not, ever, re-request an image that they have already loaded\n\t\t\t\t\t\t// once, regardless of caching headers. Append bogus stuff to the URL to make it work.\n\t\t\t\t\t\timage.src = thumb.thumburl + '?' + Math.random();\n\t\t\t\t\t}\n\n\t\t\t\t\t$( image )\n\t\t\t\t\t\t.on( 'load', () => {\n\t\t\t\t\t\t\t// publish the image to anyone who wanted it\n\t\t\t\t\t\t\tdeferred.resolve( image );\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.on( 'error', () => {\n\t\t\t\t\t\t\t// retry with exponential backoff\n\t\t\t\t\t\t\tif ( timeoutMs < 8000 ) {\n\t\t\t\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\t\t\t\ttimeoutMs = timeoutMs * 2 + Math.round( Math.random() * ( timeoutMs / 10 ) );\n\t\t\t\t\t\t\t\t\tsetSrc();\n\t\t\t\t\t\t\t\t}, timeoutMs );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdeferred.resolve( null );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t// and, go!\n\t\t\t\t\tsetSrc();\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\tif ( this.state !== 'complete' ) {\n\t\t\tthis.getStashImageInfo( thumbnailPublisher, [ 'url' ], width, height );\n\t\t} else {\n\t\t\tthis.getImageInfo( thumbnailPublisher, [ 'url' ], width, height );\n\t\t}\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Return the orientation of the image in degrees. Relies on metadata that\n\t * may have been extracted at filereader stage, or after the upload when we fetch metadata. Default returns 0.\n\t *\n\t * @return {number} orientation in degrees: 0, 90, 180 or 270\n\t */\n\tmw.UploadWizardUpload.prototype.getOrientationDegrees = function () {\n\t\tlet orientation = 0;\n\t\tif ( this.imageinfo && this.imageinfo.metadata && this.imageinfo.metadata.orientation ) {\n\t\t\tswitch ( this.imageinfo.metadata.orientation ) {\n\t\t\t\tcase 8:\n\t\t\t\t\t// 'top left' -> 'left bottom'\n\t\t\t\t\torientation = 90;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\t// 'top left' -> 'bottom right'\n\t\t\t\t\torientation = 180;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 6:\n\t\t\t\t\t// 'top left' -> 'right top'\n\t\t\t\t\torientation = 270;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t// 'top left' -> 'top left'\n\t\t\t\t\torientation = 0;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\t\t}\n\t\treturn orientation;\n\t};\n\n\t/**\n\t * Fit an image into width & height constraints with scaling factor\n\t *\n\t * @private\n\t * @param {HTMLImageElement} image\n\t * @param {Object} constraints Width & height properties\n\t * @return {number}\n\t */\n\tmw.UploadWizardUpload.prototype.getScalingFromConstraints = function ( image, constraints ) {\n\t\tlet scaling = 1;\n\t\tObject.keys( constraints ).forEach( ( dim ) => {\n\t\t\tconst constraint = constraints[ dim ];\n\t\t\tif ( constraint && image[ dim ] > constraint ) {\n\t\t\t\tconst s = constraint / image[ dim ];\n\t\t\t\tif ( s < scaling ) {\n\t\t\t\t\tscaling = s;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\treturn scaling;\n\t};\n\n\t/**\n\t * Given an image (already loaded), dimension constraints\n\t * return canvas object scaled & transformed ( & rotated if metadata indicates it's needed )\n\t *\n\t * @deprecated 1.41 browsers apply orientation themselves since 2020. Remove this in 2026'ish\n\t * @private\n\t * @param {HTMLImageElement} image\n\t * @param {Object} constraints Width & height constraints\n\t * @return {HTMLCanvasElement|null}\n\t */\n\tmw.UploadWizardUpload.prototype.getTransformedCanvasElement = function ( image, constraints ) {\n\t\tlet angle, rotation = 0;\n\n\t\t// if this wiki can rotate images to match their EXIF metadata,\n\t\t// we should do the same in our preview if the browser does not apply it already\n\t\tif ( mw.config.get( 'wgFileCanRotate' ) ) {\n\t\t\tangle = this.getOrientationDegrees();\n\t\t\trotation = angle ? 360 - angle : 0;\n\t\t}\n\n\t\tlet scaleConstraints;\n\t\t// swap scaling constraints if needed by rotation...\n\t\tif ( rotation === 90 || rotation === 270 ) {\n\t\t\tscaleConstraints = {};\n\t\t\tif ( 'height' in constraints ) {\n\t\t\t\tscaleConstraints.width = constraints.height;\n\t\t\t}\n\t\t\tif ( 'width' in constraints ) {\n\t\t\t\tscaleConstraints.height = constraints.width;\n\t\t\t}\n\t\t}\n\n\t\tconst scaling = this.getScalingFromConstraints( image, scaleConstraints );\n\n\t\tconst width = image.width * scaling;\n\t\tconst height = image.height * scaling;\n\n\t\tlet dimensions = { width: width, height: height };\n\t\tif ( rotation === 90 || rotation === 270 ) {\n\t\t\tdimensions = { width: height, height: width };\n\t\t}\n\n\t\t// Start drawing at offset 0,0\n\t\tconst dx = 0;\n\t\tconst dy = 0;\n\n\t\tlet x, y;\n\t\tswitch ( rotation ) {\n\t\t\t// If a rotation is applied, the direction of the axis\n\t\t\t// changes as well. You can derive the values below by\n\t\t\t// drawing on paper an axis system, rotate it and see\n\t\t\t// where the positive axis direction is\n\t\t\tcase 90:\n\t\t\t\tx = dx;\n\t\t\t\ty = dy - height;\n\t\t\t\tbreak;\n\t\t\tcase 180:\n\t\t\t\tx = dx - width;\n\t\t\t\ty = dy - height;\n\t\t\t\tbreak;\n\t\t\tcase 270:\n\t\t\t\tx = dx - width;\n\t\t\t\ty = dy;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tx = dx;\n\t\t\t\ty = dy;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst $canvas = $( '<canvas>' ).attr( dimensions );\n\t\tconst ctx = $canvas[ 0 ].getContext( '2d' );\n\t\tctx.clearRect( dx, dy, width, height );\n\t\tctx.rotate( rotation / 180 * Math.PI );\n\t\ttry {\n\t\t\t// Calling #drawImage likes to throw all kinds of ridiculous exceptions in various browsers,\n\t\t\t// including but not limited to:\n\t\t\t// * (Firefox) NS_ERROR_NOT_AVAILABLE:\n\t\t\t// * (Internet Explorer / Edge) Not enough storage is available to complete this operation.\n\t\t\t// * (Internet Explorer / Edge) Unspecified error.\n\t\t\t// * (Internet Explorer / Edge) The GPU device instance has been suspended. Use GetDeviceRemovedReason to determine the appropriate action.\n\t\t\t// * (Safari) IndexSizeError: Index or size was negative, or greater than the allowed value.\n\t\t\t// There is nothing we can do about this. It's okay though, there just won't be a thumbnail.\n\t\t\tctx.drawImage( image, x, y, width, height );\n\t\t} catch ( err ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn $canvas;\n\t};\n\n\t/**\n\t * Return a browser-scaled image element, given an image and constraints.\n\t *\n\t * @private\n\t * @param {HTMLImageElement} image\n\t * @param {Object} constraints Width and height properties\n\t * @return {HTMLImageElement} with same src, but different attrs\n\t */\n\tmw.UploadWizardUpload.prototype.getBrowserScaledImageElement = function ( image, constraints ) {\n\t\tconst scaling = this.getScalingFromConstraints( image, constraints );\n\t\treturn $( '<img>' )\n\t\t\t.attr( {\n\t\t\t\twidth: parseInt( image.width * scaling, 10 ),\n\t\t\t\theight: parseInt( image.height * scaling, 10 ),\n\t\t\t\tsrc: image.src\n\t\t\t} );\n\t};\n\n\t/**\n\t * Return an element suitable for the preview of a certain size. Uses canvas when possible\n\t *\n\t * @private\n\t * @param {HTMLImageElement} image\n\t * @param {number} width\n\t * @param {number} height\n\t * @return {HTMLCanvasElement|HTMLImageElement}\n\t */\n\tmw.UploadWizardUpload.prototype.getScaledImageElement = function ( image, width, height ) {\n\t\tconst constraints = {};\n\n\t\tif ( width ) {\n\t\t\tconstraints.width = width;\n\t\t}\n\t\tif ( height ) {\n\t\t\tconstraints.height = height;\n\t\t}\n\n\t\tif ( mw.canvas.isAvailable() && !CSS.supports( 'image-orientation', 'from-image' ) ) {\n\t\t\tconst transform = this.getTransformedCanvasElement( image, constraints );\n\t\t\tif ( transform ) {\n\t\t\t\treturn transform;\n\t\t\t}\n\t\t}\n\n\t\t// No canvas support or canvas drawing failed mysteriously, fall back\n\t\treturn this.getBrowserScaledImageElement( image, constraints );\n\t};\n\n\t/**\n\t * Acquire a thumbnail for this upload.\n\t *\n\t * @param {number} width\n\t * @param {number} height\n\t * @return {jQuery.Promise} Promise resolved with the HTMLImageElement or HTMLCanvasElement\n\t * containing a thumbnail, or resolved with `null` when one can't be produced\n\t */\n\tmw.UploadWizardUpload.prototype.getThumbnail = function ( width, height ) {\n\t\tconst deferred = $.Deferred();\n\n\t\tif ( this.thumbnailPromise[ width + 'x' + height ] ) {\n\t\t\treturn this.thumbnailPromise[ width + 'x' + height ];\n\t\t}\n\t\tthis.thumbnailPromise[ width + 'x' + height ] = deferred.promise();\n\n\t\t/**\n\t\t * @param {HTMLImageElement|null} image\n\t\t */\n\t\tconst imageCallback = ( image ) => {\n\t\t\tif ( image === null ) {\n\t\t\t\tthis.ui.setStatus( 'mwe-upwiz-thumbnail-failed' );\n\t\t\t\tdeferred.resolve( image );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\timage = this.getScaledImageElement( image, width, height );\n\t\t\tdeferred.resolve( image );\n\t\t};\n\n\t\tthis.extractMetadataFromJpegMeta()\n\t\t\t.then( this.makePreview.bind( this, width ) )\n\t\t\t.done( imageCallback )\n\t\t\t.fail( () => {\n\t\t\t\t// Can't generate the thumbnail locally, get the thumbnail via API after\n\t\t\t\t// the file is uploaded. Queries are cached, so if this thumbnail was\n\t\t\t\t// already fetched for some reason, we'll get it immediately.\n\t\t\t\tif ( this.state !== 'new' && this.state !== 'transporting' && this.state !== 'error' ) {\n\t\t\t\t\tthis.getApiThumbnail( width, height ).done( imageCallback );\n\t\t\t\t} else {\n\t\t\t\t\tthis.once( 'success', () => {\n\t\t\t\t\t\tthis.getApiThumbnail( width, height ).done( imageCallback );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\n\t\treturn this.thumbnailPromise[ width + 'x' + height ];\n\t};\n\n\t/**\n\t * Notification that the file input has changed and it's fine...set info.\n\t */\n\tmw.UploadWizardUpload.prototype.fileChangedOk = function () {\n\t\tthis.ui.fileChangedOk( this.imageinfo, this.file );\n\t};\n\n\t/**\n\t * Make a preview for the file.\n\t *\n\t * @private\n\t * @param {number} width\n\t * @return {jQuery.Promise}\n\t */\n\tmw.UploadWizardUpload.prototype.makePreview = function ( width ) {\n\t\tconst deferred = $.Deferred();\n\n\t\t// do preview if we can\n\t\tif ( this.isPreviewable() ) {\n\t\t\t// open video and get frame via canvas\n\t\t\tif ( this.isVideo() ) {\n\t\t\t\tlet first = true;\n\t\t\t\tconst video = document.createElement( 'video' );\n\n\t\t\t\tvideo.addEventListener( 'loadedmetadata', () => {\n\t\t\t\t\t// seek 2 seconds into video or to half if shorter\n\t\t\t\t\tvideo.currentTime = Math.min( 2, video.duration / 2 );\n\t\t\t\t\tvideo.volume = 0;\n\t\t\t\t} );\n\t\t\t\tvideo.addEventListener( 'seeked', () => {\n\t\t\t\t\t// Firefox 16 sometimes does not work on first seek, seek again\n\t\t\t\t\tif ( first ) {\n\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t\tvideo.currentTime = Math.min( 2, video.duration / 2 );\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Chrome sometimes shows black frames if grabbing right away.\n\t\t\t\t\t\t// wait 500ms before grabbing frame\n\t\t\t\t\t\tsetTimeout( () => {\n\t\t\t\t\t\t\tconst canvas = document.createElement( 'canvas' );\n\t\t\t\t\t\t\tcanvas.width = width;\n\t\t\t\t\t\t\tcanvas.height = Math.round( canvas.width * video.videoHeight / video.videoWidth );\n\t\t\t\t\t\t\tconst context = canvas.getContext( '2d' );\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t// More ridiculous exceptions, see the comment in #getTransformedCanvasElement\n\t\t\t\t\t\t\t\tcontext.drawImage( video, 0, 0, canvas.width, canvas.height );\n\t\t\t\t\t\t\t} catch ( err ) {\n\t\t\t\t\t\t\t\tdeferred.reject();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.loadImage( canvas.toDataURL(), deferred );\n\t\t\t\t\t\t\tthis.URL().revokeObjectURL( video.url );\n\t\t\t\t\t\t}, 500 );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tconst url = this.URL().createObjectURL( this.file );\n\t\t\t\tvideo.src = url;\n\t\t\t\t// If we can't get a frame within 10 seconds, something is probably seriously wrong.\n\t\t\t\t// This can happen for broken files where we can't actually seek to the time we wanted.\n\t\t\t\tsetTimeout( () => {\n\t\t\t\t\tdeferred.reject();\n\t\t\t\t\tthis.URL().revokeObjectURL( video.url );\n\t\t\t\t}, 10000 );\n\t\t\t} else {\n\t\t\t\tconst dataUrlReader = new FileReader();\n\t\t\t\tdataUrlReader.onload = () => {\n\t\t\t\t\t// this step (inserting image-as-dataurl into image object) is slow for large images, which\n\t\t\t\t\t// is why this is optional and has a control attached to it to load the preview.\n\t\t\t\t\tthis.loadImage( dataUrlReader.result, deferred );\n\t\t\t\t};\n\t\t\t\tdataUrlReader.readAsDataURL( this.file );\n\t\t\t}\n\t\t} else {\n\t\t\tdeferred.reject();\n\t\t}\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Loads an image preview.\n\t *\n\t * @param {string} url\n\t * @param {jQuery.Deferred} deferred\n\t */\n\tmw.UploadWizardUpload.prototype.loadImage = function ( url, deferred ) {\n\t\tconst image = document.createElement( 'img' );\n\t\timage.onload = function () {\n\t\t\tdeferred.resolve( image );\n\t\t};\n\t\timage.onerror = function () {\n\t\t\tdeferred.reject();\n\t\t};\n\t\ttry {\n\t\t\timage.src = url;\n\t\t} catch ( er ) {\n\t\t\t// On Internet Explorer 11 and Edge, this occasionally causes an exception (possibly\n\t\t\t// localised) like \"Not enough storage is available to complete this operation\". (T136239)\n\t\t\tdeferred.reject();\n\t\t}\n\t};\n\n\t/**\n\t * Check if the file is previewable.\n\t *\n\t * @return {boolean}\n\t */\n\tmw.UploadWizardUpload.prototype.isPreviewable = function () {\n\t\treturn this.file && mw.fileApi.isPreviewableFile( this.file );\n\t};\n\n\t/**\n\t * Finds the right URL object to use.\n\t *\n\t * @return {URL}\n\t */\n\tmw.UploadWizardUpload.prototype.URL = function () {\n\t\t// This functionality is missing on IE 11\n\n\t\treturn window.URL || window.webkitURL || window.mozURL;\n\t};\n\n\t/**\n\t * Checks if this upload is a video.\n\t *\n\t * @return {boolean}\n\t */\n\tmw.UploadWizardUpload.prototype.isVideo = function () {\n\t\treturn mw.fileApi.isPreviewableVideo( this.file );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.UploadWizardUploadInterface.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":215,"column":3,"nodeType":"CallExpression","endLine":218,"endColumn":6}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\t/**\n\t * Create an interface fragment corresponding to a file input, suitable for Upload Wizard.\n\t *\n\t * @class\n\t * @mixes OO.EventEmitter\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tmw.UploadWizardUploadInterface = function MWUploadWizardUploadInterface( upload ) {\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.upload = upload;\n\n\t\t// May need to collaborate with the particular upload type sometimes\n\t\t// for the interface, as well as the uploadwizard. OY.\n\t\tthis.$div = $( '<div>' ).addClass( 'mwe-upwiz-file' );\n\n\t\tthis.isFilled = false;\n\n\t\tthis.statusMessage = new OO.ui.MessageWidget( { inline: true } );\n\t\tthis.statusMessage.toggle( false );\n\t\tthis.$spinner = $.createSpinner( { size: 'small', type: 'inline' } );\n\t\tthis.$spinner.hide();\n\t\tthis.$indicator = $( '<div>' ).addClass( 'mwe-upwiz-file-indicator' ).append(\n\t\t\tthis.$spinner,\n\t\t\tthis.statusMessage.$element\n\t\t);\n\n\t\tthis.$visibleFilenameDiv = $( '<div>' ).addClass( 'mwe-upwiz-visible-file' ).append(\n\t\t\tthis.$indicator,\n\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-visible-file-filename' ).append(\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-preview' ),\n\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-texts' ).append(\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-visible-file-filename-text' ),\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-license' ),\n\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-status-line' ).append(\n\t\t\t\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-file-status' )\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\n\t\tthis.removeCtrl = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-remove' ).text(),\n\t\t\ttitle: mw.message( 'mwe-upwiz-remove-upload' ).text(),\n\t\t\tflags: 'destructive',\n\t\t\ticon: 'trash',\n\t\t\tframed: false\n\t\t} ).on( 'click', () => {\n\t\t\tthis.emit( 'upload-removed' );\n\t\t} );\n\n\t\tif ( mw.UploadWizard.config.defaults && mw.UploadWizard.config.defaults.objref !== '' ) {\n\t\t\tthis.$imagePicker = this.createImagePickerField(\n\t\t\t\tthis.upload.index,\n\t\t\t\tmw.UploadWizard.config.defaults.updateList === ''\n\t\t\t);\n\t\t\tthis.$visibleFilenameDiv.find( '.mwe-upwiz-file-status-line' )\n\t\t\t\t.append( this.$imagePicker );\n\t\t}\n\n\t\tthis.$visibleFilenameDiv.find( '.mwe-upwiz-file-status-line' )\n\t\t\t.append( this.removeCtrl.$element );\n\n\t\tthis.$form = $( '<form>' )\n\t\t\t.addClass( 'mwe-upwiz-form' )\n\t\t\t.append( this.$visibleFilenameDiv );\n\n\t\tthis.$div.append( this.$form );\n\n\t\t// this.progressBar = ( no progress bar for individual uploads yet )\n\t\t// we bind to the ui div since .off() doesn't work for non-DOM objects\n\t\t// TODO Convert this to an OO.EventEmitter, and use OOjs events\n\t\tthis.$div.on( 'transportProgressEvent', () => {\n\t\t\tthis.showTransportProgress();\n\t\t} );\n\t};\n\n\tOO.mixinClass( mw.UploadWizardUploadInterface, OO.EventEmitter );\n\n\t/**\n\t * Change the graphic indicator at the far end of the row for this file\n\t *\n\t * @param {string} [status] Either a OO.ui.MessageWidget type (error/success/...) or 'progress'.\n\t * Omit to hide the indicator\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showIndicator = function ( status ) {\n\t\tconst progress = status === 'progress';\n\t\tthis.$spinner.toggle( progress );\n\t\tthis.statusMessage.toggle( status && !progress ).setType( status );\n\t\tthis.$indicator.toggleClass( 'mwe-upwiz-file-indicator-visible', !!status );\n\t};\n\n\t/**\n\t * @param {string} license License text\n\t */\n\tmw.UploadWizardUploadInterface.prototype.setLicenseText = function ( license ) {\n\t\tthis.$div.find( '.mwe-upwiz-file-license' ).text( license );\n\t};\n\n\t/**\n\t * Set the status line for this upload with an internationalized message string.\n\t *\n\t * @param {string} msgKey Key for the message\n\t * @param {Array} [args] Array of values, in case any need to be fed to the image.\n\t */\n\tmw.UploadWizardUploadInterface.prototype.setStatus = function ( msgKey, args ) {\n\t\t// get the status line for our upload\n\t\tconst $status = this.$div.find( '.mwe-upwiz-file-status' );\n\t\t$status.msg( msgKey, args || [] ).show();\n\t};\n\n\t/**\n\t * Set status line directly with a string\n\t *\n\t * @param {string} html\n\t */\n\tmw.UploadWizardUploadInterface.prototype.setStatusString = function ( html ) {\n\t\tthis.$div.find( '.mwe-upwiz-file-status' ).html( html ).show();\n\t};\n\n\t/**\n\t * Set additional status information\n\t *\n\t * @param {jQuery} [$status] If not given or null, additional status is cleared\n\t */\n\tmw.UploadWizardUploadInterface.prototype.setAdditionalStatus = function ( $status ) {\n\t\tif ( this.$additionalStatus ) {\n\t\t\tthis.$additionalStatus.remove();\n\t\t}\n\t\tthis.$additionalStatus = $status;\n\t\tif ( this.$additionalStatus ) {\n\t\t\tthis.$div.find( '.mwe-upwiz-file-status' ).after( this.$additionalStatus );\n\t\t}\n\t};\n\n\t/**\n\t * Clear the status line for this upload (hide it, in case there are paddings and such which offset other things.)\n\t */\n\tmw.UploadWizardUploadInterface.prototype.clearStatus = function () {\n\t\tthis.$div.find( '.mwe-upwiz-file-status' ).hide();\n\t\tthis.setAdditionalStatus( null );\n\t};\n\n\t/**\n\t * Put the visual state of an individual upload into \"progress\"\n\t *\n\t * @param {number} fraction The fraction of progress. Float between 0 and 1\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showTransportProgress = function () {\n\t\t// if fraction available, update individual progress bar / estimates, etc.\n\t\tthis.showIndicator( 'progress' );\n\t\tthis.setStatus( 'mwe-upwiz-uploading' );\n\t\tthis.setAdditionalStatus( null );\n\t};\n\n\t/**\n\t * Show that upload is transported\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showStashed = function () {\n\t\tthis.showIndicator( 'success' );\n\t\tthis.setStatus( 'mwe-upwiz-stashed-upload' );\n\t\tthis.setAdditionalStatus( null );\n\t};\n\n\t/**\n\t * Show that transport has failed\n\t *\n\t * @param {string} code Error code from API\n\t * @param {string} html Error message\n\t * @param {jQuery} [$additionalStatus]\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showError = function ( code, html, $additionalStatus ) {\n\t\tthis.showIndicator( 'error' );\n\t\tthis.setStatusString( html );\n\t\tthis.setAdditionalStatus( $additionalStatus );\n\t};\n\n\t/**\n\t * Run this when the value of the file input has changed and we know it's acceptable -- this\n\t * will update interface to show as much info as possible, including preview.\n\t * n.b. in older browsers we only will know the filename\n\t *\n\t * @param {Object} imageinfo\n\t * @param {File} file\n\t */\n\tmw.UploadWizardUploadInterface.prototype.fileChangedOk = function ( imageinfo, file ) {\n\t\tconst statusItems = [];\n\n\t\tthis.updateFilename();\n\n\t\t// set the status string - e.g. \"256 Kb, 100 x 200\"\n\t\tif ( imageinfo && imageinfo.width && imageinfo.height ) {\n\t\t\tstatusItems.push( imageinfo.width + '\\u00d7' + imageinfo.height );\n\t\t}\n\n\t\tif ( file && file.size ) {\n\t\t\tstatusItems.push( uw.units.bytes( file.size ) );\n\t\t}\n\n\t\tthis.clearStatus();\n\t\tthis.setStatusString( statusItems.join( ' \\u00b7 ' ) );\n\t};\n\n\t/**\n\t * Display thumbnail preview.\n\t *\n\t * @return {jQuery.Promise} Promise resolved when the thumbnail is displayed or when displaying it\n\t * fails\n\t */\n\tmw.UploadWizardUploadInterface.prototype.showThumbnail = function () {\n\t\tconst $preview = this.$div.find( '.mwe-upwiz-file-preview' ),\n\t\t\tdeferred = $.Deferred();\n\t\t// This must match the CSS dimensions of .mwe-upwiz-file-preview\n\t\tthis.upload.getThumbnail( 120, 120 ).done( ( thumb ) => {\n\t\t\tmw.UploadWizard.placeThumbnail( $preview, thumb );\n\t\t\tdeferred.resolve();\n\t\t} );\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * this does two things:\n\t * 1 ) since the file input has been hidden with some clever CSS ( to avoid x-browser styling issues ),\n\t * update the visible filename\n\t *\n\t * 2 ) update the underlying \"title\" which we are targeting to add to mediawiki.\n\t * TODO silently fix to have unique filename? unnecessary at this point...\n\t */\n\tmw.UploadWizardUploadInterface.prototype.updateFilename = function () {\n\t\tconst path = this.upload.getFilename();\n\n\t\t// visible filename\n\t\tthis.$form.find( '.mwe-upwiz-visible-file-filename-text' )\n\t\t\t.text( path );\n\n\t\tif ( !this.isFilled ) {\n\t\t\tthis.isFilled = true;\n\t\t\tthis.$div.addClass( 'filled' );\n\t\t}\n\t};\n\n\t/**\n\t * Create a checkbox to process the object reference parameter\n\t *\n\t * @param {number} index Number of the file for which the field is being created\n\t * @param {boolean} setDisabled Disable in case there already is an image in the referring list\n\t * @return {jQuery} A `div` containing a checkbox, label, and optional notice\n\t */\n\tmw.UploadWizardUploadInterface.prototype.createImagePickerField = function ( index, setDisabled ) {\n\t\tconst $fieldContainer = $( '<div>' ).addClass( 'mwe-upwiz-objref-pick-image' ),\n\t\t\tattributes = {\n\t\t\t\ttype: 'checkbox',\n\t\t\t\tclass: 'imgPicker',\n\t\t\t\tid: 'imgPicker' + index,\n\t\t\t\tdisabled: false,\n\t\t\t\tchecked: false\n\t\t\t};\n\n\t\tif ( setDisabled ) {\n\t\t\tattributes.disabled = 'disabled';\n\t\t} else if ( index === 0 ) {\n\t\t\tattributes.checked = 'checked';\n\t\t}\n\n\t\t$fieldContainer.append(\n\t\t\t$( '<input>' ).attr( attributes ).on( 'click', function () {\n\t\t\t\t$( this )\n\t\t\t\t\t.prop( 'checked', true )\n\t\t\t\t\t.closest( '.mwe-upwiz-file' )\n\t\t\t\t\t.siblings()\n\t\t\t\t\t.find( '.imgPicker' )\n\t\t\t\t\t.prop( 'checked', false );\n\t\t\t} ),\n\n\t\t\t$( '<label>' ).attr( {\n\t\t\t\tfor: 'imgPicker' + index\n\t\t\t} ).text( this.getPickImageLabel() )\n\t\t);\n\n\t\tif ( setDisabled ) {\n\t\t\t$fieldContainer.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-objref-notice-existing-image' )\n\t\t\t\t\t.text( this.getExistingImageNotice() )\n\t\t\t);\n\t\t}\n\n\t\treturn $fieldContainer;\n\t};\n\n\tmw.UploadWizardUploadInterface.prototype.getExistingImageNotice = function () {\n\t\tif ( mw.UploadWizard.config && mw.UploadWizard.config.display && mw.UploadWizard.config.display.noticeExistingImage ) {\n\t\t\treturn mw.UploadWizard.config.display.noticeExistingImage;\n\t\t} else {\n\t\t\treturn mw.message( 'mwe-upwiz-objref-notice-existing-image' ).text();\n\t\t}\n\t};\n\n\tmw.UploadWizardUploadInterface.prototype.getPickImageLabel = function () {\n\t\tif ( mw.UploadWizard.config && mw.UploadWizard.config.display && mw.UploadWizard.config.display.labelPickImage ) {\n\t\t\treturn mw.UploadWizard.config.display.labelPickImage;\n\t\t} else {\n\t\t\treturn mw.message( 'mwe-upwiz-objref-pick-image' ).text();\n\t\t}\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.canvas.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.errorDialog.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/mw.fileApi.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/transports/mw.FormDataTransport.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":166,"column":5,"nodeType":"CallExpression","endLine":175,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":167,"column":6,"nodeType":"CallExpression","endLine":168,"endColumn":67},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":167,"column":6,"nodeType":"CallExpression","endLine":169,"endColumn":31}],"suppressedMessages":[{"ruleId":"no-loop-func","severity":2,"message":"Function declared in a loop contains unsafe references to variable(s) 'prevPromise', 'prevPromise'.","line":161,"column":6,"nodeType":"ArrowFunctionExpression","messageId":"unsafeRefs","endLine":177,"endColumn":5,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t/**\n\t * Represents a \"transport\" for files to upload; using HTML5 FormData.\n\t *\n\t * @class\n\t * @mixes OO.EventEmitter\n\t * @param {mw.Api} api\n\t * @param {Object} formData Additional form fields required for upload api call\n\t * @param {Object} [config]\n\t * @param {Object} [config.chunkSize]\n\t * @param {Object} [config.maxPhpUploadSize]\n\t * @param {Object} [config.useRetryTimeout]\n\t */\n\tmw.FormDataTransport = function ( api, formData, config ) {\n\t\tthis.config = config || mw.UploadWizard.config;\n\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.formData = formData;\n\t\tthis.aborted = false;\n\t\tthis.api = api;\n\n\t\t// Set chunk size to configured chunk size or max php size,\n\t\t// whichever is smaller.\n\t\tthis.chunkSize = Math.min( this.config.chunkSize, this.config.maxPhpUploadSize );\n\t\tthis.maxRetries = 2;\n\t\tthis.retries = 0;\n\t\tthis.firstPoll = false;\n\n\t\t// running API request\n\t\tthis.request = null;\n\t};\n\n\tOO.mixinClass( mw.FormDataTransport, OO.EventEmitter );\n\n\tmw.FormDataTransport.prototype.abort = function () {\n\t\tthis.aborted = true;\n\n\t\tif ( this.request ) {\n\t\t\tthis.request.abort();\n\t\t}\n\t};\n\n\t/**\n\t * Submits an upload to the API.\n\t *\n\t * @param {Object} params Request params\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.post = function ( params ) {\n\t\tconst deferred = $.Deferred();\n\n\t\tthis.request = this.api.post( params, {\n\t\t\t/*\n\t\t\t * $.ajax is not quite equiped to handle File uploads with params.\n\t\t\t * The most convenient way would be to submit it with a FormData\n\t\t\t * object, but mw.Api will already do that for us: it'll transform\n\t\t\t * params if it encounters a multipart/form-data POST request, and\n\t\t\t * submit it accordingly!\n\t\t\t *\n\t\t\t * @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Submitting_forms_and_uploading_files\n\t\t\t */\n\t\t\tcontentType: 'multipart/form-data',\n\t\t\t/*\n\t\t\t * $.ajax also has no progress event that will allow us to figure\n\t\t\t * out how much of the upload has already gone out, so let's add it!\n\t\t\t */\n\t\t\txhr: function () {\n\t\t\t\tconst xhr = $.ajaxSettings.xhr();\n\t\t\t\txhr.upload.addEventListener( 'progress', ( evt ) => {\n\t\t\t\t\tlet fraction = null;\n\t\t\t\t\tif ( evt.lengthComputable ) {\n\t\t\t\t\t\tfraction = parseFloat( evt.loaded / evt.total );\n\t\t\t\t\t}\n\t\t\t\t\tdeferred.notify( fraction );\n\t\t\t\t}, false );\n\t\t\t\treturn xhr;\n\t\t\t}\n\t\t} );\n\n\t\t// just pass on success & failures\n\t\tthis.request.then( deferred.resolve, deferred.reject );\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Creates the upload API params.\n\t *\n\t * @param {string} filename\n\t * @param {number} [offset] For chunked uploads\n\t * @return {Object}\n\t */\n\tmw.FormDataTransport.prototype.createParams = function ( filename, offset ) {\n\t\tconst params = OO.cloneObject( this.formData );\n\n\t\tObject.assign( params, {\n\t\t\tfilename: filename,\n\n\t\t\t// ignorewarnings is turned on, since warnings are presented in a\n\t\t\t// later step and this transport doesn't know how to deal with them.\n\t\t\t// Also, it's important to allow people to upload files with (for\n\t\t\t// example) blacklisted names, and then rename them later in the\n\t\t\t// wizard.\n\t\t\tignorewarnings: true,\n\n\t\t\toffset: offset || 0\n\t\t} );\n\n\t\treturn params;\n\t};\n\n\t/**\n\t * Start the upload with the provided file.\n\t *\n\t * @param {File} file\n\t * @param {string} tempFileName\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.upload = function ( file, tempFileName ) {\n\t\tlet params, ext;\n\n\t\tthis.tempname = tempFileName;\n\t\t// Limit length to 240 bytes (limit hardcoded in UploadBase.php).\n\t\tif ( this.tempname.length > 240 ) {\n\t\t\text = this.tempname.split( '.' ).pop();\n\t\t\tthis.tempname = this.tempname.slice( 0, 240 - ext.length - 1 ) + '.' + ext;\n\t\t}\n\n\t\tif ( file.size > this.chunkSize ) {\n\t\t\treturn this.chunkedUpload( file );\n\t\t} else {\n\t\t\tparams = this.createParams( this.tempname );\n\t\t\tparams.file = file;\n\t\t\treturn this.post( params );\n\t\t}\n\t};\n\n\t/**\n\t * This function exists to safely chain several hundred promises without using .then() or nested\n\t * promises. We might divide a 4 GB file into 800 chunks of 5 MB each.\n\t *\n\t * In jQuery 2.x, nested promises result in nested call stacks when resolving/rejecting/notifying\n\t * the last promise in the chain and listening on the first one, and browsers have call stack\n\t * limits low enough that we previously ran into them for files around a couple hundred megabytes\n\t * (the worst is Firefox 47 with a limit of 1024 calls).\n\t *\n\t * @param {File} file\n\t * @return {jQuery.Promise} Promise which behaves identically to a regular non-chunked upload\n\t * promise from #upload\n\t */\n\tmw.FormDataTransport.prototype.chunkedUpload = function ( file ) {\n\t\tlet prevPromise = $.Deferred().resolve();\n\t\tconst deferred = $.Deferred(),\n\t\t\tfileSize = file.size,\n\t\t\tchunkSize = this.chunkSize;\n\n\t\tfor ( let off = 0; off < fileSize; off += chunkSize ) {\n\t\t\t// Capture offset in a closure\n\t\t\t// eslint-disable-next-line no-loop-func\n\t\t\t( ( offset ) => {\n\t\t\t\tconst\n\t\t\t\t\tnewPromise = $.Deferred(),\n\t\t\t\t\tisLastChunk = offset + chunkSize >= fileSize,\n\t\t\t\t\tthisChunkSize = isLastChunk ? ( fileSize % chunkSize ) : chunkSize;\n\t\t\t\tprevPromise.done( () => {\n\t\t\t\t\tthis.uploadChunk( file, offset )\n\t\t\t\t\t\t.done( isLastChunk ? deferred.resolve : newPromise.resolve )\n\t\t\t\t\t\t.fail( deferred.reject )\n\t\t\t\t\t\t.progress( ( fraction ) => {\n\t\t\t\t\t\t\t// The progress notifications give us per-chunk progress.\n\t\t\t\t\t\t\t// Calculate progress for the whole file.\n\t\t\t\t\t\t\tdeferred.notify( ( offset + fraction * thisChunkSize ) / fileSize );\n\t\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t\tprevPromise = newPromise;\n\t\t\t} )( off );\n\t\t}\n\n\t\treturn deferred.promise();\n\t};\n\n\t/**\n\t * Upload a single chunk.\n\t *\n\t * @param {File} file\n\t * @param {number} offset Offset in bytes.\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.uploadChunk = function ( file, offset ) {\n\t\tconst params = this.createParams( this.tempname, offset ),\n\t\t\tbytesAvailable = file.size;\n\n\t\tif ( this.aborted ) {\n\t\t\treturn $.Deferred().reject( 'aborted', {\n\t\t\t\terrors: [ {\n\t\t\t\t\tcode: 'aborted',\n\t\t\t\t\thtml: mw.message( 'api-error-aborted' ).parse()\n\t\t\t\t} ]\n\t\t\t} );\n\t\t}\n\n\t\t// Slice API was changed and has vendor prefix for now\n\t\t// new version now require start/end and not start/length\n\t\tlet chunk;\n\t\tif ( file.mozSlice ) {\n\t\t\tchunk = file.mozSlice( offset, offset + this.chunkSize, file.type );\n\t\t} else if ( file.webkitSlice ) {\n\t\t\tchunk = file.webkitSlice( offset, offset + this.chunkSize, file.type );\n\t\t} else {\n\t\t\tchunk = file.slice( offset, offset + this.chunkSize, file.type );\n\t\t}\n\n\t\t// only enable async if file is larger 10Mb\n\t\tif ( bytesAvailable > 10 * 1024 * 1024 ) {\n\t\t\tparams.async = true;\n\t\t}\n\n\t\t// If offset is 0, we're uploading the file from scratch. filekey may be set if we're retrying\n\t\t// the first chunk. The API errors out if a filekey is given with zero offset (as it's\n\t\t// nonsensical). TODO Why do we need to retry in this case, if we managed to upload something?\n\t\tif ( this.filekey && offset !== 0 ) {\n\t\t\tparams.filekey = this.filekey;\n\t\t}\n\t\tparams.filesize = bytesAvailable;\n\t\tparams.chunk = chunk;\n\n\t\treturn this.post( params ).then( ( response ) => {\n\t\t\tif ( response.upload && response.upload.filekey ) {\n\t\t\t\tthis.filekey = response.upload.filekey;\n\t\t\t}\n\n\t\t\tif ( response.upload && response.upload.result ) {\n\t\t\t\tswitch ( response.upload.result ) {\n\t\t\t\t\tcase 'Continue':\n\t\t\t\t\t\t// Reset retry counter\n\t\t\t\t\t\tthis.retries = 0;\n\t\t\t\t\t\t/* falls through */\n\t\t\t\t\tcase 'Success':\n\t\t\t\t\t\t// Just pass the response through.\n\t\t\t\t\t\treturn response;\n\t\t\t\t\tcase 'Poll':\n\t\t\t\t\t\t// Need to retry with checkStatus.\n\t\t\t\t\t\treturn this.retryWithMethod( 'checkStatus' );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn this.maybeRetry(\n\t\t\t\t\t'on unknown response',\n\t\t\t\t\tresponse.error ? response.error.code : 'unknown-error',\n\t\t\t\t\tresponse,\n\t\t\t\t\t'uploadChunk',\n\t\t\t\t\tfile, offset\n\t\t\t\t);\n\t\t\t}\n\t\t}, ( code, result ) => {\n\t\t\t// Ain't this some great machine readable output eh\n\t\t\tif (\n\t\t\t\tresult.errors &&\n\t\t\t\tresult.errors[ 0 ].code === 'stashfailed' &&\n\t\t\t\tresult.errors[ 0 ].html === mw.message( 'apierror-stashfailed-complete' ).parse()\n\t\t\t) {\n\t\t\t\treturn this.retryWithMethod( 'checkStatus' );\n\t\t\t}\n\n\t\t\t// Failed to upload, try again in 3 seconds\n\t\t\t// This is really dumb, we should only do this for cases where retrying has a chance to work\n\t\t\t// (so basically, network failures). If your upload was blocked by AbuseFilter you're\n\t\t\t// shafted anyway. But some server-side errors really are temporary...\n\t\t\treturn this.maybeRetry(\n\t\t\t\t'on error event',\n\t\t\t\tcode,\n\t\t\t\tresult,\n\t\t\t\t'uploadChunk',\n\t\t\t\tfile, offset\n\t\t\t);\n\t\t} );\n\t};\n\n\t/**\n\t * Handle possible retry event - rejected if maximum retries already fired.\n\t *\n\t * @param {string} contextMsg\n\t * @param {string} code\n\t * @param {Object} response\n\t * @param {string} retryMethod\n\t * @param {File} [file]\n\t * @param {number} [offset]\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.maybeRetry = function ( contextMsg, code, response, retryMethod, file, offset ) {\n\t\tthis.retries++;\n\n\t\tif ( this.tooManyRetries() ) {\n\t\t\tmw.log.warn( 'Max retries exceeded ' + contextMsg );\n\t\t\treturn $.Deferred().reject( code, response );\n\t\t} else if ( this.aborted ) {\n\t\t\treturn $.Deferred().reject( code, response );\n\t\t} else {\n\t\t\tmw.log( 'Retry #' + this.retries + ' ' + contextMsg );\n\t\t\treturn this.retryWithMethod( retryMethod, file, offset );\n\t\t}\n\t};\n\n\t/**\n\t * Have we retried too many times already?\n\t *\n\t * @return {boolean}\n\t */\n\tmw.FormDataTransport.prototype.tooManyRetries = function () {\n\t\treturn this.maxRetries > 0 && this.retries >= this.maxRetries;\n\t};\n\n\t/**\n\t * Either retry uploading or checking the status.\n\t *\n\t * @param {'uploadChunk'|'checkStatus'} methodName\n\t * @param {File} [file]\n\t * @param {number} [offset]\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.retryWithMethod = function ( methodName, file, offset ) {\n\t\tconst\n\t\t\tretryDeferred = $.Deferred(),\n\t\t\tretry = () => {\n\t\t\t\tthis[ methodName ]( file, offset ).then( retryDeferred.resolve, retryDeferred.reject );\n\t\t\t};\n\n\t\tif ( this.config.useRetryTimeout !== false ) {\n\t\t\tsetTimeout( retry, 3000 );\n\t\t} else {\n\t\t\tretry();\n\t\t}\n\n\t\treturn retryDeferred.promise();\n\t};\n\n\t/**\n\t * Check the status of the upload.\n\t *\n\t * @return {jQuery.Promise}\n\t */\n\tmw.FormDataTransport.prototype.checkStatus = function () {\n\t\tconst params = OO.cloneObject( this.formData );\n\n\t\tif ( this.aborted ) {\n\t\t\treturn $.Deferred().reject( 'aborted', {\n\t\t\t\terrors: [ {\n\t\t\t\t\tcode: 'aborted',\n\t\t\t\t\thtml: mw.message( 'api-error-aborted' ).parse()\n\t\t\t\t} ]\n\t\t\t} );\n\t\t}\n\n\t\tif ( !this.firstPoll ) {\n\t\t\tthis.firstPoll = Date.now();\n\t\t}\n\t\tparams.checkstatus = true;\n\t\tparams.filekey = this.filekey;\n\n\t\tthis.request = this.api.post( params );\n\n\t\treturn this.request.then(\n\t\t\t( response ) => {\n\t\t\t\tif ( response.upload && response.upload.result === 'Poll' ) {\n\t\t\t\t\t// If concatenation takes longer than 10 minutes give up\n\t\t\t\t\tif ( ( Date.now() - this.firstPoll ) > 10 * 60 * 1000 ) {\n\t\t\t\t\t\treturn $.Deferred().reject( 'server-error', { errors: [ {\n\t\t\t\t\t\t\tcode: 'server-error',\n\t\t\t\t\t\t\thtml: mw.message( 'api-clientside-error-timeout' ).parse()\n\t\t\t\t\t\t} ] } );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( response.upload.stage === undefined ) {\n\t\t\t\t\t\t\tmw.log.warn( 'Unable to check file\\'s status' );\n\t\t\t\t\t\t\treturn $.Deferred().reject( 'server-error', { errors: [ {\n\t\t\t\t\t\t\t\tcode: 'server-error',\n\t\t\t\t\t\t\t\thtml: mw.message( 'api-clientside-error-invalidresponse' ).parse()\n\t\t\t\t\t\t\t} ] } );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Statuses that can be returned:\n\t\t\t\t\t\t\t// * queued\n\t\t\t\t\t\t\t// * publish\n\t\t\t\t\t\t\t// * assembling\n\t\t\t\t\t\t\tthis.emit( 'update-stage', response.upload.stage );\n\t\t\t\t\t\t\treturn this.retryWithMethod( 'checkStatus' );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn response;\n\t\t\t},\n\t\t\t( code, result ) => $.Deferred().reject( code, result )\n\t\t);\n\t};\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Deed.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":51,"column":3,"nodeType":"CallExpression","endLine":55,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":86,"column":5,"nodeType":"CallExpression","endLine":88,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":108,"column":6,"nodeType":"CallExpression","endLine":110,"endColumn":9}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard's Deed step.\n\t *\n\t * @class\n\t * @extends uw.ui.Step\n\t */\n\tuw.ui.Deed = function UWUIDeed() {\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'deeds'\n\t\t);\n\n\t\tthis.addPreviousButton();\n\t\tthis.addNextButton();\n\t};\n\n\tOO.inheritClass( uw.ui.Deed, uw.ui.Step );\n\n\tuw.ui.Deed.prototype.load = function ( uploads ) {\n\t\tuw.ui.Step.prototype.load.call( this, uploads );\n\n\t\tthis.$deedsContainer = $( '<div>' ).attr( 'id', 'mwe-upwiz-deeds' );\n\t\tthis.$thumbsContainer = $( '<div>' ).attr( 'id', 'mwe-upwiz-deeds-thumbnails' );\n\n\t\tthis.$div.prepend(\n\t\t\tthis.$thumbsContainer.addClass( 'ui-helper-clearfix' ),\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-deeds-intro' )\n\t\t\t\t.msg( 'mwe-upwiz-deeds-intro', uploads.length, mw.user ),\n\t\t\tthis.$deedsContainer.addClass( 'ui-helper-clearfix' )\n\t\t);\n\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\t// hide \"next\" button, controller will only show it once license has\n\t\t\t// been selected\n\t\t\tthis.nextButton.$element.hide();\n\t\t} );\n\t};\n\n\tuw.ui.Deed.prototype.clearForm = function () {\n\t\tthis.$deedsContainer.empty();\n\t\tthis.$thumbsContainer.empty();\n\t};\n\n\t/**\n\t * @param {OO.ui.RadioSelectWidget} multiDeedRadio\n\t */\n\tuw.ui.Deed.prototype.showMultiDeedRadio = function ( multiDeedRadio ) {\n\t\tthis.$div.prepend( multiDeedRadio.$element );\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardDeedChooser} deedChooser\n\t */\n\tuw.ui.Deed.prototype.showCommonForm = function ( deedChooser ) {\n\n\t\tthis.clearForm();\n\n\t\tthis.$deedsContainer.append( deedChooser.$element );\n\t\tdeedChooser.onLayoutReady();\n\n\t\tdeedChooser.uploads.forEach( ( upload ) => {\n\t\t\tconst $element = $( '<div>' ).addClass( 'mwe-upwiz-thumbnail' );\n\n\t\t\t// Add previews and details to the DOM\n\t\t\tif ( !upload.file.fromURL ) {\n\t\t\t\t// This must match the CSS dimensions of .mwe-upwiz-thumbnail\n\t\t\t\tupload.getThumbnail( 120, 120 ).done( ( thumb ) => {\n\t\t\t\t\tmw.UploadWizard.placeThumbnail( $element, thumb );\n\t\t\t\t} );\n\n\t\t\t\tthis.$thumbsContainer.append( $element );\n\t\t\t}\n\t\t} );\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardDeedChooser[]} deedChoosers\n\t */\n\tuw.ui.Deed.prototype.showIndividualForm = function ( deedChoosers ) {\n\t\tthis.clearForm();\n\n\t\tdeedChoosers.forEach( ( deedChooser ) => {\n\t\t\tdeedChooser.uploads.forEach( ( upload ) => {\n\t\t\t\tconst $thumbContainer = $( '<div>' ).addClass( 'mwe-upwiz-deeds-individual-thumbnail' ),\n\t\t\t\t\t$element = $( '<div>' ).addClass( 'mwe-upwiz-thumbnail' );\n\n\t\t\t\t// Add previews and details to the DOM\n\t\t\t\tif ( !upload.file.fromURL ) {\n\t\t\t\t\tupload.getThumbnail( 150, 150 ).done( ( thumb ) => {\n\t\t\t\t\t\tmw.UploadWizard.placeThumbnail( $element, thumb );\n\t\t\t\t\t} );\n\n\t\t\t\t\t$thumbContainer.append( $element );\n\t\t\t\t}\n\n\t\t\t\tthis.$deedsContainer.append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'mwe-upwiz-deeds-individual' )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$thumbContainer,\n\t\t\t\t\t\t\tdeedChooser.$element\n\t\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\tdeedChooser.onLayoutReady();\n\t\t\t} );\n\t\t} );\n\t};\n\n\t/**\n\t * @param {boolean} visible\n\t */\n\tuw.ui.Deed.prototype.toggleNext = function ( visible ) {\n\t\tif ( visible ) {\n\t\t\tthis.nextButton.$element.show();\n\t\t} else {\n\t\t\tthis.nextButton.$element.hide();\n\t\t}\n\t};\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Details.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":108,"column":3,"nodeType":"CallExpression","endLine":145,"endColumn":6}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard's Details step.\n\t *\n\t * @class\n\t * @extends uw.ui.Step\n\t */\n\tuw.ui.Details = function UWUIDetails() {\n\t\tconst startDetails = () => {\n\t\t\tthis.emit( 'start-details' );\n\t\t};\n\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'details'\n\t\t);\n\n\t\tthis.nextButton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-publish-details' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', startDetails );\n\n\t\tthis.nextButtonDespiteFailures = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-next-file-despite-failures' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', () => {\n\t\t\tthis.emit( 'finalize-details-after-removal' );\n\t\t} );\n\n\t\tthis.retryButtonSomeFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-file-retry' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', startDetails );\n\n\t\tthis.retryButtonAllFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-file-retry' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', startDetails );\n\n\t\tthis.addPreviousButton();\n\t\tthis.addNextButton();\n\t};\n\n\tOO.inheritClass( uw.ui.Details, uw.ui.Step );\n\n\tuw.ui.Details.prototype.load = function ( uploads ) {\n\t\tuw.ui.Step.prototype.load.call( this, uploads );\n\n\t\tif ( mw.UploadWizard.config.wikibase.enabled && mw.UploadWizard.config.wikibase.captions ) {\n\t\t\tthis.$div.prepend(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-license-metadata ui-corner-all' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<strong>' ).text( mw.msg( 'mwe-upwiz-license-metadata-title-v2' ) ),\n\t\t\t\t\t\t' ',\n\t\t\t\t\t\t$( '<span>' ).append( mw.message( 'mwe-upwiz-license-metadata-content' ).parseDom() )\n\t\t\t\t\t\t\t// wikitext links in i18n messages don't support target=_blank, but we\n\t\t\t\t\t\t\t// really don't want to take people away from their uploads...\n\t\t\t\t\t\t\t.find( 'a' ).attr( 'target', '_blank' ).end()\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tif ( uploads.filter( this.needsPatentAgreement.bind( this ) ).length > 0 ) {\n\t\t\tthis.$div.prepend(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-patent-weapon-policy ui-corner-all' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<p>' ).text( mw.msg( 'mwe-upwiz-patent-weapon-policy' ) ),\n\t\t\t\t\t\t$( '<p>' ).append(\n\t\t\t\t\t\t\t$( '<a>' )\n\t\t\t\t\t\t\t\t.text( mw.msg( 'mwe-upwiz-patent-weapon-policy-link' ) )\n\t\t\t\t\t\t\t\t.attr( { target: '_blank', href: mw.UploadWizard.config.patents.url.weapons } )\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-macro-files' )\n\t\t\t\t.addClass( 'mwe-upwiz-filled-filelist ui-corner-all' )\n\t\t);\n\n\t\t// set default buttons visibility (can be altered in controller later)\n\t\tthis.$div.find( '.mwe-upwiz-file-next-some-failed, .mwe-upwiz-file-next-all-failed' ).hide();\n\t\tthis.$div.find( '.mwe-upwiz-file-next-all-ok' ).show();\n\t};\n\n\tuw.ui.Details.prototype.addNextButton = function () {\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\tthis.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-file-next-all-ok mwe-upwiz-file-endchoice' )\n\t\t\t\t\t.append( this.nextButton.$element )\n\t\t\t);\n\n\t\t\tthis.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-file-next-some-failed mwe-upwiz-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mwe-upwiz-file-some-failed' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tthis.nextButtonDespiteFailures,\n\t\t\t\t\t\t\t\tthis.retryButtonSomeFailed\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\n\t\t\tthis.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-file-next-all-failed mwe-upwiz-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mwe-upwiz-file-all-failed' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tthis.retryButtonAllFailed\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\t\t} );\n\t};\n\n\t/**\n\t * Hide buttons for moving to the next step.\n\t */\n\tuw.ui.Details.prototype.hideEndButtons = function () {\n\t\tthis.$div\n\t\t\t.find( '.mwe-upwiz-buttons .mwe-upwiz-file-endchoice' )\n\t\t\t.hide();\n\t};\n\n\t/**\n\t * Disable edits to the details.\n\t */\n\tuw.ui.Details.prototype.disableEdits = function () {\n\t\tthis.$div\n\t\t\t.find( '.mwe-upwiz-data' )\n\t\t\t.morphCrossfade( '.mwe-upwiz-submitting' );\n\n\t\tthis.previousButton.$element.hide();\n\t\tthis.$div.find( '.mwe-upwiz-patent-weapon-policy' ).hide();\n\t};\n\n\t/**\n\t * Re-enabled edits to the details.\n\t */\n\tuw.ui.Details.prototype.enableEdits = function () {\n\t\tthis.previousButton.$element.show();\n\t\tthis.$div.find( '.mwe-upwiz-patent-weapon-policy' ).show();\n\t};\n\n\t/**\n\t * @param {mw.UploadWizardUpload} upload\n\t * @return {boolean}\n\t */\n\tuw.ui.Details.prototype.needsPatentAgreement = function ( upload ) {\n\t\tconst extensions = mw.UploadWizard.config.patents.extensions;\n\n\t\treturn extensions.includes( upload.title.getExtension().toLowerCase() );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Thanks.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":150,"column":3,"nodeType":"CallExpression","endLine":152,"endColumn":6},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":180,"column":4,"nodeType":"CallExpression","endLine":180,"endColumn":94}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard's Thanks step.\n\t *\n\t * @class\n\t * @extends uw.ui.Step\n\t * @param {Object} config\n\t */\n\tuw.ui.Thanks = function UWUIThanks( config ) {\n\t\tthis.config = config;\n\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'thanks'\n\t\t);\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' ).attr( 'id', 'mwe-upwiz-thanks' )\n\t\t);\n\n\t\tif ( this.isObjectReferenceGiven() ) {\n\t\t\tthis.getDelayNotice().prependTo( this.$div );\n\t\t}\n\n\t\tconst thanksMessage = new OO.ui.MessageWidget( {\n\t\t\ttype: 'success',\n\t\t\tlabel: ( this.config.display && this.config.display.thanksLabel ) ?\n\t\t\t\tnew OO.ui.HtmlSnippet( this.config.display.thanksLabel ) :\n\t\t\t\tmw.msg( 'mwe-upwiz-thanks-message' ),\n\t\t\tclasses: [ 'mwe-upwiz-thanks-message' ]\n\t\t} );\n\t\tthanksMessage.$element.prependTo( this.$div );\n\n\t\tconst homeButtonTarget = this.getButtonConfig( 'homeButton', 'target' );\n\t\tlet homeButtonHref;\n\t\tif ( !homeButtonTarget ) {\n\t\t\thomeButtonHref = mw.config.get( 'wgArticlePath' ).replace( '$1', '' );\n\t\t} else if ( homeButtonTarget === 'useObjref' ) {\n\t\t\thomeButtonHref = homeButtonTarget;\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tconst homeButtonUrl = new URL( homeButtonTarget );\n\t\t\t\t// URL parsing went fine: check the protocol.\n\t\t\t\t// If `homeButtonTarget` is a wiki page in a non-main namespace,\n\t\t\t\t// it will still be parsed into a URL with protocol == namespace.\n\t\t\t\tif ( homeButtonUrl.protocol.startsWith( 'http' ) ) {\n\t\t\t\t\t// HTTP URL: as is\n\t\t\t\t\thomeButtonHref = homeButtonUrl.href;\n\t\t\t\t} else {\n\t\t\t\t\t// Page title in a non-main namespace\n\t\t\t\t\thomeButtonHref = mw.config\n\t\t\t\t\t\t.get( 'wgArticlePath' )\n\t\t\t\t\t\t.replace( '$1', homeButtonTarget );\n\t\t\t\t}\n\t\t\t} catch ( error ) {\n\t\t\t\t// Not a URL: assume a page title\n\t\t\t\thomeButtonHref = mw.config\n\t\t\t\t\t.get( 'wgArticlePath' )\n\t\t\t\t\t.replace( '$1', homeButtonTarget );\n\t\t\t}\n\t\t}\n\t\tthis.homeButton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: this.getButtonConfig( 'homeButton', 'label' ) || mw.message( 'mwe-upwiz-home' ).text(),\n\t\t\thref: homeButtonHref\n\t\t} );\n\n\t\tthis.beginButton = new OO.ui.ButtonWidget( {\n\t\t\tlabel: this.getButtonConfig( 'beginButton', 'label' ) || mw.message( 'mwe-upwiz-upload-another' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} );\n\n\t\t// TODO: make the step order configurable by campaign definitions instead of using these hacks\n\t\tlet beginButtonTarget = this.getButtonConfig( 'beginButton', 'target' );\n\t\tif ( !beginButtonTarget || ( beginButtonTarget === 'dropObjref' && !this.isObjectReferenceGiven() ) ) {\n\t\t\tthis.beginButton.on( 'click', () => {\n\t\t\t\tthis.emit( 'next-step' );\n\t\t\t} );\n\t\t} else {\n\t\t\tif ( beginButtonTarget === 'dropObjref' ) {\n\t\t\t\tbeginButtonTarget = this.dropParameterFromURL( location.href, 'updateList' );\n\t\t\t}\n\t\t\tthis.beginButton.setHref( beginButtonTarget );\n\t\t}\n\t\tthis.beginButton.on( 'click', () => {\n\t\t\tmw.DestinationChecker.clearCache();\n\t\t} );\n\n\t\tthis.buttonGroup = new OO.ui.HorizontalLayout( {\n\t\t\titems: [ this.homeButton, this.beginButton ]\n\t\t} );\n\n\t\tthis.$buttons.append( this.buttonGroup.$element );\n\t};\n\n\tOO.inheritClass( uw.ui.Thanks, uw.ui.Step );\n\n\t/**\n\t * Adds an upload to the Thanks interface.\n\t *\n\t * @param {mw.UploadWizardUpload} upload\n\t */\n\tuw.ui.Thanks.prototype.addUpload = function ( upload ) {\n\t\tconst thumbWikiText = '[[' + [\n\t\t\tupload.details.getTitle().getPrefixedText(),\n\t\t\t'thumb',\n\t\t\tupload.details.getThumbnailCaption()\n\t\t].join( '|' ) + ']]';\n\n\t\tconst $thanksDiv = $( '<div>' )\n\t\t\t.addClass( 'mwe-upwiz-thanks ui-helper-clearfix' );\n\t\tconst $thumbnailWrapDiv = $( '<div>' )\n\t\t\t.addClass( 'mwe-upwiz-thumbnail-side' )\n\t\t\t.appendTo( $thanksDiv );\n\t\tconst $thumbnailDiv = $( '<div>' )\n\t\t\t.addClass( 'mwe-upwiz-thumbnail' )\n\t\t\t.appendTo( $thumbnailWrapDiv );\n\t\tconst $thumbnailCaption = $( '<div>' )\n\t\t\t.css( { 'text-align': 'left', 'font-size': 'small' } )\n\t\t\t.appendTo( $thumbnailWrapDiv );\n\t\tconst $thumbnailLink = $( '<a>' )\n\t\t\t.text( upload.details.getTitle().getMainText() )\n\t\t\t.appendTo( $thumbnailCaption );\n\n\t\t$( '<div>' )\n\t\t\t.addClass( 'mwe-upwiz-data' )\n\t\t\t.appendTo( $thanksDiv )\n\t\t\t.append(\n\t\t\t\tthis.makeReadOnlyInput( thumbWikiText, mw.message( 'mwe-upwiz-thanks-wikitext' ).text(), true ),\n\t\t\t\tthis.makeReadOnlyInput( upload.imageinfo.descriptionurl, mw.message( 'mwe-upwiz-thanks-url' ).text() )\n\t\t\t);\n\n\t\t// This must match the CSS dimensions of .mwe-upwiz-thumbnail\n\t\tupload.getThumbnail( 200, 200 ).done( ( thumb ) => {\n\t\t\tmw.UploadWizard.placeThumbnail( $thumbnailDiv, thumb );\n\t\t} );\n\n\t\t// Set the thumbnail links so that they point to the image description page\n\t\t$thumbnailLink.add( $thumbnailDiv.find( '.mwe-upwiz-thumbnail-link' ) ).attr( {\n\t\t\thref: upload.imageinfo.descriptionurl,\n\t\t\ttarget: '_blank'\n\t\t} );\n\n\t\tthis.$div.find( '.mwe-upwiz-buttons' ).before( $thanksDiv );\n\t};\n\n\t/**\n\t * Make an mw.widgets.CopyTextLayout, which features a button\n\t * to copy the text provided.\n\t *\n\t * @param {string} value Text it will contain\n\t * @param {string} label Label\n\t * @param {string} [useEditFont] Use edit font (for wikitext values)\n\t * @return {jQuery}\n\t */\n\tuw.ui.Thanks.prototype.makeReadOnlyInput = function ( value, label, useEditFont ) {\n\t\tconst copyText = new mw.widgets.CopyTextLayout( {\n\t\t\talign: 'top',\n\t\t\tlabel: label,\n\t\t\tcopyText: value\n\t\t} );\n\n\t\tif ( useEditFont ) {\n\t\t\tcopyText.textInput.$element.addClass( 'mw-editfont-' + mw.user.options.get( 'editfont' ) );\n\t\t}\n\n\t\treturn copyText.$element;\n\t};\n\n\t/**\n\t * Get button configuration options from a campaign definition\n\t *\n\t * @param {string} buttonName name of the button as defined in campaign configuration\n\t * @param {string} configField name of the button's attributes\n\t * @return {Object|undefined}\n\t */\n\tuw.ui.Thanks.prototype.getButtonConfig = function ( buttonName, configField ) {\n\t\tif ( !this.config.display || !this.config.display[ buttonName ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn this.config.display[ buttonName ][ configField ];\n\t};\n\n\t/**\n\t * Drops a parameter from the given url\n\t *\n\t * @param {string} url URL from which to drop a parameter\n\t * @param {string} paramName parameter to be dropped\n\t * @return {string}\n\t * @private\n\t */\n\tuw.ui.Thanks.prototype.dropParameterFromURL = function ( url, paramName ) {\n\t\tconst newUrl = new URL( url );\n\t\tnewUrl.searchParams.delete( paramName );\n\t\tnewUrl.searchParams.delete( paramName + '[]' );\n\t\treturn newUrl.toString();\n\t};\n\n\tuw.ui.Thanks.prototype.getDelayNotice = function () {\n\t\tconst $delayNotice = $( '<p>' )\n\t\t\t.addClass( 'mwe-upwiz-thanks-update-delay' )\n\t\t\t.msg( 'mwe-upwiz-objref-notice-update-delay' );\n\n\t\tif ( this.config.display && this.config.display.noticeUpdateDelay ) {\n\t\t\t$delayNotice.html( this.config.display.noticeUpdateDelay );\n\t\t}\n\t\treturn $delayNotice;\n\t};\n\n\tuw.ui.Thanks.prototype.isObjectReferenceGiven = function () {\n\t\treturn this.config.defaults && this.config.defaults.objref !== '';\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Tutorial.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":126,"column":3,"nodeType":"CallExpression","endLine":132,"endColumn":6}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":84,"column":24,"nodeType":"CallExpression","endLine":84,"endColumn":55,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":88,"column":3,"nodeType":"CallExpression","endLine":88,"endColumn":38,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Checkbox with popup information.\n\t *\n\t * @param {Object} config\n\t */\n\tfunction PopupCheckboxInputWidget( config ) {\n\t\t// Parent constructor\n\t\tPopupCheckboxInputWidget.super.call( this, config );\n\n\t\t// Mixin constructors\n\t\tOO.ui.mixin.PopupElement.call( this, config );\n\n\t\t// Events\n\t\tthis.connect( this, { change: 'onChange' } );\n\n\t\t// Initialization\n\t\tthis.$element\n\t\t\t.addClass( 'oo-ui-popupCheckboxInputWidget' )\n\t\t\t.attr( 'aria-haspopup', 'true' )\n\t\t\t.append( this.popup.$element );\n\t}\n\tOO.inheritClass( PopupCheckboxInputWidget, OO.ui.CheckboxInputWidget );\n\tOO.mixinClass( PopupCheckboxInputWidget, OO.ui.mixin.PopupElement );\n\tPopupCheckboxInputWidget.prototype.onChange = function () {\n\t\tthis.popup.toggle( this.isSelected() );\n\t};\n\n\t/**\n\t * Represents the UI for the wizard's Tutorial step.\n\t *\n\t * @class\n\t * @extends uw.ui.Step\n\t */\n\tuw.ui.Tutorial = function UWUITutorial() {\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'tutorial'\n\t\t);\n\n\t\t// 'Skip tutorial' checkbox\n\t\tthis.skipCheckbox = new PopupCheckboxInputWidget( {\n\t\t\tid: 'mwe-upwiz-skip',\n\t\t\t// Add a friendly \"Here's how to get it back\" tooltip for users who check the \"Skip next time\" checkbox\n\t\t\tpopup: {\n\t\t\t\t$content: $( '<p>' ).msg(\n\t\t\t\t\t'mwe-upwiz-tooltip-skiptutorial',\n\t\t\t\t\tmw.config.get( 'wgServer' ) + mw.util.getUrl( 'Special:Preferences' ) + '#mw-prefsection-uploads',\n\t\t\t\t\tmw.message( 'prefs-uploads' ).text(),\n\t\t\t\t\tmw.message( 'prefs-upwiz-interface' ).text()\n\t\t\t\t),\n\t\t\t\tautoClose: false,\n\t\t\t\tpadded: true\n\t\t\t}\n\t\t} );\n\t\tthis.skipCheckboxLabel = new OO.ui.LabelWidget( {\n\t\t\tinput: this.skipCheckbox,\n\t\t\tlabel: mw.message( 'mwe-upwiz-skip-tutorial-future' ).text()\n\t\t} );\n\n\t\tthis.skipCheckbox.on( 'change', () => {\n\t\t\tthis.emit( 'skip-tutorial-click', this.skipCheckbox.isSelected() );\n\t\t} );\n\n\t\t// grab the tutorial HTML that was injected into this document\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\tthis.$tutorialHtml = $( '#mwe-upwiz-tutorial-html' );\n\n\t\t// Helpdesk link click\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( '#mwe-upwiz-tutorial-helpdesk' ).on( 'click', () => {\n\t\t\tthis.emit( 'helpdesk-click' );\n\t\t} );\n\n\t\tthis.addPreviousButton();\n\t\tthis.addNextButton();\n\t};\n\n\tOO.inheritClass( uw.ui.Tutorial, uw.ui.Step );\n\n\tuw.ui.Tutorial.prototype.setSelected = function ( selected ) {\n\t\tthis.skipCheckbox.setSelected( selected );\n\t};\n\n\tuw.ui.Tutorial.prototype.load = function ( uploads ) {\n\t\tuw.ui.Step.prototype.load.call( this, uploads );\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-tutorial' )\n\t\t\t\t.append(\n\t\t\t\t\t// TODO move this to JavaScript, too.\n\t\t\t\t\tthis.$tutorialHtml.show()\n\t\t\t\t)\n\t\t);\n\n\t\tthis.skipCheckbox.popup.updateDimensions();\n\t};\n\n\tuw.ui.Tutorial.prototype.addNextButton = function () {\n\t\tthis.nextButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-button-next' ],\n\t\t\tlabel: mw.message( 'mwe-upwiz-next' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', () => {\n\t\t\tthis.emit( 'next-step' );\n\t\t} );\n\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\tthis.$buttons.append(\n\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\titems: [ this.skipCheckbox, this.skipCheckboxLabel, this.nextButton ]\n\t\t\t\t} ).$element\n\t\t\t);\n\t\t} );\n\t};\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/steps/uw.ui.Upload.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":334,"column":6,"nodeType":"CallExpression","endLine":336,"endColumn":9},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":344,"column":3,"nodeType":"CallExpression","endLine":392,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":528,"column":3,"nodeType":"CallExpression","endLine":530,"endColumn":6}],"suppressedMessages":[{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Positional selector extensions are not allowed","line":228,"column":4,"nodeType":"CallExpression","endLine":228,"endColumn":39,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Positional selector extensions are not allowed","line":230,"column":4,"nodeType":"CallExpression","endLine":230,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard's Upload step.\n\t *\n\t * @class\n\t * @extends uw.ui.Step\n\t * @param {Object} config UploadWizard config object.\n\t */\n\tuw.ui.Upload = function UWUIUpload( config ) {\n\t\tthis.config = config;\n\n\t\tuw.ui.Step.call(\n\t\t\tthis,\n\t\t\t'file'\n\t\t);\n\n\t\tthis.$addFileContainer = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-add-file-container' )\n\t\t\t.addClass( 'mwe-upwiz-add-files-0' );\n\n\t\tthis.$uploadCtrl = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-upload-ctrls' )\n\t\t\t.addClass( 'mwe-upwiz-file ui-helper-clearfix' )\n\t\t\t.append( this.$addFileContainer );\n\n\t\tthis.addFile = new OO.ui.SelectFileInputWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-add-file' ],\n\t\t\tmultiple: true,\n\t\t\tshowDropTarget: true,\n\t\t\tbutton: {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-add-file-0-free' ).text(),\n\t\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t\t}\n\t\t} );\n\t\tthis.addFile.on( 'change', ( files ) => {\n\t\t\tthis.emit( 'files-added', files );\n\t\t\tthis.addFile.setValue( null );\n\t\t} );\n\n\t\tthis.$addFileContainer.append( this.addFile.$element );\n\n\t\tif ( this.isFlickrImportEnabled() ) {\n\t\t\tthis.$flickrAddFileContainer = $( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-upload-ctrl-flickr-container' );\n\n\t\t\tthis.$uploadCenterDivide = $( '<p>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-upload-ctr-divide' )\n\t\t\t\t.text( mw.message( 'mwe-upwiz-add-flickr-or' ).text() );\n\n\t\t\tthis.addFlickrFile = new OO.ui.ButtonWidget( {\n\t\t\t\tid: 'mwe-upwiz-add-flickr-file',\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-add-file-flickr' ).text(),\n\t\t\t\tflags: 'progressive'\n\t\t\t} ).on( 'click', () => {\n\t\t\t\tthis.flickrInterfaceInit();\n\t\t\t} );\n\n\t\t\tthis.$flickrAddFileContainer.append(\n\t\t\t\tthis.$uploadCenterDivide,\n\t\t\t\tthis.addFlickrFile.$element\n\t\t\t);\n\n\t\t\tthis.$addFileContainer\n\t\t\t\t.append( this.$flickrAddFileContainer );\n\n\t\t\tthis.$flickrSelectList = $( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-flickr-select-list' );\n\n\t\t\tthis.$flickrSelectListContainer = $( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-flickr-select-list-container' )\n\t\t\t\t.addClass( 'ui-corner-all' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.text( mw.message(\n\t\t\t\t\t\t\t'mwe-upwiz-multi-file-select2',\n\t\t\t\t\t\t\tconfig.maxFlickrUploads\n\t\t\t\t\t\t) ),\n\t\t\t\t\tthis.$flickrSelectList\n\t\t\t\t);\n\n\t\t\t// Button to move on & upload the files that were selected\n\t\t\tthis.flickrSelectButton = new OO.ui.ButtonWidget( {\n\t\t\t\tid: 'mwe-upwiz-select-flickr',\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-add-file-0-free' ).text(),\n\t\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t\t} );\n\t\t\tthis.$flickrSelectListContainer.append( this.flickrSelectButton.$element );\n\n\t\t\t// A container holding a form\n\t\t\tthis.$flickrContainer = $( '<div>' ).attr( 'id', 'mwe-upwiz-upload-add-flickr-container' );\n\n\t\t\t// Form whose submit event will be listened to and prevented\n\t\t\tthis.$flickrForm = $( '<form>' ).attr( 'id', 'mwe-upwiz-flickr-url-form' )\n\t\t\t\t.appendTo( this.$flickrContainer )\n\t\t\t\t.on( 'submit', () => {\n\t\t\t\t\tconst checker = new mw.FlickrChecker( this, this.flickrSelectButton );\n\t\t\t\t\tthis.flickrButton.setDisabled( true );\n\t\t\t\t\tthis.flickrChecker( checker );\n\t\t\t\t\t// TODO Any particular reason to stopPropagation ?\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\n\t\t\t// The input that will hold a flickr URL entered by the user; will be appended to a form\n\t\t\tthis.flickrInput = new OO.ui.TextInputWidget( {\n\t\t\t\tplaceholder: mw.message( 'mwe-upwiz-flickr-input-placeholder' ).text()\n\t\t\t} );\n\n\t\t\tthis.flickrButton = new OO.ui.ButtonInputWidget( {\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-add-flickr' ).text(),\n\t\t\t\tflags: [ 'progressive', 'primary' ],\n\t\t\t\ttype: 'submit'\n\t\t\t} );\n\n\t\t\tthis.flickrField = new OO.ui.ActionFieldLayout(\n\t\t\t\tthis.flickrInput, this.flickrButton, {\n\t\t\t\t\talign: 'top',\n\t\t\t\t\tclasses: [ 'mwe-upwiz-flickr-field' ]\n\t\t\t\t}\n\t\t\t);\n\n\t\t\tthis.$flickrForm.append( this.flickrField.$element );\n\n\t\t\t// Add disclaimer\n\t\t\t$( '<div>' ).attr( 'id', 'mwe-upwiz-flickr-disclaimer' )\n\t\t\t\t.append(\n\t\t\t\t\tmw.message( 'mwe-upwiz-flickr-disclaimer1' ).parseDom(),\n\t\t\t\t\t$( '<br>' ), mw.message( 'mwe-upwiz-flickr-disclaimer2' ).parseDom()\n\t\t\t\t)\n\t\t\t\t.appendTo( this.$flickrContainer );\n\t\t}\n\n\t\tthis.nextStepButtonAllOk = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-next-file' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', () => {\n\t\t\tthis.emit( 'next-step' );\n\t\t} );\n\n\t\tthis.retryButtonSomeFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-file-retry' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', () => {\n\t\t\tthis.hideEndButtons();\n\t\t\tthis.emit( 'retry' );\n\t\t} );\n\n\t\tthis.nextStepButtonSomeFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-next-file-despite-failures' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', () => {\n\t\t\tthis.emit( 'next-step' );\n\t\t} );\n\n\t\tthis.retryButtonAllFailed = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-file-retry' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} ).on( 'click', () => {\n\t\t\tthis.hideEndButtons();\n\t\t\tthis.emit( 'retry' );\n\t\t} );\n\n\t\tthis.$fileList = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-filelist' )\n\t\t\t.addClass( 'ui-corner-all' );\n\n\t\tthis.$progress = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-progress' )\n\t\t\t.addClass( 'ui-helper-clearfix' );\n\n\t\tthis.addPreviousButton();\n\t\tthis.addNextButton();\n\t};\n\n\tOO.inheritClass( uw.ui.Upload, uw.ui.Step );\n\n\tuw.ui.Upload.prototype.showProgressBar = function () {\n\t\tthis.$progress.show();\n\t};\n\n\t/**\n\t * Updates the interface based on the number of uploads.\n\t *\n\t * @param {boolean} haveUploads Whether there are any uploads at all.\n\t * @param {boolean} fewerThanMax Whether we can add more uploads.\n\t */\n\tuw.ui.Upload.prototype.updateFileCounts = function ( haveUploads, fewerThanMax ) {\n\t\tthis.$fileList.toggleClass( 'mwe-upwiz-filled-filelist', haveUploads );\n\t\tthis.$addFileContainer.toggleClass( 'mwe-upwiz-add-files-0', !haveUploads );\n\n\t\tthis.setAddButtonText( haveUploads );\n\n\t\tif ( haveUploads ) {\n\t\t\t// we have uploads ready to go, so allow us to proceed\n\t\t\tthis.$addFileContainer.add( this.$buttons ).show();\n\n\t\t\tif ( this.isFlickrImportEnabled() ) {\n\t\t\t\tthis.$uploadCenterDivide.hide();\n\t\t\t}\n\n\t\t\t// fix the rounded corners on file elements.\n\t\t\t// we want them to be rounded only when their edge touched the top or bottom of the filelist.\n\t\t\tthis.$fileListings = this.$fileList.find( '.filled' );\n\n\t\t\tthis.$visibleFileListings = this.$fileListings.find( '.mwe-upwiz-visible-file' );\n\t\t\tthis.$visibleFileListings.removeClass( 'ui-corner-top ui-corner-bottom' );\n\t\t\tthis.$visibleFileListings.first().addClass( 'ui-corner-top' );\n\t\t\tthis.$visibleFileListings.last().addClass( 'ui-corner-bottom' );\n\t\t\tthis.showNoticeForImageMetadata( true );\n\n\t\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t\tthis.$fileListings.filter( ':odd' ).addClass( 'odd' );\n\t\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t\tthis.$fileListings.filter( ':even' ).removeClass( 'odd' );\n\t\t} else {\n\t\t\tthis.hideEndButtons();\n\t\t\tthis.showNoticeForImageMetadata( false );\n\n\t\t\tif ( this.isFlickrImportEnabled() ) {\n\t\t\t\tthis.$uploadCenterDivide.show();\n\t\t\t}\n\t\t}\n\n\t\tthis.addFile.setDisabled( !fewerThanMax );\n\n\t\tif ( this.isFlickrImportEnabled() ) {\n\t\t\tthis.addFlickrFile.setDisabled( !fewerThanMax );\n\t\t}\n\t};\n\n\t/**\n\t * Changes the initial centered invitation button to something like \"add another file\"\n\t *\n\t * @param {boolean} more\n\t */\n\tuw.ui.Upload.prototype.setAddButtonText = function ( more ) {\n\t\tlet msg = 'mwe-upwiz-add-file-',\n\t\t\tfmsg = 'mwe-upwiz-add-file-flickr';\n\n\t\tif ( more ) {\n\t\t\tmsg += 'n';\n\t\t\tfmsg += '-n';\n\t\t} else {\n\t\t\tmsg += '0-free';\n\t\t}\n\n\t\tthis.addFile.selectButton.setLabel( mw.message( msg ).text() );\n\n\t\t// if Flickr uploading is available to this user, show the \"add more files from flickr\" button\n\t\tif ( this.isFlickrImportEnabled() ) {\n\t\t\t// changes the flickr add button to \"add more files from flickr\" if necessary.\n\t\t\tthis.addFlickrFile.setLabel( mw.message( fmsg ).text() );\n\t\t\t// jQuery likes to restore the wrong 'display' value when doing .show()\n\t\t\tthis.$flickrAddFileContainer.css( 'display', '' );\n\t\t}\n\t};\n\n\tuw.ui.Upload.prototype.load = function ( uploads ) {\n\t\tuw.ui.Step.prototype.load.call( this, uploads );\n\n\t\tif ( uploads.length === 0 ) {\n\t\t\tthis.$fileList.removeClass( 'mwe-upwiz-filled-filelist' );\n\t\t\tthis.$addFileContainer.show();\n\t\t}\n\n\t\tconst $noticeMessage = $( '<span>' )\n\t\t\t.append(\n\t\t\t\t$( '<strong>' ).text( mw.message( 'mwe-upwiz-metadata-notice-header' ).text() ),\n\t\t\t\t$( '<br>' ),\n\t\t\t\tmw.message( 'mwe-upwiz-metadata-notice-description' ).parseDom()\n\t\t\t);\n\n\t\tthis.notice = new OO.ui.MessageWidget( {\n\t\t\ttype: 'notice',\n\t\t\ticon: 'pageSettings',\n\t\t\tclasses: [ 'mwe-upwiz-metadata-notice' ],\n\t\t\tlabel: $noticeMessage\n\t\t} );\n\n\t\tthis.$div.prepend(\n\t\t\t$( '<div>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-files' )\n\t\t\t\t.append(\n\t\t\t\t\tthis.$flickrSelectListContainer,\n\t\t\t\t\tthis.$fileList,\n\t\t\t\t\tthis.$uploadCtrl,\n\t\t\t\t\tthis.notice.$element\n\t\t\t\t)\n\t\t);\n\n\t\tthis.displayUploads( uploads );\n\t};\n\n\tuw.ui.Upload.prototype.displayUploads = function ( uploads ) {\n\t\tlet thumbPromise,\n\t\t\t$uploadInterfaceDivs = $( [] );\n\n\t\tuploads.forEach( ( upload ) => {\n\t\t\t// We'll attach all interfaces to the DOM at once rather than one-by-one, for better\n\t\t\t// performance\n\t\t\t$uploadInterfaceDivs = $uploadInterfaceDivs.add( upload.ui.$div );\n\t\t} );\n\n\t\t// Attach all interfaces to the DOM\n\t\tthis.$fileList.append( $uploadInterfaceDivs );\n\n\t\t// Display thumbnails, but not all at once because they're somewhat expensive to generate.\n\t\t// This will wait for each thumbnail to be complete before starting the next one.\n\t\tthumbPromise = $.Deferred().resolve();\n\t\tuploads.forEach( ( upload ) => {\n\t\t\tthumbPromise = thumbPromise.then( () => {\n\t\t\t\tconst deferred = $.Deferred();\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\tif ( this.movedFrom ) {\n\t\t\t\t\t\t// We're no longer displaying any of these thumbnails, stop\n\t\t\t\t\t\tdeferred.reject();\n\t\t\t\t\t}\n\t\t\t\t\tupload.ui.showThumbnail().done( () => {\n\t\t\t\t\t\tdeferred.resolve();\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t\treturn deferred.promise();\n\t\t\t} );\n\t\t} );\n\t};\n\n\tuw.ui.Upload.prototype.addNextButton = function () {\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\tthis.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-file-next-all-ok mwe-upwiz-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mwe-upwiz-file-all-ok' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tthis.nextStepButtonAllOk\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\n\t\t\tthis.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-file-next-some-failed mwe-upwiz-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mwe-upwiz-file-some-failed' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tthis.retryButtonSomeFailed,\n\t\t\t\t\t\t\t\tthis.nextStepButtonSomeFailed\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\n\t\t\tthis.$buttons.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'mwe-upwiz-file-next-all-failed mwe-upwiz-file-endchoice' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\tnew OO.ui.HorizontalLayout( {\n\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\tnew OO.ui.LabelWidget( {\n\t\t\t\t\t\t\t\t\tlabel: mw.message( 'mwe-upwiz-file-all-failed' ).text()\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t\tthis.retryButtonAllFailed\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} ).$element\n\t\t\t\t\t)\n\t\t\t);\n\n\t\t\tthis.$buttons.append( this.$progress );\n\t\t} );\n\t};\n\n\t/**\n\t * Hide the buttons for moving to the next step.\n\t */\n\tuw.ui.Upload.prototype.hideEndButtons = function () {\n\t\tthis.$div\n\t\t\t.find( '.mwe-upwiz-buttons .mwe-upwiz-file-endchoice' )\n\t\t\t.hide();\n\t};\n\n\t/**\n\t * @param {boolean} show\n\t */\n\tuw.ui.Upload.prototype.showNoticeForImageMetadata = function ( show ) {\n\t\tthis.$div.find( '.mwe-upwiz-metadata-notice' ).toggle( show );\n\t};\n\n\t/**\n\t * Shows an error dialog informing the user that some uploads have been omitted\n\t * since they went over the max files limit.\n\t *\n\t * @param {number} filesUploaded The number of files that have been attempted to upload\n\t */\n\tuw.ui.Upload.prototype.showTooManyFilesError = function ( filesUploaded ) {\n\t\tmw.errorDialog(\n\t\t\tmw.message(\n\t\t\t\t'mwe-upwiz-too-many-files-text',\n\t\t\t\tthis.config.maxUploads,\n\t\t\t\tfilesUploaded\n\t\t\t).text(),\n\t\t\tmw.message( 'mwe-upwiz-too-many-files' ).text()\n\t\t);\n\t};\n\n\t/**\n\t * Shows an error dialog informing the user that an upload omitted because\n\t * it is too large.\n\t *\n\t * @param {number} maxSize The max upload file size\n\t * @param {number} size The actual upload file size\n\t */\n\tuw.ui.Upload.prototype.showFileTooLargeError = function ( maxSize, size ) {\n\t\tmw.errorDialog(\n\t\t\tmw.message(\n\t\t\t\t'mwe-upwiz-file-too-large-text',\n\t\t\t\tuw.units.bytes( maxSize ),\n\t\t\t\tuw.units.bytes( size )\n\t\t\t).text(),\n\t\t\tmw.message( 'mwe-upwiz-file-too-large' ).text()\n\t\t);\n\t};\n\n\t/**\n\t * @param {string} filename\n\t * @param {string} extension\n\t */\n\tuw.ui.Upload.prototype.showBadExtensionError = function ( filename, extension ) {\n\t\tconst $errorMessage = $( '<p>' ).msg( 'mwe-upwiz-upload-error-bad-filename-extension', extension );\n\t\tthis.showFilenameError( $errorMessage );\n\t};\n\n\tuw.ui.Upload.prototype.showMissingExtensionError = function () {\n\t\tconst $errorMessage = $( '<p>' ).msg( 'mwe-upwiz-upload-error-bad-filename-no-extension' );\n\t\tthis.showFilenameError(\n\t\t\t$( '<div>' ).append(\n\t\t\t\t$errorMessage,\n\t\t\t\t$( '<p>' ).msg( 'mwe-upwiz-allowed-filename-extensions' ),\n\t\t\t\t$( '<blockquote>' ).append( $( '<tt>' ).append(\n\t\t\t\t\tmw.UploadWizard.config.fileExtensions.join( ' ' )\n\t\t\t\t) )\n\t\t\t)\n\t\t);\n\t};\n\n\t/**\n\t * @param {string} filename\n\t * @param {string} basename\n\t */\n\tuw.ui.Upload.prototype.showDuplicateError = function ( filename, basename ) {\n\t\tthis.showFilenameError( $( '<p>' ).msg( 'mwe-upwiz-upload-error-duplicate-filename-error', basename ) );\n\t};\n\n\t/**\n\t * @param {string} filename\n\t */\n\tuw.ui.Upload.prototype.showUnparseableFilenameError = function ( filename ) {\n\t\tthis.showFilenameError( mw.msg( 'mwe-upwiz-unparseable-filename', filename ) );\n\t};\n\n\t/**\n\t * Shows an error dialog informing the user that an upload has been omitted\n\t * over its filename.\n\t *\n\t * @param {jQuery|string} message The error message\n\t */\n\tuw.ui.Upload.prototype.showFilenameError = function ( message ) {\n\t\tmw.errorDialog( message );\n\t};\n\n\t/**\n\t * Checks whether flickr import is enabled and the current user has the rights to use it\n\t *\n\t * @return {boolean}\n\t */\n\tuw.ui.Upload.prototype.isFlickrImportEnabled = function () {\n\t\treturn this.config.UploadFromUrl && this.config.flickrApiKey !== '';\n\t};\n\n\t/**\n\t * Initiates the Interface to upload media from Flickr.\n\t * Called when the user clicks on the 'Add images from Flickr' button.\n\t */\n\tuw.ui.Upload.prototype.flickrInterfaceInit = function () {\n\t\t// Hide containers for selecting files, and show the flickr interface instead\n\t\tthis.$addFileContainer.hide();\n\t\tthis.$flickrAddFileContainer.hide();\n\t\tthis.$flickrContainer.show();\n\t\tthis.flickrSelectButton.$element.show();\n\t\tthis.flickrButton.setDisabled( false );\n\n\t\t// Insert form into the page\n\t\tthis.$div.find( '#mwe-upwiz-files' ).prepend( this.$flickrContainer );\n\n\t\tthis.flickrInput.focus();\n\t};\n\n\t/**\n\t * Responsible for fetching license of the provided media.\n\t *\n\t * @param {mw.FlickrChecker} checker\n\t */\n\tuw.ui.Upload.prototype.flickrChecker = function ( checker ) {\n\t\tconst flickrInputUrl = this.flickrInput.getValue();\n\n\t\tchecker.getLicenses().done( () => {\n\t\t\tchecker.checkFlickr( flickrInputUrl );\n\t\t} );\n\t};\n\n\t/**\n\t * Reset the interface if there is a problem while fetching the images from\n\t * the URL entered by the user.\n\t */\n\tuw.ui.Upload.prototype.flickrInterfaceReset = function () {\n\t\t// first destroy it completely, then reshow the add button\n\t\tthis.flickrInterfaceDestroy();\n\t\tthis.flickrButton.setDisabled( false );\n\t\tthis.$flickrContainer.show();\n\t\tthis.flickrSelectButton.$element.show();\n\t};\n\n\t/**\n\t * Removes the flickr interface.\n\t */\n\tuw.ui.Upload.prototype.flickrInterfaceDestroy = function () {\n\t\tthis.flickrInput.setValue( '' );\n\t\tthis.$flickrSelectList.empty();\n\t\tthis.$flickrSelectListContainer.off().hide();\n\t\tthis.$flickrContainer.hide();\n\t\tthis.flickrButton.setDisabled( true );\n\t\tthis.flickrSelectButton.$element.hide();\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/uw.ui.Step.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":111,"column":3,"nodeType":"CallExpression","endLine":113,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":120,"column":3,"nodeType":"CallExpression","endLine":122,"endColumn":6},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":166,"column":12,"nodeType":"CallExpression","endLine":166,"endColumn":90},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":180,"column":7,"nodeType":"CallExpression","endLine":180,"endColumn":61},{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":197,"column":5,"nodeType":"CallExpression","endLine":197,"endColumn":57}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":39,"column":3,"nodeType":"CallExpression","endLine":39,"endColumn":28,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":73,"column":18,"nodeType":"CallExpression","endLine":73,"endColumn":27,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":84,"column":3,"nodeType":"CallExpression","endLine":84,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":136,"column":35,"nodeType":"CallExpression","endLine":136,"endColumn":106,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":142,"column":4,"nodeType":"CallExpression","endLine":142,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":176,"column":11,"nodeType":"CallExpression","endLine":176,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Selector extensions are not allowed","line":182,"column":7,"nodeType":"CallExpression","endLine":182,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-unused-expressions","severity":2,"message":"Expected an assignment or function call and instead saw an expression.","line":221,"column":3,"nodeType":"ExpressionStatement","messageId":"unusedExpression","endLine":221,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents a generic UI for a step.\n\t *\n\t * @class\n\t * @mixes OO.EventEmitter\n\t * @param {string} name The name of this step\n\t */\n\tuw.ui.Step = function UWUIStep( name ) {\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.name = name;\n\n\t\tthis.$buttons = $( '<div>' ).addClass( 'mwe-upwiz-buttons' );\n\n\t\tthis.$div = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-stepdiv-' + this.name )\n\t\t\t.addClass( 'mwe-upwiz-stepdiv' )\n\t\t\t.hide();\n\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( '#mwe-upwiz-content' ).append( this.$div );\n\n\t\tthis.nextButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-button-next' ],\n\t\t\tlabel: mw.message( 'mwe-upwiz-next' ).text(),\n\t\t\tflags: [ 'progressive', 'primary' ]\n\t\t} ).on( 'click', () => {\n\t\t\tthis.emit( 'next-step' );\n\t\t} );\n\t\tthis.previousButton = new OO.ui.ButtonWidget( {\n\t\t\tclasses: [ 'mwe-upwiz-button-previous' ],\n\t\t\tlabel: mw.message( 'mwe-upwiz-previous' ).text()\n\t\t} ).on( 'click', () => {\n\t\t\tthis.emit( 'previous-step' );\n\t\t} );\n\n\t\t// this will make sure that buttons will only be added if they've been\n\t\t// set in the controller, otherwise there's nowhere to go...\n\t\tthis.nextButtonPromise = $.Deferred();\n\t\tthis.previousButtonPromise = $.Deferred();\n\n\t\tthis.$errorCount = $( '<div>' ).attr( 'id', 'mwe-upwiz-details-error-count' );\n\t\tthis.$buttons.append( this.$errorCount );\n\t};\n\n\tOO.mixinClass( uw.ui.Step, OO.EventEmitter );\n\n\t/**\n\t * Initialize this step.\n\t *\n\t * @param {mw.UploadWizardUpload[]} uploads\n\t */\n\tuw.ui.Step.prototype.load = function ( uploads ) {\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\tconst offset = $( 'h1' ).first().offset();\n\n\t\tthis.movedFrom = false;\n\n\t\tthis.uploads = uploads;\n\t\tthis.$div.append( this.$buttons ).show();\n\n\t\t// clear any errors that may have been visible\n\t\tthis.updateErrorSummary();\n\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t$( 'html, body' ).animate( {\n\t\t\tscrollTop: offset.top,\n\t\t\tscrollLeft: offset.left\n\t\t}, 'slow' );\n\t};\n\n\t/**\n\t * Cleanup this step.\n\t */\n\tuw.ui.Step.prototype.unload = function () {\n\t\tthis.movedFrom = true;\n\n\t\tthis.$div.children().detach();\n\t};\n\n\tuw.ui.Step.prototype.enableNextButton = function () {\n\t\tthis.nextButtonPromise.resolve();\n\t};\n\n\tuw.ui.Step.prototype.enablePreviousButton = function () {\n\t\tthis.previousButtonPromise.resolve();\n\t};\n\n\t/**\n\t * Add a 'next' button to the step's button container\n\t */\n\tuw.ui.Step.prototype.addNextButton = function () {\n\t\tthis.nextButtonPromise.done( () => {\n\t\t\tthis.$buttons.append( this.nextButton.$element );\n\t\t} );\n\t};\n\n\t/**\n\t * Add a 'previous' button to the step's button container\n\t */\n\tuw.ui.Step.prototype.addPreviousButton = function () {\n\t\tthis.previousButtonPromise.done( () => {\n\t\t\tthis.$buttons.append( this.previousButton.$element );\n\t\t} );\n\t};\n\n\t/**\n\t * Show errors/warnings/notices in the form.\n\t * Some pages can be vertically long, so sometimes it is not obvious there are errors above.\n\t * This counts them and puts the count right next to the submit button,\n\t * so it should be obvious to the user they need to fix things.\n\t * This is a bit of a hack. We should already know how many errors there are, and where.\n\t * This method also opens up collapsed elements if the form has errors.\n\t */\n\n\tuw.ui.Step.prototype.updateErrorSummary = function () {\n\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\tconst getElements = ( kind ) => this.$div.find( '.mwe-upwiz-fieldLayout-' + kind ).filter( ':visible' );\n\t\tconst uploadCount = ( this.uploads || [] ).length;\n\n\t\tconst scrollToFirst = ( $elements ) => {\n\t\t\t// Immediately stop existing animations, then scroll to error\n\t\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\t\t$( 'html, body' ).stop().animate( { scrollTop: $elements.eq( 0 ).offset().top - 50 }, 'slow' );\n\t\t};\n\n\t\tconst updateSummary = ( kind, message, $elements ) => {\n\t\t\tconst errorCount = $elements.length;\n\n\t\t\t// reset to pristine state: no error, no scroll button, visible next button\n\t\t\tthis.$errorCount.empty();\n\t\t\tthis.$div.find( '.mwe-upwiz-details-error-scroll' ).remove();\n\t\t\tthis.nextButton.$element.show();\n\n\t\t\tif ( errorCount === 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst warningWidget = new OO.ui.MessageWidget( {\n\t\t\t\ttype: kind,\n\t\t\t\tinline: true,\n\t\t\t\tlabel: message.params( [ errorCount, uploadCount ] ).text()\n\t\t\t} );\n\t\t\tthis.$errorCount.append( warningWidget.$element );\n\n\t\t\tconst scrollWidget = new OO.ui.ButtonWidget( {\n\t\t\t\tclasses: [ 'mwe-upwiz-details-error-scroll' ],\n\t\t\t\tlabel: mw.message( 'mwe-upwiz-details-' + kind + '-scroll', errorCount, uploadCount ).text(),\n\t\t\t\tflags: [ 'progressive' ]\n\t\t\t} );\n\t\t\tscrollWidget.on( 'click', () => scrollToFirst( $elements ) );\n\t\t\tthis.nextButton.$element.hide().before( scrollWidget.$element );\n\t\t};\n\n\t\tconst observe = ( element, kind, $observedElements ) => {\n\t\t\tconst observer = new MutationObserver( () => {\n\t\t\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t\t\tif ( !$( element ).is( ':visible' ) ) {\n\t\t\t\t\tobserver.disconnect();\n\t\t\t\t\tupdateSummary(\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tmw.message( 'mwe-upwiz-details-' + kind + '-generic' ),\n\t\t\t\t\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t\t\t\t\t$observedElements.filter( ':visible' )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} );\n\t\t\tobserver.observe(\n\t\t\t\telement.parentNode,\n\t\t\t\t{ childList: true }\n\t\t\t);\n\t\t};\n\n\t\tconst show = ( kind ) => {\n\t\t\tconst $elements = getElements( kind );\n\n\t\t\tupdateSummary(\n\t\t\t\tkind,\n\t\t\t\tmw.message( 'mwe-upwiz-details-' + kind + '-count' ),\n\t\t\t\t$elements\n\t\t\t);\n\n\t\t\tif ( $elements.length > 0 ) {\n\t\t\t\t$elements.each( function () {\n\t\t\t\t\tobserve( this, kind, $elements );\n\n\t\t\t\t\t// Open collapsed elements that contain errors\n\t\t\t\t\tconst $collapsibleWrapper = $( this ).closest( '.mw-collapsible' );\n\t\t\t\t\tif ( $collapsibleWrapper.length ) {\n\t\t\t\t\t\t$collapsibleWrapper.data( 'mw-collapsible' ).expand();\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\tscrollToFirst( $elements );\n\t\t\t}\n\n\t\t\treturn $elements.length;\n\t\t};\n\n\t\t// show errors first; warnings only when there are no errors\n\t\t// don't bother with notices; no need to inform user about those merely showing them near the input\n\t\t// eslint-disable-next-line no-unused-expressions\n\t\tshow( 'error' ) || show( 'warning' );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/uw.ui.Wizard.js","messages":[{"ruleId":"mediawiki/msg-doc","severity":1,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":141,"column":25,"nodeType":"CallExpression","endLine":141,"endColumn":72}],"suppressedMessages":[{"ruleId":"no-jquery/no-global-selector","severity":2,"message":"Avoid queries which search the entire DOM. Keep DOM nodes in memory where possible.","line":49,"column":23,"nodeType":"CallExpression","endLine":49,"endColumn":41,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":2,"message":"Positional selector extensions are not allowed","line":86,"column":3,"nodeType":"CallExpression","endLine":86,"endColumn":51,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\t/**\n\t * Represents the UI for the wizard.\n\t *\n\t * @class\n\t * @mixes OO.EventEmitter\n\t * @param {string} selector Where to put all of the wizard interface.\n\t */\n\tuw.ui.Wizard = function UWUIWizard( selector ) {\n\t\tOO.EventEmitter.call( this );\n\n\t\tthis.$div = $( '<div>' )\n\t\t\t.attr( 'id', 'mwe-upwiz-content' );\n\n\t\t$( selector ).append(\n\t\t\tthis.$div,\n\t\t\t$( '<div>' ).addClass( 'mwe-upwiz-clearing' )\n\t\t);\n\n\t\tthis.initHeader( mw.UploadWizard.config );\n\t};\n\n\tOO.mixinClass( uw.ui.Wizard, OO.EventEmitter );\n\n\t/**\n\t * Initializes the static stuff above the wizard.\n\t *\n\t * @param {Object} config\n\t */\n\tuw.ui.Wizard.prototype.initHeader = function ( config ) {\n\t\t// eslint-disable-next-line no-jquery/no-global-selector\n\t\tconst $contentSub = $( '#contentSub' );\n\n\t\tlet feedbackLink;\n\t\tif ( config.feedbackLink ) {\n\t\t\t// Preferred. Send user to bug tracker (defaults to UW's own\n\t\t\t// Phabricator project)\n\t\t\tfeedbackLink = config.feedbackLink;\n\t\t} else if ( config.feedbackPage ) {\n\t\t\t// Backwards compatibility...send user to talk page to give\n\t\t\t// feedback.\n\t\t\tfeedbackLink = mw.util.getUrl( config.feedbackPage );\n\t\t}\n\n\t\tif ( feedbackLink ) {\n\t\t\tthis.$feedbackLink = $( '<a>' )\n\t\t\t\t.addClass( 'contentSubLink' )\n\t\t\t\t.prop( 'href', feedbackLink )\n\t\t\t\t.msg( 'mwe-upwiz-feedback-prompt' );\n\n\t\t\t$contentSub.append( this.$feedbackLink );\n\t\t}\n\n\t\tif ( config.alternativeUploadToolsPage ) {\n\t\t\tthis.$alternativeUploads = $( '<a>' )\n\t\t\t\t.addClass( 'contentSubLink' )\n\t\t\t\t.prop( 'href', new mw.Title( config.alternativeUploadToolsPage ).getUrl() )\n\t\t\t\t.msg( 'mwe-upwiz-subhead-alternatives' );\n\n\t\t\t$contentSub.append( this.$alternativeUploads );\n\t\t}\n\n\t\tif ( config.altUploadForm ) {\n\t\t\tthis.initAltUploadForm( config.altUploadForm );\n\t\t}\n\n\t\t// Separate each link in the header with a dot.\n\t\t// eslint-disable-next-line no-jquery/no-sizzle\n\t\t$contentSub.find( '.contentSubLink:not(:last)' ).after( ' · ' );\n\t};\n\n\t/**\n\t * Initializes a link to the alternate upload form, if any.\n\t *\n\t * @param {Object|string} configAltUploadForm A link or map of languages to links, pointing at an alternate form.\n\t */\n\tuw.ui.Wizard.prototype.initAltUploadForm = function ( configAltUploadForm ) {\n\t\tlet altUploadForm, userLanguage, title;\n\n\t\tif ( typeof configAltUploadForm === 'object' ) {\n\t\t\tuserLanguage = mw.config.get( 'wgUserLanguage' );\n\n\t\t\tif ( configAltUploadForm[ userLanguage ] ) {\n\t\t\t\taltUploadForm = configAltUploadForm[ userLanguage ];\n\t\t\t} else if ( configAltUploadForm.default ) {\n\t\t\t\taltUploadForm = configAltUploadForm.default;\n\t\t\t}\n\t\t} else {\n\t\t\taltUploadForm = configAltUploadForm;\n\t\t}\n\n\t\t// altUploadForm is expected to be a page title like 'Commons:Upload', so convert to URL\n\t\tif ( typeof altUploadForm === 'string' && altUploadForm.length > 0 ) {\n\t\t\ttry {\n\t\t\t\ttitle = new mw.Title( altUploadForm );\n\n\t\t\t\t$( '<a>' )\n\t\t\t\t\t.msg( 'mwe-upwiz-subhead-alt-upload' )\n\t\t\t\t\t.addClass( 'contentSubLink' )\n\t\t\t\t\t.attr( 'href', title.getUrl() )\n\t\t\t\t\t.appendTo( '#contentSub' );\n\t\t\t} catch ( e ) {\n\t\t\t\t// page was empty, or impossible on this wiki (missing namespace or some other issue). Give up.\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Initializes the arrow steps above the wizard.\n\t *\n\t * @param {Object.<uw.controller.Step>} steps\n\t */\n\tuw.ui.Wizard.prototype.initialiseSteps = function ( steps ) {\n\t\tconst $steps = $( '<ul>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-steps' )\n\t\t\t\t.addClass( 'ui-helper-clearfix' )\n\t\t\t\t.insertBefore( '#mwe-upwiz-content' ),\n\t\t\tsortedSteps = this.sortSteps( Object.keys( steps ).map( ( key ) => steps[ key ] ) );\n\n\t\tsortedSteps.forEach( ( step ) => {\n\t\t\tconst $arrow = $( '<li>' )\n\t\t\t\t.attr( 'id', 'mwe-upwiz-step-' + step.stepName )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<div>' ).text( mw.message( 'mwe-upwiz-step-' + step.stepName ).text() )\n\t\t\t\t);\n\t\t\tif ( step.showInBreadcrumb ) {\n\t\t\t\t$steps.append( $arrow );\n\t\t\t}\n\n\t\t\t// once a (new) step loads, highlight it\n\t\t\tstep.on( 'load', ( ( $arr ) => {\n\t\t\t\tif ( step.showInBreadcrumb ) {\n\t\t\t\t\t$steps.arrowStepsHighlight( $arr );\n\t\t\t\t}\n\t\t\t\t$steps.show();\n\t\t\t} ).bind( step, $arrow ) );\n\n\t\t\tstep.on( 'finished', () => {\n\t\t\t\t$steps.hide();\n\t\t\t} );\n\t\t} );\n\n\t\t$steps.arrowSteps();\n\t};\n\n\t/**\n\t * Sorts the steps in the order they'll actually be used.\n\t *\n\t * @param {uw.controller.Step[]} steps\n\t * @return {uw.controller.Step[]}\n\t */\n\tuw.ui.Wizard.prototype.sortSteps = function ( steps ) {\n\t\tlet first = steps[ 0 ];\n\n\t\t// find the very first step (element at position [0] is not guaranteed\n\t\t// to be first (it was just added first)\n\t\t// The actual internal relationship is defined in previousStep & nextStep\n\t\t// properties ...)\n\t\twhile ( first.previousStep !== null ) {\n\t\t\tfirst = first.previousStep;\n\t\t}\n\n\t\tconst sorted = [ first ];\n\t\tfor ( let i = 1; i < steps.length; i++ ) {\n\t\t\tsorted.push( sorted[ i - 1 ].nextStep );\n\t\t}\n\n\t\treturn sorted;\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/ui/uw.ui.base.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.ConcurrentQueue.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.CopyMetadataWidget.js","messages":[],"suppressedMessages":[{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeOut","line":148,"column":3,"nodeType":"CallExpression","endLine":151,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-fade","severity":2,"message":"Prefer CSS transitions to .fadeOut","line":165,"column":3,"nodeType":"CallExpression","endLine":168,"endColumn":30,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.DetailsWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.FieldLayout.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.LicenseGroup.js","messages":[{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":148,"column":48,"nodeType":"ObjectExpression","endLine":152,"endColumn":5},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":180,"column":56,"nodeType":"ObjectExpression","endLine":184,"endColumn":5},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":617,"column":3,"nodeType":"CallExpression","endLine":617,"endColumn":57},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":617,"column":3,"nodeType":"CallExpression","endLine":617,"endColumn":71}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * @extends OO.ui.LicenseGroup\n\t *\n\t * @class\n\t * @inheritdoc\n\t * @param {Object} config License configuration\n\t * @param {Array} config.licenses Array of license names\n\t * @param {string} [config.head] Header for the group of licenses (if present, the group of\n\t * licenses will be collapsed and this will be the clickable title to expand the group)\n\t * @param {string} [config.subhead] Subtitle for the group of licenses\n\t * @param {string} [config.special] 'custom' if a text input field should be added\n\t * @param {string} [config.template] Filter templates. If 'filterTemplate' was 'filter',\n\t * then [ 'fooLicense', 'barLicense' ] -> {{filter|fooLicense|barLicense}}\n\t * @param {Array} [config.prependTemplates] Array of templates to prepend. If prependTemplates\n\t * were [ 'pre', 'pended' ], then [ 'fooLicense' ] -> \"{{pre}}{{pended}}{{fooLicense}}\"\n\t * @param {string} type 'radio' or 'checkbox'\n\t * @param {mw.Api} api API object, used for wikitext previews\n\t * @param {number} count Number of the things we are licensing (it matters to some texts)\n\t */\n\tuw.LicenseGroup = function UWLicenseGroup( config, type, api, count ) {\n\t\tuw.LicenseGroup.super.call( this, {} );\n\n\t\tif ( typeof config.licenses !== 'object' ) {\n\t\t\tthrow new Error( 'improper license config' );\n\t\t}\n\n\t\tif ( ![ 'radio', 'checkbox' ].includes( type ) ) {\n\t\t\tthrow new Error( 'Invalid type: ' + type );\n\t\t}\n\n\t\t// [wikitext => list of templates used in wikitext] map, used in\n\t\t// getUsedTemplates to reduce amount of API calls\n\t\tthis.templateCache = {};\n\t\tthis.config = config;\n\t\tthis.type = type;\n\t\tthis.api = api;\n\t\tthis.count = count;\n\t\tthis.customInputs = {};\n\t\tthis.customInputFields = {};\n\t\tthis.previewDialog = new uw.LicensePreviewDialog();\n\t\tthis.windowManager = new OO.ui.WindowManager();\n\t\tthis.windowManager.addWindows( [ this.previewDialog ] );\n\t\t$( document.body ).append( this.windowManager.$element );\n\n\t\tif ( this.type === 'radio' ) {\n\t\t\tthis.group = this.createRadioGroup( [ 'mwe-upwiz-deed-license-group-body' ] );\n\t\t\tthis.group.connect( this, { choose: [ 'emit', 'change', this ] } );\n\t\t} else if ( this.type === 'checkbox' ) {\n\t\t\tthis.group = this.createCheckboxGroup( [ 'mwe-upwiz-deed-license-group-body' ] );\n\t\t\tthis.group.connect( this, { select: [ 'emit', 'change', this ] } );\n\t\t}\n\n\t\t// when selecting an item that has a custom input, we'll immediately focus it\n\t\t// this would be easier to implement by listening to the \"change\" event that this object\n\t\t// emits, but those are also triggered for keyboard navigation, and we don't want to focus\n\t\t// the input field in that case as it steals focus away from the radios/checkboxes (which,\n\t\t// in this case of nested radios/checkboxes, can't easily be restored - it'll also focus\n\t\t// the parent radio, which would mess up navigation)\n\t\tthis.group.$element.on( 'click', ( event ) => {\n\t\t\t// wrapped inside setTimeout to ensure it doesn't execute until OOUI has done its thing\n\t\t\tsetTimeout( () => {\n\t\t\t\t// first find selected thing(s), then figure out if the one we just clicked is among\n\t\t\t\t// them; if so and if that option has an input field, immediately focus it\n\t\t\t\tlet selectedItems;\n\t\t\t\tif ( this.type === 'radio' ) {\n\t\t\t\t\tselectedItems = this.group.findSelectedItem() ? [ this.group.findSelectedItem() ] : [];\n\t\t\t\t} else if ( this.type === 'checkbox' ) {\n\t\t\t\t\tselectedItems = this.group.findSelectedItems();\n\t\t\t\t}\n\t\t\t\tselectedItems.forEach( ( item ) => {\n\t\t\t\t\tconst name = item.getData();\n\t\t\t\t\tif ( item.$element.has( event.target ) && this.customInputs[ name ] ) {\n\t\t\t\t\t\tthis.customInputs[ name ].focus();\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\t} );\n\n\t\tthis.fieldset = this.createFieldset( this.group );\n\t\tthis.$element = this.fieldset.$element;\n\t};\n\tOO.inheritClass( uw.LicenseGroup, OO.ui.Widget );\n\tOO.mixinClass( uw.LicenseGroup, uw.ValidatableElement );\n\n\tuw.LicenseGroup.prototype.unload = function () {\n\t\tthis.windowManager.$element.remove();\n\t};\n\n\t/**\n\t * @param {OO.ui.RadioSelectWidget|OO.ui.CheckboxMultiselectInputWidget} group\n\t * @return {OO.ui.FieldsetLayout}\n\t */\n\tuw.LicenseGroup.prototype.createFieldset = function ( group ) {\n\t\tconst fieldset = new OO.ui.FieldsetLayout( {\n\t\t\titems: [ group ],\n\t\t\tclasses: [ 'mwe-upwiz-deed-license-group' ]\n\t\t} );\n\n\t\tif ( this.config.subhead ) {\n\t\t\t// 'url' can be either a single (string) url, or an array of (string) urls;\n\t\t\t// hence this convoluted variable-length parameters assembly...\n\t\t\tconst labelParams = [ this.config.subhead, this.count ].concat( this.config.url );\n\t\t\tconst $subhead = $( '<div>' )\n\t\t\t\t.addClass( 'mwe-upwiz-deed-license-group-subhead mwe-upwiz-deed-title' )\n\t\t\t\t.append( mw.message.apply( mw.message, labelParams ).parseDom() );\n\n\t\t\tif ( this.config[ 'subhead-extra' ] ) {\n\t\t\t\tconst labelExtraParams = [ this.config[ 'subhead-extra' ], this.count ].concat( this.config.url );\n\t\t\t\t$subhead.append(\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra' )\n\t\t\t\t\t\t.append( mw.message.apply( mw.message, labelExtraParams ).parseDom() )\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// make all links open in a new tab in order to not disrupt the upload process\n\t\t\t$subhead.find( 'a' ).attr( { target: '_blank' } );\n\n\t\t\tfieldset.addItems(\n\t\t\t\t[\n\t\t\t\t\tnew OO.ui.FieldLayout(\n\t\t\t\t\t\tnew OO.ui.Widget( { content: [] } ),\n\t\t\t\t\t\t{ label: $subhead, align: 'top' }\n\t\t\t\t\t)\n\t\t\t\t],\n\t\t\t\t0 // = index; add to top\n\t\t\t);\n\t\t}\n\n\t\treturn fieldset;\n\t};\n\n\t/**\n\t * @param {Array} classes to add\n\t * @return {OO.ui.RadioSelectWidget}\n\t */\n\tuw.LicenseGroup.prototype.createRadioGroup = function ( classes ) {\n\t\tconst options = [];\n\n\t\tthis.config.licenses.forEach( ( licenseName ) => {\n\t\t\tif ( mw.UploadWizard.config.licenses[ licenseName ] === undefined ) {\n\t\t\t\t// unknown license\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst option = new OO.ui.RadioOptionWidget( {\n\t\t\t\tlabel: this.createLabel( licenseName ),\n\t\t\t\tdata: licenseName,\n\t\t\t\tclasses: [ 'mwe-upwiz-license-option-' + licenseName ]\n\t\t\t} );\n\n\t\t\t// when custom text field receives input, we should make sure this option is selected\n\t\t\tif ( this.customInputs[ licenseName ] ) {\n\t\t\t\tthis.customInputs[ licenseName ].$input.on( 'input', () => {\n\t\t\t\t\toption.setSelected( this.customInputs[ licenseName ].getValue() !== '' );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\toptions.push( option );\n\t\t} );\n\n\t\treturn new OO.ui.RadioSelectWidget( { items: options, classes: classes } );\n\t};\n\n\t/**\n\t * @param {Array} classes to add\n\t * @return {OO.ui.CheckboxMultiselectInputWidget}\n\t */\n\tuw.LicenseGroup.prototype.createCheckboxGroup = function ( classes ) {\n\t\tconst options = [];\n\n\t\tthis.config.licenses.forEach( ( licenseName ) => {\n\t\t\tif ( mw.UploadWizard.config.licenses[ licenseName ] === undefined ) {\n\t\t\t\t// unknown license\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst option = new OO.ui.CheckboxMultioptionWidget( {\n\t\t\t\tlabel: this.createLabel( licenseName ),\n\t\t\t\tdata: licenseName,\n\t\t\t\tclasses: [ 'mwe-upwiz-license-option-' + licenseName ]\n\t\t\t} );\n\n\t\t\t// when custom text field receives input, we should make sure this option is selected\n\t\t\tif ( this.customInputs[ licenseName ] ) {\n\t\t\t\tthis.customInputs[ licenseName ].$input.on( 'input', () => {\n\t\t\t\t\toption.setSelected( this.customInputs[ licenseName ].getValue() !== '' );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\toptions.push( option );\n\t\t} );\n\n\t\treturn new OO.ui.CheckboxMultiselectWidget( { items: options, classes: classes } );\n\t};\n\n\t/**\n\t * @return {string}\n\t */\n\tuw.LicenseGroup.prototype.getWikiText = function () {\n\t\tconst values = this.getValue();\n\n\t\tconst wikiTexts = Object.keys( values ).map( ( name ) => {\n\t\t\tlet wikiText = this.getLicenceWikiText( name );\n\t\t\tconst value = values[ name ];\n\t\t\tif ( typeof value === 'string' ) {\n\t\t\t\t// `value` is custom input\n\t\t\t\twikiText += '\\n' + value.trim();\n\t\t\t}\n\t\t\treturn wikiText;\n\t\t} );\n\n\t\treturn wikiTexts.join( '' ).trim();\n\t};\n\n\t/**\n\t * Returns a string unique to the group (if defined)\n\t *\n\t * @return {string}\n\t */\n\tuw.LicenseGroup.prototype.getGroup = function () {\n\t\treturn this.config.head || '';\n\t};\n\n\t/**\n\t * @return {string}\n\t */\n\tuw.LicenseGroup.prototype.getData = function () {\n\t\treturn this.getGroup();\n\t};\n\n\t/**\n\t * @return {Object} Map of { licenseName: true }, or { licenseName: \"custom input\" }\n\t */\n\tuw.LicenseGroup.prototype.getValue = function () {\n\t\tconst result = {};\n\n\t\tlet selected, name;\n\t\tif ( this.type === 'radio' ) {\n\t\t\tselected = this.group.findSelectedItem();\n\t\t\tif ( selected ) {\n\t\t\t\tname = selected.getData();\n\t\t\t\tresult[ name ] = !this.customInputs[ name ] || this.customInputs[ name ].getValue();\n\t\t\t}\n\t\t} else if ( this.type === 'checkbox' ) {\n\t\t\tselected = this.group.findSelectedItems();\n\t\t\tselected.forEach( ( item ) => {\n\t\t\t\tname = item.getData();\n\t\t\t\tresult[ name ] = !this.customInputs[ name ] || this.customInputs[ name ].getValue();\n\t\t\t} );\n\t\t}\n\n\t\treturn result;\n\t};\n\n\t/**\n\t * @param {Object} values Map of { licenseName: true }, or { licenseName: \"custom input\" }\n\t */\n\tuw.LicenseGroup.prototype.setValue = function ( values ) {\n\t\tconst selectArray = [];\n\n\t\tObject.keys( values ).forEach( ( name ) => {\n\t\t\tconst value = values[ name ];\n\t\t\tif ( typeof value === 'string' && this.customInputs[ name ] ) {\n\t\t\t\tthis.customInputs[ name ].setValue( value );\n\t\t\t\t// add to list of items to select\n\t\t\t\tselectArray.push( name );\n\t\t\t}\n\n\t\t\t// add to list of items to select\n\t\t\t// (only true/string values should be included in `values`, but might\n\t\t\t// as well play it safe...)\n\t\t\tif ( value === true ) {\n\t\t\t\tselectArray.push( name );\n\t\t\t}\n\t\t} );\n\n\t\tif ( this.type === 'radio' ) {\n\t\t\tthis.group.selectItemByData( selectArray[ 0 ] );\n\t\t} else if ( this.type === 'checkbox' ) {\n\t\t\tthis.group.selectItemsByData( selectArray );\n\t\t}\n\t};\n\n\tuw.LicenseGroup.prototype.validate = function ( thorough ) {\n\t\tconst status = new uw.ValidationStatus();\n\n\t\tif ( thorough !== true ) {\n\t\t\t// `thorough` is the strict checks executed on submit, but we don't want errors\n\t\t\t// to change/display every change event\n\t\t\treturn status.resolve();\n\t\t}\n\n\t\tlet selected, name;\n\t\tif ( this.type === 'radio' ) {\n\t\t\tselected = this.group.findSelectedItem() ? [ this.group.findSelectedItem() ] : [];\n\t\t} else if ( this.type === 'checkbox' ) {\n\t\t\tselected = this.group.findSelectedItems();\n\t\t}\n\n\t\tif ( selected.length === 0 ) {\n\t\t\treturn status\n\t\t\t\t.addError( mw.message( 'mwe-upwiz-deeds-require-selection' ) )\n\t\t\t\t.reject();\n\t\t}\n\n\t\tconst customInputPromises = [];\n\t\tselected.forEach( ( item ) => {\n\t\t\tname = item.getData();\n\t\t\tif ( name in this.customInputFields ) {\n\t\t\t\tcustomInputPromises.push( this.customInputFields[ name ].validate( thorough ) );\n\t\t\t}\n\t\t} );\n\n\t\treturn uw.ValidationStatus.mergePromises( ...customInputPromises ).then(\n\t\t\t// custom input (if any) is fine\n\t\t\t() => status.getErrors().length === 0 ? status.resolve() : status.reject(),\n\t\t\t// there was an error in one of the custom inputs; we'll still want\n\t\t\t// to reject, but those child messages need not be added into this status\n\t\t\t// object, since they'll already be displayed within those child widgets\n\t\t\t() => status.reject()\n\t\t);\n\t};\n\n\t/**\n\t * @private\n\t * @param {string} name\n\t * @return {Object}\n\t */\n\tuw.LicenseGroup.prototype.getLicenseInfo = function ( name ) {\n\t\treturn {\n\t\t\tname: name,\n\t\t\tprops: mw.UploadWizard.config.licenses[ name ]\n\t\t};\n\t};\n\n\t/**\n\t * @private\n\t * @param {string} name\n\t * @return {string[]}\n\t */\n\tuw.LicenseGroup.prototype.getTemplates = function ( name ) {\n\t\tconst licenseInfo = this.getLicenseInfo( name );\n\t\treturn licenseInfo.props.templates === undefined ?\n\t\t\t[ licenseInfo.name ] :\n\t\t\tlicenseInfo.props.templates.slice( 0 );\n\t};\n\n\t/**\n\t * License templates are these abstract ideas like cc-by-sa. In general they map directly to a license template.\n\t * However, configuration for a particular option can add other templates or transform the templates,\n\t * such as wrapping templates in an outer \"self\" template for own-work\n\t *\n\t * @private\n\t * @param {string} name license template name\n\t * @return {string} of wikitext\n\t */\n\tuw.LicenseGroup.prototype.getLicenceWikiText = function ( name ) {\n\t\tlet templates = this.getTemplates( name );\n\n\t\tif ( this.config.prependTemplates !== undefined ) {\n\t\t\tthis.config.prependTemplates.forEach( ( template ) => {\n\t\t\t\ttemplates.unshift( template );\n\t\t\t} );\n\t\t}\n\n\t\tif ( this.config.template !== undefined ) {\n\t\t\ttemplates.unshift( this.config.template );\n\t\t\ttemplates = [ templates.join( '|' ) ];\n\t\t}\n\n\t\tconst wikiTexts = templates.map( ( t ) => '{{' + t + '}}' );\n\t\treturn wikiTexts.join( '' );\n\t};\n\n\t/**\n\t * Get a label for the form element\n\t *\n\t * @private\n\t * @param {string} name license template name\n\t * @return {jQuery}\n\t */\n\tuw.LicenseGroup.prototype.createLabel = function ( name ) {\n\t\tconst licenseInfo = this.getLicenseInfo( name ),\n\t\t\tmessageKey = licenseInfo.props.msg === undefined ?\n\t\t\t\t'[missing msg for ' + licenseInfo.name + ']' :\n\t\t\t\tlicenseInfo.props.msg,\n\t\t\t$icons = $( '<span>' );\n\t\t\t// The URL is optional, but if the message includes it as $2, we surface the fact\n\t\t\t// that it's missing.\n\t\tlet licenseURL = licenseInfo.props.url === undefined ? '#missing license URL' : licenseInfo.props.url;\n\n\t\tif (\n\t\t\tlicenseInfo.props.languageCodePrefix !== undefined &&\n\t\t\tlicenseInfo.props.availableLanguages !== undefined\n\t\t) {\n\t\t\tlet targetLanguageCode = 'en'; // final fallback\n\t\t\tconst fallbackChain = mw.language.getFallbackLanguageChain();\n\t\t\tfor ( let i = 0; i < fallbackChain.length; i++ ) {\n\t\t\t\tif ( licenseInfo.props.availableLanguages.includes( fallbackChain[ i ] ) ) {\n\t\t\t\t\ttargetLanguageCode = fallbackChain[ i ];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlicenseURL += licenseInfo.props.languageCodePrefix + targetLanguageCode;\n\t\t}\n\t\tconst $licenseLink = $( '<a>' ).attr( { target: '_blank', href: licenseURL } );\n\t\tif ( licenseInfo.props.icons !== undefined ) {\n\t\t\tlicenseInfo.props.icons.forEach( ( icon ) => {\n\t\t\t\t// The following classes are used here:\n\t\t\t\t// * mwe-upwiz-cc-public-domain-icon\n\t\t\t\t// * mwe-upwiz-cc-zero-icon\n\t\t\t\t// * mwe-upwiz-cc-sa-icon\n\t\t\t\t// * mwe-upwiz-cc-by-icon\n\t\t\t\t$icons.append( $( '<span>' ).addClass( 'skin-invert mwe-upwiz-license-icon mwe-upwiz-' + icon + '-icon' ) );\n\t\t\t} );\n\t\t}\n\n\t\tconst $label = $( '<label>' ).msg( messageKey, this.count || 0, $licenseLink, $icons );\n\n\t\tif (\n\t\t\tthis.config.special === 'custom' ||\n\t\t\tlicenseInfo.props.special === 'input'\n\t\t) {\n\t\t\tconst inputField = this.createInput( name, licenseInfo.props.defaultText );\n\n\t\t\t$label.append( inputField.$element );\n\t\t\tif ( licenseInfo.props.msgSpecial !== undefined ) {\n\t\t\t\tinputField.$body.append(\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t.append( mw.message( licenseInfo.props.msgSpecial, this.count || 0, $licenseLink ).parseDom() )\n\t\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra' )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif ( licenseInfo.props.msgExplain !== undefined ) {\n\t\t\t$label.append(\n\t\t\t\t$( '<span>' )\n\t\t\t\t\t.msg( licenseInfo.props.msgExplain, this.count || 0, $licenseLink )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra mwe-upwiz-label-explainer' )\n\t\t\t);\n\t\t}\n\n\t\tif ( licenseInfo.props.msgWarning !== undefined ) {\n\t\t\t$label.append(\n\t\t\t\t$( '<span>' )\n\t\t\t\t\t.msg( licenseInfo.props.msgWarning, this.count || 0, $licenseLink )\n\t\t\t\t\t.addClass( 'mwe-upwiz-label-extra mwe-upwiz-label-warning' )\n\t\t\t);\n\t\t}\n\n\t\treturn $label.contents();\n\t};\n\n\t/**\n\t * Returns a list of templates used & transcluded in given wikitext\n\t *\n\t * @private\n\t * @param {string} wikitext\n\t * @return {jQuery.Promise} Promise that resolves with an array of template names\n\t */\n\tuw.LicenseGroup.prototype.getUsedTemplates = function ( wikitext ) {\n\t\tif ( wikitext in this.templateCache ) {\n\t\t\treturn $.Deferred().resolve( this.templateCache[ wikitext ] ).promise();\n\t\t}\n\t\treturn this.api.get( {\n\t\t\taction: 'parse',\n\t\t\tpst: true,\n\t\t\tprop: 'templates',\n\t\t\ttitle: 'File:UploadWizard license verification.png',\n\t\t\ttext: wikitext\n\t\t} ).then( ( result ) => {\n\t\t\tconst templates = [];\n\t\t\tfor ( let i = 0; i < result.parse.templates.length; i++ ) {\n\t\t\t\tconst template = result.parse.templates[ i ];\n\t\t\t\t// normalize templates to mw.Title.getPrefixedDb() format\n\t\t\t\tconst title = new mw.Title( template.title, template.ns );\n\t\t\t\ttemplates.push( title.getPrefixedDb() );\n\t\t\t}\n\t\t\t// cache result so we won't have to fire another API request\n\t\t\t// for the same content\n\t\t\tthis.templateCache[ wikitext ] = templates;\n\t\t\treturn templates;\n\t\t} );\n\t};\n\n\t/**\n\t * @private\n\t * @param {string} name license name\n\t * @param {string} [defaultText] Default custom license text\n\t * @return {uw.FieldLayout}\n\t */\n\tuw.LicenseGroup.prototype.createInput = function ( name, defaultText ) {\n\t\tconst input = new OO.ui.TextInputWidget( {\n\t\t\tvalue: defaultText\n\t\t} );\n\n\t\tconst button = new OO.ui.ButtonWidget( {\n\t\t\tlabel: mw.message( 'mwe-upwiz-license-custom-preview' ).text(),\n\t\t\tflags: [ 'progressive' ]\n\t\t} );\n\n\t\tinput.on( 'change', () => {\n\t\t\t// Update displayed errors as the user is typing\n\t\t\tthis.emit( 'change' );\n\t\t} );\n\t\tinput.$element.on( 'mousedown', ( event ) => {\n\t\t\t// T294389 \"Another reason not mentioned above\" license input textarea: Text is unclickable.\n\t\t\t// When used inside other widgets (e.g. RadioSelectWidget or CheckboxMultioptionWidget),\n\t\t\t// those may have event handlers to respond to clicks (e.g. selecting the radio/checkbox)\n\t\t\t// that would steal focus from the input. We do not want that to happen, as it may\n\t\t\t// interfere with operations within the input field (e.g. selecting text), so we'll\n\t\t\t// avoid that by not propagating the event (to RadioSelectWidget/CheckboxMultioptionWidget),\n\t\t\t// but that'll then require those parent widgets to handle such relevant events themselves.\n\t\t\tevent.stopPropagation();\n\t\t} );\n\t\tinput.$element.on( 'keydown', ( event ) => {\n\t\t\tswitch ( event.which ) {\n\t\t\t\tcase OO.ui.Keys.UP:\n\t\t\t\tcase OO.ui.Keys.LEFT:\n\t\t\t\tcase OO.ui.Keys.DOWN:\n\t\t\t\tcase OO.ui.Keys.RIGHT:\n\t\t\t\t\t// Similar to the mouse events issue described above; parent widgets may also\n\t\t\t\t\t// handle some keyboard events (e.g. RadioSelectWidget or CheckboxMultioptionWidget\n\t\t\t\t\t// capture up/left and down/right to navigate to previous/next item)\n\t\t\t\t\t// Once again, this is undesirable, as these keys are likely used for operations\n\t\t\t\t\t// within the input field (moving the cursor), so once again we're preventing\n\t\t\t\t\t// propagation of these events to the parent nodes.\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\tbreak;\n\t\t\t\tcase OO.ui.Keys.ENTER:\n\t\t\t\t\t// Hitting enter should not trigger the default button action (submitting a form),\n\t\t\t\t\t// but open the preview dialog instead.\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tbutton.emit( 'click' );\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t} );\n\n\t\tbutton.on( 'click', () => {\n\t\t\tthis.showPreview( input.getValue() );\n\t\t} );\n\n\t\tuw.ValidatableElement.decorate( input );\n\t\tinput.validate = ( thorough ) => {\n\t\t\tconst status = new uw.ValidationStatus();\n\t\t\tlet promise = $.Deferred().resolve().promise();\n\n\t\t\tif ( thorough !== true ) {\n\t\t\t\treturn status.resolve();\n\t\t\t}\n\n\t\t\tconst wikitext = input.getValue().trim();\n\t\t\tif ( wikitext === '' ) {\n\t\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-license-wikitext-missing' ) );\n\t\t\t} else if ( wikitext.length < mw.UploadWizard.config.minCustomLicenseLength ) {\n\t\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-license-wikitext-too-short' ) );\n\t\t\t} else if ( wikitext.length > mw.UploadWizard.config.maxCustomLicenseLength ) {\n\t\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-license-wikitext-too-long' ) );\n\t\t\t} else if ( !/\\{\\{(.+?)\\}\\}/g.test( wikitext ) ) {\n\t\t\t\t// if text doesn't contain a template, we don't even\n\t\t\t\t// need to validate it any further...\n\t\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-license-wikitext-missing-template' ) );\n\t\t\t} else if ( mw.UploadWizard.config.customLicenseTemplate !== false ) {\n\t\t\t\t// now do a thorough test to see if the text actually\n\t\t\t\t// includes a license template\n\t\t\t\tpromise = this.getUsedTemplates( wikitext ).then( ( usedTemplates ) => {\n\t\t\t\t\tif ( !usedTemplates.includes( mw.UploadWizard.config.customLicenseTemplate ) ) {\n\t\t\t\t\t\t// no license template found, add another error\n\t\t\t\t\t\tstatus.addError( mw.message( 'mwe-upwiz-error-license-wikitext-missing-template' ) );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn promise.then( () => status.getErrors().length === 0 ? status.resolve() : status.reject() );\n\t\t};\n\n\t\tconst inputField = new uw.FieldLayout( input, {\n\t\t\tclasses: [ 'mwe-upwiz-license-custom', 'mwe-upwiz-label-input' ]\n\t\t} );\n\t\tinputField.$body.append( button.$element );\n\t\tinput.connect( inputField, { change: [ 'emit', 'change' ] } );\n\n\t\tthis.customInputs[ name ] = input;\n\t\tthis.customInputFields[ name ] = inputField;\n\n\t\treturn inputField;\n\t};\n\n\t/**\n\t * Preview wikitext in a popup window\n\t *\n\t * @private\n\t * @param {string} wikiText\n\t */\n\tuw.LicenseGroup.prototype.showPreview = function ( wikiText ) {\n\t\tthis.previewDialog.setLoading( true );\n\t\tthis.windowManager.openWindow( this.previewDialog );\n\n\t\tconst show = ( html ) => {\n\t\t\tthis.previewDialog.setPreview( html );\n\t\t\tthis.windowManager.openWindow( this.previewDialog );\n\t\t};\n\n\t\tconst error = ( code, result ) => {\n\t\t\tconst message = result.errors[ 0 ].html;\n\n\t\t\tshow( $( '<div>' ).append(\n\t\t\t\t$( '<h3>' ).append( code ),\n\t\t\t\t$( '<p>' ).append( message )\n\t\t\t) );\n\t\t};\n\n\t\tthis.api.parse( wikiText, { pst: true } ).done( show ).fail( error );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.LicensePreviewDialog.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.ValidatableElement.js","messages":[],"suppressedMessages":[{"ruleId":"no-unused-vars","severity":2,"message":"'thorough' is defined but never used.","line":39,"column":56,"nodeType":"Identifier","messageId":"unusedVar","endLine":39,"endColumn":64,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.ValidationMessageElement.js","messages":[{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":92,"column":10,"nodeType":"CallExpression","endLine":94,"endColumn":61},{"ruleId":"mediawiki/class-doc","severity":1,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":92,"column":10,"nodeType":"CallExpression","endLine":93,"endColumn":48}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function ( uw ) {\n\n\t/**\n\t * Element that is able to display validation messages from itself or another widget.\n\t *\n\t * @abstract\n\t * @class\n\t *\n\t * @param {Object} [config]\n\t * @param {uw.ValidatableElement} [config.validatedWidget] Widget to validate\n\t */\n\tuw.ValidationMessageElement = function UWValidationMessageElement( config ) {\n\t\tconfig = config || {};\n\n\t\tthis.validatedWidget = config.validatedWidget || this;\n\t\tthis.$messages = $( '<ul>' );\n\n\t\tthis.errors = [];\n\t\tthis.warnings = [];\n\t\tthis.notices = [];\n\t\tthis.successMessages = []; // unused, but OO.ui.FieldLayout.prototype.updateMessages assumes this exists\n\n\t\tthis.validatedWidget.on( 'change', () => this.validate && this.validate( false ) );\n\n\t\tthis.$messages.addClass( 'oo-ui-fieldLayout-messages' );\n\t\tthis.$element.addClass( 'mwe-upwiz-validationMessageElement' );\n\t};\n\tOO.initClass( uw.ValidationMessageElement );\n\tOO.mixinClass( uw.ValidationMessageElement, uw.ValidatableElement );\n\n\t// Hack: Steal methods from OO.ui.FieldLayout.\n\t// TODO: Upstream ValidationMessageElement to OOUI, make FieldLayout use it.\n\tuw.ValidationMessageElement.prototype.setErrors = OO.ui.FieldLayout.prototype.setErrors;\n\tuw.ValidationMessageElement.prototype.setWarnings = OO.ui.FieldLayout.prototype.setWarnings;\n\tuw.ValidationMessageElement.prototype.setNotices = OO.ui.FieldLayout.prototype.setNotices;\n\tuw.ValidationMessageElement.prototype.updateMessages = OO.ui.FieldLayout.prototype.updateMessages;\n\n\tuw.ValidationMessageElement.prototype.preValidate = function () {\n\t\tif ( this.validatedWidget.pushPending ) {\n\t\t\tthis.validatedWidget.pushPending();\n\t\t}\n\t};\n\n\t/**\n\t * Check the field's widget for errors, warnings & notices and display them in the UI.\n\t *\n\t * @param {boolean} thorough True to perform a thorough validity check. Defaults to false for a fast on-change check.\n\t * @return {jQuery.Promise<uw.ValidationStatus>}\n\t */\n\tuw.ValidationMessageElement.prototype.validate = function ( thorough ) {\n\t\tthorough = thorough || false;\n\n\t\treturn $.Deferred().resolve().promise()\n\t\t\t.then( () => this.preValidate() )\n\t\t\t.then( () => this.validatedWidget.validate( thorough ) )\n\t\t\t.always( ( status ) => this.postValidate( status ) );\n\t};\n\n\t/**\n\t * @param {uw.ValidationStatus} status\n\t */\n\tuw.ValidationMessageElement.prototype.postValidate = function ( status ) {\n\t\t// errors, warnings & notices are arrays of mw.Messages and not strings in this subclass\n\t\tthis.setErrors( status.getErrors() );\n\t\tthis.setWarnings( status.getWarnings() );\n\t\tthis.setNotices( status.getNotices() );\n\n\t\tif ( this.validatedWidget.popPending ) {\n\t\t\tthis.validatedWidget.popPending();\n\t\t}\n\t};\n\n\t/**\n\t * @protected\n\t * @param {string} kind 'error', 'warning' or 'notice'\n\t * @param {mw.Message|Object} error Message, or an object in { key: ..., html: ... } format\n\t * @return {jQuery}\n\t */\n\tuw.ValidationMessageElement.prototype.makeMessage = function ( kind, error ) {\n\t\tlet code, $content;\n\n\t\tif ( error.parseDom ) {\n\t\t\t// mw.Message object\n\t\t\tcode = error.key;\n\t\t\t$content = error.parseDom();\n\t\t} else {\n\t\t\t// { key: ..., html: ... } object (= formatted API error responses)\n\t\t\tcode = error.code;\n\t\t\t$content = $( $.parseHTML( error.html ) );\n\t\t}\n\n\t\treturn OO.ui.FieldLayout.prototype.makeMessage.call( this, kind, $content )\n\t\t\t.addClass( 'mwe-upwiz-fieldLayout-' + kind )\n\t\t\t.addClass( 'mwe-upwiz-fieldLayout-' + kind + '-' + code );\n\t};\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.ValidationStatus.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw.units.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/uw/uw.base.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/abstractSchemaChanges/patch-uw_campaigns-cleanup.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/tables.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Deed.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Details.test.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":127,"column":3,"nodeType":"CallExpression","endLine":127,"endColumn":40}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension DetailsWizard.\n *\n * DetailsWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * DetailsWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with DetailsWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\tQUnit.module( 'mw.uploadWizard.controller.Details', QUnit.newMwEnvironment() );\n\n\tfunction createTestUpload( sandbox, aborted ) {\n\t\tconst stubs = {\n\t\t\tgetSerialized: sandbox.stub(),\n\t\t\tsetSerialized: sandbox.stub(),\n\t\t\tattach: sandbox.stub()\n\t\t};\n\n\t\treturn {\n\t\t\tdeedChooser: { deed: { name: 'cc-by-sa-4.0' } },\n\n\t\t\ton: function () {},\n\n\t\t\tdetails: {\n\t\t\t\tgetSerialized: stubs.getSerialized,\n\t\t\t\tsetSerialized: stubs.setSerialized,\n\t\t\t\tattach: stubs.attach,\n\t\t\t\ton: function () {}\n\t\t\t},\n\n\t\t\tstate: aborted ? 'aborted' : 'stashed',\n\n\t\t\tstubs: stubs\n\t\t};\n\t}\n\n\tQUnit.test( 'Constructor sense-check', ( assert ) => {\n\t\tconst step = new uw.controller.Details( new mw.Api(), {\n\t\t\tmaxSimultaneousConnections: 1\n\t\t} );\n\t\tassert.true( step instanceof uw.controller.Step );\n\t\tassert.true( !!step.ui );\n\t} );\n\n\tQUnit.test( 'load', function ( assert ) {\n\t\tconst step = new uw.controller.Details( new mw.Api(), {\n\t\t\t\tmaxSimultaneousConnections: 1\n\t\t\t} ),\n\t\t\tstepUiStub = this.sandbox.stub( step.ui, 'load' );\n\n\t\tlet testUpload = createTestUpload( this.sandbox );\n\n\t\t// replace createDetails with a stub; UploadWizardDetails needs way too\n\t\t// much setup to actually be able to create it\n\t\tstep.createDetails = this.sandbox.stub();\n\n\t\tstep.load( [ testUpload ] );\n\n\t\tassert.strictEqual( step.createDetails.callCount, 1 );\n\t\tassert.true( stepUiStub.called );\n\n\t\ttestUpload = createTestUpload( this.sandbox, true );\n\t\tstep.load( [ testUpload ] );\n\n\t\tassert.strictEqual( step.createDetails.callCount, 2 );\n\t\tassert.true( stepUiStub.called );\n\n\t\ttestUpload = createTestUpload( this.sandbox );\n\t\tstep.load( [ testUpload, createTestUpload( this.sandbox ) ] );\n\n\t\tassert.strictEqual( step.createDetails.callCount, 4 );\n\t\tassert.true( stepUiStub.called );\n\n\t\ttestUpload = createTestUpload( this.sandbox );\n\t\tstep.load( [ testUpload, createTestUpload( this.sandbox, false, true ) ] );\n\n\t\tassert.strictEqual( step.createDetails.callCount, 6 );\n\t\tassert.true( stepUiStub.called );\n\t} );\n\n\tQUnit.test( 'canTransition', ( assert ) => {\n\t\tconst upload = {},\n\t\t\tstep = new uw.controller.Details( new mw.Api(), {\n\t\t\t\tmaxSimultaneousConnections: 1\n\t\t\t} );\n\n\t\tassert.strictEqual( step.canTransition( upload ), false );\n\t\tupload.state = 'details';\n\t\tassert.strictEqual( step.canTransition( upload ), true );\n\t\tupload.state = 'complete';\n\t\tassert.strictEqual( step.canTransition( upload ), false );\n\t} );\n\n\tQUnit.test( 'transitionAll', function ( assert ) {\n\t\tconst done = assert.async(),\n\t\t\tdonestub = this.sandbox.stub(),\n\t\t\tds = [ $.Deferred(), $.Deferred(), $.Deferred() ],\n\t\t\tps = [ ds[ 0 ].promise(), ds[ 1 ].promise(), ds[ 2 ].promise() ];\n\n\t\tconst tostub = this.sandbox.stub( uw.controller.Details.prototype, 'transitionOne' );\n\t\ttostub.onFirstCall().returns( ps[ 0 ] );\n\t\ttostub.onSecondCall().returns( ps[ 1 ] );\n\t\ttostub.onThirdCall().returns( ps[ 2 ] );\n\n\t\tthis.sandbox.stub( uw.controller.Details.prototype, 'canTransition' ).returns( true );\n\n\t\tconst step = new uw.controller.Details( new mw.Api(), {\n\t\t\tmaxSimultaneousConnections: 3\n\t\t} );\n\n\t\tstep.uploads = [\n\t\t\t{ id: 15 },\n\t\t\tundefined,\n\t\t\t{ id: 21 },\n\t\t\t{ id: 'aoeu' }\n\t\t];\n\n\t\tstep.transitionAll().done( donestub );\n\t\tsetTimeout( () => {\n\t\t\tconst calls = [ tostub.getCall( 0 ), tostub.getCall( 1 ), tostub.getCall( 2 ) ];\n\n\t\t\tassert.strictEqual( calls[ 0 ].args[ 0 ].id, 15 );\n\t\t\tassert.strictEqual( calls[ 1 ].args[ 0 ].id, 21 );\n\n\t\t\tds[ 0 ].resolve();\n\t\t\tds[ 1 ].resolve();\n\t\t\tsetTimeout( () => {\n\t\t\t\tassert.strictEqual( donestub.called, false );\n\n\t\t\t\tds[ 2 ].resolve();\n\t\t\t\tsetTimeout( () => {\n\t\t\t\t\tassert.true( donestub.called );\n\n\t\t\t\t\tdone();\n\t\t\t\t} );\n\t\t\t} );\n\t\t} );\n\t} );\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Step.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Thanks.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Tutorial.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/controller/uw.controller.Upload.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/details/uw.LocationDetailsWidget.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/mw.FlickrChecker.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/mw.UploadWizardLicenseInput.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/mw.UploadWizardUpload.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/mw.fileApi.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/transports/mw.FormDataTransport.test.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":142,"column":3,"nodeType":"CallExpression","endLine":148,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":175,"column":10,"nodeType":"CallExpression","endLine":178,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .done","line":194,"column":10,"nodeType":"CallExpression","endLine":197,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":214,"column":3,"nodeType":"CallExpression","endLine":218,"endColumn":6}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function () {\n\tQUnit.module( 'mw.FormDataTransport', QUnit.newMwEnvironment() );\n\n\tfunction createTransport( chunkSize, api ) {\n\t\tchunkSize = chunkSize || 0;\n\t\tapi = api || {};\n\n\t\tconst config = {\n\t\t\tuseRetryTimeout: false,\n\t\t\tchunkSize: chunkSize,\n\t\t\tmaxPhpUploadSize: chunkSize\n\t\t};\n\n\t\treturn new mw.FormDataTransport( api, {}, config );\n\t}\n\n\tQUnit.test( 'Constructor sense-check', ( assert ) => {\n\t\tconst transport = createTransport();\n\n\t\tassert.true( !!transport );\n\t} );\n\n\tQUnit.test( 'abort', function ( assert ) {\n\t\tconst transport = createTransport( 0 ),\n\t\t\trequest = $.Deferred().promise( { abort: this.sandbox.stub() } );\n\n\t\ttransport.request = request;\n\n\t\tassert.true( request.abort.notCalled );\n\n\t\ttransport.abort();\n\n\t\tassert.true( request.abort.called );\n\t\tassert.true( transport.aborted );\n\t} );\n\n\tQUnit.test( 'createParams', ( assert ) => {\n\t\tconst transport = createTransport( 10 ),\n\t\t\tparams = transport.createParams( 'foobar.jpg', 0 );\n\n\t\tassert.true( !!params );\n\n\t\tassert.strictEqual( params.filename, 'foobar.jpg' );\n\t\tassert.strictEqual( params.offset, 0 );\n\t} );\n\n\tQUnit.test( 'post', function ( assert ) {\n\t\tconst stub = this.sandbox.stub(),\n\t\t\t// post() works on a promise and binds .then, so we have to make\n\t\t\t// sure it actually is a promise, but also that it calls our stub\n\t\t\ttransport = createTransport( 10, { post: function () {\n\t\t\t\tstub();\n\t\t\t\treturn $.Deferred().resolve();\n\t\t\t} } );\n\n\t\tthis.sandbox.useFakeServer();\n\n\t\tassert.true( stub.notCalled );\n\n\t\ttransport.post( {} );\n\n\t\tassert.true( stub.called );\n\t} );\n\n\tQUnit.test( 'upload', function ( assert ) {\n\t\tconst transport = createTransport( 10, new mw.Api() ),\n\t\t\tfakeFile = {\n\t\t\t\tname: 'test file for fdt.jpg',\n\t\t\t\tsize: 5\n\t\t\t};\n\n\t\tthis.sandbox.useFakeServer();\n\n\t\ttransport.upload( fakeFile, 'test file for fdt.jpg' );\n\n\t\tassert.strictEqual( this.sandbox.server.requests.length, 1 );\n\t\tconst request = this.sandbox.server.requests[ 0 ];\n\t\tassert.strictEqual( request.method, 'POST' );\n\t\tassert.strictEqual( request.url, mw.util.wikiScript( 'api' ) + '?action=query' );\n\t\tassert.true( request.async );\n\n\t\ttransport.abort();\n\t} );\n\n\tQUnit.test( 'uploadChunk', function ( assert ) {\n\t\tconst transport = createTransport( 10, new mw.Api() ),\n\t\t\tfakeFile = {\n\t\t\t\tname: 'test file for fdt.jpg',\n\t\t\t\tsize: 20,\n\t\t\t\tslice: function ( offset ) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tname: 'test file for fdt.jpg',\n\t\t\t\t\t\toffset: offset,\n\t\t\t\t\t\tsize: 10\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t};\n\n\t\tthis.sandbox.useFakeServer();\n\n\t\ttransport.uploadChunk( fakeFile, 0 );\n\n\t\tassert.strictEqual( this.sandbox.server.requests.length, 1 );\n\t\tconst request = this.sandbox.server.requests[ 0 ];\n\t\tassert.strictEqual( request.method, 'POST' );\n\t\tassert.strictEqual( request.url, mw.util.wikiScript( 'api' ) + '?action=query' );\n\t\tassert.true( request.async );\n\n\t\ttransport.abort();\n\t} );\n\n\t// test invalid server response (in missing 'stage' param)\n\tQUnit.test( 'checkStatus invalid API response', function ( assert ) {\n\t\tconst done = assert.async(),\n\t\t\ttransport = createTransport( 10, new mw.Api() ),\n\t\t\ttstub = this.sandbox.stub(),\n\t\t\tpoststub = this.sandbox.stub( transport.api, 'post' ),\n\t\t\tpostd = $.Deferred();\n\n\t\t// prepare a bogus invalid API result\n\t\tpoststub.returns( postd.promise() );\n\t\tpostd.resolve( { upload: { result: 'Poll' } } );\n\n\t\t// call tstub upon checkStatus failure, and verify it got called correctly\n\t\ttransport.checkStatus().fail( tstub, () => {\n\t\t\tassert.true( tstub.calledWith( 'server-error', { errors: [ {\n\t\t\t\tcode: 'server-error',\n\t\t\t\thtml: mw.message( 'api-clientside-error-invalidresponse' ).parse()\n\t\t\t} ] } ) );\n\t\t\tdone();\n\t\t} );\n\t} );\n\n\t// test retry after server responds upload is still incomplete\n\tQUnit.test( 'checkStatus retry', function ( assert ) {\n\t\tconst transport = createTransport( 10, new mw.Api() ),\n\t\t\tusstub = this.sandbox.stub(),\n\t\t\tpoststub = this.sandbox.stub( transport.api, 'post' ),\n\t\t\tpostd = $.Deferred(),\n\t\t\tpostd2 = $.Deferred();\n\n\t\ttransport.on( 'update-stage', usstub );\n\n\t\t// prepare a first API call that responds with 'Poll' (upload\n\t\t// concatenation is not yet complete) followed by a second call that\n\t\t// marks the upload successful\n\t\tpoststub\n\t\t\t.onFirstCall().returns( postd.promise() )\n\t\t\t.onSecondCall().returns( postd2.promise() );\n\n\t\t// resolve 3 API calls, where server first responds upload is not yet\n\t\t// assembled, and second says it's published\n\t\tpostd.resolve( { upload: { result: 'Poll', stage: 'queued' } } );\n\t\tpostd2.resolve( { upload: { result: 'Success' } } );\n\n\t\t// confirm that, once second API call was successful, status resolves,\n\t\t// 2 API calls have gone out & the failed call updates stage accordingly\n\t\treturn transport.checkStatus().done( () => {\n\t\t\tassert.true( poststub.calledTwice );\n\t\t\tassert.true( usstub.firstCall.calledWith( 'queued' ) );\n\t\t} );\n\t} );\n\n\tQUnit.test( 'checkStatus success', function ( assert ) {\n\t\tconst transport = createTransport( 10, new mw.Api() ),\n\t\t\ttstub = this.sandbox.stub(),\n\t\t\tusstub = this.sandbox.stub(),\n\t\t\tpoststub = this.sandbox.stub( transport.api, 'post' ),\n\t\t\tpostd = $.Deferred();\n\n\t\ttransport.on( 'update-stage', usstub );\n\n\t\t// prepare a bogus valid API result\n\t\tpoststub.returns( postd.promise() );\n\t\tpostd.resolve( 'testing' );\n\n\t\treturn transport.checkStatus().done( tstub, () => {\n\t\t\tassert.true( tstub.calledWith( 'testing' ) );\n\t\t\tassert.false( usstub.called );\n\t\t} );\n\t} );\n\n\tQUnit.test( 'checkStatus error API response', function ( assert ) {\n\t\tconst done = assert.async(),\n\t\t\ttransport = createTransport( 10, new mw.Api() ),\n\t\t\ttstub = this.sandbox.stub(),\n\t\t\tusstub = this.sandbox.stub(),\n\t\t\tpoststub = this.sandbox.stub( transport.api, 'post' ),\n\t\t\tpostd = $.Deferred();\n\n\t\ttransport.on( 'update-stage', usstub );\n\n\t\t// prepare an error API response\n\t\tpoststub.returns( postd.promise() );\n\t\tpostd.reject( 'testing', { error: 'testing' } );\n\n\t\ttransport.checkStatus().fail( tstub, () => {\n\t\t\tassert.true( tstub.calledWith( 'testing', { error: 'testing' } ) );\n\t\t\tassert.false( usstub.called );\n\t\t\tdone();\n\t\t} );\n\t} );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/uw.ConcurrentQueue.test.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":1,"message":"Prefer .then to .fail","line":54,"column":5,"nodeType":"CallExpression","endLine":54,"endColumn":87}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*\n * This file is part of the MediaWiki extension UploadWizard.\n *\n * UploadWizard is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * UploadWizard is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.\n */\n\n( function ( uw ) {\n\tQUnit.module( 'mw.uploadWizard.ConcurrentQueue', QUnit.newMwEnvironment() );\n\n\t// This is a bogus action that will be executed for every item added to the\n\t// queue. We just need to make sure that the action doesn't complete\n\t// immediately, or the order some methods are called in could be slightly\n\t// different (e.g. when adding a new item after one has just completed will\n\t// trigger the next one to execute, which would terminate immediately,\n\t// instead of giving time for a second new thingy to be added)\n\tfunction queueAction() {\n\t\tconst deferred = $.Deferred();\n\t\tsetTimeout( deferred.resolve, 10 );\n\t\treturn deferred.promise();\n\t}\n\n\t// Asserts that the given stub functions were called in the given order.\n\t// SinonJS's assert.callOrder doesn't allow to check individual calls.\n\tfunction assertCalledInOrder() {\n\t\t// Map stubs to specific calls\n\t\tconst calls = Array.prototype.map.call( arguments, ( spy ) => {\n\t\t\tif ( !spy.assertCallsInOrderLastCall ) {\n\t\t\t\tspy.assertCallsInOrderLastCall = 0;\n\t\t\t}\n\t\t\treturn spy.getCall( spy.assertCallsInOrderLastCall++ );\n\t\t} );\n\t\tlet nextSpyCall;\n\t\t// Assert stuff\n\t\tfor ( let i = 0; i < calls.length - 1; i++ ) {\n\t\t\tconst currSpyCall = calls[ i ];\n\t\t\tnextSpyCall = calls[ i + 1 ];\n\t\t\tif ( currSpyCall ) {\n\t\t\t\tQUnit.assert.true(\n\t\t\t\t\tcurrSpyCall.callId < ( nextSpyCall ? nextSpyCall.callId : -1 ),\n\t\t\t\t\t'Call ' + ( i + 1 ) + ' (callId ' + currSpyCall.callId + ') is in the right order'\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tQUnit.assert.fail( 'Call ' + ( i + 1 ) + ' (never called) is in the right order' );\n\t\t\t}\n\t\t}\n\t\tQUnit.assert.true(\n\t\t\t!!nextSpyCall,\n\t\t\t'Call ' + calls.length + ' is in the right order'\n\t\t);\n\t}\n\n\tQUnit.test( 'Basic behavior', ( assert ) => {\n\t\tconst done = assert.async();\n\t\tconst action = sinon.spy( queueAction );\n\t\tconst queue = new uw.ConcurrentQueue( {\n\t\t\tcount: 3,\n\t\t\taction: action\n\t\t} );\n\n\t\tqueue.on( 'progress', () => {\n\t\t\tQUnit.assert.true( queue.running.length <= 3, 'No more than 3 items are executing' );\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\t// All items executed\n\t\t\tsinon.assert.callCount( action, 5 );\n\t\t\t// All items executed in the expected order\n\t\t\tsinon.assert.calledWith( action.getCall( 0 ), 'a' );\n\t\t\tsinon.assert.calledWith( action.getCall( 1 ), 'b' );\n\t\t\tsinon.assert.calledWith( action.getCall( 2 ), 'c' );\n\t\t\tsinon.assert.calledWith( action.getCall( 3 ), 'd' );\n\t\t\tsinon.assert.calledWith( action.getCall( 4 ), 'e' );\n\n\t\t\tdone();\n\t\t} );\n\n\t\t[ 'a', 'b', 'c', 'd', 'e' ].forEach( ( v ) => {\n\t\t\tqueue.addItem( v );\n\t\t} );\n\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Event emitting', ( assert ) => {\n\t\tconst done = assert.async();\n\t\tconst changeHandler = sinon.stub();\n\t\tconst progressHandler = sinon.stub();\n\t\tconst completeHandler = sinon.stub();\n\t\tconst queue = new uw.ConcurrentQueue( {\n\t\t\tcount: 3,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tsinon.assert.callCount( changeHandler, 3 );\n\t\t\tsinon.assert.callCount( progressHandler, 3 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Restarting a completed queue', ( assert ) => {\n\t\tconst done = assert.async();\n\t\tconst queue = new uw.ConcurrentQueue( {\n\t\t\tcount: 3,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\n\t\tqueue.once( 'complete', () => {\n\t\t\tQUnit.assert.equal( queue.completed, true );\n\t\t\tqueue.addItem( 'd' );\n\t\t\tqueue.addItem( 'e' );\n\n\t\t\tqueue.once( 'complete', () => {\n\t\t\t\tQUnit.assert.equal( queue.completed, true );\n\t\t\t\tdone();\n\t\t\t} );\n\n\t\t\tqueue.startExecuting();\n\t\t} );\n\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Empty queue completes', ( assert ) => {\n\t\tconst done = assert.async();\n\t\tconst queue = new uw.ConcurrentQueue( {\n\t\t\tcount: 3,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tQUnit.assert.equal( queue.completed, true );\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Adding new items while queue running', ( assert ) => {\n\t\tconst done = assert.async();\n\t\tconst changeHandler = sinon.stub();\n\t\tconst progressHandler = sinon.stub();\n\t\tconst completeHandler = sinon.stub();\n\t\tconst queue = new uw.ConcurrentQueue( {\n\t\t\tcount: 2,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tsinon.assert.callCount( changeHandler, 6 );\n\t\t\tsinon.assert.callCount( progressHandler, 6 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tprogressHandler, // Finished 'a' or 'b'\n\t\t\t\tchangeHandler, // Added 'd'\n\t\t\t\tchangeHandler, // Added 'e'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c' or 'd'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c', 'd' or 'e'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c', 'd' or 'e'\n\t\t\t\tchangeHandler, // Added 'f'\n\t\t\t\tprogressHandler, // Finished f'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.once( 'progress', () => {\n\t\t\tqueue.addItem( 'd' );\n\t\t\tqueue.addItem( 'e' );\n\t\t} );\n\t\tqueue.on( 'progress', () => {\n\t\t\tif ( queue.done.length === 5 ) {\n\t\t\t\tqueue.addItem( 'f' );\n\t\t\t}\n\t\t} );\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Deleting items while queue running', ( assert ) => {\n\t\tconst done = assert.async();\n\t\tconst changeHandler = sinon.stub();\n\t\tconst progressHandler = sinon.stub();\n\t\tconst completeHandler = sinon.stub();\n\t\tconst queue = new uw.ConcurrentQueue( {\n\t\t\tcount: 2,\n\t\t\taction: queueAction\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tsinon.assert.callCount( changeHandler, 8 );\n\t\t\tsinon.assert.callCount( progressHandler, 4 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tchangeHandler, // Added 'd'\n\t\t\t\tchangeHandler, // Added 'e'\n\t\t\t\tchangeHandler, // Added 'f'\n\t\t\t\tprogressHandler, // Finished 'a' or 'b'\n\t\t\t\tchangeHandler, // Removed first of the queued (not executing), which is 'd'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\tchangeHandler, // Removed the last one queued (not executing), which is 'f'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c' or 'e'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c' or 'e'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.addItem( 'd' );\n\t\tqueue.addItem( 'e' );\n\t\tqueue.addItem( 'f' );\n\t\tqueue.once( 'progress', () => {\n\t\t\tqueue.removeItem( queue.queued[ 0 ] );\n\n\t\t\tqueue.once( 'progress', () => {\n\t\t\t\tqueue.removeItem( queue.queued[ 0 ] );\n\t\t\t} );\n\t\t} );\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Deleting currently running item', ( assert ) => {\n\t\tconst done = assert.async();\n\t\tconst action = sinon.spy( queueAction );\n\t\tconst changeHandler = sinon.stub();\n\t\tconst progressHandler = sinon.stub();\n\t\tconst completeHandler = sinon.stub();\n\t\tconst queue = new uw.ConcurrentQueue( {\n\t\t\tcount: 2,\n\t\t\taction: action\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\t// Every item in the queue was executed...\n\t\t\tsinon.assert.callCount( action, 4 );\n\n\t\t\tsinon.assert.callCount( changeHandler, 5 );\n\t\t\t// ...but the one we removed wasn't registered as finished\n\t\t\tsinon.assert.callCount( progressHandler, 3 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tchangeHandler, // Added 'd'\n\t\t\t\taction, // Started 'a'\n\t\t\t\taction, // Started 'b'\n\t\t\t\tprogressHandler, // Finished 'a' or 'b'\n\t\t\t\tchangeHandler, // Removed first of the executing, which is 'a' or 'b'\n\t\t\t\taction, // Started 'c'\n\t\t\t\taction, // Started 'd' - note how two threads are running still\n\t\t\t\tprogressHandler, // Finished 'c' or 'd'\n\t\t\t\tprogressHandler, // Finished 'c' or 'd'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.addItem( 'd' );\n\t\tqueue.once( 'progress', () => {\n\t\t\tqueue.removeItem( queue.running[ 0 ] );\n\t\t} );\n\t\tqueue.startExecuting();\n\t} );\n\n\tQUnit.test( 'Adding a new item when almost done', ( assert ) => {\n\t\tconst done = assert.async();\n\t\t// This test seems extra flaky and was occasionally failing, double the delays\n\t\tconst action = sinon.spy( queueAction );\n\t\tconst changeHandler = sinon.stub();\n\t\tconst progressHandler = sinon.stub();\n\t\tconst completeHandler = sinon.stub();\n\t\tconst queue = new uw.ConcurrentQueue( {\n\t\t\tcount: 2,\n\t\t\taction: action\n\t\t} );\n\n\t\tqueue.connect( null, {\n\t\t\tchange: changeHandler,\n\t\t\tprogress: progressHandler,\n\t\t\tcomplete: completeHandler\n\t\t} );\n\n\t\tqueue.on( 'complete', () => {\n\t\t\tsinon.assert.callCount( action, 5 );\n\t\t\tsinon.assert.callCount( changeHandler, 5 );\n\t\t\tsinon.assert.callCount( progressHandler, 5 );\n\t\t\tsinon.assert.callCount( completeHandler, 1 );\n\n\t\t\tassertCalledInOrder(\n\t\t\t\tchangeHandler, // Added 'a'\n\t\t\t\tchangeHandler, // Added 'b'\n\t\t\t\tchangeHandler, // Added 'c'\n\t\t\t\tchangeHandler, // Added 'd'\n\t\t\t\taction, // Started 'a'\n\t\t\t\taction, // Started 'b'\n\t\t\t\tprogressHandler, // Finished 'a' or 'b'\n\t\t\t\taction, // Started 'c'\n\t\t\t\tprogressHandler, // Finished 'a', 'b' or 'c'\n\t\t\t\taction, // Started 'd'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c' or 'd'\n\t\t\t\tchangeHandler, // Added 'e'\n\t\t\t\taction, // Started 'e' -- this starts a new thread\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c', 'd' or 'e'\n\t\t\t\tprogressHandler, // Finished 'a', 'b', 'c', 'd' or 'e'\n\t\t\t\tcompleteHandler\n\t\t\t);\n\n\t\t\tdone();\n\t\t} );\n\n\t\tqueue.addItem( 'a' );\n\t\tqueue.addItem( 'b' );\n\t\tqueue.addItem( 'c' );\n\t\tqueue.addItem( 'd' );\n\t\tconst onProgress = function () {\n\t\t\tif ( queue.done.length === 3 ) {\n\t\t\t\tqueue.addItem( 'e' );\n\t\t\t\tqueue.off( 'progress', onProgress );\n\t\t\t}\n\t\t};\n\t\tqueue.on( 'progress', onProgress );\n\t\tqueue.startExecuting();\n\t} );\n\n}( mw.uploadWizard ) );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/uw.CopyMetadataWidget.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/uw.TitleDetailsWidget.test.js","messages":[],"suppressedMessages":[{"ruleId":"camelcase","severity":2,"message":"Identifier 'user_talk' is not in camel case.","line":67,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":67,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'wikipedia_talk' is not in camel case.","line":69,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":69,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'file_talk' is not in camel case.","line":71,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":71,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'mediawiki_talk' is not in camel case.","line":73,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":73,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'template_talk' is not in camel case.","line":75,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":75,"endColumn":18,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'help_talk' is not in camel case.","line":77,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":77,"endColumn":14,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'category_talk' is not in camel case.","line":79,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":79,"endColumn":18,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'image_talk' is not in camel case.","line":81,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":81,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'project_talk' is not in camel case.","line":83,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":83,"endColumn":17,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'antarctic_waterfowl' is not in camel case.","line":86,"column":5,"nodeType":"Identifier","messageId":"notCamelCase","endLine":86,"endColumn":24,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]}]
--- end ---
$ /usr/bin/npm ci
--- stderr ---
npm WARN deprecated @humanwhocodes/config-array@0.13.0: Use @eslint/config-array instead
npm WARN deprecated @humanwhocodes/object-schema@2.0.3: Use @eslint/object-schema instead
npm WARN deprecated glob@7.1.7: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
npm WARN deprecated eslint@8.57.1: This version is no longer supported. Please see https://eslint.org/version-support for other options.
--- stdout ---
added 503 packages, and audited 504 packages in 5s
118 packages are looking for funding
run `npm fund` for details
4 high severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
--- end ---
$ /usr/bin/npm test
--- stdout ---
> test
> grunt test
Running "eslint:all" (eslint) task
/src/repo/resources/controller/uw.controller.Deed.js
47:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/controller/uw.controller.Details.js
164:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/controller/uw.controller.Tutorial.js
61:3 warning Prefer .then to .done no-jquery/no-done-fail
61:3 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/details/uw.CategoriesDetailsWidget.js
213:34 warning Prefer .then to .fail no-jquery/no-done-fail
242:36 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/details/uw.DateDetailsWidget.js
16:31 warning OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true mediawiki/no-unlabeled-buttonwidget
/src/repo/resources/details/uw.LocationDetailsWidget.js
25:20 warning OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true mediawiki/no-unlabeled-buttonwidget
67:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/details/uw.SingleLanguageInputWidget.js
45:23 warning OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true mediawiki/no-unlabeled-buttonwidget
/src/repo/resources/details/uw.StatementWidget.js
70:1 warning The type 'dataValues.DataValue' is undefined jsdoc/no-undefined-types
105:1 warning The type 'datamodel.StatementList' is undefined jsdoc/no-undefined-types
117:1 warning The type 'datamodel.StatementList' is undefined jsdoc/no-undefined-types
131:1 warning The type 'dataValues.DataValue' is undefined jsdoc/no-undefined-types
132:1 warning The type 'datamodel.Statement' is undefined jsdoc/no-undefined-types
145:1 warning The type 'datamodel.StatementList' is undefined jsdoc/no-undefined-types
/src/repo/resources/details/uw.TitleDetailsWidget.js
112:1 warning Missing JSDoc @param "thorough" type jsdoc/require-param-type
161:30 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
215:27 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
217:21 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/mw.DestinationChecker.js
14:3 warning Found more than one @return declaration jsdoc/require-returns
14:3 warning Found more than one @return declaration jsdoc/require-returns-check
35:3 warning Found more than one @return declaration jsdoc/require-returns
35:3 warning Found more than one @return declaration jsdoc/require-returns-check
80:3 warning Found more than one @return declaration jsdoc/require-returns
80:3 warning Found more than one @return declaration jsdoc/require-returns-check
/src/repo/resources/mw.FlickrChecker.js
4:1 warning Missing JSDoc @param "ui" type jsdoc/require-param-type
5:1 warning Missing JSDoc @param "selectButton" type jsdoc/require-param-type
212:1 warning The type 'getPhotos' is undefined jsdoc/no-undefined-types
226:17 warning 'data' is already declared in the upper scope on line 219 column 15 no-shadow
246:1 warning The type 'getCollection' is undefined jsdoc/no-undefined-types
304:45 warning 'data' is already declared in the upper scope on line 293 column 15 no-shadow
314:1 warning The type 'getPhotos' is undefined jsdoc/no-undefined-types
331:1 warning The type 'getPhotos' is undefined jsdoc/no-undefined-types
375:10 warning Prefer .then to .fail no-jquery/no-done-fail
468:5 warning Prefer .then to .done no-jquery/no-done-fail
519:10 warning Prefer .then to .fail no-jquery/no-done-fail
581:4 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/mw.UploadWizard.js
4:1 warning Missing JSDoc @param "uw" type jsdoc/require-param-type
9:1 warning Missing JSDoc @param "config" type jsdoc/require-param-type
112:16 warning 'steps' is already declared in the upper scope on line 86 column 10 no-shadow
/src/repo/resources/mw.UploadWizardDeedChooser.js
32:42 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
40:17 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
44:21 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/mw.UploadWizardDetails.js
498:5 warning Prefer .then to .done no-jquery/no-done-fail
678:1 warning Missing JSDoc @param "thorough" type jsdoc/require-param-type
715:4 warning Prefer .then to .done no-jquery/no-done-fail
935:3 warning JSDoc @return declaration present but return expression not available in function jsdoc/require-returns-check
/src/repo/resources/mw.UploadWizardLicenseInput.js
50:20 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
/src/repo/resources/mw.UploadWizardUpload.js
380:3 warning Prefer .then to .done no-jquery/no-done-fail
380:3 warning Prefer .then to .fail no-jquery/no-done-fail
445:3 warning Prefer .then to .done no-jquery/no-done-fail
445:3 warning Prefer .then to .fail no-jquery/no-done-fail
766:3 warning Prefer .then to .done no-jquery/no-done-fail
766:3 warning Prefer .then to .fail no-jquery/no-done-fail
774:6 warning Prefer .then to .done no-jquery/no-done-fail
777:7 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/mw.UploadWizardUploadInterface.js
215:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/transports/mw.FormDataTransport.js
166:5 warning Prefer .then to .done no-jquery/no-done-fail
167:6 warning Prefer .then to .done no-jquery/no-done-fail
167:6 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Deed.js
51:3 warning Prefer .then to .done no-jquery/no-done-fail
86:5 warning Prefer .then to .done no-jquery/no-done-fail
108:6 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Details.js
108:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Thanks.js
150:3 warning Prefer .then to .done no-jquery/no-done-fail
180:4 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
/src/repo/resources/ui/steps/uw.ui.Tutorial.js
126:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Upload.js
334:6 warning Prefer .then to .done no-jquery/no-done-fail
344:3 warning Prefer .then to .done no-jquery/no-done-fail
528:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/uw.ui.Step.js
111:3 warning Prefer .then to .done no-jquery/no-done-fail
120:3 warning Prefer .then to .done no-jquery/no-done-fail
166:12 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
180:7 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
197:5 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/ui/uw.ui.Wizard.js
141:25 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/uw.LicenseGroup.js
148:48 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
180:56 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
617:3 warning Prefer .then to .done no-jquery/no-done-fail
617:3 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/uw.ValidationMessageElement.js
92:10 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
92:10 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
/src/repo/tests/qunit/controller/uw.controller.Details.test.js
127:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/tests/qunit/transports/mw.FormDataTransport.test.js
142:3 warning Prefer .then to .fail no-jquery/no-done-fail
175:10 warning Prefer .then to .done no-jquery/no-done-fail
194:10 warning Prefer .then to .done no-jquery/no-done-fail
214:3 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/tests/qunit/uw.ConcurrentQueue.test.js
54:5 warning Prefer .then to .fail no-jquery/no-done-fail
✖ 89 problems (0 errors, 89 warnings)
Running "stylelint:all" (stylelint) task
>> Linted 18 files without errors
Running "banana:UploadWizard" (banana) task
>> 2 message directories checked.
Done.
--- end ---
Upgrading c:mediawiki/mediawiki-codesniffer from 50.0.0 -> 51.0.0
$ /usr/bin/composer update
--- stderr ---
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 3 updates, 0 removals
- Upgrading composer/spdx-licenses (1.5.10 => 1.6.0)
- Upgrading mediawiki/mediawiki-codesniffer (v50.0.0 => v51.0.0)
- Upgrading phpcsstandards/phpcsextra (1.4.0 => 1.5.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 3 updates, 0 removals
0 [>---------------------------] 0 [->--------------------------]
- Upgrading phpcsstandards/phpcsextra (1.4.0 => 1.5.0): Extracting archive
- Upgrading composer/spdx-licenses (1.5.10 => 1.6.0): Extracting archive
- Upgrading mediawiki/mediawiki-codesniffer (v50.0.0 => v51.0.0): Extracting archive
0/3 [>---------------------------] 0%
3/3 [============================] 100%
Generating autoload files
16 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.
--- stdout ---
--- end ---
$ vendor/bin/phpcs --report=json
--- stdout ---
{"totals":{"errors":0,"warnings":0,"fixable":0},"files":{"\/src\/repo\/includes\/SchemaHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Specials\/UploadWizardSimpleForm.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/CodeMirrorHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/CodeEditorHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/CampaignContent.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/ApiFlickrBlacklist.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Config.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/.phan\/stubs\/namespaces.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/SpecialUploadWizardTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Specials\/SpecialCampaigns.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/FlickrBlacklist.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/CampaignContentHandler.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/.phan\/config.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Tutorial.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/ApiQueryAllCampaigns.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/CampaignPageFormatter.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/ConfigTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/UploadWizard.alias.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/CampaignHooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/ApiMediaDetection.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/tests\/phpunit\/ApiFlickrBlacklistTest.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/maintenance\/migrateCampaigns.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Specials\/SpecialUploadWizard.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/CampaignSchema.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Hooks.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/includes\/Campaign.php":{"errors":0,"warnings":0,"messages":[]},"\/src\/repo\/UploadWizard.config.php":{"errors":0,"warnings":0,"messages":[]}}}
--- end ---
$ /usr/bin/composer install
--- stderr ---
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Generating autoload files
16 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
--- stdout ---
--- end ---
$ /usr/bin/composer test
--- stderr ---
> parallel-lint . --exclude vendor --exclude node_modules
> phpcs -sp --cache
> minus-x check .
--- stdout ---
PHP 8.4.18 | 10 parallel jobs
........................... 27/27 (100%)
Checked 27 files in 0.1 seconds
No syntax error found
........................... 27 / 27 (100%)
Time: 235ms; Memory: 8MB
MinusX
======
Processing /src/repo...
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
..................................................
All good!
--- end ---
$ /usr/bin/npm audit --json
--- stdout ---
{
"auditReportVersion": 2,
"vulnerabilities": {
"gaze": {
"name": "gaze",
"severity": "high",
"isDirect": false,
"via": [
"globule"
],
"effects": [
"grunt-contrib-watch"
],
"range": ">=0.4.0",
"nodes": [
"node_modules/gaze"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
},
"globule": {
"name": "globule",
"severity": "high",
"isDirect": false,
"via": [
"minimatch"
],
"effects": [
"gaze"
],
"range": "*",
"nodes": [
"node_modules/globule"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
},
"grunt-contrib-watch": {
"name": "grunt-contrib-watch",
"severity": "high",
"isDirect": true,
"via": [
"gaze"
],
"effects": [],
"range": ">=0.5.0",
"nodes": [
"node_modules/grunt-contrib-watch"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
},
"minimatch": {
"name": "minimatch",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1113459,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch has a ReDoS via repeated wildcards with non-matching literal in pattern",
"url": "https://github.com/advisories/GHSA-3ppc-4f35-3m26",
"severity": "high",
"cwe": [
"CWE-1333"
],
"cvss": {
"score": 0,
"vectorString": null
},
"range": "<3.1.3"
},
{
"source": 1113538,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adjacent GLOBSTAR segments",
"url": "https://github.com/advisories/GHSA-7r86-cg39-jmmj",
"severity": "high",
"cwe": [
"CWE-407"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<3.1.3"
},
{
"source": 1113546,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions",
"url": "https://github.com/advisories/GHSA-23c5-xmqv-rm74",
"severity": "high",
"cwe": [
"CWE-1333"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<3.1.4"
}
],
"effects": [
"globule"
],
"range": "<=3.1.3",
"nodes": [
"node_modules/minimatch"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
}
},
"metadata": {
"vulnerabilities": {
"info": 0,
"low": 0,
"moderate": 0,
"high": 4,
"critical": 0,
"total": 4
},
"dependencies": {
"prod": 1,
"dev": 503,
"optional": 0,
"peer": 1,
"peerOptional": 0,
"total": 503
}
}
}
--- end ---
Attempting to npm audit fix
$ /usr/bin/npm audit fix --dry-run --only=dev --json
--- stderr ---
npm WARN invalid config only="dev" set in command line options
npm WARN invalid config Must be one of: null, prod, production
--- stdout ---
{
"added": 0,
"removed": 0,
"changed": 0,
"audited": 504,
"funding": 118,
"audit": {
"auditReportVersion": 2,
"vulnerabilities": {
"gaze": {
"name": "gaze",
"severity": "high",
"isDirect": false,
"via": [
"globule"
],
"effects": [
"grunt-contrib-watch"
],
"range": ">=0.4.0",
"nodes": [
"node_modules/gaze"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
},
"globule": {
"name": "globule",
"severity": "high",
"isDirect": false,
"via": [
"minimatch"
],
"effects": [
"gaze"
],
"range": "*",
"nodes": [
"node_modules/globule"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
},
"grunt-contrib-watch": {
"name": "grunt-contrib-watch",
"severity": "high",
"isDirect": true,
"via": [
"gaze"
],
"effects": [],
"range": ">=0.5.0",
"nodes": [
"node_modules/grunt-contrib-watch"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
},
"minimatch": {
"name": "minimatch",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1113459,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch has a ReDoS via repeated wildcards with non-matching literal in pattern",
"url": "https://github.com/advisories/GHSA-3ppc-4f35-3m26",
"severity": "high",
"cwe": [
"CWE-1333"
],
"cvss": {
"score": 0,
"vectorString": null
},
"range": "<3.1.3"
},
{
"source": 1113538,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adjacent GLOBSTAR segments",
"url": "https://github.com/advisories/GHSA-7r86-cg39-jmmj",
"severity": "high",
"cwe": [
"CWE-407"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<3.1.3"
},
{
"source": 1113546,
"name": "minimatch",
"dependency": "minimatch",
"title": "minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions",
"url": "https://github.com/advisories/GHSA-23c5-xmqv-rm74",
"severity": "high",
"cwe": [
"CWE-1333"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<3.1.4"
}
],
"effects": [
"globule"
],
"range": "<=3.1.3",
"nodes": [
"node_modules/minimatch"
],
"fixAvailable": {
"name": "grunt-contrib-watch",
"version": "0.4.4",
"isSemVerMajor": true
}
}
},
"metadata": {
"vulnerabilities": {
"info": 0,
"low": 0,
"moderate": 0,
"high": 4,
"critical": 0,
"total": 4
},
"dependencies": {
"prod": 1,
"dev": 503,
"optional": 0,
"peer": 1,
"peerOptional": 0,
"total": 503
}
}
}
}
--- end ---
{"added": 0, "removed": 0, "changed": 0, "audited": 504, "funding": 118, "audit": {"auditReportVersion": 2, "vulnerabilities": {"gaze": {"name": "gaze", "severity": "high", "isDirect": false, "via": ["globule"], "effects": ["grunt-contrib-watch"], "range": ">=0.4.0", "nodes": ["node_modules/gaze"], "fixAvailable": {"name": "grunt-contrib-watch", "version": "0.4.4", "isSemVerMajor": true}}, "globule": {"name": "globule", "severity": "high", "isDirect": false, "via": ["minimatch"], "effects": ["gaze"], "range": "*", "nodes": ["node_modules/globule"], "fixAvailable": {"name": "grunt-contrib-watch", "version": "0.4.4", "isSemVerMajor": true}}, "grunt-contrib-watch": {"name": "grunt-contrib-watch", "severity": "high", "isDirect": true, "via": ["gaze"], "effects": [], "range": ">=0.5.0", "nodes": ["node_modules/grunt-contrib-watch"], "fixAvailable": {"name": "grunt-contrib-watch", "version": "0.4.4", "isSemVerMajor": true}}, "minimatch": {"name": "minimatch", "severity": "high", "isDirect": false, "via": [{"source": 1113459, "name": "minimatch", "dependency": "minimatch", "title": "minimatch has a ReDoS via repeated wildcards with non-matching literal in pattern", "url": "https://github.com/advisories/GHSA-3ppc-4f35-3m26", "severity": "high", "cwe": ["CWE-1333"], "cvss": {"score": 0, "vectorString": null}, "range": "<3.1.3"}, {"source": 1113538, "name": "minimatch", "dependency": "minimatch", "title": "minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adjacent GLOBSTAR segments", "url": "https://github.com/advisories/GHSA-7r86-cg39-jmmj", "severity": "high", "cwe": ["CWE-407"], "cvss": {"score": 7.5, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}, "range": "<3.1.3"}, {"source": 1113546, "name": "minimatch", "dependency": "minimatch", "title": "minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions", "url": "https://github.com/advisories/GHSA-23c5-xmqv-rm74", "severity": "high", "cwe": ["CWE-1333"], "cvss": {"score": 7.5, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}, "range": "<3.1.4"}], "effects": ["globule"], "range": "<=3.1.3", "nodes": ["node_modules/minimatch"], "fixAvailable": {"name": "grunt-contrib-watch", "version": "0.4.4", "isSemVerMajor": true}}}, "metadata": {"vulnerabilities": {"info": 0, "low": 0, "moderate": 0, "high": 4, "critical": 0, "total": 4}, "dependencies": {"prod": 1, "dev": 503, "optional": 0, "peer": 1, "peerOptional": 0, "total": 503}}}}
$ /usr/bin/npm audit fix --only=dev
--- stderr ---
npm WARN invalid config only="dev" set in command line options
npm WARN invalid config Must be one of: null, prod, production
--- stdout ---
up to date, audited 504 packages in 1s
118 packages are looking for funding
run `npm fund` for details
# npm audit report
minimatch <=3.1.3
Severity: high
minimatch has a ReDoS via repeated wildcards with non-matching literal in pattern - https://github.com/advisories/GHSA-3ppc-4f35-3m26
minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adjacent GLOBSTAR segments - https://github.com/advisories/GHSA-7r86-cg39-jmmj
minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions - https://github.com/advisories/GHSA-23c5-xmqv-rm74
fix available via `npm audit fix --force`
Will install grunt-contrib-watch@0.4.4, which is a breaking change
node_modules/minimatch
globule *
Depends on vulnerable versions of minimatch
node_modules/globule
gaze >=0.4.0
Depends on vulnerable versions of globule
node_modules/gaze
grunt-contrib-watch >=0.5.0
Depends on vulnerable versions of gaze
node_modules/grunt-contrib-watch
4 high severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
--- end ---
Verifying that tests still pass
$ /usr/bin/npm ci
--- stderr ---
npm WARN deprecated @humanwhocodes/config-array@0.13.0: Use @eslint/config-array instead
npm WARN deprecated @humanwhocodes/object-schema@2.0.3: Use @eslint/object-schema instead
npm WARN deprecated glob@7.1.7: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
npm WARN deprecated eslint@8.57.1: This version is no longer supported. Please see https://eslint.org/version-support for other options.
--- stdout ---
added 503 packages, and audited 504 packages in 5s
118 packages are looking for funding
run `npm fund` for details
4 high severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
--- end ---
$ /usr/bin/npm test
--- stdout ---
> test
> grunt test
Running "eslint:all" (eslint) task
/src/repo/resources/controller/uw.controller.Deed.js
47:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/controller/uw.controller.Details.js
164:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/controller/uw.controller.Tutorial.js
61:3 warning Prefer .then to .done no-jquery/no-done-fail
61:3 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/details/uw.CategoriesDetailsWidget.js
213:34 warning Prefer .then to .fail no-jquery/no-done-fail
242:36 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/details/uw.DateDetailsWidget.js
16:31 warning OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true mediawiki/no-unlabeled-buttonwidget
/src/repo/resources/details/uw.LocationDetailsWidget.js
25:20 warning OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true mediawiki/no-unlabeled-buttonwidget
67:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/details/uw.SingleLanguageInputWidget.js
45:23 warning OOUI button has no label. Even icon-only buttons should set a label with invisibleLabel set to true mediawiki/no-unlabeled-buttonwidget
/src/repo/resources/details/uw.StatementWidget.js
70:1 warning The type 'dataValues.DataValue' is undefined jsdoc/no-undefined-types
105:1 warning The type 'datamodel.StatementList' is undefined jsdoc/no-undefined-types
117:1 warning The type 'datamodel.StatementList' is undefined jsdoc/no-undefined-types
131:1 warning The type 'dataValues.DataValue' is undefined jsdoc/no-undefined-types
132:1 warning The type 'datamodel.Statement' is undefined jsdoc/no-undefined-types
145:1 warning The type 'datamodel.StatementList' is undefined jsdoc/no-undefined-types
/src/repo/resources/details/uw.TitleDetailsWidget.js
112:1 warning Missing JSDoc @param "thorough" type jsdoc/require-param-type
161:30 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
215:27 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
217:21 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/mw.DestinationChecker.js
14:3 warning Found more than one @return declaration jsdoc/require-returns
14:3 warning Found more than one @return declaration jsdoc/require-returns-check
35:3 warning Found more than one @return declaration jsdoc/require-returns
35:3 warning Found more than one @return declaration jsdoc/require-returns-check
80:3 warning Found more than one @return declaration jsdoc/require-returns
80:3 warning Found more than one @return declaration jsdoc/require-returns-check
/src/repo/resources/mw.FlickrChecker.js
4:1 warning Missing JSDoc @param "ui" type jsdoc/require-param-type
5:1 warning Missing JSDoc @param "selectButton" type jsdoc/require-param-type
212:1 warning The type 'getPhotos' is undefined jsdoc/no-undefined-types
226:17 warning 'data' is already declared in the upper scope on line 219 column 15 no-shadow
246:1 warning The type 'getCollection' is undefined jsdoc/no-undefined-types
304:45 warning 'data' is already declared in the upper scope on line 293 column 15 no-shadow
314:1 warning The type 'getPhotos' is undefined jsdoc/no-undefined-types
331:1 warning The type 'getPhotos' is undefined jsdoc/no-undefined-types
375:10 warning Prefer .then to .fail no-jquery/no-done-fail
468:5 warning Prefer .then to .done no-jquery/no-done-fail
519:10 warning Prefer .then to .fail no-jquery/no-done-fail
581:4 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/mw.UploadWizard.js
4:1 warning Missing JSDoc @param "uw" type jsdoc/require-param-type
9:1 warning Missing JSDoc @param "config" type jsdoc/require-param-type
112:16 warning 'steps' is already declared in the upper scope on line 86 column 10 no-shadow
/src/repo/resources/mw.UploadWizardDeedChooser.js
32:42 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
40:17 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
44:21 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/mw.UploadWizardDetails.js
498:5 warning Prefer .then to .done no-jquery/no-done-fail
678:1 warning Missing JSDoc @param "thorough" type jsdoc/require-param-type
715:4 warning Prefer .then to .done no-jquery/no-done-fail
935:3 warning JSDoc @return declaration present but return expression not available in function jsdoc/require-returns-check
/src/repo/resources/mw.UploadWizardLicenseInput.js
50:20 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
/src/repo/resources/mw.UploadWizardUpload.js
380:3 warning Prefer .then to .done no-jquery/no-done-fail
380:3 warning Prefer .then to .fail no-jquery/no-done-fail
445:3 warning Prefer .then to .done no-jquery/no-done-fail
445:3 warning Prefer .then to .fail no-jquery/no-done-fail
766:3 warning Prefer .then to .done no-jquery/no-done-fail
766:3 warning Prefer .then to .fail no-jquery/no-done-fail
774:6 warning Prefer .then to .done no-jquery/no-done-fail
777:7 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/mw.UploadWizardUploadInterface.js
215:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/transports/mw.FormDataTransport.js
166:5 warning Prefer .then to .done no-jquery/no-done-fail
167:6 warning Prefer .then to .done no-jquery/no-done-fail
167:6 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Deed.js
51:3 warning Prefer .then to .done no-jquery/no-done-fail
86:5 warning Prefer .then to .done no-jquery/no-done-fail
108:6 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Details.js
108:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Thanks.js
150:3 warning Prefer .then to .done no-jquery/no-done-fail
180:4 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
/src/repo/resources/ui/steps/uw.ui.Tutorial.js
126:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/steps/uw.ui.Upload.js
334:6 warning Prefer .then to .done no-jquery/no-done-fail
344:3 warning Prefer .then to .done no-jquery/no-done-fail
528:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/resources/ui/uw.ui.Step.js
111:3 warning Prefer .then to .done no-jquery/no-done-fail
120:3 warning Prefer .then to .done no-jquery/no-done-fail
166:12 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
180:7 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
197:5 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/ui/uw.ui.Wizard.js
141:25 warning All possible message keys should be documented. See https://w.wiki/4r9a for details mediawiki/msg-doc
/src/repo/resources/uw.LicenseGroup.js
148:48 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
180:56 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
617:3 warning Prefer .then to .done no-jquery/no-done-fail
617:3 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/resources/uw.ValidationMessageElement.js
92:10 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
92:10 warning All possible CSS classes should be documented. See https://w.wiki/PS2 for details mediawiki/class-doc
/src/repo/tests/qunit/controller/uw.controller.Details.test.js
127:3 warning Prefer .then to .done no-jquery/no-done-fail
/src/repo/tests/qunit/transports/mw.FormDataTransport.test.js
142:3 warning Prefer .then to .fail no-jquery/no-done-fail
175:10 warning Prefer .then to .done no-jquery/no-done-fail
194:10 warning Prefer .then to .done no-jquery/no-done-fail
214:3 warning Prefer .then to .fail no-jquery/no-done-fail
/src/repo/tests/qunit/uw.ConcurrentQueue.test.js
54:5 warning Prefer .then to .fail no-jquery/no-done-fail
✖ 89 problems (0 errors, 89 warnings)
Running "stylelint:all" (stylelint) task
>> Linted 18 files without errors
Running "banana:UploadWizard" (banana) task
>> 2 message directories checked.
Done.
--- end ---
$ package-lock-lint /src/repo/package-lock.json
--- stdout ---
Checking /src/repo/package-lock.json
--- end ---
build: Updating dependencies
composer:
* mediawiki/mediawiki-codesniffer: 50.0.0 → 51.0.0
npm:
* eslint-config-wikimedia: 0.32.3 → 0.32.4
$ git add .
--- stdout ---
--- end ---
$ git commit -F /tmp/tmpysgnse9o
--- stdout ---
[master 4992fae] build: Updating dependencies
5 files changed, 451 insertions(+), 352 deletions(-)
--- end ---
$ git format-patch HEAD~1 --stdout
--- stdout ---
From 4992fae13e233a9fed3f54d1369f22d76556535e Mon Sep 17 00:00:00 2001
From: libraryupgrader <tools.libraryupgrader@tools.wmflabs.org>
Date: Mon, 4 May 2026 03:53:52 +0000
Subject: [PATCH] build: Updating dependencies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
composer:
* mediawiki/mediawiki-codesniffer: 50.0.0 → 51.0.0
npm:
* eslint-config-wikimedia: 0.32.3 → 0.32.4
Change-Id: Ic19d34190c1d25914c9a38415e7f77525e97b604
---
composer.json | 2 +-
package-lock.json | 795 ++++++++++++++++++++---------------
package.json | 2 +-
resources/uw.LicenseGroup.js | 2 -
resources/uw.units.js | 2 +-
5 files changed, 451 insertions(+), 352 deletions(-)
diff --git a/composer.json b/composer.json
index ea87f4b..0c86e21 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"require-dev": {
- "mediawiki/mediawiki-codesniffer": "50.0.0",
+ "mediawiki/mediawiki-codesniffer": "51.0.0",
"mediawiki/mediawiki-phan-config": "0.20.0",
"mediawiki/minus-x": "2.0.1",
"php-parallel-lint/php-console-highlighter": "1.0.0",
diff --git a/package-lock.json b/package-lock.json
index 4be23e1..34c2c42 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,7 +6,7 @@
"": {
"name": "UploadWizard",
"devDependencies": {
- "eslint-config-wikimedia": "0.32.3",
+ "eslint-config-wikimedia": "0.32.4",
"grunt": "1.6.2",
"grunt-banana-checker": "0.13.0",
"grunt-contrib-watch": "1.1.0",
@@ -221,19 +221,32 @@
}
},
"node_modules/@es-joy/jsdoccomment": {
- "version": "0.76.0",
- "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.76.0.tgz",
- "integrity": "sha512-g+RihtzFgGTx2WYCuTHbdOXJeAlGnROws0TeALx9ow/ZmOROOZkVg5wp/B44n0WJgI4SQFP1eWM2iRPlU2Y14w==",
+ "version": "0.86.0",
+ "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz",
+ "integrity": "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.8",
- "@typescript-eslint/types": "^8.46.0",
- "comment-parser": "1.4.1",
- "esquery": "^1.6.0",
- "jsdoc-type-pratt-parser": "~6.10.0"
+ "@typescript-eslint/types": "^8.58.0",
+ "comment-parser": "1.4.6",
+ "esquery": "^1.7.0",
+ "jsdoc-type-pratt-parser": "~7.2.0"
},
"engines": {
- "node": ">=20.11.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": {
+ "version": "8.59.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz",
+ "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==",
+ "dev": true,
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@es-joy/resolve.exports": {
@@ -246,11 +259,10 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
- "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.4.3"
},
@@ -386,9 +398,9 @@
}
},
"node_modules/@mdn/browser-compat-data": {
- "version": "5.7.6",
- "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
- "integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
+ "version": "6.1.5",
+ "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-6.1.5.tgz",
+ "integrity": "sha512-PzdZZzRhcXvKB0begee28n5lvwAcinGKYuLZOVxHAZm+n7y01ddEGfdS1ZXRuVcV+ndG6mSEAE8vgudom5UjYg==",
"dev": true
},
"node_modules/@nodelib/fs.scandir": {
@@ -588,20 +600,19 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz",
- "integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz",
+ "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
"dev": true,
"dependencies": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/type-utils": "8.46.0",
- "@typescript-eslint/utils": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "graphemer": "^1.4.0",
- "ignore": "^7.0.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/type-utils": "8.54.0",
+ "@typescript-eslint/utils": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "ignore": "^7.0.5",
"natural-compare": "^1.4.0",
- "ts-api-utils": "^2.1.0"
+ "ts-api-utils": "^2.4.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -611,7 +622,7 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "@typescript-eslint/parser": "^8.46.0",
+ "@typescript-eslint/parser": "^8.54.0",
"eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
@@ -626,16 +637,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz",
- "integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz",
+ "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "debug": "^4.3.4"
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -650,14 +661,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.0.tgz",
- "integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz",
+ "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==",
"dev": true,
"dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.46.0",
- "@typescript-eslint/types": "^8.46.0",
- "debug": "^4.3.4"
+ "@typescript-eslint/tsconfig-utils": "^8.54.0",
+ "@typescript-eslint/types": "^8.54.0",
+ "debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -671,13 +682,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz",
- "integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz",
+ "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0"
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -688,9 +699,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz",
- "integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz",
+ "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -704,16 +715,16 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz",
- "integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz",
+ "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0",
- "@typescript-eslint/utils": "8.46.0",
- "debug": "^4.3.4",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0",
+ "@typescript-eslint/utils": "8.54.0",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.4.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -728,9 +739,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz",
- "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz",
+ "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -741,21 +752,20 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz",
- "integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz",
+ "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/project-service": "8.46.0",
- "@typescript-eslint/tsconfig-utils": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/project-service": "8.54.0",
+ "@typescript-eslint/tsconfig-utils": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "debug": "^4.4.3",
+ "minimatch": "^9.0.5",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.4.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -769,9 +779,9 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
- "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
+ "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
@@ -793,15 +803,15 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.0.tgz",
- "integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz",
+ "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==",
"dev": true,
"dependencies": {
- "@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0"
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -816,12 +826,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz",
- "integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz",
+ "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "8.46.0",
+ "@typescript-eslint/types": "8.54.0",
"eslint-visitor-keys": "^4.2.1"
},
"engines": {
@@ -867,11 +877,10 @@
"dev": true
},
"node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
- "license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@@ -1000,6 +1009,12 @@
"@mdn/browser-compat-data": "^5.6.19"
}
},
+ "node_modules/ast-metadata-inferer/node_modules/@mdn/browser-compat-data": {
+ "version": "5.7.6",
+ "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
+ "integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
+ "dev": true
+ },
"node_modules/astral-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
@@ -1306,9 +1321,9 @@
}
},
"node_modules/comment-parser": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz",
- "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==",
+ "version": "1.4.6",
+ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz",
+ "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==",
"dev": true,
"engines": {
"node": ">= 12.0.0"
@@ -1690,13 +1705,13 @@
}
},
"node_modules/enhanced-resolve": {
- "version": "5.18.3",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
- "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
+ "version": "5.21.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.0.tgz",
+ "integrity": "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
+ "tapable": "^2.3.3"
},
"engines": {
"node": ">=10.13.0"
@@ -1866,46 +1881,47 @@
}
},
"node_modules/eslint-config-wikimedia": {
- "version": "0.32.3",
- "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.32.3.tgz",
- "integrity": "sha512-Ekz2/ozpCCjQl3VbC6dW7ChqoW7FRilLDxmJ+FJOZhIxxzZSZR5QqQOAGWSZAlG1ONkZbYV/TPwGLWZcrNxyaA==",
+ "version": "0.32.4",
+ "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.32.4.tgz",
+ "integrity": "sha512-zcHJYss2vo8HK5PzkFuaV9mzaSGRuhA+jFGoQ4rNIwWz0usZsuQ2LYpkKxrbCVX1CbV0PzG+jJ6p0cLI+G37JQ==",
"dev": true,
"dependencies": {
"@stylistic/eslint-plugin": "^3.1.0",
- "@typescript-eslint/eslint-plugin": "8.46.0",
- "@typescript-eslint/parser": "8.46.0",
+ "@typescript-eslint/eslint-plugin": "8.54.0",
+ "@typescript-eslint/parser": "8.54.0",
"browserslist-config-wikimedia": "^0.7.0",
- "eslint": "^8.57.0",
- "eslint-plugin-compat": "^6.0.2",
+ "eslint-plugin-compat": "^6.1.0",
"eslint-plugin-es-x": "^8.7.0",
- "eslint-plugin-jest": "^29.0.1",
- "eslint-plugin-jsdoc": "61.3.0",
+ "eslint-plugin-jest": "^29.12.2",
+ "eslint-plugin-jsdoc": "^62.9.0",
"eslint-plugin-json-es": "^1.6.0",
- "eslint-plugin-mediawiki": "^0.8.2",
+ "eslint-plugin-mediawiki": "^0.8.3",
"eslint-plugin-mocha": "^10.5.0",
- "eslint-plugin-n": "^17.23.1",
- "eslint-plugin-no-jquery": "^3.1.1",
- "eslint-plugin-qunit": "^8.2.5",
- "eslint-plugin-security": "^3.0.1",
+ "eslint-plugin-n": "^17.24.0",
+ "eslint-plugin-no-jquery": "^4.0.0",
+ "eslint-plugin-qunit": "^8.2.6",
+ "eslint-plugin-security": "^4.0.0",
"eslint-plugin-unicorn": "^56.0.1",
"eslint-plugin-vue": "^9.33.0",
- "eslint-plugin-wdio": "^9.16.2",
+ "eslint-plugin-wdio": "9.23.0",
"eslint-plugin-yml": "^1.19.0"
},
"engines": {
"node": ">=20 <25"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0"
}
},
"node_modules/eslint-plugin-compat": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.0.2.tgz",
- "integrity": "sha512-1ME+YfJjmOz1blH0nPZpHgjMGK4kjgEeoYqGCqoBPQ/mGu/dJzdoP0f1C8H2jcWZjzhZjAMccbM/VdXhPORIfA==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.2.1.tgz",
+ "integrity": "sha512-gLKqUH+lQcCL+HzsROUjBDvakc5Zaga51Y4ZAkPCXc41pzKBfyluqTr2j8zOx8QQQb7zyglu1LVoL5aSNWf2SQ==",
"dev": true,
"dependencies": {
- "@mdn/browser-compat-data": "^5.5.35",
+ "@mdn/browser-compat-data": "^6.1.1",
"ast-metadata-inferer": "^0.8.1",
- "browserslist": "^4.24.2",
- "caniuse-lite": "^1.0.30001687",
+ "browserslist": "^4.25.2",
"find-up": "^5.0.0",
"globals": "^15.7.0",
"lodash.memoize": "^4.1.2",
@@ -1915,7 +1931,7 @@
"node": ">=18.x"
},
"peerDependencies": {
- "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
+ "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0"
}
},
"node_modules/eslint-plugin-compat/node_modules/globals": {
@@ -1981,57 +1997,57 @@
}
},
"node_modules/eslint-plugin-jsdoc": {
- "version": "61.3.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-61.3.0.tgz",
- "integrity": "sha512-E4m/5J5lrasd63Z74q4CCZ4PFnywnnrcvA7zZ98802NPhrZKKTp5NH+XAT+afcjXp2ps2/OQF5gPSWCT2XFCJg==",
+ "version": "62.9.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.9.0.tgz",
+ "integrity": "sha512-PY7/X4jrVgoIDncUmITlUqK546Ltmx/Pd4Hdsu4CvSjryQZJI2mEV4vrdMufyTetMiZ5taNSqvK//BTgVUlNkA==",
"dev": true,
"dependencies": {
- "@es-joy/jsdoccomment": "~0.76.0",
+ "@es-joy/jsdoccomment": "~0.86.0",
"@es-joy/resolve.exports": "1.2.0",
"are-docs-informative": "^0.0.2",
- "comment-parser": "1.4.1",
+ "comment-parser": "1.4.6",
"debug": "^4.4.3",
"escape-string-regexp": "^4.0.0",
- "espree": "^10.4.0",
- "esquery": "^1.6.0",
+ "espree": "^11.2.0",
+ "esquery": "^1.7.0",
"html-entities": "^2.6.0",
"object-deep-merge": "^2.0.0",
"parse-imports-exports": "^0.2.4",
- "semver": "^7.7.3",
+ "semver": "^7.7.4",
"spdx-expression-parse": "^4.0.0",
"to-valid-identifier": "^1.0.0"
},
"engines": {
- "node": ">=20.11.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
+ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0"
}
},
"node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true,
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-plugin-jsdoc/node_modules/espree": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
- "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+ "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
"dev": true,
"dependencies": {
- "acorn": "^8.15.0",
+ "acorn": "^8.16.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.2.1"
+ "eslint-visitor-keys": "^5.0.1"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
@@ -2051,9 +2067,9 @@
}
},
"node_modules/eslint-plugin-mediawiki": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.8.2.tgz",
- "integrity": "sha512-ydYrpkzm8IVVDQA96QPF3HnFd2xjkIEh7gixD2gvOqUbUZF0p36LtpWXOFAlPWAvHLePWbNNTD5ovd3d4hEtog==",
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.8.3.tgz",
+ "integrity": "sha512-RQKZd40C1taMDk5N9+aFLEBGBB95RNG7Gc54EsJ8pHsJu8//nIdpxNFWPtQz6RNxz6pZUXBnMCxzkMOLM3Mm1w==",
"dev": true,
"dependencies": {
"upath": "^2.0.1"
@@ -2080,9 +2096,9 @@
}
},
"node_modules/eslint-plugin-n": {
- "version": "17.23.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.23.1.tgz",
- "integrity": "sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==",
+ "version": "17.24.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.24.0.tgz",
+ "integrity": "sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.5.0",
@@ -2154,31 +2170,34 @@
}
},
"node_modules/eslint-plugin-no-jquery": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
- "integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-4.0.0.tgz",
+ "integrity": "sha512-ZR631D3qIQfgjKOAcgvYa5cB8xdTvFXAD5MbK5x5WltLSwFxmGnoaTXNtnptFU7py07ALrIe5dZRYncu4RD/Ug==",
"dev": true,
"peerDependencies": {
- "eslint": ">=8.0.0"
+ "eslint": ">=8.0.0 <9.0.0"
}
},
"node_modules/eslint-plugin-qunit": {
- "version": "8.2.5",
- "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-8.2.5.tgz",
- "integrity": "sha512-qr7RJCYImKQjB+39q4q46i1l7p1V3joHzBE5CAYfxn5tfVFjrnjn/tw7q/kDyweU9kAIcLul0Dx/KWVUCb3BgA==",
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-8.2.6.tgz",
+ "integrity": "sha512-S1jC/DIW9J8VtNX4uG1vlf5FZVrfQFlcuiYmvTHR2IICUhubHqpWA5o+qS1tujh+81Gs39omKV2D4OXfbSJE5g==",
"dev": true,
"dependencies": {
- "eslint-utils": "^3.0.0",
+ "@eslint-community/eslint-utils": "^4.4.0",
"requireindex": "^1.2.0"
},
"engines": {
"node": "^16.0.0 || ^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=8.38.0"
}
},
"node_modules/eslint-plugin-security": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.1.tgz",
- "integrity": "sha512-XjVGBhtDZJfyuhIxnQ/WMm385RbX3DBu7H1J7HNNhmB2tnGxMeqVSnYv79oAj992ayvIBZghsymwkYFS6cGH4Q==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-4.0.0.tgz",
+ "integrity": "sha512-tfuQT8K/Li1ZxhFzyD8wPIKtlzZxqBcPr9q0jFMQ77wWAbKBVEhaMPVQRTMTvCMUDhwBe5vPVqQPwAGk/ASfxQ==",
"dev": true,
"dependencies": {
"safe-regex": "^2.1.1"
@@ -2258,9 +2277,9 @@
}
},
"node_modules/eslint-plugin-wdio": {
- "version": "9.16.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-9.16.2.tgz",
- "integrity": "sha512-qkqsPgxN70OnUPWMjmzJbSbvm2+Q087JIGss53/OFI4Y46xKlV5VLhLiYealaAibAiXmnfWKd0tERjZAzVL87A==",
+ "version": "9.23.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-9.23.0.tgz",
+ "integrity": "sha512-8tcpupzp2Qmv+uSfhzeHi42LVA9PyjkpMBPclSIkPxBfXpj4fMrejwAHu1PROh1OmJN1VQcGQUTWvSzyRcV2vA==",
"dev": true,
"engines": {
"node": ">=18.20.0"
@@ -2405,9 +2424,9 @@
}
},
"node_modules/esquery": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
- "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
"dev": true,
"dependencies": {
"estraverse": "^5.1.0"
@@ -2765,9 +2784,9 @@
}
},
"node_modules/get-tsconfig": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
- "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
+ "version": "4.14.0",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz",
+ "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==",
"dev": true,
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
@@ -3562,9 +3581,9 @@
"dev": true
},
"node_modules/jsdoc-type-pratt-parser": {
- "version": "6.10.0",
- "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-6.10.0.tgz",
- "integrity": "sha512-+LexoTRyYui5iOhJGn13N9ZazL23nAHGkXsa1p/C8yeq79WRfLBag6ZZ0FQG2aRoc9yfo59JT9EYCQonOkHKkQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.2.0.tgz",
+ "integrity": "sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==",
"dev": true,
"engines": {
"node": ">=20.0.0"
@@ -4944,9 +4963,9 @@
"dev": true
},
"node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -5572,9 +5591,9 @@
"dev": true
},
"node_modules/tapable": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
- "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
"dev": true,
"engines": {
"node": ">=6"
@@ -5613,6 +5632,51 @@
"ms": "^2.1.1"
}
},
+ "node_modules/tinyglobby": {
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+ "dev": true,
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -5642,9 +5706,9 @@
}
},
"node_modules/ts-api-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
- "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
"dev": true,
"engines": {
"node": ">=18.12"
@@ -6170,16 +6234,24 @@
"dev": true
},
"@es-joy/jsdoccomment": {
- "version": "0.76.0",
- "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.76.0.tgz",
- "integrity": "sha512-g+RihtzFgGTx2WYCuTHbdOXJeAlGnROws0TeALx9ow/ZmOROOZkVg5wp/B44n0WJgI4SQFP1eWM2iRPlU2Y14w==",
+ "version": "0.86.0",
+ "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz",
+ "integrity": "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw==",
"dev": true,
"requires": {
"@types/estree": "^1.0.8",
- "@typescript-eslint/types": "^8.46.0",
- "comment-parser": "1.4.1",
- "esquery": "^1.6.0",
- "jsdoc-type-pratt-parser": "~6.10.0"
+ "@typescript-eslint/types": "^8.58.0",
+ "comment-parser": "1.4.6",
+ "esquery": "^1.7.0",
+ "jsdoc-type-pratt-parser": "~7.2.0"
+ },
+ "dependencies": {
+ "@typescript-eslint/types": {
+ "version": "8.59.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz",
+ "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==",
+ "dev": true
+ }
}
},
"@es-joy/resolve.exports": {
@@ -6189,9 +6261,9 @@
"dev": true
},
"@eslint-community/eslint-utils": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
- "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
"dev": true,
"requires": {
"eslint-visitor-keys": "^3.4.3"
@@ -6285,9 +6357,9 @@
}
},
"@mdn/browser-compat-data": {
- "version": "5.7.6",
- "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
- "integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
+ "version": "6.1.5",
+ "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-6.1.5.tgz",
+ "integrity": "sha512-PzdZZzRhcXvKB0begee28n5lvwAcinGKYuLZOVxHAZm+n7y01ddEGfdS1ZXRuVcV+ndG6mSEAE8vgudom5UjYg==",
"dev": true
},
"@nodelib/fs.scandir": {
@@ -6434,20 +6506,19 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz",
- "integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz",
+ "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
"dev": true,
"requires": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/type-utils": "8.46.0",
- "@typescript-eslint/utils": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "graphemer": "^1.4.0",
- "ignore": "^7.0.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/type-utils": "8.54.0",
+ "@typescript-eslint/utils": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "ignore": "^7.0.5",
"natural-compare": "^1.4.0",
- "ts-api-utils": "^2.1.0"
+ "ts-api-utils": "^2.4.0"
},
"dependencies": {
"ignore": {
@@ -6459,87 +6530,86 @@
}
},
"@typescript-eslint/parser": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz",
- "integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz",
+ "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
"dev": true,
"requires": {
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "debug": "^4.3.4"
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "debug": "^4.4.3"
}
},
"@typescript-eslint/project-service": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.0.tgz",
- "integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz",
+ "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==",
"dev": true,
"requires": {
- "@typescript-eslint/tsconfig-utils": "^8.46.0",
- "@typescript-eslint/types": "^8.46.0",
- "debug": "^4.3.4"
+ "@typescript-eslint/tsconfig-utils": "^8.54.0",
+ "@typescript-eslint/types": "^8.54.0",
+ "debug": "^4.4.3"
}
},
"@typescript-eslint/scope-manager": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz",
- "integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz",
+ "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0"
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0"
}
},
"@typescript-eslint/tsconfig-utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz",
- "integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz",
+ "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==",
"dev": true,
"requires": {}
},
"@typescript-eslint/type-utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz",
- "integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz",
+ "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0",
- "@typescript-eslint/utils": "8.46.0",
- "debug": "^4.3.4",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0",
+ "@typescript-eslint/utils": "8.54.0",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.4.0"
}
},
"@typescript-eslint/types": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz",
- "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz",
+ "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz",
- "integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz",
+ "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==",
"dev": true,
"requires": {
- "@typescript-eslint/project-service": "8.46.0",
- "@typescript-eslint/tsconfig-utils": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/visitor-keys": "8.46.0",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/project-service": "8.54.0",
+ "@typescript-eslint/tsconfig-utils": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/visitor-keys": "8.54.0",
+ "debug": "^4.4.3",
+ "minimatch": "^9.0.5",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.4.0"
},
"dependencies": {
"brace-expansion": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
- "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
+ "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0"
@@ -6557,24 +6627,24 @@
}
},
"@typescript-eslint/utils": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.0.tgz",
- "integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz",
+ "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==",
"dev": true,
"requires": {
- "@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.46.0",
- "@typescript-eslint/types": "8.46.0",
- "@typescript-eslint/typescript-estree": "8.46.0"
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.54.0",
+ "@typescript-eslint/types": "8.54.0",
+ "@typescript-eslint/typescript-estree": "8.54.0"
}
},
"@typescript-eslint/visitor-keys": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz",
- "integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==",
+ "version": "8.54.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz",
+ "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "8.46.0",
+ "@typescript-eslint/types": "8.54.0",
"eslint-visitor-keys": "^4.2.1"
},
"dependencies": {
@@ -6605,9 +6675,9 @@
"dev": true
},
"acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true
},
"acorn-jsx": {
@@ -6696,6 +6766,14 @@
"dev": true,
"requires": {
"@mdn/browser-compat-data": "^5.6.19"
+ },
+ "dependencies": {
+ "@mdn/browser-compat-data": {
+ "version": "5.7.6",
+ "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
+ "integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
+ "dev": true
+ }
}
},
"astral-regex": {
@@ -6909,9 +6987,9 @@
"dev": true
},
"comment-parser": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz",
- "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==",
+ "version": "1.4.6",
+ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz",
+ "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==",
"dev": true
},
"concat-map": {
@@ -7201,13 +7279,13 @@
}
},
"enhanced-resolve": {
- "version": "5.18.3",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
- "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
+ "version": "5.21.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.0.tgz",
+ "integrity": "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
+ "tapable": "^2.3.3"
}
},
"entities": {
@@ -7356,43 +7434,41 @@
}
},
"eslint-config-wikimedia": {
- "version": "0.32.3",
- "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.32.3.tgz",
- "integrity": "sha512-Ekz2/ozpCCjQl3VbC6dW7ChqoW7FRilLDxmJ+FJOZhIxxzZSZR5QqQOAGWSZAlG1ONkZbYV/TPwGLWZcrNxyaA==",
+ "version": "0.32.4",
+ "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.32.4.tgz",
+ "integrity": "sha512-zcHJYss2vo8HK5PzkFuaV9mzaSGRuhA+jFGoQ4rNIwWz0usZsuQ2LYpkKxrbCVX1CbV0PzG+jJ6p0cLI+G37JQ==",
"dev": true,
"requires": {
"@stylistic/eslint-plugin": "^3.1.0",
- "@typescript-eslint/eslint-plugin": "8.46.0",
- "@typescript-eslint/parser": "8.46.0",
+ "@typescript-eslint/eslint-plugin": "8.54.0",
+ "@typescript-eslint/parser": "8.54.0",
"browserslist-config-wikimedia": "^0.7.0",
- "eslint": "^8.57.0",
- "eslint-plugin-compat": "^6.0.2",
+ "eslint-plugin-compat": "^6.1.0",
"eslint-plugin-es-x": "^8.7.0",
- "eslint-plugin-jest": "^29.0.1",
- "eslint-plugin-jsdoc": "61.3.0",
+ "eslint-plugin-jest": "^29.12.2",
+ "eslint-plugin-jsdoc": "^62.9.0",
"eslint-plugin-json-es": "^1.6.0",
- "eslint-plugin-mediawiki": "^0.8.2",
+ "eslint-plugin-mediawiki": "^0.8.3",
"eslint-plugin-mocha": "^10.5.0",
- "eslint-plugin-n": "^17.23.1",
- "eslint-plugin-no-jquery": "^3.1.1",
- "eslint-plugin-qunit": "^8.2.5",
- "eslint-plugin-security": "^3.0.1",
+ "eslint-plugin-n": "^17.24.0",
+ "eslint-plugin-no-jquery": "^4.0.0",
+ "eslint-plugin-qunit": "^8.2.6",
+ "eslint-plugin-security": "^4.0.0",
"eslint-plugin-unicorn": "^56.0.1",
"eslint-plugin-vue": "^9.33.0",
- "eslint-plugin-wdio": "^9.16.2",
+ "eslint-plugin-wdio": "9.23.0",
"eslint-plugin-yml": "^1.19.0"
}
},
"eslint-plugin-compat": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.0.2.tgz",
- "integrity": "sha512-1ME+YfJjmOz1blH0nPZpHgjMGK4kjgEeoYqGCqoBPQ/mGu/dJzdoP0f1C8H2jcWZjzhZjAMccbM/VdXhPORIfA==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.2.1.tgz",
+ "integrity": "sha512-gLKqUH+lQcCL+HzsROUjBDvakc5Zaga51Y4ZAkPCXc41pzKBfyluqTr2j8zOx8QQQb7zyglu1LVoL5aSNWf2SQ==",
"dev": true,
"requires": {
- "@mdn/browser-compat-data": "^5.5.35",
+ "@mdn/browser-compat-data": "^6.1.1",
"ast-metadata-inferer": "^0.8.1",
- "browserslist": "^4.24.2",
- "caniuse-lite": "^1.0.30001687",
+ "browserslist": "^4.25.2",
"find-up": "^5.0.0",
"globals": "^15.7.0",
"lodash.memoize": "^4.1.2",
@@ -7428,42 +7504,42 @@
}
},
"eslint-plugin-jsdoc": {
- "version": "61.3.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-61.3.0.tgz",
- "integrity": "sha512-E4m/5J5lrasd63Z74q4CCZ4PFnywnnrcvA7zZ98802NPhrZKKTp5NH+XAT+afcjXp2ps2/OQF5gPSWCT2XFCJg==",
+ "version": "62.9.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.9.0.tgz",
+ "integrity": "sha512-PY7/X4jrVgoIDncUmITlUqK546Ltmx/Pd4Hdsu4CvSjryQZJI2mEV4vrdMufyTetMiZ5taNSqvK//BTgVUlNkA==",
"dev": true,
"requires": {
- "@es-joy/jsdoccomment": "~0.76.0",
+ "@es-joy/jsdoccomment": "~0.86.0",
"@es-joy/resolve.exports": "1.2.0",
"are-docs-informative": "^0.0.2",
- "comment-parser": "1.4.1",
+ "comment-parser": "1.4.6",
"debug": "^4.4.3",
"escape-string-regexp": "^4.0.0",
- "espree": "^10.4.0",
- "esquery": "^1.6.0",
+ "espree": "^11.2.0",
+ "esquery": "^1.7.0",
"html-entities": "^2.6.0",
"object-deep-merge": "^2.0.0",
"parse-imports-exports": "^0.2.4",
- "semver": "^7.7.3",
+ "semver": "^7.7.4",
"spdx-expression-parse": "^4.0.0",
"to-valid-identifier": "^1.0.0"
},
"dependencies": {
"eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true
},
"espree": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
- "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+ "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
"dev": true,
"requires": {
- "acorn": "^8.15.0",
+ "acorn": "^8.16.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.2.1"
+ "eslint-visitor-keys": "^5.0.1"
}
}
}
@@ -7479,9 +7555,9 @@
}
},
"eslint-plugin-mediawiki": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.8.2.tgz",
- "integrity": "sha512-ydYrpkzm8IVVDQA96QPF3HnFd2xjkIEh7gixD2gvOqUbUZF0p36LtpWXOFAlPWAvHLePWbNNTD5ovd3d4hEtog==",
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.8.3.tgz",
+ "integrity": "sha512-RQKZd40C1taMDk5N9+aFLEBGBB95RNG7Gc54EsJ8pHsJu8//nIdpxNFWPtQz6RNxz6pZUXBnMCxzkMOLM3Mm1w==",
"dev": true,
"requires": {
"upath": "^2.0.1"
@@ -7499,9 +7575,9 @@
}
},
"eslint-plugin-n": {
- "version": "17.23.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.23.1.tgz",
- "integrity": "sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==",
+ "version": "17.24.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.24.0.tgz",
+ "integrity": "sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.5.0",
@@ -7544,26 +7620,26 @@
}
},
"eslint-plugin-no-jquery": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
- "integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-4.0.0.tgz",
+ "integrity": "sha512-ZR631D3qIQfgjKOAcgvYa5cB8xdTvFXAD5MbK5x5WltLSwFxmGnoaTXNtnptFU7py07ALrIe5dZRYncu4RD/Ug==",
"dev": true,
"requires": {}
},
"eslint-plugin-qunit": {
- "version": "8.2.5",
- "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-8.2.5.tgz",
- "integrity": "sha512-qr7RJCYImKQjB+39q4q46i1l7p1V3joHzBE5CAYfxn5tfVFjrnjn/tw7q/kDyweU9kAIcLul0Dx/KWVUCb3BgA==",
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-8.2.6.tgz",
+ "integrity": "sha512-S1jC/DIW9J8VtNX4uG1vlf5FZVrfQFlcuiYmvTHR2IICUhubHqpWA5o+qS1tujh+81Gs39omKV2D4OXfbSJE5g==",
"dev": true,
"requires": {
- "eslint-utils": "^3.0.0",
+ "@eslint-community/eslint-utils": "^4.4.0",
"requireindex": "^1.2.0"
}
},
"eslint-plugin-security": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.1.tgz",
- "integrity": "sha512-XjVGBhtDZJfyuhIxnQ/WMm385RbX3DBu7H1J7HNNhmB2tnGxMeqVSnYv79oAj992ayvIBZghsymwkYFS6cGH4Q==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-4.0.0.tgz",
+ "integrity": "sha512-tfuQT8K/Li1ZxhFzyD8wPIKtlzZxqBcPr9q0jFMQ77wWAbKBVEhaMPVQRTMTvCMUDhwBe5vPVqQPwAGk/ASfxQ==",
"dev": true,
"requires": {
"safe-regex": "^2.1.1"
@@ -7618,9 +7694,9 @@
}
},
"eslint-plugin-wdio": {
- "version": "9.16.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-9.16.2.tgz",
- "integrity": "sha512-qkqsPgxN70OnUPWMjmzJbSbvm2+Q087JIGss53/OFI4Y46xKlV5VLhLiYealaAibAiXmnfWKd0tERjZAzVL87A==",
+ "version": "9.23.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-9.23.0.tgz",
+ "integrity": "sha512-8tcpupzp2Qmv+uSfhzeHi42LVA9PyjkpMBPclSIkPxBfXpj4fMrejwAHu1PROh1OmJN1VQcGQUTWvSzyRcV2vA==",
"dev": true
},
"eslint-plugin-yml": {
@@ -7688,9 +7764,9 @@
"dev": true
},
"esquery": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
- "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
"dev": true,
"requires": {
"estraverse": "^5.1.0"
@@ -7969,9 +8045,9 @@
}
},
"get-tsconfig": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
- "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
+ "version": "4.14.0",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz",
+ "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==",
"dev": true,
"requires": {
"resolve-pkg-maps": "^1.0.0"
@@ -8569,9 +8645,9 @@
"dev": true
},
"jsdoc-type-pratt-parser": {
- "version": "6.10.0",
- "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-6.10.0.tgz",
- "integrity": "sha512-+LexoTRyYui5iOhJGn13N9ZazL23nAHGkXsa1p/C8yeq79WRfLBag6ZZ0FQG2aRoc9yfo59JT9EYCQonOkHKkQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.2.0.tgz",
+ "integrity": "sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==",
"dev": true
},
"jsdoc-wmf-theme": {
@@ -9576,9 +9652,9 @@
"dev": true
},
"semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"dev": true
},
"shebang-command": {
@@ -10008,9 +10084,9 @@
}
},
"tapable": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
- "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
"dev": true
},
"text-table": {
@@ -10044,6 +10120,31 @@
}
}
},
+ "tinyglobby": {
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+ "dev": true,
+ "requires": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "dependencies": {
+ "fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "requires": {}
+ },
+ "picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true
+ }
+ }
+ },
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -10064,9 +10165,9 @@
}
},
"ts-api-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
- "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
"dev": true,
"requires": {}
},
diff --git a/package.json b/package.json
index 0f5882c..fb8a802 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"test": "grunt test"
},
"devDependencies": {
- "eslint-config-wikimedia": "0.32.3",
+ "eslint-config-wikimedia": "0.32.4",
"grunt": "1.6.2",
"grunt-banana-checker": "0.13.0",
"grunt-contrib-watch": "1.1.0",
diff --git a/resources/uw.LicenseGroup.js b/resources/uw.LicenseGroup.js
index fb8b802..395baac 100644
--- a/resources/uw.LicenseGroup.js
+++ b/resources/uw.LicenseGroup.js
@@ -161,7 +161,6 @@
options.push( option );
} );
- // eslint-disable-next-line mediawiki/class-doc
return new OO.ui.RadioSelectWidget( { items: options, classes: classes } );
};
@@ -194,7 +193,6 @@
options.push( option );
} );
- // eslint-disable-next-line mediawiki/class-doc
return new OO.ui.CheckboxMultiselectWidget( { items: options, classes: classes } );
};
diff --git a/resources/uw.units.js b/resources/uw.units.js
index 0b2caeb..dace9d3 100644
--- a/resources/uw.units.js
+++ b/resources/uw.units.js
@@ -19,7 +19,7 @@
i++;
}
// Messages are documented above (scaleMsgKeys)
- // eslint-disable-next-line mediawiki/msg-doc
+
return mw.message( scaleMsgKeys[ i ], size.toFixed( i > 1 ? 2 : 0 ) ).text();
}
};
--
2.47.3
--- end ---