You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ha...@apache.org on 2026/10/15 03:11:01 UTC
(superset) branch master updated: feat(build): migrate custom lint rule to Oxlint (#44201)
This is an automated email from the ASF dual-hosted git repository.
hainenber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 8db419ce1ab feat(build): migrate custom lint rule to Oxlint (#44201)
8db419ce1ab is described below
commit 8db419ce1abf88dcfe0faaf42fe60fab6e05b218
Author: Đỗ Trọng Hải <41...@users.noreply.github.com>
AuthorDate: Thu Oct 15 10:10:52 2026 +0700
feat(build): migrate custom lint rule to Oxlint (#44201)
Signed-off-by: hainenber <do...@gmail.com>
---
.github/workflows/superset-frontend.yml | 3 +-
scripts/eslint.sh | 30 -
.../i18n-strings/index.js} | 116 +-
.../i18n-strings}/no-eager-t-in-config.test.ts | 13 +-
.../i18n-strings}/no-template-vars.test.ts | 12 +-
.../i18n-strings}/package.json | 9 +-
.../index.ts => custom-lint-rules/icons/index.js} | 61 +-
.../icons}/no-fontawesome.test.ts | 13 +-
.../icons}/package.json | 9 +-
.../theme-colors/colors.js} | 7 +-
.../theme-colors/index.js} | 111 +-
.../theme-colors/no-literal-colors.test.ts | 81 ++
.../theme-colors}/package.json | 12 +-
superset-frontend/eslint.config.minimal.js | 130 --
superset-frontend/oxlint.custom-lint-rules.mts | 121 ++
superset-frontend/oxlint.json | 20 +-
superset-frontend/package-lock.json | 1473 +-------------------
superset-frontend/package.json | 28 +-
superset-frontend/scripts/check-custom-rules.js | 6 +-
.../scripts/internal/oxlint-metrics-uploader.js | 174 +--
.../spec/scripts/oxlint-metrics-uploader.test.ts | 327 ++++-
superset-frontend/tsconfig.json | 2 +-
22 files changed, 861 insertions(+), 1897 deletions(-)
diff --git a/.github/workflows/superset-frontend.yml b/.github/workflows/superset-frontend.yml
index 054dd55183e..2a5cb34abb5 100644
--- a/.github/workflows/superset-frontend.yml
+++ b/.github/workflows/superset-frontend.yml
@@ -153,10 +153,11 @@ jobs:
run: |
zstd -d < docker-image.tar.zst | docker load
+ # The last weird node command is to run tests fo custom Superset lint rules
- name: lint
run: |
docker run --rm $TAG bash -c \
- "npm i && npm run lint"
+ "npm i && npm run lint && node --import tsx --test custom-lint-rules/**/*.test.ts"
- name: tsc
run: |
diff --git a/scripts/eslint.sh b/scripts/eslint.sh
deleted file mode 100755
index b5d5dd4915e..00000000000
--- a/scripts/eslint.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env bash
-
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -e
-
-script_dir="$(dirname "$(realpath "$0")")"
-root_dir="$(dirname "$script_dir")"
-frontend_dir=superset-frontend
-
-if [[ ! -d "$root_dir/$frontend_dir" ]]; then
- echo "Error: $frontend_dir directory not found in $root_dir" >&2
- exit 1
-fi
-
-cd "$root_dir/$frontend_dir"
-npm run lint-fix -- "${@//$frontend_dir\//}"
diff --git a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/index.ts b/superset-frontend/custom-lint-rules/i18n-strings/index.js
similarity index 69%
rename from superset-frontend/eslint-rules/eslint-plugin-i18n-strings/index.ts
rename to superset-frontend/custom-lint-rules/i18n-strings/index.js
index 62c3094d8b6..737c7fb33c5 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/index.ts
+++ b/superset-frontend/custom-lint-rules/i18n-strings/index.js
@@ -22,14 +22,15 @@
* @author Apache
*/
-import type { Rule } from 'eslint';
-import type { Node } from 'estree';
-
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
-const plugin: { rules: Record<string, Rule.RuleModule> } = {
+/** @type {{ rules: Record<string, import('oxlint').Rule.RuleModule> }} */
+const plugin = {
+ meta: {
+ name: 'i18n-strings',
+ },
rules: {
'no-template-vars': {
meta: {
@@ -39,17 +40,22 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
},
schema: [],
},
- create(context: Rule.RuleContext): Rule.RuleListener {
- function handler(node: Node): void {
- const callNode = node as Node & {
- arguments: Array<Node & { type: string; expressions?: Node[] }>;
- };
+ /** @param {import('eslint').Rule.RuleContext} context */
+ create(context) {
+ /** @param {import('estree').Node} node */
+ function handler(node) {
+ /**
+ * @type {import('estree').Node & {
+ * arguments: Array<import('estree').Node & {
+ * type: string;
+ * expressions?: import('estree').Node[];
+ * }>;
+ * }}
+ */
+ const callNode = node;
// Check all arguments (e.g., tn has singular and plural templates)
for (const arg of callNode.arguments ?? []) {
- if (
- arg.type === 'TemplateLiteral' &&
- (arg as Node & { expressions?: Node[] }).expressions?.length
- ) {
+ if (arg.type === 'TemplateLiteral' && arg.expressions?.length) {
context.report({
node,
message:
@@ -90,23 +96,29 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
'Eager `{{property}}: {{fn}}(...)` is evaluated at module load, before i18n is initialized. Wrap in an arrow function: `{{property}}: () => {{fn}}(...)`.',
},
},
- create(context: Rule.RuleContext): Rule.RuleListener {
- const watchedProps: string[] = context.options[0]?.properties ?? [
+ /** @param {import('oxlint').Rule.RuleContext} context */
+ create(context) {
+ /** @type {string[]} */
+ const watchedProps = context?.options?.[0]?.properties ?? [
'label',
'description',
];
const TRANSLATE_FNS = new Set(['t', 'tn']);
- function handler(node: Node): void {
- const prop = node as Node & {
- key: { type: string; name?: string; value?: string };
- value: Node & {
- type: string;
- callee?: { type: string; name?: string };
- };
- shorthand?: boolean;
- computed?: boolean;
- };
+ /** @param {import('estree').Node} node */
+ function handler(node) {
+ /**
+ * @type {import('estree').Node & {
+ * key: { type: string; name?: string; value?: string };
+ * value: import('estree').Node & {
+ * type: string;
+ * callee?: { type: string; name?: string };
+ * };
+ * shorthand?: boolean;
+ * computed?: boolean;
+ * }}
+ */
+ const prop = node;
if (prop.shorthand || prop.computed) return;
const keyName =
@@ -153,21 +165,22 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
},
schema: [],
},
- create(context: Rule.RuleContext): Rule.RuleListener {
- function isTitleCase(str: string): boolean {
+ /** @param {import('oxlint').Rule.RuleContext} context */
+ create(context) {
+ /** @param {string} str */
+ function isTitleCase(str) {
// Match "Delete Dataset", "Create Chart", etc. (2+ title-cased words)
return /^[A-Z][a-z]+(\s+[A-Z][a-z]*)+$/.test(str);
}
- function isButtonContext(node: Node & { parent?: Node }): boolean {
- const { parent } = node as Node & {
- parent?: Node & Record<string, unknown>;
- };
+ /** @param {import('estree').Node & { parent?: import('estree').Node }} node */
+ function isButtonContext(node) {
+ const { parent } = node;
if (!parent) return false;
// Check for button-specific props
if (parent.type === 'Property') {
- const key = (parent as unknown as { key: { name: string } }).key
+ const key = /** @type {{ key: { name: string } }} */ (parent).key
.name;
return [
'primaryButtonName',
@@ -179,14 +192,15 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
// Check for Button components
// Cast to string because ESTree Node type doesn't include JSX types
- if ((parent.type as string) === 'JSXExpressionContainer') {
- const jsx = (parent as Node & { parent?: Node }).parent as
- | (Node & {
- type: string;
- openingElement?: { name: { name: string } };
- })
- | undefined;
- if ((jsx?.type as string) === 'JSXElement') {
+ if (parent.type === 'JSXExpressionContainer') {
+ /**
+ * @type {(import('estree').Node & {
+ * type: string;
+ * openingElement?: { name: { name: string } };
+ * }) | undefined}
+ */
+ const jsx = parent.parent;
+ if (jsx?.type === 'JSXElement') {
const elementName = jsx?.openingElement?.name.name;
return elementName === 'Button';
}
@@ -195,22 +209,26 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
return false;
}
- function handler(node: Node): void {
- const callNode = node as Node & {
- arguments: Array<Node & { type: string; value?: unknown }>;
- };
+ /** @param {import('estree').Node} node */
+ function handler(node) {
+ /**
+ * @type {import('estree').Node & {
+ * arguments: Array<import('estree').Node & {
+ * type: string;
+ * value?: unknown;
+ * }>;
+ * }}
+ */
+ const callNode = node;
// Check all string literal arguments (e.g., tn has singular and plural)
for (const arg of callNode.arguments ?? []) {
if (arg.type === 'Literal' && typeof arg.value === 'string') {
const text = arg.value;
- if (
- isButtonContext(node as Node & { parent?: Node }) &&
- isTitleCase(text)
- ) {
+ if (isButtonContext(node) && isTitleCase(text)) {
const sentenceCase = text
.toLowerCase()
- .replace(/^\w/, (c: string) => c.toUpperCase());
+ .replace(/^\w/, c => c.toUpperCase());
context.report({
node: arg,
message: `Button text should use sentence case: "${text}" should be "${sentenceCase}"`,
diff --git a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/no-eager-t-in-config.test.ts b/superset-frontend/custom-lint-rules/i18n-strings/no-eager-t-in-config.test.ts
similarity index 92%
rename from superset-frontend/eslint-rules/eslint-plugin-i18n-strings/no-eager-t-in-config.test.ts
rename to superset-frontend/custom-lint-rules/i18n-strings/no-eager-t-in-config.test.ts
index e9096087cb3..4278deb2fc0 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/no-eager-t-in-config.test.ts
+++ b/superset-frontend/custom-lint-rules/i18n-strings/no-eager-t-in-config.test.ts
@@ -16,13 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { type Rule, RuleTester } from 'eslint';
+
+import { RuleTester } from 'oxlint/plugins-dev';
+import { describe, it } from 'node:test';
import plugin from '.';
-const ruleTester = new RuleTester({
- parserOptions: { ecmaVersion: 2020, sourceType: 'module' },
-} as any);
-const rule: Rule.RuleModule = plugin.rules['no-eager-t-in-config'];
+RuleTester.describe = describe;
+RuleTester.it = it;
+
+const ruleTester = new RuleTester();
+const rule = plugin.rules['no-eager-t-in-config'];
ruleTester.run('no-eager-t-in-config', rule, {
valid: [
diff --git a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/no-template-vars.test.ts b/superset-frontend/custom-lint-rules/i18n-strings/no-template-vars.test.ts
similarity index 88%
rename from superset-frontend/eslint-rules/eslint-plugin-i18n-strings/no-template-vars.test.ts
rename to superset-frontend/custom-lint-rules/i18n-strings/no-template-vars.test.ts
index 8a075939141..995c0470967 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/no-template-vars.test.ts
+++ b/superset-frontend/custom-lint-rules/i18n-strings/no-template-vars.test.ts
@@ -21,16 +21,20 @@
* @fileoverview Rule to warn about translation template variables
* @author Apache
*/
-/* eslint-disable no-template-curly-in-string */
-import { type Rule, RuleTester } from 'eslint';
+
+import { RuleTester } from 'oxlint/plugins-dev';
+import { describe, it } from 'node:test';
import plugin from '.';
+RuleTester.describe = describe;
+RuleTester.it = it;
+
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
-const ruleTester = new RuleTester({ languageOptions: { ecmaVersion: 6 } });
-const rule: Rule.RuleModule = plugin.rules['no-template-vars'];
+const ruleTester = new RuleTester();
+const rule = plugin.rules['no-template-vars'];
const errors: Array<{ message: string }> = [
{
diff --git a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/package.json b/superset-frontend/custom-lint-rules/i18n-strings/package.json
similarity index 64%
rename from superset-frontend/eslint-rules/eslint-plugin-i18n-strings/package.json
rename to superset-frontend/custom-lint-rules/i18n-strings/package.json
index 70a5353c9fc..ea6c25c978a 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/package.json
+++ b/superset-frontend/custom-lint-rules/i18n-strings/package.json
@@ -1,17 +1,20 @@
{
- "name": "@superset-ui/eslint-plugin-i18n-strings",
+ "name": "@superset-ui/lint-plugin-i18n-strings",
"version": "1.0.0",
"description": "Warns about translation variables",
"keywords": [],
"license": "Apache-2.0",
"author": "Apache",
"type": "module",
- "main": "index.ts",
+ "main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {},
"peerDependencies": {
- "eslint": ">=0.8.0"
+ "@oxlint/plugins": "*",
+ "@types/estree": "*",
+ "jest": "*",
+ "oxlint": "*"
}
}
diff --git a/superset-frontend/eslint-rules/eslint-plugin-icons/index.ts b/superset-frontend/custom-lint-rules/icons/index.js
similarity index 66%
rename from superset-frontend/eslint-rules/eslint-plugin-icons/index.ts
rename to superset-frontend/custom-lint-rules/icons/index.js
index 6a5c186d3f7..b22ce322a19 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-icons/index.ts
+++ b/superset-frontend/custom-lint-rules/icons/index.js
@@ -22,33 +22,43 @@
* @author Apache
*/
-import type { Rule } from 'eslint';
-import type { Node } from 'estree';
-
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
-interface JSXAttribute {
- name?: { name: string };
- value?: { type: string; value?: string; expression?: { value: string } };
-}
+/**
+ * @typedef {Object} JSXAttribute
+ * @property {Object} [name]
+ * @property {string} [name.name]
+ * @property {Object} [value]
+ * @property {string} [value.type]
+ * @property {string} [value.value]
+ * @property {Object} [value.expression]
+ * @property {string} [value.expression.value]
+ */
-interface JSXOpeningElement {
- name: { name: string };
- attributes: JSXAttribute[];
-}
+/**
+ * @typedef {Object} JSXOpeningElement
+ * @property {Object} name
+ * @property {string} name.name
+ * @property {JSXAttribute[]} attributes
+ */
-interface JSXElementNode {
- type: string;
- openingElement: JSXOpeningElement;
-}
+/**
+ * @typedef {Object} JSXElementNode
+ * @property {string} type
+ * @property {JSXOpeningElement} openingElement
+ */
+/** @type {{ rules: Record<string, import('oxlint').Rule.RuleModule> }} */
const plugin = {
+ meta: {
+ name: 'icons',
+ },
rules: {
'no-fa-icons-usage': {
meta: {
- type: 'problem' as const,
+ type: 'problem',
docs: {
description:
'Disallow the usage of FontAwesome icons in the codebase',
@@ -56,16 +66,25 @@ const plugin = {
},
schema: [],
},
- create(context: Rule.RuleContext): Rule.RuleListener {
+ /**
+ * @param {import('oxlint').Rule.RuleContext} context
+ * @returns {import('oxlint').Rule.RuleListener}
+ */
+ createOnce(context) {
return {
- // Check for JSX elements with class names containing "fa"
- JSXElement(node: Node): void {
- const jsxNode = node as unknown as JSXElementNode;
+ /**
+ * Check for JSX elements with class names containing "fa"
+ * @param {import('estree').Node} node
+ * @returns {void}
+ */
+ JSXElement(node) {
+ /** @type {JSXElementNode} */
+ const jsxNode = node;
if (
jsxNode.openingElement &&
jsxNode.openingElement.name.name === 'i' &&
jsxNode.openingElement.attributes &&
- jsxNode.openingElement.attributes.some((attr: JSXAttribute) => {
+ jsxNode.openingElement.attributes.some(attr => {
if (attr.name?.name !== 'className') return false;
// Handle className="fa fa-home"
if (attr.value?.type === 'Literal') {
diff --git a/superset-frontend/eslint-rules/eslint-plugin-icons/no-fontawesome.test.ts b/superset-frontend/custom-lint-rules/icons/no-fontawesome.test.ts
similarity index 88%
rename from superset-frontend/eslint-rules/eslint-plugin-icons/no-fontawesome.test.ts
rename to superset-frontend/custom-lint-rules/icons/no-fontawesome.test.ts
index 69239980b42..bd029d8ccd9 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-icons/no-fontawesome.test.ts
+++ b/superset-frontend/custom-lint-rules/icons/no-fontawesome.test.ts
@@ -22,16 +22,23 @@
* @author Apache
*/
-import { RuleTester } from 'eslint';
+import { RuleTester } from 'oxlint/plugins-dev';
+import { describe, it } from 'node:test';
import plugin from '.';
+RuleTester.describe = describe;
+RuleTester.it = it;
+
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
const ruleTester = new RuleTester({
languageOptions: {
- ecmaVersion: 6,
- parserOptions: { ecmaFeatures: { jsx: true } },
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
},
});
const rule = plugin.rules['no-fa-icons-usage'];
diff --git a/superset-frontend/eslint-rules/eslint-plugin-icons/package.json b/superset-frontend/custom-lint-rules/icons/package.json
similarity index 66%
rename from superset-frontend/eslint-rules/eslint-plugin-icons/package.json
rename to superset-frontend/custom-lint-rules/icons/package.json
index bfd59be3855..df04bdbed4a 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-icons/package.json
+++ b/superset-frontend/custom-lint-rules/icons/package.json
@@ -1,17 +1,20 @@
{
- "name": "@superset-ui/eslint-plugin-icons",
+ "name": "@superset-ui/lint-plugin-icons",
"version": "1.0.0",
"description": "Warns about direct usage of Ant Design icons",
"keywords": [],
"license": "Apache-2.0",
"author": "Apache",
"type": "module",
- "main": "index.ts",
+ "main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {},
"peerDependencies": {
- "eslint": ">=0.8.0"
+ "@oxlint/plugins": "*",
+ "@types/estree": "*",
+ "jest": "*",
+ "oxlint": "*"
}
}
diff --git a/superset-frontend/eslint-rules/eslint-plugin-theme-colors/colors.ts b/superset-frontend/custom-lint-rules/theme-colors/colors.js
similarity index 97%
rename from superset-frontend/eslint-rules/eslint-plugin-theme-colors/colors.ts
rename to superset-frontend/custom-lint-rules/theme-colors/colors.js
index 46974c7331f..ec2a8eed4ca 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-theme-colors/colors.ts
+++ b/superset-frontend/custom-lint-rules/theme-colors/colors.js
@@ -18,7 +18,8 @@
*/
// https://www.w3.org/wiki/CSS/Properties/color/keywords
-const COLOR_KEYWORDS: string[] = [
+/** @type {string[]} */
+export const COLOR_KEYWORDS = [
'black',
'silver',
'gray',
@@ -153,6 +154,7 @@ const COLOR_KEYWORDS: string[] = [
'seagreen',
'seashell',
'sienna',
+ 'silver',
'skyblue',
'slateblue',
'slategray',
@@ -167,8 +169,7 @@ const COLOR_KEYWORDS: string[] = [
'turquoise',
'violet',
'wheat',
+ 'white',
'whitesmoke',
'yellowgreen',
];
-
-export default COLOR_KEYWORDS;
diff --git a/superset-frontend/eslint-rules/eslint-plugin-theme-colors/index.ts b/superset-frontend/custom-lint-rules/theme-colors/index.js
similarity index 67%
rename from superset-frontend/eslint-rules/eslint-plugin-theme-colors/index.ts
rename to superset-frontend/custom-lint-rules/theme-colors/index.js
index fb8af4eea87..d9a8b0aad70 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-theme-colors/index.ts
+++ b/superset-frontend/custom-lint-rules/theme-colors/index.js
@@ -22,24 +22,34 @@
* @author Apache
*/
-import type { Rule } from 'eslint';
-import type { Node, SourceLocation } from 'estree';
+import { COLOR_KEYWORDS } from './colors.js';
-import COLOR_KEYWORDS from './colors';
-
-function hasHexColor(quasi: string): boolean {
+/**
+ * @param {string} quasi
+ * @returns {boolean}
+ */
+function hasHexColor(quasi) {
const regex = /#([a-f0-9]{3}|[a-f0-9]{4}(?:[a-f0-9]{2}){0,2})\b/gi;
return !!quasi.match(regex);
}
-function hasRgbColor(quasi: string): boolean {
+/**
+ * @param {string} quasi
+ * @returns {boolean}
+ */
+function hasRgbColor(quasi) {
const regex = /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)/i;
return !!quasi.match(regex);
}
-function hasLiteralColor(quasi: string, strict: boolean = false): boolean {
+/**
+ * @param {string} quasi
+ * @param {boolean} [strict=false]
+ * @returns {boolean}
+ */
+function hasLiteralColor(quasi, strict = false) {
// matches literal colors at the start or end of a CSS prop
- return COLOR_KEYWORDS.some((color: string) => {
+ return COLOR_KEYWORDS.some(color => {
const regexColon = new RegExp(`: ${color}`);
const regexSemicolon = new RegExp(` ${color};`);
return (
@@ -50,31 +60,41 @@ function hasLiteralColor(quasi: string, strict: boolean = false): boolean {
});
}
-const WARNING_MESSAGE: string =
+/** @type {string} */
+const WARNING_MESSAGE =
'Theme color variables are preferred over rgb(a)/hex/literal colors';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
-interface TemplateElementNode {
- type: string;
- value?: { raw: string };
- loc?: SourceLocation | null;
- parent?: {
- type: string;
- parent?: { type: string; loc?: SourceLocation | null };
- };
-}
+/**
+ * @typedef {Object} TemplateElementNode
+ * @property {string} type
+ * @property {Object} [value]
+ * @property {string} [value.raw]
+ * @property {Object} [loc]
+ * @property {Object} [parent]
+ * @property {string} [parent.type]
+ * @property {Object} [parent.parent]
+ * @property {string} [parent.parent.type]
+ * @property {Object} [parent.parent.loc]
+ */
-interface LiteralNode {
- type: string;
- value?: unknown;
- loc?: SourceLocation | null;
- parent?: { type: string };
-}
+/**
+ * @typedef {Object} LiteralNode
+ * @property {string} type
+ * @property {unknown} [value]
+ * @property {Object} [loc]
+ * @property {Object} [parent]
+ * @property {string} [parent.type]
+ */
-const plugin: { rules: Record<string, Rule.RuleModule> } = {
+/** @type {{ rules: Record<string, import('oxlint').Rule.RuleModule> }} */
+const plugin = {
+ meta: {
+ name: 'theme-colors',
+ },
rules: {
'no-literal-colors': {
meta: {
@@ -85,11 +105,22 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
},
schema: [],
},
- create(context: Rule.RuleContext): Rule.RuleListener {
- const warned: string[] = [];
+ /**
+ * @param {import('oxlint').Rule.RuleContext} context
+ * @returns {import('oxlint').Rule.RuleListener}
+ */
+ create(context) {
+ /** @type {string[]} */
+ const warned = [];
+
return {
- TemplateElement(node: Node): void {
- const templateNode = node as TemplateElementNode;
+ /**
+ * @param {import('estree').Node} node
+ * @returns {void}
+ */
+ TemplateElement(node) {
+ /** @type {TemplateElementNode} */
+ const templateNode = node;
const rawValue = templateNode?.value?.raw;
const isChildParentTagged =
templateNode?.parent?.parent?.type === 'TaggedTemplateExpression';
@@ -100,6 +131,7 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
const loc = templateNode?.parent?.parent?.loc;
const locId = loc && JSON.stringify(loc);
const hasWarned = locId ? warned.includes(locId) : false;
+
if (
!hasWarned &&
(isChildParentTagged ||
@@ -111,7 +143,7 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
) {
context.report({
node,
- ...(loc && { loc: loc as SourceLocation }),
+ ...(loc && { loc }),
message: WARNING_MESSAGE,
});
if (locId) {
@@ -119,17 +151,22 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
}
}
},
- Literal(node: Node): void {
- const literalNode = node as LiteralNode;
+
+ /**
+ * @param {import('estree').Node} node
+ * @returns {void}
+ */
+ Literal(node) {
+ /** @type {LiteralNode} */
+ const literalNode = node;
const value = literalNode?.value;
+
// Only process string literals (not numbers, booleans, null, or RegExp)
if (typeof value !== 'string') {
return;
}
- const parent = literalNode?.parent as Node & {
- type: string;
- value?: Node;
- };
+
+ const parent = literalNode?.parent;
// Only check property values, not keys (e.g., { color: 'red' } not { red: 1 })
const isPropertyValue =
parent?.type === 'Property' && parent.value === node;
@@ -145,7 +182,7 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
) {
context.report({
node,
- ...(node.loc && { loc: node.loc as SourceLocation }),
+ ...(node.loc && { loc: node.loc }),
message: WARNING_MESSAGE,
});
if (locId) {
diff --git a/superset-frontend/custom-lint-rules/theme-colors/no-literal-colors.test.ts b/superset-frontend/custom-lint-rules/theme-colors/no-literal-colors.test.ts
new file mode 100644
index 00000000000..c94479c32b5
--- /dev/null
+++ b/superset-frontend/custom-lint-rules/theme-colors/no-literal-colors.test.ts
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { RuleTester } from 'oxlint/plugins-dev';
+import { describe, it } from 'node:test';
+import plugin from '.';
+
+RuleTester.describe = describe;
+RuleTester.it = it;
+
+const ruleTester = new RuleTester();
+const rule = plugin.rules['no-literal-colors'];
+
+const errors: Array<{ message: string }> = [
+ {
+ message:
+ 'Theme color variables are preferred over rgb(a)/hex/literal colors',
+ },
+];
+
+const doubleErrors: Array<{ message: string }> = [
+ {
+ message:
+ 'Theme color variables are preferred over rgb(a)/hex/literal colors',
+ },
+ {
+ message:
+ 'Theme color variables are preferred over rgb(a)/hex/literal colors',
+ },
+];
+
+ruleTester.run('no-literal-colors', rule, {
+ valid: [
+ 'const styles = { color: theme.colorText, background: theme.colorBg };',
+ "const colors = { red: 'not a property value' };",
+ "const color = 'red';",
+ 'styled.div`color: ${theme.colorText};`',
+ ],
+ invalid: [
+ {
+ code: "const styles = { color: 'red' };",
+ errors,
+ },
+ {
+ code: "const styles = { color: 'red', secondColor: 'tan' };",
+ errors: doubleErrors,
+ },
+ {
+ code: "const styles = { background: '#fff' };",
+ errors,
+ },
+ {
+ code: "const styles = { color: 'rgb(1, 2, 3)' };",
+ errors,
+ },
+ {
+ code: 'styled.div`color: red;`',
+ errors,
+ },
+ {
+ code: 'const styles = () => `background: #fff;`;',
+ errors,
+ },
+ ],
+});
diff --git a/superset-frontend/eslint-rules/eslint-plugin-theme-colors/package.json b/superset-frontend/custom-lint-rules/theme-colors/package.json
similarity index 54%
rename from superset-frontend/eslint-rules/eslint-plugin-theme-colors/package.json
rename to superset-frontend/custom-lint-rules/theme-colors/package.json
index 5d355318733..3b2e853d656 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-theme-colors/package.json
+++ b/superset-frontend/custom-lint-rules/theme-colors/package.json
@@ -1,14 +1,20 @@
{
- "name": "@superset-ui/eslint-plugin-theme-colors",
+ "name": "@superset-ui/lint-plugin-theme-colors",
"version": "1.0.0",
"description": "Warns about rgb(a)/hex/literal colors",
"keywords": [],
"license": "Apache-2.0",
"author": "Apache",
"type": "module",
- "main": "index.ts",
+ "main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
- "dependencies": {}
+ "dependencies": {},
+ "peerDependencies": {
+ "@oxlint/plugins": "*",
+ "@types/estree": "*",
+ "jest": "*",
+ "oxlint": "*"
+ }
}
diff --git a/superset-frontend/eslint.config.minimal.js b/superset-frontend/eslint.config.minimal.js
deleted file mode 100644
index 8e766e9e655..00000000000
--- a/superset-frontend/eslint.config.minimal.js
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * MINIMAL ESLint flat config - ONLY for rules OXC doesn't support.
- *
- * This config is run alongside the OXC (oxlint) linter, which handles the
- * bulk of linting. ESLint here only covers the custom Superset plugins that
- * oxlint cannot express. It is consumed by
- * `scripts/oxlint-metrics-uploader.js` (`npm run lint-stats`).
- *
- * Migrated from the legacy `.eslintrc.minimal.js` (eslintrc) format to flat
- * config for ESLint v9+/v10, where eslintrc is no longer supported.
- *
- * Only covers:
- * - Custom Superset plugins (theme-colors, icons, i18n-strings)
- */
-
-// Register the TypeScript require hook so ESLint can load the .ts plugin files
-// from eslint-rules/*.
-import 'tsx/cjs';
-
-import tsParser from '@typescript-eslint/parser';
-import themeColorsPlugin from '@superset-ui/eslint-plugin-theme-colors';
-import iconsPlugin from '@superset-ui/eslint-plugin-icons';
-import i18nStringsPlugin from '@superset-ui/eslint-plugin-i18n-strings';
-
-export default [
- // Files this config applies to. Flat config has no `--ext`; globs live here.
- // Only check src/ files where the theme/icon/i18n rules matter.
- {
- ignores: [
- 'node_modules/**',
- 'dist/**',
- 'build/**',
- '.next/**',
- 'coverage/**',
- '**/*.min.js',
- 'vendor/**',
- // Skip packages/plugins since they have different theming rules
- 'packages/**',
- 'plugins/**',
- // Skip generated/external/config files
- '**/*.generated.*',
- '**/*.config.js',
- '**/webpack.*',
- '*.json',
- ],
- },
- {
- files: ['**/*.{js,jsx,ts,tsx}'],
- languageOptions: {
- ecmaVersion: 2020,
- sourceType: 'module',
- // The @typescript-eslint parser handles both TS/TSX and plain JS/JSX and
- // is compatible with ESLint v10's scope manager. (The legacy
- // @babel/eslint-parser does not support ESLint v10.) The custom rules
- // here are pure AST visitors and do not require type information, so no
- // `project` is configured — this keeps parsing fast.
- parser: tsParser,
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
- },
- },
- },
- // Don't report on eslint-disable comments for rules we don't have.
- linterOptions: {
- reportUnusedDisableDirectives: false,
- },
- plugins: {
- 'theme-colors': themeColorsPlugin,
- icons: iconsPlugin,
- 'i18n-strings': i18nStringsPlugin,
- },
- rules: {
- // Custom Superset plugins
- 'theme-colors/no-literal-colors': 'error',
- 'icons/no-fa-icons-usage': 'error',
- 'i18n-strings/no-template-vars': 'error',
- // Enabled only for controlPanel files via the override below.
- 'i18n-strings/no-eager-t-in-config': 'off',
- },
- },
- {
- // Eager t()/tn() in `label`/`description` config props is captured at
- // module-load time, before i18n initializes — labels stay in the fallback
- // language even after the user switches. Surfaced as a warning (with
- // autofix to `() => t(...)`) wherever this is a real foot-gun:
- // controlPanel files. Promote to `'error'` once the codebase is clean.
- files: ['**/controlPanel.{ts,tsx,js,jsx}'],
- rules: {
- 'i18n-strings/no-eager-t-in-config': 'warn',
- },
- },
- {
- // Disable custom rules in test/story files
- files: [
- '**/*.test.*',
- '**/*.spec.*',
- '**/*.stories.*',
- '**/test/**',
- '**/tests/**',
- '**/spec/**',
- '**/__tests__/**',
- '**/__mocks__/**',
- ],
- rules: {
- 'theme-colors/no-literal-colors': 'off',
- 'icons/no-fa-icons-usage': 'off',
- 'i18n-strings/no-template-vars': 'off',
- },
- },
-];
diff --git a/superset-frontend/oxlint.custom-lint-rules.mts b/superset-frontend/oxlint.custom-lint-rules.mts
new file mode 100644
index 00000000000..7a4b78d91bf
--- /dev/null
+++ b/superset-frontend/oxlint.custom-lint-rules.mts
@@ -0,0 +1,121 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * MINIMAL Oxlint config - ONLY for custom rules
+ *
+ * This config is run alongside the OXC (oxlint) linter, which handles the
+ * bulk of linting. Oxlint here only covers the custom Superset plugins that
+ * oxlint cannot express. It is consumed by
+ * `scripts/oxlint-metrics-uploader.js` (`npm run lint-stats`).
+ *
+ * 1. Migrated from the legacy `.eslintrc.minimal.js` (eslintrc) format to flat
+ * config for ESLint v9+/v10, where eslintrc is no longer supported.
+ * 2. Migrated from legacy `eslint.config.minimal.js` to `oxlint.custom-lint-rules.mts`
+ * for speed
+ *
+ * Only covers:
+ * - Custom Superset plugins (theme-colors, icons, i18n-strings)
+ */
+
+import { defineConfig } from 'oxlint';
+
+export default defineConfig({
+ // Files this config applies to. Flat config has no `--ext`; globs live here.
+ // Only check src/ files where the theme/icon/i18n rules matter.
+ ignorePatterns: [
+ 'node_modules/**',
+ 'dist/**',
+ 'build/**',
+ '.next/**',
+ 'coverage/**',
+ '**/*.min.js',
+ 'vendor/**',
+ // Skip packages/plugins since they have different theming rules
+ 'packages/**',
+ 'plugins/**',
+ // Skip generated/external/config files
+ '**/*.generated.*',
+ '**/*.config.js',
+ '**/webpack.*',
+ '*.json',
+ ],
+ plugins: [],
+ jsPlugins: [
+ "./custom-lint-rules/i18n-strings/index.js",
+ "./custom-lint-rules/icons/index.js",
+ "./custom-lint-rules/theme-colors/index.js"
+ ],
+ options: {
+ reportUnusedDisableDirectives: 'off',
+ respectEslintDisableDirectives: false
+ },
+ // Toggle off built-in lint rules that cannot be toggled off by setting empty `plugins` array at L59
+ // TODO: remove once Oxlint has managed to fix said issue and/or it cannot be reproduced in your run.
+ rules: {
+ "no-unused-vars": "off",
+ "no-extra-boolean-cast": "off",
+ "no-shadow-restricted-names": "off",
+ "no-control-regex": "off"
+ },
+ overrides: [
+ {
+ files: ['**/*.{js,jsx,ts,tsx}'],
+ // Don't report on eslint-disable comments for rules we don't have.
+ rules: {
+ // Custom Superset plugins
+ 'theme-colors/no-literal-colors': 'error',
+ 'icons/no-fa-icons-usage': 'error',
+ 'i18n-strings/no-template-vars': 'error',
+ // Enabled only for controlPanel files via the override below.
+ 'i18n-strings/no-eager-t-in-config': 'off',
+ },
+ },
+ {
+ // Eager t()/tn() in `label`/`description` config props is captured at
+ // module-load time, before i18n initializes — labels stay in the fallback
+ // language even after the user switches. Surfaced as a warning (with
+ // autofix to `() => t(...)`) wherever this is a real foot-gun:
+ // controlPanel files. Promote to `'error'` once the codebase is clean.
+ files: ['**/controlPanel.{ts,tsx,js,jsx}'],
+ rules: {
+ 'i18n-strings/no-eager-t-in-config': 'warn',
+ },
+ },
+ {
+ // Disable custom rules in test/story files
+ files: [
+ '**/*.test.*',
+ '**/*.spec.*',
+ '**/*.stories.*',
+ '**/test/**',
+ '**/tests/**',
+ '**/spec/**',
+ '**/__tests__/**',
+ '**/__mocks__/**',
+ 'cypress-base/**',
+ ],
+ rules: {
+ 'theme-colors/no-literal-colors': 'off',
+ 'icons/no-fa-icons-usage': 'off',
+ 'i18n-strings/no-template-vars': 'off',
+ },
+ },
+ ],
+});
diff --git a/superset-frontend/oxlint.json b/superset-frontend/oxlint.json
index 366138af18b..660887c5b2c 100644
--- a/superset-frontend/oxlint.json
+++ b/superset-frontend/oxlint.json
@@ -222,15 +222,15 @@
"jsx-a11y/tabindex-no-positive": "error",
// === TypeScript rules ===
- "@typescript-eslint/ban-ts-comment": "off",
- "@typescript-eslint/ban-types": "off",
- "@typescript-eslint/no-empty-function": "off",
- "@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/no-use-before-define": "error",
- "@typescript-eslint/no-non-null-assertion": "off",
- "@typescript-eslint/explicit-function-return-type": "off",
- "@typescript-eslint/explicit-module-boundary-types": "off",
- "@typescript-eslint/no-unused-vars": [
+ "typescript/ban-ts-comment": "off",
+ "typescript/ban-types": "off",
+ "typescript/no-empty-function": "off",
+ "typescript/no-explicit-any": "off",
+ "typescript/no-use-before-define": "error",
+ "typescript/no-non-null-assertion": "off",
+ "typescript/explicit-function-return-type": "off",
+ "typescript/explicit-module-boundary-types": "off",
+ "typescript/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
@@ -238,7 +238,7 @@
"caughtErrors": "none"
}
],
- "@typescript-eslint/prefer-optional-chain": "error",
+ "typescript/prefer-optional-chain": "error",
// === Unicorn rules (bonus coverage) ===
"unicorn/no-new-array": "error",
diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json
index b952bab3a09..1594a03f2f1 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -157,7 +157,6 @@
"@babel/cli": "^7.29.7",
"@babel/compat-data": "^7.28.4",
"@babel/core": "^7.29.7",
- "@babel/eslint-parser": "^7.29.9",
"@babel/node": "^7.29.7",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-export-namespace-from": "^7.29.7",
@@ -174,15 +173,13 @@
"@emotion/jest": "^11.14.2",
"@formatjs/intl-durationformat": "^0.11.1",
"@istanbuljs/nyc-config-typescript": "^1.0.1",
+ "@oxlint/plugins": "^1.81.0",
"@playwright/test": "^1.62.1",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.3",
"@storybook/addon-docs": "10.6.1",
"@storybook/addon-links": "10.6.1",
"@storybook/react-webpack5": "10.6.1",
"@storybook/test-runner": "0.26.0",
- "@superset-ui/eslint-plugin-i18n-strings": "file:eslint-rules/eslint-plugin-i18n-strings",
- "@superset-ui/eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
- "@superset-ui/eslint-plugin-theme-colors": "file:eslint-rules/eslint-plugin-theme-colors",
"@svgr/webpack": "^8.1.0",
"@swc/core": "^1.16.13",
"@swc/plugin-emotion": "^19.0.0",
@@ -193,6 +190,7 @@
"@testing-library/user-event": "^14.6.7",
"@types/content-disposition": "^0.5.9",
"@types/dom-to-image": "^2.6.7",
+ "@types/estree": "^1.0.9",
"@types/jest": "^30.0.0",
"@types/jquery": "^4.0.1",
"@types/js-levenshtein": "^1.1.3",
@@ -209,8 +207,6 @@
"@types/rison": "0.1.0",
"@types/tinycolor2": "^1.4.3",
"@types/unzipper": "^0.10.11",
- "@typescript-eslint/eslint-plugin": "^8.71.1",
- "@typescript-eslint/parser": "^8.63.0",
"babel-jest": "^30.5.2",
"babel-loader": "^10.1.1",
"babel-plugin-dynamic-import-node": "^2.3.3",
@@ -221,17 +217,6 @@
"copy-webpack-plugin": "^14.0.0",
"cross-env": "^10.1.0",
"css-loader": "^7.1.5",
- "eslint": "^10.10.0",
- "eslint-import-resolver-alias": "^1.1.2",
- "eslint-import-resolver-typescript": "^4.4.5",
- "eslint-plugin-import": "^2.32.0",
- "eslint-plugin-jest-dom": "^5.10.1",
- "eslint-plugin-lodash": "^8.0.0",
- "eslint-plugin-no-only-tests": "^3.4.0",
- "eslint-plugin-react-prefer-function-component": "^5.0.0",
- "eslint-plugin-react-you-might-not-need-an-effect": "^1.0.2",
- "eslint-plugin-storybook": "10.6.1",
- "eslint-plugin-testing-library": "^7.16.2",
"fetch-mock": "^12.6.0",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"gettext-parser": "^9.1.1",
@@ -288,30 +273,6 @@
"regenerator-runtime": "^0.14.1"
}
},
- "eslint-rules/eslint-plugin-i18n-strings": {
- "name": "@superset-ui/eslint-plugin-i18n-strings",
- "version": "1.0.0",
- "dev": true,
- "license": "Apache-2.0",
- "peerDependencies": {
- "eslint": ">=0.8.0"
- }
- },
- "eslint-rules/eslint-plugin-icons": {
- "name": "@superset-ui/eslint-plugin-icons",
- "version": "1.0.0",
- "dev": true,
- "license": "Apache-2.0",
- "peerDependencies": {
- "eslint": ">=0.8.0"
- }
- },
- "eslint-rules/eslint-plugin-theme-colors": {
- "name": "@superset-ui/eslint-plugin-theme-colors",
- "version": "1.0.0",
- "dev": true,
- "license": "Apache-2.0"
- },
"node_modules/@adobe/css-tools": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.1.tgz",
@@ -606,35 +567,6 @@
"semver": "bin/semver.js"
}
},
- "node_modules/@babel/eslint-parser": {
- "version": "7.29.9",
- "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.29.9.tgz",
- "integrity": "sha512-GmrJTAtiRbNip+eKFqeuSvoHMJhKlH36j8U0yE3Gqn45B+SIO7NvsEiHtsmzkBqV1hLSMqYr41dI1aZLTkJ37g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
- "eslint-visitor-keys": "^2.1.0",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || >=14.0.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.11.0",
- "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0"
- }
- },
- "node_modules/@babel/eslint-parser/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
"node_modules/@babel/generator": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
@@ -3956,129 +3888,6 @@
"node": ">=18"
}
},
- "node_modules/@eslint-community/eslint-utils": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
- "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "eslint-visitor-keys": "^3.4.3"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
- }
- },
- "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint-community/regexpp": {
- "version": "4.12.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
- "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
- }
- },
- "node_modules/@eslint/config-array": {
- "version": "0.23.5",
- "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz",
- "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@eslint/object-schema": "^3.0.5",
- "debug": "^4.3.1",
- "minimatch": "^10.2.4"
- },
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- }
- },
- "node_modules/@eslint/config-array/node_modules/minimatch": {
- "version": "10.2.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
- "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
- "dev": true,
- "license": "BlueOak-1.0.0",
- "dependencies": {
- "brace-expansion": "^5.0.5"
- },
- "engines": {
- "node": "18 || 20 || >=22"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/@eslint/config-helpers": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz",
- "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@eslint/core": "^1.2.1"
- },
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- }
- },
- "node_modules/@eslint/core": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz",
- "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@types/json-schema": "^7.0.15"
- },
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- }
- },
- "node_modules/@eslint/object-schema": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz",
- "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- }
- },
- "node_modules/@eslint/plugin-kit": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz",
- "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@eslint/core": "^1.2.1",
- "levn": "^0.4.1"
- },
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- }
- },
"node_modules/@floating-ui/core": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz",
@@ -4265,72 +4074,6 @@
"@hapi/hoek": "^11.0.2"
}
},
- "node_modules/@humanfs/core": {
- "version": "0.19.2",
- "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
- "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@humanfs/types": "^0.15.0"
- },
- "engines": {
- "node": ">=18.18.0"
- }
- },
- "node_modules/@humanfs/node": {
- "version": "0.16.8",
- "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
- "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@humanfs/core": "^0.19.2",
- "@humanfs/types": "^0.15.0",
- "@humanwhocodes/retry": "^0.4.0"
- },
- "engines": {
- "node": ">=18.18.0"
- }
- },
- "node_modules/@humanfs/types": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
- "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=18.18.0"
- }
- },
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=12.22"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@humanwhocodes/retry": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
- "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=18.18"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
"node_modules/@inquirer/ansi": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
@@ -8360,16 +8103,6 @@
"license": "MIT",
"optional": true
},
- "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
- "version": "5.1.1-v1",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
- "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "eslint-scope": "5.1.1"
- }
- },
"node_modules/@noble/hashes": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz",
@@ -10739,6 +10472,19 @@
"node": "^20.19.0 || >=22.12.0"
}
},
+ "node_modules/@oxlint/plugins": {
+ "version": "1.86.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/plugins/-/plugins-1.86.0.tgz",
+ "integrity": "sha512-JeAiaaRMyUiUEQHQ7zBsJn1aEdbLyt1HJsOs4XKIIlATNxcvWRrRxneZA+RF4G03cQobq3IhTqSfyLhOFv03qA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/oxc-project"
+ }
+ },
"node_modules/@parcel/watcher": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz",
@@ -12319,13 +12065,6 @@
"@rjsf/utils": "^6.11.0"
}
},
- "node_modules/@rtsao/scc": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
- "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@scarf/scarf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
@@ -13079,18 +12818,6 @@
"resolved": "packages/superset-ui-core",
"link": true
},
- "node_modules/@superset-ui/eslint-plugin-i18n-strings": {
- "resolved": "eslint-rules/eslint-plugin-i18n-strings",
- "link": true
- },
- "node_modules/@superset-ui/eslint-plugin-icons": {
- "resolved": "eslint-rules/eslint-plugin-icons",
- "link": true
- },
- "node_modules/@superset-ui/eslint-plugin-theme-colors": {
- "resolved": "eslint-rules/eslint-plugin-theme-colors",
- "link": true
- },
"node_modules/@superset-ui/generator-superset": {
"resolved": "packages/generator-superset",
"link": true
@@ -14334,17 +14061,10 @@
"integrity": "sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==",
"license": "MIT"
},
- "node_modules/@types/esrecurse": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
- "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@types/estree": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
- "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
"license": "MIT"
},
"node_modules/@types/estree-jsx": {
@@ -14583,13 +14303,6 @@
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"license": "MIT"
},
- "node_modules/@types/json5": {
- "version": "0.0.29",
- "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
- "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@types/lodash": {
"version": "4.17.25",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.25.tgz",
@@ -15009,265 +14722,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.71.1.tgz",
- "integrity": "sha512-nNlBf6HuotqMgZvSkWD5hNdemiBIxQ2NmrlgfcUIeZRs+BbakjscCQRq/Hb74EFVnFiSWWdL12JruqwBy3ERDw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/regexpp": "^4.12.2",
- "@typescript-eslint/scope-manager": "8.71.1",
- "@typescript-eslint/type-utils": "8.71.1",
- "@typescript-eslint/utils": "8.71.1",
- "@typescript-eslint/visitor-keys": "8.71.1",
- "ignore": "^7.0.5",
- "natural-compare": "^1.4.0",
- "ts-api-utils": "^2.5.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "@typescript-eslint/parser": "^8.71.1",
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.1.0"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
- "version": "7.0.5",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
- "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/@typescript-eslint/parser": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.71.1.tgz",
- "integrity": "sha512-oM/5sAqz/l1v/zYK1qTOPrn2+JIrBGC1V6uNYucRO5gh6eT9vWJ/RhPbGE59byvZEUQ4VP6XkLBaS5Jti5jpvw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/scope-manager": "8.71.1",
- "@typescript-eslint/types": "8.71.1",
- "@typescript-eslint/typescript-estree": "8.71.1",
- "@typescript-eslint/visitor-keys": "8.71.1",
- "debug": "^4.4.3"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.1.0"
- }
- },
- "node_modules/@typescript-eslint/project-service": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.1.tgz",
- "integrity": "sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.71.1",
- "@typescript-eslint/types": "^8.71.1",
- "debug": "^4.4.3"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.1.0"
- }
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.71.1.tgz",
- "integrity": "sha512-1YUDZXdTnXLlob03SFHBipdyMBsDVm7zoSz0ytTJ39dk5J1TgsTK03VlR/dLXG/RLLUrPcYbD4rp23BmHxHP0w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.71.1",
- "@typescript-eslint/visitor-keys": "8.71.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.1.tgz",
- "integrity": "sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.1.0"
- }
- },
- "node_modules/@typescript-eslint/type-utils": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.71.1.tgz",
- "integrity": "sha512-kH3t3jZCYv2PZSBEWPKTariLrCaoF1CLoPitYFBJOhAGEwWnSRAtGEifrfrpBa4K9JlwWNZotgA5w3/wLSk/FQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.71.1",
- "@typescript-eslint/typescript-estree": "8.71.1",
- "@typescript-eslint/utils": "8.71.1",
- "debug": "^4.4.3",
- "ts-api-utils": "^2.5.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.1.0"
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.71.1.tgz",
- "integrity": "sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.1.tgz",
- "integrity": "sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/project-service": "8.71.1",
- "@typescript-eslint/tsconfig-utils": "8.71.1",
- "@typescript-eslint/types": "8.71.1",
- "@typescript-eslint/visitor-keys": "8.71.1",
- "debug": "^4.4.3",
- "minimatch": "^10.2.2",
- "semver": "^7.7.3",
- "tinyglobby": "^0.2.15",
- "ts-api-utils": "^2.5.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.1.0"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "10.2.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
- "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
- "dev": true,
- "license": "BlueOak-1.0.0",
- "dependencies": {
- "brace-expansion": "^5.0.8"
- },
- "engines": {
- "node": "18 || 20 || >=22"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/@typescript-eslint/utils": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.1.tgz",
- "integrity": "sha512-CBjT6gfAz3DW2j9Q4moFnqt208Aq+506sVGXfpRcyAeqn0EpayL0mjdWoCO2t3RC7GewNrFxdeehuEaPg6DMzQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.9.1",
- "@typescript-eslint/scope-manager": "8.71.1",
- "@typescript-eslint/types": "8.71.1",
- "@typescript-eslint/typescript-estree": "8.71.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "typescript": ">=4.8.4 <6.1.0"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.71.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.71.1.tgz",
- "integrity": "sha512-0GxiUGqMU0qXJt58cBsiG3DP8lUmBaFo2vChtUX+CT7PnR3v/VGLLrzVP4K9r1lNiZXjHYefMBbPunplr09v6w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.71.1",
- "eslint-visitor-keys": "^5.0.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
- "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
"node_modules/@ungap/structured-clone": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
@@ -16567,16 +16021,6 @@
"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==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
"node_modules/acorn-walk": {
"version": "8.3.5",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
@@ -17029,29 +16473,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/array-includes": {
- "version": "3.1.9",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
- "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.4",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.24.0",
- "es-object-atoms": "^1.1.1",
- "get-intrinsic": "^1.3.0",
- "is-string": "^1.1.1",
- "math-intrinsics": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/array-union": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz",
@@ -17064,66 +16485,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/array.prototype.findlastindex": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
- "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.4",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.9",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "es-shim-unscopables": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flat": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
- "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flatmap": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
- "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/array.prototype.reduce": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.7.tgz",
@@ -21728,19 +21089,6 @@
"node": ">= 0.4"
}
},
- "node_modules/es-shim-unscopables": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
- "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/es-to-primitive": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
@@ -21877,574 +21225,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/eslint": {
- "version": "10.10.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.10.0.tgz",
- "integrity": "sha512-NPXn6r5zl4uET1DAVPaOwzX3rut4c0wcmw3dWJAfOsTM5+TogXo0DDjz8pwm/hL8cyVNpHqeK4JpN0NjnyFFNw==",
- "dev": true,
- "license": "MIT",
- "workspaces": [
- "packages/*"
- ],
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.8.0",
- "@eslint-community/regexpp": "^4.12.2",
- "@eslint/config-array": "^0.23.5",
- "@eslint/config-helpers": "^0.7.0",
- "@eslint/core": "^1.2.1",
- "@eslint/plugin-kit": "^0.7.3",
- "@humanfs/node": "^0.16.6",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@humanwhocodes/retry": "^0.4.2",
- "@types/estree": "^1.0.6",
- "ajv": "^6.14.0",
- "cross-spawn": "^7.0.6",
- "debug": "^4.3.2",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^9.1.2",
- "eslint-visitor-keys": "^5.0.1",
- "espree": "^11.2.0",
- "esquery": "^1.7.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "11.1.5 || >11.1.6 <12",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "ignore": "^5.2.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "minimatch": "^10.2.5",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- },
- "funding": {
- "url": "https://eslint.org/donate"
- },
- "peerDependencies": {
- "jiti": "*"
- },
- "peerDependenciesMeta": {
- "jiti": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-import-context": {
- "version": "0.1.9",
- "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz",
- "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "get-tsconfig": "^4.10.1",
- "stable-hash-x": "^0.2.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint-import-context"
- },
- "peerDependencies": {
- "unrs-resolver": "^1.0.0"
- },
- "peerDependenciesMeta": {
- "unrs-resolver": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-import-resolver-alias": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz",
- "integrity": "sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- },
- "peerDependencies": {
- "eslint-plugin-import": ">=1.4.0"
- }
- },
- "node_modules/eslint-import-resolver-node": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
- "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "debug": "^3.2.7",
- "is-core-module": "^2.13.0",
- "resolve": "^1.22.4"
- }
- },
- "node_modules/eslint-import-resolver-node/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-import-resolver-typescript": {
- "version": "4.4.5",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.5.tgz",
- "integrity": "sha512-nbE5XLph6TLtGYcu/U6e6ZVXyKBhbDWK5cLGk76eJ7NdZpwf1P9EFkpt1Z01mNZNrrilsAYWKH6zUkL4reoXbw==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "debug": "^4.4.1",
- "eslint-import-context": "^0.1.8",
- "get-tsconfig": "^4.10.1",
- "is-bun-module": "^2.0.0",
- "stable-hash-x": "^0.2.0",
- "tinyglobby": "^0.2.14",
- "unrs-resolver": "^1.7.11"
- },
- "engines": {
- "node": "^16.17.0 || >=18.6.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint-import-resolver-typescript"
- },
- "peerDependencies": {
- "eslint": "*",
- "eslint-plugin-import": "*",
- "eslint-plugin-import-x": "*"
- },
- "peerDependenciesMeta": {
- "eslint-plugin-import": {
- "optional": true
- },
- "eslint-plugin-import-x": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-module-utils": {
- "version": "2.12.1",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
- "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "debug": "^3.2.7"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependenciesMeta": {
- "eslint": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-module-utils/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-plugin-import": {
- "version": "2.32.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
- "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@rtsao/scc": "^1.1.0",
- "array-includes": "^3.1.9",
- "array.prototype.findlastindex": "^1.2.6",
- "array.prototype.flat": "^1.3.3",
- "array.prototype.flatmap": "^1.3.3",
- "debug": "^3.2.7",
- "doctrine": "^2.1.0",
- "eslint-import-resolver-node": "^0.3.9",
- "eslint-module-utils": "^2.12.1",
- "hasown": "^2.0.2",
- "is-core-module": "^2.16.1",
- "is-glob": "^4.0.3",
- "minimatch": "^3.1.2",
- "object.fromentries": "^2.0.8",
- "object.groupby": "^1.0.3",
- "object.values": "^1.2.1",
- "semver": "^6.3.1",
- "string.prototype.trimend": "^1.0.9",
- "tsconfig-paths": "^3.15.0"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/json5": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
- "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "minimist": "^1.2.0"
- },
- "bin": {
- "json5": "lib/cli.js"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": {
- "version": "3.15.0",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
- "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/json5": "^0.0.29",
- "json5": "^1.0.2",
- "minimist": "^1.2.6",
- "strip-bom": "^3.0.0"
- }
- },
- "node_modules/eslint-plugin-jest-dom": {
- "version": "5.10.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.10.1.tgz",
- "integrity": "sha512-IIJdzbACbhJUJyMAqpA9E9gxp1Gv29TeQ3DtL+pepwP8Oq2WiqjOB2HbnEIs23h0ewdKIZRDI56yLro2eUO+DA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "requireindex": "^1.2.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0",
- "npm": ">=6",
- "yarn": ">=1"
- },
- "peerDependencies": {
- "@testing-library/dom": "^8.0.0 || ^9.0.0 || ^10.0.0",
- "eslint": "^6.8.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0"
- },
- "peerDependenciesMeta": {
- "@testing-library/dom": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-plugin-lodash": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-lodash/-/eslint-plugin-lodash-8.0.0.tgz",
- "integrity": "sha512-7DA8485FolmWRzh+8t4S8Pzin2TTuWfb0ZW3j/2fYElgk82ZanFz8vDcvc4BBPceYdX1p/za+tkbO68maDBGGw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lodash": "^4.17.21"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "eslint": ">=9.0.0"
- }
- },
- "node_modules/eslint-plugin-no-only-tests": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.4.0.tgz",
- "integrity": "sha512-4S3/9Nb7A2tiMcpzEQE9bQSlpeOz6WJkgryBuou/SA8W2x2c8Zf4j0NvTKBjv6qNhF9T79tmkecm/0CHqV0UGg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=5.0.0"
- }
- },
- "node_modules/eslint-plugin-react-prefer-function-component": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-prefer-function-component/-/eslint-plugin-react-prefer-function-component-5.0.0.tgz",
- "integrity": "sha512-kXRP41OT/hgR8QDlHCO2tOFGbQgXcER58xjV3nlNOggGvRoSZ5u3wdqogWnD/W2lOTmk/noNOLDt3LRD39G9iQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/eslint-plugin-react-you-might-not-need-an-effect": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-you-might-not-need-an-effect/-/eslint-plugin-react-you-might-not-need-an-effect-1.0.2.tgz",
- "integrity": "sha512-HgYol2zhH3KbnW9Q4FY/FcIINbsYVL6rwQESChqBC2s9SLWtw1wg05+J7SCrr3BfQpNY2ReYhf8xjpd2JhKJOQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "globals": "^16.2.0"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/nickjvandyke"
- },
- "peerDependencies": {
- "eslint": ">=8.40.0"
- }
- },
- "node_modules/eslint-plugin-react-you-might-not-need-an-effect/node_modules/globals": {
- "version": "16.5.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz",
- "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint-plugin-storybook": {
- "version": "10.6.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-10.6.1.tgz",
- "integrity": "sha512-XBmXuQcI0wzxMYc0rWKIiydvUxgS+GzLesO1YK1adnj97LhMqqsnlalbM+nXfQo1JoH2F2CI12sAH9/dAC99Dw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "^8.60.0",
- "@typescript-eslint/utils": "^8.60.0"
- },
- "peerDependencies": {
- "eslint": ">=8"
- }
- },
- "node_modules/eslint-plugin-testing-library": {
- "version": "7.16.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-7.16.2.tgz",
- "integrity": "sha512-8gleGnQXK2ZA3hHwjCwpYTZvM+9VsrJ+/9kDI8CjqAQGAdMQOdn/rJNu7ZySENuiWlGKQWyZJ4ZjEg2zamaRHw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/scope-manager": "^8.56.0",
- "@typescript-eslint/utils": "^8.56.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0"
- }
- },
- "node_modules/eslint-scope": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
- "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/eslint-scope/node_modules/estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint/node_modules/ajv": {
- "version": "6.15.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
- "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
- "dev": true,
- "license": "MIT",
- "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/eslint/node_modules/eslint-scope": {
- "version": "9.1.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
- "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "@types/esrecurse": "^4.3.1",
- "@types/estree": "^1.0.8",
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint/node_modules/eslint-visitor-keys": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
- "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint/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==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/eslint/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==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/eslint/node_modules/minimatch": {
- "version": "10.2.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
- "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
- "dev": true,
- "license": "BlueOak-1.0.0",
- "dependencies": {
- "brace-expansion": "^5.0.5"
- },
- "engines": {
- "node": "18 || 20 || >=22"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/espree": {
- "version": "11.2.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
- "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "acorn": "^8.16.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^5.0.1"
- },
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/espree/node_modules/acorn": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
- "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/espree/node_modules/eslint-visitor-keys": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
- "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -22458,32 +21238,6 @@
"node": ">=4"
}
},
- "node_modules/esquery": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
- "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
- "dev": true,
- "license": "BSD-3-Clause",
- "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==",
- "dev": true,
- "license": "BSD-2-Clause",
- "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",
@@ -24533,19 +23287,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/get-tsconfig": {
- "version": "4.10.1",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
- "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "resolve-pkg-maps": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
- }
- },
"node_modules/get-value": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
@@ -25750,16 +24491,6 @@
],
"license": "BSD-3-Clause"
},
- "node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
"node_modules/ignore-walk": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz",
@@ -26170,16 +24901,6 @@
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
"license": "MIT"
},
- "node_modules/is-bun-module": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
- "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "semver": "^7.7.1"
- }
- },
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
@@ -31181,13 +29902,6 @@
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
- "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==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/json-stringify-nice": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz",
@@ -32002,20 +30716,6 @@
"node": ">=6"
}
},
- "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==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/libnpmaccess": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-10.0.3.tgz",
@@ -35579,25 +34279,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/object.fromentries": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
- "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/object.getownpropertydescriptors": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.8.tgz",
@@ -35620,40 +34301,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/object.groupby": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
- "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.values": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
- "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/objectorarray": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz",
@@ -35848,24 +34495,6 @@
"node": ">=0.4.0"
}
},
- "node_modules/optionator": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
- "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.5"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/ora": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
@@ -37156,16 +35785,6 @@
}
}
},
- "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==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/pretty-error": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz",
@@ -40107,16 +38726,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/requireindex": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz",
- "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.5"
- }
- },
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -40199,16 +38808,6 @@
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==",
"license": "MIT"
},
- "node_modules/resolve-pkg-maps": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
- "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
- }
- },
"node_modules/resolve-protobuf-schema": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
@@ -41498,16 +40097,6 @@
"node": "^18.17.0 || >=20.5.0"
}
},
- "node_modules/stable-hash-x": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz",
- "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- }
- },
"node_modules/stack-utils": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
@@ -43511,19 +42100,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/ts-api-utils": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
- "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18.12"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4"
- }
- },
"node_modules/ts-dedent": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz",
@@ -43712,19 +42288,6 @@
"node": "^20.17.0 || >=22.9.0"
}
},
- "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==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
diff --git a/superset-frontend/package.json b/superset-frontend/package.json
index 1f52dd4e4d0..9b7c3434736 100644
--- a/superset-frontend/package.json
+++ b/superset-frontend/package.json
@@ -234,7 +234,6 @@
"@babel/cli": "^7.29.7",
"@babel/compat-data": "^7.28.4",
"@babel/core": "^7.29.7",
- "@babel/eslint-parser": "^7.29.9",
"@babel/node": "^7.29.7",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-export-namespace-from": "^7.29.7",
@@ -251,15 +250,13 @@
"@emotion/jest": "^11.14.2",
"@formatjs/intl-durationformat": "^0.11.1",
"@istanbuljs/nyc-config-typescript": "^1.0.1",
+ "@oxlint/plugins": "^1.81.0",
"@playwright/test": "^1.62.1",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.3",
"@storybook/addon-docs": "10.6.1",
"@storybook/addon-links": "10.6.1",
"@storybook/react-webpack5": "10.6.1",
"@storybook/test-runner": "0.26.0",
- "@superset-ui/eslint-plugin-i18n-strings": "file:eslint-rules/eslint-plugin-i18n-strings",
- "@superset-ui/eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
- "@superset-ui/eslint-plugin-theme-colors": "file:eslint-rules/eslint-plugin-theme-colors",
"@svgr/webpack": "^8.1.0",
"@swc/core": "^1.16.13",
"@swc/plugin-emotion": "^19.0.0",
@@ -270,6 +267,7 @@
"@testing-library/user-event": "^14.6.7",
"@types/content-disposition": "^0.5.9",
"@types/dom-to-image": "^2.6.7",
+ "@types/estree": "^1.0.9",
"@types/jest": "^30.0.0",
"@types/jquery": "^4.0.1",
"@types/js-levenshtein": "^1.1.3",
@@ -286,8 +284,6 @@
"@types/rison": "0.1.0",
"@types/tinycolor2": "^1.4.3",
"@types/unzipper": "^0.10.11",
- "@typescript-eslint/eslint-plugin": "^8.71.1",
- "@typescript-eslint/parser": "^8.63.0",
"babel-jest": "^30.5.2",
"babel-loader": "^10.1.1",
"babel-plugin-dynamic-import-node": "^2.3.3",
@@ -298,17 +294,6 @@
"copy-webpack-plugin": "^14.0.0",
"cross-env": "^10.1.0",
"css-loader": "^7.1.5",
- "eslint": "^10.10.0",
- "eslint-import-resolver-alias": "^1.1.2",
- "eslint-import-resolver-typescript": "^4.4.5",
- "eslint-plugin-import": "^2.32.0",
- "eslint-plugin-jest-dom": "^5.10.1",
- "eslint-plugin-lodash": "^8.0.0",
- "eslint-plugin-no-only-tests": "^3.4.0",
- "eslint-plugin-react-prefer-function-component": "^5.0.0",
- "eslint-plugin-react-you-might-not-need-an-effect": "^1.0.2",
- "eslint-plugin-storybook": "10.6.1",
- "eslint-plugin-testing-library": "^7.16.2",
"fetch-mock": "^12.6.0",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"gettext-parser": "^9.1.1",
@@ -361,9 +346,6 @@
"regenerator-runtime": "^0.14.1"
},
"overrides": {
- "@babel/eslint-parser": {
- "eslint": "$eslint"
- },
"@deck.gl/aggregation-layers": "~9.4.0",
"@deck.gl/core": "~9.4.0",
"@deck.gl/extensions": "~9.4.0",
@@ -395,12 +377,6 @@
},
"dompurify": "^3.4.16",
"esbuild": "^0.28.1",
- "eslint-plugin-import": {
- "eslint": "$eslint"
- },
- "eslint-plugin-jest-dom": {
- "eslint": "$eslint"
- },
"fast-uri": "^3.1.8",
"fast-xml-parser": "^5.8.0",
"http-proxy-middleware": "^2.0.10",
diff --git a/superset-frontend/scripts/check-custom-rules.js b/superset-frontend/scripts/check-custom-rules.js
index d623cd31926..9804bac8af3 100755
--- a/superset-frontend/scripts/check-custom-rules.js
+++ b/superset-frontend/scripts/check-custom-rules.js
@@ -283,15 +283,13 @@ function checkEagerTranslationsInConfig(ast, filepath) {
if (hasEslintDisable(path, 'i18n-strings/no-eager-t-in-config')) return;
// Warn (not error) because there are many pre-existing violations.
- // The ESLint plugin provides an autofix so authors can sweep files
- // as they touch them. Promote to error once the codebase is clean.
+ // Promote to error once the codebase is clean.
// eslint-disable-next-line no-console
console.warn(
`${YELLOW}⚠${RESET} ${filepath}:${node.loc?.start.line ?? '?'}: ` +
`Eager \`${keyName}: ${value.callee.name}(...)\` is evaluated at ` +
`module load, before i18n is initialized. Wrap in an arrow ` +
- `function: \`${keyName}: () => ${value.callee.name}(...)\`. ` +
- `Run \`eslint --fix\` to autofix.`,
+ `function: \`${keyName}: () => ${value.callee.name}(...)\`. `,
);
warningCount += 1;
},
diff --git a/superset-frontend/scripts/internal/oxlint-metrics-uploader.js b/superset-frontend/scripts/internal/oxlint-metrics-uploader.js
index 3c6b8506514..65293849f88 100644
--- a/superset-frontend/scripts/internal/oxlint-metrics-uploader.js
+++ b/superset-frontend/scripts/internal/oxlint-metrics-uploader.js
@@ -34,6 +34,7 @@ if (SERVICE_ACCOUNT_KEY.client_email) {
}
const DATETIME = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '');
+const CUSTOM_PLUGIN_ID_PREFIXES = ['theme-colors', 'icons', 'i18n-strings'];
/**
* Turn an oxlint diagnostic code into the canonical rule id used by the metrics
@@ -54,22 +55,60 @@ const DATETIME = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '');
*/
function parseRuleId(code) {
if (!code) {
- return 'unknown';
+ return { parsed: 'unknown', pluginId: 'unknown' };
}
const match = code.match(/^([\w-]+)\(([^)]+)\)$/);
if (!match) {
- return code;
+ return { parsed: code, pluginId: 'unknown' };
}
const [, namespace, rule] = match;
if (namespace === 'eslint') {
- return rule;
+ return { parsed: rule, pluginId: namespace };
}
// `eslint-plugin-unicorn(...)` is the same rule as `unicorn/...`
const plugin = namespace.replace(/^eslint-plugin-/, '');
- return `${plugin}/${rule}`;
+ return { parsed: `${plugin}/${rule}`, pluginId: plugin };
+}
+
+function parseOxlintResult(results, ruleIdPrefixes) {
+ // Process OXC JSON output
+ const metricsByRule = {};
+ const occurrencesData = [];
+
+ // OXC JSON format has diagnostics array
+ if (results.diagnostics && Array.isArray(results.diagnostics)) {
+ results.diagnostics.forEach(diagnostic => {
+ const { parsed: ruleId, pluginId } = parseRuleId(diagnostic.code);
+
+ const file = diagnostic.filename || 'unknown';
+ const line = diagnostic.labels?.[0]?.span?.line || 0;
+ const column = diagnostic.labels?.[0]?.span?.column || 0;
+ const message = diagnostic.message || '';
+
+ const ruleData = metricsByRule[ruleId] || { count: 0 };
+ ruleData.count += 1;
+
+ if (
+ !ruleIdPrefixes ||
+ (ruleIdPrefixes && ruleIdPrefixes.includes(pluginId))
+ ) {
+ metricsByRule[ruleId] = ruleData;
+ occurrencesData.push({
+ rule: ruleId,
+ message,
+ file,
+ line,
+ column,
+ ts: DATETIME,
+ });
+ }
+ });
+ }
+
+ return { metricsByRule, occurrencesData };
}
async function writeToGoogleSheet(data, range, headers, append = false) {
@@ -120,104 +159,71 @@ async function runOxlintAndProcess() {
// config has to be passed explicitly or the run reports oxlint's defaults
// instead of the project's ruleset. Matches the `lint` scripts in
// package.json.
- const oxlintOutput = execSync(
- 'npx oxlint --config oxlint.json --format json',
- {
+ let oxlintOutput = '{}';
+ try {
+ oxlintOutput = execSync('npx oxlint --config oxlint.json --format json', {
encoding: 'utf8',
maxBuffer: 50 * 1024 * 1024, // 50MB buffer for large outputs
stdio: ['pipe', 'pipe', 'ignore'], // Ignore stderr to avoid error output
- },
- );
-
- const results = JSON.parse(oxlintOutput);
-
- // Process OXC JSON output
- const metricsByRule = {};
- let occurrencesData = [];
-
- // OXC JSON format has diagnostics array
- if (results.diagnostics && Array.isArray(results.diagnostics)) {
- results.diagnostics.forEach(diagnostic => {
- const ruleId = parseRuleId(diagnostic.code);
-
- const file = diagnostic.filename || 'unknown';
- const line = diagnostic.labels?.[0]?.span?.line || 0;
- const column = diagnostic.labels?.[0]?.span?.column || 0;
- const message = diagnostic.message || '';
-
- const ruleData = metricsByRule[ruleId] || { count: 0 };
- ruleData.count += 1;
- metricsByRule[ruleId] = ruleData;
-
- occurrencesData.push({
- rule: ruleId,
- message,
- file,
- line,
- column,
- ts: DATETIME,
- });
});
+ } catch (error) {
+ if (error.stdout) {
+ oxlintOutput = error.stdout.toString();
+ } else {
+ throw error;
+ }
}
+ const results = JSON.parse(oxlintOutput);
console.log(
`OXC found ${results.diagnostics?.length || 0} issues across ${results.number_of_files} files`,
);
+ const { metricsByRule, occurrencesData } = parseOxlintResult(results);
- // Also run minimal ESLint for custom rules and merge results
- console.log('Running minimal ESLint for custom rules...');
- let eslintOutput = '[]';
+ // Also run Oxlint for custom rules and merge results
+ console.log('Running Oxlint for custom rules...');
+ // Run ESLint and capture output directly.
+ // Flat config (oxlint.custom-lint-rules.mts) is explicitly selected via --config
+ let oxlintCustomRuleOutput = '{}';
try {
- // Run ESLint and capture output directly.
- // Flat config (eslint.config.minimal.js) is explicitly selected via
- // --config; ESLint v9+/v10 no longer support eslintrc or --no-eslintrc.
- eslintOutput = execSync(
- 'npx eslint --config eslint.config.minimal.js --no-inline-config --format json src',
+ oxlintCustomRuleOutput = execSync(
+ 'npx oxlint --config oxlint.custom-lint-rules.mts --format json src',
{
encoding: 'utf8',
- maxBuffer: 50 * 1024 * 1024,
+ maxBuffer: 50 * 1024 * 1024, // 50MB buffer for large outputs
stdio: ['pipe', 'pipe', 'ignore'], // Ignore stderr
},
);
- } catch (e) {
- // ESLint exits with non-zero when it finds issues, capture the stdout
- if (e.stdout) {
- eslintOutput = e.stdout.toString();
+ } catch (error) {
+ if (error.stdout) {
+ oxlintCustomRuleOutput = error.stdout.toString();
+ } else {
+ throw error;
}
}
- // Parse minimal ESLint output
- try {
- const eslintResults = JSON.parse(eslintOutput);
-
- eslintResults.forEach(result => {
- result.messages.forEach(({ ruleId, line, column, message }) => {
- const ruleData = metricsByRule[ruleId] || { count: 0 };
- ruleData.count += 1;
- metricsByRule[ruleId] = ruleData;
-
- occurrencesData.push({
- rule: ruleId,
- message,
- file: result.filePath,
- line,
- column,
- ts: DATETIME,
- });
- });
- });
-
- console.log(
- `ESLint found ${eslintResults.reduce((sum, r) => sum + r.messages.length, 0)} custom rule violations`,
- );
- } catch (e) {
- console.log('No ESLint issues found or parsing error:', e.message);
- }
+ // Parse Oxlint output for custom rules
+ // We only want to persist custom rule violations and discard any built-in rule violations that are
+ // not yet toggled off in oxlint.custom-lint-rules.mts
+ const oxlintCustomRuleResults = JSON.parse(oxlintCustomRuleOutput);
+ console.log(
+ `OXC found ${oxlintCustomRuleResults.diagnostics?.length || 0} issues across ${oxlintCustomRuleResults.number_of_files} files for custom rules`,
+ );
+ const {
+ metricsByRule: metricsByCustomRule,
+ occurrencesData: customRuleOccurrencesData,
+ } = parseOxlintResult(oxlintCustomRuleResults, CUSTOM_PLUGIN_ID_PREFIXES);
+
+ const mergedMetricsByRule = { ...metricsByRule, ...metricsByCustomRule };
+ const mergedOccurrencesData = [
+ ...occurrencesData,
+ ...customRuleOccurrencesData,
+ ];
// Transform data for Google Sheets
- const metricsData = Object.entries(metricsByRule).map(
+ const metricsData = Object.entries(mergedMetricsByRule).map(
([rule, { count }]) => [
- 'OXC+ESLint',
+ 'OXC',
rule,
enrichedRules[rule]?.description || 'N/A',
`${count}`,
@@ -225,7 +231,7 @@ async function runOxlintAndProcess() {
],
);
- occurrencesData = occurrencesData.map(
+ const finalizedConcurrencesData = mergedOccurrencesData.map(
({ rule, message, file, line, column }) => [
rule,
enrichedRules[rule]?.description || 'N/A',
@@ -255,7 +261,7 @@ async function runOxlintAndProcess() {
];
console.log(
- `Found ${Object.keys(metricsByRule).length} unique rules with ${occurrencesData.length} total occurrences`,
+ `Found ${Object.keys(metricsByRule).length} unique rules with ${finalizedConcurrencesData.length} total occurrences`,
);
await writeToGoogleSheet(
@@ -266,7 +272,7 @@ async function runOxlintAndProcess() {
);
await writeToGoogleSheet(
- occurrencesData,
+ finalizedConcurrencesData,
'ESLint Backlog!A:G',
eslintBacklogHeaders,
);
@@ -278,4 +284,4 @@ async function runOxlintAndProcess() {
}
}
-export { parseRuleId, runOxlintAndProcess };
+export { parseRuleId, parseOxlintResult, runOxlintAndProcess };
diff --git a/superset-frontend/spec/scripts/oxlint-metrics-uploader.test.ts b/superset-frontend/spec/scripts/oxlint-metrics-uploader.test.ts
index 74e7201d0f3..41c9287f5fb 100644
--- a/superset-frontend/spec/scripts/oxlint-metrics-uploader.test.ts
+++ b/superset-frontend/spec/scripts/oxlint-metrics-uploader.test.ts
@@ -16,43 +16,320 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { parseRuleId } from '../../scripts/internal/oxlint-metrics-uploader';
+import {
+ parseOxlintResult,
+ parseRuleId,
+} from '../../scripts/internal/oxlint-metrics-uploader';
+
+jest.mock('node:child_process', () => ({
+ execSync: jest.fn(),
+}));
+
+jest.mock('@googleapis/sheets', () => ({
+ __esModule: true,
+ default: {
+ sheets: jest.fn(),
+ },
+}));
+
+jest.mock('google-auth-library', () => ({
+ __esModule: true,
+ GoogleAuth: jest.fn(),
+}));
+
+beforeEach(() => {
+ process.env.SERVICE_ACCOUNT_KEY = JSON.stringify({
+ client_email: 'foo@bar.com',
+ });
+ process.env.SPREADSHEET_ID = 'spreadsheet-id';
+});
+
+afterEach(() => {
+ delete process.env.SERVICE_ACCOUNT_KEY;
+ delete process.env.SPREADSHEET_ID;
+ jest.restoreAllMocks();
+});
test('eslint rules keep their bare name', () => {
- expect(parseRuleId('eslint(no-console)')).toBe('no-console');
- expect(parseRuleId('eslint(prefer-destructuring)')).toBe(
- 'prefer-destructuring',
- );
+ expect(parseRuleId('eslint(no-console)')).toMatchObject({
+ parsed: 'no-console',
+ pluginId: 'eslint',
+ });
+ expect(parseRuleId('eslint(prefer-destructuring)')).toMatchObject({
+ parsed: 'prefer-destructuring',
+ pluginId: 'eslint',
+ });
});
test('plugin rules are recorded under plugin/rule (#42981)', () => {
// These are the codes oxlint actually emits. They previously fell through to
// the raw `react-hooks(exhaustive-deps)` string, so the rows no longer lined
// up with the ids the same rules were recorded under before the migration.
- expect(parseRuleId('react-hooks(exhaustive-deps)')).toBe(
- 'react-hooks/exhaustive-deps',
- );
- expect(parseRuleId('react-hooks(rules-of-hooks)')).toBe(
- 'react-hooks/rules-of-hooks',
- );
- expect(parseRuleId('react(jsx-key)')).toBe('react/jsx-key');
- expect(parseRuleId('jest(no-conditional-expect)')).toBe(
- 'jest/no-conditional-expect',
- );
- expect(parseRuleId('oxc(erasing-op)')).toBe('oxc/erasing-op');
- expect(parseRuleId('typescript(no-explicit-any)')).toBe(
- 'typescript/no-explicit-any',
- );
+ expect(parseRuleId('react-hooks(exhaustive-deps)')).toMatchObject({
+ parsed: 'react-hooks/exhaustive-deps',
+ pluginId: 'react-hooks',
+ });
+ expect(parseRuleId('react-hooks(rules-of-hooks)')).toMatchObject({
+ parsed: 'react-hooks/rules-of-hooks',
+ pluginId: 'react-hooks',
+ });
+ expect(parseRuleId('react(jsx-key)')).toMatchObject({
+ parsed: 'react/jsx-key',
+ pluginId: 'react',
+ });
+ expect(parseRuleId('jest(no-conditional-expect)')).toMatchObject({
+ parsed: 'jest/no-conditional-expect',
+ pluginId: 'jest',
+ });
+ expect(parseRuleId('oxc(erasing-op)')).toMatchObject({
+ parsed: 'oxc/erasing-op',
+ pluginId: 'oxc',
+ });
+ expect(parseRuleId('typescript(no-explicit-any)')).toMatchObject({
+ parsed: 'typescript/no-explicit-any',
+ pluginId: 'typescript',
+ });
});
test('the legacy eslint-plugin- prefix still collapses to the plugin name', () => {
- expect(parseRuleId('eslint-plugin-unicorn(no-new-array)')).toBe(
- 'unicorn/no-new-array',
- );
+ expect(parseRuleId('eslint-plugin-unicorn(no-new-array)')).toMatchObject({
+ parsed: 'unicorn/no-new-array',
+ pluginId: 'unicorn',
+ });
});
test('an unrecognized or missing code is passed through rather than dropped', () => {
- expect(parseRuleId('something-unparseable')).toBe('something-unparseable');
- expect(parseRuleId(undefined)).toBe('unknown');
- expect(parseRuleId('')).toBe('unknown');
+ expect(parseRuleId('something-unparseable')).toMatchObject({
+ parsed: 'something-unparseable',
+ pluginId: 'unknown',
+ });
+ expect(parseRuleId(undefined)).toMatchObject({
+ parsed: 'unknown',
+ pluginId: 'unknown',
+ });
+ expect(parseRuleId('')).toMatchObject({
+ parsed: 'unknown',
+ pluginId: 'unknown',
+ });
+});
+
+test('parseOxlintResult aggregates diagnostics and records their locations', () => {
+ const result = parseOxlintResult({
+ diagnostics: [
+ {
+ code: 'eslint(no-console)',
+ filename: 'src/first.ts',
+ message: 'Unexpected console statement',
+ labels: [{ span: { line: 4, column: 8 } }],
+ },
+ {
+ code: 'eslint(no-console)',
+ filename: 'src/second.ts',
+ message: 'Unexpected console statement',
+ labels: [{ span: { line: 9, column: 2 } }],
+ },
+ {
+ code: 'theme-colors(no-literal-colors)',
+ filename: 'src/theme.ts',
+ message: 'Use a theme color',
+ labels: [{ span: { line: 12, column: 6 } }],
+ },
+ ],
+ });
+
+ expect(result.metricsByRule).toEqual({
+ 'no-console': { count: 2 },
+ 'theme-colors/no-literal-colors': { count: 1 },
+ });
+ expect(result.occurrencesData).toMatchObject([
+ {
+ rule: 'no-console',
+ message: 'Unexpected console statement',
+ file: 'src/first.ts',
+ line: 4,
+ column: 8,
+ },
+ {
+ rule: 'no-console',
+ message: 'Unexpected console statement',
+ file: 'src/second.ts',
+ line: 9,
+ column: 2,
+ },
+ {
+ rule: 'theme-colors/no-literal-colors',
+ message: 'Use a theme color',
+ file: 'src/theme.ts',
+ line: 12,
+ column: 6,
+ },
+ ]);
+ expect(result.occurrencesData[0].ts).toEqual(expect.any(String));
+});
+
+test('parseOxlintResult filters diagnostics by plugin ID prefixes', () => {
+ const result = parseOxlintResult(
+ {
+ diagnostics: [
+ {
+ code: 'eslint(no-console)',
+ filename: 'src/app.ts',
+ message: 'Unexpected console statement',
+ },
+ {
+ code: 'i18n-strings(no-template-vars)',
+ filename: 'src/translation.ts',
+ message: 'Avoid template variables',
+ },
+ ],
+ },
+ ['i18n-strings'],
+ );
+
+ expect(result.metricsByRule).toEqual({
+ 'i18n-strings/no-template-vars': { count: 1 },
+ });
+ expect(result.occurrencesData).toMatchObject([
+ {
+ rule: 'i18n-strings/no-template-vars',
+ file: 'src/translation.ts',
+ message: 'Avoid template variables',
+ },
+ ]);
+});
+
+test('runOxlintAndProcess uploads aggregated and backlog data to Google Sheets when oxc commands exits with nonzero code due to detection of rule violations', async () => {
+ jest.resetModules();
+
+ const appendSheetMock = jest.fn().mockResolvedValue({});
+ const updateSheetMock = jest.fn().mockResolvedValue({});
+ const googleSheetsModule = jest.requireMock('@googleapis/sheets');
+ const googleAuthModule = jest.requireMock('google-auth-library');
+ const mockedExecSync = jest.requireMock('node:child_process')
+ .execSync as jest.Mock;
+
+ googleSheetsModule.default.sheets.mockReturnValue({
+ spreadsheets: {
+ values: {
+ append: appendSheetMock,
+ update: updateSheetMock,
+ },
+ },
+ } as any);
+ googleAuthModule.GoogleAuth.mockImplementation(() => ({}) as any);
+ mockedExecSync.mockImplementation((cmd: string) => {
+ if (cmd.includes('oxlint.json')) {
+ throw {
+ stdout: JSON.stringify({
+ diagnostics: [
+ {
+ message: 'Use Array destructuring.',
+ code: 'eslint(prefer-destructuring)',
+ severity: 'warning',
+ filename:
+ 'src/chartCustomizations/components/DeckglLayerVisibility/DeckglLayerVisibilityCustomizationPlugin.test.tsx',
+ labels: [
+ {
+ span: { offset: 4357, length: 38, line: 155, column: 20 },
+ },
+ ],
+ },
+ ],
+ number_of_files: 1,
+ }),
+ };
+ }
+
+ if (cmd.includes('oxlint.custom-lint-rules.mts')) {
+ throw {
+ stdout: JSON.stringify({
+ diagnostics: [
+ {
+ message:
+ 'Eager `label: t(...)` is evaluated at module load, before i18n is initialized. Wrap in an arrow function: `label: () => t(...)`.',
+ code: 'i18n-strings(no-eager-t-in-config)',
+ severity: 'warning',
+ filename: 'src/filters/components/TimeColumn/controlPanel.ts',
+ labels: [
+ {
+ span: {
+ offset: 1013,
+ length: 21,
+ line: 25,
+ column: 14,
+ },
+ },
+ ],
+ },
+ ],
+ number_of_files: 1,
+ }),
+ };
+ }
+
+ throw new Error('Unknown oxlint executions');
+ });
+
+ const { runOxlintAndProcess } =
+ await import('../../scripts/internal/oxlint-metrics-uploader');
+ await runOxlintAndProcess();
+
+ expect(appendSheetMock).toHaveBeenCalledTimes(1);
+ expect(updateSheetMock).toHaveBeenCalledTimes(1);
+
+ const appendCall = appendSheetMock.mock.calls[0][0];
+ const backlogCall = updateSheetMock.mock.calls[0][0];
+
+ expect(appendCall).toMatchObject({
+ spreadsheetId: 'spreadsheet-id',
+ range: 'Aggregated History!A:E',
+ valueInputOption: 'USER_ENTERED',
+ });
+ expect(appendCall.resource.values).toEqual(
+ expect.arrayContaining([
+ ['OXC', 'prefer-destructuring', 'N/A', '1', expect.any(String)],
+ [
+ 'OXC',
+ 'i18n-strings/no-eager-t-in-config',
+ 'N/A',
+ '1',
+ expect.any(String),
+ ],
+ ]),
+ );
+
+ expect(backlogCall).toMatchObject({
+ spreadsheetId: 'spreadsheet-id',
+ range: 'ESLint Backlog!A:G',
+ valueInputOption: 'USER_ENTERED',
+ });
+ expect(backlogCall.resource.values).toEqual([
+ [
+ 'Rule',
+ 'Rule Description',
+ 'ESLint Message',
+ 'File',
+ 'Line',
+ 'Column',
+ 'Timestamp',
+ ],
+ [
+ 'prefer-destructuring',
+ 'N/A',
+ 'Use Array destructuring.',
+ 'src/chartCustomizations/components/DeckglLayerVisibility/DeckglLayerVisibilityCustomizationPlugin.test.tsx',
+ '155',
+ '20',
+ expect.any(String),
+ ],
+ [
+ 'i18n-strings/no-eager-t-in-config',
+ 'N/A',
+ 'Eager `label: t(...)` is evaluated at module load, before i18n is initialized. Wrap in an arrow function: `label: () => t(...)`.',
+ 'src/filters/components/TimeColumn/controlPanel.ts',
+ '25',
+ '14',
+ expect.any(String),
+ ],
+ ]);
});
diff --git a/superset-frontend/tsconfig.json b/superset-frontend/tsconfig.json
index 16400707368..f4dbd05c713 100644
--- a/superset-frontend/tsconfig.json
+++ b/superset-frontend/tsconfig.json
@@ -58,13 +58,13 @@
"@apache-superset/core": ["./packages/superset-core/src"],
"@apache-superset/core/*": ["./packages/superset-core/src/*"],
"@superset-ui/plugin-chart-*": ["./plugins/plugin-chart-*/src"],
- "@superset-ui/plugin-chart-*": ["./plugins/plugin-chart-*/src"],
"@superset-ui/preset-chart-*": ["./plugins/preset-chart-*/src"],
"echarts/types/src/*": ["./node_modules/echarts/types/src/*"]
}
},
"include": [
"./src/**/*",
+ "./custom-lint-rules/**/*",
"./spec/**/*",
"./plugins/**/*",
"./packages/**/*",