@isentinel/eslint-config 6.0.0-beta.35 → 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.mjs +228 -172
- package/dist/lint-cli.mjs +13 -9
- package/dist/oxlint.mjs +254 -204
- 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.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,177 +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 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-manual-cleanup": "error",
|
|
3710
|
-
"testing-library/no-promise-in-fire-event": "error",
|
|
3711
|
-
"testing-library/no-render-in-lifecycle": "error",
|
|
3712
|
-
"testing-library/no-unnecessary-act": "error",
|
|
3713
|
-
"testing-library/no-wait-for-multiple-assertions": "error",
|
|
3714
|
-
"testing-library/no-wait-for-side-effects": "error",
|
|
3715
|
-
"testing-library/no-wait-for-snapshot": "error",
|
|
3716
|
-
"testing-library/prefer-explicit-assert": "error",
|
|
3717
|
-
"testing-library/prefer-find-by": "error",
|
|
3718
|
-
"testing-library/prefer-presence-queries": "error",
|
|
3719
|
-
"testing-library/prefer-query-by-disappearance": "error",
|
|
3720
|
-
"testing-library/prefer-screen-queries": "error",
|
|
3721
|
-
"testing-library/render-result-naming-convention": "error",
|
|
3722
|
-
...restrictedDomImport !== void 0 ? { "no-restricted-imports": restrictedDomImport } : {}
|
|
3723
|
-
} : {},
|
|
3724
|
-
...stylistic !== false ? {
|
|
3725
|
-
"flawless/jsx-shorthand-boolean": "warn",
|
|
3726
|
-
"flawless/jsx-shorthand-fragment": "warn",
|
|
3727
|
-
"flawless/prefer-destructuring-assignment": "error",
|
|
3728
|
-
"flawless/react-namespace": "error",
|
|
3729
|
-
"one-var": "off",
|
|
3730
|
-
"react-jsx/no-useless-fragment": "warn",
|
|
3731
|
-
"react-naming-convention/context-name": "error",
|
|
3732
|
-
"react-naming-convention/ref-name": "error",
|
|
3733
|
-
"react/use-state": "error",
|
|
3734
|
-
"style/jsx-curly-brace-presence": ["error", {
|
|
3735
|
-
children: "never",
|
|
3736
|
-
propElementValues: "always",
|
|
3737
|
-
props: "never"
|
|
3738
|
-
}],
|
|
3739
|
-
"style/jsx-newline": "error",
|
|
3740
|
-
"style/jsx-self-closing-comp": "error",
|
|
3741
|
-
"unicorn/filename-case": ["error", {
|
|
3742
|
-
case: filenameCase,
|
|
3743
|
-
ignore: ["^[A-Z0-9]+.md$"],
|
|
3744
|
-
multipleFileExtensions: true
|
|
3745
|
-
}]
|
|
3746
|
-
} : {}
|
|
3747
|
-
};
|
|
3748
|
-
}
|
|
3749
|
-
//#endregion
|
|
3750
3791
|
//#region src/rules/small-rules.ts
|
|
3751
3792
|
/**
|
|
3752
3793
|
* Small-rules rules shared between the ESLint and oxlint factories.
|
|
@@ -3944,7 +3985,7 @@ function robloxRules({ stylistic = true } = {}) {
|
|
|
3944
3985
|
//#region src/eslint/configs/roblox.ts
|
|
3945
3986
|
init_globs();
|
|
3946
3987
|
async function roblox(options = {}, formatLua = true) {
|
|
3947
|
-
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;
|
|
3948
3989
|
const pluginSmallRules = loadSmallRulesPlugin();
|
|
3949
3990
|
const [parserTs, pluginRobloxTs, pluginSentinel] = await Promise.all([
|
|
3950
3991
|
interopDefault(import("@typescript-eslint/parser")),
|
|
@@ -3966,8 +4007,11 @@ async function roblox(options = {}, formatLua = true) {
|
|
|
3966
4007
|
configName: "roblox",
|
|
3967
4008
|
files: parserFiles,
|
|
3968
4009
|
ignores,
|
|
4010
|
+
outOfProjectFiles,
|
|
3969
4011
|
parser: parserTs,
|
|
3970
4012
|
parserOptions,
|
|
4013
|
+
parserOptionsNonTypeAware,
|
|
4014
|
+
parserOptionsTypeAware,
|
|
3971
4015
|
tsconfigPath,
|
|
3972
4016
|
typeAware: usesTypeInformation
|
|
3973
4017
|
});
|
|
@@ -19671,6 +19715,8 @@ async function isentinel(options, ...userConfigs) {
|
|
|
19671
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;
|
|
19672
19716
|
const rootGlobs = mergeGlobs(GLOB_ROOT, customRootGlobs);
|
|
19673
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;
|
|
19674
19720
|
const oxlintMode = (() => {
|
|
19675
19721
|
if (enableOxlint === false) return "off";
|
|
19676
19722
|
return enableOxlint === "native" ? "native" : "full";
|
|
@@ -19872,6 +19918,16 @@ async function isentinel(options, ...userConfigs) {
|
|
|
19872
19918
|
if (options.markdown !== false) composer = composer.setDefaultIgnores((previous) => {
|
|
19873
19919
|
return [...previous, GLOB_MARKDOWN];
|
|
19874
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
|
+
});
|
|
19875
19931
|
if (autoRenamePlugins) composer = composer.renamePlugins(defaultPluginRenaming);
|
|
19876
19932
|
if (oxlintMode !== "off") {
|
|
19877
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.mjs
CHANGED
|
@@ -5226,6 +5226,23 @@ const GLOB_EXCLUDE = [
|
|
|
5226
5226
|
"**/scratch/**"
|
|
5227
5227
|
];
|
|
5228
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
|
|
5229
5246
|
//#region src/prettier-config.ts
|
|
5230
5247
|
/**
|
|
5231
5248
|
* Synchronous resolution of the effective Prettier-shaped formatting settings
|
|
@@ -5330,15 +5347,15 @@ function parseJsonLike(contents) {
|
|
|
5330
5347
|
return;
|
|
5331
5348
|
}
|
|
5332
5349
|
}
|
|
5333
|
-
function isRecord
|
|
5350
|
+
function isRecord(value) {
|
|
5334
5351
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5335
5352
|
}
|
|
5336
5353
|
function readPackageJsonPrettierKey(filePath) {
|
|
5337
5354
|
const contents = readFileOrUndefined(filePath);
|
|
5338
5355
|
if (contents === void 0) return;
|
|
5339
5356
|
const parsed = parseJsonLike(contents);
|
|
5340
|
-
const prettierKey = isRecord
|
|
5341
|
-
return isRecord
|
|
5357
|
+
const prettierKey = isRecord(parsed) ? parsed["prettier"] : void 0;
|
|
5358
|
+
return isRecord(prettierKey) ? prettierKey : void 0;
|
|
5342
5359
|
}
|
|
5343
5360
|
/**
|
|
5344
5361
|
* Load a JS Prettier config. Node's `require` handles ESM entry points
|
|
@@ -5351,8 +5368,8 @@ function readPackageJsonPrettierKey(filePath) {
|
|
|
5351
5368
|
function requireConfigModule(filePath) {
|
|
5352
5369
|
try {
|
|
5353
5370
|
const loaded = createRequire(filePath)(filePath);
|
|
5354
|
-
const value = isRecord
|
|
5355
|
-
return isRecord
|
|
5371
|
+
const value = isRecord(loaded) && "default" in loaded ? loaded["default"] : loaded;
|
|
5372
|
+
return isRecord(value) ? value : void 0;
|
|
5356
5373
|
} catch {
|
|
5357
5374
|
return;
|
|
5358
5375
|
}
|
|
@@ -5370,7 +5387,7 @@ function readConfigFile(filePath) {
|
|
|
5370
5387
|
const contents = readFileOrUndefined(filePath);
|
|
5371
5388
|
if (contents === void 0) return;
|
|
5372
5389
|
const parsed = parseJsonLike(contents) ?? parseYamlLike(contents);
|
|
5373
|
-
return isRecord
|
|
5390
|
+
return isRecord(parsed) ? parsed : void 0;
|
|
5374
5391
|
}
|
|
5375
5392
|
function ancestorDirectories(cwd) {
|
|
5376
5393
|
const directories = [];
|
|
@@ -5569,21 +5586,216 @@ function buildOxfmtOptions({ oxfmtConfigOptions = {}, oxfmtOptions, prettierOpti
|
|
|
5569
5586
|
};
|
|
5570
5587
|
}
|
|
5571
5588
|
//#endregion
|
|
5572
|
-
//#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.";
|
|
5573
5591
|
/**
|
|
5574
|
-
*
|
|
5575
|
-
*
|
|
5576
|
-
*
|
|
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.
|
|
5577
5597
|
*/
|
|
5598
|
+
function restrictedDomImportRule(domPackage) {
|
|
5599
|
+
if (domPackage === void 0) return;
|
|
5600
|
+
return ["error", { paths: [domImportRestriction(domPackage)] }];
|
|
5601
|
+
}
|
|
5578
5602
|
/**
|
|
5579
|
-
*
|
|
5580
|
-
*
|
|
5603
|
+
* Merge the direct DOM Testing Library restriction into an existing
|
|
5604
|
+
* `no-restricted-imports` entry.
|
|
5581
5605
|
*
|
|
5582
|
-
*
|
|
5583
|
-
*
|
|
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.
|
|
5584
5612
|
*/
|
|
5585
|
-
function
|
|
5586
|
-
|
|
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);
|
|
5587
5799
|
}
|
|
5588
5800
|
createRequire(import.meta.url);
|
|
5589
5801
|
/**
|
|
@@ -5639,7 +5851,7 @@ function resolveNodeMajor(settings, cwd = process.cwd()) {
|
|
|
5639
5851
|
let manifest = {};
|
|
5640
5852
|
try {
|
|
5641
5853
|
const parsed = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
5642
|
-
if (isRecord(parsed)) manifest = parsed;
|
|
5854
|
+
if (isRecord$1(parsed)) manifest = parsed;
|
|
5643
5855
|
} catch {}
|
|
5644
5856
|
const range = readNodeRange(manifest);
|
|
5645
5857
|
if (range !== void 0) return parseNodeMajor(range);
|
|
@@ -5657,7 +5869,7 @@ function toSourceGlob(glob) {
|
|
|
5657
5869
|
}
|
|
5658
5870
|
function getOverrides(options, key) {
|
|
5659
5871
|
const sub = resolveSubOptions(options, key);
|
|
5660
|
-
if (!isRecord(sub)) return {
|
|
5872
|
+
if (!isRecord$1(sub)) return {
|
|
5661
5873
|
overrides: {},
|
|
5662
5874
|
overridesTypeAware: {}
|
|
5663
5875
|
};
|
|
@@ -5828,7 +6040,7 @@ function resolveOxfmtConfigOptionsSync() {
|
|
|
5828
6040
|
try {
|
|
5829
6041
|
const content = fs.readFileSync(configPath, "utf-8");
|
|
5830
6042
|
const parsed = JSON.parse(content);
|
|
5831
|
-
if (!isRecord(parsed)) continue;
|
|
6043
|
+
if (!isRecord$1(parsed)) continue;
|
|
5832
6044
|
const { $schema: _, ...config } = parsed;
|
|
5833
6045
|
return config;
|
|
5834
6046
|
} catch {
|
|
@@ -5882,7 +6094,7 @@ function parseNodeMajor(range) {
|
|
|
5882
6094
|
function readSettingsNodeVersion(settings) {
|
|
5883
6095
|
for (const key of ["n", "node"]) {
|
|
5884
6096
|
const setting = settings?.[key];
|
|
5885
|
-
const version = isRecord(setting) ? setting["version"] : void 0;
|
|
6097
|
+
const version = isRecord$1(setting) ? setting["version"] : void 0;
|
|
5886
6098
|
if (typeof version === "string") return version;
|
|
5887
6099
|
}
|
|
5888
6100
|
}
|
|
@@ -5895,9 +6107,9 @@ function readSettingsNodeVersion(settings) {
|
|
|
5895
6107
|
* @returns The declared range, or `undefined` when the manifest declares none.
|
|
5896
6108
|
*/
|
|
5897
6109
|
function readNodeRange({ devEngines, engines }) {
|
|
5898
|
-
if (isRecord(engines) && typeof engines["node"] === "string") return engines["node"];
|
|
5899
|
-
const runtime = isRecord(devEngines) ? devEngines["runtime"] : void 0;
|
|
5900
|
-
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"];
|
|
5901
6113
|
return typeof version === "string" ? version : void 0;
|
|
5902
6114
|
}
|
|
5903
6115
|
//#endregion
|
|
@@ -7492,7 +7704,7 @@ const require$1 = createRequire(import.meta.url);
|
|
|
7492
7704
|
function oxlintOxfmt(options) {
|
|
7493
7705
|
const { componentExts: componentExtensions = [], files: oxfmtFiles, oxfmtOptions = {} } = options ?? {};
|
|
7494
7706
|
const configPrettier = require$1("eslint-config-prettier/flat");
|
|
7495
|
-
const configPrettierRules = isRecord(configPrettier) && isRecord(configPrettier["rules"]) ? configPrettier["rules"] : {};
|
|
7707
|
+
const configPrettierRules = isRecord$1(configPrettier) && isRecord$1(configPrettier["rules"]) ? configPrettier["rules"] : {};
|
|
7496
7708
|
const rulesToIgnore = /* @__PURE__ */ new Set(["curly", "style/quotes"]);
|
|
7497
7709
|
const canonicalDisables = {};
|
|
7498
7710
|
const prettierRuleNames = Object.keys(renameRules(configPrettierRules, defaultPluginRenaming));
|
|
@@ -7825,177 +8037,6 @@ function oxlintPromise() {
|
|
|
7825
8037
|
});
|
|
7826
8038
|
}
|
|
7827
8039
|
//#endregion
|
|
7828
|
-
//#region src/rules/react.ts
|
|
7829
|
-
/**
|
|
7830
|
-
* Build the direct DOM Testing Library import restriction shared by both
|
|
7831
|
-
* engines.
|
|
7832
|
-
*
|
|
7833
|
-
* @param domPackage - Package name for DOM Testing Library.
|
|
7834
|
-
* @returns The configured restriction, or `undefined` when no package is set.
|
|
7835
|
-
*/
|
|
7836
|
-
function restrictedDomImportRule(domPackage) {
|
|
7837
|
-
if (domPackage === void 0) return;
|
|
7838
|
-
return ["error", { paths: [{
|
|
7839
|
-
name: domPackage,
|
|
7840
|
-
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."
|
|
7841
|
-
}] }];
|
|
7842
|
-
}
|
|
7843
|
-
/**
|
|
7844
|
-
* React rules shared between the ESLint and oxlint factories.
|
|
7845
|
-
*
|
|
7846
|
-
* The type-aware react rules stay in the ESLint config (oxlint jsPlugins have
|
|
7847
|
-
* no type information).
|
|
7848
|
-
*
|
|
7849
|
-
* @param options - Shared rule options.
|
|
7850
|
-
* @returns The rule map.
|
|
7851
|
-
*/
|
|
7852
|
-
function reactRules({ domPackage, filenameCase = "kebabCase", reactCompiler = true, stylistic = true, testing = false } = {}) {
|
|
7853
|
-
const restrictedDomImport = testing ? restrictedDomImportRule(domPackage) : void 0;
|
|
7854
|
-
return {
|
|
7855
|
-
"flawless/no-unnecessary-use-callback": "error",
|
|
7856
|
-
"flawless/no-unnecessary-use-memo": "error",
|
|
7857
|
-
"flawless/purity": "error",
|
|
7858
|
-
"small-rules/react-hooks-strict-return": "error",
|
|
7859
|
-
...reactCompiler ? {
|
|
7860
|
-
"react/globals": "error",
|
|
7861
|
-
"react/refs": "error"
|
|
7862
|
-
} : {},
|
|
7863
|
-
"react-jsx/no-children-prop": "warn",
|
|
7864
|
-
"react-jsx/no-children-prop-with-children": "error",
|
|
7865
|
-
"react-jsx/no-comment-textnodes": "off",
|
|
7866
|
-
"react-jsx/no-key-after-spread": "error",
|
|
7867
|
-
"react-jsx/no-leaked-dollar": "warn",
|
|
7868
|
-
"react-jsx/no-leaked-semicolon": "warn",
|
|
7869
|
-
"react/error-boundaries": "error",
|
|
7870
|
-
"react/exhaustive-deps": "error",
|
|
7871
|
-
"react/immutability": "error",
|
|
7872
|
-
"react/no-access-state-in-setstate": "error",
|
|
7873
|
-
"react/no-array-index-key": "warn",
|
|
7874
|
-
"react/no-children-count": "warn",
|
|
7875
|
-
"react/no-children-for-each": "warn",
|
|
7876
|
-
"react/no-children-map": "warn",
|
|
7877
|
-
"react/no-children-only": "warn",
|
|
7878
|
-
"react/no-children-to-array": "warn",
|
|
7879
|
-
"react/no-class-component": "error",
|
|
7880
|
-
"react/no-clone-element": "warn",
|
|
7881
|
-
"react/no-component-will-mount": "error",
|
|
7882
|
-
"react/no-component-will-receive-props": "error",
|
|
7883
|
-
"react/no-component-will-update": "error",
|
|
7884
|
-
"react/no-create-ref": "error",
|
|
7885
|
-
"react/no-direct-mutation-state": "error",
|
|
7886
|
-
"react/no-duplicate-key": "error",
|
|
7887
|
-
"react/no-forward-ref": "off",
|
|
7888
|
-
"react/no-missing-component-display-name": "error",
|
|
7889
|
-
"react/no-missing-context-display-name": "error",
|
|
7890
|
-
"react/no-missing-key": "error",
|
|
7891
|
-
"react/no-misused-capture-owner-stack": "off",
|
|
7892
|
-
"react/no-nested-component-definitions": "warn",
|
|
7893
|
-
"react/no-nested-lazy-component-declarations": "warn",
|
|
7894
|
-
"react/no-set-state-in-component-did-mount": "warn",
|
|
7895
|
-
"react/no-set-state-in-component-did-update": "warn",
|
|
7896
|
-
"react/no-set-state-in-component-will-update": "warn",
|
|
7897
|
-
"react/no-unnecessary-use-prefix": "error",
|
|
7898
|
-
"react/no-unsafe-component-will-mount": "error",
|
|
7899
|
-
"react/no-unsafe-component-will-receive-props": "error",
|
|
7900
|
-
"react/no-unsafe-component-will-update": "error",
|
|
7901
|
-
"react/no-unstable-context-value": "error",
|
|
7902
|
-
"react/no-unstable-default-props": ["error", { safeDefaultProps: [
|
|
7903
|
-
"Axes",
|
|
7904
|
-
"BrickColor",
|
|
7905
|
-
"CatalogSearchParams",
|
|
7906
|
-
"CFrame",
|
|
7907
|
-
"Color3",
|
|
7908
|
-
"ColorSequence",
|
|
7909
|
-
"CFrame",
|
|
7910
|
-
"Content",
|
|
7911
|
-
"DateTime",
|
|
7912
|
-
"DockWidgetPluginGuiInfo",
|
|
7913
|
-
"Enum",
|
|
7914
|
-
"Faces",
|
|
7915
|
-
"FloatCurveKey",
|
|
7916
|
-
"Font",
|
|
7917
|
-
"NumberRange",
|
|
7918
|
-
"NumberSequence",
|
|
7919
|
-
"NumberSequenceKeypoint",
|
|
7920
|
-
"OverlapParams",
|
|
7921
|
-
"Path2DControlPoint",
|
|
7922
|
-
"PathWaypoint",
|
|
7923
|
-
"PhysicalProperties",
|
|
7924
|
-
"Ray",
|
|
7925
|
-
"RaycastParams",
|
|
7926
|
-
"Rect",
|
|
7927
|
-
"Region3",
|
|
7928
|
-
"Region3int16",
|
|
7929
|
-
"RotationCurveKey",
|
|
7930
|
-
"SecurityCapabilities",
|
|
7931
|
-
"TweenInfo",
|
|
7932
|
-
"UDim",
|
|
7933
|
-
"UDim2",
|
|
7934
|
-
"ValueCurveKey",
|
|
7935
|
-
"Vector2",
|
|
7936
|
-
"Vector3",
|
|
7937
|
-
"Vector3int16"
|
|
7938
|
-
] }],
|
|
7939
|
-
"react/no-unused-class-component-members": "off",
|
|
7940
|
-
"react/no-unused-state": "error",
|
|
7941
|
-
"react/no-use-context": "off",
|
|
7942
|
-
"react/rules-of-hooks": "error",
|
|
7943
|
-
"react/set-state-in-effect": "error",
|
|
7944
|
-
"react/set-state-in-render": "error",
|
|
7945
|
-
"react/static-components": "error",
|
|
7946
|
-
"react/use-memo": "error",
|
|
7947
|
-
"react/use-state": ["error", {
|
|
7948
|
-
enforceAssignment: false,
|
|
7949
|
-
enforceSetterName: false
|
|
7950
|
-
}],
|
|
7951
|
-
...testing ? {
|
|
7952
|
-
"testing-library/await-async-queries": "error",
|
|
7953
|
-
"testing-library/await-async-utils": "error",
|
|
7954
|
-
"testing-library/no-await-sync-events": ["error", { eventModules: ["fire-event"] }],
|
|
7955
|
-
"testing-library/no-await-sync-queries": "error",
|
|
7956
|
-
"testing-library/no-container": "error",
|
|
7957
|
-
"testing-library/no-debugging-utils": "error",
|
|
7958
|
-
"testing-library/no-manual-cleanup": "error",
|
|
7959
|
-
"testing-library/no-promise-in-fire-event": "error",
|
|
7960
|
-
"testing-library/no-render-in-lifecycle": "error",
|
|
7961
|
-
"testing-library/no-unnecessary-act": "error",
|
|
7962
|
-
"testing-library/no-wait-for-multiple-assertions": "error",
|
|
7963
|
-
"testing-library/no-wait-for-side-effects": "error",
|
|
7964
|
-
"testing-library/no-wait-for-snapshot": "error",
|
|
7965
|
-
"testing-library/prefer-explicit-assert": "error",
|
|
7966
|
-
"testing-library/prefer-find-by": "error",
|
|
7967
|
-
"testing-library/prefer-presence-queries": "error",
|
|
7968
|
-
"testing-library/prefer-query-by-disappearance": "error",
|
|
7969
|
-
"testing-library/prefer-screen-queries": "error",
|
|
7970
|
-
"testing-library/render-result-naming-convention": "error",
|
|
7971
|
-
...restrictedDomImport !== void 0 ? { "no-restricted-imports": restrictedDomImport } : {}
|
|
7972
|
-
} : {},
|
|
7973
|
-
...stylistic !== false ? {
|
|
7974
|
-
"flawless/jsx-shorthand-boolean": "warn",
|
|
7975
|
-
"flawless/jsx-shorthand-fragment": "warn",
|
|
7976
|
-
"flawless/prefer-destructuring-assignment": "error",
|
|
7977
|
-
"flawless/react-namespace": "error",
|
|
7978
|
-
"one-var": "off",
|
|
7979
|
-
"react-jsx/no-useless-fragment": "warn",
|
|
7980
|
-
"react-naming-convention/context-name": "error",
|
|
7981
|
-
"react-naming-convention/ref-name": "error",
|
|
7982
|
-
"react/use-state": "error",
|
|
7983
|
-
"style/jsx-curly-brace-presence": ["error", {
|
|
7984
|
-
children: "never",
|
|
7985
|
-
propElementValues: "always",
|
|
7986
|
-
props: "never"
|
|
7987
|
-
}],
|
|
7988
|
-
"style/jsx-newline": "error",
|
|
7989
|
-
"style/jsx-self-closing-comp": "error",
|
|
7990
|
-
"unicorn/filename-case": ["error", {
|
|
7991
|
-
case: filenameCase,
|
|
7992
|
-
ignore: ["^[A-Z0-9]+.md$"],
|
|
7993
|
-
multipleFileExtensions: true
|
|
7994
|
-
}]
|
|
7995
|
-
} : {}
|
|
7996
|
-
};
|
|
7997
|
-
}
|
|
7998
|
-
//#endregion
|
|
7999
8040
|
//#region src/oxlint/configs/react.ts
|
|
8000
8041
|
/**
|
|
8001
8042
|
* React configs for oxlint: the shared react family plus oxlint's native
|
|
@@ -9179,6 +9220,10 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
9179
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;
|
|
9180
9221
|
const rootGlobs = mergeGlobs(GLOB_ROOT, customRootGlobs);
|
|
9181
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;
|
|
9182
9227
|
const nativeOnly = userJsPlugins === false;
|
|
9183
9228
|
const robloxScopedFiles = typeof options.roblox === "object" && options.roblox.files !== void 0 ? options.roblox.files.flat() : void 0;
|
|
9184
9229
|
const hasComplement = !enableRoblox || robloxScopedFiles !== void 0;
|
|
@@ -9289,15 +9334,12 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
9289
9334
|
...resolveSubOptions(options, "perfectionist"),
|
|
9290
9335
|
type: projectType
|
|
9291
9336
|
}), oxlintStylistic(stylisticOptions));
|
|
9292
|
-
if (enableReact !== false) {
|
|
9293
|
-
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
...reactOptions
|
|
9299
|
-
}));
|
|
9300
|
-
}
|
|
9337
|
+
if (enableReact !== false) configs.push(oxlintReact({
|
|
9338
|
+
roblox: enableRoblox,
|
|
9339
|
+
settings: options.settings,
|
|
9340
|
+
stylistic: stylisticOptions,
|
|
9341
|
+
...reactOptions
|
|
9342
|
+
}));
|
|
9301
9343
|
if (enableSpellCheck !== false) configs.push(oxlintSpelling({
|
|
9302
9344
|
...resolveSubOptions(options, "spellCheck"),
|
|
9303
9345
|
componentExts: componentExtensions,
|
|
@@ -9358,6 +9400,14 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
9358
9400
|
for (const jsPlugin of fragmentJsPlugins) jsPlugins.set(jsPluginKey(jsPlugin), jsPlugin);
|
|
9359
9401
|
if (config.settings) Object.assign(mergedSettings, config.settings);
|
|
9360
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
|
+
}
|
|
9361
9411
|
override.files = override.files.map(anchorOxlintGlob);
|
|
9362
9412
|
if (override.excludeFiles !== void 0) override.excludeFiles = override.excludeFiles.map(anchorOxlintGlob);
|
|
9363
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",
|