diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /tools/lint/eslint | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools/lint/eslint')
161 files changed, 28791 insertions, 0 deletions
diff --git a/tools/lint/eslint/.eslintrc.js b/tools/lint/eslint/.eslintrc.js new file mode 100644 index 0000000000..762ddba02c --- /dev/null +++ b/tools/lint/eslint/.eslintrc.js @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +module.exports = { + plugins: ["eslint-plugin"], + extends: ["plugin:eslint-plugin/recommended"], + // eslint-plugin-mozilla runs under node, so we need a more restrictive + // environment / parser setup here than the rest of mozilla-central. + env: { + browser: false, + node: true, + }, + parser: "espree", + parserOptions: { + // This should match with the minimum node version that the ESLint CI + // process uses (check the linux64-node toolchain). + ecmaVersion: 12, + }, + + rules: { + camelcase: ["error", { properties: "never" }], + "handle-callback-err": ["error", "er"], + "no-shadow": "error", + "no-undef-init": "error", + "one-var": ["error", "never"], + strict: ["error", "global"], + }, +}; diff --git a/tools/lint/eslint/__init__.py b/tools/lint/eslint/__init__.py new file mode 100644 index 0000000000..fdd7504c34 --- /dev/null +++ b/tools/lint/eslint/__init__.py @@ -0,0 +1,293 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import json +import os +import signal +import subprocess +import sys + +sys.path.append(os.path.join(os.path.dirname(__file__), "eslint")) +from mozbuild.nodeutil import find_node_executable +from mozlint import result + +from eslint import setup_helper + +ESLINT_ERROR_MESSAGE = """ +An error occurred running eslint. Please check the following error messages: + +{} +""".strip() + +ESLINT_NOT_FOUND_MESSAGE = """ +Could not find eslint! We looked at the --binary option, at the ESLINT +environment variable, and then at your local node_modules path. Please Install +eslint and needed plugins with: + +mach eslint --setup + +and try again. +""".strip() + +PRETTIER_ERROR_MESSAGE = """ +An error occurred running prettier. Please check the following error messages: + +{} +""".strip() + +PRETTIER_FORMATTING_MESSAGE = ( + "This file needs formatting with Prettier (use 'mach lint --fix <path>')." +) + + +def setup(root, **lintargs): + setup_helper.set_project_root(root) + + if not setup_helper.check_node_executables_valid(): + return 1 + + return setup_helper.eslint_maybe_setup() + + +def lint(paths, config, binary=None, fix=None, rules=[], setup=None, **lintargs): + """Run eslint.""" + log = lintargs["log"] + setup_helper.set_project_root(lintargs["root"]) + module_path = setup_helper.get_project_root() + + # Valid binaries are: + # - Any provided by the binary argument. + # - Any pointed at by the ESLINT environmental variable. + # - Those provided by |mach lint --setup|. + + if not binary: + binary, _ = find_node_executable() + + if not binary: + print(ESLINT_NOT_FOUND_MESSAGE) + return 1 + + extra_args = lintargs.get("extra_args") or [] + exclude_args = [] + for path in config.get("exclude", []): + exclude_args.extend( + ["--ignore-pattern", os.path.relpath(path, lintargs["root"])] + ) + + for rule in rules: + extra_args.extend(["--rule", rule]) + + # First run ESLint + cmd_args = ( + [ + binary, + os.path.join(module_path, "node_modules", "eslint", "bin", "eslint.js"), + # This keeps ext as a single argument. + "--ext", + "[{}]".format(",".join(config["extensions"])), + "--format", + "json", + "--no-error-on-unmatched-pattern", + ] + + rules + + extra_args + + exclude_args + + paths + ) + + if fix: + # eslint requires that --fix be set before the --ext argument. + cmd_args.insert(2, "--fix") + + log.debug("ESLint command: {}".format(" ".join(cmd_args))) + + result = run(cmd_args, config) + if result == 1: + return result + + # Then run Prettier + cmd_args = ( + [ + binary, + os.path.join(module_path, "node_modules", "prettier", "bin-prettier.js"), + "--list-different", + "--no-error-on-unmatched-pattern", + ] + + extra_args + # Prettier does not support exclude arguments. + # + exclude_args + + paths + ) + log.debug("Prettier command: {}".format(" ".join(cmd_args))) + + if fix: + cmd_args.append("--write") + + prettier_result = run_prettier(cmd_args, config, fix) + if prettier_result == 1: + return prettier_result + + result["results"].extend(prettier_result["results"]) + result["fixed"] = result["fixed"] + prettier_result["fixed"] + return result + + +def run(cmd_args, config): + shell = False + if ( + os.environ.get("MSYSTEM") in ("MINGW32", "MINGW64") + or "MOZILLABUILD" in os.environ + ): + # The eslint binary needs to be run from a shell with msys + shell = True + encoding = "utf-8" + + orig = signal.signal(signal.SIGINT, signal.SIG_IGN) + proc = subprocess.Popen( + cmd_args, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + signal.signal(signal.SIGINT, orig) + + try: + output, errors = proc.communicate() + except KeyboardInterrupt: + proc.kill() + return {"results": [], "fixed": 0} + + if errors: + errors = errors.decode(encoding, "replace") + print(ESLINT_ERROR_MESSAGE.format(errors)) + + if proc.returncode >= 2: + return 1 + + if not output: + return {"results": [], "fixed": 0} # no output means success + output = output.decode(encoding, "replace") + try: + jsonresult = json.loads(output) + except ValueError: + print(ESLINT_ERROR_MESSAGE.format(output)) + return 1 + + results = [] + fixed = 0 + for obj in jsonresult: + errors = obj["messages"] + # This will return a count of files fixed, rather than issues fixed, as + # that is the only count we have. + if "output" in obj: + fixed = fixed + 1 + + for err in errors: + err.update( + { + "hint": err.get("fix"), + "level": "error" if err["severity"] == 2 else "warning", + "lineno": err.get("line") or 0, + "path": obj["filePath"], + "rule": err.get("ruleId"), + } + ) + results.append(result.from_config(config, **err)) + + return {"results": results, "fixed": fixed} + + +def run_prettier(cmd_args, config, fix): + shell = False + if is_windows(): + # The eslint binary needs to be run from a shell with msys + shell = True + encoding = "utf-8" + + orig = signal.signal(signal.SIGINT, signal.SIG_IGN) + proc = subprocess.Popen( + cmd_args, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + signal.signal(signal.SIGINT, orig) + + try: + output, errors = proc.communicate() + except KeyboardInterrupt: + proc.kill() + return {"results": [], "fixed": 0} + + results = [] + + if errors: + errors = errors.decode(encoding, "replace").strip().split("\n") + errors = [ + error + for error in errors + # Unknown options are not an issue for Prettier, this avoids + # errors during tests. + if not ("Ignored unknown option" in error) + ] + if len(errors): + results.append( + result.from_config( + config, + **{ + "name": "eslint", + "path": os.path.abspath("."), + "message": PRETTIER_ERROR_MESSAGE.format("\n".join(errors)), + "level": "error", + "rule": "prettier", + "lineno": 0, + "column": 0, + } + ) + ) + + if not output: + # If we have errors, but no output, we assume something really bad happened. + if errors and len(errors): + return {"results": results, "fixed": 0} + + return {"results": [], "fixed": 0} # no output means success + + output = output.decode(encoding, "replace").splitlines() + + fixed = 0 + + if fix: + # When Prettier is running in fix mode, it outputs the list of files + # that have been fixed, so sum them up here. + # If it can't fix files, it will throw an error, which will be handled + # above. + fixed = len(output) + else: + # When in "check" mode, Prettier will output the list of files that + # need changing, so we'll wrap them in our result structure here. + for file in output: + if not file: + continue + + file = os.path.abspath(file) + results.append( + result.from_config( + config, + **{ + "name": "eslint", + "path": file, + "message": PRETTIER_FORMATTING_MESSAGE, + "level": "error", + "rule": "prettier", + "lineno": 0, + "column": 0, + } + ) + ) + + return {"results": results, "fixed": fixed} + + +def is_windows(): + return ( + os.environ.get("MSYSTEM") in ("MINGW32", "MINGW64") + or "MOZILLABUILD" in os.environ + ) diff --git a/tools/lint/eslint/eslint-plugin-mozilla/.npmignore b/tools/lint/eslint/eslint-plugin-mozilla/.npmignore new file mode 100644 index 0000000000..3713448c7a --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/.npmignore @@ -0,0 +1,8 @@ +.eslintrc.js +.npmignore +node_modules +reporters +scripts +tests +package-lock.json +update.sh diff --git a/tools/lint/eslint/eslint-plugin-mozilla/LICENSE b/tools/lint/eslint/eslint-plugin-mozilla/LICENSE new file mode 100644 index 0000000000..e87a115e46 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/tools/lint/eslint/eslint-plugin-mozilla/README.md b/tools/lint/eslint/eslint-plugin-mozilla/README.md new file mode 100644 index 0000000000..650507754e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/README.md @@ -0,0 +1,56 @@ +# eslint-plugin-mozilla + +A collection of rules that help enforce JavaScript coding standard in the Mozilla project. + +These are primarily developed and used within the Firefox build system ([mozilla-central](https://hg.mozilla.org/mozilla-central/)), but are made available for other +related projects to use as well. + +## Installation + +### Within mozilla-central: + +``` +$ ./mach eslint --setup +``` + +### Outside mozilla-central: + +Install ESLint [ESLint](http://eslint.org): + +``` +$ npm i eslint --save-dev +``` + +Next, install `eslint-plugin-mozilla`: + +``` +$ npm install eslint-plugin-mozilla --save-dev +``` + +## Documentation + +For details about the rules, please see the [firefox documentation page](http://firefox-source-docs.mozilla.org/tools/lint/linters/eslint-plugin-mozilla.html). + +## Source Code + +The sources can be found at: + +* Code: https://searchfox.org/mozilla-central/source/tools/lint/eslint/eslint-plugin-mozilla +* Documentation: https://searchfox.org/mozilla-central/source/docs/code-quality/lint/linters + +## Bugs + +Please file bugs in Bugzilla in the Lint component of the Testing product. + +* [Existing bugs](https://bugzilla.mozilla.org/buglist.cgi?resolution=---&query_format=advanced&component=Lint&product=Testing) +* [New bugs](https://bugzilla.mozilla.org/enter_bug.cgi?product=Testing&component=Lint) + +## Tests + +The tests can only be run from within mozilla-central. To run the tests: + +``` +./mach eslint --setup +cd tools/lint/eslint/eslint-plugin-mozilla +npm run test +``` diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/.eslintrc.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/.eslintrc.js new file mode 100644 index 0000000000..76df4134f5 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/.eslintrc.js @@ -0,0 +1,8 @@ +"use strict"; + +module.exports = { + rules: { + // Require object keys to be sorted. + "sort-keys": "error", + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/browser-test.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/browser-test.js new file mode 100644 index 0000000000..08747a3f88 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/browser-test.js @@ -0,0 +1,95 @@ +// Parent config file for all browser-chrome files. +"use strict"; + +module.exports = { + env: { + browser: true, + "mozilla/browser-window": true, + "mozilla/simpletest": true, + // "node": true + }, + + // All globals made available in the test environment. + globals: { + // `$` is defined in SimpleTest.js + $: false, + Assert: false, + BrowserTestUtils: false, + ContentTask: false, + ContentTaskUtils: false, + EventUtils: false, + IOUtils: false, + PathUtils: false, + PromiseDebugging: false, + SpecialPowers: false, + TestUtils: false, + addLoadEvent: false, + add_setup: false, + add_task: false, + content: false, + executeSoon: false, + expectUncaughtException: false, + export_assertions: false, + extractJarToTmp: false, + finish: false, + gTestPath: false, + getChromeDir: false, + getJar: false, + getResolvedURI: false, + getRootDirectory: false, + getTestFilePath: false, + ignoreAllUncaughtExceptions: false, + info: false, + is: false, + isnot: false, + ok: false, + record: false, + registerCleanupFunction: false, + requestLongerTimeout: false, + setExpectedFailuresForSelfTest: false, + stringContains: false, + stringMatches: false, + todo: false, + todo_is: false, + todo_isnot: false, + waitForClipboard: false, + waitForExplicitFinish: false, + waitForFocus: false, + }, + + plugins: ["mozilla", "@microsoft/sdl"], + + rules: { + // No using of insecure url, so no http urls + "@microsoft/sdl/no-insecure-url": [ + "error", + { + exceptions: [ + "^http:\\/\\/mochi\\.test?.*", + "^http:\\/\\/localhost?.*", + "^http:\\/\\/127\\.0\\.0\\.1?.*", + // Exempt xmlns urls + "^http:\\/\\/www\\.w3\\.org?.*", + "^http:\\/\\/www\\.mozilla\\.org\\/keymaster\\/gatekeeper?.*", + // Exempt urls that start with ftp or ws. + "^ws:?.*", + "^ftp:?.*", + ], + varExceptions: ["insecure?.*"], + }, + ], + "mozilla/import-content-task-globals": "error", + "mozilla/import-headjs-globals": "error", + "mozilla/mark-test-function-used": "error", + "mozilla/no-addtask-setup": "error", + "mozilla/no-arbitrary-setTimeout": "error", + "mozilla/no-redeclare-with-import-autofix": [ + "error", + { errorForNonImports: false }, + ], + // Turn off no-unsanitized for tests, as we do want to be able to use + // these for testing. + "no-unsanitized/method": "off", + "no-unsanitized/property": "off", + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/chrome-test.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/chrome-test.js new file mode 100644 index 0000000000..3b5bbc06e2 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/chrome-test.js @@ -0,0 +1,65 @@ +// Parent config file for all mochitest files. +"use strict"; + +module.exports = { + env: { + browser: true, + "mozilla/browser-window": true, + }, + + // All globals made available in the test environment. + globals: { + // SpecialPowers is injected into the window object via SimpleTest.js + SpecialPowers: false, + extractJarToTmp: false, + getChromeDir: false, + getJar: false, + getResolvedURI: false, + getRootDirectory: false, + }, + + overrides: [ + { + env: { + // Ideally we wouldn't be using the simpletest env here, but our uses of + // js files mean we pick up everything from the global scope, which could + // be any one of a number of html files. So we just allow the basics... + "mozilla/simpletest": true, + }, + files: ["*.js"], + }, + ], + + plugins: ["mozilla", "@microsoft/sdl"], + + rules: { + // No using of insecure url, so no http urls + "@microsoft/sdl/no-insecure-url": [ + "error", + { + exceptions: [ + "^http:\\/\\/mochi\\.test?.*", + "^http:\\/\\/localhost?.*", + "^http:\\/\\/127\\.0\\.0\\.1?.*", + // Exempt xmlns urls + "^http:\\/\\/www\\.w3\\.org?.*", + "^http:\\/\\/www\\.mozilla\\.org\\/keymaster\\/gatekeeper?.*", + // Exempt urls that start with ftp or ws. + "^ws:?.*", + "^ftp:?.*", + ], + varExceptions: ["insecure?.*"], + }, + ], + "mozilla/import-content-task-globals": "error", + "mozilla/import-headjs-globals": "error", + "mozilla/mark-test-function-used": "error", + // We mis-predict globals for HTML test files in directories shared + // with browser tests. + "mozilla/no-redeclare-with-import-autofix": "off", + // Turn off no-unsanitized for tests, as we do want to be able to use + // these for testing. + "no-unsanitized/method": "off", + "no-unsanitized/property": "off", + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/mochitest-test.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/mochitest-test.js new file mode 100644 index 0000000000..ceca2beec4 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/mochitest-test.js @@ -0,0 +1,66 @@ +// Parent config file for all mochitest files. +"use strict"; + +module.exports = { + env: { + browser: true, + }, + + // All globals made available in the test environment. + globals: { + // SpecialPowers is injected into the window object via SimpleTest.js + SpecialPowers: false, + }, + + overrides: [ + { + env: { + // Ideally we wouldn't be using the simpletest env here, but our uses of + // js files mean we pick up everything from the global scope, which could + // be any one of a number of html files. So we just allow the basics... + "mozilla/simpletest": true, + }, + files: ["*.js"], + }, + ], + plugins: ["mozilla", "@microsoft/sdl"], + + rules: { + // No using of insecure url, so no http urls + "@microsoft/sdl/no-insecure-url": [ + "error", + { + exceptions: [ + "^http:\\/\\/mochi\\.test?.*", + "^http:\\/\\/mochi\\.xorigin-test?.*", + "^http:\\/\\/localhost?.*", + "^http:\\/\\/127\\.0\\.0\\.1?.*", + // Exempt xmlns urls + "^http:\\/\\/www\\.w3\\.org?.*", + "^http:\\/\\/www\\.mozilla\\.org\\/keymaster\\/gatekeeper?.*", + // Exempt urls that start with ftp or ws. + "^ws:?.*", + "^ftp:?.*", + ], + varExceptions: ["insecure?.*"], + }, + ], + "mozilla/import-content-task-globals": "error", + "mozilla/import-headjs-globals": "error", + "mozilla/mark-test-function-used": "error", + // Turn off no-define-cc-etc for mochitests as these don't have Cc etc defined in the + // global scope. + "mozilla/no-define-cc-etc": "off", + // We mis-predict globals for HTML test files in directories shared + // with browser tests, so don't try to "fix" imports that are needed. + "mozilla/no-redeclare-with-import-autofix": "off", + // Turn off use-chromeutils-generateqi as these tests don't have ChromeUtils + // available. + "mozilla/use-chromeutils-generateqi": "off", + "no-shadow": "error", + // Turn off no-unsanitized for tests, as we do want to be able to use + // these for testing. + "no-unsanitized/method": "off", + "no-unsanitized/property": "off", + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js new file mode 100644 index 0000000000..db7a0dc731 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js @@ -0,0 +1,351 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * The configuration is based on eslint:recommended config. The details for all + * the ESLint rules, and which ones are in the recommended configuration can + * be found here: + * + * https://eslint.org/docs/rules/ + * + * Rules that we've explicitly decided not to enable: + * + * require-await - bug 1381030. + * no-prototype-builtins - bug 1551829. + * require-atomic-updates - bug 1551829. + * - This generates too many false positives that are not easy to work + * around, and false positives seem to be inherent in the rule. + */ +module.exports = { + env: { + browser: true, + es2022: true, + "mozilla/privileged": true, + "mozilla/specific": true, + }, + + // The prettier configuration here comes from eslint-config-prettier and + // turns off all of ESLint's rules related to formatting. + extends: [ + "eslint:recommended", + "prettier", + "plugin:json/recommended-with-comments", + ], + + overrides: [ + { + // System mjs files and jsm files are not loaded in the browser scope, + // so we turn that off for those. Though we do have our own special + // environment for them. + env: { + browser: false, + "mozilla/jsm": true, + }, + files: ["**/*.sys.mjs", "**/*.jsm"], + rules: { + "mozilla/lazy-getter-object-name": "error", + "mozilla/reject-eager-module-in-lazy-getter": "error", + "mozilla/reject-global-this": "error", + "mozilla/reject-globalThis-modification": "error", + // For all system modules, we expect no properties to need importing, + // hence reject everything. + "mozilla/reject-importGlobalProperties": ["error", "everything"], + "mozilla/reject-mixing-eager-and-lazy": "error", + "mozilla/reject-top-level-await": "error", + // TODO: Bug 1575506 turn `builtinGlobals` on here. + // We can enable builtinGlobals for jsms due to their scopes. + "no-redeclare": ["error", { builtinGlobals: false }], + }, + }, + { + files: ["**/*.mjs", "**/*.jsx", "**/*.jsm", "**/?(*.)worker.?(m)js"], + rules: { + // Modules and workers are far easier to check for no-unused-vars on a + // global scope, than our content files. Hence we turn that on here. + "no-unused-vars": [ + "error", + { + args: "none", + vars: "all", + }, + ], + }, + }, + { + excludedFiles: ["**/*.sys.mjs"], + files: ["**/*.mjs"], + rules: { + "mozilla/reject-import-system-module-from-non-system": "error", + "mozilla/reject-lazy-imports-into-globals": "error", + "no-shadow": ["error", { allow: ["event"], builtinGlobals: true }], + }, + }, + { + files: ["**/*.mjs", "**/*.jsx"], + parserOptions: { + sourceType: "module", + }, + rules: { + "mozilla/use-static-import": "error", + // This rule defaults to not allowing "use strict" in module files since + // they are always loaded in strict mode. + strict: "error", + }, + }, + { + files: ["**/*.jsm"], + rules: { + "mozilla/mark-exported-symbols-as-used": "error", + }, + }, + { + env: { + browser: false, + "mozilla/privileged": false, + "mozilla/sjs": true, + "mozilla/specific": false, + }, + files: ["**/*.sjs"], + rules: { + // For sjs files, reject everything as we should update the sandbox + // to include the globals we need, as these are test-only files. + "mozilla/reject-importGlobalProperties": ["error", "everything"], + }, + }, + { + env: { + browser: false, + worker: true, + }, + files: [ + // Most files should use the `.worker.` format to be consistent with + // other items like `.sys.mjs`, but we allow simply calling the file + // "worker" as well. + "**/?(*.)worker.?(m)js", + ], + }, + ], + + parserOptions: { + ecmaVersion: "latest", + }, + + // When adding items to this file please check for effects on sub-directories. + plugins: ["fetch-options", "html", "json", "no-unsanitized"], + + // When adding items to this file please check for effects on all of toolkit + // and browser + rules: { + // This may conflict with prettier, so we turn it off. + "arrow-body-style": "off", + + // Warn about cyclomatic complexity in functions. + // XXX Get this down to 20? + complexity: ["error", 34], + + // Functions must always return something or nothing + "consistent-return": "error", + + // XXX This rule line should be removed to enable it. See bug 1487642. + // Require super() calls in constructors + "constructor-super": "off", + + // Require braces around blocks that start a new line + curly: ["error", "all"], + + // Encourage the use of dot notation whenever possible. + "dot-notation": "error", + + // XXX This rule should be enabled, see Bug 1557040 + // No credentials submitted with fetch calls + "fetch-options/no-fetch-credentials": "off", + + // XXX This rule line should be removed to enable it. See bug 1487642. + // Enforce return statements in getters + "getter-return": "off", + + // Don't enforce the maximum depth that blocks can be nested. The complexity + // rule is a better rule to check this. + "max-depth": "off", + + // Maximum depth callbacks can be nested. + "max-nested-callbacks": ["error", 10], + + "mozilla/avoid-removeChild": "error", + "mozilla/consistent-if-bracing": "error", + "mozilla/import-browser-window-globals": "error", + "mozilla/import-globals": "error", + "mozilla/no-compare-against-boolean-literals": "error", + "mozilla/no-cu-reportError": "error", + "mozilla/no-define-cc-etc": "error", + "mozilla/no-throw-cr-literal": "error", + "mozilla/no-useless-parameters": "error", + "mozilla/no-useless-removeEventListener": "error", + "mozilla/prefer-boolean-length-check": "error", + "mozilla/prefer-formatValues": "error", + "mozilla/reject-addtask-only": "error", + "mozilla/reject-chromeutils-import-params": "error", + "mozilla/reject-importGlobalProperties": ["error", "allownonwebidl"], + "mozilla/reject-multiple-getters-calls": "error", + "mozilla/reject-scriptableunicodeconverter": "warn", + "mozilla/rejects-requires-await": "error", + "mozilla/use-cc-etc": "error", + "mozilla/use-chromeutils-definelazygetter": "error", + "mozilla/use-chromeutils-generateqi": "error", + "mozilla/use-chromeutils-import": "error", + "mozilla/use-console-createInstance": "error", + "mozilla/use-default-preference-values": "error", + "mozilla/use-includes-instead-of-indexOf": "error", + "mozilla/use-isInstance": "error", + "mozilla/use-ownerGlobal": "error", + "mozilla/use-returnValue": "error", + "mozilla/use-services": "error", + "mozilla/valid-lazy": "error", + "mozilla/valid-services": "error", + + // Use [] instead of Array() + "no-array-constructor": "error", + + // Disallow use of arguments.caller or arguments.callee. + "no-caller": "error", + + // XXX Bug 1487642 - decide if we want to enable this or not. + // Disallow lexical declarations in case clauses + "no-case-declarations": "off", + + // XXX Bug 1487642 - decide if we want to enable this or not. + // Disallow the use of console + "no-console": "off", + + // Disallows expressions where the operation doesn't affect the value. + // TODO: This is enabled by default in ESLint's v9 recommended configuration. + "no-constant-binary-expression": "error", + + // XXX Bug 1487642 - decide if we want to enable this or not. + // Disallow constant expressions in conditions + "no-constant-condition": "off", + + // If an if block ends with a return no need for an else block + "no-else-return": "error", + + // No empty statements + "no-empty": ["error", { allowEmptyCatch: true }], + + // Disallow eval and setInteral/setTimeout with strings + "no-eval": "error", + + // Disallow unnecessary calls to .bind() + "no-extra-bind": "error", + + // Disallow fallthrough of case statements + "no-fallthrough": [ + "error", + { + // The eslint rule doesn't allow for case-insensitive regex option. + // The following pattern allows for a dash between "fall through" as + // well as alternate spelling of "fall thru". The pattern also allows + // for an optional "s" at the end of "fall" ("falls through"). + commentPattern: + "[Ff][Aa][Ll][Ll][Ss]?[\\s-]?([Tt][Hh][Rr][Oo][Uu][Gg][Hh]|[Tt][Hh][Rr][Uu])", + }, + ], + + // Disallow eval and setInteral/setTimeout with strings + "no-implied-eval": "error", + + // This has been superseded since we're using ES6. + // Disallow variable or function declarations in nested blocks + "no-inner-declarations": "off", + + // Disallow the use of the __iterator__ property + "no-iterator": "error", + + // No labels + "no-labels": "error", + + // Disallow unnecessary nested blocks + "no-lone-blocks": "error", + + // No single if block inside an else block + "no-lonely-if": "error", + + // Nested ternary statements are confusing + "no-nested-ternary": "error", + + // Disallow use of new wrappers + "no-new-wrappers": "error", + + // Use {} instead of new Object(), unless arguments are passed. + "no-object-constructor": "error", + + // We don't want this, see bug 1551829 + "no-prototype-builtins": "off", + + // Disable builtinGlobals for no-redeclare as this conflicts with our + // globals declarations especially for browser window. + "no-redeclare": ["error", { builtinGlobals: false }], + + // Disallow use of event global. + "no-restricted-globals": ["error", "event"], + + // No unnecessary comparisons + "no-self-compare": "error", + + // No comma sequenced statements + "no-sequences": "error", + + // No declaring variables from an outer scope + // "no-shadow": "error", + + // Disallow throwing literals (eg. throw "error" instead of + // throw new Error("error")). + "no-throw-literal": "error", + + // Disallow the use of Boolean literals in conditional expressions. + "no-unneeded-ternary": "error", + + // No unsanitized use of innerHTML=, document.write() etc. + // cf. https://github.com/mozilla/eslint-plugin-no-unsanitized#rule-details + "no-unsanitized/method": "error", + "no-unsanitized/property": "error", + + // No declaring variables that are never used + "no-unused-vars": [ + "error", + { + args: "none", + vars: "local", + }, + ], + + // No using variables before defined + // "no-use-before-define": ["error", "nofunc"], + + // Disallow unnecessary .call() and .apply() + "no-useless-call": "error", + + // Don't concatenate string literals together (unless they span multiple + // lines) + "no-useless-concat": "error", + + // XXX Bug 1487642 - decide if we want to enable this or not. + // Disallow unnecessary escape characters + "no-useless-escape": "off", + + // Disallow redundant return statements + "no-useless-return": "error", + + // Require object-literal shorthand with ES6 method syntax + "object-shorthand": ["error", "always", { avoidQuotes: true }], + + // This may conflict with prettier, so turn it off. + "prefer-arrow-callback": "off", + + // XXX Bug 1487642 - decide if we want to enable this or not. + // Require generator functions to contain yield + "require-yield": "off", + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/require-jsdoc.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/require-jsdoc.js new file mode 100644 index 0000000000..086fc8b1d3 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/require-jsdoc.js @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +module.exports = { + plugins: ["jsdoc"], + + rules: { + "jsdoc/require-jsdoc": [ + "error", + { + require: { + ClassDeclaration: true, + FunctionDeclaration: false, + }, + }, + ], + "jsdoc/require-param": "error", + "jsdoc/require-param-description": "error", + "jsdoc/require-param-name": "error", + "jsdoc/require-property": "error", + "jsdoc/require-property-description": "error", + "jsdoc/require-property-name": "error", + "jsdoc/require-property-type": "error", + "jsdoc/require-returns": "error", + "jsdoc/require-returns-check": "error", + "jsdoc/require-yields": "error", + "jsdoc/require-yields-check": "error", + }, + settings: { + jsdoc: { + // This changes what's allowed in JSDocs, enabling more type-inference + // friendly types. This is the default in eslint-plugin-jsdoc versions + // since May 2023, but we're still on 39.9 and need opt-in for now. + // https://github.com/gajus/eslint-plugin-jsdoc/issues/834 + mode: "typescript", + }, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/valid-jsdoc.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/valid-jsdoc.js new file mode 100644 index 0000000000..65fb760fe0 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/valid-jsdoc.js @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +module.exports = { + plugins: ["jsdoc"], + + rules: { + "jsdoc/check-access": "error", + // Handled by prettier + // "jsdoc/check-alignment": "error", + "jsdoc/check-param-names": "error", + "jsdoc/check-property-names": "error", + "jsdoc/check-tag-names": "error", + "jsdoc/check-types": "error", + "jsdoc/empty-tags": "error", + "jsdoc/newline-after-description": "error", + "jsdoc/no-multi-asterisks": "error", + "jsdoc/require-param-type": "error", + "jsdoc/require-returns-type": "error", + "jsdoc/valid-types": "error", + }, + settings: { + jsdoc: { + // This changes what's allowed in JSDocs, enabling more type-inference + // friendly types. This is the default in eslint-plugin-jsdoc versions + // since May 2023, but we're still on 39.9 and need opt-in for now. + // https://github.com/gajus/eslint-plugin-jsdoc/issues/834 + mode: "typescript", + }, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/xpcshell-test.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/xpcshell-test.js new file mode 100644 index 0000000000..6a4d572911 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/xpcshell-test.js @@ -0,0 +1,54 @@ +// Parent config file for all xpcshell files. +"use strict"; + +module.exports = { + env: { + browser: false, + "mozilla/privileged": true, + "mozilla/xpcshell": true, + }, + + overrides: [ + { + // If it is a head file, we turn off global unused variable checks, as it + // would require searching the other test files to know if they are used or not. + // This would be expensive and slow, and it isn't worth it for head files. + // We could get developers to declare as exported, but that doesn't seem worth it. + files: "head*.js", + rules: { + "no-unused-vars": [ + "error", + { + args: "none", + vars: "local", + }, + ], + }, + }, + { + // No declaring variables that are never used + files: "test*.js", + rules: { + "no-unused-vars": [ + "error", + { + args: "none", + vars: "all", + }, + ], + }, + }, + ], + + rules: { + "mozilla/import-headjs-globals": "error", + "mozilla/mark-test-function-used": "error", + "mozilla/no-arbitrary-setTimeout": "error", + "mozilla/no-useless-run-test": "error", + "no-shadow": "error", + // Turn off no-unsanitized for tests, as we do want to be able to use + // these for testing. + "no-unsanitized/method": "off", + "no-unsanitized/property": "off", + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js new file mode 100644 index 0000000000..241299e2d3 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js @@ -0,0 +1,121 @@ +/** + * @fileoverview Defines the environment when in the browser.xhtml window. + * Imports many globals from various files. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +// ----------------------------------------------------------------------------- +// Rule Definition +// ----------------------------------------------------------------------------- + +var fs = require("fs"); +var helpers = require("../helpers"); +var { getScriptGlobals } = require("./utils"); + +// When updating EXTRA_SCRIPTS or MAPPINGS, be sure to also update the +// 'support-files' config in `tools/lint/eslint.yml`. + +// These are scripts not loaded from browser.xhtml or global-scripts.inc +// but via other includes. +const EXTRA_SCRIPTS = [ + "browser/base/content/nsContextMenu.js", + "browser/components/downloads/content/downloads.js", + "browser/components/downloads/content/indicator.js", + "toolkit/content/customElements.js", + "toolkit/content/editMenuOverlay.js", +]; + +const extraDefinitions = [ + // Via Components.utils, defineModuleGetter, defineLazyModuleGetters or + // defineLazyScriptGetter (and map to + // single) variable. + { name: "XPCOMUtils", writable: false }, + { name: "Task", writable: false }, + { name: "windowGlobalChild", writable: false }, + // structuredClone is a new global that would be defined for the `browser` + // environment in ESLint, but only Firefox has implemented it currently and so + // it isn't in ESLint's globals yet. + // https://developer.mozilla.org/docs/Web/API/structuredClone + { name: "structuredClone", writable: false }, +]; + +// Some files in global-scripts.inc need mapping to specific locations. +const MAPPINGS = { + "printUtils.js": "toolkit/components/printing/content/printUtils.js", + "panelUI.js": "browser/components/customizableui/content/panelUI.js", + "viewSourceUtils.js": + "toolkit/components/viewsource/content/viewSourceUtils.js", + "browserPlacesViews.js": + "browser/components/places/content/browserPlacesViews.js", + "places-tree.js": "browser/components/places/content/places-tree.js", + "places-menupopup.js": + "browser/components/places/content/places-menupopup.js", + "shopping-sidebar.js": + "browser/components/shopping/content/shopping-sidebar.js", +}; + +const globalScriptsRegExp = + /^\s*Services.scriptloader.loadSubScript\(\"(.*?)\", this\);$/; + +function getGlobalScriptIncludes(scriptPath) { + let fileData; + try { + fileData = fs.readFileSync(scriptPath, { encoding: "utf8" }); + } catch (ex) { + // The file isn't present, so this isn't an m-c repository. + return null; + } + + fileData = fileData.split("\n"); + + let result = []; + + for (let line of fileData) { + let match = line.match(globalScriptsRegExp); + if (match) { + let sourceFile = match[1] + .replace( + "chrome://browser/content/search/", + "browser/components/search/content/" + ) + .replace( + "chrome://browser/content/screenshots/", + "browser/components/screenshots/content/" + ) + .replace("chrome://browser/content/", "browser/base/content/") + .replace("chrome://global/content/", "toolkit/content/"); + + for (let mapping of Object.getOwnPropertyNames(MAPPINGS)) { + if (sourceFile.includes(mapping)) { + sourceFile = MAPPINGS[mapping]; + } + } + + result.push(sourceFile); + } + } + + return result; +} + +function getGlobalScripts() { + let results = []; + for (let scriptPath of helpers.globalScriptPaths) { + results = results.concat(getGlobalScriptIncludes(scriptPath)); + } + return results; +} + +module.exports = getScriptGlobals( + "browser-window", + getGlobalScripts().concat(EXTRA_SCRIPTS), + extraDefinitions, + { + browserjsScripts: getGlobalScripts().concat(EXTRA_SCRIPTS), + } +); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/chrome-script.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/chrome-script.js new file mode 100644 index 0000000000..9b0ae54a2e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/chrome-script.js @@ -0,0 +1,28 @@ +/** + * @fileoverview Defines the environment for SpecialPowers chrome script. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var { globals } = require("./special-powers-sandbox"); +var util = require("util"); + +module.exports = { + globals: util._extend( + { + // testing/specialpowers/content/SpecialPowersParent.sys.mjs + + // SPLoadChromeScript block + createWindowlessBrowser: false, + sendAsyncMessage: false, + addMessageListener: false, + removeMessageListener: false, + actorParent: false, + }, + globals + ), +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/chrome-worker.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/chrome-worker.js new file mode 100644 index 0000000000..db5759b26c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/chrome-worker.js @@ -0,0 +1,25 @@ +/** + * @fileoverview Defines the environment for chrome workers. This differs + * from normal workers by the fact that `ctypes` can be accessed + * as well. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var globals = require("globals"); +var util = require("util"); + +var workerGlobals = util._extend( + { + ctypes: false, + }, + globals.worker +); + +module.exports = { + globals: workerGlobals, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js new file mode 100644 index 0000000000..7ac5c941cf --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js @@ -0,0 +1,39 @@ +/** + * @fileoverview Defines the environment for frame scripts. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + globals: { + // dom/chrome-webidl/MessageManager.webidl + + // MessageManagerGlobal + dump: false, + atob: false, + btoa: false, + + // MessageListenerManagerMixin + addMessageListener: false, + removeMessageListener: false, + addWeakMessageListener: false, + removeWeakMessageListener: false, + + // MessageSenderMixin + sendAsyncMessage: false, + processMessageManager: false, + remoteType: false, + + // SyncMessageSenderMixin + sendSyncMessage: false, + + // ContentFrameMessageManager + content: false, + docShell: false, + tabEventTarget: false, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/jsm.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/jsm.js new file mode 100644 index 0000000000..30d8e0eb9c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/jsm.js @@ -0,0 +1,25 @@ +/** + * @fileoverview Defines the environment for jsm files. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + globals: { + // These globals are hard-coded and available in .jsm scopes. + // https://searchfox.org/mozilla-central/rev/dcb0cfb66e4ed3b9c7fbef1e80572426ff5f3c3a/js/xpconnect/loader/mozJSModuleLoader.cpp#222-223 + // Although `debug` is allowed for jsm files, this is non-standard and something + // we don't want to allow in mjs files. Hence it is not included here. + atob: false, + btoa: false, + dump: false, + // The WebAssembly global is available in most (if not all) contexts where + // JS can run. It's definitely available in JSMs. So even if this is not + // the perfect place to add it, it's not wrong, and we can move it later. + WebAssembly: false, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/privileged.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/privileged.js new file mode 100644 index 0000000000..c517de6209 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/privileged.js @@ -0,0 +1,819 @@ +/** + * @fileoverview Defines the environment for privileges JS files. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + globals: { + // Intl and WebAssembly are available everywhere but are not webIDL definitions. + Intl: false, + WebAssembly: false, + // This list of items is currently obtained manually from the list of + // mozilla::dom::constructor::id::ID enumerations in an object directory + // generated dom/bindings/RegisterBindings.cpp + APZHitResultFlags: false, + AbortController: false, + AbortSignal: false, + AccessibleNode: false, + Addon: false, + AddonEvent: false, + AddonInstall: false, + AddonManager: true, + AddonManagerPermissions: false, + AnalyserNode: false, + Animation: false, + AnimationEffect: false, + AnimationEvent: false, + AnimationPlaybackEvent: false, + AnimationTimeline: false, + AnonymousContent: false, + Attr: false, + AudioBuffer: false, + AudioBufferSourceNode: false, + AudioContext: false, + AudioDecoder: false, + AudioDestinationNode: false, + AudioData: false, + AudioEncoder: false, + AudioListener: false, + AudioNode: false, + AudioParam: false, + AudioParamMap: false, + AudioProcessingEvent: false, + AudioScheduledSourceNode: false, + AudioTrack: false, + AudioTrackList: false, + AudioWorklet: false, + AudioWorkletNode: false, + AuthenticatorAssertionResponse: false, + AuthenticatorAttestationResponse: false, + AuthenticatorResponse: false, + BarProp: false, + BaseAudioContext: false, + BatteryManager: false, + BeforeUnloadEvent: false, + BiquadFilterNode: false, + Blob: false, + BlobEvent: false, + BoxObject: false, + BroadcastChannel: false, + BrowsingContext: false, + ByteLengthQueuingStrategy: false, + CanonicalBrowsingContext: false, + CDATASection: false, + CSS: false, + CSS2Properties: false, + CSSAnimation: false, + CSSConditionRule: false, + CSSCounterStyleRule: false, + CSSFontFaceRule: false, + CSSFontFeatureValuesRule: false, + CSSGroupingRule: false, + CSSImportRule: false, + CSSKeyframeRule: false, + CSSKeyframesRule: false, + CSSMediaRule: false, + CSSMozDocumentRule: false, + CSSNamespaceRule: false, + CSSPageRule: false, + CSSPseudoElement: false, + CSSRule: false, + CSSRuleList: false, + CSSStyleDeclaration: false, + CSSStyleRule: false, + CSSStyleSheet: false, + CSSSupportsRule: false, + CSSTransition: false, + Cache: false, + CacheStorage: false, + CanvasCaptureMediaStream: false, + CanvasGradient: false, + CanvasPattern: false, + CanvasRenderingContext2D: false, + CaretPosition: false, + CaretStateChangedEvent: false, + ChannelMergerNode: false, + ChannelSplitterNode: false, + ChannelWrapper: false, + CharacterData: false, + CheckerboardReportService: false, + ChildProcessMessageManager: false, + ChildSHistory: false, + ChromeMessageBroadcaster: false, + ChromeMessageSender: false, + ChromeNodeList: false, + ChromeUtils: false, + ChromeWorker: false, + Clipboard: false, + ClipboardEvent: false, + ClonedErrorHolder: false, + CloseEvent: false, + CommandEvent: false, + Comment: false, + CompositionEvent: false, + ConsoleInstance: false, + ConstantSourceNode: false, + ContentFrameMessageManager: false, + ContentProcessMessageManager: false, + ConvolverNode: false, + CountQueuingStrategy: false, + CreateOfferRequest: false, + Credential: false, + CredentialsContainer: false, + Crypto: false, + CryptoKey: false, + CustomElementRegistry: false, + CustomEvent: false, + DOMError: false, + DOMException: false, + DOMImplementation: false, + DOMLocalization: false, + DOMMatrix: false, + DOMMatrixReadOnly: false, + DOMParser: false, + DOMPoint: false, + DOMPointReadOnly: false, + DOMQuad: false, + DOMRect: false, + DOMRectList: false, + DOMRectReadOnly: false, + DOMRequest: false, + DOMStringList: false, + DOMStringMap: false, + DOMTokenList: false, + DataTransfer: false, + DataTransferItem: false, + DataTransferItemList: false, + DebuggerNotificationObserver: false, + DelayNode: false, + DeprecationReportBody: false, + DeviceLightEvent: false, + DeviceMotionEvent: false, + DeviceOrientationEvent: false, + DeviceProximityEvent: false, + Directory: false, + Document: false, + DocumentFragment: false, + DocumentTimeline: false, + DocumentType: false, + DominatorTree: false, + DragEvent: false, + DynamicsCompressorNode: false, + Element: false, + EncodedAudioChunk: false, + EncodedVideoChunk: false, + ErrorEvent: false, + Event: false, + EventSource: false, + EventTarget: false, + FeaturePolicyViolationReportBody: false, + FetchObserver: false, + File: false, + FileList: false, + FileReader: false, + FileSystem: false, + FileSystemDirectoryEntry: false, + FileSystemDirectoryReader: false, + FileSystemEntry: false, + FileSystemFileEntry: false, + Flex: false, + FlexItemValues: false, + FlexLineValues: false, + FluentBundle: false, + FluentResource: false, + FocusEvent: false, + FontFace: false, + FontFaceSet: false, + FontFaceSetLoadEvent: false, + FormData: false, + FrameCrashedEvent: false, + FrameLoader: false, + GainNode: false, + Gamepad: false, + GamepadAxisMoveEvent: false, + GamepadButton: false, + GamepadButtonEvent: false, + GamepadEvent: false, + GamepadHapticActuator: false, + GamepadPose: false, + GamepadServiceTest: false, + Glean: false, + GleanPings: false, + Grid: false, + GridArea: false, + GridDimension: false, + GridLine: false, + GridLines: false, + GridTrack: false, + GridTracks: false, + HTMLAllCollection: false, + HTMLAnchorElement: false, + HTMLAreaElement: false, + HTMLAudioElement: false, + Audio: false, + HTMLBRElement: false, + HTMLBaseElement: false, + HTMLBodyElement: false, + HTMLButtonElement: false, + HTMLCanvasElement: false, + HTMLCollection: false, + HTMLDListElement: false, + HTMLDataElement: false, + HTMLDataListElement: false, + HTMLDetailsElement: false, + HTMLDialogElement: false, + HTMLDirectoryElement: false, + HTMLDivElement: false, + HTMLDocument: false, + HTMLElement: false, + HTMLEmbedElement: false, + HTMLFieldSetElement: false, + HTMLFontElement: false, + HTMLFormControlsCollection: false, + HTMLFormElement: false, + HTMLFrameElement: false, + HTMLFrameSetElement: false, + HTMLHRElement: false, + HTMLHeadElement: false, + HTMLHeadingElement: false, + HTMLHtmlElement: false, + HTMLIFrameElement: false, + HTMLImageElement: false, + Image: false, + HTMLInputElement: false, + HTMLLIElement: false, + HTMLLabelElement: false, + HTMLLegendElement: false, + HTMLLinkElement: false, + HTMLMapElement: false, + HTMLMarqueeElement: false, + HTMLMediaElement: false, + HTMLMenuElement: false, + HTMLMenuItemElement: false, + HTMLMetaElement: false, + HTMLMeterElement: false, + HTMLModElement: false, + HTMLOListElement: false, + HTMLObjectElement: false, + HTMLOptGroupElement: false, + HTMLOptionElement: false, + Option: false, + HTMLOptionsCollection: false, + HTMLOutputElement: false, + HTMLParagraphElement: false, + HTMLParamElement: false, + HTMLPictureElement: false, + HTMLPreElement: false, + HTMLProgressElement: false, + HTMLQuoteElement: false, + HTMLScriptElement: false, + HTMLSelectElement: false, + HTMLSlotElement: false, + HTMLSourceElement: false, + HTMLSpanElement: false, + HTMLStyleElement: false, + HTMLTableCaptionElement: false, + HTMLTableCellElement: false, + HTMLTableColElement: false, + HTMLTableElement: false, + HTMLTableRowElement: false, + HTMLTableSectionElement: false, + HTMLTemplateElement: false, + HTMLTextAreaElement: false, + HTMLTimeElement: false, + HTMLTitleElement: false, + HTMLTrackElement: false, + HTMLUListElement: false, + HTMLUnknownElement: false, + HTMLVideoElement: false, + HashChangeEvent: false, + Headers: false, + HeapSnapshot: false, + History: false, + IDBCursor: false, + IDBCursorWithValue: false, + IDBDatabase: false, + IDBFactory: false, + IDBFileHandle: false, + IDBFileRequest: false, + IDBIndex: false, + IDBKeyRange: false, + IDBMutableFile: false, + IDBObjectStore: false, + IDBOpenDBRequest: false, + IDBRequest: false, + IDBTransaction: false, + IDBVersionChangeEvent: false, + IIRFilterNode: false, + IdleDeadline: false, + ImageBitmap: false, + ImageBitmapRenderingContext: false, + ImageCapture: false, + ImageCaptureErrorEvent: false, + ImageData: false, + ImageDocument: false, + InputEvent: false, + InspectorFontFace: false, + InspectorUtils: false, + InstallTriggerImpl: false, + IntersectionObserver: false, + IntersectionObserverEntry: false, + IOUtils: false, + JSProcessActorChild: false, + JSProcessActorParent: false, + JSWindowActorChild: false, + JSWindowActorParent: false, + KeyEvent: false, + KeyboardEvent: false, + KeyframeEffect: false, + L10nFileSource: false, + L10nRegistry: false, + Localization: false, + Location: false, + MIDIAccess: false, + MIDIConnectionEvent: false, + MIDIInput: false, + MIDIInputMap: false, + MIDIMessageEvent: false, + MIDIOutput: false, + MIDIOutputMap: false, + MIDIPort: false, + MatchGlob: false, + MatchPattern: false, + MatchPatternSet: false, + MediaCapabilities: false, + MediaCapabilitiesInfo: false, + MediaControlService: false, + MediaDeviceInfo: false, + MediaDevices: false, + MediaElementAudioSourceNode: false, + MediaEncryptedEvent: false, + MediaError: false, + MediaKeyError: false, + MediaKeyMessageEvent: false, + MediaKeySession: false, + MediaKeyStatusMap: false, + MediaKeySystemAccess: false, + MediaKeys: false, + MediaList: false, + MediaQueryList: false, + MediaQueryListEvent: false, + MediaRecorder: false, + MediaRecorderErrorEvent: false, + MediaSource: false, + MediaStream: false, + MediaStreamAudioDestinationNode: false, + MediaStreamAudioSourceNode: false, + MediaStreamEvent: false, + MediaStreamTrack: false, + MediaStreamTrackAudioSourceNode: false, + MediaStreamTrackEvent: false, + MerchantValidationEvent: false, + MessageBroadcaster: false, + MessageChannel: false, + MessageEvent: false, + MessageListenerManager: false, + MessagePort: false, + MessageSender: false, + MimeType: false, + MimeTypeArray: false, + MouseEvent: false, + MouseScrollEvent: false, + MozCanvasPrintState: false, + MozDocumentMatcher: false, + MozDocumentObserver: false, + MozQueryInterface: false, + MozSharedMap: false, + MozSharedMapChangeEvent: false, + MozStorageAsyncStatementParams: false, + MozStorageStatementParams: false, + MozStorageStatementRow: false, + MozWritableSharedMap: false, + MutationEvent: false, + MutationObserver: false, + MutationRecord: false, + NamedNodeMap: false, + Navigator: false, + NetworkInformation: false, + Node: false, + NodeFilter: false, + NodeIterator: false, + NodeList: false, + Notification: false, + NotifyPaintEvent: false, + OfflineAudioCompletionEvent: false, + OfflineAudioContext: false, + OfflineResourceList: false, + OffscreenCanvas: false, + OscillatorNode: false, + PageTransitionEvent: false, + PaintRequest: false, + PaintRequestList: false, + PannerNode: false, + ParentProcessMessageManager: false, + Path2D: false, + PathUtils: false, + PaymentAddress: false, + PaymentMethodChangeEvent: false, + PaymentRequest: false, + PaymentRequestUpdateEvent: false, + PaymentResponse: false, + PeerConnectionImpl: false, + PeerConnectionObserver: false, + Performance: false, + PerformanceEntry: false, + PerformanceEntryEvent: false, + PerformanceMark: false, + PerformanceMeasure: false, + PerformanceNavigation: false, + PerformanceNavigationTiming: false, + PerformanceObserver: false, + PerformanceObserverEntryList: false, + PerformanceResourceTiming: false, + PerformanceServerTiming: false, + PerformanceTiming: false, + PeriodicWave: false, + PermissionStatus: false, + Permissions: false, + PlacesBookmark: false, + PlacesBookmarkAddition: false, + PlacesBookmarkGuid: false, + PlacesBookmarkKeyword: false, + PlacesBookmarkMoved: false, + PlacesBookmarkRemoved: false, + PlacesBookmarkTags: false, + PlacesBookmarkTime: false, + PlacesBookmarkTitle: false, + PlacesBookmarkUrl: false, + PlacesEvent: false, + PlacesHistoryCleared: false, + PlacesObservers: false, + PlacesPurgeCaches: false, + PlacesRanking: false, + PlacesVisit: false, + PlacesVisitRemoved: false, + PlacesVisitTitle: false, + PlacesWeakCallbackWrapper: false, + Plugin: false, + PluginArray: false, + PluginCrashedEvent: false, + PointerEvent: false, + PopStateEvent: false, + PopupBlockedEvent: false, + PrecompiledScript: false, + Presentation: false, + PresentationAvailability: false, + PresentationConnection: false, + PresentationConnectionAvailableEvent: false, + PresentationConnectionCloseEvent: false, + PresentationConnectionList: false, + PresentationReceiver: false, + PresentationRequest: false, + PrioEncoder: false, + ProcessMessageManager: false, + ProcessingInstruction: false, + ProgressEvent: false, + PromiseDebugging: false, + PromiseRejectionEvent: false, + PublicKeyCredential: false, + PushManager: false, + PushManagerImpl: false, + PushSubscription: false, + PushSubscriptionOptions: false, + RTCCertificate: false, + RTCDTMFSender: false, + RTCDTMFToneChangeEvent: false, + RTCDataChannel: false, + RTCDataChannelEvent: false, + RTCIceCandidate: false, + RTCPeerConnection: false, + RTCPeerConnectionIceEvent: false, + RTCPeerConnectionStatic: false, + RTCRtpReceiver: false, + RTCRtpSender: false, + RTCRtpTransceiver: false, + RTCSessionDescription: false, + RTCStatsReport: false, + RTCTrackEvent: false, + RadioNodeList: false, + Range: false, + ReadableStreamBYOBReader: false, + ReadableStreamBYOBRequest: false, + ReadableByteStreamController: false, + ReadableStream: false, + ReadableStreamDefaultController: false, + ReadableStreamDefaultReader: false, + Report: false, + ReportBody: false, + ReportingObserver: false, + Request: false, + Response: false, + SessionStoreUtils: false, + SVGAElement: false, + SVGAngle: false, + SVGAnimateElement: false, + SVGAnimateMotionElement: false, + SVGAnimateTransformElement: false, + SVGAnimatedAngle: false, + SVGAnimatedBoolean: false, + SVGAnimatedEnumeration: false, + SVGAnimatedInteger: false, + SVGAnimatedLength: false, + SVGAnimatedLengthList: false, + SVGAnimatedNumber: false, + SVGAnimatedNumberList: false, + SVGAnimatedPreserveAspectRatio: false, + SVGAnimatedRect: false, + SVGAnimatedString: false, + SVGAnimatedTransformList: false, + SVGAnimationElement: false, + SVGCircleElement: false, + SVGClipPathElement: false, + SVGComponentTransferFunctionElement: false, + SVGDefsElement: false, + SVGDescElement: false, + SVGElement: false, + SVGEllipseElement: false, + SVGFEBlendElement: false, + SVGFEColorMatrixElement: false, + SVGFEComponentTransferElement: false, + SVGFECompositeElement: false, + SVGFEConvolveMatrixElement: false, + SVGFEDiffuseLightingElement: false, + SVGFEDisplacementMapElement: false, + SVGFEDistantLightElement: false, + SVGFEDropShadowElement: false, + SVGFEFloodElement: false, + SVGFEFuncAElement: false, + SVGFEFuncBElement: false, + SVGFEFuncGElement: false, + SVGFEFuncRElement: false, + SVGFEGaussianBlurElement: false, + SVGFEImageElement: false, + SVGFEMergeElement: false, + SVGFEMergeNodeElement: false, + SVGFEMorphologyElement: false, + SVGFEOffsetElement: false, + SVGFEPointLightElement: false, + SVGFESpecularLightingElement: false, + SVGFESpotLightElement: false, + SVGFETileElement: false, + SVGFETurbulenceElement: false, + SVGFilterElement: false, + SVGForeignObjectElement: false, + SVGGElement: false, + SVGGeometryElement: false, + SVGGradientElement: false, + SVGGraphicsElement: false, + SVGImageElement: false, + SVGLength: false, + SVGLengthList: false, + SVGLineElement: false, + SVGLinearGradientElement: false, + SVGMPathElement: false, + SVGMarkerElement: false, + SVGMaskElement: false, + SVGMatrix: false, + SVGMetadataElement: false, + SVGNumber: false, + SVGNumberList: false, + SVGPathElement: false, + SVGPathSegList: false, + SVGPatternElement: false, + SVGPoint: false, + SVGPointList: false, + SVGPolygonElement: false, + SVGPolylineElement: false, + SVGPreserveAspectRatio: false, + SVGRadialGradientElement: false, + SVGRect: false, + SVGRectElement: false, + SVGSVGElement: false, + SVGScriptElement: false, + SVGSetElement: false, + SVGStopElement: false, + SVGStringList: false, + SVGStyleElement: false, + SVGSwitchElement: false, + SVGSymbolElement: false, + SVGTSpanElement: false, + SVGTextContentElement: false, + SVGTextElement: false, + SVGTextPathElement: false, + SVGTextPositioningElement: false, + SVGTitleElement: false, + SVGTransform: false, + SVGTransformList: false, + SVGUnitTypes: false, + SVGUseElement: false, + SVGViewElement: false, + SVGZoomAndPan: false, + Screen: false, + ScreenLuminance: false, + ScreenOrientation: false, + ScriptProcessorNode: false, + ScrollAreaEvent: false, + ScrollViewChangeEvent: false, + SecurityPolicyViolationEvent: false, + Selection: false, + ServiceWorker: false, + ServiceWorkerContainer: false, + ServiceWorkerRegistration: false, + ShadowRoot: false, + SharedWorker: false, + SimpleGestureEvent: false, + SourceBuffer: false, + SourceBufferList: false, + SpeechGrammar: false, + SpeechGrammarList: false, + SpeechRecognition: false, + SpeechRecognitionAlternative: false, + SpeechRecognitionError: false, + SpeechRecognitionEvent: false, + SpeechRecognitionResult: false, + SpeechRecognitionResultList: false, + SpeechSynthesis: false, + SpeechSynthesisErrorEvent: false, + SpeechSynthesisEvent: false, + SpeechSynthesisUtterance: false, + SpeechSynthesisVoice: false, + StereoPannerNode: false, + Storage: false, + StorageEvent: false, + StorageManager: false, + StreamFilter: false, + StreamFilterDataEvent: false, + StructuredCloneHolder: false, + StructuredCloneTester: false, + StyleSheet: false, + StyleSheetApplicableStateChangeEvent: false, + StyleSheetList: false, + StyleSheetRemovedEvent: false, + SubtleCrypto: false, + SyncMessageSender: false, + TCPServerSocket: false, + TCPServerSocketEvent: false, + TCPSocket: false, + TCPSocketErrorEvent: false, + TCPSocketEvent: false, + TelemetryStopwatch: false, + TestingDeprecatedInterface: false, + Text: false, + TextClause: false, + TextDecoder: false, + TextEncoder: false, + TextMetrics: false, + TextTrack: false, + TextTrackCue: false, + TextTrackCueList: false, + TextTrackList: false, + TimeEvent: false, + TimeRanges: false, + Touch: false, + TouchEvent: false, + TouchList: false, + TrackEvent: false, + TransceiverImpl: false, + TransformStream: false, + TransformStreamDefaultController: false, + TransitionEvent: false, + TreeColumn: false, + TreeColumns: false, + TreeContentView: false, + TreeWalker: false, + U2F: false, + UDPMessageEvent: false, + UDPSocket: false, + UIEvent: false, + URL: false, + URLSearchParams: false, + UserInteraction: false, + UserProximityEvent: false, + VRDisplay: false, + VRDisplayCapabilities: false, + VRDisplayEvent: false, + VREyeParameters: false, + VRFieldOfView: false, + VRFrameData: false, + VRMockController: false, + VRMockDisplay: false, + VRPose: false, + VRServiceTest: false, + VRStageParameters: false, + VRSubmitFrameResult: false, + VTTCue: false, + VTTRegion: false, + ValidityState: false, + VideoColorSpace: false, + VideoDecoder: false, + VideoEncoder: false, + VideoFrame: false, + VideoPlaybackQuality: false, + VideoTrack: false, + VideoTrackList: false, + VisualViewport: false, + WaveShaperNode: false, + WebExtensionContentScript: false, + WebExtensionPolicy: false, + WebGL2RenderingContext: false, + WebGLActiveInfo: false, + WebGLBuffer: false, + WebGLContextEvent: false, + WebGLFramebuffer: false, + WebGLProgram: false, + WebGLQuery: false, + WebGLRenderbuffer: false, + WebGLRenderingContext: false, + WebGLSampler: false, + WebGLShader: false, + WebGLShaderPrecisionFormat: false, + WebGLSync: false, + WebGLTexture: false, + WebGLTransformFeedback: false, + WebGLUniformLocation: false, + WebGLVertexArrayObject: false, + WebGPU: false, + WebGPUAdapter: false, + WebGPUAttachmentState: false, + WebGPUBindGroup: false, + WebGPUBindGroupLayout: false, + WebGPUBindingType: false, + WebGPUBlendFactor: false, + WebGPUBlendOperation: false, + WebGPUBlendState: false, + WebGPUBuffer: false, + WebGPUBufferUsage: false, + WebGPUColorWriteBits: false, + WebGPUCommandBuffer: false, + WebGPUCommandEncoder: false, + WebGPUCompareFunction: false, + WebGPUComputePipeline: false, + WebGPUDepthStencilState: false, + WebGPUDevice: false, + WebGPUFence: false, + WebGPUFilterMode: false, + WebGPUIndexFormat: false, + WebGPUInputState: false, + WebGPUInputStepMode: false, + WebGPULoadOp: false, + WebGPULogEntry: false, + WebGPUPipelineLayout: false, + WebGPUPrimitiveTopology: false, + WebGPUQueue: false, + WebGPURenderPipeline: false, + WebGPUSampler: false, + WebGPUShaderModule: false, + WebGPUShaderStage: false, + WebGPUShaderStageBit: false, + WebGPUStencilOperation: false, + WebGPUStoreOp: false, + WebGPUSwapChain: false, + WebGPUTexture: false, + WebGPUTextureDimension: false, + WebGPUTextureFormat: false, + WebGPUTextureUsage: false, + WebGPUTextureView: false, + WebGPUVertexFormat: false, + WebKitCSSMatrix: false, + WebSocket: false, + WebrtcGlobalInformation: false, + WheelEvent: false, + Window: false, + WindowGlobalChild: false, + WindowGlobalParent: false, + WindowRoot: false, + Worker: false, + Worklet: false, + WritableStream: false, + WritableStreamDefaultController: false, + WritableStreamDefaultWriter: false, + XMLDocument: false, + XMLHttpRequest: false, + XMLHttpRequestEventTarget: false, + XMLHttpRequestUpload: false, + XMLSerializer: false, + XPathEvaluator: false, + XPathExpression: false, + XPathResult: false, + XSLTProcessor: false, + XULCommandEvent: false, + XULElement: false, + XULFrameElement: false, + XULMenuElement: false, + XULPopupElement: false, + XULScrollElement: false, + XULTextElement: false, + console: false, + // These are hard-coded and available in privileged scopes. + // See BackstagePass::Resolve. + fetch: false, + crypto: false, + indexedDB: false, + structuredClone: false, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/process-script.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/process-script.js new file mode 100644 index 0000000000..f329a6650b --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/process-script.js @@ -0,0 +1,38 @@ +/** + * @fileoverview Defines the environment for process scripts. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + globals: { + // dom/chrome-webidl/MessageManager.webidl + + // MessageManagerGlobal + dump: false, + atob: false, + btoa: false, + + // MessageListenerManagerMixin + addMessageListener: false, + removeMessageListener: false, + addWeakMessageListener: false, + removeWeakMessageListener: false, + + // MessageSenderMixin + sendAsyncMessage: false, + processMessageManager: false, + remoteType: false, + + // SyncMessageSenderMixin + sendSyncMessage: false, + + // ContentProcessMessageManager + initialProcessData: false, + sharedData: false, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/remote-page.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/remote-page.js new file mode 100644 index 0000000000..74055457fe --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/remote-page.js @@ -0,0 +1,43 @@ +/** + * @fileoverview Defines the environment for remote page. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + globals: { + atob: false, + btoa: false, + RPMAddTRRExcludedDomain: false, + RPMGetAppBuildID: false, + RPMGetInnerMostURI: false, + RPMGetIntPref: false, + RPMGetStringPref: false, + RPMGetBoolPref: false, + RPMSetPref: false, + RPMGetFormatURLPref: false, + RPMIsTRROnlyFailure: false, + RPMIsFirefox: false, + RPMIsNativeFallbackFailure: false, + RPMIsWindowPrivate: false, + RPMSendAsyncMessage: false, + RPMSendQuery: false, + RPMAddMessageListener: false, + RPMRecordTelemetryEvent: false, + RPMCheckAlternateHostAvailable: false, + RPMAddToHistogram: false, + RPMRemoveMessageListener: false, + RPMGetHttpResponseHeader: false, + RPMTryPingSecureWWWLink: false, + RPMOpenSecureWWWLink: false, + RPMOpenPreferences: false, + RPMGetTRRSkipReason: false, + RPMGetTRRDomain: false, + RPMIsSiteSpecificTRRError: false, + RPMSetTRRDisabledLoadFlags: false, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/simpletest.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/simpletest.js new file mode 100644 index 0000000000..2f5dd5c33e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/simpletest.js @@ -0,0 +1,35 @@ +/** + * @fileoverview Defines the environment for scripts that use the SimpleTest + * mochitest harness. Imports the globals from the relevant files. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +// ----------------------------------------------------------------------------- +// Rule Definition +// ----------------------------------------------------------------------------- + +var path = require("path"); +var { getScriptGlobals } = require("./utils"); + +// When updating this list, be sure to also update the 'support-files' config +// in `tools/lint/eslint.yml`. +const simpleTestFiles = [ + "AccessibilityUtils.js", + "ExtensionTestUtils.js", + "EventUtils.js", + "MockObjects.js", + "SimpleTest.js", + "WindowSnapshot.js", + "paint_listener.js", +]; +const simpleTestPath = "testing/mochitest/tests/SimpleTest"; + +module.exports = getScriptGlobals( + "simpletest", + simpleTestFiles.map(file => path.join(simpleTestPath, file)) +); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/sjs.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/sjs.js new file mode 100644 index 0000000000..4f10641c09 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/sjs.js @@ -0,0 +1,41 @@ +/** + * @fileoverview Defines the environment for sjs files. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + globals: { + // All these variables are hard-coded to be available for sjs scopes only. + // https://searchfox.org/mozilla-central/rev/26a1b0fce12e6dd495a954c542bb1e7bd6e0d548/netwerk/test/httpserver/httpd.js#2879 + atob: false, + btoa: false, + Cc: false, + ChromeUtils: false, + Ci: false, + Components: false, + Cr: false, + Cu: false, + dump: false, + IOUtils: false, + PathUtils: false, + TextDecoder: false, + TextEncoder: false, + URLSearchParams: false, + URL: false, + getState: false, + setState: false, + getSharedState: false, + setSharedState: false, + getObjectState: false, + setObjectState: false, + registerPathHandler: false, + Services: false, + // importScripts is also available. + importScripts: false, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/special-powers-sandbox.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/special-powers-sandbox.js new file mode 100644 index 0000000000..5a28c91883 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/special-powers-sandbox.js @@ -0,0 +1,46 @@ +/** + * @fileoverview Defines the environment for SpecialPowers sandbox. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + globals: { + // wantComponents defaults to true, + Components: false, + Ci: false, + Cr: false, + Cc: false, + Cu: false, + Services: false, + + // testing/specialpowers/content/SpecialPowersSandbox.sys.mjs + + // SANDBOX_GLOBALS + Blob: false, + ChromeUtils: false, + FileReader: false, + TextDecoder: false, + TextEncoder: false, + URL: false, + + // EXTRA_IMPORTS + EventUtils: false, + + // SpecialPowersSandbox constructor + assert: false, + Assert: false, + BrowsingContext: false, + InspectorUtils: false, + ok: false, + is: false, + isnot: false, + todo: false, + todo_is: false, + info: false, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/specific.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/specific.js new file mode 100644 index 0000000000..23ebcb5bb1 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/specific.js @@ -0,0 +1,31 @@ +/** + * @fileoverview Defines the environment for the Firefox browser. Allows global + * variables which are non-standard and specific to Firefox. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + globals: { + Cc: false, + ChromeUtils: false, + Ci: false, + Components: false, + Cr: false, + Cu: false, + Debugger: false, + InstallTrigger: false, + // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/InternalError + InternalError: true, + Services: false, + // https://developer.mozilla.org/docs/Web/API/Window/dump + dump: true, + openDialog: false, + // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/uneval + uneval: false, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/testharness.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/testharness.js new file mode 100644 index 0000000000..cea4088a4c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/testharness.js @@ -0,0 +1,61 @@ +/** + * @fileoverview Defines the environment for testharness.js files. This + * is automatically included in (x)html files including + * /resources/testharness.js. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +// These globals are taken from dom/imptests/testharness.js, via the expose +// function. + +module.exports = { + globals: { + EventWatcher: false, + test: false, + async_test: false, + promise_test: false, + promise_rejects: false, + generate_tests: false, + setup: false, + done: false, + on_event: false, + step_timeout: false, + format_value: false, + assert_true: false, + assert_false: false, + assert_equals: false, + assert_not_equals: false, + assert_in_array: false, + assert_object_equals: false, + assert_array_equals: false, + assert_approx_equals: false, + assert_less_than: false, + assert_greater_than: false, + assert_between_exclusive: false, + assert_less_than_equal: false, + assert_greater_than_equal: false, + assert_between_inclusive: false, + assert_regexp_match: false, + assert_class_string: false, + assert_exists: false, + assert_own_property: false, + assert_not_exists: false, + assert_inherits: false, + assert_idl_attribute: false, + assert_readonly: false, + assert_throws: false, + assert_unreaded: false, + assert_any: false, + fetch_tests_from_worker: false, + timeout: false, + add_start_callback: false, + add_test_state_callback: false, + add_result_callback: false, + add_completion_callback: false, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/utils.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/utils.js new file mode 100644 index 0000000000..aeda690ba5 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/utils.js @@ -0,0 +1,62 @@ +/** + * @fileoverview Provides utilities for setting up environments. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var path = require("path"); +var helpers = require("../helpers"); +var globals = require("../globals"); + +/** + * Obtains the globals for a list of files. + * + * @param {Array.<String>} files + * The array of files to get globals for. The paths are relative to the topsrcdir. + * @returns {Object} + * Returns an object with keys of the global names and values of if they are + * writable or not. + */ +function getGlobalsForScripts(environmentName, files, extraDefinitions) { + let fileGlobals = extraDefinitions; + const root = helpers.rootDir; + for (const file of files) { + const fileName = path.join(root, file); + try { + fileGlobals = fileGlobals.concat(globals.getGlobalsForFile(fileName)); + } catch (e) { + console.error(`Could not load globals from file ${fileName}: ${e}`); + console.error( + `You may need to update the mappings for the ${environmentName} environment` + ); + throw new Error(`Could not load globals from file ${fileName}: ${e}`); + } + } + + var globalObjects = {}; + for (let global of fileGlobals) { + globalObjects[global.name] = global.writable; + } + return globalObjects; +} + +module.exports = { + getScriptGlobals( + environmentName, + files, + extraDefinitions = [], + extraEnv = {} + ) { + if (helpers.isMozillaCentralBased()) { + return { + globals: getGlobalsForScripts(environmentName, files, extraDefinitions), + ...extraEnv, + }; + } + return helpers.getSavedEnvironmentItems(environmentName); + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/xpcshell.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/xpcshell.js new file mode 100644 index 0000000000..408bc2e277 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/xpcshell.js @@ -0,0 +1,59 @@ +/** + * @fileoverview Defines the environment for xpcshell test files. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var { getScriptGlobals } = require("./utils"); + +const extraGlobals = [ + // Defined in XPCShellImpl.cpp + "print", + "readline", + "load", + "quit", + "dumpXPC", + "dump", + "gc", + "gczeal", + "options", + "sendCommand", + "atob", + "btoa", + "setInterruptCallback", + "simulateNoScriptActivity", + "registerXPCTestComponents", + + // Assert.sys.mjs globals. + "setReporter", + "report", + "ok", + "equal", + "notEqual", + "deepEqual", + "notDeepEqual", + "strictEqual", + "notStrictEqual", + "throws", + "rejects", + "greater", + "greaterOrEqual", + "less", + "lessOrEqual", + // TestingFunctions.cpp globals + "allocationMarker", + "byteSize", + "saveStack", +]; + +module.exports = getScriptGlobals( + "xpcshell", + ["testing/xpcshell/head.js"], + extraGlobals.map(g => { + return { name: g, writable: false }; + }) +); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js new file mode 100644 index 0000000000..25c149fa9f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js @@ -0,0 +1,668 @@ +/** + * @fileoverview functions for scanning an AST for globals including + * traversing referenced scripts. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const path = require("path"); +const fs = require("fs"); +const helpers = require("./helpers"); +const htmlparser = require("htmlparser2"); +const testharnessEnvironment = require("./environments/testharness.js"); + +const callExpressionDefinitions = [ + /^loader\.lazyGetter\((?:globalThis|this), "(\w+)"/, + /^loader\.lazyServiceGetter\((?:globalThis|this), "(\w+)"/, + /^loader\.lazyRequireGetter\((?:globalThis|this), "(\w+)"/, + /^XPCOMUtils\.defineLazyGetter\((?:globalThis|this), "(\w+)"/, + /^ChromeUtils\.defineLazyGetter\((?:globalThis|this), "(\w+)"/, + /^ChromeUtils\.defineModuleGetter\((?:globalThis|this), "(\w+)"/, + /^XPCOMUtils\.defineLazyPreferenceGetter\((?:globalThis|this), "(\w+)"/, + /^XPCOMUtils\.defineLazyScriptGetter\((?:globalThis|this), "(\w+)"/, + /^XPCOMUtils\.defineLazyServiceGetter\((?:globalThis|this), "(\w+)"/, + /^XPCOMUtils\.defineConstant\((?:globalThis|this), "(\w+)"/, + /^DevToolsUtils\.defineLazyGetter\((?:globalThis|this), "(\w+)"/, + /^Object\.defineProperty\((?:globalThis|this), "(\w+)"/, + /^Reflect\.defineProperty\((?:globalThis|this), "(\w+)"/, + /^this\.__defineGetter__\("(\w+)"/, +]; + +const callExpressionMultiDefinitions = [ + "XPCOMUtils.defineLazyGlobalGetters(this,", + "XPCOMUtils.defineLazyGlobalGetters(globalThis,", + "XPCOMUtils.defineLazyModuleGetters(this,", + "XPCOMUtils.defineLazyModuleGetters(globalThis,", + "XPCOMUtils.defineLazyServiceGetters(this,", + "XPCOMUtils.defineLazyServiceGetters(globalThis,", + "ChromeUtils.defineESModuleGetters(this,", + "ChromeUtils.defineESModuleGetters(globalThis,", + "loader.lazyRequireGetter(this,", + "loader.lazyRequireGetter(globalThis,", +]; + +const subScriptMatches = [ + /Services\.scriptloader\.loadSubScript\("(.*?)", this\)/, +]; + +const workerImportFilenameMatch = /(.*\/)*((.*?)\.jsm?)/; + +/** + * Parses a list of "name:boolean_value" or/and "name" options divided by comma + * or whitespace. + * + * This function was copied from eslint.js + * + * @param {string} string The string to parse. + * @param {Comment} comment The comment node which has the string. + * @returns {Object} Result map object of names and boolean values + */ +function parseBooleanConfig(string, comment) { + let items = {}; + + // Collapse whitespace around : to make parsing easier + string = string.replace(/\s*:\s*/g, ":"); + // Collapse whitespace around , + string = string.replace(/\s*,\s*/g, ","); + + string.split(/\s|,+/).forEach(function (name) { + if (!name) { + return; + } + + let pos = name.indexOf(":"); + let value; + if (pos !== -1) { + value = name.substring(pos + 1, name.length); + name = name.substring(0, pos); + } + + items[name] = { + value: value === "true", + comment, + }; + }); + + return items; +} + +/** + * Global discovery can require parsing many files. This map of + * {String} => {Object} caches what globals were discovered for a file path. + */ +const globalCache = new Map(); + +/** + * Global discovery can occasionally meet circular dependencies due to the way + * js files are included via html/xhtml files etc. This set is used to avoid + * getting into loops whilst the discovery is in progress. + */ +var globalDiscoveryInProgressForFiles = new Set(); + +/** + * When looking for globals in HTML files, it can be common to have more than + * one script tag with inline javascript. These will normally be called together, + * so we store the globals for just the last HTML file processed. + */ +var lastHTMLGlobals = {}; + +/** + * Attempts to convert an CallExpressions that look like module imports + * into global variable definitions. + * + * @param {Object} node + * The AST node to convert. + * @param {boolean} isGlobal + * True if the current node is in the global scope. + * + * @return {Array} + * An array of objects that contain details about the globals: + * - {String} name + * The name of the global. + * - {Boolean} writable + * If the global is writeable or not. + */ +function convertCallExpressionToGlobals(node, isGlobal) { + let express = node.expression; + if ( + express.type === "CallExpression" && + express.callee.type === "MemberExpression" && + express.callee.object && + express.callee.object.type === "Identifier" && + express.arguments.length === 1 && + express.arguments[0].type === "ArrayExpression" && + express.callee.property.type === "Identifier" && + express.callee.property.name === "importGlobalProperties" + ) { + return express.arguments[0].elements.map(literal => { + return { + explicit: true, + name: literal.value, + writable: false, + }; + }); + } + + let source; + try { + source = helpers.getASTSource(node); + } catch (e) { + return []; + } + + // The definition matches below must be in the global scope for us to define + // a global, so bail out early if we're not a global. + if (!isGlobal) { + return []; + } + + for (let reg of subScriptMatches) { + let match = source.match(reg); + if (match) { + return getGlobalsForScript(match[1], "script").map(g => { + // We don't want any loadSubScript globals to be explicit, as this + // could trigger no-unused-vars when importing multiple variables + // from a script and not using all of them. + g.explicit = false; + return g; + }); + } + } + + for (let reg of callExpressionDefinitions) { + let match = source.match(reg); + if (match) { + return [{ name: match[1], writable: true, explicit: true }]; + } + } + + if ( + callExpressionMultiDefinitions.some(expr => source.startsWith(expr)) && + node.expression.arguments[1] + ) { + let arg = node.expression.arguments[1]; + if (arg.type === "ObjectExpression") { + return arg.properties + .map(p => ({ + name: p.type === "Property" && p.key.name, + writable: true, + explicit: true, + })) + .filter(g => g.name); + } + if (arg.type === "ArrayExpression") { + return arg.elements + .map(p => ({ + name: p.type === "Literal" && p.value, + writable: true, + explicit: true, + })) + .filter(g => typeof g.name == "string"); + } + } + + if ( + node.expression.callee.type == "MemberExpression" && + node.expression.callee.property.type == "Identifier" && + node.expression.callee.property.name == "defineLazyScriptGetter" + ) { + // The case where we have a single symbol as a string has already been + // handled by the regexp, so we have an array of symbols here. + return node.expression.arguments[1].elements.map(n => ({ + name: n.value, + writable: true, + explicit: true, + })); + } + + return []; +} + +/** + * Attempts to convert an AssignmentExpression into a global variable + * definition if it applies to `this` in the global scope. + * + * @param {Object} node + * The AST node to convert. + * @param {boolean} isGlobal + * True if the current node is in the global scope. + * + * @return {Array} + * An array of objects that contain details about the globals: + * - {String} name + * The name of the global. + * - {Boolean} writable + * If the global is writeable or not. + */ +function convertThisAssignmentExpressionToGlobals(node, isGlobal) { + if ( + isGlobal && + node.expression.left && + node.expression.left.object && + node.expression.left.object.type === "ThisExpression" && + node.expression.left.property && + node.expression.left.property.type === "Identifier" + ) { + return [{ name: node.expression.left.property.name, writable: true }]; + } + return []; +} + +/** + * Attempts to convert an ExpressionStatement to likely global variable + * definitions. + * + * @param {Object} node + * The AST node to convert. + * @param {boolean} isGlobal + * True if the current node is in the global scope. + * + * @return {Array} + * An array of objects that contain details about the globals: + * - {String} name + * The name of the global. + * - {Boolean} writable + * If the global is writeable or not. + */ +function convertWorkerExpressionToGlobals(node, isGlobal, dirname) { + let results = []; + let expr = node.expression; + + if ( + node.expression.type === "CallExpression" && + expr.callee && + expr.callee.type === "Identifier" && + expr.callee.name === "importScripts" + ) { + for (var arg of expr.arguments) { + var match = arg.value && arg.value.match(workerImportFilenameMatch); + if (match) { + if (!match[1]) { + let filePath = path.resolve(dirname, match[2]); + if (fs.existsSync(filePath)) { + let additionalGlobals = module.exports.getGlobalsForFile(filePath); + results = results.concat(additionalGlobals); + } + } + // Import with relative/absolute path should explicitly use + // `import-globals-from` comment. + } + } + } + + return results; +} + +/** + * Attempts to load the globals for a given script. + * + * @param {string} src + * The source path or url of the script to look for. + * @param {string} type + * The type of the current file (script/module). + * @param {string} [dir] + * The directory of the current file. + * @returns {object[]} + * An array of objects with details of the globals in them. + */ +function getGlobalsForScript(src, type, dir) { + let scriptName; + if (src.includes("http:")) { + // We don't handle this currently as the paths are complex to match. + } else if (src.startsWith("chrome://mochikit/content/")) { + // Various ways referencing test files. + src = src.replace("chrome://mochikit/content/", "/"); + scriptName = path.join(helpers.rootDir, "testing", "mochitest", src); + } else if (src.startsWith("chrome://mochitests/content/browser")) { + src = src.replace("chrome://mochitests/content/browser", ""); + scriptName = path.join(helpers.rootDir, src); + } else if (src.includes("SimpleTest")) { + // This is another way of referencing test files... + scriptName = path.join(helpers.rootDir, "testing", "mochitest", src); + } else if (src.startsWith("/tests/")) { + scriptName = path.join(helpers.rootDir, src.substring(7)); + } else if (src.startsWith("/resources/testharness.js")) { + return Object.keys(testharnessEnvironment.globals).map(name => ({ + name, + writable: true, + })); + } else if (dir) { + // Fallback to hoping this is a relative path. + scriptName = path.join(dir, src); + } + if (scriptName && fs.existsSync(scriptName)) { + return module.exports.getGlobalsForFile(scriptName, { + ecmaVersion: helpers.getECMAVersion(), + sourceType: type, + }); + } + return []; +} + +/** + * An object that returns found globals for given AST node types. Each prototype + * property should be named for a node type and accepts a node parameter and a + * parents parameter which is a list of the parent nodes of the current node. + * Each returns an array of globals found. + * + * @param {String} filePath + * The absolute path of the file being parsed. + */ +function GlobalsForNode(filePath, context) { + this.path = filePath; + this.context = context; + + if (this.path) { + this.dirname = path.dirname(this.path); + } else { + this.dirname = null; + } +} + +GlobalsForNode.prototype = { + Program(node) { + let globals = []; + for (let comment of node.comments) { + if (comment.type !== "Block") { + continue; + } + let value = comment.value.trim(); + value = value.replace(/\n/g, ""); + + // We have to discover any globals that ESLint would have defined through + // comment directives. + let match = /^globals?\s+(.+)/.exec(value); + if (match) { + let values = parseBooleanConfig(match[1].trim(), node); + for (let name of Object.keys(values)) { + globals.push({ + name, + writable: values[name].value, + }); + } + // We matched globals, so we won't match import-globals-from. + continue; + } + + match = /^import-globals-from\s+(.+)$/.exec(value); + if (!match) { + continue; + } + + if (!this.dirname) { + // If this is testing context without path, ignore import. + return globals; + } + + let filePath = match[1].trim(); + + if (filePath.endsWith(".mjs")) { + if (this.context) { + this.context.report( + comment, + "import-globals-from does not support module files - use a direct import instead" + ); + } else { + // Fall back to throwing an error, as we do not have a context in all situations, + // e.g. when loading the environment. + throw new Error( + "import-globals-from does not support module files - use a direct import instead" + ); + } + continue; + } + + if (!path.isAbsolute(filePath)) { + filePath = path.resolve(this.dirname, filePath); + } else { + filePath = path.join(helpers.rootDir, filePath); + } + globals = globals.concat(module.exports.getGlobalsForFile(filePath)); + } + + return globals; + }, + + ExpressionStatement(node, parents, globalScope) { + let isGlobal = helpers.getIsGlobalThis(parents); + let globals = []; + + // Note: We check the expression types here and only call the necessary + // functions to aid performance. + if (node.expression.type === "AssignmentExpression") { + globals = convertThisAssignmentExpressionToGlobals(node, isGlobal); + } else if (node.expression.type === "CallExpression") { + globals = convertCallExpressionToGlobals(node, isGlobal); + } + + // Here we assume that if importScripts is set in the global scope, then + // this is a worker. It would be nice if eslint gave us a way of getting + // the environment directly. + // + // If this is testing context without path, ignore import. + if (globalScope && globalScope.set.get("importScripts") && this.dirname) { + let workerDetails = convertWorkerExpressionToGlobals( + node, + isGlobal, + this.dirname + ); + globals = globals.concat(workerDetails); + } + + return globals; + }, +}; + +module.exports = { + /** + * Returns all globals for a given file. Recursively searches through + * import-globals-from directives and also includes globals defined by + * standard eslint directives. + * + * @param {String} filePath + * The absolute path of the file to be parsed. + * @param {Object} astOptions + * Extra options to pass to the parser. + * @return {Array} + * An array of objects that contain details about the globals: + * - {String} name + * The name of the global. + * - {Boolean} writable + * If the global is writeable or not. + */ + getGlobalsForFile(filePath, astOptions = {}) { + if (globalCache.has(filePath)) { + return globalCache.get(filePath); + } + + if (globalDiscoveryInProgressForFiles.has(filePath)) { + // We're already processing this file, so return an empty set for now - + // the initial processing will pick up on the globals for this file. + return []; + } + globalDiscoveryInProgressForFiles.add(filePath); + + let content = fs.readFileSync(filePath, "utf8"); + + // Parse the content into an AST + let { ast, scopeManager, visitorKeys } = helpers.parseCode( + content, + astOptions + ); + + // Discover global declarations + let globalScope = scopeManager.acquire(ast); + + let globals = Object.keys(globalScope.variables).map(v => ({ + name: globalScope.variables[v].name, + writable: true, + })); + + // Walk over the AST to find any of our custom globals + let handler = new GlobalsForNode(filePath); + + helpers.walkAST(ast, visitorKeys, (type, node, parents) => { + if (type in handler) { + let newGlobals = handler[type](node, parents, globalScope); + globals.push.apply(globals, newGlobals); + } + }); + + globalCache.set(filePath, globals); + + globalDiscoveryInProgressForFiles.delete(filePath); + return globals; + }, + + /** + * Returns all globals for a code. + * This is only for testing. + * + * @param {String} code + * The JS code + * @param {Object} astOptions + * Extra options to pass to the parser. + * @return {Array} + * An array of objects that contain details about the globals: + * - {String} name + * The name of the global. + * - {Boolean} writable + * If the global is writeable or not. + */ + getGlobalsForCode(code, astOptions = {}) { + // Parse the content into an AST + let { ast, scopeManager, visitorKeys } = helpers.parseCode( + code, + astOptions, + { useBabel: false } + ); + + // Discover global declarations + let globalScope = scopeManager.acquire(ast); + + let globals = Object.keys(globalScope.variables).map(v => ({ + name: globalScope.variables[v].name, + writable: true, + })); + + // Walk over the AST to find any of our custom globals + let handler = new GlobalsForNode(null); + + helpers.walkAST(ast, visitorKeys, (type, node, parents) => { + if (type in handler) { + let newGlobals = handler[type](node, parents, globalScope); + globals.push.apply(globals, newGlobals); + } + }); + + return globals; + }, + + /** + * Returns all the globals for an html file that are defined by imported + * scripts (i.e. <script src="foo.js">). + * + * This function will cache results for one html file only - we expect + * this to be called sequentially for each chunk of a HTML file, rather + * than chucks of different files in random order. + * + * @param {String} filePath + * The absolute path of the file to be parsed. + * @return {Array} + * An array of objects that contain details about the globals: + * - {String} name + * The name of the global. + * - {Boolean} writable + * If the global is writeable or not. + */ + getImportedGlobalsForHTMLFile(filePath) { + if (lastHTMLGlobals.filename === filePath) { + return lastHTMLGlobals.globals; + } + + let dir = path.dirname(filePath); + let globals = []; + + let content = fs.readFileSync(filePath, "utf8"); + let scriptSrcs = []; + + // We use htmlparser as this ensures we find the script tags correctly. + let parser = new htmlparser.Parser( + { + onopentag(name, attribs) { + if (name === "script" && "src" in attribs) { + scriptSrcs.push({ + src: attribs.src, + type: + "type" in attribs && attribs.type == "module" + ? "module" + : "script", + }); + } + }, + }, + { + xmlMode: filePath.endsWith("xhtml"), + } + ); + + parser.parseComplete(content); + + for (let script of scriptSrcs) { + // Ensure that the script src isn't just "". + if (!script.src) { + continue; + } + globals.push(...getGlobalsForScript(script.src, script.type, dir)); + } + + lastHTMLGlobals.filePath = filePath; + return (lastHTMLGlobals.globals = globals); + }, + + /** + * Intended to be used as-is for an ESLint rule that parses for globals in + * the current file and recurses through import-globals-from directives. + * + * @param {Object} context + * The ESLint parsing context. + */ + getESLintGlobalParser(context) { + let globalScope; + + let parser = { + Program(node) { + globalScope = context.getScope(); + }, + }; + let filename = context.getFilename(); + + let extraHTMLGlobals = []; + if (filename.endsWith(".html") || filename.endsWith(".xhtml")) { + extraHTMLGlobals = module.exports.getImportedGlobalsForHTMLFile(filename); + } + + // Install thin wrappers around GlobalsForNode + let handler = new GlobalsForNode(helpers.getAbsoluteFilePath(context)); + + for (let type of Object.keys(GlobalsForNode.prototype)) { + parser[type] = function (node) { + if (type === "Program") { + globalScope = context.getScope(); + helpers.addGlobals(extraHTMLGlobals, globalScope); + } + let globals = handler[type](node, context.getAncestors(), globalScope); + helpers.addGlobals( + globals, + globalScope, + node.type !== "Program" && node + ); + }; + } + + return parser; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js new file mode 100644 index 0000000000..dc4106631a --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js @@ -0,0 +1,797 @@ +/** + * @fileoverview A collection of helper functions. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +"use strict"; + +const parser = require("espree"); +const { analyze } = require("eslint-scope"); +const { KEYS: defaultVisitorKeys } = require("eslint-visitor-keys"); +const estraverse = require("estraverse"); +const path = require("path"); +const fs = require("fs"); +const toml = require("toml-eslint-parser"); +const recommendedConfig = require("./configs/recommended"); + +var gRootDir = null; +var directoryManifests = new Map(); + +let xpidlData; + +module.exports = { + get servicesData() { + return require("./services.json"); + }, + + /** + * Obtains xpidl data from the object directory specified in the + * environment. + * + * @returns {Map<string, object>} + * A map of interface names to the interface details. + */ + get xpidlData() { + let xpidlDir; + + if (process.env.TASK_ID && !process.env.MOZ_XPT_ARTIFACTS_DIR) { + throw new Error( + "MOZ_XPT_ARTIFACTS_DIR must be set for this rule in automation" + ); + } + xpidlDir = process.env.MOZ_XPT_ARTIFACTS_DIR; + + if (!xpidlDir && process.env.MOZ_OBJDIR) { + xpidlDir = `${process.env.MOZ_OBJDIR}/dist/xpt_artifacts/`; + if (!fs.existsSync(xpidlDir)) { + xpidlDir = `${process.env.MOZ_OBJDIR}/config/makefiles/xpidl/`; + } + } + if (!xpidlDir) { + throw new Error( + "MOZ_OBJDIR must be defined in the environment for this rule, i.e. MOZ_OBJDIR=objdir-ff ./mach ..." + ); + } + if (xpidlData) { + return xpidlData; + } + let files = fs.readdirSync(`${xpidlDir}`); + // `Makefile` is an expected file in the directory. + if (files.length <= 1) { + throw new Error("Missing xpidl data files, maybe you need to build?"); + } + xpidlData = new Map(); + for (let file of files) { + if (!file.endsWith(".xpt")) { + continue; + } + let data = JSON.parse(fs.readFileSync(path.join(`${xpidlDir}`, file))); + for (let details of data) { + xpidlData.set(details.name, details); + } + } + return xpidlData; + }, + + /** + * Gets the abstract syntax tree (AST) of the JavaScript source code contained + * in sourceText. This matches the results for an eslint parser, see + * https://eslint.org/docs/developer-guide/working-with-custom-parsers. + * + * @param {String} sourceText + * Text containing valid JavaScript. + * @param {Object} astOptions + * Extra configuration to pass to the espree parser, these will override + * the configuration from getPermissiveConfig(). + * @param {Object} configOptions + * Extra options for getPermissiveConfig(). + * + * @return {Object} + * Returns an object containing `ast`, `scopeManager` and + * `visitorKeys` + */ + parseCode(sourceText, astOptions = {}, configOptions = {}) { + // Use a permissive config file to allow parsing of anything that Espree + // can parse. + let config = { ...this.getPermissiveConfig(configOptions), ...astOptions }; + + let parseResult = parser.parse(sourceText, config); + + let visitorKeys = parseResult.visitorKeys || defaultVisitorKeys; + + // eslint-scope doesn't support "latest" as a version, so we pass a really + // big number to ensure this always reads as the latest. + // xref https://github.com/eslint/eslint-scope/issues/74 + config.ecmaVersion = + config.ecmaVersion == "latest" ? 1e8 : config.ecmaVersion; + + return { + ast: parseResult, + scopeManager: parseResult.scopeManager || analyze(parseResult, config), + visitorKeys, + }; + }, + + /** + * A simplistic conversion of some AST nodes to a standard string form. + * + * @param {Object} node + * The AST node to convert. + * + * @return {String} + * The JS source for the node. + */ + getASTSource(node, context) { + switch (node.type) { + case "MemberExpression": + if (node.computed) { + let filename = context && context.getFilename(); + throw new Error( + `getASTSource unsupported computed MemberExpression in ${filename}` + ); + } + return ( + this.getASTSource(node.object) + + "." + + this.getASTSource(node.property) + ); + case "ThisExpression": + return "this"; + case "Identifier": + return node.name; + case "Literal": + return JSON.stringify(node.value); + case "CallExpression": + var args = node.arguments.map(a => this.getASTSource(a)).join(", "); + return this.getASTSource(node.callee) + "(" + args + ")"; + case "ObjectExpression": + return "{}"; + case "ExpressionStatement": + return this.getASTSource(node.expression) + ";"; + case "FunctionExpression": + return "function() {}"; + case "ArrayExpression": + return "[" + node.elements.map(this.getASTSource, this).join(",") + "]"; + case "ArrowFunctionExpression": + return "() => {}"; + case "AssignmentExpression": + return ( + this.getASTSource(node.left) + " = " + this.getASTSource(node.right) + ); + case "BinaryExpression": + return ( + this.getASTSource(node.left) + + " " + + node.operator + + " " + + this.getASTSource(node.right) + ); + case "UnaryExpression": + return node.operator + " " + this.getASTSource(node.argument); + default: + throw new Error("getASTSource unsupported node type: " + node.type); + } + }, + + /** + * This walks an AST in a manner similar to ESLint passing node events to the + * listener. The listener is expected to be a simple function + * which accepts node type, node and parents arguments. + * + * @param {Object} ast + * The AST to walk. + * @param {Array} visitorKeys + * The visitor keys to use for the AST. + * @param {Function} listener + * A callback function to call for the nodes. Passed three arguments, + * event type, node and an array of parent nodes for the current node. + */ + walkAST(ast, visitorKeys, listener) { + let parents = []; + + estraverse.traverse(ast, { + enter(node, parent) { + listener(node.type, node, parents); + + parents.push(node); + }, + + leave(node, parent) { + if (!parents.length) { + throw new Error("Left more nodes than entered."); + } + parents.pop(); + }, + + keys: visitorKeys, + }); + if (parents.length) { + throw new Error("Entered more nodes than left."); + } + }, + + /** + * Add a variable to the current scope. + * HACK: This relies on eslint internals so it could break at any time. + * + * @param {String} name + * The variable name to add to the scope. + * @param {ASTScope} scope + * The scope to add to. + * @param {boolean} writable + * Whether the global can be overwritten. + * @param {Object} [node] + * The AST node that defined the globals. + */ + addVarToScope(name, scope, writable, node) { + scope.__defineGeneric(name, scope.set, scope.variables, null, null); + + let variable = scope.set.get(name); + variable.eslintExplicitGlobal = false; + variable.writeable = writable; + if (node) { + variable.defs.push({ + type: "Variable", + node, + name: { name, parent: node.parent }, + }); + variable.identifiers.push(node); + } + + // Walk to the global scope which holds all undeclared variables. + while (scope.type != "global") { + scope = scope.upper; + } + + // "through" contains all references with no found definition. + scope.through = scope.through.filter(function (reference) { + if (reference.identifier.name != name) { + return true; + } + + // Links the variable and the reference. + // And this reference is removed from `Scope#through`. + reference.resolved = variable; + variable.references.push(reference); + return false; + }); + }, + + /** + * Adds a set of globals to a scope. + * + * @param {Array} globalVars + * An array of global variable names. + * @param {ASTScope} scope + * The scope. + * @param {Object} [node] + * The AST node that defined the globals. + */ + addGlobals(globalVars, scope, node) { + globalVars.forEach(v => + this.addVarToScope(v.name, scope, v.writable, v.explicit && node) + ); + }, + + /** + * To allow espree to parse almost any JavaScript we need as many features as + * possible turned on. This method returns that config. + * + * @param {Object} options + * { + * useBabel: {boolean} whether to set babelOptions. + * } + * @return {Object} + * Espree compatible permissive config. + */ + getPermissiveConfig({ useBabel = true } = {}) { + return { + range: true, + loc: true, + comment: true, + attachComment: true, + ecmaVersion: this.getECMAVersion(), + sourceType: "script", + }; + }, + + /** + * Returns the ECMA version of the recommended config. + * + * @return {Number} The ECMA version of the recommended config. + */ + getECMAVersion() { + return recommendedConfig.parserOptions.ecmaVersion; + }, + + /** + * Check whether it's inside top-level script. + * + * @param {Array} ancestors + * The parents of the current node. + * + * @return {Boolean} + * True or false + */ + getIsTopLevelScript(ancestors) { + for (let parent of ancestors) { + switch (parent.type) { + case "ArrowFunctionExpression": + case "FunctionDeclaration": + case "FunctionExpression": + case "PropertyDefinition": + case "StaticBlock": + return false; + } + } + return true; + }, + + isTopLevel(ancestors) { + for (let parent of ancestors) { + switch (parent.type) { + case "ArrowFunctionExpression": + case "FunctionDeclaration": + case "FunctionExpression": + case "PropertyDefinition": + case "StaticBlock": + case "BlockStatement": + return false; + } + } + return true; + }, + + /** + * Check whether `this` expression points the global this. + * + * @param {Array} ancestors + * The parents of the current node. + * + * @return {Boolean} + * True or false + */ + getIsGlobalThis(ancestors) { + for (let parent of ancestors) { + switch (parent.type) { + case "FunctionDeclaration": + case "FunctionExpression": + case "PropertyDefinition": + case "StaticBlock": + return false; + } + } + return true; + }, + + /** + * Check whether the node is evaluated at top-level script unconditionally. + * + * @param {Array} ancestors + * The parents of the current node. + * + * @return {Boolean} + * True or false + */ + getIsTopLevelAndUnconditionallyExecuted(ancestors) { + for (let parent of ancestors) { + switch (parent.type) { + // Control flow + case "IfStatement": + case "SwitchStatement": + case "TryStatement": + case "WhileStatement": + case "DoWhileStatement": + case "ForStatement": + case "ForInStatement": + case "ForOfStatement": + return false; + + // Function + case "FunctionDeclaration": + case "FunctionExpression": + case "ArrowFunctionExpression": + case "ClassBody": + return false; + + // Branch + case "LogicalExpression": + case "ConditionalExpression": + case "ChainExpression": + return false; + + case "AssignmentExpression": + switch (parent.operator) { + // Branch + case "||=": + case "&&=": + case "??=": + return false; + } + break; + + // Implicit branch (default value) + case "ObjectPattern": + case "ArrayPattern": + return false; + } + } + return true; + }, + + /** + * Check whether we might be in a test head file. + * + * @param {RuleContext} scope + * You should pass this from within a rule + * e.g. helpers.getIsHeadFile(context) + * + * @return {Boolean} + * True or false + */ + getIsHeadFile(scope) { + var pathAndFilename = this.cleanUpPath(scope.getFilename()); + + return /.*[\\/]head(_.+)?\.js$/.test(pathAndFilename); + }, + + /** + * Gets the head files for a potential test file + * + * @param {RuleContext} scope + * You should pass this from within a rule + * e.g. helpers.getIsHeadFile(context) + * + * @return {String[]} + * Paths to head files to load for the test + */ + getTestHeadFiles(scope) { + if (!this.getIsTest(scope)) { + return []; + } + + let filepath = this.cleanUpPath(scope.getFilename()); + let dir = path.dirname(filepath); + + let names = fs + .readdirSync(dir) + .filter( + name => + (name.startsWith("head") || name.startsWith("xpcshell-head")) && + name.endsWith(".js") + ) + .map(name => path.join(dir, name)); + return names; + }, + + /** + * Gets all the test manifest data for a directory + * + * @param {String} dir + * The directory + * + * @return {Array} + * An array of objects with file and manifest properties + */ + getManifestsForDirectory(dir) { + if (directoryManifests.has(dir)) { + return directoryManifests.get(dir); + } + + let manifests = []; + let names = []; + try { + names = fs.readdirSync(dir); + } catch (err) { + // Ignore directory not found, it might be faked by a test + if (err.code !== "ENOENT") { + throw err; + } + } + + for (let name of names) { + if (name.endsWith(".toml")) { + try { + const ast = toml.parseTOML( + fs.readFileSync(path.join(dir, name), "utf8") + ); + var manifest = {}; + ast.body.forEach(top => { + if (top.type == "TOMLTopLevelTable") { + top.body.forEach(obj => { + if (obj.type == "TOMLTable") { + manifest[obj.resolvedKey] = {}; + } + }); + } + }); + manifests.push({ + file: path.join(dir, name), + manifest, + }); + } catch (e) { + console.log( + "TOML ERROR: " + + e.message + + " @line: " + + e.lineNumber + + ", column: " + + e.column + ); + } + } + } + + directoryManifests.set(dir, manifests); + return manifests; + }, + + /** + * Gets the manifest file a test is listed in + * + * @param {RuleContext} scope + * You should pass this from within a rule + * e.g. helpers.getIsHeadFile(context) + * + * @return {String} + * The path to the test manifest file + */ + getTestManifest(scope) { + let filepath = this.cleanUpPath(scope.getFilename()); + + let dir = path.dirname(filepath); + let filename = path.basename(filepath); + + for (let manifest of this.getManifestsForDirectory(dir)) { + if (filename in manifest.manifest) { + return manifest.file; + } + } + + return null; + }, + + /** + * Check whether we are in a test of some kind. + * + * @param {RuleContext} scope + * You should pass this from within a rule + * e.g. helpers.getIsTest(context) + * + * @return {Boolean} + * True or false + */ + getIsTest(scope) { + // Regardless of the manifest name being in a manifest means we're a test. + let manifest = this.getTestManifest(scope); + if (manifest) { + return true; + } + + return !!this.getTestType(scope); + }, + + /* + * Check if this is an .sjs file. + */ + getIsSjs(scope) { + let filepath = this.cleanUpPath(scope.getFilename()); + + return path.extname(filepath) == ".sjs"; + }, + + /** + * Gets the type of test or null if this isn't a test. + * + * @param {RuleContext} scope + * You should pass this from within a rule + * e.g. helpers.getIsHeadFile(context) + * + * @return {String or null} + * Test type: xpcshell, browser, chrome, mochitest + */ + getTestType(scope) { + let testTypes = ["browser", "xpcshell", "chrome", "mochitest", "a11y"]; + let manifest = this.getTestManifest(scope); + if (manifest) { + let name = path.basename(manifest); + for (let testType of testTypes) { + if (name.startsWith(testType)) { + return testType; + } + } + } + + let filepath = this.cleanUpPath(scope.getFilename()); + let filename = path.basename(filepath); + + if (filename.startsWith("browser_")) { + return "browser"; + } + + if (filename.startsWith("test_")) { + let parent = path.basename(path.dirname(filepath)); + for (let testType of testTypes) { + if (parent.startsWith(testType)) { + return testType; + } + } + + // It likely is a test, we're just not sure what kind. + return "unknown"; + } + + // Likely not a test + return null; + }, + + getIsWorker(filePath) { + let filename = path.basename(this.cleanUpPath(filePath)).toLowerCase(); + + return filename.includes("worker"); + }, + + /** + * Gets the root directory of the repository by walking up directories from + * this file until a .eslintignore file is found. If this fails, the same + * procedure will be attempted from the current working dir. + * @return {String} The absolute path of the repository directory + */ + get rootDir() { + if (!gRootDir) { + function searchUpForIgnore(dirName, filename) { + let parsed = path.parse(dirName); + while (parsed.root !== dirName) { + if (fs.existsSync(path.join(dirName, filename))) { + return dirName; + } + // Move up a level + dirName = parsed.dir; + parsed = path.parse(dirName); + } + return null; + } + + let possibleRoot = searchUpForIgnore( + path.dirname(module.filename), + ".eslintignore" + ); + if (!possibleRoot) { + possibleRoot = searchUpForIgnore(path.resolve(), ".eslintignore"); + } + if (!possibleRoot) { + possibleRoot = searchUpForIgnore(path.resolve(), "package.json"); + } + if (!possibleRoot) { + // We've couldn't find a root from the module or CWD, so lets just go + // for the CWD. We really don't want to throw if possible, as that + // tends to give confusing results when used with ESLint. + possibleRoot = process.cwd(); + } + + gRootDir = possibleRoot; + } + + return gRootDir; + }, + + /** + * ESLint may be executed from various places: from mach, at the root of the + * repository, or from a directory in the repository when, for instance, + * executed by a text editor's plugin. + * The value returned by context.getFileName() varies because of this. + * This helper function makes sure to return an absolute file path for the + * current context, by looking at process.cwd(). + * @param {Context} context + * @return {String} The absolute path + */ + getAbsoluteFilePath(context) { + var fileName = this.cleanUpPath(context.getFilename()); + var cwd = process.cwd(); + + if (path.isAbsolute(fileName)) { + // Case 2: executed from the repo's root with mach: + // fileName: /path/to/mozilla/repo/a/b/c/d.js + // cwd: /path/to/mozilla/repo + return fileName; + } else if (path.basename(fileName) == fileName) { + // Case 1b: executed from a nested directory, fileName is the base name + // without any path info (happens in Atom with linter-eslint) + return path.join(cwd, fileName); + } + // Case 1: executed form in a nested directory, e.g. from a text editor: + // fileName: a/b/c/d.js + // cwd: /path/to/mozilla/repo/a/b/c + var dirName = path.dirname(fileName); + return cwd.slice(0, cwd.length - dirName.length) + fileName; + }, + + /** + * When ESLint is run from SublimeText, paths retrieved from + * context.getFileName contain leading and trailing double-quote characters. + * These characters need to be removed. + */ + cleanUpPath(pathName) { + return pathName.replace(/^"/, "").replace(/"$/, ""); + }, + + get globalScriptPaths() { + return [ + path.join(this.rootDir, "browser", "base", "content", "browser.xhtml"), + path.join( + this.rootDir, + "browser", + "base", + "content", + "global-scripts.inc" + ), + ]; + }, + + isMozillaCentralBased() { + return fs.existsSync(this.globalScriptPaths[0]); + }, + + getSavedEnvironmentItems(environment) { + return require("./environments/saved-globals.json").environments[ + environment + ]; + }, + + getSavedRuleData(rule) { + return require("./rules/saved-rules-data.json").rulesData[rule]; + }, + + getBuildEnvironment() { + var { execFileSync } = require("child_process"); + var output = execFileSync( + path.join(this.rootDir, "mach"), + ["environment", "--format=json"], + { silent: true } + ); + return JSON.parse(output); + }, + + /** + * Extract the path of require (and require-like) helpers used in DevTools. + */ + getDevToolsRequirePath(node) { + if ( + node.callee.type == "Identifier" && + node.callee.name == "require" && + node.arguments.length == 1 && + node.arguments[0].type == "Literal" + ) { + return node.arguments[0].value; + } else if ( + node.callee.type == "MemberExpression" && + node.callee.property.type == "Identifier" && + node.callee.property.name == "lazyRequireGetter" && + node.arguments.length >= 3 && + node.arguments[2].type == "Literal" + ) { + return node.arguments[2].value; + } + return null; + }, + + /** + * Returns property name from MemberExpression. Also accepts Identifier for consistency. + * @param {import("estree").MemberExpression | import("estree").Identifier} node + * @returns {string | null} + * + * @example `foo` gives "foo" + * @example `foo.bar` gives "bar" + * @example `foo.bar.baz` gives "baz" + */ + maybeGetMemberPropertyName(node) { + if (node.type === "MemberExpression") { + return node.property.name; + } + if (node.type === "Identifier") { + return node.name; + } + return null; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js new file mode 100644 index 0000000000..0801958597 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js @@ -0,0 +1,102 @@ +/** + * @fileoverview A collection of rules that help enforce JavaScript coding + * standard and avoid common errors in the Mozilla project. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Plugin Definition +// ------------------------------------------------------------------------------ +module.exports = { + configs: { + "browser-test": require("../lib/configs/browser-test"), + "chrome-test": require("../lib/configs/chrome-test"), + "mochitest-test": require("../lib/configs/mochitest-test"), + recommended: require("../lib/configs/recommended"), + "require-jsdoc": require("../lib/configs/require-jsdoc"), + "valid-jsdoc": require("../lib/configs/valid-jsdoc"), + "xpcshell-test": require("../lib/configs/xpcshell-test"), + }, + environments: { + "browser-window": require("../lib/environments/browser-window.js"), + "chrome-script": require("../lib/environments/chrome-script.js"), + "chrome-worker": require("../lib/environments/chrome-worker.js"), + "frame-script": require("../lib/environments/frame-script.js"), + jsm: require("../lib/environments/jsm.js"), + privileged: require("../lib/environments/privileged.js"), + "process-script": require("../lib/environments/process-script.js"), + "remote-page": require("../lib/environments/remote-page.js"), + simpletest: require("../lib/environments/simpletest.js"), + sjs: require("../lib/environments/sjs.js"), + "special-powers-sandbox": require("../lib/environments/special-powers-sandbox.js"), + specific: require("../lib/environments/specific"), + testharness: require("../lib/environments/testharness.js"), + xpcshell: require("../lib/environments/xpcshell.js"), + }, + rules: { + "avoid-Date-timing": require("../lib/rules/avoid-Date-timing"), + "avoid-removeChild": require("../lib/rules/avoid-removeChild"), + "balanced-listeners": require("../lib/rules/balanced-listeners"), + "balanced-observers": require("../lib/rules/balanced-observers"), + "consistent-if-bracing": require("../lib/rules/consistent-if-bracing"), + "import-browser-window-globals": require("../lib/rules/import-browser-window-globals"), + "import-content-task-globals": require("../lib/rules/import-content-task-globals"), + "import-globals": require("../lib/rules/import-globals"), + "import-headjs-globals": require("../lib/rules/import-headjs-globals"), + "lazy-getter-object-name": require("../lib/rules/lazy-getter-object-name"), + "mark-exported-symbols-as-used": require("../lib/rules/mark-exported-symbols-as-used"), + "mark-test-function-used": require("../lib/rules/mark-test-function-used"), + "no-aArgs": require("../lib/rules/no-aArgs"), + "no-addtask-setup": require("../lib/rules/no-addtask-setup"), + "no-arbitrary-setTimeout": require("../lib/rules/no-arbitrary-setTimeout"), + "no-browser-refs-in-toolkit": require("../lib/rules/no-browser-refs-in-toolkit"), + "no-compare-against-boolean-literals": require("../lib/rules/no-compare-against-boolean-literals"), + "no-comparison-or-assignment-inside-ok": require("../lib/rules/no-comparison-or-assignment-inside-ok"), + "no-cu-reportError": require("../lib/rules/no-cu-reportError"), + "no-define-cc-etc": require("../lib/rules/no-define-cc-etc"), + "no-redeclare-with-import-autofix": require("../lib/rules/no-redeclare-with-import-autofix"), + "no-throw-cr-literal": require("../lib/rules/no-throw-cr-literal"), + "no-useless-parameters": require("../lib/rules/no-useless-parameters"), + "no-useless-removeEventListener": require("../lib/rules/no-useless-removeEventListener"), + "no-useless-run-test": require("../lib/rules/no-useless-run-test"), + "prefer-boolean-length-check": require("../lib/rules/prefer-boolean-length-check"), + "prefer-formatValues": require("../lib/rules/prefer-formatValues"), + "reject-addtask-only": require("../lib/rules/reject-addtask-only"), + "reject-chromeutils-import": require("../lib/rules/reject-chromeutils-import"), + "reject-chromeutils-import-params": require("../lib/rules/reject-chromeutils-import-params"), + "reject-eager-module-in-lazy-getter": require("../lib/rules/reject-eager-module-in-lazy-getter"), + "reject-global-this": require("../lib/rules/reject-global-this"), + "reject-globalThis-modification": require("../lib/rules/reject-globalThis-modification"), + "reject-import-system-module-from-non-system": require("../lib/rules/reject-import-system-module-from-non-system"), + "reject-importGlobalProperties": require("../lib/rules/reject-importGlobalProperties"), + "reject-lazy-imports-into-globals": require("../lib/rules/reject-lazy-imports-into-globals"), + "reject-mixing-eager-and-lazy": require("../lib/rules/reject-mixing-eager-and-lazy"), + "reject-multiple-getters-calls": require("../lib/rules/reject-multiple-getters-calls"), + "reject-scriptableunicodeconverter": require("../lib/rules/reject-scriptableunicodeconverter"), + "reject-relative-requires": require("../lib/rules/reject-relative-requires"), + "reject-some-requires": require("../lib/rules/reject-some-requires"), + "reject-top-level-await": require("../lib/rules/reject-top-level-await"), + "rejects-requires-await": require("../lib/rules/rejects-requires-await"), + "use-cc-etc": require("../lib/rules/use-cc-etc"), + "use-chromeutils-definelazygetter": require("../lib/rules/use-chromeutils-definelazygetter"), + "use-chromeutils-generateqi": require("../lib/rules/use-chromeutils-generateqi"), + "use-chromeutils-import": require("../lib/rules/use-chromeutils-import"), + "use-console-createInstance": require("../lib/rules/use-console-createInstance"), + "use-default-preference-values": require("../lib/rules/use-default-preference-values"), + "use-ownerGlobal": require("../lib/rules/use-ownerGlobal"), + "use-includes-instead-of-indexOf": require("../lib/rules/use-includes-instead-of-indexOf"), + "use-isInstance": require("./rules/use-isInstance"), + "use-returnValue": require("../lib/rules/use-returnValue"), + "use-services": require("../lib/rules/use-services"), + "use-static-import": require("../lib/rules/use-static-import"), + "valid-ci-uses": require("../lib/rules/valid-ci-uses"), + "valid-lazy": require("../lib/rules/valid-lazy"), + "valid-services": require("../lib/rules/valid-services"), + "valid-services-property": require("../lib/rules/valid-services-property"), + "var-only-at-top-level": require("../lib/rules/var-only-at-top-level"), + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-Date-timing.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-Date-timing.js new file mode 100644 index 0000000000..437c53e244 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-Date-timing.js @@ -0,0 +1,61 @@ +/** + * @fileoverview Disallow using Date for timing in performance sensitive code + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/avoid-Date-timing.html", + }, + messages: { + usePerfNow: + "use performance.now() instead of Date.now() for timing measurements", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + CallExpression(node) { + let callee = node.callee; + if ( + callee.type !== "MemberExpression" || + callee.object.type !== "Identifier" || + callee.object.name !== "Date" || + callee.property.type !== "Identifier" || + callee.property.name !== "now" + ) { + return; + } + + context.report({ + node, + messageId: "usePerfNow", + }); + }, + + NewExpression(node) { + let callee = node.callee; + if ( + callee.type !== "Identifier" || + callee.name !== "Date" || + node.arguments.length + ) { + return; + } + + context.report({ + node, + messageId: "usePerfNow", + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-removeChild.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-removeChild.js new file mode 100644 index 0000000000..6c74d8aa59 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-removeChild.js @@ -0,0 +1,70 @@ +/** + * @fileoverview Reject using element.parentNode.removeChild(element) when + * element.remove() can be used instead. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var helpers = require("../helpers"); + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/avoid-removeChild.html", + }, + messages: { + useRemove: + "use element.remove() instead of element.parentNode.removeChild(element)", + useFirstChildRemove: + "use element.firstChild.remove() instead of element.removeChild(element.firstChild)", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + CallExpression(node) { + let callee = node.callee; + if ( + callee.type !== "MemberExpression" || + callee.property.type !== "Identifier" || + callee.property.name != "removeChild" || + node.arguments.length != 1 + ) { + return; + } + + if ( + callee.object.type == "MemberExpression" && + callee.object.property.type == "Identifier" && + callee.object.property.name == "parentNode" && + helpers.getASTSource(callee.object.object, context) == + helpers.getASTSource(node.arguments[0]) + ) { + context.report({ + node, + messageId: "useRemove", + }); + } + + if ( + node.arguments[0].type == "MemberExpression" && + node.arguments[0].property.type == "Identifier" && + node.arguments[0].property.name == "firstChild" && + helpers.getASTSource(callee.object, context) == + helpers.getASTSource(node.arguments[0].object) + ) { + context.report({ + node, + messageId: "useFirstChildRemove", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-listeners.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-listeners.js new file mode 100644 index 0000000000..f1c98a01bc --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-listeners.js @@ -0,0 +1,149 @@ +/** + * @fileoverview Check that there's a removeEventListener for each + * addEventListener and an off for each on. + * Note that for now, this rule is rather simple in that it only checks that + * for each event name there is both an add and remove listener. It doesn't + * check that these are called on the right objects or with the same callback. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/balanced-listeners.html", + }, + messages: { + noCorresponding: + "No corresponding '{{functionName}}({{type}})' was found.", + }, + schema: [], + type: "problem", + }, + + create(context) { + var DICTIONARY = { + addEventListener: "removeEventListener", + on: "off", + }; + // Invert this dictionary to make it easy later. + var INVERTED_DICTIONARY = {}; + for (var i in DICTIONARY) { + INVERTED_DICTIONARY[DICTIONARY[i]] = i; + } + + // Collect the add/remove listeners in these 2 arrays. + var addedListeners = []; + var removedListeners = []; + + function addAddedListener(node) { + var capture = false; + let options = node.arguments[2]; + if (options) { + if (options.type == "ObjectExpression") { + if ( + options.properties.some( + p => p.key.name == "once" && p.value.value === true + ) + ) { + // No point in adding listeners using the 'once' option. + return; + } + capture = options.properties.some( + p => p.key.name == "capture" && p.value.value === true + ); + } else { + capture = options.value; + } + } + addedListeners.push({ + functionName: node.callee.property.name, + type: node.arguments[0].value, + node: node.callee.property, + useCapture: capture, + }); + } + + function addRemovedListener(node) { + var capture = false; + let options = node.arguments[2]; + if (options) { + if (options.type == "ObjectExpression") { + capture = options.properties.some( + p => p.key.name == "capture" && p.value.value === true + ); + } else { + capture = options.value; + } + } + removedListeners.push({ + functionName: node.callee.property.name, + type: node.arguments[0].value, + useCapture: capture, + }); + } + + function getUnbalancedListeners() { + var unbalanced = []; + + for (var j = 0; j < addedListeners.length; j++) { + if (!hasRemovedListener(addedListeners[j])) { + unbalanced.push(addedListeners[j]); + } + } + addedListeners = removedListeners = []; + + return unbalanced; + } + + function hasRemovedListener(addedListener) { + for (var k = 0; k < removedListeners.length; k++) { + var listener = removedListeners[k]; + if ( + DICTIONARY[addedListener.functionName] === listener.functionName && + addedListener.type === listener.type && + addedListener.useCapture === listener.useCapture + ) { + return true; + } + } + + return false; + } + + return { + CallExpression(node) { + if (node.arguments.length === 0) { + return; + } + + if (node.callee.type === "MemberExpression") { + var listenerMethodName = node.callee.property.name; + + if (DICTIONARY.hasOwnProperty(listenerMethodName)) { + addAddedListener(node); + } else if (INVERTED_DICTIONARY.hasOwnProperty(listenerMethodName)) { + addRemovedListener(node); + } + } + }, + + "Program:exit": function () { + getUnbalancedListeners().forEach(function (listener) { + context.report({ + node: listener.node, + messageId: "noCorresponding", + data: { + functionName: DICTIONARY[listener.functionName], + type: listener.type, + }, + }); + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-observers.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-observers.js new file mode 100644 index 0000000000..854fbc9a63 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-observers.js @@ -0,0 +1,121 @@ +/** + * @fileoverview Check that there's a Services.(prefs|obs).removeObserver for + * each addObserver. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/balanced-observers.html", + }, + messages: { + noCorresponding: + "No corresponding 'removeObserver(\"{{observable}}\")' was found.", + }, + schema: [], + type: "problem", + }, + + create(context) { + var addedObservers = []; + var removedObservers = []; + + function getObserverAPI(node) { + const object = node.callee.object; + if ( + object.type == "MemberExpression" && + object.property.type == "Identifier" + ) { + return object.property.name; + } + return null; + } + + function isServicesObserver(api) { + return api == "obs" || api == "prefs"; + } + + function getObservableName(node, api) { + if (api === "obs") { + return node.arguments[1].value; + } + return node.arguments[0].value; + } + + function addAddedObserver(node) { + const api = getObserverAPI(node); + if (!isServicesObserver(api)) { + return; + } + + addedObservers.push({ + functionName: node.callee.property.name, + observable: getObservableName(node, api), + node: node.callee.property, + }); + } + + function addRemovedObserver(node) { + const api = getObserverAPI(node); + if (!isServicesObserver(api)) { + return; + } + + removedObservers.push({ + functionName: node.callee.property.name, + observable: getObservableName(node, api), + }); + } + + function getUnbalancedObservers() { + const unbalanced = addedObservers.filter( + observer => !hasRemovedObserver(observer) + ); + addedObservers = removedObservers = []; + + return unbalanced; + } + + function hasRemovedObserver(addedObserver) { + return removedObservers.some( + observer => addedObserver.observable === observer.observable + ); + } + + return { + CallExpression(node) { + if (node.arguments.length === 0) { + return; + } + + if (node.callee.type === "MemberExpression") { + var methodName = node.callee.property.name; + + if (methodName === "addObserver") { + addAddedObserver(node); + } else if (methodName === "removeObserver") { + addRemovedObserver(node); + } + } + }, + + "Program:exit": function () { + getUnbalancedObservers().forEach(function (observer) { + context.report({ + node: observer.node, + messageId: "noCorresponding", + data: { + observable: observer.observable, + }, + }); + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/consistent-if-bracing.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/consistent-if-bracing.js new file mode 100644 index 0000000000..0c9c9a342f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/consistent-if-bracing.js @@ -0,0 +1,54 @@ +/** + * @fileoverview checks if/else if/else bracing is consistent + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/consistent-if-bracing.html", + }, + messages: { + consistentIfBracing: "Bracing of if..else bodies should be consistent.", + }, + schema: [], + type: "layout", + }, + + create(context) { + return { + IfStatement(node) { + if (node.parent.type !== "IfStatement") { + let types = new Set(); + for ( + let currentNode = node; + currentNode; + currentNode = currentNode.alternate + ) { + let type = currentNode.consequent.type; + types.add(type == "BlockStatement" ? "Block" : "NotBlock"); + if ( + currentNode.alternate && + currentNode.alternate.type !== "IfStatement" + ) { + type = currentNode.alternate.type; + types.add(type == "BlockStatement" ? "Block" : "NotBlock"); + break; + } + } + if (types.size > 1) { + context.report({ + node, + messageId: "consistentIfBracing", + }); + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browser-window-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browser-window-globals.js new file mode 100644 index 0000000000..7a099ba340 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browser-window-globals.js @@ -0,0 +1,50 @@ +/** + * @fileoverview For scripts included in browser-window, this will automatically + * inject the browser-window global scopes into the file. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var path = require("path"); +var helpers = require("../helpers"); +var browserWindowEnv = require("../environments/browser-window"); + +module.exports = { + // This rule currently has no messages. + // eslint-disable-next-line eslint-plugin/prefer-message-ids + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/import-browser-window-globals.html", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + Program(node) { + let filePath = helpers.getAbsoluteFilePath(context); + let relativePath = path.relative(helpers.rootDir, filePath); + // We need to translate the path on Windows, due to the change + // from \ to /, and browserjsScripts assumes Posix. + if (path.win32) { + relativePath = relativePath.split(path.sep).join("/"); + } + + if (browserWindowEnv.browserjsScripts?.includes(relativePath)) { + for (let global in browserWindowEnv.globals) { + helpers.addVarToScope( + global, + context.getScope(), + browserWindowEnv.globals[global] + ); + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-content-task-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-content-task-globals.js new file mode 100644 index 0000000000..e2b66ce8b0 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-content-task-globals.js @@ -0,0 +1,73 @@ +/** + * @fileoverview For ContentTask.spawn, this will automatically declare the + * frame script variables in the global scope. + * Note: due to the way ESLint works, it appears it is only + * easy to declare these variables on a file-global scope, rather + * than function global. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var helpers = require("../helpers"); +var frameScriptEnv = require("../environments/frame-script"); +var sandboxEnv = require("../environments/special-powers-sandbox"); + +module.exports = { + // eslint-disable-next-line eslint-plugin/prefer-message-ids + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/import-content-task-globals.html", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + "CallExpression[callee.object.name='ContentTask'][callee.property.name='spawn']": + function (node) { + // testing/mochitest/BrowserTestUtils/content/content-task.js + // This script is loaded as a sub script into a frame script. + for (let [name, value] of Object.entries(frameScriptEnv.globals)) { + helpers.addVarToScope(name, context.getScope(), value); + } + }, + "CallExpression[callee.object.name='SpecialPowers'][callee.property.name='spawn']": + function (node) { + for (let [name, value] of Object.entries(sandboxEnv.globals)) { + helpers.addVarToScope(name, context.getScope(), value); + } + let globals = [ + // testing/specialpowers/content/SpecialPowersChild.sys.mjs + // SpecialPowersChild._spawnTask + "SpecialPowers", + "ContentTaskUtils", + "content", + "docShell", + ]; + for (let global of globals) { + helpers.addVarToScope(global, context.getScope(), false); + } + }, + "CallExpression[callee.object.name='SpecialPowers'][callee.property.name='spawnChrome']": + function (node) { + for (let [name, value] of Object.entries(sandboxEnv.globals)) { + helpers.addVarToScope(name, context.getScope(), value); + } + let globals = [ + // testing/specialpowers/content/SpecialPowersParent.sys.mjs + // SpecialPowersParent._spawnChrome + "windowGlobalParent", + "browsingContext", + ]; + for (let global of globals) { + helpers.addVarToScope(global, context.getScope(), false); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-globals.js new file mode 100644 index 0000000000..abbab511ff --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-globals.js @@ -0,0 +1,21 @@ +/** + * @fileoverview Discovers all globals for the current file. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/import-globals.html", + }, + schema: [], + type: "problem", + }, + + create: require("../globals").getESLintGlobalParser, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-headjs-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-headjs-globals.js new file mode 100644 index 0000000000..d4fa484b99 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-headjs-globals.js @@ -0,0 +1,51 @@ +/** + * @fileoverview Import globals from head.js and from any files that were + * imported by head.js (as far as we can correctly resolve the path). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var fs = require("fs"); +var helpers = require("../helpers"); +var globals = require("../globals"); + +function importHead(context, path, node) { + try { + let stats = fs.statSync(path); + if (!stats.isFile()) { + return; + } + } catch (e) { + return; + } + + let newGlobals = globals.getGlobalsForFile(path); + helpers.addGlobals(newGlobals, context.getScope()); +} + +module.exports = { + // This rule currently has no messages. + // eslint-disable-next-line eslint-plugin/prefer-message-ids + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/import-headjs-globals.html", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + Program(node) { + let heads = helpers.getTestHeadFiles(context); + for (let head of heads) { + importHead(context, head, node); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/lazy-getter-object-name.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/lazy-getter-object-name.js new file mode 100644 index 0000000000..b18cbc3725 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/lazy-getter-object-name.js @@ -0,0 +1,48 @@ +/** + * @fileoverview Enforce the standard object name for + * ChromeUtils.defineESModuleGetters + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isIdentifier(node, id) { + return node.type === "Identifier" && node.name === id; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/lazy-getter-object-name.html", + }, + messages: { + mustUseLazy: + "The variable name of the object passed to ChromeUtils.defineESModuleGetters must be `lazy`", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + CallExpression(node) { + let { callee } = node; + if ( + callee.type === "MemberExpression" && + isIdentifier(callee.object, "ChromeUtils") && + isIdentifier(callee.property, "defineESModuleGetters") && + node.arguments.length >= 1 && + !isIdentifier(node.arguments[0], "lazy") + ) { + context.report({ + node, + messageId: "mustUseLazy", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-exported-symbols-as-used.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-exported-symbols-as-used.js new file mode 100644 index 0000000000..5d0e57e4c8 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-exported-symbols-as-used.js @@ -0,0 +1,90 @@ +/** + * @fileoverview Simply marks exported symbols as used. Designed for use in + * .jsm files only. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function markArrayElementsAsUsed(context, node, expression) { + if (expression.type != "ArrayExpression") { + context.report({ + node, + messageId: "nonArrayAssignedToImported", + }); + return; + } + + for (let element of expression.elements) { + context.markVariableAsUsed(element.value); + } + // Also mark EXPORTED_SYMBOLS as used. + context.markVariableAsUsed("EXPORTED_SYMBOLS"); +} + +// Ignore assignments not in the global scope, e.g. where special module +// definitions are required due to having different ways of importing files, +// e.g. osfile. +function isGlobalScope(context) { + return !context.getScope().upper; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/mark-exported-symbols-as-used.html", + }, + messages: { + useLetForExported: + "EXPORTED_SYMBOLS cannot be declared via `let`. Use `var` or `this.EXPORTED_SYMBOLS =`", + nonArrayAssignedToImported: + "Unexpected assignment of non-Array to EXPORTED_SYMBOLS", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + AssignmentExpression(node, parents) { + if ( + node.operator === "=" && + node.left.type === "MemberExpression" && + node.left.object.type === "ThisExpression" && + node.left.property.name === "EXPORTED_SYMBOLS" && + isGlobalScope(context) + ) { + markArrayElementsAsUsed(context, node, node.right); + } + }, + + VariableDeclaration(node, parents) { + if (!isGlobalScope(context)) { + return; + } + + for (let item of node.declarations) { + if ( + item.id && + item.id.type == "Identifier" && + item.id.name === "EXPORTED_SYMBOLS" + ) { + if (node.kind === "let") { + // The use of 'let' isn't allowed as the lexical scope may die after + // the script executes. + context.report({ + node, + messageId: "useLetForExported", + }); + } + + markArrayElementsAsUsed(context, node, item.init); + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-test-function-used.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-test-function-used.js new file mode 100644 index 0000000000..4afe8a70ac --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-test-function-used.js @@ -0,0 +1,44 @@ +/** + * @fileoverview Simply marks `test` (the test method) or `run_test` as used + * when in mochitests or xpcshell tests respectively. This avoids ESLint telling + * us that the function is never called. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var helpers = require("../helpers"); + +module.exports = { + // This rule currently has no messages. + // eslint-disable-next-line eslint-plugin/prefer-message-ids + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/mark-test-function-used.html", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + Program() { + let testType = helpers.getTestType(context); + if (testType == "browser") { + context.markVariableAsUsed("test"); + } + + if (testType == "xpcshell") { + context.markVariableAsUsed("run_test"); + } + + if (helpers.getIsSjs(context)) { + context.markVariableAsUsed("handleRequest"); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-aArgs.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-aArgs.js new file mode 100644 index 0000000000..7135890761 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-aArgs.js @@ -0,0 +1,57 @@ +/** + * @fileoverview warns against using hungarian notation in function arguments + * (i.e. aArg). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isPrefixed(name) { + return name.length >= 2 && /^a[A-Z]/.test(name); +} + +function deHungarianize(name) { + return name.substring(1, 2).toLowerCase() + name.substring(2, name.length); +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-aArgs.html", + }, + messages: { + dontUseHungarian: + "Parameter '{{name}}' uses Hungarian Notation, consider using '{{suggestion}}' instead.", + }, + schema: [], + type: "layout", + }, + + create(context) { + function checkFunction(node) { + for (var i = 0; i < node.params.length; i++) { + var param = node.params[i]; + if (param.name && isPrefixed(param.name)) { + var errorObj = { + name: param.name, + suggestion: deHungarianize(param.name), + }; + context.report({ + node: param, + messageId: "dontUseHungarian", + data: errorObj, + }); + } + } + } + + return { + FunctionDeclaration: checkFunction, + ArrowFunctionExpression: checkFunction, + FunctionExpression: checkFunction, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-addtask-setup.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-addtask-setup.js new file mode 100644 index 0000000000..e711252e09 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-addtask-setup.js @@ -0,0 +1,57 @@ +/** + * @fileoverview Reject `add_task(async function setup` or similar patterns in + * favour of add_setup. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isNamedLikeSetup(name) { + return /^(init|setup)$/i.test(name); +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-addtask-setup.html", + }, + fixable: "code", + messages: { + useAddSetup: "Do not use add_task() for setup, use add_setup() instead.", + }, + schema: [], + type: "suggestion", + }, + create(context) { + return { + "Program > ExpressionStatement > CallExpression": function (node) { + let callee = node.callee; + if (callee.type === "Identifier" && callee.name === "add_task") { + let arg = node.arguments[0]; + if ( + arg.type !== "FunctionExpression" || + !arg.id || + !isNamedLikeSetup(arg.id.name) + ) { + return; + } + context.report({ + node, + messageId: "useAddSetup", + fix: fixer => { + let range = [node.callee.range[0], arg.id.range[1]]; + let asyncOrNot = arg.async ? "async " : ""; + return fixer.replaceTextRange( + range, + `add_setup(${asyncOrNot}function` + ); + }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-arbitrary-setTimeout.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-arbitrary-setTimeout.js new file mode 100644 index 0000000000..d0e891292d --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-arbitrary-setTimeout.js @@ -0,0 +1,65 @@ +/** + * @fileoverview Reject use of non-zero values in setTimeout + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var helpers = require("../helpers"); +var testTypes = new Set(["browser", "xpcshell"]); + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-arbitrary-setTimeout.html", + }, + messages: { + listenForEvents: + "listen for events instead of setTimeout() with arbitrary delay", + }, + schema: [], + type: "problem", + }, + + create(context) { + // We don't want to run this on mochitest plain as it already + // prevents flaky setTimeout at runtime. This check is built-in + // to the rule itself as sometimes other tests can live alongside + // plain mochitests and so it can't be configured via eslintrc. + if (!testTypes.has(helpers.getTestType(context))) { + return {}; + } + + return { + CallExpression(node) { + let callee = node.callee; + if (callee.type === "MemberExpression") { + if ( + callee.property.name !== "setTimeout" || + callee.object.name !== "window" || + node.arguments.length < 2 + ) { + return; + } + } else if (callee.type === "Identifier") { + if (callee.name !== "setTimeout" || node.arguments.length < 2) { + return; + } + } else { + return; + } + + let timeout = node.arguments[1]; + if (timeout.type !== "Literal" || timeout.value > 0) { + context.report({ + node, + messageId: "listenForEvents", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-browser-refs-in-toolkit.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-browser-refs-in-toolkit.js new file mode 100644 index 0000000000..fea94d364e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-browser-refs-in-toolkit.js @@ -0,0 +1,48 @@ +/** + * @fileoverview Reject use of browser/-based references from code in + * directories like toolkit/ that ought not to depend on + * running inside desktop Firefox. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-browser-refs-in-toolkit.html", + }, + messages: { + noBrowserChrome: + "> {{url}} is part of Desktop Firefox and cannot be unconditionally " + + "used by this code (which has to also work elsewhere).", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + Literal(node) { + if (typeof node.value != "string") { + return; + } + if ( + node.value.startsWith("chrome://browser") || + node.value.startsWith("resource:///") || + node.value.startsWith("resource://app/") || + (node.value.startsWith("browser/") && node.value.endsWith(".ftl")) + ) { + context.report({ + node, + messageId: "noBrowserChrome", + data: { url: node.value }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-compare-against-boolean-literals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-compare-against-boolean-literals.js new file mode 100644 index 0000000000..cf52b2ad21 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-compare-against-boolean-literals.js @@ -0,0 +1,40 @@ +/** + * @fileoverview Restrict comparing against `true` or `false`. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-compare-against-boolean-literals.html", + }, + messages: { + noCompareBoolean: + "Don't compare for inexact equality against boolean literals", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + BinaryExpression(node) { + if ( + ["==", "!="].includes(node.operator) && + (["true", "false"].includes(node.left.raw) || + ["true", "false"].includes(node.right.raw)) + ) { + context.report({ + node, + messageId: "noCompareBoolean", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-comparison-or-assignment-inside-ok.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-comparison-or-assignment-inside-ok.js new file mode 100644 index 0000000000..9bab06b000 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-comparison-or-assignment-inside-ok.js @@ -0,0 +1,80 @@ +/** + * @fileoverview Don't allow accidental assignments inside `ok()`, + * and encourage people to use appropriate alternatives + * when using comparisons between 2 values. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const operatorToAssertionMap = { + "==": "Assert.equal", + "===": "Assert.strictEqual", + "!=": "Assert.notEqual", + "!==": "Assert.notStrictEqual", + ">": "Assert.greater", + "<": "Assert.less", + "<=": "Assert.lessOrEqual", + ">=": "Assert.greaterOrEqual", +}; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-comparison-or-assignment-inside-ok.html", + }, + fixable: "code", + messages: { + assignment: + "Assigning to a variable inside ok() is odd - did you mean to compare the two?", + comparison: + "Use dedicated assertion methods rather than ok(a {{operator}} b).", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + const exprs = new Set(["BinaryExpression", "AssignmentExpression"]); + return { + CallExpression(node) { + if (node.callee.type != "Identifier" || node.callee.name != "ok") { + return; + } + let firstArg = node.arguments[0]; + if (!exprs.has(firstArg.type)) { + return; + } + if (firstArg.type == "AssignmentExpression") { + context.report({ + node: firstArg, + messageId: "assignment", + }); + } else if ( + firstArg.type == "BinaryExpression" && + operatorToAssertionMap.hasOwnProperty(firstArg.operator) + ) { + context.report({ + node, + messageId: "comparison", + data: { operator: firstArg.operator }, + fix: fixer => { + let left = context.sourceCode.getText(firstArg.left); + let right = context.sourceCode.getText(firstArg.right); + return [ + fixer.replaceText(firstArg, left + ", " + right), + fixer.replaceText( + node.callee, + operatorToAssertionMap[firstArg.operator] + ), + ]; + }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-cu-reportError.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-cu-reportError.js new file mode 100644 index 0000000000..85daa8823e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-cu-reportError.js @@ -0,0 +1,130 @@ +/** + * @fileoverview Reject common XPCOM methods called with useless optional + * parameters, or non-existent parameters. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isCuReportError(node) { + return ( + node.type == "MemberExpression" && + node.object.type == "Identifier" && + node.object.name == "Cu" && + node.property.type == "Identifier" && + node.property.name == "reportError" + ); +} + +function isConcatenation(node) { + return node.type == "BinaryExpression" && node.operator == "+"; +} + +function isIdentOrMember(node) { + return node.type == "MemberExpression" || node.type == "Identifier"; +} + +function isLiteralOrConcat(node) { + return node.type == "Literal" || isConcatenation(node); +} + +function replaceConcatWithComma(fixer, node) { + let fixes = []; + let didFixTrailingIdentifier = false; + let recursiveFixes; + let trailingIdentifier; + // Deal with recursion first: + if (isConcatenation(node.right)) { + // Uh oh. If the RHS is a concatenation, there are parens involved, + // e.g.: + // console.error("literal" + (b + "literal")); + // It's pretty much impossible to guess what to do here so bail out: + return { fixes: [], trailingIdentifier: false }; + } + if (isConcatenation(node.left)) { + ({ fixes: recursiveFixes, trailingIdentifier } = replaceConcatWithComma( + fixer, + node.left + )); + fixes.push(...recursiveFixes); + } + // If the left is an identifier or memberexpression, and the right is a + // literal or concatenation - or vice versa - replace a + with a comma: + if ( + (isIdentOrMember(node.left) && isLiteralOrConcat(node.right)) || + (isIdentOrMember(node.right) && isLiteralOrConcat(node.left)) || + // Or if the rhs is a literal/concatenation, while the right-most part of + // the lhs is also an identifier (need 2 commas either side!) + (trailingIdentifier && isLiteralOrConcat(node.right)) + ) { + fixes.push( + fixer.replaceTextRange([node.left.range[1], node.right.range[0]], ", ") + ); + didFixTrailingIdentifier = isIdentOrMember(node.right); + } + return { fixes, trailingIdentifier: didFixTrailingIdentifier }; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-cu-reportError.html", + }, + fixable: "code", + messages: { + useConsoleError: "Please use console.error instead of Cu.reportError", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + CallExpression(node) { + let checkNodes = []; + if (isCuReportError(node.callee)) { + // Handles cases of `Cu.reportError()`. + if (node.arguments.length > 1) { + // TODO: Bug 1802347 For initial landing, we allow the two + // argument form of Cu.reportError as the second argument is a stack + // argument which is more complicated to deal with. + return; + } + checkNodes = [node.callee]; + } else if (node.arguments.length >= 1) { + // Handles cases of `.foo(Cu.reportError)`. + checkNodes = node.arguments.filter(n => isCuReportError(n)); + } + + for (let checkNode of checkNodes) { + context.report({ + node, + fix: fixer => { + let fixes = [ + fixer.replaceText(checkNode.object, "console"), + fixer.replaceText(checkNode.property, "error"), + ]; + // If we're adding stuff together as an argument, split + // into multiple arguments instead: + if ( + checkNode == node.callee && + isConcatenation(node.arguments[0]) + ) { + let { fixes: recursiveFixes } = replaceConcatWithComma( + fixer, + node.arguments[0] + ); + fixes.push(...recursiveFixes); + } + return fixes; + }, + messageId: "useConsoleError", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-define-cc-etc.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-define-cc-etc.js new file mode 100644 index 0000000000..05e7648632 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-define-cc-etc.js @@ -0,0 +1,57 @@ +/** + * @fileoverview Reject defining Cc/Ci/Cr/Cu. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const componentsBlacklist = ["Cc", "Ci", "Cr", "Cu"]; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-define-cc-etc.html", + }, + messages: { + noSeparateDefinition: + "{{name}} is now defined in global scope, a separate definition is no longer necessary.", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + VariableDeclarator(node) { + if ( + node.id.type == "Identifier" && + componentsBlacklist.includes(node.id.name) + ) { + context.report({ + node, + messageId: "noSeparateDefinition", + data: { name: node.id.name }, + }); + } + + if (node.id.type == "ObjectPattern") { + for (let property of node.id.properties) { + if ( + property.type == "Property" && + componentsBlacklist.includes(property.value.name) + ) { + context.report({ + node, + messageId: "noSeparateDefinition", + data: { name: property.value.name }, + }); + } + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-redeclare-with-import-autofix.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-redeclare-with-import-autofix.js new file mode 100644 index 0000000000..d914e003d3 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-redeclare-with-import-autofix.js @@ -0,0 +1,160 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const { dirname, join } = require("path"); + +const eslintBasePath = dirname(require.resolve("eslint")); + +const noredeclarePath = join(eslintBasePath, "rules/no-redeclare.js"); +const baseRule = require(noredeclarePath); +const astUtils = require(join(eslintBasePath, "rules/utils/ast-utils.js")); + +// Hack alert: our eslint env is pretty confused about `require` and +// `loader` for devtools modules - so ignore it for now. +// See bug 1812547 +const gIgnoredImports = new Set(["loader", "require"]); + +/** + * Create a trap for a call to `report` that the original rule is + * trying to make on `context`. + * + * Returns a function that forwards to `report` but provides a fixer + * for redeclared imports that just removes those imports. + * + * @return {function} + */ +function trapReport(context) { + return function (obj) { + let declarator = obj.node.parent; + while ( + declarator && + declarator.parent && + declarator.type != "VariableDeclarator" + ) { + declarator = declarator.parent; + } + if ( + declarator && + declarator.type == "VariableDeclarator" && + declarator.id.type == "ObjectPattern" && + declarator.init.type == "CallExpression" + ) { + let initialization = declarator.init; + if ( + astUtils.isSpecificMemberAccess( + initialization.callee, + "ChromeUtils", + /^import(ESModule|)$/ + ) + ) { + // Hack alert: our eslint env is pretty confused about `require` and + // `loader` for devtools modules - so ignore it for now. + // See bug 1812547 + if (gIgnoredImports.has(obj.node.name)) { + return; + } + // OK, we've got something we can fix. But we should be careful in case + // there are multiple imports being destructured. + // Do the easy (and common) case first - just one property: + if (declarator.id.properties.length == 1) { + context.report({ + node: declarator.parent, + messageId: "duplicateImport", + data: { + name: declarator.id.properties[0].key.name, + }, + fix(fixer) { + return fixer.remove(declarator.parent); + }, + }); + return; + } + + // OK, figure out which import is duplicated here: + let node = obj.node.parent; + // Then remove a comma after it, or a comma before + // if there's no comma after it. + let sourceCode = context.getSourceCode(); + let rangeToRemove = node.range; + let tokenAfter = sourceCode.getTokenAfter(node); + let tokenBefore = sourceCode.getTokenBefore(node); + if (astUtils.isCommaToken(tokenAfter)) { + rangeToRemove[1] = tokenAfter.range[1]; + } else if (astUtils.isCommaToken(tokenBefore)) { + rangeToRemove[0] = tokenBefore.range[0]; + } + context.report({ + node, + messageId: "duplicateImport", + data: { + name: node.key.name, + }, + fix(fixer) { + return fixer.removeRange(rangeToRemove); + }, + }); + return; + } + } + if (context.options[0]?.errorForNonImports) { + // Report the result from no-redeclare - we can't autofix it. + // This can happen for other redeclaration issues, e.g. naming + // variables in a way that conflicts with builtins like "URL" or + // "escape". + context.report(obj); + } + }; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-redeclare-with-import-autofix.html", + }, + messages: { + ...baseRule.meta.messages, + duplicateImport: + "The import of '{{ name }}' is redundant with one set up earlier (e.g. head.js or the browser window environment). It should be removed.", + }, + schema: [ + { + type: "object", + properties: { + errorForNonImports: { + type: "boolean", + default: true, + }, + }, + additionalProperties: false, + }, + ], + type: "suggestion", + fixable: "code", + }, + + create(context) { + // Test modules get the browser env applied wrongly in some cases, + // don't try and remove imports there. This works out of the box + // for sys.mjs modules because eslint won't check builtinGlobals + // for the no-redeclare rule. + if (context.getFilename().endsWith(".jsm")) { + return {}; + } + let newOptions = [{ builtinGlobals: true }]; + const contextForBaseRule = Object.create(context, { + report: { + value: trapReport(context), + writable: false, + }, + options: { + value: newOptions, + }, + }); + return baseRule.create(contextForBaseRule); + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-throw-cr-literal.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-throw-cr-literal.js new file mode 100644 index 0000000000..5ff6bfd7c9 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-throw-cr-literal.js @@ -0,0 +1,101 @@ +/** + * @fileoverview Rule to prevent throwing bare Cr.ERRORs. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isCr(object) { + return object.type === "Identifier" && object.name === "Cr"; +} + +function isComponentsResults(object) { + return ( + object.type === "MemberExpression" && + object.object.type === "Identifier" && + object.object.name === "Components" && + object.property.type === "Identifier" && + object.property.name === "results" + ); +} + +function isNewError(argument) { + return ( + argument.type === "NewExpression" && + argument.callee.type === "Identifier" && + argument.callee.name === "Error" && + argument.arguments.length === 1 + ); +} + +function fixT(context, node, argument, fixer) { + const sourceText = context.getSourceCode().getText(argument); + return fixer.replaceText(node, `Components.Exception("", ${sourceText})`); +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-throw-cr-literal.html", + }, + fixable: "code", + messages: { + bareCR: "Do not throw bare Cr.ERRORs, use Components.Exception instead", + bareComponentsResults: + "Do not throw bare Components.results.ERRORs, use Components.Exception instead", + newErrorCR: + "Do not pass Cr.ERRORs to new Error(), use Components.Exception instead", + newErrorComponentsResults: + "Do not pass Components.results.ERRORs to new Error(), use Components.Exception instead", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + ThrowStatement(node) { + if (node.argument.type === "MemberExpression") { + const fix = fixT.bind(null, context, node.argument, node.argument); + + if (isCr(node.argument.object)) { + context.report({ + node, + messageId: "bareCR", + fix, + }); + } else if (isComponentsResults(node.argument.object)) { + context.report({ + node, + messageId: "bareComponentsResults", + fix, + }); + } + } else if (isNewError(node.argument)) { + const argument = node.argument.arguments[0]; + + if (argument.type === "MemberExpression") { + const fix = fixT.bind(null, context, node.argument, argument); + + if (isCr(argument.object)) { + context.report({ + node, + messageId: "newErrorCR", + fix, + }); + } else if (isComponentsResults(argument.object)) { + context.report({ + node, + messageId: "newErrorComponentsResults", + fix, + }); + } + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-parameters.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-parameters.js new file mode 100644 index 0000000000..ac1cc334e6 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-parameters.js @@ -0,0 +1,156 @@ +/** + * @fileoverview Reject common XPCOM methods called with useless optional + * parameters, or non-existent parameters. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-useless-parameters.html", + }, + fixable: "code", + messages: { + newURIParams: "newURI's last parameters are optional.", + obmittedWhenFalse: + "{{fnName}}'s {{index}} parameter can be omitted when it's false.", + onlyTakes: "{{fnName}} only takes {{params}}", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + function getRangeAfterArgToEnd(argNumber, args) { + let sourceCode = context.getSourceCode(); + return [ + sourceCode.getTokenAfter(args[argNumber]).range[0], + args[args.length - 1].range[1], + ]; + } + + return { + CallExpression(node) { + let callee = node.callee; + if ( + callee.type !== "MemberExpression" || + callee.property.type !== "Identifier" + ) { + return; + } + + let isFalse = arg => arg.type === "Literal" && arg.value === false; + let isFalsy = arg => arg.type === "Literal" && !arg.value; + let isBool = arg => + arg.type === "Literal" && (arg.value === false || arg.value === true); + let name = callee.property.name; + let args = node.arguments; + + if ( + ["addEventListener", "removeEventListener", "addObserver"].includes( + name + ) && + args.length === 3 && + isFalse(args[2]) + ) { + context.report({ + node, + fix: fixer => { + return fixer.removeRange(getRangeAfterArgToEnd(1, args)); + }, + messageId: "obmittedWhenFalse", + data: { fnName: name, index: "third" }, + }); + } + + if (name === "clearUserPref" && args.length > 1) { + context.report({ + node, + fix: fixer => { + return fixer.removeRange(getRangeAfterArgToEnd(0, args)); + }, + messageId: "onlyTakes", + data: { fnName: name, params: "1 parameter" }, + }); + } + + if (name === "removeObserver" && args.length === 3 && isBool(args[2])) { + context.report({ + node, + fix: fixer => { + return fixer.removeRange(getRangeAfterArgToEnd(1, args)); + }, + messageId: "onlyTakes", + data: { fnName: name, params: "2 parameters" }, + }); + } + + if (name === "appendElement" && args.length === 2 && isFalse(args[1])) { + context.report({ + node, + fix: fixer => { + return fixer.removeRange(getRangeAfterArgToEnd(0, args)); + }, + messageId: "obmittedWhenFalse", + data: { fnName: name, index: "second" }, + }); + } + + if ( + name === "notifyObservers" && + args.length === 3 && + isFalsy(args[2]) + ) { + context.report({ + node, + fix: fixer => { + return fixer.removeRange(getRangeAfterArgToEnd(1, args)); + }, + messageId: "obmittedWhenFalse", + data: { fnName: name, index: "third" }, + }); + } + + if ( + name === "getComputedStyle" && + args.length === 2 && + isFalsy(args[1]) + ) { + context.report({ + node, + fix: fixer => { + return fixer.removeRange(getRangeAfterArgToEnd(0, args)); + }, + messageId: "obmittedWhenFalse", + data: { fnName: "getComputedStyle", index: "second" }, + }); + } + + if ( + name === "newURI" && + args.length > 1 && + isFalsy(args[args.length - 1]) + ) { + context.report({ + node, + fix: fixer => { + if (args.length > 2 && isFalsy(args[args.length - 2])) { + return fixer.removeRange(getRangeAfterArgToEnd(0, args)); + } + + return fixer.removeRange( + getRangeAfterArgToEnd(args.length - 2, args) + ); + }, + messageId: "newURIParams", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-removeEventListener.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-removeEventListener.js new file mode 100644 index 0000000000..d5f19ab717 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-removeEventListener.js @@ -0,0 +1,69 @@ +/** + * @fileoverview Reject calls to removeEventListenter where {once: true} could + * be used instead. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-useless-removeEventListener.html", + }, + messages: { + useOnce: + "use {once: true} instead of removeEventListener as the first instruction of the listener", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + CallExpression(node) { + let callee = node.callee; + if ( + callee.type !== "MemberExpression" || + callee.property.type !== "Identifier" || + callee.property.name !== "addEventListener" || + node.arguments.length == 4 + ) { + return; + } + + let listener = node.arguments[1]; + if ( + !listener || + listener.type != "FunctionExpression" || + !listener.body || + listener.body.type != "BlockStatement" || + !listener.body.body.length || + listener.body.body[0].type != "ExpressionStatement" || + listener.body.body[0].expression.type != "CallExpression" + ) { + return; + } + + let call = listener.body.body[0].expression; + if ( + call.callee.type == "MemberExpression" && + call.callee.property.type == "Identifier" && + call.callee.property.name == "removeEventListener" && + ((call.arguments[0].type == "Literal" && + call.arguments[0].value == node.arguments[0].value) || + (call.arguments[0].type == "Identifier" && + call.arguments[0].name == node.arguments[0].name)) + ) { + context.report({ + node: call, + messageId: "useOnce", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-run-test.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-run-test.js new file mode 100644 index 0000000000..ddfbea05e3 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-run-test.js @@ -0,0 +1,76 @@ +/** + * @fileoverview Reject run_test() definitions where they aren't necessary. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/no-useless-run-test.html", + }, + fixable: "code", + messages: { + noUselessRunTest: + "Useless run_test function - only contains run_next_test; whole function can be removed", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + "Program > FunctionDeclaration": function (node) { + if ( + node.id.name === "run_test" && + node.body.type === "BlockStatement" && + node.body.body.length === 1 && + node.body.body[0].type === "ExpressionStatement" && + node.body.body[0].expression.type === "CallExpression" && + node.body.body[0].expression.callee.name === "run_next_test" + ) { + context.report({ + node, + fix: fixer => { + let sourceCode = context.getSourceCode(); + let startNode; + if (sourceCode.getCommentsBefore) { + // ESLint 4 has getCommentsBefore. + startNode = sourceCode.getCommentsBefore(node); + } else if (node && node.body && node.leadingComments) { + // This is for ESLint 3. + startNode = node.leadingComments; + } + + // If we have comments, we want the start node to be the comments, + // rather than the token before the comments, so that we don't + // remove the comments - for run_test, these are likely to be useful + // information about the test. + if (startNode?.length) { + startNode = startNode[startNode.length - 1]; + } else { + startNode = sourceCode.getTokenBefore(node); + } + + return fixer.removeRange([ + // If there's no startNode, we fall back to zero, i.e. start of + // file. + startNode ? startNode.range[1] + 1 : 0, + // We know the function is a block and it'll end with }. Normally + // there's a new line after that, so just advance past it. This + // may be slightly not dodgy in some cases, but covers the existing + // cases. + node.range[1] + 1, + ]); + }, + messageId: "noUselessRunTest", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/prefer-boolean-length-check.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/prefer-boolean-length-check.js new file mode 100644 index 0000000000..41c0aa1d30 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/prefer-boolean-length-check.js @@ -0,0 +1,129 @@ +/** + * @fileoverview Prefer boolean length check + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function funcForBooleanLength(context, node, conditionCheck) { + let newText = ""; + const sourceCode = context.getSourceCode(); + switch (node.operator) { + case ">": + if (node.right.value == 0) { + if (conditionCheck) { + newText = sourceCode.getText(node.left); + } else { + newText = "!!" + sourceCode.getText(node.left); + } + } else { + newText = "!" + sourceCode.getText(node.right); + } + break; + case "<": + if (node.right.value == 0) { + newText = "!" + sourceCode.getText(node.left); + } else if (conditionCheck) { + newText = sourceCode.getText(node.right); + } else { + newText = "!!" + sourceCode.getText(node.right); + } + break; + case "==": + if (node.right.value == 0) { + newText = "!" + sourceCode.getText(node.left); + } else { + newText = "!" + sourceCode.getText(node.right); + } + break; + case "!=": + if (node.right.value == 0) { + if (conditionCheck) { + newText = sourceCode.getText(node.left); + } else { + newText = "!!" + sourceCode.getText(node.left); + } + } else if (conditionCheck) { + newText = sourceCode.getText(node.right); + } else { + newText = "!!" + sourceCode.getText(node.right); + } + break; + } + return newText; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/prefer-boolean-length-check.html", + }, + fixable: "code", + messages: { + preferBooleanCheck: "Prefer boolean length check", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + const conditionStatement = [ + "IfStatement", + "WhileStatement", + "DoWhileStatement", + "ForStatement", + "ForInStatement", + "ConditionalExpression", + ]; + + return { + BinaryExpression(node) { + if ( + ["==", "!=", ">", "<"].includes(node.operator) && + ((node.right.type == "Literal" && + node.right.value == 0 && + node.left.property?.name == "length") || + (node.left.type == "Literal" && + node.left.value == 0 && + node.right.property?.name == "length")) + ) { + if ( + conditionStatement.includes(node.parent.type) || + (node.parent.type == "LogicalExpression" && + conditionStatement.includes(node.parent.parent.type)) + ) { + context.report({ + node, + fix: fixer => { + let generateExpression = funcForBooleanLength( + context, + node, + true + ); + + return fixer.replaceText(node, generateExpression); + }, + messageId: "preferBooleanCheck", + }); + } else { + context.report({ + node, + fix: fixer => { + let generateExpression = funcForBooleanLength( + context, + node, + false + ); + return fixer.replaceText(node, generateExpression); + }, + messageId: "preferBooleanCheck", + }); + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/prefer-formatValues.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/prefer-formatValues.js new file mode 100644 index 0000000000..4807cf1f1f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/prefer-formatValues.js @@ -0,0 +1,97 @@ +/** + * @fileoverview Reject multiple calls to document.l10n.formatValue in the same + * code block. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isIdentifier(node, id) { + return node && node.type === "Identifier" && node.name === id; +} + +/** + * As we enter blocks new sets are pushed onto this stack and then popped when + * we exit the block. + */ +const BlockStack = []; + +module.exports = { + meta: { + docs: { + description: "disallow multiple document.l10n.formatValue calls", + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/prefer-formatValues.html", + }, + messages: { + outsideCallBlock: "call expression found outside of known block", + useSingleCall: + "prefer to use a single document.l10n.formatValues call instead " + + "of multiple calls to document.l10n.formatValue or document.l10n.formatValues", + }, + schema: [], + type: "problem", + }, + + create(context) { + function enterBlock() { + BlockStack.push(new Set()); + } + + function exitBlock() { + let calls = BlockStack.pop(); + if (calls.size > 1) { + for (let callNode of calls) { + context.report({ + node: callNode, + messageId: "useSingleCall", + }); + } + } + } + + return { + Program: enterBlock, + "Program:exit": exitBlock, + BlockStatement: enterBlock, + "BlockStatement:exit": exitBlock, + + CallExpression(node) { + if (!BlockStack.length) { + context.report({ + node, + messageId: "outsideCallBlock", + }); + } + + let callee = node.callee; + if (callee.type !== "MemberExpression") { + return; + } + + if ( + !isIdentifier(callee.property, "formatValue") && + !isIdentifier(callee.property, "formatValues") + ) { + return; + } + + if (callee.object.type !== "MemberExpression") { + return; + } + + if ( + !isIdentifier(callee.object.object, "document") || + !isIdentifier(callee.object.property, "l10n") + ) { + return; + } + + let calls = BlockStack[BlockStack.length - 1]; + calls.add(node); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-addtask-only.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-addtask-only.js new file mode 100644 index 0000000000..b1a67cad7d --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-addtask-only.js @@ -0,0 +1,53 @@ +/** + * @fileoverview Don't allow only() in tests + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-addtask-only.html", + }, + hasSuggestions: true, + messages: { + addTaskNotAllowed: + "add_task(...).only() not allowed - add an exception if this is intentional", + addTaskNotAllowedSuggestion: "Remove only() call from task", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + CallExpression(node) { + if ( + ["add_task", "decorate_task"].includes( + node.callee.object?.callee?.name + ) && + node.callee.property?.name == "only" + ) { + context.report({ + node, + messageId: "addTaskNotAllowed", + suggest: [ + { + messageId: "addTaskNotAllowedSuggestion", + fix: fixer => + fixer.replaceTextRange( + [node.callee.object.range[1], node.range[1]], + "" + ), + }, + ], + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-chromeutils-import-params.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-chromeutils-import-params.js new file mode 100644 index 0000000000..ccfb0a1cb0 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-chromeutils-import-params.js @@ -0,0 +1,66 @@ +/** + * @fileoverview Reject calls to ChromeUtils.import(..., null). This allows to + * retrieve the global object for the JSM, instead we should rely on explicitly + * exported symbols. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isIdentifier(node, id) { + return node && node.type === "Identifier" && node.name === id; +} + +function getRangeAfterArgToEnd(context, argNumber, args) { + let sourceCode = context.getSourceCode(); + return [ + sourceCode.getTokenAfter(args[argNumber]).range[0], + args[args.length - 1].range[1], + ]; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-chromeutils-import-params.html", + }, + hasSuggestions: true, + messages: { + importOnlyOneArg: "ChromeUtils.import only takes one argument.", + importOnlyOneArgSuggestion: "Remove the unnecessary parameters.", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + CallExpression(node) { + let { callee } = node; + if ( + isIdentifier(callee.object, "ChromeUtils") && + isIdentifier(callee.property, "import") && + node.arguments.length >= 2 + ) { + context.report({ + node, + messageId: "importOnlyOneArg", + suggest: [ + { + messageId: "importOnlyOneArgSuggestion", + fix: fixer => { + return fixer.removeRange( + getRangeAfterArgToEnd(context, 0, node.arguments) + ); + }, + }, + ], + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-chromeutils-import.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-chromeutils-import.js new file mode 100644 index 0000000000..1f746db730 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-chromeutils-import.js @@ -0,0 +1,80 @@ +/** + * @fileoverview Reject use of Cu.import and ChromeUtils.import + * in favor of ChromeUtils.importESModule. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isIdentifier(node, id) { + return node && node.type === "Identifier" && node.name === id; +} + +function isMemberExpression(node, object, member) { + return ( + node.type === "MemberExpression" && + isIdentifier(node.object, object) && + isIdentifier(node.property, member) + ); +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-chromeutils-import.html", + }, + messages: { + useImportESModule: + "Please use ChromeUtils.importESModule instead of " + + "ChromeUtils.import unless the module is not yet ESMified", + useImportESModuleLazy: + "Please use ChromeUtils.defineESModuleGetters instead of " + + "ChromeUtils.defineModuleGetter " + + "unless the module is not yet ESMified", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + CallExpression(node) { + if (node.callee.type !== "MemberExpression") { + return; + } + + let { callee } = node; + + if ( + (isIdentifier(callee.object, "ChromeUtils") || + isMemberExpression( + callee.object, + "SpecialPowers", + "ChromeUtils" + )) && + isIdentifier(callee.property, "import") + ) { + context.report({ + node, + messageId: "useImportESModule", + }); + } + + if ( + (isMemberExpression(callee.object, "SpecialPowers", "ChromeUtils") && + isIdentifier(callee.property, "defineModuleGetter")) || + isMemberExpression(callee, "ChromeUtils", "defineModuleGetter") || + isMemberExpression(callee, "XPCOMUtils", "defineLazyModuleGetters") + ) { + context.report({ + node, + messageId: "useImportESModuleLazy", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-eager-module-in-lazy-getter.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-eager-module-in-lazy-getter.js new file mode 100644 index 0000000000..133dd6d71f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-eager-module-in-lazy-getter.js @@ -0,0 +1,99 @@ +/** + * @fileoverview Reject use of lazy getters for modules that's loaded early in + * the startup process and not necessarily be lazy. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; +const helpers = require("../helpers"); + +function isString(node) { + return node.type === "Literal" && typeof node.value === "string"; +} + +function isEagerModule(resourceURI) { + return [ + "resource://gre/modules/XPCOMUtils", + "resource://gre/modules/AppConstants", + ].includes(resourceURI.replace(/(\.jsm|\.jsm\.js|\.js|\.sys\.mjs)$/, "")); +} + +function checkEagerModule(context, node, resourceURI) { + if (!isEagerModule(resourceURI)) { + return; + } + context.report({ + node, + messageId: "eagerModule", + data: { uri: resourceURI }, + }); +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-eager-module-in-lazy-getter.html", + }, + messages: { + eagerModule: + 'Module "{{uri}}" is known to be loaded early in the startup process, and should be loaded eagerly, instead of defining a lazy getter.', + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + CallExpression(node) { + if (node.callee.type !== "MemberExpression") { + return; + } + + let callerSource; + try { + callerSource = helpers.getASTSource(node.callee); + } catch (e) { + return; + } + + if (callerSource === "ChromeUtils.defineModuleGetter") { + if (node.arguments.length < 3) { + return; + } + const resourceURINode = node.arguments[2]; + if (!isString(resourceURINode)) { + return; + } + checkEagerModule(context, node, resourceURINode.value); + } else if ( + callerSource === "XPCOMUtils.defineLazyModuleGetters" || + callerSource === "ChromeUtils.defineESModuleGetters" + ) { + if (node.arguments.length < 2) { + return; + } + const obj = node.arguments[1]; + if (obj.type !== "ObjectExpression") { + return; + } + for (let prop of obj.properties) { + if (prop.type !== "Property") { + continue; + } + if (prop.kind !== "init") { + continue; + } + const resourceURINode = prop.value; + if (!isString(resourceURINode)) { + continue; + } + checkEagerModule(context, node, resourceURINode.value); + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-global-this.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-global-this.js new file mode 100644 index 0000000000..ec4b5fd43d --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-global-this.js @@ -0,0 +1,43 @@ +/** + * @fileoverview Reject attempts to use the global object in jsms. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const helpers = require("../helpers"); + +// ----------------------------------------------------------------------------- +// Rule Definition +// ----------------------------------------------------------------------------- + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-global-this.html", + }, + messages: { + avoidGlobalThis: "JSM should not use the global this", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + ThisExpression(node) { + if (!helpers.getIsGlobalThis(context.getAncestors())) { + return; + } + + context.report({ + node, + messageId: "avoidGlobalThis", + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-globalThis-modification.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-globalThis-modification.js new file mode 100644 index 0000000000..13052db80c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-globalThis-modification.js @@ -0,0 +1,74 @@ +/** + * @fileoverview Enforce the standard object name for + * ChromeUtils.defineESMGetters + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isIdentifier(node, id) { + return node.type === "Identifier" && node.name === id; +} + +function calleeToString(node) { + if (node.type === "Identifier") { + return node.name; + } + + if (node.type === "MemberExpression" && !node.computed) { + return calleeToString(node.object) + "." + node.property.name; + } + + return "???"; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-globalThis-modification.html", + }, + messages: { + rejectModifyGlobalThis: + "`globalThis` shouldn't be modified. `globalThis` is the shared global inside the system module, and properties defined on it is visible from all modules.", + rejectPassingGlobalThis: + "`globalThis` shouldn't be passed to function that can modify it. `globalThis` is the shared global inside the system module, and properties defined on it is visible from all modules.", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + AssignmentExpression(node, parents) { + let target = node.left; + while (target.type === "MemberExpression") { + target = target.object; + } + if (isIdentifier(target, "globalThis")) { + context.report({ + node, + messageId: "rejectModifyGlobalThis", + }); + } + }, + CallExpression(node) { + const calleeStr = calleeToString(node.callee); + if (calleeStr.endsWith(".deserialize")) { + return; + } + + for (const arg of node.arguments) { + if (isIdentifier(arg, "globalThis")) { + context.report({ + node, + messageId: "rejectPassingGlobalThis", + }); + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-import-system-module-from-non-system.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-import-system-module-from-non-system.js new file mode 100644 index 0000000000..2cbc4e7652 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-import-system-module-from-non-system.js @@ -0,0 +1,36 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-import-system-module-from-non-system.html", + }, + messages: { + rejectStaticImportSystemModuleFromNonSystem: + "System modules (*.sys.mjs) can be imported with static import declaration only from system modules.", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + ImportDeclaration(node) { + if (!node.source.value.endsWith(".sys.mjs")) { + return; + } + + context.report({ + node, + messageId: "rejectStaticImportSystemModuleFromNonSystem", + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-importGlobalProperties.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-importGlobalProperties.js new file mode 100644 index 0000000000..b2f0aad1ae --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-importGlobalProperties.js @@ -0,0 +1,97 @@ +/** + * @fileoverview Reject use of Cu.importGlobalProperties + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const path = require("path"); + +const privilegedGlobals = Object.keys( + require("../environments/privileged.js").globals +); + +function getMessageId(context) { + return path.extname(context.getFilename()) == ".sjs" + ? "unexpectedCallSjs" + : "unexpectedCall"; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-importGlobalProperties.html", + }, + messages: { + unexpectedCall: "Unexpected call to Cu.importGlobalProperties", + unexpectedCallCuWebIdl: + "Unnecessary call to Cu.importGlobalProperties for {{name}} (webidl names are automatically imported)", + unexpectedCallSjs: + "Do not call Cu.importGlobalProperties in sjs files, expand the global instead (see rule docs).", + unexpectedCallXPCOMWebIdl: + "Unnecessary call to XPCOMUtils.defineLazyGlobalGetters for {{name}} (webidl names are automatically imported)", + }, + schema: [ + { + enum: ["everything", "allownonwebidl"], + }, + ], + type: "problem", + }, + + create(context) { + return { + CallExpression(node) { + if (node.callee.type !== "MemberExpression") { + return; + } + let memexp = node.callee; + if ( + memexp.object.type === "Identifier" && + // Only Cu, not Components.utils as `use-cc-etc` handles this for us. + memexp.object.name === "Cu" && + memexp.property.type === "Identifier" && + memexp.property.name === "importGlobalProperties" + ) { + if (context.options.includes("allownonwebidl")) { + for (let element of node.arguments[0].elements) { + if (privilegedGlobals.includes(element.value)) { + context.report({ + node, + messageId: "unexpectedCallCuWebIdl", + data: { name: element.value }, + }); + } + } + } else { + context.report({ node, messageId: getMessageId(context) }); + } + } + if ( + memexp.object.type === "Identifier" && + memexp.object.name === "XPCOMUtils" && + memexp.property.type === "Identifier" && + memexp.property.name === "defineLazyGlobalGetters" && + node.arguments.length >= 2 + ) { + if (context.options.includes("allownonwebidl")) { + for (let element of node.arguments[1].elements) { + if (privilegedGlobals.includes(element.value)) { + context.report({ + node, + messageId: "unexpectedCallXPCOMWebIdl", + data: { name: element.value }, + }); + } + } + } else { + context.report({ node, messageId: getMessageId(context) }); + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-lazy-imports-into-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-lazy-imports-into-globals.js new file mode 100644 index 0000000000..492a1e3bd7 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-lazy-imports-into-globals.js @@ -0,0 +1,72 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const helpers = require("../helpers"); + +const callExpressionDefinitions = [ + /^loader\.lazyGetter\((?:globalThis|window), "(\w+)"/, + /^loader\.lazyServiceGetter\((?:globalThis|window), "(\w+)"/, + /^loader\.lazyRequireGetter\((?:globalThis|window), "(\w+)"/, + /^ChromeUtils\.defineLazyGetter\((?:globalThis|window), "(\w+)"/, + /^ChromeUtils\.defineModuleGetter\((?:globalThis|window), "(\w+)"/, + /^XPCOMUtils\.defineLazyPreferenceGetter\((?:globalThis|window), "(\w+)"/, + /^XPCOMUtils\.defineLazyScriptGetter\((?:globalThis|window), "(\w+)"/, + /^XPCOMUtils\.defineLazyServiceGetter\((?:globalThis|window), "(\w+)"/, + /^XPCOMUtils\.defineConstant\((?:globalThis|window), "(\w+)"/, + /^DevToolsUtils\.defineLazyGetter\((?:globalThis|window), "(\w+)"/, + /^Object\.defineProperty\((?:globalThis|window), "(\w+)"/, + /^Reflect\.defineProperty\((?:globalThis|window), "(\w+)"/, + /^this\.__defineGetter__\("(\w+)"/, +]; + +const callExpressionMultiDefinitions = [ + "XPCOMUtils.defineLazyGlobalGetters(window,", + "XPCOMUtils.defineLazyGlobalGetters(globalThis,", + "XPCOMUtils.defineLazyModuleGetters(window,", + "XPCOMUtils.defineLazyModuleGetters(globalThis,", + "XPCOMUtils.defineLazyServiceGetters(window,", + "XPCOMUtils.defineLazyServiceGetters(globalThis,", + "ChromeUtils.defineESModuleGetters(window,", + "ChromeUtils.defineESModuleGetters(globalThis,", + "loader.lazyRequireGetter(window,", + "loader.lazyRequireGetter(globalThis,", +]; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-lazy-imports-into-globals.html", + }, + messages: { + rejectLazyImportsIntoGlobals: + "Non-system modules should not import into globalThis nor window. Prefer a lazy object holder", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + CallExpression(node) { + let source; + try { + source = helpers.getASTSource(node); + } catch (e) { + return; + } + + if ( + callExpressionDefinitions.some(expr => source.match(expr)) || + callExpressionMultiDefinitions.some(expr => source.startsWith(expr)) + ) { + context.report({ node, messageId: "rejectLazyImportsIntoGlobals" }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixing-eager-and-lazy.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixing-eager-and-lazy.js new file mode 100644 index 0000000000..5779a90afd --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixing-eager-and-lazy.js @@ -0,0 +1,150 @@ +/** + * @fileoverview Reject use of lazy getters for modules that's loaded early in + * the startup process and not necessarily be lazy. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; +const helpers = require("../helpers"); + +function isIdentifier(node, id) { + return node.type === "Identifier" && node.name === id; +} + +function isString(node) { + return node.type === "Literal" && typeof node.value === "string"; +} + +function checkMixed(loadedModules, context, node, type, resourceURI) { + if (!loadedModules.has(resourceURI)) { + loadedModules.set(resourceURI, type); + } + + if (loadedModules.get(resourceURI) === type) { + return; + } + + context.report({ + node, + messageId: "mixedEagerAndLazy", + data: { uri: resourceURI }, + }); +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixed-eager-and-lazy.html", + }, + messages: { + mixedEagerAndLazy: + 'Module "{{uri}}" is loaded eagerly, and should not be used for lazy getter.', + }, + schema: [], + type: "problem", + }, + + create(context) { + const loadedModules = new Map(); + + return { + ImportDeclaration(node) { + const resourceURI = node.source.value; + checkMixed(loadedModules, context, node, "eager", resourceURI); + }, + CallExpression(node) { + if (node.callee.type !== "MemberExpression") { + return; + } + + let callerSource; + try { + callerSource = helpers.getASTSource(node.callee); + } catch (e) { + return; + } + + if ( + (callerSource === "ChromeUtils.import" || + callerSource === "ChromeUtils.importESModule") && + helpers.getIsTopLevelAndUnconditionallyExecuted( + context.getAncestors() + ) + ) { + if (node.arguments.length < 1) { + return; + } + const resourceURINode = node.arguments[0]; + if (!isString(resourceURINode)) { + return; + } + checkMixed( + loadedModules, + context, + node, + "eager", + resourceURINode.value + ); + } + + if (callerSource === "ChromeUtils.defineModuleGetter") { + if (node.arguments.length < 3) { + return; + } + if (!isIdentifier(node.arguments[0], "lazy")) { + return; + } + + const resourceURINode = node.arguments[2]; + if (!isString(resourceURINode)) { + return; + } + checkMixed( + loadedModules, + context, + node, + "lazy", + resourceURINode.value + ); + } else if ( + callerSource === "XPCOMUtils.defineLazyModuleGetters" || + callerSource === "ChromeUtils.defineESModuleGetters" + ) { + if (node.arguments.length < 2) { + return; + } + if (!isIdentifier(node.arguments[0], "lazy")) { + return; + } + + const obj = node.arguments[1]; + if (obj.type !== "ObjectExpression") { + return; + } + for (let prop of obj.properties) { + if (prop.type !== "Property") { + continue; + } + if (prop.kind !== "init") { + continue; + } + const resourceURINode = prop.value; + if (!isString(resourceURINode)) { + continue; + } + checkMixed( + loadedModules, + context, + node, + "lazy", + resourceURINode.value + ); + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-multiple-getters-calls.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-multiple-getters-calls.js new file mode 100644 index 0000000000..e6e37ad035 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-multiple-getters-calls.js @@ -0,0 +1,81 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const helpers = require("../helpers"); + +function findStatement(node) { + while (node && node.type !== "ExpressionStatement") { + node = node.parent; + } + + return node; +} + +function isIdentifier(node, id) { + return node && node.type === "Identifier" && node.name === id; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-multiple-getters-calls.html", + }, + messages: { + rejectMultipleCalls: + "ChromeUtils.defineESModuleGetters is already called for {{target}} in the same context. Please merge those calls", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + const parentToTargets = new Map(); + + return { + CallExpression(node) { + let callee = node.callee; + if ( + callee.type === "MemberExpression" && + isIdentifier(callee.object, "ChromeUtils") && + isIdentifier(callee.property, "defineESModuleGetters") + ) { + const stmt = findStatement(node); + if (!stmt) { + return; + } + + let target; + try { + target = helpers.getASTSource(node.arguments[0]); + } catch (e) { + return; + } + + const parent = stmt.parent; + let targets; + if (parentToTargets.has(parent)) { + targets = parentToTargets.get(parent); + } else { + targets = new Set(); + parentToTargets.set(parent, targets); + } + + if (targets.has(target)) { + context.report({ + node, + messageId: "rejectMultipleCalls", + data: { target }, + }); + } + + targets.add(target); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-relative-requires.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-relative-requires.js new file mode 100644 index 0000000000..34e4b6bd5e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-relative-requires.js @@ -0,0 +1,42 @@ +/** + * @fileoverview Reject some uses of require. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var helpers = require("../helpers"); + +const isRelativePath = function (path) { + return path.startsWith("./") || path.startsWith("../"); +}; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-relative-requires.html", + }, + messages: { + rejectRelativeRequires: "relative paths are not allowed with require()", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + CallExpression(node) { + const path = helpers.getDevToolsRequirePath(node); + if (path && isRelativePath(path)) { + context.report({ + node, + messageId: "rejectRelativeRequires", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-scriptableunicodeconverter.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-scriptableunicodeconverter.js new file mode 100644 index 0000000000..e29a60089c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-scriptableunicodeconverter.js @@ -0,0 +1,44 @@ +/** + * @fileoverview Reject calls into Ci.nsIScriptableUnicodeConverter. We're phasing this out in + * favour of TextEncoder or TextDecoder. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isIdentifier(node, id) { + return node && node.type === "Identifier" && node.name === id; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-scriptableunicodeconverter.html", + }, + messages: { + rejectScriptableUnicodeConverter: + "Ci.nsIScriptableUnicodeConverter is deprecated. You should use TextEncoder or TextDecoder instead.", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + MemberExpression(node) { + if ( + isIdentifier(node.object, "Ci") && + isIdentifier(node.property, "nsIScriptableUnicodeConverter") + ) { + context.report({ + node, + messageId: "rejectScriptableUnicodeConverter", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-some-requires.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-some-requires.js new file mode 100644 index 0000000000..5a4c6b4df7 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-some-requires.js @@ -0,0 +1,44 @@ +/** + * @fileoverview Reject some uses of require. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var helpers = require("../helpers"); + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-some-requires.html", + }, + messages: { + rejectRequire: `require({{path}}) is not allowed`, + }, + schema: [ + { + type: "string", + }, + ], + type: "problem", + }, + + create(context) { + if (typeof context.options[0] !== "string") { + throw new Error("reject-some-requires expects a regexp"); + } + const RX = new RegExp(context.options[0]); + + return { + CallExpression(node) { + const path = helpers.getDevToolsRequirePath(node); + if (path && RX.test(path)) { + context.report({ node, messageId: "rejectRequire", data: { path } }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-top-level-await.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-top-level-await.js new file mode 100644 index 0000000000..dff7db0f9a --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-top-level-await.js @@ -0,0 +1,45 @@ +/** + * @fileoverview Don't allow only() in tests + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var helpers = require("../helpers"); + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-top-level-await.html", + }, + messages: { + rejectTopLevelAwait: + "Top-level await is not currently supported in component files.", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + AwaitExpression(node) { + if (!helpers.getIsTopLevelScript(context.getAncestors())) { + return; + } + context.report({ node, messageId: "rejectTopLevelAwait" }); + }, + ForOfStatement(node) { + if ( + !node.await || + !helpers.getIsTopLevelScript(context.getAncestors()) + ) { + return; + } + context.report({ node, messageId: "rejectTopLevelAwait" }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/rejects-requires-await.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/rejects-requires-await.js new file mode 100644 index 0000000000..a7e7d9d7e2 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/rejects-requires-await.js @@ -0,0 +1,47 @@ +/** + * @fileoverview Ensure Assert.rejects is preceded by await. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/reject-requires-await.html", + }, + messages: { + rejectRequiresAwait: "Assert.rejects needs to be preceded by await.", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + CallExpression(node) { + if (node.callee.type === "MemberExpression") { + let memexp = node.callee; + if ( + memexp.object.type === "Identifier" && + memexp.object.name === "Assert" && + memexp.property.type === "Identifier" && + memexp.property.name === "rejects" + ) { + // We have ourselves an Assert.rejects. + + if (node.parent.type !== "AwaitExpression") { + context.report({ + node, + messageId: "rejectRequiresAwait", + }); + } + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-cc-etc.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-cc-etc.js new file mode 100644 index 0000000000..f47f03f0d2 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-cc-etc.js @@ -0,0 +1,57 @@ +/** + * @fileoverview Reject use of Components.classes etc, prefer the shorthand instead. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const componentsMap = { + classes: "Cc", + interfaces: "Ci", + results: "Cr", + utils: "Cu", +}; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-cc-etc.html", + }, + fixable: "code", + messages: { + useCcEtc: "Use {{ shortName }} rather than Components.{{ oldName }}", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + MemberExpression(node) { + if ( + node.object.type === "Identifier" && + node.object.name === "Components" && + node.property.type === "Identifier" && + Object.getOwnPropertyNames(componentsMap).includes(node.property.name) + ) { + context.report({ + node, + messageId: "useCcEtc", + data: { + shortName: componentsMap[node.property.name], + oldName: node.property.name, + }, + fix: fixer => + fixer.replaceTextRange( + [node.range[0], node.range[1]], + componentsMap[node.property.name] + ), + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-definelazygetter.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-definelazygetter.js new file mode 100644 index 0000000000..a9f43a945a --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-definelazygetter.js @@ -0,0 +1,58 @@ +/** + * @fileoverview Reject use of XPCOMUtils.defineLazyGetter in favor of ChromeUtils.defineLazyGetter. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isIdentifier(node, id) { + return node && node.type === "Identifier" && node.name === id; +} + +function isMemberExpression(node, object, member) { + return ( + node.type === "MemberExpression" && + isIdentifier(node.object, object) && + isIdentifier(node.property, member) + ); +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-chromeutils-definelazygetter.html", + }, + fixable: "code", + messages: { + useChromeUtilsDefineLazyGetter: + "Please use ChromeUtils.defineLazyGetter instead of XPCOMUtils.defineLazyGetter", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + CallExpression(node) { + if (node.callee.type !== "MemberExpression") { + return; + } + + let { callee } = node; + + if (isMemberExpression(callee, "XPCOMUtils", "defineLazyGetter")) { + context.report({ + node, + messageId: "useChromeUtilsDefineLazyGetter", + fix(fixer) { + return fixer.replaceText(callee, "ChromeUtils.defineLazyGetter"); + }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-generateqi.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-generateqi.js new file mode 100644 index 0000000000..d654b0410c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-generateqi.js @@ -0,0 +1,105 @@ +/** + * @fileoverview Reject use of XPCOMUtils.generateQI and JS-implemented + * QueryInterface methods in favor of ChromeUtils. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isIdentifier(node, id) { + return node && node.type === "Identifier" && node.name === id; +} + +function isMemberExpression(node, object, member) { + return ( + node.type === "MemberExpression" && + isIdentifier(node.object, object) && + isIdentifier(node.property, member) + ); +} + +function funcToGenerateQI(context, node) { + const sourceCode = context.getSourceCode(); + const text = sourceCode.getText(node); + + let interfaces = []; + let match; + let re = /\bCi\.([a-zA-Z0-9]+)\b|\b(nsI[A-Z][a-zA-Z0-9]+)\b/g; + while ((match = re.exec(text))) { + interfaces.push(match[1] || match[2]); + } + + let ifaces = interfaces + .filter(iface => iface != "nsISupports") + .map(iface => JSON.stringify(iface)) + .join(", "); + + return `ChromeUtils.generateQI([${ifaces}])`; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-chromeutils-generateqi.html", + }, + fixable: "code", + messages: { + noJSQueryInterface: + "Please use ChromeUtils.generateQI rather than " + + "manually creating JavaScript QueryInterface functions", + noXpcomUtilsGenerateQI: + "Please use ChromeUtils.generateQI instead of XPCOMUtils.generateQI", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + CallExpression(node) { + let { callee } = node; + if (isMemberExpression(callee, "XPCOMUtils", "generateQI")) { + context.report({ + node, + messageId: "noXpcomUtilsGenerateQI", + fix(fixer) { + return fixer.replaceText(callee, "ChromeUtils.generateQI"); + }, + }); + } + }, + + "AssignmentExpression > MemberExpression[property.name='QueryInterface']": + function (node) { + const { right } = node.parent; + if (right.type === "FunctionExpression") { + context.report({ + node: node.parent, + messageId: "noJSQueryInterface", + fix(fixer) { + return fixer.replaceText( + right, + funcToGenerateQI(context, right) + ); + }, + }); + } + }, + + "Property[key.name='QueryInterface'][value.type='FunctionExpression']": + function (node) { + context.report({ + node, + messageId: "noJSQueryInterface", + fix(fixer) { + let generateQI = funcToGenerateQI(context, node.value); + return fixer.replaceText(node, `QueryInterface: ${generateQI}`); + }, + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-import.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-import.js new file mode 100644 index 0000000000..925b4800bc --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-import.js @@ -0,0 +1,63 @@ +/** + * @fileoverview Reject use of Cu.import in favor of ChromeUtils. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +function isIdentifier(node, id) { + return node && node.type === "Identifier" && node.name === id; +} + +function isMemberExpression(node, object, member) { + return ( + node.type === "MemberExpression" && + isIdentifier(node.object, object) && + isIdentifier(node.property, member) + ); +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-chromeutils-import.html", + }, + fixable: "code", + messages: { + useChromeUtilsImport: + "Please use ChromeUtils.import instead of Cu.import", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + CallExpression(node) { + if (node.callee.type !== "MemberExpression") { + return; + } + + let { callee } = node; + + // Is the expression starting with `Cu` or `Components.utils`? + if ( + (isIdentifier(callee.object, "Cu") || + isMemberExpression(callee.object, "Components", "utils")) && + isIdentifier(callee.property, "import") + ) { + context.report({ + node, + messageId: "useChromeUtilsImport", + fix(fixer) { + return fixer.replaceText(callee, "ChromeUtils.import"); + }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-console-createInstance.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-console-createInstance.js new file mode 100644 index 0000000000..72add0ab24 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-console-createInstance.js @@ -0,0 +1,44 @@ +/** + * @fileoverview Reject use of Console.sys.mjs and Log.sys.mjs. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-console-createInstance.html", + }, + messages: { + useConsoleRatherThanModule: + "Use console.createInstance rather than {{module}}", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + Literal(node) { + if (typeof node.value != "string") { + return; + } + /* eslint-disable mozilla/use-console-createInstance */ + if ( + node.value == "resource://gre/modules/Console.sys.mjs" || + node.value == "resource://gre/modules/Log.sys.mjs" + ) { + context.report({ + node, + messageId: "useConsoleRatherThanModule", + data: { module: node.value.split("/").at(-1) }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-default-preference-values.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-default-preference-values.js new file mode 100644 index 0000000000..edc1e28405 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-default-preference-values.js @@ -0,0 +1,56 @@ +/** + * @fileoverview Require providing a second parameter to get*Pref + * methods instead of using a try/catch block. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-default-preference-values.html", + }, + messages: { + provideDefaultValue: + "provide a default value instead of using a try/catch block", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + TryStatement(node) { + let types = ["Bool", "Char", "Float", "Int"]; + let methods = types.map(type => "get" + type + "Pref"); + if ( + node.block.type != "BlockStatement" || + node.block.body.length != 1 + ) { + return; + } + + let firstStm = node.block.body[0]; + if ( + firstStm.type != "ExpressionStatement" || + firstStm.expression.type != "AssignmentExpression" || + firstStm.expression.right.type != "CallExpression" || + firstStm.expression.right.callee.type != "MemberExpression" || + firstStm.expression.right.callee.property.type != "Identifier" || + !methods.includes(firstStm.expression.right.callee.property.name) + ) { + return; + } + + context.report({ + node, + messageId: "provideDefaultValue", + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-includes-instead-of-indexOf.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-includes-instead-of-indexOf.js new file mode 100644 index 0000000000..245c89a095 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-includes-instead-of-indexOf.js @@ -0,0 +1,53 @@ +/** + * @fileoverview Use .includes instead of .indexOf + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-includes-instead-of-indexOf.html", + }, + messages: { + useIncludes: "use .includes instead of .indexOf", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + BinaryExpression(node) { + if ( + node.left.type != "CallExpression" || + node.left.callee.type != "MemberExpression" || + node.left.callee.property.type != "Identifier" || + node.left.callee.property.name != "indexOf" + ) { + return; + } + + if ( + (["!=", "!==", "==", "==="].includes(node.operator) && + node.right.type == "UnaryExpression" && + node.right.operator == "-" && + node.right.argument.type == "Literal" && + node.right.argument.value == 1) || + ([">=", "<"].includes(node.operator) && + node.right.type == "Literal" && + node.right.value == 0) + ) { + context.report({ + node, + messageId: "useIncludes", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-isInstance.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-isInstance.js new file mode 100644 index 0000000000..ffd9bc9566 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-isInstance.js @@ -0,0 +1,155 @@ +/** + * @fileoverview Reject use of instanceof against DOM interfaces + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const fs = require("fs"); + +const { maybeGetMemberPropertyName } = require("../helpers"); + +const privilegedGlobals = Object.keys( + require("../environments/privileged.js").globals +); + +// ----------------------------------------------------------------------------- +// Rule Definition +// ----------------------------------------------------------------------------- + +/** + * Whether an identifier is defined by eslint configuration. + * `env: { browser: true }` or `globals: []` for example. + * @param {import("eslint-scope").Scope} currentScope + * @param {import("estree").Identifier} id + */ +function refersToEnvironmentGlobals(currentScope, id) { + const reference = currentScope.references.find(ref => ref.identifier === id); + const { resolved } = reference || {}; + if (!resolved) { + return false; + } + + // No definition in script files; defined via .eslintrc + return resolved.scope.type === "global" && resolved.defs.length === 0; +} + +/** + * Whether a node points to a DOM interface. + * Includes direct references to interfaces objects and also indirect references + * via property access. + * OS.File and lazy.(Foo) are explicitly excluded. + * + * @example HTMLElement + * @example win.HTMLElement + * @example iframe.contentWindow.HTMLElement + * @example foo.HTMLElement + * + * @param {import("eslint-scope").Scope} currentScope + * @param {import("estree").Node} node + */ +function pointsToDOMInterface(currentScope, node) { + if (node.type === "MemberExpression") { + const objectName = maybeGetMemberPropertyName(node.object); + if (objectName === "lazy") { + // lazy.Foo is probably a non-IDL import. + return false; + } + if (objectName === "OS" && node.property.name === "File") { + // OS.File is an exception that is not a Web IDL interface + return false; + } + // For `win.Foo`, `iframe.contentWindow.Foo`, or such. + return privilegedGlobals.includes(node.property.name); + } + + if ( + node.type === "Identifier" && + refersToEnvironmentGlobals(currentScope, node) + ) { + return privilegedGlobals.includes(node.name); + } + + return false; +} + +/** + * @param {import("eslint").Rule.RuleContext} context + */ +function isChromeContext(context) { + const filename = context.getFilename(); + const isChromeFileName = + filename.endsWith(".sys.mjs") || filename.endsWith(".jsm"); + if (isChromeFileName) { + return true; + } + + if (filename.endsWith(".xhtml")) { + // Treat scripts in XUL files as chrome scripts + // Note: readFile is needed as getSourceCode() only gives JS blocks + return fs.readFileSync(filename).includes("there.is.only.xul"); + } + + // Treat scripts as chrome privileged when using: + // 1. ChromeUtils, but not SpecialPowers.ChromeUtils + // 2. BrowserTestUtils, PlacesUtils + // 3. document.createXULElement + // 4. loader.lazyRequireGetter + // 5. Services.foo, but not SpecialPowers.Services.foo + // 6. evalInSandbox + const source = context.getSourceCode().text; + return !!source.match( + /(^|\s)ChromeUtils|BrowserTestUtils|PlacesUtils|createXULElement|lazyRequireGetter|(^|\s)Services\.|evalInSandbox/ + ); +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-isInstance.html", + }, + fixable: "code", + messages: { + preferIsInstance: + "Please prefer .isInstance() in chrome scripts over the standard instanceof operator for DOM interfaces, " + + "since the latter will return false when the object is created from a different context.", + }, + schema: [], + type: "problem", + }, + /** + * @param {import("eslint").Rule.RuleContext} context + */ + create(context) { + if (!isChromeContext(context)) { + return {}; + } + + return { + BinaryExpression(node) { + const { operator, right } = node; + if ( + operator === "instanceof" && + pointsToDOMInterface(context.getScope(), right) + ) { + context.report({ + node, + messageId: "preferIsInstance", + fix(fixer) { + const sourceCode = context.getSourceCode(); + return fixer.replaceText( + node, + `${sourceCode.getText(right)}.isInstance(${sourceCode.getText( + node.left + )})` + ); + }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-ownerGlobal.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-ownerGlobal.js new file mode 100644 index 0000000000..1d71e82b8f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-ownerGlobal.js @@ -0,0 +1,43 @@ +/** + * @fileoverview Require .ownerGlobal instead of .ownerDocument.defaultView. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-ownerGlobal.html", + }, + messages: { + useOwnerGlobal: "use .ownerGlobal instead of .ownerDocument.defaultView", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + MemberExpression(node) { + if ( + node.property.type != "Identifier" || + node.property.name != "defaultView" || + node.object.type != "MemberExpression" || + node.object.property.type != "Identifier" || + node.object.property.name != "ownerDocument" + ) { + return; + } + + context.report({ + node, + messageId: "useOwnerGlobal", + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-returnValue.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-returnValue.js new file mode 100644 index 0000000000..23bbc040b9 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-returnValue.js @@ -0,0 +1,48 @@ +/** + * @fileoverview Warn when idempotent methods are called and their return value is unused. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-returnValue.html", + }, + messages: { + useReturnValue: + "{Array/String}.{{ property }} doesn't modify the instance in-place", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + ExpressionStatement(node) { + if ( + node.expression?.type != "CallExpression" || + node.expression.callee?.type != "MemberExpression" || + node.expression.callee.property?.type != "Identifier" || + !["concat", "join", "slice"].includes( + node.expression.callee.property?.name + ) + ) { + return; + } + + context.report({ + node, + messageId: "useReturnValue", + data: { + property: node.expression.callee.property.name, + }, + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-services.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-services.js new file mode 100644 index 0000000000..3a7cc34633 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-services.js @@ -0,0 +1,120 @@ +/** + * @fileoverview Require use of Services.* rather than getService. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; +const helpers = require("../helpers"); + +let servicesInterfaceMap = helpers.servicesData; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-services.html", + }, + // fixable: "code", + messages: { + useServices: + "Use Services.{{ serviceName }} rather than {{ getterName }}.", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + CallExpression(node) { + if (!node.callee || !node.callee.property) { + return; + } + + if ( + node.callee.property.type == "Identifier" && + node.callee.property.name == "defineLazyServiceGetter" && + node.arguments.length == 4 && + node.arguments[3].type == "Literal" && + node.arguments[3].value in servicesInterfaceMap + ) { + let serviceName = servicesInterfaceMap[node.arguments[3].value]; + + context.report({ + node, + messageId: "useServices", + data: { + serviceName, + getterName: "defineLazyServiceGetter", + }, + }); + return; + } + + if ( + node.callee.property.type == "Identifier" && + node.callee.property.name == "defineLazyServiceGetters" && + node.arguments.length == 2 && + node.arguments[1].type == "ObjectExpression" + ) { + for (let property of node.arguments[1].properties) { + if ( + property.value.type == "ArrayExpression" && + property.value.elements.length == 2 && + property.value.elements[1].value in servicesInterfaceMap + ) { + let serviceName = + servicesInterfaceMap[property.value.elements[1].value]; + + context.report({ + node: property.value, + messageId: "useServices", + data: { + serviceName, + getterName: "defineLazyServiceGetters", + }, + }); + } + } + return; + } + + if ( + node.callee.property.type != "Identifier" || + node.callee.property.name != "getService" || + node.arguments.length != 1 || + !node.arguments[0].property || + node.arguments[0].property.type != "Identifier" || + !node.arguments[0].property.name || + !(node.arguments[0].property.name in servicesInterfaceMap) + ) { + return; + } + + let serviceName = servicesInterfaceMap[node.arguments[0].property.name]; + context.report({ + node, + messageId: "useServices", + data: { + serviceName, + getterName: "getService()", + }, + // This is not enabled by default as for mochitest plain tests we + // would need to replace with `SpecialPowers.Services.${serviceName}`. + // At the moment we do not have an easy way to detect that. + // fix(fixer) { + // let sourceCode = context.getSourceCode(); + // return fixer.replaceTextRange( + // [ + // sourceCode.getFirstToken(node.callee).range[0], + // sourceCode.getLastToken(node).range[1], + // ], + // `Services.${serviceName}` + // ); + // }, + }); + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-static-import.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-static-import.js new file mode 100644 index 0000000000..100b5682de --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-static-import.js @@ -0,0 +1,87 @@ +/** + * @fileoverview Require use of static imports where possible. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const helpers = require("../helpers"); + +function isIdentifier(node, id) { + return node && node.type === "Identifier" && node.name === id; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/use-static-import.html", + }, + fixable: "code", + messages: { + useStaticImport: + "Please use static import instead of ChromeUtils.importESModule", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + VariableDeclarator(node) { + if ( + node.init?.type != "CallExpression" || + node.init?.callee?.type != "MemberExpression" || + !context.getFilename().endsWith(".sys.mjs") || + !helpers.isTopLevel(context.getAncestors()) + ) { + return; + } + + let callee = node.init.callee; + + if ( + isIdentifier(callee.object, "ChromeUtils") && + isIdentifier(callee.property, "importESModule") && + callee.parent.arguments.length == 1 + ) { + let sourceCode = context.getSourceCode(); + let importItemSource; + if (node.id.type != "ObjectPattern") { + importItemSource = sourceCode.getText(node.id); + } else { + importItemSource = "{ "; + let initial = true; + for (let property of node.id.properties) { + if (!initial) { + importItemSource += ", "; + } + initial = false; + if (property.key.name == property.value.name) { + importItemSource += property.key.name; + } else { + importItemSource += `${property.key.name} as ${property.value.name}`; + } + } + importItemSource += " }"; + } + + context.report({ + node: node.parent, + messageId: "useStaticImport", + fix(fixer) { + return fixer.replaceText( + node.parent, + `import ${importItemSource} from ${sourceCode.getText( + callee.parent.arguments[0] + )}` + ); + }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-ci-uses.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-ci-uses.js new file mode 100644 index 0000000000..4036a72928 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-ci-uses.js @@ -0,0 +1,172 @@ +/** + * @fileoverview Reject uses of unknown interfaces on Ci and properties of those + * interfaces. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const os = require("os"); +const helpers = require("../helpers"); + +// These interfaces are all platform specific, so may be not present +// on all platforms. +const platformSpecificInterfaces = new Map([ + ["nsIAboutThirdParty", "windows"], + ["nsIAboutWindowsMessages", "windows"], + ["nsIDefaultAgent", "windows"], + ["nsIJumpListBuilder", "windows"], + ["nsILegacyJumpListBuilder", "windows"], + ["nsILegacyJumpListItem", "windows"], + ["nsILegacyJumpListLink", "windows"], + ["nsILegacyJumpListSeparator", "windows"], + ["nsILegacyJumpListShortcut", "windows"], + ["nsITaskbarWindowPreview", "windows"], + ["nsIWindowsAlertsService", "windows"], + ["nsIWindowsAlertNotification", "windows"], + ["nsIWindowsMutexFactory", "windows"], + ["nsIWinAppHelper", "windows"], + ["nsIWinTaskbar", "windows"], + ["nsIWinTaskSchedulerService", "windows"], + ["nsIWindowsRegKey", "windows"], + ["nsIWindowsPackageManager", "windows"], + ["nsIWindowsShellService", "windows"], + ["nsIAccessibleMacEvent", "darwin"], + ["nsIAccessibleMacInterface", "darwin"], + ["nsILocalFileMac", "darwin"], + ["nsIAccessibleMacEvent", "darwin"], + ["nsIMacAttributionService", "darwin"], + ["nsIMacShellService", "darwin"], + ["nsIMacDockSupport", "darwin"], + ["nsIMacFinderProgress", "darwin"], + ["nsIMacPreferencesReader", "darwin"], + ["nsIMacSharingService", "darwin"], + ["nsIMacUserActivityUpdater", "darwin"], + ["nsIMacWebAppUtils", "darwin"], + ["nsIStandaloneNativeMenu", "darwin"], + ["nsITouchBarHelper", "darwin"], + ["nsITouchBarInput", "darwin"], + ["nsITouchBarUpdater", "darwin"], + ["mozISandboxReporter", "linux"], + ["nsIApplicationChooser", "linux"], + ["nsIGNOMEShellService", "linux"], + ["nsIGtkTaskbarProgress", "linux"], + + // These are used in the ESLint test code. + ["amIFoo", "any"], + ["nsIMeh", "any"], + // Can't easily detect android builds from ESLint at the moment. + ["nsIAndroidBridge", "any"], + ["nsIAndroidView", "any"], + // Code coverage is enabled only for certain builds (MOZ_CODE_COVERAGE). + ["nsICodeCoverage", "any"], + // Layout debugging is enabled only for certain builds (MOZ_LAYOUT_DEBUGGER). + ["nsILayoutDebuggingTools", "any"], + // Sandbox test is only enabled for certain configurations (MOZ_SANDBOX, + // MOZ_DEBUG, ENABLE_TESTS). + ["mozISandboxTest", "any"], +]); + +function interfaceHasProperty(interfaceName, propertyName) { + // `Ci.nsIFoo.number` is valid, it returns the iid. + if (propertyName == "number") { + return true; + } + + let interfaceInfo = helpers.xpidlData.get(interfaceName); + + if (!interfaceInfo) { + return true; + } + + // If the property is not in the lists of consts for this interface, check + // any parents as well. + if (!interfaceInfo.consts.find(e => e.name === propertyName)) { + if (interfaceInfo.parent && interfaceInfo.parent != "nsISupports") { + return interfaceHasProperty(interfaceName.parent, propertyName); + } + return false; + } + return true; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/valid-ci-uses.html", + }, + messages: { + missingInterface: + "{{ interface }} is defined in this rule's platform specific list, but is not available", + unknownInterface: "Use of unknown interface Ci.{{ interface}}", + unknownProperty: + "Use of unknown property Ci.{{ interface }}.{{ property }}", + }, + schema: [], + type: "problem", + }, + + create(context) { + return { + MemberExpression(node) { + if ( + node.computed === false && + node.type === "MemberExpression" && + node.object.type === "Identifier" && + node.object.name === "Ci" && + node.property.type === "Identifier" && + node.property.name.includes("I") + ) { + if (!helpers.xpidlData.get(node.property.name)) { + let platformSpecific = platformSpecificInterfaces.get( + node.property.name + ); + if (!platformSpecific) { + context.report({ + node, + messageId: "unknownInterface", + data: { + interface: node.property.name, + }, + }); + } else if (platformSpecific == os.platform) { + context.report({ + node, + messageId: "missingInterface", + data: { + interface: node.property.name, + }, + }); + } + } + } + + if ( + node.computed === false && + node.object.type === "MemberExpression" && + node.object.object.type === "Identifier" && + node.object.object.name === "Ci" && + node.object.property.type === "Identifier" && + node.object.property.name.includes("I") && + node.property.type === "Identifier" + ) { + if ( + !interfaceHasProperty(node.object.property.name, node.property.name) + ) { + context.report({ + node, + messageId: "unknownProperty", + data: { + interface: node.object.property.name, + property: node.property.name, + }, + }); + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-lazy.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-lazy.js new file mode 100644 index 0000000000..048ed17e3e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-lazy.js @@ -0,0 +1,276 @@ +/** + * @fileoverview Ensures that definitions and uses of properties on the + * ``lazy`` object are valid. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; +const helpers = require("../helpers"); + +const items = [ + "loader", + "XPCOMUtils", + "Integration", + "ChromeUtils", + "DevToolsUtils", + "Object", + "Reflect", +]; + +const callExpressionDefinitions = [ + /^loader\.lazyGetter\(lazy, "(\w+)"/, + /^loader\.lazyServiceGetter\(lazy, "(\w+)"/, + /^loader\.lazyRequireGetter\(lazy, "(\w+)"/, + /^XPCOMUtils\.defineLazyGetter\(lazy, "(\w+)"/, + /^Integration\.downloads\.defineESModuleGetter\(lazy, "(\w+)"/, + /^ChromeUtils\.defineLazyGetter\(lazy, "(\w+)"/, + /^ChromeUtils\.defineModuleGetter\(lazy, "(\w+)"/, + /^XPCOMUtils\.defineLazyPreferenceGetter\(lazy, "(\w+)"/, + /^XPCOMUtils\.defineLazyScriptGetter\(lazy, "(\w+)"/, + /^XPCOMUtils\.defineLazyServiceGetter\(lazy, "(\w+)"/, + /^XPCOMUtils\.defineConstant\(lazy, "(\w+)"/, + /^DevToolsUtils\.defineLazyGetter\(lazy, "(\w+)"/, + /^Object\.defineProperty\(lazy, "(\w+)"/, + /^Reflect\.defineProperty\(lazy, "(\w+)"/, +]; + +const callExpressionMultiDefinitions = [ + "ChromeUtils.defineESModuleGetters(lazy,", + "XPCOMUtils.defineLazyModuleGetters(lazy,", + "XPCOMUtils.defineLazyServiceGetters(lazy,", + "Object.defineProperties(lazy,", + "loader.lazyRequireGetter(lazy,", +]; + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/valid-lazy.html", + }, + messages: { + duplicateSymbol: "Duplicate symbol {{name}} being added to lazy.", + incorrectType: "Unexpected literal for property name {{name}}", + unknownProperty: "Unknown lazy member property {{name}}", + unusedProperty: "Unused lazy property {{name}}", + topLevelAndUnconditional: + "Lazy property {{name}} is used at top-level unconditionally. It should be non-lazy.", + }, + schema: [], + type: "problem", + }, + + create(context) { + let lazyProperties = new Map(); + let unknownProperties = []; + let isLazyExported = false; + + function getAncestorNodes(node) { + const ancestors = []; + node = node.parent; + while (node) { + ancestors.unshift(node); + node = node.parent; + } + return ancestors; + } + + // Returns true if lazy getter definitions in prevNode and currNode are + // duplicate. + // This returns false if prevNode and currNode have the same IfStatement as + // ancestor and they're in different branches. + function isDuplicate(prevNode, currNode) { + const prevAncestors = getAncestorNodes(prevNode); + const currAncestors = getAncestorNodes(currNode); + + for ( + let i = 0; + i < prevAncestors.length && i < currAncestors.length; + i++ + ) { + const prev = prevAncestors[i]; + const curr = currAncestors[i]; + if (prev === curr && prev.type === "IfStatement") { + if (prevAncestors[i + 1] !== currAncestors[i + 1]) { + return false; + } + } + } + + return true; + } + + function addProp(callNode, propNode, name) { + if ( + lazyProperties.has(name) && + isDuplicate(lazyProperties.get(name).callNode, callNode) + ) { + context.report({ + node: propNode, + messageId: "duplicateSymbol", + data: { name }, + }); + return; + } + lazyProperties.set(name, { used: false, callNode, propNode }); + } + + function setPropertiesFromArgument(callNode, arg) { + if (arg.type === "ObjectExpression") { + for (let propNode of arg.properties) { + if (propNode.key.type == "Literal") { + context.report({ + node: propNode, + messageId: "incorrectType", + data: { name: propNode.key.value }, + }); + continue; + } + addProp(callNode, propNode, propNode.key.name); + } + } else if (arg.type === "ArrayExpression") { + for (let propNode of arg.elements) { + if (propNode.type != "Literal") { + continue; + } + addProp(callNode, propNode, propNode.value); + } + } + } + + return { + VariableDeclarator(node) { + if ( + node.id.type === "Identifier" && + node.id.name == "lazy" && + node.init.type == "CallExpression" && + node.init.callee.name == "createLazyLoaders" + ) { + setPropertiesFromArgument(node.init, node.init.arguments[0]); + } + }, + + CallExpression(node) { + if ( + node.callee.type != "MemberExpression" || + (node.callee.object.type == "MemberExpression" && + !items.includes(node.callee.object.object.name)) || + (node.callee.object.type != "MemberExpression" && + !items.includes(node.callee.object.name)) + ) { + return; + } + + let source; + try { + source = helpers.getASTSource(node); + } catch (e) { + return; + } + + for (let reg of callExpressionDefinitions) { + let match = source.match(reg); + if (match) { + if ( + lazyProperties.has(match[1]) && + isDuplicate(lazyProperties.get(match[1]).callNode, node) + ) { + context.report({ + node, + messageId: "duplicateSymbol", + data: { name: match[1] }, + }); + return; + } + lazyProperties.set(match[1], { + used: false, + callNode: node, + propNode: node, + }); + break; + } + } + + if ( + callExpressionMultiDefinitions.some(expr => + source.startsWith(expr) + ) && + node.arguments[1] + ) { + setPropertiesFromArgument(node, node.arguments[1]); + } + }, + + MemberExpression(node) { + if (node.computed || node.object.type !== "Identifier") { + return; + } + + let name; + if (node.object.name == "lazy") { + name = node.property.name; + } else { + return; + } + let property = lazyProperties.get(name); + if (!property) { + // These will be reported on Program:exit - some definitions may + // be after first use, so we need to wait until we've processed + // the whole file before reporting. + unknownProperties.push({ name, node }); + } else { + property.used = true; + } + if ( + helpers.getIsTopLevelAndUnconditionallyExecuted( + context.getAncestors() + ) + ) { + context.report({ + node, + messageId: "topLevelAndUnconditional", + data: { name }, + }); + } + }, + + ExportNamedDeclaration(node) { + for (const spec of node.specifiers) { + if (spec.local.name === "lazy") { + // If the lazy object is exported, do not check unused property. + isLazyExported = true; + break; + } + } + }, + + "Program:exit": function () { + for (let { name, node } of unknownProperties) { + let property = lazyProperties.get(name); + if (!property) { + context.report({ + node, + messageId: "unknownProperty", + data: { name }, + }); + } else { + property.used = true; + } + } + if (!isLazyExported) { + for (let [name, property] of lazyProperties.entries()) { + if (!property.used) { + context.report({ + node: property.propNode, + messageId: "unusedProperty", + data: { name }, + }); + } + } + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-services-property.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-services-property.js new file mode 100644 index 0000000000..8f665d6d8a --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-services-property.js @@ -0,0 +1,126 @@ +/** + * @fileoverview Ensures that property accesses on Services.<alias> are valid. + * Although this largely duplicates the valid-services rule, the checks here + * require an objdir and a manual run. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const helpers = require("../helpers"); + +function findInterfaceNames(name) { + let interfaces = []; + for (let [key, value] of Object.entries(helpers.servicesData)) { + if (value == name) { + interfaces.push(key); + } + } + return interfaces; +} + +function isInInterface(interfaceName, name) { + let interfaceDetails = helpers.xpidlData.get(interfaceName); + + // TODO: Bug 1790261 - check only methods if the expression is callable. + if (interfaceDetails.methods.some(m => m.name == name)) { + return true; + } + + if (interfaceDetails.consts.some(c => c.name == name)) { + return true; + } + + if (interfaceDetails.parent) { + return isInInterface(interfaceDetails.parent, name); + } + return false; +} + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/valid-services-property.html", + }, + messages: { + unknownProperty: + "Unknown property access Services.{{ alias }}.{{ propertyName }}, Interfaces: {{ checkedInterfaces }}", + }, + schema: [], + type: "problem", + }, + + create(context) { + let servicesInterfaceMap = helpers.servicesData; + let serviceAliases = new Set([ + ...Object.values(servicesInterfaceMap), + // This is defined only for Android, so most builds won't pick it up. + "androidBridge", + // These are defined without interfaces and hence are not in the services map. + "cpmm", + "crashmanager", + "mm", + "ppmm", + // The new xulStore also does not have an interface. + "xulStore", + ]); + return { + MemberExpression(node) { + if (node.computed || node.object.type !== "Identifier") { + return; + } + + let mainNode; + if (node.object.name == "Services") { + mainNode = node; + } else if ( + node.property.name == "Services" && + node.parent.type == "MemberExpression" + ) { + mainNode = node.parent; + } else { + return; + } + + let alias = mainNode.property.name; + if (!serviceAliases.has(alias)) { + return; + } + + if ( + mainNode.parent.type == "MemberExpression" && + !mainNode.parent.computed + ) { + let propertyName = mainNode.parent.property.name; + if (propertyName == "wrappedJSObject") { + return; + } + let interfaces = findInterfaceNames(alias); + if (!interfaces.length) { + return; + } + + let checkedInterfaces = []; + for (let item of interfaces) { + if (isInInterface(item, propertyName)) { + return; + } + checkedInterfaces.push(item); + } + context.report({ + node, + messageId: "unknownProperty", + data: { + alias, + propertyName, + checkedInterfaces, + }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-services.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-services.js new file mode 100644 index 0000000000..7380fda491 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/valid-services.js @@ -0,0 +1,68 @@ +/** + * @fileoverview Ensures that Services uses have valid property names. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; +const helpers = require("../helpers"); + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/valid-services.html", + }, + messages: { + unknownProperty: "Unknown Services member property {{ alias }}", + }, + schema: [], + type: "problem", + }, + + create(context) { + let servicesInterfaceMap = helpers.servicesData; + let serviceAliases = new Set([ + ...Object.values(servicesInterfaceMap), + // This is defined only for Android, so most builds won't pick it up. + "androidBridge", + // These are defined without interfaces and hence are not in the services map. + "cpmm", + "crashmanager", + "mm", + "ppmm", + // The new xulStore also does not have an interface. + "xulStore", + ]); + return { + MemberExpression(node) { + if (node.computed || node.object.type !== "Identifier") { + return; + } + + let alias; + if (node.object.name == "Services") { + alias = node.property.name; + } else if ( + node.property.name == "Services" && + node.parent.type == "MemberExpression" + ) { + alias = node.parent.property.name; + } else { + return; + } + + if (!serviceAliases.has(alias)) { + context.report({ + node, + messageId: "unknownProperty", + data: { + alias, + }, + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/var-only-at-top-level.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/var-only-at-top-level.js new file mode 100644 index 0000000000..5da799c643 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/var-only-at-top-level.js @@ -0,0 +1,42 @@ +/** + * @fileoverview Marks all var declarations that are not at the top level + * invalid. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +var helpers = require("../helpers"); + +module.exports = { + meta: { + docs: { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/var-only-at-top-level.html", + }, + messages: { + unexpectedVar: "Unexpected var, use let or const instead.", + }, + schema: [], + type: "suggestion", + }, + + create(context) { + return { + VariableDeclaration(node) { + if (node.kind === "var") { + if (helpers.getIsTopLevelScript(context.getAncestors())) { + return; + } + + context.report({ + node, + messageId: "unexpectedVar", + }); + } + }, + }; + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/services.json b/tools/lint/eslint/eslint-plugin-mozilla/lib/services.json new file mode 100644 index 0000000000..476c6bf784 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/services.json @@ -0,0 +1,63 @@ +{ + "mozIJSSubScriptLoader": "scriptloader", + "mozILocaleService": "locale", + "mozIMozIntl": "intl", + "mozIStorageService": "storage", + "nsIAppShellService": "appShell", + "nsIAppStartup": "startup", + "nsIBlocklistService": "blocklist", + "nsICacheStorageService": "cache2", + "nsICategoryManager": "catMan", + "nsIClearDataService": "clearData", + "nsIClipboard": "clipboard", + "nsIConsoleService": "console", + "nsICookieBannerService": "cookieBanners", + "nsICookieManager": "cookies", + "nsICookieService": "cookies", + "nsICrashReporter": "appinfo", + "nsIDAPTelemetry": "DAPTelemetry", + "nsIDOMRequestService": "DOMRequest", + "nsIDOMStorageManager": "domStorageManager", + "nsIDNSService": "dns", + "nsIDirectoryService": "dirsvc", + "nsIDroppedLinkHandler": "droppedLinkHandler", + "nsIEffectiveTLDService": "eTLD", + "nsIEnterprisePolicies": "policies", + "nsIEnvironment": "env", + "nsIEventListenerService": "els", + "nsIFOG": "fog", + "nsIFocusManager": "focus", + "nsIIOService": "io", + "nsILoadContextInfoFactory": "loadContextInfo", + "nsILocalStorageManager": "domStorageManager", + "nsILoginManager": "logins", + "nsINetUtil": "io", + "nsIObserverService": "obs", + "nsIPermissionManager": "perms", + "nsIPrefBranch": "prefs", + "nsIPrefService": "prefs", + "nsIProfiler": "profiler", + "nsIPromptService": "prompt", + "nsIProperties": "dirsvc", + "nsIPropertyBag2": "sysinfo", + "nsIQuotaManagerService": "qms", + "nsIRFPService": "rfp", + "nsIScriptSecurityManager": "scriptSecurityManager", + "nsISearchService": "search", + "nsISessionStorageService": "sessionStorage", + "nsISpeculativeConnect": "io", + "nsIStringBundleService": "strings", + "nsISystemInfo": "sysinfo", + "nsITelemetry": "telemetry", + "nsITextToSubURI": "textToSubURI", + "nsIThreadManager": "tm", + "nsIURIFixup": "uriFixup", + "nsIURLFormatter": "urlFormatter", + "nsIUUIDGenerator": "uuid", + "nsIVersionComparator": "vc", + "nsIWindowMediator": "wm", + "nsIWindowWatcher": "ww", + "nsIXULAppInfo": "appinfo", + "nsIXULRuntime": "appinfo", + "nsIXULStore": "xulStore" +} diff --git a/tools/lint/eslint/eslint-plugin-mozilla/manifest.tt b/tools/lint/eslint/eslint-plugin-mozilla/manifest.tt new file mode 100644 index 0000000000..47ca98109b --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/manifest.tt @@ -0,0 +1,10 @@ +[ + { + "filename": "eslint-plugin-mozilla.tar.gz", + "size": 5546844, + "algorithm": "sha512", + "digest": "7df05ad96a7e892f04079570e7847cef71048e3d96e7a338f7e5aa431d5bf34225196200fffc42a630678f2bb074b806dd24d76da25827fbfc16d0ae5e8e6cd5", + "unpack": true, + "visibility": "public" + } +]
\ No newline at end of file diff --git a/tools/lint/eslint/eslint-plugin-mozilla/package-lock.json b/tools/lint/eslint/eslint-plugin-mozilla/package-lock.json new file mode 100644 index 0000000000..8265c41a94 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/package-lock.json @@ -0,0 +1,5249 @@ +{ + "name": "eslint-plugin-mozilla", + "version": "3.7.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "eslint-plugin-mozilla", + "version": "3.7.0", + "license": "MPL-2.0", + "dependencies": { + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "estraverse": "^5.3.0", + "htmlparser2": "^8.0.1", + "toml-eslint-parser": "0.9.3" + }, + "devDependencies": { + "eslint": "8.56.0", + "mocha": "10.2.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@microsoft/eslint-plugin-sdl": "^0.2.2", + "eslint": "^7.23.0 || ^8.0.0", + "eslint-config-prettier": "^8.0.0 || ^9.0.0", + "eslint-plugin-fetch-options": "^0.0.5", + "eslint-plugin-html": "^7.0.0", + "eslint-plugin-json": "^3.1.0", + "eslint-plugin-no-unsanitized": "^4.0.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" + }, + "node_modules/@microsoft/eslint-plugin-sdl": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@microsoft/eslint-plugin-sdl/-/eslint-plugin-sdl-0.2.2.tgz", + "integrity": "sha512-TiBepeQMSxHpvIbKA03TbO9nZqRrKR1th47wGdjY1sH2SSer+JgKlSF3S8GURGA8/zp2T/HwSiAJelclJ3hEvg==", + "peer": true, + "dependencies": { + "eslint-plugin-node": "11.1.0", + "eslint-plugin-react": "7.33.0", + "eslint-plugin-security": "1.4.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "eslint": "^4.19.1 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", + "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "peer": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", + "integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "peer": true, + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "peer": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "peer": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "peer": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "peer": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "peer": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "peer": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "peer": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "peer": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-fetch-options": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-fetch-options/-/eslint-plugin-fetch-options-0.0.5.tgz", + "integrity": "sha512-ZMxrccsOAZ7uMQ4nMvPJLqLg6oyLF96YOEwTKWAIbDHpwWUp1raXALZom8ikKucaEnhqWSRuBWI8jBXveFwkJg==", + "peer": true, + "engines": { + "node": ">=0.9.0" + } + }, + "node_modules/eslint-plugin-html": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-7.1.0.tgz", + "integrity": "sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==", + "peer": true, + "dependencies": { + "htmlparser2": "^8.0.1" + } + }, + "node_modules/eslint-plugin-json": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-3.1.0.tgz", + "integrity": "sha512-MrlG2ynFEHe7wDGwbUuFPsaT2b1uhuEFhJ+W1f1u+1C2EkXmTYJp4B1aAdQQ8M+CC3t//N/oRKiIVw14L2HR1g==", + "peer": true, + "dependencies": { + "lodash": "^4.17.21", + "vscode-json-languageservice": "^4.1.6" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/eslint-plugin-no-unsanitized": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.2.tgz", + "integrity": "sha512-Pry0S9YmHoz8NCEMRQh7N0Yexh2MYCNPIlrV52hTmS7qXnTghWsjXouF08bgsrrZqaW9tt1ZiK3j5NEmPE+EjQ==", + "peer": true, + "peerDependencies": { + "eslint": "^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "peer": true, + "dependencies": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.33.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.0.tgz", + "integrity": "sha512-qewL/8P34WkY8jAqdQxsiL82pDUeT7nhs8IsuXgfgnsEloKCT4miAV9N9kGtx7/KM9NH/NCGUE7Edt9iGxLXFw==", + "peer": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "peer": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-security": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-1.4.0.tgz", + "integrity": "sha512-xlS7P2PLMXeqfhyf3NpqbvbnW04kN8M9NtmhpR3XGyOvt/vNKS7XPXT5EDbwKW9vCjWH4PpfQvgD/+JgN0VJKA==", + "peer": true, + "dependencies": { + "safe-regex": "^1.1.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "peer": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "node_modules/fastq": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", + "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "peer": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "peer": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "peer": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "peer": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "peer": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "peer": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "peer": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "peer": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "peer": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "peer": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "peer": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "peer": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "peer": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "peer": true + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "peer": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "peer": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "peer": true, + "dependencies": { + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "peer": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "peer": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "peer": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "peer": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "peer": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "peer": true, + "dependencies": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "peer": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toml-eslint-parser": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/toml-eslint-parser/-/toml-eslint-parser-0.9.3.tgz", + "integrity": "sha512-moYoCvkNUAPCxSW9jmHmRElhm4tVJpHL8ItC/+uYD0EpPSFXbck7yREz9tNdJVTSpHVod8+HoipcpbQ0oE6gsw==", + "dependencies": { + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "peer": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vscode-json-languageservice": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz", + "integrity": "sha512-xGmv9QIWs2H8obGbWg+sIPI/3/pFgj/5OWBhNzs00BkYQ9UaB2F6JJaGB/2/YOZJ3BvLXQTC4Q7muqU25QgAhA==", + "peer": true, + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-languageserver-textdocument": "^1.0.3", + "vscode-languageserver-types": "^3.16.0", + "vscode-nls": "^5.0.0", + "vscode-uri": "^3.0.3" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", + "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==", + "peer": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "peer": true + }, + "node_modules/vscode-nls": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", + "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "peer": true + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "peer": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "peer": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "peer": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==" + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==" + }, + "@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==" + }, + "@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "requires": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" + }, + "@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" + }, + "@microsoft/eslint-plugin-sdl": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@microsoft/eslint-plugin-sdl/-/eslint-plugin-sdl-0.2.2.tgz", + "integrity": "sha512-TiBepeQMSxHpvIbKA03TbO9nZqRrKR1th47wGdjY1sH2SSer+JgKlSF3S8GURGA8/zp2T/HwSiAJelclJ3hEvg==", + "peer": true, + "requires": { + "eslint-plugin-node": "11.1.0", + "eslint-plugin-react": "7.33.0", + "eslint-plugin-security": "1.4.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==" + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + } + }, + "array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.tosorted": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", + "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "peer": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, + "available-typed-arrays": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", + "integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==", + "peer": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "peer": true, + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "peer": true, + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "peer": true, + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "peer": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + } + }, + "es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "peer": true, + "requires": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "peer": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "peer": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + } + }, + "eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "peer": true, + "requires": {} + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "peer": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, + "eslint-plugin-fetch-options": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-fetch-options/-/eslint-plugin-fetch-options-0.0.5.tgz", + "integrity": "sha512-ZMxrccsOAZ7uMQ4nMvPJLqLg6oyLF96YOEwTKWAIbDHpwWUp1raXALZom8ikKucaEnhqWSRuBWI8jBXveFwkJg==", + "peer": true + }, + "eslint-plugin-html": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-7.1.0.tgz", + "integrity": "sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==", + "peer": true, + "requires": { + "htmlparser2": "^8.0.1" + } + }, + "eslint-plugin-json": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-3.1.0.tgz", + "integrity": "sha512-MrlG2ynFEHe7wDGwbUuFPsaT2b1uhuEFhJ+W1f1u+1C2EkXmTYJp4B1aAdQQ8M+CC3t//N/oRKiIVw14L2HR1g==", + "peer": true, + "requires": { + "lodash": "^4.17.21", + "vscode-json-languageservice": "^4.1.6" + } + }, + "eslint-plugin-no-unsanitized": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.2.tgz", + "integrity": "sha512-Pry0S9YmHoz8NCEMRQh7N0Yexh2MYCNPIlrV52hTmS7qXnTghWsjXouF08bgsrrZqaW9tt1ZiK3j5NEmPE+EjQ==", + "peer": true, + "requires": {} + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "peer": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + } + }, + "eslint-plugin-react": { + "version": "7.33.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.0.tgz", + "integrity": "sha512-qewL/8P34WkY8jAqdQxsiL82pDUeT7nhs8IsuXgfgnsEloKCT4miAV9N9kGtx7/KM9NH/NCGUE7Edt9iGxLXFw==", + "peer": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.8" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "peer": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "peer": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-plugin-security": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-1.4.0.tgz", + "integrity": "sha512-xlS7P2PLMXeqfhyf3NpqbvbnW04kN8M9NtmhpR3XGyOvt/vNKS7XPXT5EDbwKW9vCjWH4PpfQvgD/+JgN0VJKA==", + "peer": true, + "requires": { + "safe-regex": "^1.1.0" + } + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "peer": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "peer": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==" + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "fastq": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", + "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "peer": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "peer": true + }, + "function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "peer": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "peer": true, + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "peer": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "peer": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "peer": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "peer": true, + "requires": { + "get-intrinsic": "^1.2.2" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "peer": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "peer": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "peer": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "peer": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "peer": true, + "requires": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "peer": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "peer": true + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "peer": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "peer": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "peer": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "peer": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "peer": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "peer": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "peer": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "peer": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "peer": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "peer": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "peer": true + }, + "jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "peer": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + } + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "requires": { + "json-buffer": "3.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "peer": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "peer": true + }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "peer": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "peer": true + }, + "object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "peer": true, + "requires": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "object.hasown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "peer": true, + "requires": { + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "peer": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "peer": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "peer": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "peer": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "peer": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-array-concat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "peer": true, + "requires": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "peer": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safe-regex-test": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "peer": true, + "requires": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "is-regex": "^1.1.4" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-function-length": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "peer": true, + "requires": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + } + }, + "set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "peer": true, + "requires": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "peer": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.matchall": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "peer": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toml-eslint-parser": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/toml-eslint-parser/-/toml-eslint-parser-0.9.3.tgz", + "integrity": "sha512-moYoCvkNUAPCxSW9jmHmRElhm4tVJpHL8ItC/+uYD0EpPSFXbck7yREz9tNdJVTSpHVod8+HoipcpbQ0oE6gsw==", + "requires": { + "eslint-visitor-keys": "^3.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "peer": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "peer": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "vscode-json-languageservice": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz", + "integrity": "sha512-xGmv9QIWs2H8obGbWg+sIPI/3/pFgj/5OWBhNzs00BkYQ9UaB2F6JJaGB/2/YOZJ3BvLXQTC4Q7muqU25QgAhA==", + "peer": true, + "requires": { + "jsonc-parser": "^3.0.0", + "vscode-languageserver-textdocument": "^1.0.3", + "vscode-languageserver-types": "^3.16.0", + "vscode-nls": "^5.0.0", + "vscode-uri": "^3.0.3" + } + }, + "vscode-languageserver-textdocument": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", + "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==", + "peer": true + }, + "vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "peer": true + }, + "vscode-nls": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", + "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "peer": true + }, + "vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "peer": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "peer": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "peer": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } +} diff --git a/tools/lint/eslint/eslint-plugin-mozilla/package.json b/tools/lint/eslint/eslint-plugin-mozilla/package.json new file mode 100644 index 0000000000..9d4a111dd2 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/package.json @@ -0,0 +1,53 @@ +{ + "name": "eslint-plugin-mozilla", + "version": "3.7.0", + "description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla project.", + "keywords": [ + "eslint", + "eslintplugin", + "eslint-plugin", + "mozilla", + "firefox" + ], + "bugs": { + "url": "https://bugzilla.mozilla.org/enter_bug.cgi?product=Testing&component=Lint" + }, + "homepage": "http://firefox-source-docs.mozilla.org/tools/lint/linters/eslint-plugin-mozilla.html", + "repository": { + "type": "hg", + "url": "https://hg.mozilla.org/mozilla-central/" + }, + "author": "Mike Ratcliffe", + "main": "lib/index.js", + "dependencies": { + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "estraverse": "^5.3.0", + "htmlparser2": "^8.0.1", + "toml-eslint-parser": "0.9.3" + }, + "devDependencies": { + "eslint": "8.56.0", + "mocha": "10.2.0" + }, + "peerDependencies": { + "@microsoft/eslint-plugin-sdl": "^0.2.2", + "eslint": "^7.23.0 || ^8.0.0", + "eslint-config-prettier": "^8.0.0 || ^9.0.0", + "eslint-plugin-fetch-options": "^0.0.5", + "eslint-plugin-html": "^7.0.0", + "eslint-plugin-json": "^3.1.0", + "eslint-plugin-no-unsanitized": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "scripts": { + "prepack": "node scripts/createExports.js", + "test": "mocha --reporter 'reporters/mozilla-format.js' tests", + "postpublish": "rm -f lib/environments/saved-globals.json lib/rules/saved-rules-data.json", + "update-tooltool": "./update.sh" + }, + "license": "MPL-2.0" +} diff --git a/tools/lint/eslint/eslint-plugin-mozilla/reporters/mozilla-format.js b/tools/lint/eslint/eslint-plugin-mozilla/reporters/mozilla-format.js new file mode 100644 index 0000000000..a3f96e7bef --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/reporters/mozilla-format.js @@ -0,0 +1,57 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This file outputs the format that treeherder requires. If we integrate + * these tests with ./mach, then we may replace this with a json handler within + * mach itself. + */ + +"use strict"; + +var mocha = require("mocha"); +var path = require("path"); +module.exports = MozillaFormatter; + +function MozillaFormatter(runner) { + mocha.reporters.Base.call(this, runner); + var passes = 0; + var failures = []; + + runner.on("start", () => { + console.log("SUITE-START | eslint-plugin-mozilla"); + }); + + runner.on("pass", function (test) { + passes++; + let title = test.title.replace(/\n/g, "|"); + console.log(`TEST-PASS | ${path.basename(test.file)} | ${title}`); + }); + + runner.on("fail", function (test, err) { + failures.push(test); + // Replace any newlines in the title. + let title = test.title.replace(/\n/g, "|"); + console.log( + `TEST-UNEXPECTED-FAIL | ${path.basename(test.file)} | ${title} | ${ + err.message + }` + ); + mocha.reporters.Base.list([test]); + }); + + runner.on("end", function () { + // Space the results out visually with an additional blank line. + console.log(""); + console.log("INFO | Result summary:"); + console.log(`INFO | Passed: ${passes}`); + console.log(`INFO | Failed: ${failures.length}`); + console.log("SUITE-END"); + // Space the failures out visually with an additional blank line. + console.log(""); + console.log("Failure summary:"); + mocha.reporters.Base.list(failures); + process.exit(failures.length); + }); +} diff --git a/tools/lint/eslint/eslint-plugin-mozilla/scripts/createExports.js b/tools/lint/eslint/eslint-plugin-mozilla/scripts/createExports.js new file mode 100644 index 0000000000..7f839edfba --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/scripts/createExports.js @@ -0,0 +1,77 @@ +/** + * @fileoverview A script to export the known globals to a file. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +"use strict"; + +var fs = require("fs"); +var path = require("path"); +var helpers = require("../lib/helpers"); + +const eslintDir = path.join(helpers.rootDir, "tools", "lint", "eslint"); + +const globalsFile = path.join( + eslintDir, + "eslint-plugin-mozilla", + "lib", + "environments", + "saved-globals.json" +); +const rulesFile = path.join( + eslintDir, + "eslint-plugin-mozilla", + "lib", + "rules", + "saved-rules-data.json" +); + +console.log("Copying services.json"); + +const env = helpers.getBuildEnvironment(); + +const servicesFile = path.join( + env.topobjdir, + "xpcom", + "components", + "services.json" +); +const shipServicesFile = path.join( + eslintDir, + "eslint-plugin-mozilla", + "lib", + "services.json" +); + +fs.writeFileSync(shipServicesFile, fs.readFileSync(servicesFile)); + +console.log("Generating globals file"); + +// Export the environments. +let environmentGlobals = require("../lib/index.js").environments; + +return fs.writeFile( + globalsFile, + JSON.stringify({ environments: environmentGlobals }), + err => { + if (err) { + console.error(err); + process.exit(1); + } + + console.log("Globals file generation complete"); + + console.log("Creating rules data file"); + let rulesData = {}; + + return fs.writeFile(rulesFile, JSON.stringify({ rulesData }), err1 => { + if (err1) { + console.error(err1); + process.exit(1); + } + + console.log("Globals file generation complete"); + }); + } +); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-Date-timing.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-Date-timing.js new file mode 100644 index 0000000000..37fc424617 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-Date-timing.js @@ -0,0 +1,34 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/avoid-Date-timing"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, type, message) { + return { code, errors: [{ messageId: "usePerfNow", type }] }; +} + +ruleTester.run("avoid-Date-timing", rule, { + valid: [ + "new Date('2017-07-11');", + "new Date(1499790192440);", + "new Date(2017, 7, 11);", + "Date.UTC(2017, 7);", + ], + invalid: [ + invalidCode("Date.now();", "CallExpression"), + invalidCode("new Date();", "NewExpression"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js new file mode 100644 index 0000000000..3736f25853 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/avoid-removeChild"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, messageId = "useRemove") { + return { code, errors: [{ messageId, type: "CallExpression" }] }; +} + +ruleTester.run("avoid-removeChild", rule, { + valid: [ + "elt.remove();", + "elt.parentNode.parentNode.removeChild(elt2.parentNode);", + "elt.parentNode.removeChild(elt2);", + "elt.removeChild(elt2);", + ], + invalid: [ + invalidCode("elt.parentNode.removeChild(elt);"), + invalidCode("elt.parentNode.parentNode.removeChild(elt.parentNode);"), + invalidCode("$(e).parentNode.removeChild($(e));"), + invalidCode("$('e').parentNode.removeChild($('e'));"), + invalidCode("elt.removeChild(elt.firstChild);", "useFirstChildRemove"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js new file mode 100644 index 0000000000..b7cd4e2c2f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js @@ -0,0 +1,100 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/balanced-listeners"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function error(code, functionName, type) { + return { + code, + errors: [ + { + messageId: "noCorresponding", + type: "Identifier", + data: { functionName, type }, + }, + ], + }; +} + +ruleTester.run("balanced-listeners", rule, { + valid: [ + "elt.addEventListener('event', handler);" + + "elt.removeEventListener('event', handler);", + + "elt.addEventListener('event', handler, true);" + + "elt.removeEventListener('event', handler, true);", + + "elt.addEventListener('event', handler, false);" + + "elt.removeEventListener('event', handler, false);", + + "elt.addEventListener('event', handler);" + + "elt.removeEventListener('event', handler, false);", + + "elt.addEventListener('event', handler, false);" + + "elt.removeEventListener('event', handler);", + + "elt.addEventListener('event', handler, {capture: false});" + + "elt.removeEventListener('event', handler);", + + "elt.addEventListener('event', handler);" + + "elt.removeEventListener('event', handler, {capture: false});", + + "elt.addEventListener('event', handler, {capture: true});" + + "elt.removeEventListener('event', handler, true);", + + "elt.addEventListener('event', handler, true);" + + "elt.removeEventListener('event', handler, {capture: true});", + + "elt.addEventListener('event', handler, {once: true});", + + "elt.addEventListener('event', handler, {once: true, capture: true});", + ], + invalid: [ + error( + "elt.addEventListener('click', handler, false);", + "removeEventListener", + "click" + ), + + error( + "elt.addEventListener('click', handler, false);" + + "elt.removeEventListener('click', handler, true);", + "removeEventListener", + "click" + ), + + error( + "elt.addEventListener('click', handler, {capture: false});" + + "elt.removeEventListener('click', handler, true);", + "removeEventListener", + "click" + ), + + error( + "elt.addEventListener('click', handler, {capture: true});" + + "elt.removeEventListener('click', handler);", + "removeEventListener", + "click" + ), + + error( + "elt.addEventListener('click', handler, true);" + + "elt.removeEventListener('click', handler);", + "removeEventListener", + "click" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-observers.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-observers.js new file mode 100644 index 0000000000..97e578a1f4 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-observers.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/balanced-observers"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function error(code, observable) { + return { + code, + errors: [ + { + messageId: "noCorresponding", + type: "Identifier", + data: { observable }, + }, + ], + }; +} + +ruleTester.run("balanced-observers", rule, { + valid: [ + "Services.obs.addObserver(observer, 'observable');" + + "Services.obs.removeObserver(observer, 'observable');", + "Services.prefs.addObserver('preference.name', otherObserver);" + + "Services.prefs.removeObserver('preference.name', otherObserver);", + ], + invalid: [ + error( + // missing Services.obs.removeObserver + "Services.obs.addObserver(observer, 'observable');", + "observable" + ), + + error( + // wrong observable name for Services.obs.removeObserver + "Services.obs.addObserver(observer, 'observable');" + + "Services.obs.removeObserver(observer, 'different-observable');", + "observable" + ), + + error( + // missing Services.prefs.removeObserver + "Services.prefs.addObserver('preference.name', otherObserver);", + "preference.name" + ), + + error( + // wrong observable name for Services.prefs.removeObserver + "Services.prefs.addObserver('preference.name', otherObserver);" + + "Services.prefs.removeObserver('other.preference', otherObserver);", + "preference.name" + ), + + error( + // mismatch Services.prefs vs Services.obs + "Services.obs.addObserver(observer, 'observable');" + + "Services.prefs.removeObserver(observer, 'observable');", + "observable" + ), + + error( + "Services.prefs.addObserver('preference.name', otherObserver);" + + // mismatch Services.prefs vs Services.obs + "Services.obs.removeObserver('preference.name', otherObserver);", + "preference.name" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/consistent-if-bracing.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/consistent-if-bracing.js new file mode 100644 index 0000000000..9712fd9a78 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/consistent-if-bracing.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/consistent-if-bracing"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { code, errors: [{ messageId: "consistentIfBracing" }] }; +} + +ruleTester.run("consistent-if-bracing", rule, { + valid: [ + "if (true) {1} else {0}", + "if (false) 1; else 0", + "if (true) {1} else if (true) {2} else {0}", + "if (true) {1} else if (true) {2} else if (true) {3} else {0}", + ], + invalid: [ + invalidCode(`if (true) {1} else 0`), + invalidCode("if (true) 1; else {0}"), + invalidCode("if (true) {1} else if (true) 2; else {0}"), + invalidCode("if (true) 1; else if (true) {2} else {0}"), + invalidCode("if (true) {1} else if (true) {2} else 0"), + invalidCode("if (true) {1} else if (true) {2} else if (true) 3; else {0}"), + invalidCode("if (true) {if (true) 1; else {0}} else {0}"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/globals.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/globals.js new file mode 100644 index 0000000000..1098cb8a34 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/globals.js @@ -0,0 +1,161 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +var { getGlobalsForCode } = require("../lib/globals"); +var assert = require("assert"); + +/* global describe, it */ + +describe("globals", function () { + it("should reflect top-level this property assignment", function () { + const globals = getGlobalsForCode(` +this.foo = 10; +`); + assert.deepEqual(globals, [{ name: "foo", writable: true }]); + }); + + it("should reflect this property assignment inside block", function () { + const globals = getGlobalsForCode(` +{ + this.foo = 10; +} +`); + assert.deepEqual(globals, [{ name: "foo", writable: true }]); + }); + + it("should ignore this property assignment inside function declaration", function () { + const globals = getGlobalsForCode(` +function f() { + this.foo = 10; +} +`); + assert.deepEqual(globals, [{ name: "f", writable: true }]); + }); + + it("should ignore this property assignment inside function expression", function () { + const globals = getGlobalsForCode(` +(function f() { + this.foo = 10; +}); +`); + assert.deepEqual(globals, []); + }); + + it("should ignore this property assignment inside method", function () { + const globals = getGlobalsForCode(` +({ + method() { + this.foo = 10; + } +}); +`); + assert.deepEqual(globals, []); + }); + + it("should ignore this property assignment inside accessor", function () { + const globals = getGlobalsForCode(` +({ + get x() { + this.foo = 10; + }, + set x(v) { + this.bar = 10; + } +}); +`); + assert.deepEqual(globals, []); + }); + + it("should reflect this property assignment inside arrow function", function () { + const globals = getGlobalsForCode(` +() => { + this.foo = 10; +}; +`); + assert.deepEqual(globals, [{ name: "foo", writable: true }]); + }); + + it("should ignore this property assignment inside arrow function inside function expression", function () { + const globals = getGlobalsForCode(` +(function f() { + () => { + this.foo = 10; + }; +}); +`); + assert.deepEqual(globals, []); + }); + + it("should ignore this property assignment inside class static", function () { + const globals = getGlobalsForCode(` +class A { + static { + this.foo = 10; + (() => { + this.bar = 10; + })(); + } +} +`); + assert.deepEqual(globals, [{ name: "A", writable: true }]); + }); + + it("should ignore this property assignment inside class property", function () { + const globals = getGlobalsForCode(` +class A { + a = this.foo = 10; + b = (() => { + this.bar = 10; + })(); +} +`); + assert.deepEqual(globals, [{ name: "A", writable: true }]); + }); + + it("should ignore this property assignment inside class static property", function () { + const globals = getGlobalsForCode(` +class A { + static a = this.foo = 10; + static b = (() => { + this.bar = 10; + })(); +} +`); + assert.deepEqual(globals, [{ name: "A", writable: true }]); + }); + + it("should ignore this property assignment inside class private property", function () { + const globals = getGlobalsForCode(` +class A { + #a = this.foo = 10; + #b = (() => { + this.bar = 10; + })(); +} +`); + assert.deepEqual(globals, [{ name: "A", writable: true }]); + }); + + it("should ignore this property assignment inside class static private property", function () { + const globals = getGlobalsForCode(` +class A { + static #a = this.foo = 10; + static #b = (() => { + this.bar = 10; + })(); +} +`); + assert.deepEqual(globals, [{ name: "A", writable: true }]); + }); + + it("should reflect lazy getters", function () { + const globals = getGlobalsForCode(` +ChromeUtils.defineESModuleGetters(this, { + A: "B", +}); +`); + assert.deepEqual(globals, [{ name: "A", writable: true, explicit: true }]); + }); +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/lazy-getter-object-name.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/lazy-getter-object-name.js new file mode 100644 index 0000000000..33a2a6c130 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/lazy-getter-object-name.js @@ -0,0 +1,51 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/lazy-getter-object-name"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { + code, + errors: [{ messageId: "mustUseLazy", type: "CallExpression" }], + }; +} + +ruleTester.run("lazy-getter-object-name", rule, { + valid: [ + ` + ChromeUtils.defineESModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); +`, + ], + invalid: [ + invalidCode(` + ChromeUtils.defineESModuleGetters(obj, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); +`), + invalidCode(` + ChromeUtils.defineESModuleGetters(this, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); +`), + invalidCode(` + ChromeUtils.defineESModuleGetters(window, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); +`), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/mark-exported-symbols-as-used.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/mark-exported-symbols-as-used.js new file mode 100644 index 0000000000..e738825fab --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/mark-exported-symbols-as-used.js @@ -0,0 +1,45 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/mark-exported-symbols-as-used"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, type, messageId) { + return { code, errors: [{ messageId, type }] }; +} + +ruleTester.run("mark-exported-symbols-as-used", rule, { + valid: [ + "var EXPORTED_SYMBOLS = ['foo'];", + "this.EXPORTED_SYMBOLS = ['foo'];", + ], + invalid: [ + invalidCode( + "let EXPORTED_SYMBOLS = ['foo'];", + "VariableDeclaration", + "useLetForExported" + ), + invalidCode( + "var EXPORTED_SYMBOLS = 'foo';", + "VariableDeclaration", + "nonArrayAssignedToImported" + ), + invalidCode( + "this.EXPORTED_SYMBOLS = 'foo';", + "AssignmentExpression", + "nonArrayAssignedToImported" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-addtask-setup.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-addtask-setup.js new file mode 100644 index 0000000000..cd036d7d91 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-addtask-setup.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-addtask-setup"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError() { + return [{ messageId: "useAddSetup", type: "CallExpression" }]; +} + +ruleTester.run("no-addtask-setup", rule, { + valid: [ + "add_task(function() {});", + "add_task(function () {});", + "add_task(function foo() {});", + "add_task(async function() {});", + "add_task(async function () {});", + "add_task(async function foo() {});", + "something(function setup() {});", + "something(async function setup() {});", + "add_task(setup);", + "add_task(setup => {});", + "add_task(async setup => {});", + ], + invalid: [ + { + code: "add_task(function setup() {});", + output: "add_setup(function() {});", + errors: callError(), + }, + { + code: "add_task(function setup () {});", + output: "add_setup(function () {});", + errors: callError(), + }, + { + code: "add_task(async function setup() {});", + output: "add_setup(async function() {});", + errors: callError(), + }, + { + code: "add_task(async function setup () {});", + output: "add_setup(async function () {});", + errors: callError(), + }, + { + code: "add_task(async function setUp() {});", + output: "add_setup(async function() {});", + errors: callError(), + }, + { + code: "add_task(async function init() {});", + output: "add_setup(async function() {});", + errors: callError(), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-arbitrary-setTimeout.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-arbitrary-setTimeout.js new file mode 100644 index 0000000000..ea194af6e3 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-arbitrary-setTimeout.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-arbitrary-setTimeout"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function wrapCode(code, filename = "xpcshell/test_foo.js") { + return { code, filename }; +} + +function invalidCode(code) { + let obj = wrapCode(code); + obj.errors = [{ messageId: "listenForEvents", type: "CallExpression" }]; + return obj; +} + +ruleTester.run("no-arbitrary-setTimeout", rule, { + valid: [ + wrapCode("setTimeout(function() {}, 0);"), + wrapCode("setTimeout(function() {});"), + wrapCode("setTimeout(function() {}, 10);", "test_foo.js"), + ], + invalid: [ + invalidCode("setTimeout(function() {}, 10);"), + invalidCode("setTimeout(function() {}, timeout);"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-compare-against-boolean-literals.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-compare-against-boolean-literals.js new file mode 100644 index 0000000000..983ff0583e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-compare-against-boolean-literals.js @@ -0,0 +1,59 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-compare-against-boolean-literals"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError() { + return [{ messageId: "noCompareBoolean", type: "BinaryExpression" }]; +} + +ruleTester.run("no-compare-against-boolean-literals", rule, { + valid: [`if (!foo) {}`, `if (!!foo) {}`], + invalid: [ + { + code: `if (foo == true) {}`, + errors: callError(), + }, + { + code: `if (foo != true) {}`, + errors: callError(), + }, + { + code: `if (foo == false) {}`, + errors: callError(), + }, + { + code: `if (foo != false) {}`, + errors: callError(), + }, + { + code: `if (true == foo) {}`, + errors: callError(), + }, + { + code: `if (true != foo) {}`, + errors: callError(), + }, + { + code: `if (false == foo) {}`, + errors: callError(), + }, + { + code: `if (false != foo) {}`, + errors: callError(), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-comparison-or-assignment-inside-ok.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-comparison-or-assignment-inside-ok.js new file mode 100644 index 0000000000..3c43e5879f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-comparison-or-assignment-inside-ok.js @@ -0,0 +1,139 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-comparison-or-assignment-inside-ok"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, output, messageId, options = []) { + let rv = { + code, + errors: [{ messageId }], + }; + if (output) { + rv.output = output; + } + return rv; +} + +ruleTester.run("no-comparison-or-assignment-inside-ok", rule, { + valid: [ + "ok(foo)", + "ok(!bar)", + "ok(!foo, 'Message')", + "ok(bar, 'Message')", + "ok(!!foo, 'Message')", + ], + invalid: [ + // Assignment + invalidCode("ok(foo = bar)", null, "assignment"), + invalidCode("ok(foo = bar, 'msg')", null, "assignment"), + + // Comparisons: + invalidCode("ok(foo == bar)", "Assert.equal(foo, bar)", "comparison", { + operator: "==", + }), + invalidCode("ok(foo != bar)", "Assert.notEqual(foo, bar)", "comparison", { + operator: "!=", + }), + invalidCode("ok(foo < bar)", "Assert.less(foo, bar)", "comparison", { + operator: "<", + }), + invalidCode("ok(foo > bar)", "Assert.greater(foo, bar)", "comparison", { + operator: ">", + }), + invalidCode( + "ok(foo <= bar)", + "Assert.lessOrEqual(foo, bar)", + "comparison", + { operator: "<=" } + ), + invalidCode( + "ok(foo >= bar)", + "Assert.greaterOrEqual(foo, bar)", + "comparison", + { operator: ">=" } + ), + invalidCode( + "ok(foo === bar)", + "Assert.strictEqual(foo, bar)", + "comparison", + { operator: "===" } + ), + invalidCode( + "ok(foo !== bar)", + "Assert.notStrictEqual(foo, bar)", + "comparison", + { operator: "!==" } + ), + + // Comparisons with messages: + invalidCode( + "ok(foo == bar, 'hi')", + "Assert.equal(foo, bar, 'hi')", + "comparison", + { operator: "==" } + ), + invalidCode( + "ok(foo != bar, 'hi')", + "Assert.notEqual(foo, bar, 'hi')", + "comparison", + { operator: "!=" } + ), + invalidCode( + "ok(foo < bar, 'hi')", + "Assert.less(foo, bar, 'hi')", + "comparison", + { operator: "<" } + ), + invalidCode( + "ok(foo > bar, 'hi')", + "Assert.greater(foo, bar, 'hi')", + "comparison", + { operator: ">" } + ), + invalidCode( + "ok(foo <= bar, 'hi')", + "Assert.lessOrEqual(foo, bar, 'hi')", + "comparison", + { operator: "<=" } + ), + invalidCode( + "ok(foo >= bar, 'hi')", + "Assert.greaterOrEqual(foo, bar, 'hi')", + "comparison", + { operator: ">=" } + ), + invalidCode( + "ok(foo === bar, 'hi')", + "Assert.strictEqual(foo, bar, 'hi')", + "comparison", + { operator: "===" } + ), + invalidCode( + "ok(foo !== bar, 'hi')", + "Assert.notStrictEqual(foo, bar, 'hi')", + "comparison", + { operator: "!==" } + ), + + // Confusing bits that break fixup: + invalidCode( + "async () => ok((await foo) === bar, 'Oh no')", + "async () => Assert.strictEqual(await foo, bar, 'Oh no')", + "comparison", + { operator: "===" } + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-cu-reportError.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-cu-reportError.js new file mode 100644 index 0000000000..6650c8bf4e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-cu-reportError.js @@ -0,0 +1,100 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-cu-reportError"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError() { + return [{ messageId: "useConsoleError", type: "CallExpression" }]; +} + +ruleTester.run("no-cu-reportError", rule, { + valid: [ + "console.error('foo')", + "Cu.cloneInto({}, {})", + "foo().catch(console.error)", + // TODO: Bug 1802347 - this should be treated as an error as well. + "Cu.reportError('foo', stack)", + ], + invalid: [ + { + code: "Cu.reportError('foo')", + output: "console.error('foo')", + errors: callError(), + }, + { + code: "Cu.reportError(bar)", + output: "console.error(bar)", + errors: callError(), + }, + { + code: "Cu.reportError(bar.stack)", + output: "console.error(bar.stack)", + errors: callError(), + }, + { + code: "foo().catch(Cu.reportError)", + output: "foo().catch(console.error)", + errors: callError(), + }, + { + code: "foo().then(bar, Cu.reportError)", + output: "foo().then(bar, console.error)", + errors: callError(), + }, + // When referencing identifiers/members, try to reference them rather + // than stringifying: + { + code: "Cu.reportError('foo' + e)", + output: "console.error('foo', e)", + errors: callError(), + }, + { + code: "Cu.reportError('foo' + msg.data)", + output: "console.error('foo', msg.data)", + errors: callError(), + }, + // Don't touch existing concatenation of literals (usually done for + // wrapping reasons) + { + code: "Cu.reportError('foo' + 'bar' + 'baz')", + output: "console.error('foo' + 'bar' + 'baz')", + errors: callError(), + }, + // Ensure things work when nested: + { + code: "Cu.reportError('foo' + e + 'baz')", + output: "console.error('foo', e, 'baz')", + errors: callError(), + }, + // Ensure things work when nested in different places: + { + code: "Cu.reportError('foo' + e + 'quux' + 'baz')", + output: "console.error('foo', e, 'quux' + 'baz')", + errors: callError(), + }, + { + code: "Cu.reportError('foo' + 'quux' + e + 'baz')", + output: "console.error('foo' + 'quux', e, 'baz')", + errors: callError(), + }, + // Ensure things work with parens changing order of operations: + { + code: "Cu.reportError('foo' + 'quux' + (e + 'baz'))", + output: "console.error('foo' + 'quux' + (e + 'baz'))", + errors: callError(), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-define-cc-etc.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-define-cc-etc.js new file mode 100644 index 0000000000..ed71f6087e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-define-cc-etc.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-define-cc-etc"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, varNames) { + if (!Array.isArray(varNames)) { + varNames = [varNames]; + } + return { + code, + errors: varNames.map(name => { + return { + messageId: "noSeparateDefinition", + data: { name }, + type: "VariableDeclarator", + }; + }), + }; +} + +ruleTester.run("no-define-cc-etc", rule, { + valid: [ + "var Cm = Components.manager;", + "const CC = Components.Constructor;", + "var {Constructor: CC, manager: Cm} = Components;", + "const {Constructor: CC, manager: Cm} = Components;", + "foo.Cc.test();", + "const {bar, ...foo} = obj;", + ], + invalid: [ + invalidCode("var Cc;", "Cc"), + invalidCode("let Cc;", "Cc"), + invalidCode("let Ci;", "Ci"), + invalidCode("let Cr;", "Cr"), + invalidCode("let Cu;", "Cu"), + invalidCode("var Cc = Components.classes;", "Cc"), + invalidCode("const {classes: Cc} = Components;", "Cc"), + invalidCode("let {classes: Cc, manager: Cm} = Components", "Cc"), + invalidCode("const Cu = Components.utils;", "Cu"), + invalidCode("var Ci = Components.interfaces, Cc = Components.classes;", [ + "Ci", + "Cc", + ]), + invalidCode("var {'interfaces': Ci, 'classes': Cc} = Components;", [ + "Ci", + "Cc", + ]), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-redeclare-with-import-autofix.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-redeclare-with-import-autofix.js new file mode 100644 index 0000000000..36842000d5 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-redeclare-with-import-autofix.js @@ -0,0 +1,77 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-redeclare-with-import-autofix"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, output, messageId, options = []) { + let rv = { + code, + errors: [{ messageId }], + options, + }; + if (output) { + rv.output = output; + } + return rv; +} + +ruleTester.run("no-redeclare-with-import-autofix", rule, { + valid: [ + 'const foo = "whatever";', + 'let foo = "whatever";', + 'const {foo} = {foo: "whatever"};', + 'const {foo} = ChromeUtils.import("foo.jsm")', + 'let {foo} = ChromeUtils.import("foo.jsm")', + 'const {foo} = ChromeUtils.importESModule("foo.sys.mjs")', + 'let {foo} = ChromeUtils.importESModule("foo.sys.mjs")', + ], + invalid: [ + invalidCode( + `var {foo} = ChromeUtils.importESModule("foo.sys.mjs"); +var {foo} = ChromeUtils.importESModule("foo.sys.mjs");`, + 'var {foo} = ChromeUtils.importESModule("foo.sys.mjs");\n', + "duplicateImport" + ), + invalidCode( + `var {foo} = ChromeUtils.import("foo.jsm"); +var {foo} = ChromeUtils.import("foo.jsm");`, + 'var {foo} = ChromeUtils.import("foo.jsm");\n', + "duplicateImport" + ), + + invalidCode( + `var {foo} = ChromeUtils.import("foo.jsm"); +var {foo, bar} = ChromeUtils.import("foo.jsm");`, + `var {foo} = ChromeUtils.import("foo.jsm"); +var { bar} = ChromeUtils.import("foo.jsm");`, + "duplicateImport" + ), + + invalidCode( + `var {foo} = ChromeUtils.import("foo.jsm"); +var {bar, foo} = ChromeUtils.import("foo.jsm");`, + `var {foo} = ChromeUtils.import("foo.jsm"); +var {bar} = ChromeUtils.import("foo.jsm");`, + "duplicateImport" + ), + + invalidCode(`var foo = 5; var foo = 10;`, "", "redeclared", [ + { + errorForNonImports: true, + }, + ]), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-throw-cr-literal.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-throw-cr-literal.js new file mode 100644 index 0000000000..aecc5cd971 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-throw-cr-literal.js @@ -0,0 +1,62 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-throw-cr-literal"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, output, messageId) { + return { + code, + output, + errors: [{ messageId, type: "ThrowStatement" }], + }; +} + +ruleTester.run("no-throw-cr-literal", rule, { + valid: [ + 'throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);', + 'throw Components.Exception("", Components.results.NS_ERROR_UNEXPECTED);', + 'function t() { throw Components.Exception("", Cr.NS_ERROR_NO_CONTENT); }', + // We don't handle combined values, regular no-throw-literal catches them + 'throw Components.results.NS_ERROR_UNEXPECTED + "whoops";', + ], + invalid: [ + invalidCode( + "throw Cr.NS_ERROR_NO_INTERFACE;", + 'throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);', + "bareCR" + ), + invalidCode( + "throw Components.results.NS_ERROR_ABORT;", + 'throw Components.Exception("", Components.results.NS_ERROR_ABORT);', + "bareComponentsResults" + ), + invalidCode( + "function t() { throw Cr.NS_ERROR_NULL_POINTER; }", + 'function t() { throw Components.Exception("", Cr.NS_ERROR_NULL_POINTER); }', + "bareCR" + ), + invalidCode( + "throw new Error(Cr.NS_ERROR_ABORT);", + 'throw Components.Exception("", Cr.NS_ERROR_ABORT);', + "newErrorCR" + ), + invalidCode( + "throw new Error(Components.results.NS_ERROR_ABORT);", + 'throw Components.Exception("", Components.results.NS_ERROR_ABORT);', + "newErrorComponentsResults" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js new file mode 100644 index 0000000000..28d4d0d151 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js @@ -0,0 +1,175 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-useless-parameters"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError(messageId, data = {}) { + return [{ messageId, data, type: "CallExpression" }]; +} + +ruleTester.run("no-useless-parameters", rule, { + valid: [ + "Services.prefs.clearUserPref('browser.search.custom');", + "Services.removeObserver('notification name', {});", + "Services.io.newURI('http://example.com');", + "Services.io.newURI('http://example.com', 'utf8');", + "elt.addEventListener('click', handler);", + "elt.addEventListener('click', handler, true);", + "elt.addEventListener('click', handler, {once: true});", + "elt.removeEventListener('click', handler);", + "elt.removeEventListener('click', handler, true);", + "Services.obs.addObserver(this, 'topic', true);", + "Services.obs.addObserver(this, 'topic');", + "Services.prefs.addObserver('branch', this, true);", + "Services.prefs.addObserver('branch', this);", + "array.appendElement(elt);", + "Services.obs.notifyObservers(obj, 'topic', 'data');", + "Services.obs.notifyObservers(obj, 'topic');", + "window.getComputedStyle(elt);", + "window.getComputedStyle(elt, ':before');", + ], + invalid: [ + { + code: "Services.prefs.clearUserPref('browser.search.custom', false);", + output: "Services.prefs.clearUserPref('browser.search.custom');", + errors: callError("onlyTakes", { + fnName: "clearUserPref", + params: "1 parameter", + }), + }, + { + code: "Services.prefs.clearUserPref('browser.search.custom',\n false);", + output: "Services.prefs.clearUserPref('browser.search.custom');", + errors: callError("onlyTakes", { + fnName: "clearUserPref", + params: "1 parameter", + }), + }, + { + code: "Services.removeObserver('notification name', {}, false);", + output: "Services.removeObserver('notification name', {});", + errors: callError("onlyTakes", { + fnName: "removeObserver", + params: "2 parameters", + }), + }, + { + code: "Services.removeObserver('notification name', {}, true);", + output: "Services.removeObserver('notification name', {});", + errors: callError("onlyTakes", { + fnName: "removeObserver", + params: "2 parameters", + }), + }, + { + code: "Services.io.newURI('http://example.com', null, null);", + output: "Services.io.newURI('http://example.com');", + errors: callError("newURIParams"), + }, + { + code: "Services.io.newURI('http://example.com', 'utf8', null);", + output: "Services.io.newURI('http://example.com', 'utf8');", + errors: callError("newURIParams"), + }, + { + code: "Services.io.newURI('http://example.com', null);", + output: "Services.io.newURI('http://example.com');", + errors: callError("newURIParams"), + }, + { + code: "Services.io.newURI('http://example.com', '', '');", + output: "Services.io.newURI('http://example.com');", + errors: callError("newURIParams"), + }, + { + code: "Services.io.newURI('http://example.com', '');", + output: "Services.io.newURI('http://example.com');", + errors: callError("newURIParams"), + }, + { + code: "elt.addEventListener('click', handler, false);", + output: "elt.addEventListener('click', handler);", + errors: callError("obmittedWhenFalse", { + fnName: "addEventListener", + index: "third", + }), + }, + { + code: "elt.removeEventListener('click', handler, false);", + output: "elt.removeEventListener('click', handler);", + errors: callError("obmittedWhenFalse", { + fnName: "removeEventListener", + index: "third", + }), + }, + { + code: "Services.obs.addObserver(this, 'topic', false);", + output: "Services.obs.addObserver(this, 'topic');", + errors: callError("obmittedWhenFalse", { + fnName: "addObserver", + index: "third", + }), + }, + { + code: "Services.prefs.addObserver('branch', this, false);", + output: "Services.prefs.addObserver('branch', this);", + errors: callError("obmittedWhenFalse", { + fnName: "addObserver", + index: "third", + }), + }, + { + code: "array.appendElement(elt, false);", + output: "array.appendElement(elt);", + errors: callError("obmittedWhenFalse", { + fnName: "appendElement", + index: "second", + }), + }, + { + code: "Services.obs.notifyObservers(obj, 'topic', null);", + output: "Services.obs.notifyObservers(obj, 'topic');", + errors: callError("obmittedWhenFalse", { + fnName: "notifyObservers", + index: "third", + }), + }, + { + code: "Services.obs.notifyObservers(obj, 'topic', '');", + output: "Services.obs.notifyObservers(obj, 'topic');", + errors: callError("obmittedWhenFalse", { + fnName: "notifyObservers", + index: "third", + }), + }, + { + code: "window.getComputedStyle(elt, null);", + output: "window.getComputedStyle(elt);", + errors: callError("obmittedWhenFalse", { + fnName: "getComputedStyle", + index: "second", + }), + }, + { + code: "window.getComputedStyle(elt, '');", + output: "window.getComputedStyle(elt);", + errors: callError("obmittedWhenFalse", { + fnName: "getComputedStyle", + index: "second", + }), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js new file mode 100644 index 0000000000..f5fc60158d --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js @@ -0,0 +1,96 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-useless-removeEventListener"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { code, errors: [{ messageId: "useOnce", type: "CallExpression" }] }; +} + +ruleTester.run("no-useless-removeEventListener", rule, { + valid: [ + // Listeners that aren't a function are always valid. + "elt.addEventListener('click', handler);", + "elt.addEventListener('click', handler, true);", + "elt.addEventListener('click', handler, {once: true});", + + // Should not fail on empty functions. + "elt.addEventListener('click', function() {});", + + // Should not reject when removing a listener for another event. + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('keypress', listener);" + + "});", + + // Should not reject when there's another instruction before + // removeEventListener. + "elt.addEventListener('click', function listener() {" + + " elt.focus();" + + " elt.removeEventListener('click', listener);" + + "});", + + // Should not reject when wantsUntrusted is true. + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener);" + + "}, false, true);", + + // Should not reject when there's a literal and a variable + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener(eventName, listener);" + + "});", + + // Should not reject when there's 2 different variables + "elt.addEventListener(event1, function listener() {" + + " elt.removeEventListener(event2, listener);" + + "});", + + // Should not fail if this is a different type of event listener function. + "myfunc.addEventListener(listener);", + ], + invalid: [ + invalidCode( + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener);" + + "});" + ), + invalidCode( + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener, true);" + + "}, true);" + ), + invalidCode( + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener);" + + "}, {once: true});" + ), + invalidCode( + "elt.addEventListener('click', function listener() {" + + " /* Comment */" + + " elt.removeEventListener('click', listener);" + + "});" + ), + invalidCode( + "elt.addEventListener('click', function() {" + + " elt.removeEventListener('click', arguments.callee);" + + "});" + ), + invalidCode( + "elt.addEventListener(eventName, function listener() {" + + " elt.removeEventListener(eventName, listener);" + + "});" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-run-test.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-run-test.js new file mode 100644 index 0000000000..5ee6e0e575 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-run-test.js @@ -0,0 +1,126 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-useless-run-test"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, output) { + return { + code, + output, + errors: [{ messageId: "noUselessRunTest", type: "FunctionDeclaration" }], + }; +} + +ruleTester.run("no-useless-run-test", rule, { + valid: [ + "function run_test() {}", + "function run_test() {let args = 1; run_next_test();}", + "function run_test() {fakeCall(); run_next_test();}", + ], + invalid: [ + // Single-line case. + invalidCode("function run_test() { run_next_test(); }", ""), + // Multiple-line cases + invalidCode( + ` +function run_test() { + run_next_test(); +}`, + `` + ), + invalidCode( + ` +foo(); +function run_test() { + run_next_test(); +} +`, + ` +foo(); +` + ), + invalidCode( + ` +foo(); +function run_test() { + run_next_test(); +} +bar(); +`, + ` +foo(); +bar(); +` + ), + invalidCode( + ` +foo(); + +function run_test() { + run_next_test(); +} + +bar();`, + ` +foo(); + +bar();` + ), + invalidCode( + ` +foo(); + +function run_test() { + run_next_test(); +} + +// A comment +bar(); +`, + ` +foo(); + +// A comment +bar(); +` + ), + invalidCode( + ` +foo(); + +/** + * A useful comment. + */ +function run_test() { + run_next_test(); +} + +// A comment +bar(); +`, + ` +foo(); + +/** + * A useful comment. + */ + +// A comment +bar(); +` + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-boolean-length-check.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-boolean-length-check.js new file mode 100644 index 0000000000..102112a3f5 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-boolean-length-check.js @@ -0,0 +1,96 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/prefer-boolean-length-check"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidError() { + return [{ messageId: "preferBooleanCheck", type: "BinaryExpression" }]; +} + +ruleTester.run("check-length", rule, { + valid: [ + "if (foo.length && foo.length) {}", + "if (!foo.length) {}", + "if (foo.value == 0) {}", + "if (foo.value > 0) {}", + "if (0 == foo.value) {}", + "if (0 < foo.value) {}", + "var a = !!foo.length", + "function bar() { return !!foo.length }", + ], + invalid: [ + { + code: "if (foo.length == 0) {}", + output: "if (!foo.length) {}", + errors: invalidError(), + }, + { + code: "if (foo.length > 0) {}", + output: "if (foo.length) {}", + errors: invalidError(), + }, + { + code: "if (0 < foo.length) {}", + output: "if (foo.length) {}", + errors: invalidError(), + }, + { + code: "if (0 == foo.length) {}", + output: "if (!foo.length) {}", + errors: invalidError(), + }, + { + code: "if (foo && foo.length == 0) {}", + output: "if (foo && !foo.length) {}", + errors: invalidError(), + }, + { + code: "if (foo.bar.length == 0) {}", + output: "if (!foo.bar.length) {}", + errors: invalidError(), + }, + { + code: "var a = foo.length>0", + output: "var a = !!foo.length", + errors: invalidError(), + }, + { + code: "function bar() { return foo.length>0 }", + output: "function bar() { return !!foo.length }", + errors: invalidError(), + }, + { + code: "if (foo && bar.length>0) {}", + output: "if (foo && bar.length) {}", + errors: invalidError(), + }, + { + code: "while (foo && bar.length>0) {}", + output: "while (foo && bar.length) {}", + errors: invalidError(), + }, + { + code: "x = y && bar.length > 0", + output: "x = y && !!bar.length", + errors: invalidError(), + }, + { + code: "function bar() { return x && foo.length > 0}", + output: "function bar() { return x && !!foo.length}", + errors: invalidError(), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-formatValues.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-formatValues.js new file mode 100644 index 0000000000..4aa5cd1d3c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-formatValues.js @@ -0,0 +1,70 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/prefer-formatValues"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function error(line, column = undefined) { + return { + messageId: "useSingleCall", + type: "CallExpression", + line, + column, + }; +} + +ruleTester.run("check-length", rule, { + valid: [ + "document.l10n.formatValue('foobar');", + "document.l10n.formatValues(['foobar', 'foobaz']);", + `if (foo) { + document.l10n.formatValue('foobar'); + } else { + document.l10n.formatValue('foobaz'); + }`, + `document.l10n.formatValue('foobaz'); + if (foo) { + document.l10n.formatValue('foobar'); + }`, + `if (foo) { + document.l10n.formatValue('foobar'); + } + document.l10n.formatValue('foobaz');`, + `if (foo) { + document.l10n.formatValue('foobar'); + } + document.l10n.formatValues(['foobaz']);`, + ], + invalid: [ + { + code: `document.l10n.formatValue('foobar'); + document.l10n.formatValue('foobaz');`, + errors: [error(1, 1), error(2, 14)], + }, + { + code: `document.l10n.formatValue('foobar'); + if (foo) { + document.l10n.formatValue('foobiz'); + } + document.l10n.formatValue('foobaz');`, + errors: [error(1, 1), error(5, 14)], + }, + { + code: `document.l10n.formatValues('foobar'); + document.l10n.formatValue('foobaz');`, + errors: [error(1, 1), error(2, 14)], + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-addtask-only.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-addtask-only.js new file mode 100644 index 0000000000..f29726d9fc --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-addtask-only.js @@ -0,0 +1,54 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-addtask-only"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidError(output) { + return [ + { + messageId: "addTaskNotAllowed", + type: "CallExpression", + suggestions: [{ messageId: "addTaskNotAllowedSuggestion", output }], + }, + ]; +} + +ruleTester.run("reject-addtask-only", rule, { + valid: [ + "add_task(foo())", + "add_task(foo()).skip()", + "add_task(function() {})", + "add_task(function() {}).skip()", + ], + invalid: [ + { + code: "add_task(foo()).only()", + errors: invalidError("add_task(foo())"), + }, + { + code: "add_task(foo()).only(bar())", + errors: invalidError("add_task(foo())"), + }, + { + code: "add_task(function() {}).only()", + errors: invalidError("add_task(function() {})"), + }, + { + code: "add_task(function() {}).only(bar())", + errors: invalidError("add_task(function() {})"), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-chromeutils-import-params.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-chromeutils-import-params.js new file mode 100644 index 0000000000..c2b5fd9349 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-chromeutils-import-params.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-chromeutils-import-params"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidError(suggested) { + return [ + { + messageId: "importOnlyOneArg", + type: "CallExpression", + suggestions: [ + { + messageId: "importOnlyOneArgSuggestion", + output: suggested, + }, + ], + }, + ]; +} + +ruleTester.run("reject-chromeutils-import-params", rule, { + valid: ['ChromeUtils.import("resource://some/path/to/My.jsm")'], + invalid: [ + { + code: 'ChromeUtils.import("resource://some/path/to/My.jsm", null)', + errors: invalidError( + `ChromeUtils.import("resource://some/path/to/My.jsm")` + ), + }, + { + code: ` +ChromeUtils.import( + "resource://some/path/to/My.jsm", + null +);`, + errors: invalidError(` +ChromeUtils.import( + "resource://some/path/to/My.jsm" +);`), + }, + { + code: 'ChromeUtils.import("resource://some/path/to/My.jsm", this)', + errors: invalidError( + `ChromeUtils.import("resource://some/path/to/My.jsm")` + ), + }, + { + code: 'ChromeUtils.import("resource://some/path/to/My.jsm", foo, bar)', + errors: invalidError( + `ChromeUtils.import("resource://some/path/to/My.jsm")` + ), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-chromeutils-import.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-chromeutils-import.js new file mode 100644 index 0000000000..ced46f4a0f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-chromeutils-import.js @@ -0,0 +1,60 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-chromeutils-import"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const invalidError = [ + { + messageId: "useImportESModule", + type: "CallExpression", + }, +]; + +const invalidErrorLazy = [ + { + messageId: "useImportESModuleLazy", + type: "CallExpression", + }, +]; + +ruleTester.run("reject-chromeutils-import", rule, { + valid: [ + 'ChromeUtils.importESModule("resource://some/path/to/My.sys.mjs")', + 'ChromeUtils.defineESModuleGetters(obj, { My: "resource://some/path/to/My.sys.mjs" })', + ], + invalid: [ + { + code: 'ChromeUtils.import("resource://some/path/to/My.jsm")', + errors: invalidError, + }, + { + code: 'SpecialPowers.ChromeUtils.import("resource://some/path/to/My.jsm")', + errors: invalidError, + }, + { + code: 'ChromeUtils.defineModuleGetter(obj, "My", "resource://some/path/to/My.jsm")', + errors: invalidErrorLazy, + }, + { + code: 'SpecialPowers.ChromeUtils.defineModuleGetter(obj, "My", "resource://some/path/to/My.jsm")', + errors: invalidErrorLazy, + }, + { + code: 'XPCOMUtils.defineLazyModuleGetters(obj, { My: "resource://some/path/to/My.jsm" })', + errors: invalidErrorLazy, + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-eager-module-in-lazy-getter.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-eager-module-in-lazy-getter.js new file mode 100644 index 0000000000..490346b94a --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-eager-module-in-lazy-getter.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-eager-module-in-lazy-getter"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, uri) { + return { code, errors: [{ messageId: "eagerModule", data: { uri } }] }; +} + +ruleTester.run("reject-eager-module-in-lazy-getter", rule, { + valid: [ + ` + ChromeUtils.defineModuleGetter( + lazy, "Integration", "resource://gre/modules/Integration.jsm" + ); +`, + ` + XPCOMUtils.defineLazyModuleGetters(lazy, { + Integration: "resource://gre/modules/Integration.jsm", + }); +`, + ` + ChromeUtils.defineESModuleGetters(lazy, { + Integration: "resource://gre/modules/Integration.sys.mjs", + }); +`, + ], + invalid: [ + invalidCode( + ` + ChromeUtils.defineModuleGetter( + lazy, "XPCOMUtils", "resource://gre/modules/XPCOMUtils.jsm" + ); +`, + "resource://gre/modules/XPCOMUtils.jsm" + ), + invalidCode( + ` + XPCOMUtils.defineLazyModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.jsm", + }); +`, + "resource://gre/modules/AppConstants.jsm" + ), + invalidCode( + ` + ChromeUtils.defineESModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); +`, + "resource://gre/modules/AppConstants.sys.mjs" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-global-this.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-global-this.js new file mode 100644 index 0000000000..ec9ba711dc --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-global-this.js @@ -0,0 +1,51 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-global-this"); +var RuleTester = require("eslint").RuleTester; + +// class static block is available from ES2022 = 13. +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { + code, + errors: [{ messageId: "avoidGlobalThis", type: "ThisExpression" }], + }; +} + +ruleTester.run("reject-top-level-await", rule, { + valid: [ + "function f() { this; }", + "(function f() { this; });", + "({ foo() { this; } });", + "({ get foo() { this; } })", + "({ set foo(x) { this; } })", + "class X { foo() { this; } }", + "class X { get foo() { this; } }", + "class X { set foo(x) { this; } }", + "class X { static foo() { this; } }", + "class X { static get foo() { this; } }", + "class X { static set foo(x) { this; } }", + "class X { P = this; }", + "class X { #P = this; }", + "class X { static { this; } }", + ], + invalid: [ + invalidCode("this;"), + invalidCode("() => this;"), + + invalidCode("this.foo = 10;"), + invalidCode("ChromeUtils.defineModuleGetter(this, {});"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-globalThis-modification.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-globalThis-modification.js new file mode 100644 index 0000000000..c0244eaeab --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-globalThis-modification.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-globalThis-modification"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCall(code) { + return { + code, + errors: [ + { + messageId: "rejectPassingGlobalThis", + type: "CallExpression", + }, + ], + }; +} + +function invalidAssignment(code) { + return { + code, + errors: [ + { + messageId: "rejectModifyGlobalThis", + type: "AssignmentExpression", + }, + ], + }; +} + +ruleTester.run("reject-globalThis-modification", rule, { + valid: [ + `var x = globalThis.Array;`, + `Array in globalThis;`, + `result.deserialize(globalThis)`, + ], + invalid: [ + invalidAssignment(` + globalThis.foo = 10; +`), + invalidCall(` + Object.defineProperty(globalThis, "foo", { value: 10 }); +`), + invalidCall(` + Object.defineProperties(globalThis, { + foo: { value: 10 }, + }); +`), + invalidCall(` + Object.assign(globalThis, { foo: 10 }); +`), + invalidCall(` + ChromeUtils.defineModuleGetter( + globalThis, "AppConstants", "resource://gre/modules/AppConstants.jsm" + ); +`), + invalidCall(` + ChromeUtils.defineESMGetters(globalThis, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); +`), + invalidCall(` + XPCOMUtils.defineLazyModuleGetters(globalThis, { + AppConstants: "resource://gre/modules/AppConstants.jsm", + }); +`), + invalidCall(` + someFunction(1, globalThis); +`), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-import-system-module-from-non-system.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-import-system-module-from-non-system.js new file mode 100644 index 0000000000..5b09007626 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-import-system-module-from-non-system.js @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-import-system-module-from-non-system"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ + parserOptions: { ecmaVersion: "latest", sourceType: "module" }, +}); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +ruleTester.run("reject-import-system-module-from-non-system", rule, { + valid: [ + { + code: `const { AppConstants } = ChromeUtils.importESM("resource://gre/modules/AppConstants.sys.mjs");`, + }, + ], + invalid: [ + { + code: `import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";`, + errors: [{ messageId: "rejectStaticImportSystemModuleFromNonSystem" }], + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-importGlobalProperties.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-importGlobalProperties.js new file mode 100644 index 0000000000..7f796abae7 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-importGlobalProperties.js @@ -0,0 +1,89 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-importGlobalProperties"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +ruleTester.run("reject-importGlobalProperties", rule, { + valid: [ + { + code: "Cu.something();", + }, + { + options: ["allownonwebidl"], + code: "Cu.importGlobalProperties(['caches'])", + }, + { + options: ["allownonwebidl"], + code: "XPCOMUtils.defineLazyGlobalGetters(this, ['caches'])", + }, + ], + invalid: [ + { + code: "Cu.importGlobalProperties(['fetch'])", + options: ["everything"], + errors: [{ messageId: "unexpectedCall" }], + }, + { + code: "XPCOMUtils.defineLazyGlobalGetters(this, ['fetch'])", + options: ["everything"], + errors: [{ messageId: "unexpectedCall" }], + }, + { + code: "Cu.importGlobalProperties(['TextEncoder'])", + options: ["everything"], + errors: [{ messageId: "unexpectedCall" }], + }, + { + options: ["everything"], + code: "XPCOMUtils.defineLazyGlobalGetters(this, ['TextEncoder'])", + errors: [{ messageId: "unexpectedCallSjs" }], + filename: "foo.sjs", + }, + { + code: "XPCOMUtils.defineLazyGlobalGetters(this, ['TextEncoder'])", + options: ["everything"], + errors: [{ messageId: "unexpectedCall" }], + }, + { + code: "Cu.importGlobalProperties(['TextEncoder'])", + options: ["allownonwebidl"], + errors: [{ messageId: "unexpectedCallCuWebIdl" }], + }, + { + code: "XPCOMUtils.defineLazyGlobalGetters(this, ['TextEncoder'])", + options: ["allownonwebidl"], + errors: [{ messageId: "unexpectedCallXPCOMWebIdl" }], + }, + { + options: ["allownonwebidl"], + code: "Cu.importGlobalProperties(['TextEncoder'])", + errors: [{ messageId: "unexpectedCallCuWebIdl" }], + filename: "foo.js", + }, + { + options: ["allownonwebidl"], + code: "XPCOMUtils.defineLazyGlobalGetters(this, ['TextEncoder'])", + errors: [{ messageId: "unexpectedCallXPCOMWebIdl" }], + filename: "foo.js", + }, + { + options: ["allownonwebidl"], + code: "Cu.importGlobalProperties(['TextEncoder'])", + errors: [{ messageId: "unexpectedCallCuWebIdl" }], + filename: "foo.sjs", + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-lazy-imports-into-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-lazy-imports-into-globals.js new file mode 100644 index 0000000000..2c50c5524d --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-lazy-imports-into-globals.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-lazy-imports-into-globals"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ + parserOptions: { ecmaVersion: "latest", sourceType: "module" }, +}); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { code, errors: [{ messageId: "rejectLazyImportsIntoGlobals" }] }; +} + +ruleTester.run("reject-lazy-imports-into-globals", rule, { + valid: [ + ` + const lazy = {}; + ChromeUtils.defineLazyGetter(lazy, "foo", () => {}); + `, + ], + invalid: [ + invalidCode(`ChromeUtils.defineLazyGetter(globalThis, "foo", () => {});`), + invalidCode(`ChromeUtils.defineLazyGetter(window, "foo", () => {});`), + invalidCode( + `XPCOMUtils.defineLazyPreferenceGetter(globalThis, "foo", "foo.bar");` + ), + invalidCode( + `XPCOMUtils.defineLazyServiceGetter(globalThis, "foo", "@foo", "nsIFoo");` + ), + invalidCode(`XPCOMUtils.defineLazyGlobalGetters(globalThis, {});`), + invalidCode(`XPCOMUtils.defineLazyGlobalGetters(window, {});`), + invalidCode(`XPCOMUtils.defineLazyModuleGetters(globalThis, {});`), + invalidCode(`ChromeUtils.defineESModuleGetters(window, {});`), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-mixing-eager-and-lazy.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-mixing-eager-and-lazy.js new file mode 100644 index 0000000000..af0dd99c22 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-mixing-eager-and-lazy.js @@ -0,0 +1,104 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-mixing-eager-and-lazy"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ + parserOptions: { ecmaVersion: "latest", sourceType: "module" }, +}); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, uri) { + return { code, errors: [{ messageId: "mixedEagerAndLazy", data: { uri } }] }; +} + +ruleTester.run("reject-mixing-eager-and-lazy", rule, { + valid: [ + ` + ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); +`, + ` + ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs"); +`, + ` + import{ AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; +`, + ` + ChromeUtils.defineModuleGetter( + lazy, "AppConstants", "resource://gre/modules/AppConstants.jsm" + ); +`, + ` + XPCOMUtils.defineLazyModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.jsm", + }); +`, + ` + ChromeUtils.defineESModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); +`, + ` + if (some_condition) { + ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); + } + XPCOMUtils.defineLazyModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.jsm" + }); +`, + ` + ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); + XPCOMUtils.defineLazyModuleGetters(sandbox, { + AppConstants: "resource://gre/modules/AppConstants.jsm", + }); +`, + ], + invalid: [ + invalidCode( + ` + ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); + ChromeUtils.defineModuleGetter( + lazy, "AppConstants", "resource://gre/modules/AppConstants.jsm" + ); +`, + "resource://gre/modules/AppConstants.jsm" + ), + invalidCode( + ` + ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); + XPCOMUtils.defineLazyModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.jsm", + }); +`, + "resource://gre/modules/AppConstants.jsm" + ), + invalidCode( + ` + ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs"); + ChromeUtils.defineESModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); +`, + "resource://gre/modules/AppConstants.sys.mjs" + ), + invalidCode( + ` + import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; + ChromeUtils.defineESModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); +`, + "resource://gre/modules/AppConstants.sys.mjs" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-multiple-getters-calls.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-multiple-getters-calls.js new file mode 100644 index 0000000000..a2b88a8652 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-multiple-getters-calls.js @@ -0,0 +1,60 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-multiple-getters-calls"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { code, errors: [{ messageId: "rejectMultipleCalls" }] }; +} + +ruleTester.run("reject-multiple-getters-calls", rule, { + valid: [ + ` + ChromeUtils.defineESModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", + }); + `, + ` + ChromeUtils.defineESModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); + ChromeUtils.defineESModuleGetters(window, { + PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", + }); + `, + ` + ChromeUtils.defineESModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); + if (cond) { + ChromeUtils.defineESModuleGetters(lazy, { + PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", + }); + } + `, + ], + invalid: [ + invalidCode(` + ChromeUtils.defineESModuleGetters(lazy, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + }); + ChromeUtils.defineESModuleGetters(lazy, { + PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", + }); + `), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-relative-requires.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-relative-requires.js new file mode 100644 index 0000000000..a7bad6f992 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-relative-requires.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-relative-requires"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidError() { + return [{ messageId: "rejectRelativeRequires", type: "CallExpression" }]; +} + +ruleTester.run("reject-relative-requires", rule, { + valid: [ + 'require("devtools/absolute/path")', + 'require("resource://gre/modules/SomeModule.jsm")', + 'loader.lazyRequireGetter(this, "path", "devtools/absolute/path", true)', + 'loader.lazyRequireGetter(this, "Path", "devtools/absolute/path")', + ], + invalid: [ + { + code: 'require("./relative/path")', + errors: invalidError(), + }, + { + code: 'require("../parent/folder/path")', + errors: invalidError(), + }, + { + code: 'loader.lazyRequireGetter(this, "path", "./relative/path", true)', + errors: invalidError(), + }, + { + code: 'loader.lazyRequireGetter(this, "path", "../parent/folder/path", true)', + errors: invalidError(), + }, + { + code: 'loader.lazyRequireGetter(this, "path", "./relative/path")', + errors: invalidError(), + }, + { + code: 'loader.lazyRequireGetter(this, "path", "../parent/folder/path")', + errors: invalidError(), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-scriptableunicodeconverter.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-scriptableunicodeconverter.js new file mode 100644 index 0000000000..22123bb99c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-scriptableunicodeconverter.js @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-scriptableunicodeconverter"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidError() { + return [ + { messageId: "rejectScriptableUnicodeConverter", type: "MemberExpression" }, + ]; +} + +ruleTester.run("reject-scriptableunicodeconverter", rule, { + valid: ["TextEncoder", "TextDecoder"], + invalid: [ + { + code: "Ci.nsIScriptableUnicodeConverter", + errors: invalidError(), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-some-requires.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-some-requires.js new file mode 100644 index 0000000000..3415946b07 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-some-requires.js @@ -0,0 +1,50 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-some-requires"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function requirePathError(path) { + return [ + { messageId: "rejectRequire", data: { path }, type: "CallExpression" }, + ]; +} + +const DEVTOOLS_FORBIDDEN_PATH = "^(resource://)?devtools/forbidden"; + +ruleTester.run("reject-some-requires", rule, { + valid: [ + { + code: 'require("devtools/not-forbidden/path")', + options: [DEVTOOLS_FORBIDDEN_PATH], + }, + { + code: 'require("resource://devtools/not-forbidden/path")', + options: [DEVTOOLS_FORBIDDEN_PATH], + }, + ], + invalid: [ + { + code: 'require("devtools/forbidden/path")', + errors: requirePathError("devtools/forbidden/path"), + options: [DEVTOOLS_FORBIDDEN_PATH], + }, + { + code: 'require("resource://devtools/forbidden/path")', + errors: requirePathError("resource://devtools/forbidden/path"), + options: [DEVTOOLS_FORBIDDEN_PATH], + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-top-level-await.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-top-level-await.js new file mode 100644 index 0000000000..4416b42abb --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-top-level-await.js @@ -0,0 +1,36 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-top-level-await"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ + parserOptions: { ecmaVersion: "latest", sourceType: "module" }, +}); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, messageId) { + return { code, errors: [{ messageId: "rejectTopLevelAwait" }] }; +} + +ruleTester.run("reject-top-level-await", rule, { + valid: [ + "async() => { await bar() }", + "async() => { for await (let x of []) {} }", + ], + invalid: [ + invalidCode("await foo"), + invalidCode("{ await foo }"), + invalidCode("(await foo)"), + invalidCode("for await (let x of []) {}"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/rejects-requires-await.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/rejects-requires-await.js new file mode 100644 index 0000000000..a7e95769c1 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/rejects-requires-await.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/rejects-requires-await"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, messageId) { + return { code, errors: [{ messageId: "rejectRequiresAwait" }] }; +} + +ruleTester.run("reject-requires-await", rule, { + valid: [ + "async() => { await Assert.rejects(foo, /assertion/) }", + "async() => { await Assert.rejects(foo, /assertion/, 'msg') }", + ], + invalid: [ + invalidCode("Assert.rejects(foo)"), + invalidCode("Assert.rejects(foo, 'msg')"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-cc-etc.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-cc-etc.js new file mode 100644 index 0000000000..d588fabc84 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-cc-etc.js @@ -0,0 +1,64 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-cc-etc"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, originalName, newName, output) { + return { + code, + output, + errors: [ + { + messageId: "useCcEtc", + data: { + shortName: newName, + oldName: originalName, + }, + type: "MemberExpression", + }, + ], + }; +} + +ruleTester.run("use-cc-etc", rule, { + valid: ["Components.Constructor();", "let x = Components.foo;"], + invalid: [ + invalidCode( + "let foo = Components.classes['bar'];", + "classes", + "Cc", + "let foo = Cc['bar'];" + ), + invalidCode( + "let bar = Components.interfaces.bar;", + "interfaces", + "Ci", + "let bar = Ci.bar;" + ), + invalidCode( + "Components.results.NS_ERROR_ILLEGAL_INPUT;", + "results", + "Cr", + "Cr.NS_ERROR_ILLEGAL_INPUT;" + ), + invalidCode( + "Components.utils.reportError('fake');", + "utils", + "Cu", + "Cu.reportError('fake');" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-definelazygetter.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-definelazygetter.js new file mode 100644 index 0000000000..89948f12b7 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-definelazygetter.js @@ -0,0 +1,34 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-chromeutils-definelazygetter"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError(messageId) { + return [{ messageId, type: "CallExpression" }]; +} + +ruleTester.run("use-chromeutils-definelazygetter", rule, { + valid: [ + `ChromeUtils.defineLazyGetter(lazy, "textEncoder", function () { return new TextEncoder(); });`, + ], + invalid: [ + { + code: `XPCOMUtils.defineLazyGetter(lazy, "textEncoder", function () { return new TextEncoder(); });`, + output: `ChromeUtils.defineLazyGetter(lazy, "textEncoder", function () { return new TextEncoder(); });`, + errors: callError("useChromeUtilsDefineLazyGetter"), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-generateqi.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-generateqi.js new file mode 100644 index 0000000000..ca32d2ac26 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-generateqi.js @@ -0,0 +1,71 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-chromeutils-generateqi"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function error(messageId, type) { + return [{ messageId, type }]; +} + +/* globals nsIFlug */ +function QueryInterface(iid) { + if ( + iid.equals(Ci.nsISupports) || + iid.equals(Ci.nsIMeh) || + iid.equals(nsIFlug) || + iid.equals(Ci.amIFoo) + ) { + return this; + } + throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); +} + +ruleTester.run("use-chromeutils-generateqi", rule, { + valid: [ + `X.prototype.QueryInterface = ChromeUtils.generateQI(["nsIMeh"]);`, + `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh"]) }`, + ], + invalid: [ + { + code: `X.prototype.QueryInterface = XPCOMUtils.generateQI(["nsIMeh"]);`, + output: `X.prototype.QueryInterface = ChromeUtils.generateQI(["nsIMeh"]);`, + errors: error("noXpcomUtilsGenerateQI", "CallExpression"), + }, + { + code: `X.prototype = { QueryInterface: XPCOMUtils.generateQI(["nsIMeh"]) };`, + output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh"]) };`, + errors: error("noXpcomUtilsGenerateQI", "CallExpression"), + }, + { + code: `X.prototype = { QueryInterface: ${QueryInterface} };`, + output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]) };`, + errors: error("noJSQueryInterface", "Property"), + }, + { + code: `X.prototype = { ${String(QueryInterface).replace( + /^function /, + "" + )} };`, + output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]) };`, + errors: error("noJSQueryInterface", "Property"), + }, + { + code: `X.prototype.QueryInterface = ${QueryInterface};`, + output: `X.prototype.QueryInterface = ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]);`, + errors: error("noJSQueryInterface", "AssignmentExpression"), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-import.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-import.js new file mode 100644 index 0000000000..37976d252e --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-import.js @@ -0,0 +1,47 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-chromeutils-import"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError(messageId) { + return [{ messageId, type: "CallExpression" }]; +} + +ruleTester.run("use-chromeutils-import", rule, { + valid: [ + `ChromeUtils.import("resource://gre/modules/AppConstants.jsm");`, + `ChromeUtils.import("resource://gre/modules/AppConstants.jsm", this);`, + `ChromeUtils.defineModuleGetter(this, "AppConstants", + "resource://gre/modules/AppConstants.jsm");`, + ], + invalid: [ + { + code: `Cu.import("resource://gre/modules/AppConstants.jsm");`, + output: `ChromeUtils.import("resource://gre/modules/AppConstants.jsm");`, + errors: callError("useChromeUtilsImport"), + }, + { + code: `Cu.import("resource://gre/modules/AppConstants.jsm", this);`, + output: `ChromeUtils.import("resource://gre/modules/AppConstants.jsm", this);`, + errors: callError("useChromeUtilsImport"), + }, + { + code: `Components.utils.import("resource://gre/modules/AppConstants.jsm");`, + output: `ChromeUtils.import("resource://gre/modules/AppConstants.jsm");`, + errors: callError("useChromeUtilsImport"), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-console-createInstance.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-console-createInstance.js new file mode 100644 index 0000000000..bd7fe3a507 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-console-createInstance.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-console-createInstance"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +ruleTester.run("use-console-createInstance", rule, { + valid: ['"resource://gre/modules/Foo.sys.mjs"'], + invalid: [ + { + code: '"resource://gre/modules/Console.sys.mjs"', + errors: [ + { + messageId: "useConsoleRatherThanModule", + data: { module: "Console.sys.mjs" }, + }, + ], + }, + { + code: '"resource://gre/modules/Log.sys.mjs"', + errors: [ + { + messageId: "useConsoleRatherThanModule", + data: { module: "Log.sys.mjs" }, + }, + ], + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js new file mode 100644 index 0000000000..a8353ec200 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js @@ -0,0 +1,43 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-default-preference-values"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { + code, + errors: [{ messageId: "provideDefaultValue", type: "TryStatement" }], + }; +} + +let types = ["Bool", "Char", "Float", "Int"]; +let methods = types.map(type => "get" + type + "Pref"); + +ruleTester.run("use-default-preference-values", rule, { + valid: [].concat( + methods.map(m => "blah = branch." + m + "('blah', true);"), + methods.map(m => "blah = branch." + m + "('blah');"), + methods.map( + m => "try { canThrow(); blah = branch." + m + "('blah'); } catch(e) {}" + ) + ), + + invalid: [].concat( + methods.map(m => + invalidCode("try { blah = branch." + m + "('blah'); } catch(e) {}") + ) + ), +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-includes-instead-of-indexOf.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-includes-instead-of-indexOf.js new file mode 100644 index 0000000000..fff826874f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-includes-instead-of-indexOf.js @@ -0,0 +1,40 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-includes-instead-of-indexOf"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { + code, + errors: [{ messageId: "useIncludes", type: "BinaryExpression" }], + }; +} + +ruleTester.run("use-includes-instead-of-indexOf", rule, { + valid: [ + "let a = foo.includes(bar);", + "let a = foo.indexOf(bar) > 0;", + "let a = foo.indexOf(bar) != 0;", + ], + invalid: [ + invalidCode("let a = foo.indexOf(bar) >= 0;"), + invalidCode("let a = foo.indexOf(bar) != -1;"), + invalidCode("let a = foo.indexOf(bar) !== -1;"), + invalidCode("let a = foo.indexOf(bar) == -1;"), + invalidCode("let a = foo.indexOf(bar) === -1;"), + invalidCode("let a = foo.indexOf(bar) < 0;"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-isInstance.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-isInstance.js new file mode 100644 index 0000000000..0de5e4577c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-isInstance.js @@ -0,0 +1,128 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-isInstance"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const errors = [ + { + messageId: "preferIsInstance", + type: "BinaryExpression", + }, +]; + +const env = { browser: true }; + +/** + * A test case boilerplate simulating chrome privileged script. + * @param {string} code + */ +function mockChromeScript(code) { + return { + code, + filename: "foo.sys.mjs", + env, + }; +} + +/** + * A test case boilerplate simulating content script. + * @param {string} code + */ +function mockContentScript(code) { + return { + code, + filename: "foo.js", + env, + }; +} + +ruleTester.run("use-isInstance", rule, { + valid: [ + mockChromeScript("(() => {}) instanceof Function;"), + mockChromeScript("({}) instanceof Object;"), + mockChromeScript("Node instanceof Object;"), + mockChromeScript("node instanceof lazy.Node;"), + mockChromeScript("var Node;node instanceof Node;"), + mockChromeScript("file instanceof lazy.File;"), + mockChromeScript("file instanceof OS.File;"), + mockChromeScript("file instanceof OS.File.Error;"), + mockChromeScript("file instanceof lazy.OS.File;"), + mockChromeScript("file instanceof lazy.OS.File.Error;"), + mockChromeScript("file instanceof lazy.lazy.OS.File;"), + mockChromeScript("var File;file instanceof File;"), + mockChromeScript("foo instanceof RandomGlobalThing;"), + mockChromeScript("foo instanceof lazy.RandomGlobalThing;"), + mockContentScript("node instanceof Node;"), + mockContentScript("file instanceof File;"), + mockContentScript( + "SpecialPowers.ChromeUtils.import(''); file instanceof File;" + ), + ], + invalid: [ + { + code: "node instanceof Node", + output: "Node.isInstance(node)", + env, + errors, + filename: "foo.sys.mjs", + }, + { + code: "text instanceof win.Text", + output: "win.Text.isInstance(text)", + errors, + filename: "foo.sys.mjs", + }, + { + code: "target instanceof this.contentWindow.HTMLAudioElement", + output: "this.contentWindow.HTMLAudioElement.isInstance(target)", + errors, + filename: "foo.sys.mjs", + }, + { + code: "target instanceof File", + output: "File.isInstance(target)", + env, + errors, + filename: "foo.sys.mjs", + }, + { + code: "target instanceof win.File", + output: "win.File.isInstance(target)", + errors, + filename: "foo.sys.mjs", + }, + { + code: "window.arguments[0] instanceof window.XULElement", + output: "window.XULElement.isInstance(window.arguments[0])", + errors, + filename: "foo.sys.mjs", + }, + { + code: "ChromeUtils.import(''); node instanceof Node", + output: "ChromeUtils.import(''); Node.isInstance(node)", + env, + errors, + filename: "foo.js", + }, + { + code: "ChromeUtils.import(''); file instanceof File", + output: "ChromeUtils.import(''); File.isInstance(file)", + env, + errors, + filename: "foo.js", + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js new file mode 100644 index 0000000000..150f0fac63 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-ownerGlobal"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { + code, + errors: [{ messageId: "useOwnerGlobal", type: "MemberExpression" }], + }; +} + +ruleTester.run("use-ownerGlobal", rule, { + valid: [ + "aEvent.target.ownerGlobal;", + "this.DOMPointNode.ownerGlobal.getSelection();", + "windowToMessageManager(node.ownerGlobal);", + ], + invalid: [ + invalidCode("aEvent.target.ownerDocument.defaultView;"), + invalidCode("this.DOMPointNode.ownerDocument.defaultView.getSelection();"), + invalidCode("windowToMessageManager(node.ownerDocument.defaultView);"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-returnValue.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-returnValue.js new file mode 100644 index 0000000000..2c15349139 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-returnValue.js @@ -0,0 +1,49 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-returnValue"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, methodName) { + return { + code, + errors: [ + { + messageId: "useReturnValue", + data: { + property: methodName, + }, + type: "ExpressionStatement", + }, + ], + }; +} + +ruleTester.run("use-returnValue", rule, { + valid: [ + "a = foo.concat(bar)", + "b = bar.concat([1,3,4])", + "c = baz.concat()", + "d = qux.join(' ')", + "e = quux.slice(1)", + ], + invalid: [ + invalidCode("foo.concat(bar)", "concat"), + invalidCode("bar.concat([1,3,4])", "concat"), + invalidCode("baz.concat()", "concat"), + invalidCode("qux.join(' ')", "join"), + invalidCode("quux.slice(1)", "slice"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-services.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-services.js new file mode 100644 index 0000000000..fc4af03ac1 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-services.js @@ -0,0 +1,64 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-services"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, serviceName, getterName, type = "CallExpression") { + return { + code, + errors: [ + { messageId: "useServices", data: { serviceName, getterName }, type }, + ], + }; +} + +ruleTester.run("use-services", rule, { + valid: [ + 'Cc["@mozilla.org/fakeservice;1"].getService(Ci.nsIFake)', + 'Components.classes["@mozilla.org/fakeservice;1"].getService(Components.interfaces.nsIFake)', + "Services.wm.addListener()", + ], + invalid: [ + invalidCode( + 'Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);', + "wm", + "getService()" + ), + invalidCode( + 'Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(Components.interfaces.nsIAppStartup);', + "startup", + "getService()" + ), + invalidCode( + `XPCOMUtils.defineLazyServiceGetters(this, { + uuidGen: ["@mozilla.org/uuid-generator;1", "nsIUUIDGenerator"], + });`, + "uuid", + "defineLazyServiceGetters", + "ArrayExpression" + ), + invalidCode( + `XPCOMUtils.defineLazyServiceGetter( + this, + "gELS", + "@mozilla.org/eventlistenerservice;1", + "nsIEventListenerService" + );`, + "els", + "defineLazyServiceGetter" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-static-import.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-static-import.js new file mode 100644 index 0000000000..656e83e0e9 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-static-import.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-static-import"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ + parserOptions: { ecmaVersion: "latest", sourceType: "module" }, +}); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError() { + return [{ messageId: "useStaticImport", type: "VariableDeclaration" }]; +} + +ruleTester.run("use-static-import", rule, { + valid: [ + { + // Already converted, no issues. + code: 'import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";', + filename: "test.sys.mjs", + }, + { + // Inside an if statement. + code: 'if (foo) { const { XPCOMUtils } = ChromeUtils.importESModule("resource://gre/modules/XPCOMUtils.sys.mjs") }', + filename: "test.sys.mjs", + }, + { + // Inside a function. + code: 'function foo() { const { XPCOMUtils } = ChromeUtils.importESModule("resource://gre/modules/XPCOMUtils.sys.mjs") }', + filename: "test.sys.mjs", + }, + { + // importESModule with two args cannot be converted. + code: 'const { f } = ChromeUtils.importESModule("some/module.sys.mjs", { loadInDevToolsLoader : true });', + filename: "test.sys.mjs", + }, + { + // A non-system file attempting to import a system file should not be + // converted. + code: 'const { XPCOMUtils } = ChromeUtils.importESModule("resource://gre/modules/XPCOMUtils.sys.mjs")', + filename: "test.mjs", + }, + ], + invalid: [ + { + // Simple import in system module should be converted. + code: 'const { XPCOMUtils } = ChromeUtils.importESModule("resource://gre/modules/XPCOMUtils.sys.mjs")', + errors: callError(), + filename: "test.sys.mjs", + output: + 'import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"', + }, + { + // Should handle rewritten variables as well. + code: 'const { XPCOMUtils: foo } = ChromeUtils.importESModule("resource://gre/modules/XPCOMUtils.sys.mjs")', + errors: callError(), + filename: "test.sys.mjs", + output: + 'import { XPCOMUtils as foo } from "resource://gre/modules/XPCOMUtils.sys.mjs"', + }, + { + // Should handle multiple variables. + code: 'const { foo, XPCOMUtils } = ChromeUtils.importESModule("resource://gre/modules/XPCOMUtils.sys.mjs")', + errors: callError(), + filename: "test.sys.mjs", + output: + 'import { foo, XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"', + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-ci-uses.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-ci-uses.js new file mode 100644 index 0000000000..0f5fe2eadf --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-ci-uses.js @@ -0,0 +1,58 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var os = require("os"); +var rule = require("../lib/rules/valid-ci-uses"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, messageId, data) { + return { code, errors: [{ messageId, data }] }; +} + +process.env.MOZ_XPT_ARTIFACTS_DIR = `${__dirname}/xpidl`; + +const tests = { + valid: ["Ci.nsIURIFixup", "Ci.nsIURIFixup.FIXUP_FLAG_NONE"], + invalid: [ + invalidCode("Ci.nsIURIFixup.UNKNOWN_CONSTANT", "unknownProperty", { + interface: "nsIURIFixup", + property: "UNKNOWN_CONSTANT", + }), + invalidCode("Ci.nsIFoo", "unknownInterface", { + interface: "nsIFoo", + }), + ], +}; + +// For ESLint tests, we only have a couple of xpt examples in the xpidl directory. +// Therefore we can pretend that these interfaces no longer exist. +switch (os.platform) { + case "windows": + tests.invalid.push( + invalidCode("Ci.nsIJumpListShortcut", "missingInterface") + ); + break; + case "darwin": + tests.invalid.push( + invalidCode("Ci.nsIMacShellService", "missingInterface") + ); + break; + case "linux": + tests.invalid.push( + invalidCode("Ci.mozISandboxReporter", "missingInterface") + ); +} + +ruleTester.run("valid-ci-uses", rule, tests); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-lazy.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-lazy.js new file mode 100644 index 0000000000..ba0a8dafab --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-lazy.js @@ -0,0 +1,160 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/valid-lazy"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ + parserOptions: { ecmaVersion: "latest", sourceType: "module" }, +}); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, name, messageId) { + return { code, errors: [{ messageId, data: { name } }] }; +} + +ruleTester.run("valid-lazy", rule, { + // Note: these tests build on top of one another, although lazy gets + // re-declared, it + valid: [ + ` + const lazy = {}; + ChromeUtils.defineLazyGetter(lazy, "foo", () => {}); + if (x) { lazy.foo.bar(); } + `, + ` + const lazy = {}; + ChromeUtils.defineESModuleGetters(lazy, { + foo: "foo.mjs", + }); + if (x) { lazy.foo.bar(); } + `, + ` + const lazy = {}; + Integration.downloads.defineESModuleGetter(lazy, "foo", "foo.sys.mjs"); + if (x) { lazy.foo.bar(); } + `, + ` + const lazy = createLazyLoaders({ foo: () => {}}); + if (x) { lazy.foo.bar(); } + `, + ` + const lazy = {}; + loader.lazyRequireGetter( + lazy, + ["foo1", "foo2"], + "bar", + true + ); + if (x) { + lazy.foo1.bar(); + lazy.foo2.bar(); + } + `, + // Test for top-level unconditional. + ` + const lazy = {}; + ChromeUtils.defineLazyGetter(lazy, "foo", () => {}); + if (x) { lazy.foo.bar(); } + for (;;) { lazy.foo.bar(); } + for (var x in y) { lazy.foo.bar(); } + for (var x of y) { lazy.foo.bar(); } + while (true) { lazy.foo.bar(); } + do { lazy.foo.bar(); } while (true); + switch (x) { case 1: lazy.foo.bar(); } + try { lazy.foo.bar(); } catch (e) {} + function f() { lazy.foo.bar(); } + (function f() { lazy.foo.bar(); }); + () => { lazy.foo.bar(); }; + class C { + constructor() { lazy.foo.bar(); } + foo() { lazy.foo.bar(); } + get x() { lazy.foo.bar(); } + set x(v) { lazy.foo.bar(); } + a = lazy.foo.bar(); + #b = lazy.foo.bar(); + static { + lazy.foo.bar(); + } + } + a && lazy.foo.bar(); + a || lazy.foo.bar(); + a ?? lazy.foo.bar(); + a ? lazy.foo.bar() : b; + a?.b[lazy.foo.bar()]; + a ||= lazy.foo.bar(); + a &&= lazy.foo.bar(); + a ??= lazy.foo.bar(); + var { x = lazy.foo.bar() } = {}; + var [ y = lazy.foo.bar() ] = []; + `, + ` + const lazy = {}; + ChromeUtils.defineLazyGetter(lazy, "foo", () => {}); + export { lazy as Foo }; + `, + ` + const lazy = {}; + if (cond) { + ChromeUtils.defineLazyGetter(lazy, "foo", () => { return 1; }); + } else { + ChromeUtils.defineLazyGetter(lazy, "foo", () => { return 2; }); + } + if (x) { lazy.foo; } + `, + ], + invalid: [ + invalidCode("if (x) { lazy.bar; }", "bar", "unknownProperty"), + invalidCode( + ` + const lazy = {}; + ChromeUtils.defineLazyGetter(lazy, "foo", "foo.jsm"); + ChromeUtils.defineLazyGetter(lazy, "foo", "foo1.jsm"); + if (x) { lazy.foo.bar(); } + `, + "foo", + "duplicateSymbol" + ), + invalidCode( + ` + const lazy = {}; + XPCOMUtils.defineLazyModuleGetters(lazy, { + "foo-bar": "foo.jsm", + }); + if (x) { lazy["foo-bar"].bar(); } + `, + "foo-bar", + "incorrectType" + ), + invalidCode( + `const lazy = {}; + ChromeUtils.defineLazyGetter(lazy, "foo", "foo.jsm"); + `, + "foo", + "unusedProperty" + ), + invalidCode( + `const lazy = {}; + ChromeUtils.defineLazyGetter(lazy, "foo1", () => {}); + lazy.foo1.bar();`, + "foo1", + "topLevelAndUnconditional" + ), + invalidCode( + `const lazy = {}; + ChromeUtils.defineLazyGetter(lazy, "foo1", () => {}); + { x = -f(1 + lazy.foo1.bar()); }`, + "foo1", + "topLevelAndUnconditional" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-services-property.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-services-property.js new file mode 100644 index 0000000000..a9806ccc72 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-services-property.js @@ -0,0 +1,42 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/valid-services-property"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, messageId, data) { + return { code, errors: [{ messageId, data }] }; +} + +process.env.MOZ_XPT_ARTIFACTS_DIR = `${__dirname}/xpidl`; + +ruleTester.run("valid-services-property", rule, { + valid: [ + "Services.uriFixup.keywordToURI()", + "Services.uriFixup.FIXUP_FLAG_NONE", + ], + invalid: [ + invalidCode("Services.uriFixup.UNKNOWN_CONSTANT", "unknownProperty", { + alias: "uriFixup", + propertyName: "UNKNOWN_CONSTANT", + checkedInterfaces: ["nsIURIFixup"], + }), + invalidCode("Services.uriFixup.foo()", "unknownProperty", { + alias: "uriFixup", + propertyName: "foo", + checkedInterfaces: ["nsIURIFixup"], + }), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-services.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-services.js new file mode 100644 index 0000000000..1453e95b7b --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/valid-services.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/valid-services"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "latest" } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, alias) { + return { code, errors: [{ messageId: "unknownProperty", data: { alias } }] }; +} + +ruleTester.run("valid-services", rule, { + valid: ["Services.crashmanager", "lazy.Services.crashmanager"], + invalid: [ + invalidCode("Services.foo", "foo"), + invalidCode("Services.foo()", "foo"), + invalidCode("lazy.Services.foo", "foo"), + invalidCode("Services.foo.bar()", "foo"), + invalidCode("lazy.Services.foo.bar()", "foo"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/xpidl/docshell.xpt b/tools/lint/eslint/eslint-plugin-mozilla/tests/xpidl/docshell.xpt new file mode 100644 index 0000000000..fc8a45216b --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/xpidl/docshell.xpt @@ -0,0 +1,5940 @@ +[ + { + "consts": [ + { + "name": "ePrompt", + "type": { + "tag": "TD_UINT8" + }, + "value": 0 + }, + { + "name": "eDontPromptAndDontUnload", + "type": { + "tag": "TD_UINT8" + }, + "value": 1 + }, + { + "name": "eDontPromptAndUnload", + "type": { + "tag": "TD_UINT8" + }, + "value": 2 + }, + { + "name": "eAllowNavigation", + "type": { + "tag": "TD_UINT8" + }, + "value": 0 + }, + { + "name": "eRequestBlockNavigation", + "type": { + "tag": "TD_UINT8" + }, + "value": 1 + }, + { + "name": "eDelayResize", + "type": { + "tag": "TD_UINT32" + }, + "value": 1 + } + ], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [ + "hidden" + ], + "name": "init", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "container", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocShell", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "container", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocShell", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "loadStart", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "headerFile": "mozilla/dom/Document.h", + "name": "Document", + "native": "mozilla::dom::Document", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [], + "name": "loadComplete", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hidden", + "hasretval" + ], + "name": "loadCompleted", + "params": [] + }, + { + "flags": [ + "getter", + "hidden", + "hasretval" + ], + "name": "isStopped", + "params": [] + }, + { + "flags": [ + "hasretval" + ], + "name": "permitUnload", + "params": [ + { + "flags": [ + "in", + "optional" + ], + "type": { + "tag": "TD_UINT8" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "inPermitUnload", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "dispatchBeforeUnload", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "beforeUnloadFiring", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "pageHide", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "close", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsISHEntry", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "destroy", + "params": [] + }, + { + "flags": [], + "name": "stop", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "DOMDocument", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "headerFile": "mozilla/dom/Document.h", + "name": "Document", + "native": "mozilla::dom::Document", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getDocument", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "setDocument", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "headerFile": "mozilla/dom/Document.h", + "name": "Document", + "native": "mozilla::dom::Document", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getBounds", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "setBounds", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "setBoundsWithFlags", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hidden", + "hasretval" + ], + "name": "previousViewer", + "params": [] + }, + { + "flags": [ + "setter", + "hidden" + ], + "name": "previousViewer", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocumentViewer", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "move", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "show", + "params": [] + }, + { + "flags": [], + "name": "hide", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "sticky", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "sticky", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "open", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISHEntry", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "clearHistoryEntry", + "params": [] + }, + { + "flags": [], + "name": "setPageModeForTesting", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIPrintSettings", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "setPrintSettingsForSubdocument", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIPrintSettings", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "historyEntry", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsISHEntry", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isTabModalPromptAllowed", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isHidden", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "isHidden", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hidden", + "hasretval" + ], + "name": "presShell", + "params": [] + }, + { + "flags": [ + "getter", + "hidden", + "hasretval" + ], + "name": "presContext", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "setDocumentInternal", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "headerFile": "mozilla/dom/Document.h", + "name": "Document", + "native": "mozilla::dom::Document", + "tag": "TD_DOMOBJECT" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "findContainerView", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "setNavigationTiming", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "deviceFullZoomForTest", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_FLOAT" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "authorStyleDisabled", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "authorStyleDisabled", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "getContentSize", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "getContentSizeConstrained", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getReloadEncodingAndSource", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "setReloadEncodingAndSource", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "forgetReloadEncoding", + "params": [] + } + ], + "name": "nsIDocumentViewer", + "parent": "nsISupports", + "uuid": "48118355-e9a5-4452-ab18-59cc426fb817" + }, + { + "consts": [ + { + "name": "COPY_IMAGE_TEXT", + "type": { + "tag": "TD_INT32" + }, + "value": 1 + }, + { + "name": "COPY_IMAGE_HTML", + "type": { + "tag": "TD_INT32" + }, + "value": 2 + }, + { + "name": "COPY_IMAGE_DATA", + "type": { + "tag": "TD_INT32" + }, + "value": 4 + }, + { + "name": "COPY_IMAGE_ALL", + "type": { + "tag": "TD_INT32" + }, + "value": -1 + } + ], + "flags": [], + "methods": [ + { + "flags": [], + "name": "clearSelection", + "params": [] + }, + { + "flags": [], + "name": "selectAll", + "params": [] + }, + { + "flags": [], + "name": "copySelection", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "copyable", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "copyLinkLocation", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "inLink", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "copyImage", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "inImage", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "getContents", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "canGetContents", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "setCommandNode", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "headerFile": "nsIContent.h", + "name": "Node", + "native": "nsINode", + "tag": "TD_DOMOBJECT" + } + } + ] + } + ], + "name": "nsIDocumentViewerEdit", + "parent": "nsISupports", + "uuid": "35be2d7e-f29b-48ec-bf7e-80a30a724de3" + }, + { + "consts": [ + { + "name": "ENUMERATE_FORWARDS", + "type": { + "tag": "TD_UINT8" + }, + "value": 0 + }, + { + "name": "ENUMERATE_BACKWARDS", + "type": { + "tag": "TD_UINT8" + }, + "value": 1 + }, + { + "name": "APP_TYPE_UNKNOWN", + "type": { + "tag": "TD_UINT8" + }, + "value": 0 + }, + { + "name": "APP_TYPE_MAIL", + "type": { + "tag": "TD_UINT8" + }, + "value": 1 + }, + { + "name": "APP_TYPE_EDITOR", + "type": { + "tag": "TD_UINT8" + }, + "value": 2 + }, + { + "name": "BUSY_FLAGS_NONE", + "type": { + "tag": "TD_UINT8" + }, + "value": 0 + }, + { + "name": "BUSY_FLAGS_BUSY", + "type": { + "tag": "TD_UINT8" + }, + "value": 1 + }, + { + "name": "BUSY_FLAGS_BEFORE_PAGE_LOAD", + "type": { + "tag": "TD_UINT8" + }, + "value": 2 + }, + { + "name": "BUSY_FLAGS_PAGE_LOADING", + "type": { + "tag": "TD_UINT8" + }, + "value": 4 + }, + { + "name": "LOAD_CMD_NORMAL", + "type": { + "tag": "TD_UINT8" + }, + "value": 1 + }, + { + "name": "LOAD_CMD_RELOAD", + "type": { + "tag": "TD_UINT8" + }, + "value": 2 + }, + { + "name": "LOAD_CMD_HISTORY", + "type": { + "tag": "TD_UINT8" + }, + "value": 4 + }, + { + "name": "LOAD_CMD_PUSHSTATE", + "type": { + "tag": "TD_UINT8" + }, + "value": 8 + }, + { + "name": "META_VIEWPORT_OVERRIDE_DISABLED", + "type": { + "tag": "TD_UINT8" + }, + "value": 0 + }, + { + "name": "META_VIEWPORT_OVERRIDE_ENABLED", + "type": { + "tag": "TD_UINT8" + }, + "value": 1 + }, + { + "name": "META_VIEWPORT_OVERRIDE_NONE", + "type": { + "tag": "TD_UINT8" + }, + "value": 2 + } + ], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [], + "name": "setCancelContentJSEpoch", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "loadURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "jscontext" + ], + "name": "addState", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_JSVAL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "prepareForNewContentModel", + "params": [] + }, + { + "flags": [], + "name": "setCurrentURIForSessionStore", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "firePageHideNotification", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hidden", + "hasretval" + ], + "name": "presContext", + "params": [] + }, + { + "flags": [ + "getter", + "hidden", + "hasretval" + ], + "name": "presShell", + "params": [] + }, + { + "flags": [ + "getter", + "hidden", + "hasretval" + ], + "name": "eldestPresShell", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "docViewer", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocumentViewer", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "outerWindowID", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "chromeEventHandler", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "headerFile": "mozilla/dom/EventTarget.h", + "name": "EventTarget", + "native": "mozilla::dom::EventTarget", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "chromeEventHandler", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "headerFile": "mozilla/dom/EventTarget.h", + "name": "EventTarget", + "native": "mozilla::dom::EventTarget", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "customUserAgent", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "customUserAgent", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "cssErrorReportingEnabled", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "cssErrorReportingEnabled", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowPlugins", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowPlugins", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowMetaRedirects", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowMetaRedirects", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowSubframes", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowSubframes", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowImages", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowImages", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowMedia", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowMedia", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowDNSPrefetch", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowDNSPrefetch", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowWindowControl", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowWindowControl", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowContentRetargeting", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowContentRetargeting", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowContentRetargetingOnChildren", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowContentRetargetingOnChildren", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "getAllDocShellsInSubtree", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT8" + } + }, + { + "flags": [ + "out" + ], + "type": { + "element": { + "name": "nsIDocShell", + "tag": "TD_INTERFACE_TYPE" + }, + "tag": "TD_ARRAY" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "appType", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT8" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "appType", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT8" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "allowAuth", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "allowAuth", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "zoom", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_FLOAT" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "zoom", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_FLOAT" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "tabToTreeOwner", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "busyFlags", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT8" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "loadType", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "loadType", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "defaultLoadFlags", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "defaultLoadFlags", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "isBeingDestroyed", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isExecutingOnLoadHandler", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "layoutHistoryState", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsILayoutHistoryState", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "layoutHistoryState", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsILayoutHistoryState", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "loadURIDelegate", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsILoadURIDelegate", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "suspendRefreshURIs", + "params": [] + }, + { + "flags": [], + "name": "resumeRefreshURIs", + "params": [] + }, + { + "flags": [], + "name": "beginRestore", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocumentViewer", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "finishRestore", + "params": [] + }, + { + "flags": [], + "name": "clearCachedUserAgent", + "params": [] + }, + { + "flags": [], + "name": "clearCachedPlatform", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "restoringDocument", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "useErrorPages", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "useErrorPages", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "displayLoadError", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PWSTRING" + } + }, + { + "flags": [ + "in", + "optional" + ], + "type": { + "name": "nsIChannel", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "failedChannel", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIChannel", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "previousEntryIndex", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "loadedEntryIndex", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "historyPurged", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "currentDocumentChannel", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIChannel", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isInUnload", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "DetachEditorFromWindow", + "params": [] + }, + { + "flags": [], + "name": "exitPrintPreview", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "historyID", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_NSID" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "HistoryID", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isAppTab", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "isAppTab", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "createAboutBlankDocumentViewer", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIPrincipal", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIPrincipal", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in", + "optional" + ], + "type": { + "name": "nsIContentSecurityPolicy", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "charset", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_CSTRING" + } + } + ] + }, + { + "flags": [], + "name": "forceEncodingDetection", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "setParentCharset", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIPrincipal", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getParentCharset", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "out" + ], + "type": { + "name": "nsIPrincipal", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "now", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_DOUBLE" + } + } + ] + }, + { + "flags": [], + "name": "addWeakPrivacyTransitionObserver", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIPrivacyTransitionObserver", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "addWeakReflowObserver", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIReflowObserver", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "removeWeakReflowObserver", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIReflowObserver", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "notifyReflowObservers", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_DOUBLE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_DOUBLE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "addWeakScrollObserver", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIScrollObserver", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "removeWeakScrollObserver", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIScrollObserver", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "notifyScrollObservers", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isTopLevelContentDocShell", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "asyncPanZoomEnabled", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "pluginsAllowedInCurrentDoc", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "mayEnableCharacterEncodingMenu", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "editor", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIEditor", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "editor", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIEditor", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "editable", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "hasEditingSession", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "makeEditable", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "getCurrentSHEntry", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsISHEntry", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "isCommandEnabled", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "doCommand", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + } + ] + }, + { + "flags": [], + "name": "doCommandWithParams", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsICommandParams", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "IsInvisible", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "SetInvisible", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "GetScriptGlobalObject", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "getExtantDocument", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "deviceSizeIsPageSize", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "deviceSizeIsPageSize", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "hasLoadedNonBlankURI", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "windowDraggingAllowed", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "windowDraggingAllowed", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "currentScrollRestorationIsManual", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "currentScrollRestorationIsManual", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "jscontext", + "hasretval" + ], + "name": "getOriginAttributes", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_JSVAL" + } + } + ] + }, + { + "flags": [ + "jscontext" + ], + "name": "setOriginAttributes", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_JSVAL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "editingSession", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIEditingSession", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "browserChild", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIBrowserChild", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "GetBrowserChild", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "GetCommandManager", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "metaViewportOverride", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT8" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "metaViewportOverride", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT8" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "useTrackingProtection", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "useTrackingProtection", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "dispatchLocationChangeEvent", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "startDelayedAutoplayMediaComponents", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "TakeInitialClientSource", + "params": [] + }, + { + "flags": [], + "name": "setColorMatrix", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "element": { + "tag": "TD_FLOAT" + }, + "tag": "TD_ARRAY" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isForceReloading", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "getColorMatrix", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "element": { + "tag": "TD_FLOAT" + }, + "tag": "TD_ARRAY" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "messageManager", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "headerFile": "mozilla/dom/ContentFrameMessageManager.h", + "name": "ContentFrameMessageManager", + "native": "mozilla::dom::ContentFrameMessageManager", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "getHasTrackingContentBlocked", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_PROMISE" + } + } + ] + }, + { + "flags": [ + "getter", + "hidden", + "hasretval" + ], + "name": "isAttemptingToNavigate", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isNavigating", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "synchronizeLayoutHistoryState", + "params": [] + }, + { + "flags": [], + "name": "persistLayoutHistoryState", + "params": [] + } + ], + "name": "nsIDocShell", + "parent": "nsIDocShellTreeItem", + "uuid": "049234fe-da10-478b-bc5d-bc6f9a1ba63d" + }, + { + "consts": [ + { + "name": "typeChrome", + "type": { + "tag": "TD_INT32" + }, + "value": 0 + }, + { + "name": "typeContent", + "type": { + "tag": "TD_INT32" + }, + "value": 1 + }, + { + "name": "typeContentWrapper", + "type": { + "tag": "TD_INT32" + }, + "value": 2 + }, + { + "name": "typeChromeWrapper", + "type": { + "tag": "TD_INT32" + }, + "value": 3 + }, + { + "name": "typeAll", + "type": { + "tag": "TD_INT32" + }, + "value": 2147483647 + } + ], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [ + "getter", + "hasretval" + ], + "name": "name", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "name", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "nameEquals", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "itemType", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "ItemType", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "parent", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "sameTypeParent", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "rootTreeItem", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "sameTypeRootTreeItem", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "treeOwner", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocShellTreeOwner", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "setTreeOwner", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocShellTreeOwner", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "childCount", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "addChild", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "removeChild", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "getChildAt", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "browsingContext", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "headerFile": "mozilla/dom/BrowsingContext.h", + "name": "BrowsingContext", + "native": "mozilla::dom::BrowsingContext", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getBrowsingContext", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "domWindow", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "mozIDOMWindowProxy", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getDocument", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "getWindow", + "params": [] + } + ], + "name": "nsIDocShellTreeItem", + "parent": "nsISupports", + "uuid": "9b7c586f-9214-480c-a2c4-49b526fff1a6" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "contentShellAdded", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "contentShellRemoved", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "primaryContentShell", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "remoteTabAdded", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIRemoteTab", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "remoteTabRemoved", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIRemoteTab", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "primaryRemoteTab", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIRemoteTab", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "primaryContentBrowsingContext", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "headerFile": "mozilla/dom/BrowsingContext.h", + "name": "BrowsingContext", + "native": "mozilla::dom::BrowsingContext", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [], + "name": "sizeShellTo", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocShellTreeItem", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "getPrimaryContentSize", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "setPrimaryContentSize", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "getRootShellSize", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "setRootShellSize", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "setPersistence", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "getPersistence", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "tabCount", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "hasPrimaryContent", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + } + ], + "name": "nsIDocShellTreeOwner", + "parent": "nsISupports", + "uuid": "0e3dc4b1-4cea-4a37-af71-79f0afd07574" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "createInstance", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIChannel", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsILoadGroup", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocShell", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "out" + ], + "type": { + "name": "nsIStreamListener", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocumentViewer", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "createInstanceForDocument", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "headerFile": "mozilla/dom/Document.h", + "name": "Document", + "native": "mozilla::dom::Document", + "tag": "TD_DOMOBJECT" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "out" + ], + "type": { + "name": "nsIDocumentViewer", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsIDocumentLoaderFactory", + "parent": "nsISupports", + "uuid": "e795239e-9d3c-47c4-b063-9e600fb3b287" + }, + { + "consts": [], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [ + "getter", + "hasretval" + ], + "name": "associatedWindow", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "mozIDOMWindowProxy", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "topWindow", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "mozIDOMWindowProxy", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "topFrameElement", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "headerFile": "mozilla/dom/Element.h", + "name": "Element", + "native": "mozilla::dom::Element", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isContent", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "usePrivateBrowsing", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "usePrivateBrowsing", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "useRemoteTabs", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "useRemoteSubframes", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "useTrackingProtection", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "useTrackingProtection", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "SetPrivateBrowsing", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "SetRemoteTabs", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "SetRemoteSubframes", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "originAttributes", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_JSVAL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "GetOriginAttributes", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + } + ], + "name": "nsILoadContext", + "parent": "nsISupports", + "uuid": "2813a7a3-d084-4d00-acd0-f76620315c02" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "loadURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT16" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIPrincipal", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "handleLoadError", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT16" + } + }, + { + "flags": [ + "out" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsILoadURIDelegate", + "parent": "nsISupports", + "uuid": "78e42d37-a34c-4d96-b901-25385669aba4" + }, + { + "consts": [], + "flags": [ + "function" + ], + "methods": [ + { + "flags": [], + "name": "privateModeChanged", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + } + ], + "name": "nsIPrivacyTransitionObserver", + "parent": "nsISupports", + "uuid": "b4b1449d-0ef0-47f5-b62e-adc57fd49702" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "reflow", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_DOUBLE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_DOUBLE" + } + } + ] + }, + { + "flags": [], + "name": "reflowInterruptible", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_DOUBLE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_DOUBLE" + } + } + ] + } + ], + "name": "nsIReflowObserver", + "parent": "nsISupports", + "uuid": "832e692c-c4a6-11e2-8fd1-dce678957a39" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "refreshURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIPrincipal", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [], + "name": "forceRefreshURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIPrincipal", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [], + "name": "cancelRefreshURITimers", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "refreshPending", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + } + ], + "name": "nsIRefreshURI", + "parent": "nsISupports", + "uuid": "a5e61a3c-51bd-45be-ac0c-e87b71860656" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "onShowTooltip", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [], + "name": "onHideTooltip", + "params": [] + } + ], + "name": "nsITooltipListener", + "parent": "nsISupports", + "uuid": "44b78386-1dd2-11b2-9ad2-e4eee2ca1916" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "getNodeText", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "headerFile": "nsIContent.h", + "name": "Node", + "native": "nsINode", + "tag": "TD_DOMOBJECT" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_PWSTRING" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_PWSTRING" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + } + ], + "name": "nsITooltipTextProvider", + "parent": "nsISupports", + "uuid": "b128a1e6-44f3-4331-8fbe-5af360ff21ee" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "getter", + "hasretval" + ], + "name": "consumer", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "headerFile": "mozilla/dom/BrowsingContext.h", + "name": "BrowsingContext", + "native": "mozilla::dom::BrowsingContext", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "consumer", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "headerFile": "mozilla/dom/BrowsingContext.h", + "name": "BrowsingContext", + "native": "mozilla::dom::BrowsingContext", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "preferredURI", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "preferredURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "fixedURI", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "fixedURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "keywordProviderName", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "keywordProviderName", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "keywordAsSent", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "keywordAsSent", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "fixupChangedProtocol", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "fixupChangedProtocol", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "fixupCreatedAlternateURI", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "fixupCreatedAlternateURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "originalInput", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UTF8STRING" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "originalInput", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UTF8STRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "postData", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIInputStream", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "postData", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIInputStream", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsIURIFixupInfo", + "parent": "nsISupports", + "uuid": "4819f183-b532-4932-ac09-b309cd853be7" + }, + { + "consts": [ + { + "name": "FIXUP_FLAG_NONE", + "type": { + "tag": "TD_UINT32" + }, + "value": 0 + }, + { + "name": "FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP", + "type": { + "tag": "TD_UINT32" + }, + "value": 1 + }, + { + "name": "FIXUP_FLAGS_MAKE_ALTERNATE_URI", + "type": { + "tag": "TD_UINT32" + }, + "value": 2 + }, + { + "name": "FIXUP_FLAG_PRIVATE_CONTEXT", + "type": { + "tag": "TD_UINT32" + }, + "value": 4 + }, + { + "name": "FIXUP_FLAG_FIX_SCHEME_TYPOS", + "type": { + "tag": "TD_UINT32" + }, + "value": 8 + } + ], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "getFixupURIInfo", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UTF8STRING" + } + }, + { + "flags": [ + "in", + "optional" + ], + "type": { + "tag": "TD_UINT32" + } + }, + { + "flags": [ + "out" + ], + "type": { + "name": "nsIURIFixupInfo", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "webNavigationFlagsToFixupFlags", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UTF8STRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "keywordToURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UTF8STRING" + } + }, + { + "flags": [ + "in", + "optional" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "out" + ], + "type": { + "name": "nsIURIFixupInfo", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "forceHttpFixup", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UTF8STRING" + } + }, + { + "flags": [ + "out" + ], + "type": { + "name": "nsIURIFixupInfo", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "checkHost", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDNSListener", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in", + "optional" + ], + "type": { + "tag": "TD_JSVAL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "isDomainKnown", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UTF8STRING" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + } + ], + "name": "nsIURIFixup", + "parent": "nsISupports", + "uuid": "1da7e9d4-620b-4949-849a-1cd6077b1b2d" + }, + { + "consts": [ + { + "name": "LOAD_FLAGS_MASK", + "type": { + "tag": "TD_UINT32" + }, + "value": 65535 + }, + { + "name": "LOAD_FLAGS_NONE", + "type": { + "tag": "TD_UINT32" + }, + "value": 0 + }, + { + "name": "LOAD_FLAGS_IS_REFRESH", + "type": { + "tag": "TD_UINT32" + }, + "value": 16 + }, + { + "name": "LOAD_FLAGS_IS_LINK", + "type": { + "tag": "TD_UINT32" + }, + "value": 32 + }, + { + "name": "LOAD_FLAGS_BYPASS_HISTORY", + "type": { + "tag": "TD_UINT32" + }, + "value": 64 + }, + { + "name": "LOAD_FLAGS_REPLACE_HISTORY", + "type": { + "tag": "TD_UINT32" + }, + "value": 128 + }, + { + "name": "LOAD_FLAGS_BYPASS_CACHE", + "type": { + "tag": "TD_UINT32" + }, + "value": 256 + }, + { + "name": "LOAD_FLAGS_BYPASS_PROXY", + "type": { + "tag": "TD_UINT32" + }, + "value": 512 + }, + { + "name": "LOAD_FLAGS_CHARSET_CHANGE", + "type": { + "tag": "TD_UINT32" + }, + "value": 1024 + }, + { + "name": "LOAD_FLAGS_STOP_CONTENT", + "type": { + "tag": "TD_UINT32" + }, + "value": 2048 + }, + { + "name": "LOAD_FLAGS_FROM_EXTERNAL", + "type": { + "tag": "TD_UINT32" + }, + "value": 4096 + }, + { + "name": "LOAD_FLAGS_FIRST_LOAD", + "type": { + "tag": "TD_UINT32" + }, + "value": 16384 + }, + { + "name": "LOAD_FLAGS_ALLOW_POPUPS", + "type": { + "tag": "TD_UINT32" + }, + "value": 32768 + }, + { + "name": "LOAD_FLAGS_BYPASS_CLASSIFIER", + "type": { + "tag": "TD_UINT32" + }, + "value": 65536 + }, + { + "name": "LOAD_FLAGS_FORCE_ALLOW_COOKIES", + "type": { + "tag": "TD_UINT32" + }, + "value": 131072 + }, + { + "name": "LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL", + "type": { + "tag": "TD_UINT32" + }, + "value": 262144 + }, + { + "name": "LOAD_FLAGS_ERROR_LOAD_CHANGES_RV", + "type": { + "tag": "TD_UINT32" + }, + "value": 524288 + }, + { + "name": "LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP", + "type": { + "tag": "TD_UINT32" + }, + "value": 1048576 + }, + { + "name": "LOAD_FLAGS_FIXUP_SCHEME_TYPOS", + "type": { + "tag": "TD_UINT32" + }, + "value": 2097152 + }, + { + "name": "LOAD_FLAGS_FORCE_ALLOW_DATA_URI", + "type": { + "tag": "TD_UINT32" + }, + "value": 4194304 + }, + { + "name": "LOAD_FLAGS_IS_REDIRECT", + "type": { + "tag": "TD_UINT32" + }, + "value": 8388608 + }, + { + "name": "LOAD_FLAGS_DISABLE_TRR", + "type": { + "tag": "TD_UINT32" + }, + "value": 16777216 + }, + { + "name": "LOAD_FLAGS_FORCE_TRR", + "type": { + "tag": "TD_UINT32" + }, + "value": 33554432 + }, + { + "name": "LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE", + "type": { + "tag": "TD_UINT32" + }, + "value": 67108864 + }, + { + "name": "LOAD_FLAGS_USER_ACTIVATION", + "type": { + "tag": "TD_UINT32" + }, + "value": 134217728 + }, + { + "name": "STOP_NETWORK", + "type": { + "tag": "TD_UINT32" + }, + "value": 1 + }, + { + "name": "STOP_CONTENT", + "type": { + "tag": "TD_UINT32" + }, + "value": 2 + }, + { + "name": "STOP_ALL", + "type": { + "tag": "TD_UINT32" + }, + "value": 3 + } + ], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [ + "getter", + "hasretval" + ], + "name": "canGoBack", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "canGoForward", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "goBack", + "params": [ + { + "flags": [ + "in", + "optional" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in", + "optional" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "goForward", + "params": [ + { + "flags": [ + "in", + "optional" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in", + "optional" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "gotoIndex", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in", + "optional" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "jscontext" + ], + "name": "loadURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_JSVAL" + } + } + ] + }, + { + "flags": [], + "name": "binaryLoadURI", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [], + "name": "reload", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [], + "name": "stop", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "document", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "headerFile": "mozilla/dom/Document.h", + "name": "Document", + "native": "mozilla::dom::Document", + "tag": "TD_DOMOBJECT" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "currentURI", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIURI", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "sessionHistory", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "resumeRedirectedLoad", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT64" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + } + ], + "name": "nsIWebNavigation", + "parent": "nsISupports", + "uuid": "3ade79d4-8cb9-4952-b18d-4f9b63ca0d31" + }, + { + "consts": [ + { + "name": "UNSUPPORTED", + "type": { + "tag": "TD_UINT32" + }, + "value": 0 + }, + { + "name": "IMAGE", + "type": { + "tag": "TD_UINT32" + }, + "value": 1 + }, + { + "name": "FALLBACK", + "type": { + "tag": "TD_UINT32" + }, + "value": 2 + }, + { + "name": "OTHER", + "type": { + "tag": "TD_UINT32" + }, + "value": 32768 + } + ], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "isTypeSupported", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + } + ], + "name": "nsIWebNavigationInfo", + "parent": "nsISupports", + "uuid": "62a93afb-93a1-465c-84c8-0432264229de" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "loadPageAsViewSource", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDocShell", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "currentDescriptor", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsIWebPageDescriptor", + "parent": "nsISupports", + "uuid": "6f30b676-3710-4c2c-80b1-0395fb26516e" + } +]
\ No newline at end of file diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/xpidl/xpcom_base.xpt b/tools/lint/eslint/eslint-plugin-mozilla/tests/xpidl/xpcom_base.xpt new file mode 100644 index 0000000000..8b3db4bdeb --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/xpidl/xpcom_base.xpt @@ -0,0 +1,3165 @@ +[ + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "unloadTabAsync", + "params": [] + } + ], + "name": "nsITabUnloader", + "parent": "nsISupports", + "uuid": "2e530956-6054-464f-9f4c-0ae6f8de5523" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "registerTabUnloader", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsITabUnloader", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "onUnloadAttemptCompleted", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + } + ], + "name": "nsIAvailableMemoryWatcherBase", + "parent": "nsISupports", + "uuid": "b0b5701e-239d-49db-9009-37e89f86441c" + }, + { + "consts": [], + "flags": [ + "function" + ], + "methods": [ + { + "flags": [], + "name": "observe", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIConsoleMessage", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsIConsoleListener", + "parent": "nsISupports", + "uuid": "35c400a4-5792-438c-b915-65e30d58d557" + }, + { + "consts": [ + { + "name": "debug", + "type": { + "tag": "TD_UINT32" + }, + "value": 0 + }, + { + "name": "info", + "type": { + "tag": "TD_UINT32" + }, + "value": 1 + }, + { + "name": "warn", + "type": { + "tag": "TD_UINT32" + }, + "value": 2 + }, + { + "name": "error", + "type": { + "tag": "TD_UINT32" + }, + "value": 3 + } + ], + "flags": [], + "methods": [ + { + "flags": [ + "getter", + "hasretval" + ], + "name": "logLevel", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "timeStamp", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "microSecondTimeStamp", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "message", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isForwardedFromContentProcess", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "isForwardedFromContentProcess", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "toString", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UTF8STRING" + } + } + ] + } + ], + "name": "nsIConsoleMessage", + "parent": "nsISupports", + "uuid": "3aba9617-10e2-4839-83ae-2e6fc4df428b" + }, + { + "consts": [ + { + "name": "SuppressLog", + "type": { + "tag": "TD_UINT8" + }, + "value": 0 + }, + { + "name": "OutputToLog", + "type": { + "tag": "TD_UINT8" + }, + "value": 1 + } + ], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [], + "name": "logMessage", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIConsoleMessage", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "logMessageWithMode", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIConsoleMessage", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT8" + } + } + ] + }, + { + "flags": [], + "name": "logStringMessage", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PWSTRING" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "getMessageArray", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "element": { + "name": "nsIConsoleMessage", + "tag": "TD_INTERFACE_TYPE" + }, + "tag": "TD_ARRAY" + } + } + ] + }, + { + "flags": [], + "name": "registerListener", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIConsoleListener", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "unregisterListener", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIConsoleListener", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "reset", + "params": [] + }, + { + "flags": [], + "name": "resetWindow", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT64" + } + } + ] + } + ], + "name": "nsIConsoleService", + "parent": "nsISupports", + "uuid": "0eb81d20-c37e-42d4-82a8-ca9ae96bdf52" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "noteRefCountedObject", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + } + ] + }, + { + "flags": [], + "name": "noteGCedObject", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + } + ] + }, + { + "flags": [], + "name": "noteEdge", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + } + ] + }, + { + "flags": [], + "name": "describeRoot", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UINT32" + } + } + ] + }, + { + "flags": [], + "name": "describeGarbage", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + } + ] + } + ], + "name": "nsICycleCollectorHandler", + "parent": "nsISupports", + "uuid": "7f093367-1492-4b89-87af-c01dbc831246" + }, + { + "consts": [], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [ + "hidden" + ], + "name": "open", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [], + "name": "closeGCLog", + "params": [] + }, + { + "flags": [], + "name": "closeCCLog", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "filenameIdentifier", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "filenameIdentifier", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "processIdentifier", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "processIdentifier", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "gcLog", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIFile", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "ccLog", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIFile", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsICycleCollectorLogSink", + "parent": "nsISupports", + "uuid": "3ad9875f-d0e4-4ac2-87e3-f127f6c02ce1" + }, + { + "consts": [], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "allTraces", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsICycleCollectorListener", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "wantAllTraces", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "disableLog", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "disableLog", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "logSink", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsICycleCollectorLogSink", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "logSink", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsICycleCollectorLogSink", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "wantAfterProcessing", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "setter" + ], + "name": "wantAfterProcessing", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "processNext", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsICycleCollectorHandler", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden", + "hasretval" + ], + "name": "asLogger", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + } + ], + "name": "nsICycleCollectorListener", + "parent": "nsISupports", + "uuid": "703b53b6-24f6-40c6-9ea9-aeb2dc53d170" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isDebugBuild", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "assertionCount", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isDebuggerAttached", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "assertion", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "warning", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "break", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "abort", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [], + "name": "rustPanic", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + } + ] + }, + { + "flags": [], + "name": "rustLog", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_PSTRING" + } + } + ] + }, + { + "flags": [], + "name": "crashWithOOM", + "params": [] + } + ], + "name": "nsIDebug2", + "parent": "nsISupports", + "uuid": "9641dc15-10fb-42e3-a285-18be90a5c10b" + }, + { + "consts": [], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "filename", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "name", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "sourceId", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "lineNumber", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "columnNumber", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "sourceLine", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UTF8STRING" + } + } + ] + }, + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "asyncCause", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "asyncCaller", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIStackFrame", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "caller", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIStackFrame", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "getter", + "jscontext", + "hasretval" + ], + "name": "formattedStack", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "nativeSavedFrame", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_JSVAL" + } + } + ] + }, + { + "flags": [ + "jscontext", + "hasretval" + ], + "name": "toString", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UTF8STRING" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getFilename", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getName", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getSourceId", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getLineNumber", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getColumnNumber", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getAsyncCause", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getAsyncCaller", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getCaller", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getFormattedStack", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "toStringInfallible", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_UTF8STRING" + } + } + ] + } + ], + "name": "nsIStackFrame", + "parent": "nsISupports", + "uuid": "28bfb2a2-5ea6-4738-918b-049dc4d51f0b" + }, + { + "consts": [], + "flags": [ + "builtinclass" + ], + "methods": [], + "name": "nsIException", + "parent": "nsISupports", + "uuid": "4371b5bf-6845-487f-8d9d-3f1e4a9badd2" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "init", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIFile", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "initANSIFileDesc", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + }, + { + "flags": [], + "name": "write", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UTF8STRING" + } + } + ] + }, + { + "flags": [], + "name": "finish", + "params": [] + } + ], + "name": "nsIGZFileWriter", + "parent": "nsISupports", + "uuid": "6bd5642c-1b90-4499-ba4b-199f27efaba5" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "getInterface", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_NSID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "iid_is": 0, + "tag": "TD_INTERFACE_IS_TYPE" + } + } + ] + } + ], + "name": "nsIInterfaceRequestor", + "parent": "nsISupports", + "uuid": "033a1470-8b2a-11d3-af88-00a024ffc08c" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "policiesEnabled", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "jscontext", + "hasretval" + ], + "name": "readPreferences", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_JSVAL" + } + } + ] + } + ], + "name": "nsIMacPreferencesReader", + "parent": "nsISupports", + "uuid": "b0f20595-88ce-4738-a1a4-24de78eb8051" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "getter", + "hasretval" + ], + "name": "architecturesInBinary", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isTranslated", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + } + ], + "name": "nsIMacUtils", + "parent": "nsISupports", + "uuid": "5e9072d7-ff95-455e-9466-8af9841a72ec" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "heapMinimize", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hasretval" + ], + "name": "isLowMemoryPlatform", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + } + ], + "name": "nsIMemory", + "parent": "nsISupports", + "uuid": "1e004834-6d8f-425a-bc9c-a2812ed43bb7" + }, + { + "consts": [], + "flags": [ + "function" + ], + "methods": [ + { + "flags": [], + "name": "callback", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsIFinishDumpingCallback", + "parent": "nsISupports", + "uuid": "2dea18fc-fbfa-4bf7-ad45-0efaf5495f5e" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [], + "name": "onDump", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIFile", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIFile", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "onFinish", + "params": [] + } + ], + "name": "nsIDumpGCAndCCLogsCallback", + "parent": "nsISupports", + "uuid": "dc1b2b24-65bd-441b-b6bd-cb5825a7ed14" + }, + { + "consts": [], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [], + "name": "dumpMemoryReportsToNamedFile", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIFinishDumpingCallback", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "dumpMemoryInfoToTempDir", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "dumpGCAndCCLogsToFile", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIDumpGCAndCCLogsCallback", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "dumpGCAndCCLogsToSink", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsICycleCollectorLogSink", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsIMemoryInfoDumper", + "parent": "nsISupports", + "uuid": "48541b74-47ee-4a62-9557-7f4b809bda5c" + }, + { + "consts": [], + "flags": [ + "function" + ], + "methods": [ + { + "flags": [], + "name": "callback", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UTF8STRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT32" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT64" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_UTF8STRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsIHandleReportCallback", + "parent": "nsISupports", + "uuid": "62ef0e1c-dbd6-11e3-aa75-3c970e9f4238" + }, + { + "consts": [ + { + "name": "KIND_NONHEAP", + "type": { + "tag": "TD_INT32" + }, + "value": 0 + }, + { + "name": "KIND_HEAP", + "type": { + "tag": "TD_INT32" + }, + "value": 1 + }, + { + "name": "KIND_OTHER", + "type": { + "tag": "TD_INT32" + }, + "value": 2 + }, + { + "name": "UNITS_BYTES", + "type": { + "tag": "TD_INT32" + }, + "value": 0 + }, + { + "name": "UNITS_COUNT", + "type": { + "tag": "TD_INT32" + }, + "value": 1 + }, + { + "name": "UNITS_COUNT_CUMULATIVE", + "type": { + "tag": "TD_INT32" + }, + "value": 2 + }, + { + "name": "UNITS_PERCENTAGE", + "type": { + "tag": "TD_INT32" + }, + "value": 3 + } + ], + "flags": [], + "methods": [ + { + "flags": [], + "name": "collectReports", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIHandleReportCallback", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + } + ], + "name": "nsIMemoryReporter", + "parent": "nsISupports", + "uuid": "92a36db1-46bd-4fe6-988e-47db47236d8b" + }, + { + "consts": [], + "flags": [ + "function" + ], + "methods": [ + { + "flags": [], + "name": "callback", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsIFinishReportingCallback", + "parent": "nsISupports", + "uuid": "548b3909-c04d-4ca6-8466-b8bee3837457" + }, + { + "consts": [], + "flags": [ + "function" + ], + "methods": [ + { + "flags": [], + "name": "callback", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + } + ], + "name": "nsIHeapAllocatedCallback", + "parent": "nsISupports", + "uuid": "1a80cd0f-0d9e-4397-be69-68ad28fe5175" + }, + { + "consts": [], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [], + "name": "init", + "params": [] + }, + { + "flags": [], + "name": "registerStrongReporter", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIMemoryReporter", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "registerStrongAsyncReporter", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIMemoryReporter", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "registerWeakReporter", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIMemoryReporter", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "registerWeakAsyncReporter", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIMemoryReporter", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "unregisterStrongReporter", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIMemoryReporter", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "unregisterWeakReporter", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIMemoryReporter", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "blockRegistrationAndHideExistingReporters", + "params": [] + }, + { + "flags": [], + "name": "unblockRegistrationAndRestoreOriginalReporters", + "params": [] + }, + { + "flags": [], + "name": "registerStrongReporterEvenIfBlocked", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIMemoryReporter", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "getReports", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIHandleReportCallback", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIFinishReportingCallback", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getReportsExtended", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIHandleReportCallback", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIFinishReportingCallback", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_ASTRING" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "getReportsForThisProcessExtended", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIHandleReportCallback", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_BOOL" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsIFinishReportingCallback", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "in" + ], + "type": { + "name": "nsISupports", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "endReport", + "params": [] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "vsize", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "vsizeMaxContiguous", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "resident", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "residentFast", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "residentPeak", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "residentUnique", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "heapAllocated", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "heapOverheadFraction", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "JSMainRuntimeGCHeap", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "JSMainRuntimeTemporaryPeak", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "JSMainRuntimeCompartmentsSystem", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "JSMainRuntimeCompartmentsUser", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "JSMainRuntimeRealmsSystem", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "JSMainRuntimeRealmsUser", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "imagesContentUsedUncompressed", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "storageSQLite", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "lowMemoryEventsPhysical", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "ghostWindows", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "pageFaultsHard", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "hasMozMallocUsableSize", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isDMDEnabled", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [ + "getter", + "hasretval" + ], + "name": "isDMDRunning", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_BOOL" + } + } + ] + }, + { + "flags": [], + "name": "minimizeMemoryUsage", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "nsIRunnable", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + }, + { + "flags": [], + "name": "sizeOfTab", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "name": "mozIDOMWindowProxy", + "tag": "TD_INTERFACE_TYPE" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT64" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_DOUBLE" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_DOUBLE" + } + } + ] + } + ], + "name": "nsIMemoryReporterManager", + "parent": "nsISupports", + "uuid": "2998574d-8993-407a-b1a5-8ad7417653e1" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "QueryInterface", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_NSID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "iid_is": 0, + "tag": "TD_INTERFACE_IS_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "AddRef", + "params": [] + }, + { + "flags": [ + "hidden" + ], + "name": "Release", + "params": [] + } + ], + "name": "nsISupports", + "parent": null, + "uuid": "00000000-0000-0000-c000-000000000046" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "generateUUID", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_NSIDPTR" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "generateUUIDInPlace", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + } + ], + "name": "nsIUUIDGenerator", + "parent": "nsISupports", + "uuid": "138ad1b2-c694-41cc-b201-333ce936d8b8" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "compare", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_CSTRING" + } + }, + { + "flags": [ + "out" + ], + "type": { + "tag": "TD_INT32" + } + } + ] + } + ], + "name": "nsIVersionComparator", + "parent": "nsISupports", + "uuid": "e6cd620a-edbb-41d2-9e42-9a2ffc8107f3" + }, + { + "consts": [], + "flags": [ + "builtinclass" + ], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "QueryReferent", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_NSID" + } + }, + { + "flags": [ + "out" + ], + "type": { + "iid_is": 0, + "tag": "TD_INTERFACE_IS_TYPE" + } + } + ] + }, + { + "flags": [ + "hidden" + ], + "name": "sizeOfOnlyThis", + "params": [ + { + "flags": [ + "in" + ], + "type": { + "tag": "TD_VOID" + } + } + ] + } + ], + "name": "nsIWeakReference", + "parent": "nsISupports", + "uuid": "9188bc85-f92e-11d2-81ef-0060083a0bcf" + }, + { + "consts": [], + "flags": [], + "methods": [ + { + "flags": [ + "hasretval" + ], + "name": "GetWeakReference", + "params": [ + { + "flags": [ + "out" + ], + "type": { + "name": "nsIWeakReference", + "tag": "TD_INTERFACE_TYPE" + } + } + ] + } + ], + "name": "nsISupportsWeakReference", + "parent": "nsISupports", + "uuid": "9188bc86-f92e-11d2-81ef-0060083a0bcf" + } +] diff --git a/tools/lint/eslint/eslint-plugin-mozilla/update.sh b/tools/lint/eslint/eslint-plugin-mozilla/update.sh new file mode 100755 index 0000000000..240cfdb9c2 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/update.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# Script to regenerate the npm packages used for eslint-plugin-mozilla by the builders. +# Requires + +# Force the scripts working directory to be projdir/tools/lint/eslint/eslint-plugin-mozilla. +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $DIR + +if [ -z "$TASKCLUSTER_ACCESS_TOKEN" -o -z "$TASKCLUSTER_CLIENT_ID" -o -z "$TASKCLUSTER_ROOT_URL" ]; then + echo "Please ensure you have run the taskcluster shell correctly to set" + echo "the TASKCLUSTER_ACCESS_TOKEN, TASKCLUSTER_CLIENT_ID and" + echo "TASKCLUSTER_ROOT_URL environment variables." + echo "See https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint/enabling-rules.html" + exit 1; +fi + +echo "" +echo "Removing node_modules and package-lock.json..." +# Move to the top-level directory. +rm -rf node_modules +rm package-lock.json + +echo "Installing modules for eslint-plugin-mozilla..." +../../../../mach npm install + +echo "Creating eslint-plugin-mozilla.tar.gz..." +tar cvz -f eslint-plugin-mozilla.tar.gz node_modules + +echo "Adding eslint-plugin-mozilla.tar.gz to tooltool..." +rm -f manifest.tt +../../../../python/mozbuild/mozbuild/action/tooltool.py add --visibility public --unpack eslint-plugin-mozilla.tar.gz --url="https://tooltool.mozilla-releng.net/" + +echo "Uploading eslint-plugin-mozilla.tar.gz to tooltool..." +../../../../python/mozbuild/mozbuild/action/tooltool.py upload --message "node_modules folder update for tools/lint/eslint/eslint-plugin-mozilla" --url="https://tooltool.mozilla-releng.net/" + +echo "Cleaning up..." +rm eslint-plugin-mozilla.tar.gz + +echo "" +echo "Update complete, please commit and check in your changes." diff --git a/tools/lint/eslint/eslint-plugin-spidermonkey-js/LICENSE b/tools/lint/eslint/eslint-plugin-spidermonkey-js/LICENSE new file mode 100644 index 0000000000..e87a115e46 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-spidermonkey-js/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/environments/self-hosted.js b/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/environments/self-hosted.js new file mode 100644 index 0000000000..37ae42bfa3 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/environments/self-hosted.js @@ -0,0 +1,180 @@ +/** + * @fileoverview Add environment defaults to SpiderMonkey's self-hosted JS. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const path = require("path"); +const fs = require("fs"); + +let gRootDir = null; + +// Copied from `tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js`. +function getRootDir() { + if (!gRootDir) { + function searchUpForIgnore(dirName, filename) { + let parsed = path.parse(dirName); + while (parsed.root !== dirName) { + if (fs.existsSync(path.join(dirName, filename))) { + return dirName; + } + // Move up a level + dirName = parsed.dir; + parsed = path.parse(dirName); + } + return null; + } + + let possibleRoot = searchUpForIgnore( + path.dirname(module.filename), + ".eslintignore" + ); + if (!possibleRoot) { + possibleRoot = searchUpForIgnore(path.resolve(), ".eslintignore"); + } + if (!possibleRoot) { + possibleRoot = searchUpForIgnore(path.resolve(), "package.json"); + } + if (!possibleRoot) { + // We've couldn't find a root from the module or CWD, so lets just go + // for the CWD. We really don't want to throw if possible, as that + // tends to give confusing results when used with ESLint. + possibleRoot = process.cwd(); + } + + gRootDir = possibleRoot; + } + + return gRootDir; +} + +function tryReadFile(filePath) { + let absPath = path.join(getRootDir(), filePath); + if (!fs.existsSync(absPath)) { + // Safely handle the case when the file wasn't found, because throwing + // errors can lead to confusing result when used with ESLint. + return ""; + } + return fs.readFileSync(absPath, "utf-8"); +} + +// Search for top-level declarations, #defines, and #includes. +function addGlobalsFrom(dirName, fileName, globals) { + let filePath = path.join(dirName, fileName); + + // Definitions are separated by line. + let lines = tryReadFile(filePath).split("\n"); + + // We don't have to fully parse the source code, because it's formatted + // through "prettier", which means we know the exact code structure. + // + // |class| is disallowed in self-hosted code, so we don't have to handle it. + for (let line of lines) { + if ( + line.startsWith("function") || + line.startsWith("function*") || + line.startsWith("async function") || + line.startsWith("async function*") + ) { + let m = line.match(/^(?:async )?function(?:\*)?\s+([\w\$]+)\s*\(/); + if (m) { + globals[m[1]] = "readonly"; + } + } else if ( + line.startsWith("var") || + line.startsWith("let") || + line.startsWith("const") + ) { + let m = line.match(/^(?:var|let|const)\s+([\w\$]+)\s*[;=]/); + if (m) { + globals[m[1]] = "readonly"; + } + } else if (line.startsWith("#define")) { + let m = line.match(/^#define (\w+)/); + if (m) { + globals[m[1]] = "readonly"; + } + } else if (line.startsWith("#include")) { + let m = line.match(/^#include \"([\w\.]+)\"$/); + if (m) { + // Also process definitions from includes. + addGlobalsFrom(dirName, m[1], globals); + } + } + } +} + +function selfHostingDefines(dirName = "js/src/builtin/") { + let absDir = path.join(getRootDir(), dirName); + if (!fs.existsSync(absDir)) { + // See |tryReadFile| for why we avoid to throw any errors. + return {}; + } + + // Search sub-directories and js-files within |dirName|. + let dirs = []; + let jsFiles = []; + for (let name of fs.readdirSync(absDir)) { + let stat = fs.statSync(path.join(absDir, name)); + if (stat.isDirectory()) { + dirs.push(name); + } else if (stat.isFile() && name.endsWith(".js")) { + jsFiles.push(name); + } + } + + let globals = Object.create(null); + + // Process each js-file. + for (let jsFile of jsFiles) { + addGlobalsFrom(dirName, jsFile, globals); + } + + // Recursively traverse all sub-directories. + for (let dir of dirs) { + globals = { ...globals, ...selfHostingDefines(path.join(dirName, dir)) }; + } + + return globals; +} + +function selfHostingFunctions() { + // Definitions can be spread across multiple lines and may have extra + // whitespace, so we simply remove all whitespace and match over the complete + // file. + let content = tryReadFile("js/src/vm/SelfHosting.cpp").replace(/\s+/g, ""); + + let globals = Object.create(null); + for (let m of content.matchAll(/(?:JS_FN|JS_INLINABLE_FN)\("(\w+)"/g)) { + globals[m[1]] = "readonly"; + } + return globals; +} + +function errorNumbers() { + // Definitions are separated by line. + let lines = tryReadFile("js/public/friend/ErrorNumbers.msg").split("\n"); + + let globals = Object.create(null); + for (let line of lines) { + let m = line.match(/^MSG_DEF\((\w+),/); + if (m) { + globals[m[1]] = "readonly"; + } + } + return globals; +} + +const globals = { + ...selfHostingDefines(), + ...selfHostingFunctions(), + ...errorNumbers(), +}; + +module.exports = { + globals, +}; diff --git a/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/index.js b/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/index.js new file mode 100644 index 0000000000..d9d40af8c6 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/index.js @@ -0,0 +1,20 @@ +/** + * @fileoverview A processor to help parse the spidermonkey js code. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Plugin Definition +// ------------------------------------------------------------------------------ +module.exports = { + processors: { + processor: require("../lib/processors/self-hosted"), + }, + environments: { + environment: require("../lib/environments/self-hosted"), + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/processors/self-hosted.js b/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/processors/self-hosted.js new file mode 100644 index 0000000000..02201a329b --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/processors/self-hosted.js @@ -0,0 +1,129 @@ +/** + * @fileoverview Remove macros from SpiderMonkey's self-hosted JS. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const path = require("path"); +const fs = require("fs"); + +const selfHostedRegex = /js\/src\/builtin\/.*?\.js$/; +const macroRegex = + /\s*\#(if|ifdef|else|elif|endif|include|define|undef|error).*/; + +function isSelfHostedFile(filename) { + if (path.win32) { + filename = filename.split(path.sep).join("/"); + } + return selfHostedRegex.test(filename); +} + +function tryReadFile(filePath) { + if (!path.isAbsolute(filePath)) { + return ""; + } + if (!fs.existsSync(filePath)) { + // Safely handle the case when the file wasn't found, because throwing + // errors can lead to confusing result when used with ESLint. + return ""; + } + return fs.readFileSync(filePath, "utf-8"); +} + +// Adjust the range of fixes to match the original source code. +function createFix(lines, message) { + let { line, column, fix } = message; + + // Line and column are 1-based. Make sure we got a valid input. + if (line <= 0 || column <= 0) { + return null; + } + + // Reject to create a fix when the line is out of range for some reason. + if (line > lines.length) { + return null; + } + + // Find the absolute start position of the line in the original file. + let startOfLine = 0; + for (let i = 0; i < line - 1; ++i) { + // Add the length of the line, including its line separator. + startOfLine += lines[i].length + "\n".length; + } + + // Add the 1-based column to the start of line to get the start position. + let start = startOfLine + (column - 1); + + // Add the fix range to get the end position. + let end = start + (fix.range[1] - fix.range[0]); + + // And finally return the new fix object. + return { text: fix.text, range: [start, end] }; +} + +module.exports = { + preprocess(text, filename) { + if (!isSelfHostedFile(filename)) { + return [text]; + } + + let lines = text.split(/\n/); + for (let i = 0; i < lines.length; i++) { + if (!macroRegex.test(lines[i])) { + // No macro here, nothing to do. + continue; + } + + for (; i < lines.length; i++) { + // The macro isn't correctly indented, so we need to instruct + // prettier to ignore them. + lines[i] = "// prettier-ignore -- " + lines[i]; + + // If the line ends with a backslash (\), the next line + // is also part of part of the macro. + if (!lines[i].endsWith("\\")) { + break; + } + } + } + + return [lines.join("\n")]; + }, + + postprocess(messages, filename) { + // Don't attempt to create fixes for any non-selfhosted files. + if (!isSelfHostedFile(filename)) { + return [].concat(...messages); + } + + let lines = null; + + let result = []; + for (let message of messages.flat()) { + if (message.fix) { + if (lines === null) { + lines = tryReadFile(filename).split(/\n/); + } + + let fix = createFix(lines, message); + if (fix) { + message.fix = fix; + } else { + // We couldn't create a fix, so we better remove the passed in fix, + // because its range points to the preprocessor output, but the post- + // processor must translate it into a range of the original source. + delete message.fix; + } + } + + result.push(message); + } + return result; + }, + + supportsAutofix: true, +}; diff --git a/tools/lint/eslint/eslint-plugin-spidermonkey-js/package.json b/tools/lint/eslint/eslint-plugin-spidermonkey-js/package.json new file mode 100644 index 0000000000..7d96b5b1c4 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-spidermonkey-js/package.json @@ -0,0 +1,28 @@ +{ + "name": "eslint-plugin-spidermonkey-js", + "version": "0.1.1", + "description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla SpiderMonkey project.", + "keywords": [ + "eslint", + "eslintplugin", + "eslint-plugin", + "mozilla", + "spidermonkey" + ], + "bugs": { + "url": "https://bugzilla.mozilla.org/enter_bug.cgi?product=Testing&component=Lint" + }, + "homepage": "http://firefox-source-docs.mozilla.org/tools/lint/linters/eslint-plugin-spidermonkey-js.html", + "repository": { + "type": "hg", + "url": "https://hg.mozilla.org/mozilla-central/" + }, + "author": "Mozilla", + "main": "lib/index.js", + "dependencies": {}, + "devDependencies": {}, + "engines": { + "node": ">=6.9.1" + }, + "license": "MPL-2.0" +} diff --git a/tools/lint/eslint/manifest.tt b/tools/lint/eslint/manifest.tt new file mode 100644 index 0000000000..c1ec658b0e --- /dev/null +++ b/tools/lint/eslint/manifest.tt @@ -0,0 +1,10 @@ +[ + { + "filename": "eslint.tar.gz", + "size": 22086762, + "algorithm": "sha512", + "digest": "abf5caa29669e1f8f889459b7af074f2744c7ba7e51901a1b3ad3e504c3f331d360616a0d9c1f0114034dce33874ca7ed3971a8ae7f38f21ae2a6b4514a0e5eb", + "unpack": true, + "visibility": "public" + } +]
\ No newline at end of file diff --git a/tools/lint/eslint/setup_helper.py b/tools/lint/eslint/setup_helper.py new file mode 100644 index 0000000000..2f2074d2cf --- /dev/null +++ b/tools/lint/eslint/setup_helper.py @@ -0,0 +1,423 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import json +import os +import platform +import re +import subprocess +import sys +from filecmp import dircmp + +from mozbuild.nodeutil import ( + NODE_MIN_VERSION, + NPM_MIN_VERSION, + find_node_executable, + find_npm_executable, +) +from mozfile.mozfile import remove as mozfileremove +from packaging.version import Version + +NODE_MACHING_VERSION_NOT_FOUND_MESSAGE = """ +Could not find Node.js executable later than %s. + +Executing `mach bootstrap --no-system-changes` should +install a compatible version in ~/.mozbuild on most platforms. +""".strip() + +NPM_MACHING_VERSION_NOT_FOUND_MESSAGE = """ +Could not find npm executable later than %s. + +Executing `mach bootstrap --no-system-changes` should +install a compatible version in ~/.mozbuild on most platforms. +""".strip() + +NODE_NOT_FOUND_MESSAGE = """ +nodejs is either not installed or is installed to a non-standard path. + +Executing `mach bootstrap --no-system-changes` should +install a compatible version in ~/.mozbuild on most platforms. +""".strip() + +NPM_NOT_FOUND_MESSAGE = """ +Node Package Manager (npm) is either not installed or installed to a +non-standard path. + +Executing `mach bootstrap --no-system-changes` should +install a compatible version in ~/.mozbuild on most platforms. +""".strip() + + +VERSION_RE = re.compile(r"^\d+\.\d+\.\d+$") +CARET_VERSION_RANGE_RE = re.compile(r"^\^((\d+)\.\d+\.\d+)$") + +project_root = None + + +def eslint_maybe_setup(): + """Setup ESLint only if it is needed.""" + has_issues, needs_clobber = eslint_module_needs_setup() + + if has_issues: + eslint_setup(needs_clobber) + + +def eslint_setup(should_clobber=False): + """Ensure eslint is optimally configured. + + This command will inspect your eslint configuration and + guide you through an interactive wizard helping you configure + eslint for optimal use on Mozilla projects. + """ + package_setup(get_project_root(), "eslint", should_clobber=should_clobber) + + +def remove_directory(path): + print("Clobbering %s..." % path) + if sys.platform.startswith("win") and have_winrm(): + process = subprocess.Popen(["winrm", "-rf", path]) + process.wait() + else: + mozfileremove(path) + + +def package_setup( + package_root, + package_name, + should_update=False, + should_clobber=False, + no_optional=False, +): + """Ensure `package_name` at `package_root` is installed. + + When `should_update` is true, clobber, install, and produce a new + "package-lock.json" file. + + This populates `package_root/node_modules`. + + """ + orig_project_root = get_project_root() + orig_cwd = os.getcwd() + + if should_update: + should_clobber = True + + try: + set_project_root(package_root) + sys.path.append(os.path.dirname(__file__)) + + # npm sometimes fails to respect cwd when it is run using check_call so + # we manually switch folders here instead. + project_root = get_project_root() + os.chdir(project_root) + + if should_clobber: + remove_directory(os.path.join(project_root, "node_modules")) + + # Always remove the eslint-plugin-mozilla sub-directory as that can + # sometimes conflict with the top level node_modules, see bug 1809036. + remove_directory( + os.path.join( + get_eslint_module_path(), "eslint-plugin-mozilla", "node_modules" + ) + ) + + npm_path, _ = find_npm_executable() + if not npm_path: + return 1 + + node_path, _ = find_node_executable() + if not node_path: + return 1 + + extra_parameters = ["--loglevel=error"] + + if no_optional: + extra_parameters.append("--no-optional") + + package_lock_json_path = os.path.join(get_project_root(), "package-lock.json") + + if should_update: + cmd = [npm_path, "install"] + mozfileremove(package_lock_json_path) + else: + cmd = [npm_path, "ci"] + + # On non-Windows, ensure npm is called via node, as node may not be in the + # path. + if platform.system() != "Windows": + cmd.insert(0, node_path) + + cmd.extend(extra_parameters) + + # Ensure that bare `node` and `npm` in scripts, including post-install scripts, finds the + # binary we're invoking with. Without this, it's easy for compiled extensions to get + # mismatched versions of the Node.js extension API. + path = os.environ.get("PATH", "").split(os.pathsep) + node_dir = os.path.dirname(node_path) + if node_dir not in path: + path = [node_dir] + path + + print('Installing %s for mach using "%s"...' % (package_name, " ".join(cmd))) + result = call_process( + package_name, cmd, append_env={"PATH": os.pathsep.join(path)} + ) + + if not result: + return 1 + + bin_path = os.path.join( + get_project_root(), "node_modules", ".bin", package_name + ) + + print("\n%s installed successfully!" % package_name) + print("\nNOTE: Your local %s binary is at %s\n" % (package_name, bin_path)) + + finally: + set_project_root(orig_project_root) + os.chdir(orig_cwd) + + +def call_process(name, cmd, cwd=None, append_env={}): + env = dict(os.environ) + env.update(append_env) + + try: + with open(os.devnull, "w") as fnull: + subprocess.check_call(cmd, cwd=cwd, stdout=fnull, env=env) + except subprocess.CalledProcessError: + if cwd: + print("\nError installing %s in the %s folder, aborting." % (name, cwd)) + else: + print("\nError installing %s, aborting." % name) + + return False + + return True + + +def expected_eslint_modules(): + # Read the expected version of ESLint and external modules + expected_modules_path = os.path.join(get_project_root(), "package.json") + with open(expected_modules_path, encoding="utf-8") as f: + sections = json.load(f) + expected_modules = sections.get("dependencies", {}) + expected_modules.update(sections.get("devDependencies", {})) + + # Also read the in-tree ESLint plugin mozilla information, to ensure the + # dependencies are up to date. + mozilla_json_path = os.path.join( + get_eslint_module_path(), "eslint-plugin-mozilla", "package.json" + ) + with open(mozilla_json_path, encoding="utf-8") as f: + dependencies = json.load(f).get("dependencies", {}) + expected_modules.update(dependencies) + + # Also read the in-tree ESLint plugin spidermonkey information, to ensure the + # dependencies are up to date. + mozilla_json_path = os.path.join( + get_eslint_module_path(), "eslint-plugin-spidermonkey-js", "package.json" + ) + with open(mozilla_json_path, encoding="utf-8") as f: + expected_modules.update(json.load(f).get("dependencies", {})) + + return expected_modules + + +def check_eslint_files(node_modules_path, name): + def check_file_diffs(dcmp): + # Diff files only looks at files that are different. Not for files + # that are only present on one side. This should be generally OK as + # new files will need to be added in the index.js for the package. + if dcmp.diff_files and dcmp.diff_files != ["package.json"]: + return True + + result = False + + # Again, we only look at common sub directories for the same reason + # as above. + for sub_dcmp in dcmp.subdirs.values(): + result = result or check_file_diffs(sub_dcmp) + + return result + + dcmp = dircmp( + os.path.join(node_modules_path, name), + os.path.join(get_eslint_module_path(), name), + ) + + return check_file_diffs(dcmp) + + +def eslint_module_needs_setup(): + has_issues = False + needs_clobber = False + node_modules_path = os.path.join(get_project_root(), "node_modules") + + for name, expected_data in expected_eslint_modules().items(): + # expected_eslint_modules returns a string for the version number of + # dependencies for installation of eslint generally, and an object + # for our in-tree plugins (which contains the entire module info). + if "version" in expected_data: + version_range = expected_data["version"] + else: + version_range = expected_data + + path = os.path.join(node_modules_path, name, "package.json") + + if not os.path.exists(path): + print("%s v%s needs to be installed locally." % (name, version_range)) + has_issues = True + continue + data = json.load(open(path, encoding="utf-8")) + + if version_range.startswith("file:"): + # We don't need to check local file installations for versions, as + # these are symlinked, so we'll always pick up the latest. + continue + + if name == "eslint" and Version("4.0.0") > Version(data["version"]): + print("ESLint is an old version, clobbering node_modules directory") + needs_clobber = True + has_issues = True + continue + + if not version_in_range(data["version"], version_range): + print("%s v%s should be v%s." % (name, data["version"], version_range)) + has_issues = True + continue + + return has_issues, needs_clobber + + +def version_in_range(version, version_range): + """ + Check if a module version is inside a version range. Only supports explicit versions and + caret ranges for the moment, since that's all we've used so far. + """ + if version == version_range: + return True + + version_match = VERSION_RE.match(version) + if not version_match: + raise RuntimeError("mach eslint doesn't understand module version %s" % version) + version = Version(version) + + # Caret ranges as specified by npm allow changes that do not modify the left-most non-zero + # digit in the [major, minor, patch] tuple. The code below assumes the major digit is + # non-zero. + range_match = CARET_VERSION_RANGE_RE.match(version_range) + if range_match: + range_version = range_match.group(1) + range_major = int(range_match.group(2)) + + range_min = Version(range_version) + range_max = Version("%d.0.0" % (range_major + 1)) + + return range_min <= version < range_max + + return False + + +def get_possible_node_paths_win(): + """ + Return possible nodejs paths on Windows. + """ + if platform.system() != "Windows": + return [] + + return list( + { + "%s\\nodejs" % os.environ.get("SystemDrive"), + os.path.join(os.environ.get("ProgramFiles"), "nodejs"), + os.path.join(os.environ.get("PROGRAMW6432"), "nodejs"), + os.path.join(os.environ.get("PROGRAMFILES"), "nodejs"), + } + ) + + +def get_version(path): + try: + version_str = subprocess.check_output( + [path, "--version"], stderr=subprocess.STDOUT, universal_newlines=True + ) + return version_str + except (subprocess.CalledProcessError, OSError): + return None + + +def set_project_root(root=None): + """Sets the project root to the supplied path, or works out what the root + is based on looking for 'mach'. + + Keyword arguments: + root - (optional) The path to set the root to. + """ + global project_root + + if root: + project_root = root + return + + file_found = False + folder = os.getcwd() + + while folder: + if os.path.exists(os.path.join(folder, "mach")): + file_found = True + break + else: + folder = os.path.dirname(folder) + + if file_found: + project_root = os.path.abspath(folder) + + +def get_project_root(): + """Returns the absolute path to the root of the project, see set_project_root() + for how this is determined. + """ + global project_root + + if not project_root: + set_project_root() + + return project_root + + +def get_eslint_module_path(): + return os.path.join(get_project_root(), "tools", "lint", "eslint") + + +def check_node_executables_valid(): + node_path, version = find_node_executable() + if not node_path: + print(NODE_NOT_FOUND_MESSAGE) + return False + if not version: + print(NODE_MACHING_VERSION_NOT_FOUND_MESSAGE % NODE_MIN_VERSION) + return False + + npm_path, version = find_npm_executable() + if not npm_path: + print(NPM_NOT_FOUND_MESSAGE) + return False + if not version: + print(NPM_MACHING_VERSION_NOT_FOUND_MESSAGE % NPM_MIN_VERSION) + return False + + return True + + +def have_winrm(): + # `winrm -h` should print 'winrm version ...' and exit 1 + try: + p = subprocess.Popen( + ["winrm.exe", "-h"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) + return p.wait() == 1 and p.stdout.read().startswith("winrm") + except Exception: + return False diff --git a/tools/lint/eslint/update.sh b/tools/lint/eslint/update.sh new file mode 100755 index 0000000000..025f747135 --- /dev/null +++ b/tools/lint/eslint/update.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# Script to regenerate the npm packages used for ESLint by the builders. +# Requires + +# Force the scripts working directory to be projdir/tools/lint/eslint. +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $DIR + +if [ -z "$TASKCLUSTER_ACCESS_TOKEN" -o -z "$TASKCLUSTER_CLIENT_ID" -o -z "$TASKCLUSTER_ROOT_URL" ]; then + echo "Please ensure you have run the taskcluster shell correctly to set" + echo "the TASKCLUSTER_ACCESS_TOKEN, TASKCLUSTER_CLIENT_ID and" + echo "TASKCLUSTER_ROOT_URL environment variables." + echo "See https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint/enabling-rules.html" + exit 1; +fi + +echo "" +echo "Removing node_modules and package-lock.json..." +# Move to the top-level directory. +cd ../../../ +rm -rf node_modules/ +rm -rf tools/lint/eslint/eslint-plugin-mozilla/node_modules +rm package-lock.json + +echo "Installing eslint and external plugins..." +# ESLint and all _external_ plugins are listed in this directory's package.json, +# so a regular `npm install` will install them at the specified versions. +# The in-tree eslint-plugin-mozilla is kept out of this tooltool archive on +# purpose so that it can be changed by any developer without requiring tooltool +# access to make changes. +./mach npm install + +echo "Creating eslint.tar.gz..." +tar cvz --exclude=eslint-plugin-mozilla --exclude=eslint-plugin-spidermonkey-js -f eslint.tar.gz node_modules + +echo "Adding eslint.tar.gz to tooltool..." +rm tools/lint/eslint/manifest.tt +./python/mozbuild/mozbuild/action/tooltool.py add --visibility public --unpack eslint.tar.gz + +echo "Uploading eslint.tar.gz to tooltool..." +./python/mozbuild/mozbuild/action/tooltool.py upload --message "node_modules folder update for tools/lint/eslint" + +echo "Cleaning up..." +mv manifest.tt tools/lint/eslint/manifest.tt +rm eslint.tar.gz + +cd $DIR + +echo "" +echo "Update complete, please commit and check in your changes." |