@isentinel/eslint-config 6.0.0-beta.34 → 6.0.0-beta.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +228 -174
- package/dist/lint-cli.mjs +13 -9
- package/dist/oxlint.d.mts +1 -1
- package/dist/oxlint.mjs +254 -208
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import path from "node:path";
|
|
|
9
9
|
import { existsSync, readFileSync } from "fs";
|
|
10
10
|
import { execSync } from "node:child_process";
|
|
11
11
|
//#region package.json
|
|
12
|
-
var version = "6.0.0-beta.
|
|
12
|
+
var version = "6.0.0-beta.36";
|
|
13
13
|
var package_default = {
|
|
14
14
|
name: "@isentinel/eslint-config",
|
|
15
15
|
version,
|
package/dist/index.d.mts
CHANGED
|
@@ -26933,7 +26933,7 @@ type ConfigSettings = NonNullable<Linter.Config["settings"]> & {
|
|
|
26933
26933
|
* Package name for DOM Testing Library.
|
|
26934
26934
|
*
|
|
26935
26935
|
* When React testing support is enabled, importing this package is
|
|
26936
|
-
* forbidden in favor of
|
|
26936
|
+
* forbidden in favor of `react-testing-library-lua`.
|
|
26937
26937
|
*/
|
|
26938
26938
|
domPackage?: string;
|
|
26939
26939
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -682,6 +682,218 @@ function isRecord(value) {
|
|
|
682
682
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
683
683
|
}
|
|
684
684
|
//#endregion
|
|
685
|
+
//#region src/rules/react.ts
|
|
686
|
+
const DOM_IMPORT_MESSAGE = "Import from react-testing-library-lua instead; it re-exports the DOM utilities, and eslint-plugin-testing-library only detects one module per file.";
|
|
687
|
+
/**
|
|
688
|
+
* Build the direct DOM Testing Library import restriction shared by both
|
|
689
|
+
* engines.
|
|
690
|
+
*
|
|
691
|
+
* @param domPackage - Package name for DOM Testing Library.
|
|
692
|
+
* @returns The configured restriction, or `undefined` when no package is set.
|
|
693
|
+
*/
|
|
694
|
+
function restrictedDomImportRule(domPackage) {
|
|
695
|
+
if (domPackage === void 0) return;
|
|
696
|
+
return ["error", { paths: [domImportRestriction(domPackage)] }];
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Merge the direct DOM Testing Library restriction into an existing
|
|
700
|
+
* `no-restricted-imports` entry.
|
|
701
|
+
*
|
|
702
|
+
* The existing entry owns the severity and any duplicate restriction. An
|
|
703
|
+
* explicit disabled entry remains disabled.
|
|
704
|
+
*
|
|
705
|
+
* @param rule - Existing rule entry.
|
|
706
|
+
* @param domPackage - Package name for DOM Testing Library.
|
|
707
|
+
* @returns The composed rule entry.
|
|
708
|
+
*/
|
|
709
|
+
function mergeRestrictedDomImportRule(rule, domPackage) {
|
|
710
|
+
if (domPackage === void 0 || rule === "off" || rule === 0) return rule;
|
|
711
|
+
if (rule === void 0) return restrictedDomImportRule(domPackage);
|
|
712
|
+
const parts = Array.isArray(rule) ? [...rule] : [rule];
|
|
713
|
+
const [severity, ...options] = parts;
|
|
714
|
+
if (severity === "off" || severity === 0) return rule;
|
|
715
|
+
if (severity !== "error" && severity !== "warn" && severity !== 1 && severity !== 2) return rule;
|
|
716
|
+
const [firstOption] = options;
|
|
717
|
+
if (options.length === 1 && isObjectStyleRestriction(firstOption)) {
|
|
718
|
+
const paths = Array.isArray(firstOption["paths"]) ? firstOption["paths"] : [];
|
|
719
|
+
if (paths.some((path) => isDomImportRestriction(path, domPackage))) return rule;
|
|
720
|
+
return [severity, {
|
|
721
|
+
...firstOption,
|
|
722
|
+
paths: [...paths, domImportRestriction(domPackage)]
|
|
723
|
+
}];
|
|
724
|
+
}
|
|
725
|
+
if (options.some((option) => isDomImportRestriction(option, domPackage))) return rule;
|
|
726
|
+
if (options.length === 0) return [severity, { paths: [domImportRestriction(domPackage)] }];
|
|
727
|
+
return [...parts, domImportRestriction(domPackage)];
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* React rules shared between the ESLint and oxlint factories.
|
|
731
|
+
*
|
|
732
|
+
* The type-aware react rules stay in the ESLint config (oxlint jsPlugins have
|
|
733
|
+
* no type information).
|
|
734
|
+
*
|
|
735
|
+
* @param options - Shared rule options.
|
|
736
|
+
* @returns The rule map.
|
|
737
|
+
*/
|
|
738
|
+
function reactRules({ domPackage, filenameCase = "kebabCase", reactCompiler = true, stylistic = true, testing = false } = {}) {
|
|
739
|
+
const restrictedDomImport = testing ? restrictedDomImportRule(domPackage) : void 0;
|
|
740
|
+
return {
|
|
741
|
+
"flawless/no-unnecessary-use-callback": "error",
|
|
742
|
+
"flawless/no-unnecessary-use-memo": "error",
|
|
743
|
+
"flawless/purity": "error",
|
|
744
|
+
"small-rules/react-hooks-strict-return": "error",
|
|
745
|
+
...reactCompiler ? {
|
|
746
|
+
"react/globals": "error",
|
|
747
|
+
"react/refs": "error"
|
|
748
|
+
} : {},
|
|
749
|
+
"react-jsx/no-children-prop": "warn",
|
|
750
|
+
"react-jsx/no-children-prop-with-children": "error",
|
|
751
|
+
"react-jsx/no-comment-textnodes": "off",
|
|
752
|
+
"react-jsx/no-key-after-spread": "error",
|
|
753
|
+
"react-jsx/no-leaked-dollar": "warn",
|
|
754
|
+
"react-jsx/no-leaked-semicolon": "warn",
|
|
755
|
+
"react/error-boundaries": "error",
|
|
756
|
+
"react/exhaustive-deps": "error",
|
|
757
|
+
"react/immutability": "error",
|
|
758
|
+
"react/no-access-state-in-setstate": "error",
|
|
759
|
+
"react/no-array-index-key": "warn",
|
|
760
|
+
"react/no-children-count": "warn",
|
|
761
|
+
"react/no-children-for-each": "warn",
|
|
762
|
+
"react/no-children-map": "warn",
|
|
763
|
+
"react/no-children-only": "warn",
|
|
764
|
+
"react/no-children-to-array": "warn",
|
|
765
|
+
"react/no-class-component": "error",
|
|
766
|
+
"react/no-clone-element": "warn",
|
|
767
|
+
"react/no-component-will-mount": "error",
|
|
768
|
+
"react/no-component-will-receive-props": "error",
|
|
769
|
+
"react/no-component-will-update": "error",
|
|
770
|
+
"react/no-create-ref": "error",
|
|
771
|
+
"react/no-direct-mutation-state": "error",
|
|
772
|
+
"react/no-duplicate-key": "error",
|
|
773
|
+
"react/no-forward-ref": "off",
|
|
774
|
+
"react/no-missing-component-display-name": "error",
|
|
775
|
+
"react/no-missing-context-display-name": "error",
|
|
776
|
+
"react/no-missing-key": "error",
|
|
777
|
+
"react/no-misused-capture-owner-stack": "off",
|
|
778
|
+
"react/no-nested-component-definitions": "warn",
|
|
779
|
+
"react/no-nested-lazy-component-declarations": "warn",
|
|
780
|
+
"react/no-set-state-in-component-did-mount": "warn",
|
|
781
|
+
"react/no-set-state-in-component-did-update": "warn",
|
|
782
|
+
"react/no-set-state-in-component-will-update": "warn",
|
|
783
|
+
"react/no-unnecessary-use-prefix": "error",
|
|
784
|
+
"react/no-unsafe-component-will-mount": "error",
|
|
785
|
+
"react/no-unsafe-component-will-receive-props": "error",
|
|
786
|
+
"react/no-unsafe-component-will-update": "error",
|
|
787
|
+
"react/no-unstable-context-value": "error",
|
|
788
|
+
"react/no-unstable-default-props": ["error", { safeDefaultProps: [
|
|
789
|
+
"Axes",
|
|
790
|
+
"BrickColor",
|
|
791
|
+
"CatalogSearchParams",
|
|
792
|
+
"CFrame",
|
|
793
|
+
"Color3",
|
|
794
|
+
"ColorSequence",
|
|
795
|
+
"CFrame",
|
|
796
|
+
"Content",
|
|
797
|
+
"DateTime",
|
|
798
|
+
"DockWidgetPluginGuiInfo",
|
|
799
|
+
"Enum",
|
|
800
|
+
"Faces",
|
|
801
|
+
"FloatCurveKey",
|
|
802
|
+
"Font",
|
|
803
|
+
"NumberRange",
|
|
804
|
+
"NumberSequence",
|
|
805
|
+
"NumberSequenceKeypoint",
|
|
806
|
+
"OverlapParams",
|
|
807
|
+
"Path2DControlPoint",
|
|
808
|
+
"PathWaypoint",
|
|
809
|
+
"PhysicalProperties",
|
|
810
|
+
"Ray",
|
|
811
|
+
"RaycastParams",
|
|
812
|
+
"Rect",
|
|
813
|
+
"Region3",
|
|
814
|
+
"Region3int16",
|
|
815
|
+
"RotationCurveKey",
|
|
816
|
+
"SecurityCapabilities",
|
|
817
|
+
"TweenInfo",
|
|
818
|
+
"UDim",
|
|
819
|
+
"UDim2",
|
|
820
|
+
"ValueCurveKey",
|
|
821
|
+
"Vector2",
|
|
822
|
+
"Vector3",
|
|
823
|
+
"Vector3int16"
|
|
824
|
+
] }],
|
|
825
|
+
"react/no-unused-class-component-members": "off",
|
|
826
|
+
"react/no-unused-state": "error",
|
|
827
|
+
"react/no-use-context": "off",
|
|
828
|
+
"react/rules-of-hooks": "error",
|
|
829
|
+
"react/set-state-in-effect": "error",
|
|
830
|
+
"react/set-state-in-render": "error",
|
|
831
|
+
"react/static-components": "error",
|
|
832
|
+
"react/use-memo": "error",
|
|
833
|
+
"react/use-state": ["error", {
|
|
834
|
+
enforceAssignment: false,
|
|
835
|
+
enforceSetterName: false
|
|
836
|
+
}],
|
|
837
|
+
...testing ? {
|
|
838
|
+
"testing-library/await-async-queries": "error",
|
|
839
|
+
"testing-library/await-async-utils": "error",
|
|
840
|
+
"testing-library/no-await-sync-events": ["error", { eventModules: ["fire-event"] }],
|
|
841
|
+
"testing-library/no-await-sync-queries": "error",
|
|
842
|
+
"testing-library/no-container": "error",
|
|
843
|
+
"testing-library/no-debugging-utils": "error",
|
|
844
|
+
"testing-library/no-manual-cleanup": "error",
|
|
845
|
+
"testing-library/no-promise-in-fire-event": "error",
|
|
846
|
+
"testing-library/no-render-in-lifecycle": "error",
|
|
847
|
+
"testing-library/no-unnecessary-act": "error",
|
|
848
|
+
"testing-library/no-wait-for-multiple-assertions": "error",
|
|
849
|
+
"testing-library/no-wait-for-side-effects": "error",
|
|
850
|
+
"testing-library/no-wait-for-snapshot": "error",
|
|
851
|
+
"testing-library/prefer-explicit-assert": "error",
|
|
852
|
+
"testing-library/prefer-find-by": "error",
|
|
853
|
+
"testing-library/prefer-presence-queries": "error",
|
|
854
|
+
"testing-library/prefer-query-by-disappearance": "error",
|
|
855
|
+
"testing-library/prefer-screen-queries": "error",
|
|
856
|
+
"testing-library/render-result-naming-convention": "error",
|
|
857
|
+
...restrictedDomImport !== void 0 ? { "no-restricted-imports": restrictedDomImport } : {}
|
|
858
|
+
} : {},
|
|
859
|
+
...stylistic !== false ? {
|
|
860
|
+
"flawless/jsx-shorthand-boolean": "warn",
|
|
861
|
+
"flawless/jsx-shorthand-fragment": "warn",
|
|
862
|
+
"flawless/prefer-destructuring-assignment": "error",
|
|
863
|
+
"flawless/react-namespace": "error",
|
|
864
|
+
"one-var": "off",
|
|
865
|
+
"react-jsx/no-useless-fragment": "warn",
|
|
866
|
+
"react-naming-convention/context-name": "error",
|
|
867
|
+
"react-naming-convention/ref-name": "error",
|
|
868
|
+
"react/use-state": "error",
|
|
869
|
+
"style/jsx-curly-brace-presence": ["error", {
|
|
870
|
+
children: "never",
|
|
871
|
+
propElementValues: "always",
|
|
872
|
+
props: "never"
|
|
873
|
+
}],
|
|
874
|
+
"style/jsx-newline": "error",
|
|
875
|
+
"style/jsx-self-closing-comp": "error",
|
|
876
|
+
"unicorn/filename-case": ["error", {
|
|
877
|
+
case: filenameCase,
|
|
878
|
+
ignore: ["^[A-Z0-9]+.md$"],
|
|
879
|
+
multipleFileExtensions: true
|
|
880
|
+
}]
|
|
881
|
+
} : {}
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
function domImportRestriction(domPackage) {
|
|
885
|
+
return {
|
|
886
|
+
name: domPackage,
|
|
887
|
+
message: DOM_IMPORT_MESSAGE
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
function isDomImportRestriction(value, domPackage) {
|
|
891
|
+
return value === domPackage || isRecord(value) && "name" in value && value["name"] === domPackage;
|
|
892
|
+
}
|
|
893
|
+
function isObjectStyleRestriction(value) {
|
|
894
|
+
return isRecord(value) && !("name" in value);
|
|
895
|
+
}
|
|
896
|
+
//#endregion
|
|
685
897
|
//#region src/utils.ts
|
|
686
898
|
const require$2 = createRequire(import.meta.url);
|
|
687
899
|
/**
|
|
@@ -3576,179 +3788,6 @@ function promise() {
|
|
|
3576
3788
|
}];
|
|
3577
3789
|
}
|
|
3578
3790
|
//#endregion
|
|
3579
|
-
//#region src/rules/react.ts
|
|
3580
|
-
/**
|
|
3581
|
-
* Build the direct DOM Testing Library import restriction shared by both
|
|
3582
|
-
* engines.
|
|
3583
|
-
*
|
|
3584
|
-
* @param domPackage - Package name for DOM Testing Library.
|
|
3585
|
-
* @returns The configured restriction, or `undefined` when no package is set.
|
|
3586
|
-
*/
|
|
3587
|
-
function restrictedDomImportRule(domPackage) {
|
|
3588
|
-
if (domPackage === void 0) return;
|
|
3589
|
-
return ["error", { paths: [{
|
|
3590
|
-
name: domPackage,
|
|
3591
|
-
message: "Import from @packages/react-testing-library-lua instead; it re-exports the DOM utilities, and eslint-plugin-testing-library only detects one module per file."
|
|
3592
|
-
}] }];
|
|
3593
|
-
}
|
|
3594
|
-
/**
|
|
3595
|
-
* React rules shared between the ESLint and oxlint factories.
|
|
3596
|
-
*
|
|
3597
|
-
* The type-aware react rules stay in the ESLint config (oxlint jsPlugins have
|
|
3598
|
-
* no type information).
|
|
3599
|
-
*
|
|
3600
|
-
* @param options - Shared rule options.
|
|
3601
|
-
* @returns The rule map.
|
|
3602
|
-
*/
|
|
3603
|
-
function reactRules({ domPackage, filenameCase = "kebabCase", reactCompiler = true, stylistic = true, testing = false } = {}) {
|
|
3604
|
-
const restrictedDomImport = testing ? restrictedDomImportRule(domPackage) : void 0;
|
|
3605
|
-
return {
|
|
3606
|
-
"flawless/no-unnecessary-use-callback": "error",
|
|
3607
|
-
"flawless/no-unnecessary-use-memo": "error",
|
|
3608
|
-
"flawless/purity": "error",
|
|
3609
|
-
"small-rules/react-hooks-strict-return": "error",
|
|
3610
|
-
...reactCompiler ? {
|
|
3611
|
-
"react/globals": "error",
|
|
3612
|
-
"react/refs": "error"
|
|
3613
|
-
} : {},
|
|
3614
|
-
"react-jsx/no-children-prop": "warn",
|
|
3615
|
-
"react-jsx/no-children-prop-with-children": "error",
|
|
3616
|
-
"react-jsx/no-comment-textnodes": "off",
|
|
3617
|
-
"react-jsx/no-key-after-spread": "error",
|
|
3618
|
-
"react-jsx/no-leaked-dollar": "warn",
|
|
3619
|
-
"react-jsx/no-leaked-semicolon": "warn",
|
|
3620
|
-
"react/error-boundaries": "error",
|
|
3621
|
-
"react/exhaustive-deps": "error",
|
|
3622
|
-
"react/immutability": "error",
|
|
3623
|
-
"react/no-access-state-in-setstate": "error",
|
|
3624
|
-
"react/no-array-index-key": "warn",
|
|
3625
|
-
"react/no-children-count": "warn",
|
|
3626
|
-
"react/no-children-for-each": "warn",
|
|
3627
|
-
"react/no-children-map": "warn",
|
|
3628
|
-
"react/no-children-only": "warn",
|
|
3629
|
-
"react/no-children-to-array": "warn",
|
|
3630
|
-
"react/no-class-component": "error",
|
|
3631
|
-
"react/no-clone-element": "warn",
|
|
3632
|
-
"react/no-component-will-mount": "error",
|
|
3633
|
-
"react/no-component-will-receive-props": "error",
|
|
3634
|
-
"react/no-component-will-update": "error",
|
|
3635
|
-
"react/no-create-ref": "error",
|
|
3636
|
-
"react/no-direct-mutation-state": "error",
|
|
3637
|
-
"react/no-duplicate-key": "error",
|
|
3638
|
-
"react/no-forward-ref": "off",
|
|
3639
|
-
"react/no-missing-component-display-name": "error",
|
|
3640
|
-
"react/no-missing-context-display-name": "error",
|
|
3641
|
-
"react/no-missing-key": "error",
|
|
3642
|
-
"react/no-misused-capture-owner-stack": "off",
|
|
3643
|
-
"react/no-nested-component-definitions": "warn",
|
|
3644
|
-
"react/no-nested-lazy-component-declarations": "warn",
|
|
3645
|
-
"react/no-set-state-in-component-did-mount": "warn",
|
|
3646
|
-
"react/no-set-state-in-component-did-update": "warn",
|
|
3647
|
-
"react/no-set-state-in-component-will-update": "warn",
|
|
3648
|
-
"react/no-unnecessary-use-prefix": "error",
|
|
3649
|
-
"react/no-unsafe-component-will-mount": "error",
|
|
3650
|
-
"react/no-unsafe-component-will-receive-props": "error",
|
|
3651
|
-
"react/no-unsafe-component-will-update": "error",
|
|
3652
|
-
"react/no-unstable-context-value": "error",
|
|
3653
|
-
"react/no-unstable-default-props": ["error", { safeDefaultProps: [
|
|
3654
|
-
"Axes",
|
|
3655
|
-
"BrickColor",
|
|
3656
|
-
"CatalogSearchParams",
|
|
3657
|
-
"CFrame",
|
|
3658
|
-
"Color3",
|
|
3659
|
-
"ColorSequence",
|
|
3660
|
-
"CFrame",
|
|
3661
|
-
"Content",
|
|
3662
|
-
"DateTime",
|
|
3663
|
-
"DockWidgetPluginGuiInfo",
|
|
3664
|
-
"Enum",
|
|
3665
|
-
"Faces",
|
|
3666
|
-
"FloatCurveKey",
|
|
3667
|
-
"Font",
|
|
3668
|
-
"NumberRange",
|
|
3669
|
-
"NumberSequence",
|
|
3670
|
-
"NumberSequenceKeypoint",
|
|
3671
|
-
"OverlapParams",
|
|
3672
|
-
"Path2DControlPoint",
|
|
3673
|
-
"PathWaypoint",
|
|
3674
|
-
"PhysicalProperties",
|
|
3675
|
-
"Ray",
|
|
3676
|
-
"RaycastParams",
|
|
3677
|
-
"Rect",
|
|
3678
|
-
"Region3",
|
|
3679
|
-
"Region3int16",
|
|
3680
|
-
"RotationCurveKey",
|
|
3681
|
-
"SecurityCapabilities",
|
|
3682
|
-
"TweenInfo",
|
|
3683
|
-
"UDim",
|
|
3684
|
-
"UDim2",
|
|
3685
|
-
"ValueCurveKey",
|
|
3686
|
-
"Vector2",
|
|
3687
|
-
"Vector3",
|
|
3688
|
-
"Vector3int16"
|
|
3689
|
-
] }],
|
|
3690
|
-
"react/no-unused-class-component-members": "off",
|
|
3691
|
-
"react/no-unused-state": "error",
|
|
3692
|
-
"react/no-use-context": "off",
|
|
3693
|
-
"react/rules-of-hooks": "error",
|
|
3694
|
-
"react/set-state-in-effect": "error",
|
|
3695
|
-
"react/set-state-in-render": "error",
|
|
3696
|
-
"react/static-components": "error",
|
|
3697
|
-
"react/use-memo": "error",
|
|
3698
|
-
"react/use-state": ["error", {
|
|
3699
|
-
enforceAssignment: false,
|
|
3700
|
-
enforceSetterName: false
|
|
3701
|
-
}],
|
|
3702
|
-
...testing ? {
|
|
3703
|
-
"testing-library/await-async-queries": "error",
|
|
3704
|
-
"testing-library/await-async-utils": "error",
|
|
3705
|
-
"testing-library/no-await-sync-events": ["error", { eventModules: ["fire-event"] }],
|
|
3706
|
-
"testing-library/no-await-sync-queries": "error",
|
|
3707
|
-
"testing-library/no-container": "error",
|
|
3708
|
-
"testing-library/no-debugging-utils": "error",
|
|
3709
|
-
"testing-library/no-global-regexp-flag-in-query": "error",
|
|
3710
|
-
"testing-library/no-manual-cleanup": "error",
|
|
3711
|
-
"testing-library/no-node-access": "error",
|
|
3712
|
-
"testing-library/no-promise-in-fire-event": "error",
|
|
3713
|
-
"testing-library/no-render-in-lifecycle": "error",
|
|
3714
|
-
"testing-library/no-unnecessary-act": "error",
|
|
3715
|
-
"testing-library/no-wait-for-multiple-assertions": "error",
|
|
3716
|
-
"testing-library/no-wait-for-side-effects": "error",
|
|
3717
|
-
"testing-library/no-wait-for-snapshot": "error",
|
|
3718
|
-
"testing-library/prefer-explicit-assert": "error",
|
|
3719
|
-
"testing-library/prefer-find-by": "error",
|
|
3720
|
-
"testing-library/prefer-presence-queries": "error",
|
|
3721
|
-
"testing-library/prefer-query-by-disappearance": "error",
|
|
3722
|
-
"testing-library/prefer-screen-queries": "error",
|
|
3723
|
-
"testing-library/render-result-naming-convention": "error",
|
|
3724
|
-
...restrictedDomImport !== void 0 ? { "no-restricted-imports": restrictedDomImport } : {}
|
|
3725
|
-
} : {},
|
|
3726
|
-
...stylistic !== false ? {
|
|
3727
|
-
"flawless/jsx-shorthand-boolean": "warn",
|
|
3728
|
-
"flawless/jsx-shorthand-fragment": "warn",
|
|
3729
|
-
"flawless/prefer-destructuring-assignment": "error",
|
|
3730
|
-
"flawless/react-namespace": "error",
|
|
3731
|
-
"one-var": "off",
|
|
3732
|
-
"react-jsx/no-useless-fragment": "warn",
|
|
3733
|
-
"react-naming-convention/context-name": "error",
|
|
3734
|
-
"react-naming-convention/ref-name": "error",
|
|
3735
|
-
"react/use-state": "error",
|
|
3736
|
-
"style/jsx-curly-brace-presence": ["error", {
|
|
3737
|
-
children: "never",
|
|
3738
|
-
propElementValues: "always",
|
|
3739
|
-
props: "never"
|
|
3740
|
-
}],
|
|
3741
|
-
"style/jsx-newline": "error",
|
|
3742
|
-
"style/jsx-self-closing-comp": "error",
|
|
3743
|
-
"unicorn/filename-case": ["error", {
|
|
3744
|
-
case: filenameCase,
|
|
3745
|
-
ignore: ["^[A-Z0-9]+.md$"],
|
|
3746
|
-
multipleFileExtensions: true
|
|
3747
|
-
}]
|
|
3748
|
-
} : {}
|
|
3749
|
-
};
|
|
3750
|
-
}
|
|
3751
|
-
//#endregion
|
|
3752
3791
|
//#region src/rules/small-rules.ts
|
|
3753
3792
|
/**
|
|
3754
3793
|
* Small-rules rules shared between the ESLint and oxlint factories.
|
|
@@ -3946,7 +3985,7 @@ function robloxRules({ stylistic = true } = {}) {
|
|
|
3946
3985
|
//#region src/eslint/configs/roblox.ts
|
|
3947
3986
|
init_globs();
|
|
3948
3987
|
async function roblox(options = {}, formatLua = true) {
|
|
3949
|
-
const { componentExts: componentExtensions = [], overrides = {}, overridesTypeAware = {}, parserOptions = {}, stylistic = true, typeAware = true } = options;
|
|
3988
|
+
const { componentExts: componentExtensions = [], outOfProjectFiles, overrides = {}, overridesTypeAware = {}, parserOptions = {}, parserOptionsNonTypeAware = {}, parserOptionsTypeAware = {}, stylistic = true, typeAware = true } = options;
|
|
3950
3989
|
const pluginSmallRules = loadSmallRulesPlugin();
|
|
3951
3990
|
const [parserTs, pluginRobloxTs, pluginSentinel] = await Promise.all([
|
|
3952
3991
|
interopDefault(import("@typescript-eslint/parser")),
|
|
@@ -3968,8 +4007,11 @@ async function roblox(options = {}, formatLua = true) {
|
|
|
3968
4007
|
configName: "roblox",
|
|
3969
4008
|
files: parserFiles,
|
|
3970
4009
|
ignores,
|
|
4010
|
+
outOfProjectFiles,
|
|
3971
4011
|
parser: parserTs,
|
|
3972
4012
|
parserOptions,
|
|
4013
|
+
parserOptionsNonTypeAware,
|
|
4014
|
+
parserOptionsTypeAware,
|
|
3973
4015
|
tsconfigPath,
|
|
3974
4016
|
typeAware: usesTypeInformation
|
|
3975
4017
|
});
|
|
@@ -19673,6 +19715,8 @@ async function isentinel(options, ...userConfigs) {
|
|
|
19673
19715
|
const { autoRenamePlugins = true, componentExts: componentExtensions = [], e18e: enableE18e = true, eslintPlugin: enableEslintPlugin = false, formatters, gitignore: enableGitignore = true, jsdoc: enableJsdoc = true, jsonc: enableJsonc = true, jsx: enableJsx = true, markdown: enableMarkdown = true, oxlint: enableOxlint = false, pnpm: enableCatalogs = findUpSync("pnpm-workspace.yaml") !== void 0, react: enableReact = false, root: customRootGlobs, spellCheck: enableSpellCheck, toml: enableToml = true, yaml: enableYaml = true } = options;
|
|
19674
19716
|
const rootGlobs = mergeGlobs(GLOB_ROOT, customRootGlobs);
|
|
19675
19717
|
const enableRoblox = options.roblox !== false;
|
|
19718
|
+
const reactOptions = resolveSubOptions(options, "react");
|
|
19719
|
+
const restrictedDomPackage = enableReact !== false && reactOptions.testing === true ? options.settings?.["testing-library"]?.domPackage : void 0;
|
|
19676
19720
|
const oxlintMode = (() => {
|
|
19677
19721
|
if (enableOxlint === false) return "off";
|
|
19678
19722
|
return enableOxlint === "native" ? "native" : "full";
|
|
@@ -19874,6 +19918,16 @@ async function isentinel(options, ...userConfigs) {
|
|
|
19874
19918
|
if (options.markdown !== false) composer = composer.setDefaultIgnores((previous) => {
|
|
19875
19919
|
return [...previous, GLOB_MARKDOWN];
|
|
19876
19920
|
});
|
|
19921
|
+
if (restrictedDomPackage !== void 0) composer = composer.onResolved((resolved) => {
|
|
19922
|
+
for (const config of resolved) {
|
|
19923
|
+
const restrictedImports = config.rules?.["no-restricted-imports"];
|
|
19924
|
+
if (restrictedImports === void 0) continue;
|
|
19925
|
+
config.rules = {
|
|
19926
|
+
...config.rules,
|
|
19927
|
+
"no-restricted-imports": mergeRestrictedDomImportRule(restrictedImports, restrictedDomPackage)
|
|
19928
|
+
};
|
|
19929
|
+
}
|
|
19930
|
+
});
|
|
19877
19931
|
if (autoRenamePlugins) composer = composer.renamePlugins(defaultPluginRenaming);
|
|
19878
19932
|
if (oxlintMode !== "off") {
|
|
19879
19933
|
const { dropOxlintCoveredRules, warnDeadMappedRules, warnMissingTsgolint } = await Promise.resolve().then(() => (init_oxlint_drop(), oxlint_drop_exports));
|
package/dist/lint-cli.mjs
CHANGED
|
@@ -38,7 +38,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
38
38
|
}) : target, mod));
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region package.json
|
|
41
|
-
var version = "6.0.0-beta.
|
|
41
|
+
var version = "6.0.0-beta.36";
|
|
42
42
|
//#endregion
|
|
43
43
|
//#region src/lint-cli/lib/cli/types.ts
|
|
44
44
|
/**
|
|
@@ -776,7 +776,7 @@ function composeOxlintCommand(options, context) {
|
|
|
776
776
|
if (options.agents) args.push("--format", "agent");
|
|
777
777
|
if (context.oxlintTypeAware) args.push("--type-aware");
|
|
778
778
|
if (options.fix) args.push("--fix");
|
|
779
|
-
args.push(...options.oxlintArgs, ...context.paths);
|
|
779
|
+
args.push("--no-error-on-unmatched-pattern", ...options.oxlintArgs, ...context.paths);
|
|
780
780
|
return {
|
|
781
781
|
args,
|
|
782
782
|
bin: "oxlint",
|
|
@@ -3738,17 +3738,21 @@ function withoutIgnored(files, ignored) {
|
|
|
3738
3738
|
};
|
|
3739
3739
|
}
|
|
3740
3740
|
/**
|
|
3741
|
-
* Restrict explicit lint targets to the ones oxlint could lint
|
|
3742
|
-
*
|
|
3743
|
-
*
|
|
3744
|
-
*
|
|
3745
|
-
*
|
|
3746
|
-
* extension, or when it is an existing directory (either may hold TS/JS files).
|
|
3741
|
+
* Restrict explicit lint targets to the ones oxlint could lint, so a run with
|
|
3742
|
+
* nothing for oxlint to do spawns no oxlint child at all. Oxlint only handles
|
|
3743
|
+
* the TS/JS family: a path is kept when its extension is type-aware, when it
|
|
3744
|
+
* has no extension, or when it is an existing directory (either may hold TS/JS
|
|
3745
|
+
* files).
|
|
3747
3746
|
*
|
|
3748
3747
|
* Surviving targets are then dropped when oxlint's own ignore matching would
|
|
3749
3748
|
* skip them (see {@link gitIgnoredTargets}): a hook stages a `.gitignore`d yet
|
|
3750
3749
|
* git-tracked file (a committed generated `*.d.ts`, say), which passes the
|
|
3751
|
-
* extension test but is
|
|
3750
|
+
* extension test but is a path oxlint refuses.
|
|
3751
|
+
*
|
|
3752
|
+
* This is a spawn-avoidance filter, not a correctness one — the config
|
|
3753
|
+
* `ignores` an all-ignored set usually comes from are invisible to git.
|
|
3754
|
+
* Tolerating that set is `--no-error-on-unmatched-pattern`'s job (see
|
|
3755
|
+
* `composeOxlintCommand`).
|
|
3752
3756
|
*
|
|
3753
3757
|
* @param cwd - The working directory to resolve targets against.
|
|
3754
3758
|
* @param targets - The explicit lint target paths.
|
package/dist/oxlint.d.mts
CHANGED
|
@@ -24305,7 +24305,7 @@ type ConfigSettings = NonNullable<Linter.Config["settings"]> & {
|
|
|
24305
24305
|
* Package name for DOM Testing Library.
|
|
24306
24306
|
*
|
|
24307
24307
|
* When React testing support is enabled, importing this package is
|
|
24308
|
-
* forbidden in favor of
|
|
24308
|
+
* forbidden in favor of `react-testing-library-lua`.
|
|
24309
24309
|
*/
|
|
24310
24310
|
domPackage?: string;
|
|
24311
24311
|
};
|
package/dist/oxlint.mjs
CHANGED
|
@@ -3462,9 +3462,7 @@ const enabledPresetRuleNames = /* @__PURE__ */ new Set([
|
|
|
3462
3462
|
"testing-library/no-await-sync-queries",
|
|
3463
3463
|
"testing-library/no-container",
|
|
3464
3464
|
"testing-library/no-debugging-utils",
|
|
3465
|
-
"testing-library/no-global-regexp-flag-in-query",
|
|
3466
3465
|
"testing-library/no-manual-cleanup",
|
|
3467
|
-
"testing-library/no-node-access",
|
|
3468
3466
|
"testing-library/no-promise-in-fire-event",
|
|
3469
3467
|
"testing-library/no-render-in-lifecycle",
|
|
3470
3468
|
"testing-library/no-unnecessary-act",
|
|
@@ -5228,6 +5226,23 @@ const GLOB_EXCLUDE = [
|
|
|
5228
5226
|
"**/scratch/**"
|
|
5229
5227
|
];
|
|
5230
5228
|
//#endregion
|
|
5229
|
+
//#region src/guards.ts
|
|
5230
|
+
/**
|
|
5231
|
+
* Internal runtime type guards. Prefer these over `as` assertions so values
|
|
5232
|
+
* crossing untyped boundaries (`JSON.parse`, dynamic `import`, plugin objects)
|
|
5233
|
+
* are validated at runtime rather than asserted away.
|
|
5234
|
+
*/
|
|
5235
|
+
/**
|
|
5236
|
+
* Whether a value is a non-null, non-array object usable as a string-keyed
|
|
5237
|
+
* record. Narrows `unknown` without an assertion.
|
|
5238
|
+
*
|
|
5239
|
+
* @param value - The value to test.
|
|
5240
|
+
* @returns Whether the value is a plain object.
|
|
5241
|
+
*/
|
|
5242
|
+
function isRecord$1(value) {
|
|
5243
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5244
|
+
}
|
|
5245
|
+
//#endregion
|
|
5231
5246
|
//#region src/prettier-config.ts
|
|
5232
5247
|
/**
|
|
5233
5248
|
* Synchronous resolution of the effective Prettier-shaped formatting settings
|
|
@@ -5332,15 +5347,15 @@ function parseJsonLike(contents) {
|
|
|
5332
5347
|
return;
|
|
5333
5348
|
}
|
|
5334
5349
|
}
|
|
5335
|
-
function isRecord
|
|
5350
|
+
function isRecord(value) {
|
|
5336
5351
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5337
5352
|
}
|
|
5338
5353
|
function readPackageJsonPrettierKey(filePath) {
|
|
5339
5354
|
const contents = readFileOrUndefined(filePath);
|
|
5340
5355
|
if (contents === void 0) return;
|
|
5341
5356
|
const parsed = parseJsonLike(contents);
|
|
5342
|
-
const prettierKey = isRecord
|
|
5343
|
-
return isRecord
|
|
5357
|
+
const prettierKey = isRecord(parsed) ? parsed["prettier"] : void 0;
|
|
5358
|
+
return isRecord(prettierKey) ? prettierKey : void 0;
|
|
5344
5359
|
}
|
|
5345
5360
|
/**
|
|
5346
5361
|
* Load a JS Prettier config. Node's `require` handles ESM entry points
|
|
@@ -5353,8 +5368,8 @@ function readPackageJsonPrettierKey(filePath) {
|
|
|
5353
5368
|
function requireConfigModule(filePath) {
|
|
5354
5369
|
try {
|
|
5355
5370
|
const loaded = createRequire(filePath)(filePath);
|
|
5356
|
-
const value = isRecord
|
|
5357
|
-
return isRecord
|
|
5371
|
+
const value = isRecord(loaded) && "default" in loaded ? loaded["default"] : loaded;
|
|
5372
|
+
return isRecord(value) ? value : void 0;
|
|
5358
5373
|
} catch {
|
|
5359
5374
|
return;
|
|
5360
5375
|
}
|
|
@@ -5372,7 +5387,7 @@ function readConfigFile(filePath) {
|
|
|
5372
5387
|
const contents = readFileOrUndefined(filePath);
|
|
5373
5388
|
if (contents === void 0) return;
|
|
5374
5389
|
const parsed = parseJsonLike(contents) ?? parseYamlLike(contents);
|
|
5375
|
-
return isRecord
|
|
5390
|
+
return isRecord(parsed) ? parsed : void 0;
|
|
5376
5391
|
}
|
|
5377
5392
|
function ancestorDirectories(cwd) {
|
|
5378
5393
|
const directories = [];
|
|
@@ -5571,21 +5586,216 @@ function buildOxfmtOptions({ oxfmtConfigOptions = {}, oxfmtOptions, prettierOpti
|
|
|
5571
5586
|
};
|
|
5572
5587
|
}
|
|
5573
5588
|
//#endregion
|
|
5574
|
-
//#region src/
|
|
5589
|
+
//#region src/rules/react.ts
|
|
5590
|
+
const DOM_IMPORT_MESSAGE = "Import from react-testing-library-lua instead; it re-exports the DOM utilities, and eslint-plugin-testing-library only detects one module per file.";
|
|
5575
5591
|
/**
|
|
5576
|
-
*
|
|
5577
|
-
*
|
|
5578
|
-
*
|
|
5592
|
+
* Build the direct DOM Testing Library import restriction shared by both
|
|
5593
|
+
* engines.
|
|
5594
|
+
*
|
|
5595
|
+
* @param domPackage - Package name for DOM Testing Library.
|
|
5596
|
+
* @returns The configured restriction, or `undefined` when no package is set.
|
|
5579
5597
|
*/
|
|
5598
|
+
function restrictedDomImportRule(domPackage) {
|
|
5599
|
+
if (domPackage === void 0) return;
|
|
5600
|
+
return ["error", { paths: [domImportRestriction(domPackage)] }];
|
|
5601
|
+
}
|
|
5580
5602
|
/**
|
|
5581
|
-
*
|
|
5582
|
-
*
|
|
5603
|
+
* Merge the direct DOM Testing Library restriction into an existing
|
|
5604
|
+
* `no-restricted-imports` entry.
|
|
5583
5605
|
*
|
|
5584
|
-
*
|
|
5585
|
-
*
|
|
5606
|
+
* The existing entry owns the severity and any duplicate restriction. An
|
|
5607
|
+
* explicit disabled entry remains disabled.
|
|
5608
|
+
*
|
|
5609
|
+
* @param rule - Existing rule entry.
|
|
5610
|
+
* @param domPackage - Package name for DOM Testing Library.
|
|
5611
|
+
* @returns The composed rule entry.
|
|
5586
5612
|
*/
|
|
5587
|
-
function
|
|
5588
|
-
|
|
5613
|
+
function mergeRestrictedDomImportRule(rule, domPackage) {
|
|
5614
|
+
if (domPackage === void 0 || rule === "off" || rule === 0) return rule;
|
|
5615
|
+
if (rule === void 0) return restrictedDomImportRule(domPackage);
|
|
5616
|
+
const parts = Array.isArray(rule) ? [...rule] : [rule];
|
|
5617
|
+
const [severity, ...options] = parts;
|
|
5618
|
+
if (severity === "off" || severity === 0) return rule;
|
|
5619
|
+
if (severity !== "error" && severity !== "warn" && severity !== 1 && severity !== 2) return rule;
|
|
5620
|
+
const [firstOption] = options;
|
|
5621
|
+
if (options.length === 1 && isObjectStyleRestriction(firstOption)) {
|
|
5622
|
+
const paths = Array.isArray(firstOption["paths"]) ? firstOption["paths"] : [];
|
|
5623
|
+
if (paths.some((path) => isDomImportRestriction(path, domPackage))) return rule;
|
|
5624
|
+
return [severity, {
|
|
5625
|
+
...firstOption,
|
|
5626
|
+
paths: [...paths, domImportRestriction(domPackage)]
|
|
5627
|
+
}];
|
|
5628
|
+
}
|
|
5629
|
+
if (options.some((option) => isDomImportRestriction(option, domPackage))) return rule;
|
|
5630
|
+
if (options.length === 0) return [severity, { paths: [domImportRestriction(domPackage)] }];
|
|
5631
|
+
return [...parts, domImportRestriction(domPackage)];
|
|
5632
|
+
}
|
|
5633
|
+
/**
|
|
5634
|
+
* React rules shared between the ESLint and oxlint factories.
|
|
5635
|
+
*
|
|
5636
|
+
* The type-aware react rules stay in the ESLint config (oxlint jsPlugins have
|
|
5637
|
+
* no type information).
|
|
5638
|
+
*
|
|
5639
|
+
* @param options - Shared rule options.
|
|
5640
|
+
* @returns The rule map.
|
|
5641
|
+
*/
|
|
5642
|
+
function reactRules({ domPackage, filenameCase = "kebabCase", reactCompiler = true, stylistic = true, testing = false } = {}) {
|
|
5643
|
+
const restrictedDomImport = testing ? restrictedDomImportRule(domPackage) : void 0;
|
|
5644
|
+
return {
|
|
5645
|
+
"flawless/no-unnecessary-use-callback": "error",
|
|
5646
|
+
"flawless/no-unnecessary-use-memo": "error",
|
|
5647
|
+
"flawless/purity": "error",
|
|
5648
|
+
"small-rules/react-hooks-strict-return": "error",
|
|
5649
|
+
...reactCompiler ? {
|
|
5650
|
+
"react/globals": "error",
|
|
5651
|
+
"react/refs": "error"
|
|
5652
|
+
} : {},
|
|
5653
|
+
"react-jsx/no-children-prop": "warn",
|
|
5654
|
+
"react-jsx/no-children-prop-with-children": "error",
|
|
5655
|
+
"react-jsx/no-comment-textnodes": "off",
|
|
5656
|
+
"react-jsx/no-key-after-spread": "error",
|
|
5657
|
+
"react-jsx/no-leaked-dollar": "warn",
|
|
5658
|
+
"react-jsx/no-leaked-semicolon": "warn",
|
|
5659
|
+
"react/error-boundaries": "error",
|
|
5660
|
+
"react/exhaustive-deps": "error",
|
|
5661
|
+
"react/immutability": "error",
|
|
5662
|
+
"react/no-access-state-in-setstate": "error",
|
|
5663
|
+
"react/no-array-index-key": "warn",
|
|
5664
|
+
"react/no-children-count": "warn",
|
|
5665
|
+
"react/no-children-for-each": "warn",
|
|
5666
|
+
"react/no-children-map": "warn",
|
|
5667
|
+
"react/no-children-only": "warn",
|
|
5668
|
+
"react/no-children-to-array": "warn",
|
|
5669
|
+
"react/no-class-component": "error",
|
|
5670
|
+
"react/no-clone-element": "warn",
|
|
5671
|
+
"react/no-component-will-mount": "error",
|
|
5672
|
+
"react/no-component-will-receive-props": "error",
|
|
5673
|
+
"react/no-component-will-update": "error",
|
|
5674
|
+
"react/no-create-ref": "error",
|
|
5675
|
+
"react/no-direct-mutation-state": "error",
|
|
5676
|
+
"react/no-duplicate-key": "error",
|
|
5677
|
+
"react/no-forward-ref": "off",
|
|
5678
|
+
"react/no-missing-component-display-name": "error",
|
|
5679
|
+
"react/no-missing-context-display-name": "error",
|
|
5680
|
+
"react/no-missing-key": "error",
|
|
5681
|
+
"react/no-misused-capture-owner-stack": "off",
|
|
5682
|
+
"react/no-nested-component-definitions": "warn",
|
|
5683
|
+
"react/no-nested-lazy-component-declarations": "warn",
|
|
5684
|
+
"react/no-set-state-in-component-did-mount": "warn",
|
|
5685
|
+
"react/no-set-state-in-component-did-update": "warn",
|
|
5686
|
+
"react/no-set-state-in-component-will-update": "warn",
|
|
5687
|
+
"react/no-unnecessary-use-prefix": "error",
|
|
5688
|
+
"react/no-unsafe-component-will-mount": "error",
|
|
5689
|
+
"react/no-unsafe-component-will-receive-props": "error",
|
|
5690
|
+
"react/no-unsafe-component-will-update": "error",
|
|
5691
|
+
"react/no-unstable-context-value": "error",
|
|
5692
|
+
"react/no-unstable-default-props": ["error", { safeDefaultProps: [
|
|
5693
|
+
"Axes",
|
|
5694
|
+
"BrickColor",
|
|
5695
|
+
"CatalogSearchParams",
|
|
5696
|
+
"CFrame",
|
|
5697
|
+
"Color3",
|
|
5698
|
+
"ColorSequence",
|
|
5699
|
+
"CFrame",
|
|
5700
|
+
"Content",
|
|
5701
|
+
"DateTime",
|
|
5702
|
+
"DockWidgetPluginGuiInfo",
|
|
5703
|
+
"Enum",
|
|
5704
|
+
"Faces",
|
|
5705
|
+
"FloatCurveKey",
|
|
5706
|
+
"Font",
|
|
5707
|
+
"NumberRange",
|
|
5708
|
+
"NumberSequence",
|
|
5709
|
+
"NumberSequenceKeypoint",
|
|
5710
|
+
"OverlapParams",
|
|
5711
|
+
"Path2DControlPoint",
|
|
5712
|
+
"PathWaypoint",
|
|
5713
|
+
"PhysicalProperties",
|
|
5714
|
+
"Ray",
|
|
5715
|
+
"RaycastParams",
|
|
5716
|
+
"Rect",
|
|
5717
|
+
"Region3",
|
|
5718
|
+
"Region3int16",
|
|
5719
|
+
"RotationCurveKey",
|
|
5720
|
+
"SecurityCapabilities",
|
|
5721
|
+
"TweenInfo",
|
|
5722
|
+
"UDim",
|
|
5723
|
+
"UDim2",
|
|
5724
|
+
"ValueCurveKey",
|
|
5725
|
+
"Vector2",
|
|
5726
|
+
"Vector3",
|
|
5727
|
+
"Vector3int16"
|
|
5728
|
+
] }],
|
|
5729
|
+
"react/no-unused-class-component-members": "off",
|
|
5730
|
+
"react/no-unused-state": "error",
|
|
5731
|
+
"react/no-use-context": "off",
|
|
5732
|
+
"react/rules-of-hooks": "error",
|
|
5733
|
+
"react/set-state-in-effect": "error",
|
|
5734
|
+
"react/set-state-in-render": "error",
|
|
5735
|
+
"react/static-components": "error",
|
|
5736
|
+
"react/use-memo": "error",
|
|
5737
|
+
"react/use-state": ["error", {
|
|
5738
|
+
enforceAssignment: false,
|
|
5739
|
+
enforceSetterName: false
|
|
5740
|
+
}],
|
|
5741
|
+
...testing ? {
|
|
5742
|
+
"testing-library/await-async-queries": "error",
|
|
5743
|
+
"testing-library/await-async-utils": "error",
|
|
5744
|
+
"testing-library/no-await-sync-events": ["error", { eventModules: ["fire-event"] }],
|
|
5745
|
+
"testing-library/no-await-sync-queries": "error",
|
|
5746
|
+
"testing-library/no-container": "error",
|
|
5747
|
+
"testing-library/no-debugging-utils": "error",
|
|
5748
|
+
"testing-library/no-manual-cleanup": "error",
|
|
5749
|
+
"testing-library/no-promise-in-fire-event": "error",
|
|
5750
|
+
"testing-library/no-render-in-lifecycle": "error",
|
|
5751
|
+
"testing-library/no-unnecessary-act": "error",
|
|
5752
|
+
"testing-library/no-wait-for-multiple-assertions": "error",
|
|
5753
|
+
"testing-library/no-wait-for-side-effects": "error",
|
|
5754
|
+
"testing-library/no-wait-for-snapshot": "error",
|
|
5755
|
+
"testing-library/prefer-explicit-assert": "error",
|
|
5756
|
+
"testing-library/prefer-find-by": "error",
|
|
5757
|
+
"testing-library/prefer-presence-queries": "error",
|
|
5758
|
+
"testing-library/prefer-query-by-disappearance": "error",
|
|
5759
|
+
"testing-library/prefer-screen-queries": "error",
|
|
5760
|
+
"testing-library/render-result-naming-convention": "error",
|
|
5761
|
+
...restrictedDomImport !== void 0 ? { "no-restricted-imports": restrictedDomImport } : {}
|
|
5762
|
+
} : {},
|
|
5763
|
+
...stylistic !== false ? {
|
|
5764
|
+
"flawless/jsx-shorthand-boolean": "warn",
|
|
5765
|
+
"flawless/jsx-shorthand-fragment": "warn",
|
|
5766
|
+
"flawless/prefer-destructuring-assignment": "error",
|
|
5767
|
+
"flawless/react-namespace": "error",
|
|
5768
|
+
"one-var": "off",
|
|
5769
|
+
"react-jsx/no-useless-fragment": "warn",
|
|
5770
|
+
"react-naming-convention/context-name": "error",
|
|
5771
|
+
"react-naming-convention/ref-name": "error",
|
|
5772
|
+
"react/use-state": "error",
|
|
5773
|
+
"style/jsx-curly-brace-presence": ["error", {
|
|
5774
|
+
children: "never",
|
|
5775
|
+
propElementValues: "always",
|
|
5776
|
+
props: "never"
|
|
5777
|
+
}],
|
|
5778
|
+
"style/jsx-newline": "error",
|
|
5779
|
+
"style/jsx-self-closing-comp": "error",
|
|
5780
|
+
"unicorn/filename-case": ["error", {
|
|
5781
|
+
case: filenameCase,
|
|
5782
|
+
ignore: ["^[A-Z0-9]+.md$"],
|
|
5783
|
+
multipleFileExtensions: true
|
|
5784
|
+
}]
|
|
5785
|
+
} : {}
|
|
5786
|
+
};
|
|
5787
|
+
}
|
|
5788
|
+
function domImportRestriction(domPackage) {
|
|
5789
|
+
return {
|
|
5790
|
+
name: domPackage,
|
|
5791
|
+
message: DOM_IMPORT_MESSAGE
|
|
5792
|
+
};
|
|
5793
|
+
}
|
|
5794
|
+
function isDomImportRestriction(value, domPackage) {
|
|
5795
|
+
return value === domPackage || isRecord$1(value) && "name" in value && value["name"] === domPackage;
|
|
5796
|
+
}
|
|
5797
|
+
function isObjectStyleRestriction(value) {
|
|
5798
|
+
return isRecord$1(value) && !("name" in value);
|
|
5589
5799
|
}
|
|
5590
5800
|
createRequire(import.meta.url);
|
|
5591
5801
|
/**
|
|
@@ -5641,7 +5851,7 @@ function resolveNodeMajor(settings, cwd = process.cwd()) {
|
|
|
5641
5851
|
let manifest = {};
|
|
5642
5852
|
try {
|
|
5643
5853
|
const parsed = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
5644
|
-
if (isRecord(parsed)) manifest = parsed;
|
|
5854
|
+
if (isRecord$1(parsed)) manifest = parsed;
|
|
5645
5855
|
} catch {}
|
|
5646
5856
|
const range = readNodeRange(manifest);
|
|
5647
5857
|
if (range !== void 0) return parseNodeMajor(range);
|
|
@@ -5659,7 +5869,7 @@ function toSourceGlob(glob) {
|
|
|
5659
5869
|
}
|
|
5660
5870
|
function getOverrides(options, key) {
|
|
5661
5871
|
const sub = resolveSubOptions(options, key);
|
|
5662
|
-
if (!isRecord(sub)) return {
|
|
5872
|
+
if (!isRecord$1(sub)) return {
|
|
5663
5873
|
overrides: {},
|
|
5664
5874
|
overridesTypeAware: {}
|
|
5665
5875
|
};
|
|
@@ -5830,7 +6040,7 @@ function resolveOxfmtConfigOptionsSync() {
|
|
|
5830
6040
|
try {
|
|
5831
6041
|
const content = fs.readFileSync(configPath, "utf-8");
|
|
5832
6042
|
const parsed = JSON.parse(content);
|
|
5833
|
-
if (!isRecord(parsed)) continue;
|
|
6043
|
+
if (!isRecord$1(parsed)) continue;
|
|
5834
6044
|
const { $schema: _, ...config } = parsed;
|
|
5835
6045
|
return config;
|
|
5836
6046
|
} catch {
|
|
@@ -5884,7 +6094,7 @@ function parseNodeMajor(range) {
|
|
|
5884
6094
|
function readSettingsNodeVersion(settings) {
|
|
5885
6095
|
for (const key of ["n", "node"]) {
|
|
5886
6096
|
const setting = settings?.[key];
|
|
5887
|
-
const version = isRecord(setting) ? setting["version"] : void 0;
|
|
6097
|
+
const version = isRecord$1(setting) ? setting["version"] : void 0;
|
|
5888
6098
|
if (typeof version === "string") return version;
|
|
5889
6099
|
}
|
|
5890
6100
|
}
|
|
@@ -5897,9 +6107,9 @@ function readSettingsNodeVersion(settings) {
|
|
|
5897
6107
|
* @returns The declared range, or `undefined` when the manifest declares none.
|
|
5898
6108
|
*/
|
|
5899
6109
|
function readNodeRange({ devEngines, engines }) {
|
|
5900
|
-
if (isRecord(engines) && typeof engines["node"] === "string") return engines["node"];
|
|
5901
|
-
const runtime = isRecord(devEngines) ? devEngines["runtime"] : void 0;
|
|
5902
|
-
const version = (Array.isArray(runtime) ? runtime : [runtime]).find((entry) => isRecord(entry) && entry["name"] === "node")?.["version"];
|
|
6110
|
+
if (isRecord$1(engines) && typeof engines["node"] === "string") return engines["node"];
|
|
6111
|
+
const runtime = isRecord$1(devEngines) ? devEngines["runtime"] : void 0;
|
|
6112
|
+
const version = (Array.isArray(runtime) ? runtime : [runtime]).find((entry) => isRecord$1(entry) && entry["name"] === "node")?.["version"];
|
|
5903
6113
|
return typeof version === "string" ? version : void 0;
|
|
5904
6114
|
}
|
|
5905
6115
|
//#endregion
|
|
@@ -7494,7 +7704,7 @@ const require$1 = createRequire(import.meta.url);
|
|
|
7494
7704
|
function oxlintOxfmt(options) {
|
|
7495
7705
|
const { componentExts: componentExtensions = [], files: oxfmtFiles, oxfmtOptions = {} } = options ?? {};
|
|
7496
7706
|
const configPrettier = require$1("eslint-config-prettier/flat");
|
|
7497
|
-
const configPrettierRules = isRecord(configPrettier) && isRecord(configPrettier["rules"]) ? configPrettier["rules"] : {};
|
|
7707
|
+
const configPrettierRules = isRecord$1(configPrettier) && isRecord$1(configPrettier["rules"]) ? configPrettier["rules"] : {};
|
|
7498
7708
|
const rulesToIgnore = /* @__PURE__ */ new Set(["curly", "style/quotes"]);
|
|
7499
7709
|
const canonicalDisables = {};
|
|
7500
7710
|
const prettierRuleNames = Object.keys(renameRules(configPrettierRules, defaultPluginRenaming));
|
|
@@ -7827,179 +8037,6 @@ function oxlintPromise() {
|
|
|
7827
8037
|
});
|
|
7828
8038
|
}
|
|
7829
8039
|
//#endregion
|
|
7830
|
-
//#region src/rules/react.ts
|
|
7831
|
-
/**
|
|
7832
|
-
* Build the direct DOM Testing Library import restriction shared by both
|
|
7833
|
-
* engines.
|
|
7834
|
-
*
|
|
7835
|
-
* @param domPackage - Package name for DOM Testing Library.
|
|
7836
|
-
* @returns The configured restriction, or `undefined` when no package is set.
|
|
7837
|
-
*/
|
|
7838
|
-
function restrictedDomImportRule(domPackage) {
|
|
7839
|
-
if (domPackage === void 0) return;
|
|
7840
|
-
return ["error", { paths: [{
|
|
7841
|
-
name: domPackage,
|
|
7842
|
-
message: "Import from @packages/react-testing-library-lua instead; it re-exports the DOM utilities, and eslint-plugin-testing-library only detects one module per file."
|
|
7843
|
-
}] }];
|
|
7844
|
-
}
|
|
7845
|
-
/**
|
|
7846
|
-
* React rules shared between the ESLint and oxlint factories.
|
|
7847
|
-
*
|
|
7848
|
-
* The type-aware react rules stay in the ESLint config (oxlint jsPlugins have
|
|
7849
|
-
* no type information).
|
|
7850
|
-
*
|
|
7851
|
-
* @param options - Shared rule options.
|
|
7852
|
-
* @returns The rule map.
|
|
7853
|
-
*/
|
|
7854
|
-
function reactRules({ domPackage, filenameCase = "kebabCase", reactCompiler = true, stylistic = true, testing = false } = {}) {
|
|
7855
|
-
const restrictedDomImport = testing ? restrictedDomImportRule(domPackage) : void 0;
|
|
7856
|
-
return {
|
|
7857
|
-
"flawless/no-unnecessary-use-callback": "error",
|
|
7858
|
-
"flawless/no-unnecessary-use-memo": "error",
|
|
7859
|
-
"flawless/purity": "error",
|
|
7860
|
-
"small-rules/react-hooks-strict-return": "error",
|
|
7861
|
-
...reactCompiler ? {
|
|
7862
|
-
"react/globals": "error",
|
|
7863
|
-
"react/refs": "error"
|
|
7864
|
-
} : {},
|
|
7865
|
-
"react-jsx/no-children-prop": "warn",
|
|
7866
|
-
"react-jsx/no-children-prop-with-children": "error",
|
|
7867
|
-
"react-jsx/no-comment-textnodes": "off",
|
|
7868
|
-
"react-jsx/no-key-after-spread": "error",
|
|
7869
|
-
"react-jsx/no-leaked-dollar": "warn",
|
|
7870
|
-
"react-jsx/no-leaked-semicolon": "warn",
|
|
7871
|
-
"react/error-boundaries": "error",
|
|
7872
|
-
"react/exhaustive-deps": "error",
|
|
7873
|
-
"react/immutability": "error",
|
|
7874
|
-
"react/no-access-state-in-setstate": "error",
|
|
7875
|
-
"react/no-array-index-key": "warn",
|
|
7876
|
-
"react/no-children-count": "warn",
|
|
7877
|
-
"react/no-children-for-each": "warn",
|
|
7878
|
-
"react/no-children-map": "warn",
|
|
7879
|
-
"react/no-children-only": "warn",
|
|
7880
|
-
"react/no-children-to-array": "warn",
|
|
7881
|
-
"react/no-class-component": "error",
|
|
7882
|
-
"react/no-clone-element": "warn",
|
|
7883
|
-
"react/no-component-will-mount": "error",
|
|
7884
|
-
"react/no-component-will-receive-props": "error",
|
|
7885
|
-
"react/no-component-will-update": "error",
|
|
7886
|
-
"react/no-create-ref": "error",
|
|
7887
|
-
"react/no-direct-mutation-state": "error",
|
|
7888
|
-
"react/no-duplicate-key": "error",
|
|
7889
|
-
"react/no-forward-ref": "off",
|
|
7890
|
-
"react/no-missing-component-display-name": "error",
|
|
7891
|
-
"react/no-missing-context-display-name": "error",
|
|
7892
|
-
"react/no-missing-key": "error",
|
|
7893
|
-
"react/no-misused-capture-owner-stack": "off",
|
|
7894
|
-
"react/no-nested-component-definitions": "warn",
|
|
7895
|
-
"react/no-nested-lazy-component-declarations": "warn",
|
|
7896
|
-
"react/no-set-state-in-component-did-mount": "warn",
|
|
7897
|
-
"react/no-set-state-in-component-did-update": "warn",
|
|
7898
|
-
"react/no-set-state-in-component-will-update": "warn",
|
|
7899
|
-
"react/no-unnecessary-use-prefix": "error",
|
|
7900
|
-
"react/no-unsafe-component-will-mount": "error",
|
|
7901
|
-
"react/no-unsafe-component-will-receive-props": "error",
|
|
7902
|
-
"react/no-unsafe-component-will-update": "error",
|
|
7903
|
-
"react/no-unstable-context-value": "error",
|
|
7904
|
-
"react/no-unstable-default-props": ["error", { safeDefaultProps: [
|
|
7905
|
-
"Axes",
|
|
7906
|
-
"BrickColor",
|
|
7907
|
-
"CatalogSearchParams",
|
|
7908
|
-
"CFrame",
|
|
7909
|
-
"Color3",
|
|
7910
|
-
"ColorSequence",
|
|
7911
|
-
"CFrame",
|
|
7912
|
-
"Content",
|
|
7913
|
-
"DateTime",
|
|
7914
|
-
"DockWidgetPluginGuiInfo",
|
|
7915
|
-
"Enum",
|
|
7916
|
-
"Faces",
|
|
7917
|
-
"FloatCurveKey",
|
|
7918
|
-
"Font",
|
|
7919
|
-
"NumberRange",
|
|
7920
|
-
"NumberSequence",
|
|
7921
|
-
"NumberSequenceKeypoint",
|
|
7922
|
-
"OverlapParams",
|
|
7923
|
-
"Path2DControlPoint",
|
|
7924
|
-
"PathWaypoint",
|
|
7925
|
-
"PhysicalProperties",
|
|
7926
|
-
"Ray",
|
|
7927
|
-
"RaycastParams",
|
|
7928
|
-
"Rect",
|
|
7929
|
-
"Region3",
|
|
7930
|
-
"Region3int16",
|
|
7931
|
-
"RotationCurveKey",
|
|
7932
|
-
"SecurityCapabilities",
|
|
7933
|
-
"TweenInfo",
|
|
7934
|
-
"UDim",
|
|
7935
|
-
"UDim2",
|
|
7936
|
-
"ValueCurveKey",
|
|
7937
|
-
"Vector2",
|
|
7938
|
-
"Vector3",
|
|
7939
|
-
"Vector3int16"
|
|
7940
|
-
] }],
|
|
7941
|
-
"react/no-unused-class-component-members": "off",
|
|
7942
|
-
"react/no-unused-state": "error",
|
|
7943
|
-
"react/no-use-context": "off",
|
|
7944
|
-
"react/rules-of-hooks": "error",
|
|
7945
|
-
"react/set-state-in-effect": "error",
|
|
7946
|
-
"react/set-state-in-render": "error",
|
|
7947
|
-
"react/static-components": "error",
|
|
7948
|
-
"react/use-memo": "error",
|
|
7949
|
-
"react/use-state": ["error", {
|
|
7950
|
-
enforceAssignment: false,
|
|
7951
|
-
enforceSetterName: false
|
|
7952
|
-
}],
|
|
7953
|
-
...testing ? {
|
|
7954
|
-
"testing-library/await-async-queries": "error",
|
|
7955
|
-
"testing-library/await-async-utils": "error",
|
|
7956
|
-
"testing-library/no-await-sync-events": ["error", { eventModules: ["fire-event"] }],
|
|
7957
|
-
"testing-library/no-await-sync-queries": "error",
|
|
7958
|
-
"testing-library/no-container": "error",
|
|
7959
|
-
"testing-library/no-debugging-utils": "error",
|
|
7960
|
-
"testing-library/no-global-regexp-flag-in-query": "error",
|
|
7961
|
-
"testing-library/no-manual-cleanup": "error",
|
|
7962
|
-
"testing-library/no-node-access": "error",
|
|
7963
|
-
"testing-library/no-promise-in-fire-event": "error",
|
|
7964
|
-
"testing-library/no-render-in-lifecycle": "error",
|
|
7965
|
-
"testing-library/no-unnecessary-act": "error",
|
|
7966
|
-
"testing-library/no-wait-for-multiple-assertions": "error",
|
|
7967
|
-
"testing-library/no-wait-for-side-effects": "error",
|
|
7968
|
-
"testing-library/no-wait-for-snapshot": "error",
|
|
7969
|
-
"testing-library/prefer-explicit-assert": "error",
|
|
7970
|
-
"testing-library/prefer-find-by": "error",
|
|
7971
|
-
"testing-library/prefer-presence-queries": "error",
|
|
7972
|
-
"testing-library/prefer-query-by-disappearance": "error",
|
|
7973
|
-
"testing-library/prefer-screen-queries": "error",
|
|
7974
|
-
"testing-library/render-result-naming-convention": "error",
|
|
7975
|
-
...restrictedDomImport !== void 0 ? { "no-restricted-imports": restrictedDomImport } : {}
|
|
7976
|
-
} : {},
|
|
7977
|
-
...stylistic !== false ? {
|
|
7978
|
-
"flawless/jsx-shorthand-boolean": "warn",
|
|
7979
|
-
"flawless/jsx-shorthand-fragment": "warn",
|
|
7980
|
-
"flawless/prefer-destructuring-assignment": "error",
|
|
7981
|
-
"flawless/react-namespace": "error",
|
|
7982
|
-
"one-var": "off",
|
|
7983
|
-
"react-jsx/no-useless-fragment": "warn",
|
|
7984
|
-
"react-naming-convention/context-name": "error",
|
|
7985
|
-
"react-naming-convention/ref-name": "error",
|
|
7986
|
-
"react/use-state": "error",
|
|
7987
|
-
"style/jsx-curly-brace-presence": ["error", {
|
|
7988
|
-
children: "never",
|
|
7989
|
-
propElementValues: "always",
|
|
7990
|
-
props: "never"
|
|
7991
|
-
}],
|
|
7992
|
-
"style/jsx-newline": "error",
|
|
7993
|
-
"style/jsx-self-closing-comp": "error",
|
|
7994
|
-
"unicorn/filename-case": ["error", {
|
|
7995
|
-
case: filenameCase,
|
|
7996
|
-
ignore: ["^[A-Z0-9]+.md$"],
|
|
7997
|
-
multipleFileExtensions: true
|
|
7998
|
-
}]
|
|
7999
|
-
} : {}
|
|
8000
|
-
};
|
|
8001
|
-
}
|
|
8002
|
-
//#endregion
|
|
8003
8040
|
//#region src/oxlint/configs/react.ts
|
|
8004
8041
|
/**
|
|
8005
8042
|
* React configs for oxlint: the shared react family plus oxlint's native
|
|
@@ -9183,6 +9220,10 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
9183
9220
|
const { categories, componentExts: componentExtensions = [], e18e: enableE18e = true, env, eslintPlugin: enableEslintPlugin = false, formatters, gitignore: enableGitignore = true, globals, ignores, jsdoc: enableJsdoc = true, jsPlugins: userJsPlugins, jsx: enableJsx = true, options: linterOptions, oxc: enableOxc = true, react: enableReact = false, root: customRootGlobs, rules = {}, spellCheck: enableSpellCheck, test: enableTest = false, warnDroppedOverrides: enableDroppedOverrideWarning = true } = options;
|
|
9184
9221
|
const rootGlobs = mergeGlobs(GLOB_ROOT, customRootGlobs);
|
|
9185
9222
|
const enableRoblox = options.roblox !== false;
|
|
9223
|
+
const reactOptions = resolveSubOptions(options, "react");
|
|
9224
|
+
const testingLibrarySettings = options.settings?.["testing-library"];
|
|
9225
|
+
const configuredDomPackage = isRecord$1(testingLibrarySettings) && typeof testingLibrarySettings["domPackage"] === "string" ? testingLibrarySettings["domPackage"] : void 0;
|
|
9226
|
+
const restrictedDomPackage = enableReact !== false && reactOptions.testing === true ? configuredDomPackage : void 0;
|
|
9186
9227
|
const nativeOnly = userJsPlugins === false;
|
|
9187
9228
|
const robloxScopedFiles = typeof options.roblox === "object" && options.roblox.files !== void 0 ? options.roblox.files.flat() : void 0;
|
|
9188
9229
|
const hasComplement = !enableRoblox || robloxScopedFiles !== void 0;
|
|
@@ -9293,15 +9334,12 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
9293
9334
|
...resolveSubOptions(options, "perfectionist"),
|
|
9294
9335
|
type: projectType
|
|
9295
9336
|
}), oxlintStylistic(stylisticOptions));
|
|
9296
|
-
if (enableReact !== false) {
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
...reactOptions
|
|
9303
|
-
}));
|
|
9304
|
-
}
|
|
9337
|
+
if (enableReact !== false) configs.push(oxlintReact({
|
|
9338
|
+
roblox: enableRoblox,
|
|
9339
|
+
settings: options.settings,
|
|
9340
|
+
stylistic: stylisticOptions,
|
|
9341
|
+
...reactOptions
|
|
9342
|
+
}));
|
|
9305
9343
|
if (enableSpellCheck !== false) configs.push(oxlintSpelling({
|
|
9306
9344
|
...resolveSubOptions(options, "spellCheck"),
|
|
9307
9345
|
componentExts: componentExtensions,
|
|
@@ -9362,6 +9400,14 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
9362
9400
|
for (const jsPlugin of fragmentJsPlugins) jsPlugins.set(jsPluginKey(jsPlugin), jsPlugin);
|
|
9363
9401
|
if (config.settings) Object.assign(mergedSettings, config.settings);
|
|
9364
9402
|
const { name: _name, settings: _settings, ...override } = config;
|
|
9403
|
+
const restrictedImports = override.rules?.["no-restricted-imports"];
|
|
9404
|
+
if (restrictedDomPackage !== void 0 && restrictedImports !== void 0) {
|
|
9405
|
+
const mergedRestrictedImports = mergeRestrictedDomImportRule(restrictedImports, restrictedDomPackage);
|
|
9406
|
+
override.rules = {
|
|
9407
|
+
...override.rules,
|
|
9408
|
+
"no-restricted-imports": mergedRestrictedImports
|
|
9409
|
+
};
|
|
9410
|
+
}
|
|
9365
9411
|
override.files = override.files.map(anchorOxlintGlob);
|
|
9366
9412
|
if (override.excludeFiles !== void 0) override.excludeFiles = override.excludeFiles.map(anchorOxlintGlob);
|
|
9367
9413
|
overrides.push(override);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@isentinel/eslint-config",
|
|
3
|
-
"version": "6.0.0-beta.
|
|
3
|
+
"version": "6.0.0-beta.36",
|
|
4
4
|
"description": "iSentinel's ESLint config",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint-config",
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
"typescript": "6.0.3",
|
|
144
144
|
"unplugin-unused": "0.5.7",
|
|
145
145
|
"vitest": "4.1.10",
|
|
146
|
-
"@isentinel/eslint-config": "6.0.0-beta.
|
|
146
|
+
"@isentinel/eslint-config": "6.0.0-beta.36"
|
|
147
147
|
},
|
|
148
148
|
"peerDependencies": {
|
|
149
149
|
"@vitest/eslint-plugin": "^1.6.4",
|