@dauphaihau/eslint-config 0.1.5 → 0.2.1

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +5 -4
  2. package/dist/index.js +259 -110
  3. package/package.json +20 -14
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ type Options = {
4
4
  typescript?: boolean;
5
5
  react?: boolean;
6
6
  vue?: boolean;
7
+ tailwind?: boolean;
7
8
  };
8
9
  /**
9
10
  * Default factory function for creating ESLint configurations.
@@ -11,10 +12,10 @@ type Options = {
11
12
  *
12
13
  * @example
13
14
  * ```ts
14
- * import dauphaihau from '@dauphaihau/eslint-config'
15
- * export default dauphaihau({ typescript: true })
15
+ * import eslintConfig from '@dauphaihau/eslint-config'
16
+ * export default eslintConfig({ typescript: true })
16
17
  * ```
17
18
  */
18
- declare function dauphaihau(options?: Options): Promise<Config[]>;
19
+ declare function eslintConfig(options?: Options): Promise<Config[]>;
19
20
 
20
- export { type Options, dauphaihau as default };
21
+ export { type Options, eslintConfig as default };
package/dist/index.js CHANGED
@@ -109,6 +109,27 @@ var ComponentFilesStrategy = class {
109
109
  return true;
110
110
  }
111
111
  };
112
+ var TailwindStrategy = class {
113
+ getName() {
114
+ return "tailwind";
115
+ }
116
+ getFilePatterns(options) {
117
+ const patterns = ["**/*.html"];
118
+ if (options.react) {
119
+ patterns.push(options.typescript ? "**/*.{jsx,tsx}" : "**/*.jsx");
120
+ }
121
+ if (options.vue) {
122
+ patterns.push("**/*.vue");
123
+ }
124
+ if (!options.react && !options.vue) {
125
+ patterns.push(options.typescript ? "**/*.{jsx,tsx}" : "**/*.jsx");
126
+ }
127
+ return patterns;
128
+ }
129
+ shouldApply(options) {
130
+ return options.tailwind === true;
131
+ }
132
+ };
112
133
 
113
134
  // src/strategies/strategy-manager.ts
114
135
  var StrategyManager = class {
@@ -122,6 +143,7 @@ var StrategyManager = class {
122
143
  this.register(new AllFilesStrategy());
123
144
  this.register(new SourceFilesStrategy());
124
145
  this.register(new ComponentFilesStrategy());
146
+ this.register(new TailwindStrategy());
125
147
  }
126
148
  /**
127
149
  * Register a new strategy.
@@ -195,6 +217,12 @@ var StrategyManager = class {
195
217
  getTestFiles(options) {
196
218
  return this.getFilePatterns("test", options);
197
219
  }
220
+ /**
221
+ * Convenience method: Get Tailwind CSS file patterns.
222
+ */
223
+ getTailwindFiles(options) {
224
+ return this.getFilePatterns("tailwind", options);
225
+ }
198
226
  };
199
227
  var strategyManager = new StrategyManager();
200
228
 
@@ -216,7 +244,7 @@ function baseConfig(options = {}) {
216
244
  plugins: { "@stylistic": stylistic },
217
245
  rules: {
218
246
  // Spacing
219
- "@stylistic/func-call-spacing": "error",
247
+ "@stylistic/function-call-spacing": "error",
220
248
  "@stylistic/space-before-function-paren": ["error", {
221
249
  anonymous: "always",
222
250
  named: "never",
@@ -264,7 +292,14 @@ function baseConfig(options = {}) {
264
292
  // Operators
265
293
  "@stylistic/multiline-ternary": ["error", "always-multiline"],
266
294
  "@stylistic/no-mixed-operators": "error",
267
- "@stylistic/operator-linebreak": ["error", "after"],
295
+ "@stylistic/operator-linebreak": ["error", "after", {
296
+ overrides: {
297
+ "?": "before",
298
+ "|": "before",
299
+ ":": "before",
300
+ "||": "before"
301
+ }
302
+ }],
268
303
  "@stylistic/dot-location": ["error", "property"],
269
304
  // Disallow
270
305
  "@stylistic/no-multiple-empty-lines": ["error", { max: 2, maxEOF: 0 }],
@@ -423,6 +458,17 @@ function typescriptConfig(options = {}) {
423
458
  }
424
459
 
425
460
  // src/configs/react.ts
461
+ import fs from "fs";
462
+ function getReactVersion() {
463
+ try {
464
+ const pkg = JSON.parse(fs.readFileSync("package.json", "utf-8"));
465
+ const dep = pkg.dependencies?.react || pkg.devDependencies?.react || pkg.peerDependencies?.react;
466
+ const match = dep?.match(/\d+/);
467
+ if (match) return `${match[0]}.0`;
468
+ } catch {
469
+ }
470
+ return "18.0";
471
+ }
426
472
  async function reactConfig(options = {}) {
427
473
  const reactFiles = strategyManager.getReactFiles(options);
428
474
  if (reactFiles.length === 0) {
@@ -461,8 +507,7 @@ async function reactConfig(options = {}) {
461
507
  },
462
508
  settings: {
463
509
  react: {
464
- version: "detect"
465
- // Automatically detect React version
510
+ version: getReactVersion()
466
511
  }
467
512
  },
468
513
  rules: {
@@ -505,8 +550,154 @@ async function reactConfig(options = {}) {
505
550
  ];
506
551
  }
507
552
 
553
+ // src/configs/tailwind.ts
554
+ async function tailwindConfig(options = {}) {
555
+ const tailwindFiles = strategyManager.getTailwindFiles(options);
556
+ if (tailwindFiles.length === 0) {
557
+ return [];
558
+ }
559
+ const { default: tailwind } = await import("eslint-plugin-tailwindcss");
560
+ return [
561
+ {
562
+ name: "dauphaihau/tailwind",
563
+ files: tailwindFiles,
564
+ plugins: { tailwindcss: tailwind },
565
+ settings: {
566
+ tailwindcss: {
567
+ // Common utility function callees to analyze for class names
568
+ callees: ["classnames", "clsx", "ctl", "cva", "cx", "cn"],
569
+ // Support tagged template literals: tw`bg-blue-500`
570
+ tags: ["tw"]
571
+ }
572
+ },
573
+ rules: {
574
+ "tailwindcss/classnames-order": "warn",
575
+ "tailwindcss/enforces-negative-arbitrary-values": "warn",
576
+ "tailwindcss/enforces-shorthand": "warn",
577
+ "tailwindcss/migration-from-tailwind-2": "off",
578
+ // projects target v3+
579
+ "tailwindcss/no-arbitrary-value": "off",
580
+ // too restrictive globally; colors enforced below via no-restricted-syntax
581
+ "tailwindcss/no-contradicting-classname": "error",
582
+ "tailwindcss/no-custom-classname": "warn",
583
+ "tailwindcss/no-unnecessary-arbitrary-value": "warn",
584
+ // Partial enforcement of no-arbitrary-value scoped to color utilities.
585
+ // Arbitrary color values (bg-[#fff], text-[rgba(...)]) bypass the design
586
+ // system and should use config tokens instead. Covers: bg, text, border,
587
+ // ring, fill, stroke, from, via, to, accent, caret, decoration, outline,
588
+ // placeholder, shadow, divide — for hex, rgb(), rgba(), hsl(), hsla(), oklch().
589
+ "no-restricted-syntax": [
590
+ "warn",
591
+ {
592
+ selector: "Literal[value=/(?:^|\\s)(?:bg|text|border|ring|fill|stroke|from|via|to|accent|caret|decoration|outline|placeholder|shadow|divide)-\\[(?:#[0-9a-fA-F]|rgba?\\(|hsla?\\(|oklch\\()/]",
593
+ message: "Avoid arbitrary color values (e.g. bg-[#fff]). Use a design system color token from the Tailwind config instead."
594
+ }
595
+ ]
596
+ }
597
+ }
598
+ ];
599
+ }
600
+
508
601
  // src/configs/naming.ts
509
602
  import ts2 from "typescript-eslint";
603
+ var identifierQualityRules = {
604
+ // Invalid example: const n = 'Name User'
605
+ "id-length": [
606
+ "warn",
607
+ {
608
+ min: 2,
609
+ exceptions: ["i", "j", "x", "y"]
610
+ }
611
+ ],
612
+ // Discourage vague placeholder names.
613
+ // Prefer domain-specific names such as users, payload, responseBody, or config.
614
+ "id-denylist": ["warn", "foo", "bar", "baz", "tmp", "arr", "obj", "data"]
615
+ };
616
+ var variableNamingSelectors = [
617
+ // Valid examples: userName, fetchUsers, _internalValue
618
+ {
619
+ selector: ["variable", "function"],
620
+ format: ["camelCase"],
621
+ leadingUnderscore: "allow"
622
+ // allows _privateVar
623
+ },
624
+ {
625
+ // Enforce UPPER_CASE for exported constants.
626
+ // Valid examples: API_BASE_URL, MAX_RETRY_COUNT, DEFAULT_TIMEOUT_MS
627
+ selector: "variable",
628
+ modifiers: ["const", "exported"],
629
+ format: ["UPPER_CASE"],
630
+ filter: {
631
+ regex: "^[A-Z0-9_]+$",
632
+ match: true
633
+ }
634
+ },
635
+ // ---------- Boolean naming ----------
636
+ {
637
+ selector: "variable",
638
+ types: ["boolean"],
639
+ format: ["PascalCase", "camelCase"],
640
+ prefix: ["is", "has", "should", "can", "did", "will"],
641
+ filter: { regex: "^(is|has|should|can|did|will)[A-Z]", match: true }
642
+ }
643
+ ];
644
+ var baseNamingSelectors = [
645
+ ...variableNamingSelectors,
646
+ // ---------- Interfaces ----------
647
+ {
648
+ selector: "interface",
649
+ format: ["PascalCase"],
650
+ custom: { regex: "^I[A-Z]", match: false }
651
+ // forbid I prefix
652
+ },
653
+ // ---------- Type Aliases ----------
654
+ {
655
+ selector: "typeAlias",
656
+ format: ["PascalCase"]
657
+ // User, UserPayload
658
+ },
659
+ // ---------- Classes ----------
660
+ {
661
+ selector: "class",
662
+ format: ["PascalCase"]
663
+ },
664
+ // ---------- Enums ----------
665
+ {
666
+ selector: "enum",
667
+ format: ["PascalCase"]
668
+ },
669
+ {
670
+ selector: "enumMember",
671
+ format: ["UPPER_CASE"]
672
+ // STATUS.OK
673
+ },
674
+ // ---------- Parameters ----------
675
+ {
676
+ selector: "parameter",
677
+ format: ["camelCase"],
678
+ leadingUnderscore: "allow"
679
+ // allow _unused
680
+ },
681
+ // ---------- Properties (object keys) ----------
682
+ {
683
+ selector: "objectLiteralProperty",
684
+ format: null
685
+ // allow anything -> API response, snake_case keys allowed
686
+ },
687
+ {
688
+ // internal domain types
689
+ selector: "typeProperty",
690
+ format: ["camelCase"]
691
+ },
692
+ // ---------- Private members ----------
693
+ {
694
+ selector: "classProperty",
695
+ modifiers: ["private"],
696
+ format: ["camelCase"],
697
+ leadingUnderscore: "allow"
698
+ // _value
699
+ }
700
+ ];
510
701
  function namingConfig(options = {}) {
511
702
  const { typescript = false } = options;
512
703
  if (!typescript) {
@@ -527,93 +718,11 @@ function namingConfig(options = {}) {
527
718
  "@typescript-eslint": ts2.plugin
528
719
  },
529
720
  rules: {
530
- // Naming conventions
531
- "@typescript-eslint/naming-convention": [
532
- "error",
533
- // ---------- Variable, Function ----------
534
- {
535
- selector: ["variable", "function"],
536
- format: ["camelCase"],
537
- leadingUnderscore: "allow"
538
- // allows _privateVar
539
- },
540
- {
541
- selector: "variable",
542
- // constants (like env, config)
543
- modifiers: ["const"],
544
- format: ["UPPER_CASE"],
545
- filter: {
546
- regex: "^[A-Z0-9_]+$",
547
- match: true
548
- }
549
- },
550
- // ---------- Interfaces ----------
551
- {
552
- selector: "interface",
553
- format: ["PascalCase"],
554
- custom: { regex: "^I[A-Z]", match: false }
555
- // forbid I prefix
556
- },
557
- // ---------- Type Aliases ----------
558
- {
559
- selector: "typeAlias",
560
- format: ["PascalCase"]
561
- // User, UserPayload
562
- },
563
- // ---------- Classes ----------
564
- {
565
- selector: "class",
566
- format: ["PascalCase"]
567
- },
568
- // ---------- Enums ----------
569
- {
570
- selector: "enum",
571
- format: ["PascalCase"]
572
- },
573
- {
574
- selector: "enumMember",
575
- format: ["UPPER_CASE"]
576
- // STATUS.OK
577
- },
578
- // ---------- Parameters ----------
579
- {
580
- selector: "parameter",
581
- format: ["camelCase"],
582
- leadingUnderscore: "allow"
583
- // allow _unused
584
- },
585
- // ---------- Properties (object keys) ----------
586
- {
587
- selector: "objectLiteralProperty",
588
- format: null
589
- // allow anything -> API response, snake_case keys allowed
590
- },
591
- {
592
- // internal domain types
593
- selector: "typeProperty",
594
- format: ["camelCase"]
595
- },
596
- // ---------- Private members ----------
597
- {
598
- selector: "classProperty",
599
- modifiers: ["private"],
600
- format: ["camelCase"],
601
- leadingUnderscore: "allow"
602
- // _value
603
- },
604
- // ---------- Boolean naming ----------
605
- {
606
- selector: "variable",
607
- types: ["boolean"],
608
- format: ["PascalCase", "camelCase"],
609
- prefix: ["is", "has", "should", "can", "did", "will"],
610
- filter: { regex: "^(is|has|should|can|did|will)[A-Z]", match: true }
611
- }
612
- ]
721
+ ...identifierQualityRules,
722
+ "@typescript-eslint/naming-convention": ["error", ...baseNamingSelectors]
613
723
  }
614
724
  },
615
- // TSX/JSX specific: Allow PascalCase for functions (React components)
616
- // Helper functions will still be camelCase due to the general rule above
725
+ // TSX/JSX specific: Allow PascalCase for functions (React components) and component variables
617
726
  {
618
727
  name: "dauphaihau/naming-tsx",
619
728
  files: componentFiles,
@@ -624,23 +733,23 @@ function namingConfig(options = {}) {
624
733
  "@typescript-eslint": ts2.plugin
625
734
  },
626
735
  rules: {
736
+ ...identifierQualityRules,
627
737
  "@typescript-eslint/naming-convention": [
628
738
  "error",
739
+ // TSX overrides come first — same-specificity selectors use first-match wins
629
740
  {
630
741
  selector: "function",
631
742
  format: ["PascalCase", "camelCase"]
632
- // Allow both for components and helpers
633
743
  },
634
744
  {
635
745
  selector: "variable",
636
746
  format: ["camelCase", "PascalCase"],
637
- // Allow PascalCase for component variables
638
747
  filter: {
639
- // Only allow PascalCase if it's likely a component (starts with uppercase)
640
748
  regex: "^[A-Z]",
641
749
  match: true
642
750
  }
643
- }
751
+ },
752
+ ...baseNamingSelectors
644
753
  ]
645
754
  }
646
755
  }
@@ -648,7 +757,7 @@ function namingConfig(options = {}) {
648
757
  }
649
758
 
650
759
  // src/configs/file-names.ts
651
- import filenamesSimple from "eslint-plugin-filenames-simple";
760
+ import checkFile from "eslint-plugin-check-file";
652
761
  function fileNamesConfig(options = {}) {
653
762
  const allFiles = strategyManager.getSourceFiles(options);
654
763
  const tsxFiles = strategyManager.getComponentFiles(options);
@@ -657,15 +766,15 @@ function fileNamesConfig(options = {}) {
657
766
  name: "dauphaihau/file-names",
658
767
  files: allFiles,
659
768
  plugins: {
660
- "filenames-simple": filenamesSimple
769
+ "check-file": checkFile
661
770
  },
662
771
  rules: {
663
772
  // Enforce kebab-case for regular files
664
- "filenames-simple/naming-convention": [
773
+ "check-file/filename-naming-convention": [
665
774
  "error",
666
- { rule: "kebab-case" }
667
- ],
668
- "filenames-simple/extension": "error"
775
+ { "**/*": "KEBAB_CASE" },
776
+ { ignoreMiddleExtensions: true }
777
+ ]
669
778
  }
670
779
  },
671
780
  // TSX/JSX files: Allow PascalCase for React components (e.g., MyComponent.tsx)
@@ -673,14 +782,14 @@ function fileNamesConfig(options = {}) {
673
782
  name: "dauphaihau/file-names-tsx",
674
783
  files: tsxFiles,
675
784
  plugins: {
676
- "filenames-simple": filenamesSimple
785
+ "check-file": checkFile
677
786
  },
678
787
  rules: {
679
- "filenames-simple/naming-convention": [
788
+ "check-file/filename-naming-convention": [
680
789
  "error",
681
- { rule: "PascalCase" }
682
- ],
683
- "filenames-simple/extension": "error"
790
+ { "**/*": "PASCAL_CASE" },
791
+ { ignoreMiddleExtensions: true }
792
+ ]
684
793
  }
685
794
  }
686
795
  ];
@@ -698,6 +807,7 @@ var ESLintConfigBuilder = class {
698
807
  this.fileNamesAdded = false;
699
808
  this.typescriptAdded = false;
700
809
  this.reactAdded = false;
810
+ this.tailwindAdded = false;
701
811
  }
702
812
  /**
703
813
  * Set options that will be used for all subsequent config additions.
@@ -777,6 +887,21 @@ var ESLintConfigBuilder = class {
777
887
  this.reactAdded = true;
778
888
  return this;
779
889
  }
890
+ /**
891
+ * Add Tailwind CSS-specific rules and plugins.
892
+ * Requires tailwind option to be set to true.
893
+ */
894
+ withTailwind(options) {
895
+ const mergedOptions = { ...this.options, ...options };
896
+ if (!mergedOptions.tailwind) {
897
+ console.warn(
898
+ "ESLintConfigBuilder: Tailwind config added but tailwind option is not set. Consider calling setOptions({ tailwind: true }) first."
899
+ );
900
+ }
901
+ this.pendingConfigs.push(tailwindConfig(mergedOptions));
902
+ this.tailwindAdded = true;
903
+ return this;
904
+ }
780
905
  /**
781
906
  * Add a custom config object directly.
782
907
  * Useful for adding project-specific rules or third-party configs.
@@ -806,6 +931,9 @@ var ESLintConfigBuilder = class {
806
931
  if (mergedOptions.react) {
807
932
  this.withReact(mergedOptions);
808
933
  }
934
+ if (mergedOptions.tailwind) {
935
+ this.withTailwind(mergedOptions);
936
+ }
809
937
  return this;
810
938
  }
811
939
  /**
@@ -829,6 +957,7 @@ var ESLintConfigBuilder = class {
829
957
  this.fileNamesAdded = false;
830
958
  this.typescriptAdded = false;
831
959
  this.reactAdded = false;
960
+ this.tailwindAdded = false;
832
961
  return this;
833
962
  }
834
963
  /**
@@ -858,16 +987,19 @@ var ESLintConfigBuilder = class {
858
987
  hasReact() {
859
988
  return this.reactAdded;
860
989
  }
990
+ hasTailwind() {
991
+ return this.tailwindAdded;
992
+ }
861
993
  };
862
994
 
863
995
  // src/index.ts
864
- import fs from "fs";
865
- var hasTsConfig = fs.existsSync("tsconfig.json") || fs.existsSync("tsconfig.base.json");
996
+ import fs2 from "fs";
997
+ var hasTsConfig = fs2.existsSync("tsconfig.json") || fs2.existsSync("tsconfig.base.json");
866
998
  var hasReact = () => {
867
999
  try {
868
1000
  const packageJsonPath = "package.json";
869
- if (fs.existsSync(packageJsonPath)) {
870
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
1001
+ if (fs2.existsSync(packageJsonPath)) {
1002
+ const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
871
1003
  const deps = {
872
1004
  ...packageJson.dependencies,
873
1005
  ...packageJson.devDependencies,
@@ -879,14 +1011,31 @@ var hasReact = () => {
879
1011
  }
880
1012
  return false;
881
1013
  };
882
- function dauphaihau(options = {}) {
1014
+ var hasTailwind = () => {
1015
+ try {
1016
+ const packageJsonPath = "package.json";
1017
+ if (fs2.existsSync(packageJsonPath)) {
1018
+ const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
1019
+ const deps = {
1020
+ ...packageJson.dependencies,
1021
+ ...packageJson.devDependencies,
1022
+ ...packageJson.peerDependencies
1023
+ };
1024
+ if ("tailwindcss" in deps) return true;
1025
+ }
1026
+ } catch {
1027
+ }
1028
+ return fs2.existsSync("tailwind.config.js") || fs2.existsSync("tailwind.config.ts") || fs2.existsSync("tailwind.config.mjs") || fs2.existsSync("tailwind.config.cjs");
1029
+ };
1030
+ function eslintConfig(options = {}) {
883
1031
  const finalOptions = {
884
1032
  typescript: options.typescript ?? hasTsConfig,
885
1033
  react: options.react ?? hasReact(),
1034
+ tailwind: options.tailwind ?? hasTailwind(),
886
1035
  ...options
887
1036
  };
888
1037
  return new ESLintConfigBuilder().setOptions(finalOptions).withAll().build();
889
1038
  }
890
1039
  export {
891
- dauphaihau as default
1040
+ eslintConfig as default
892
1041
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dauphaihau/eslint-config",
3
- "version": "0.1.5",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,14 +12,15 @@
12
12
  "README.md"
13
13
  ],
14
14
  "dependencies": {
15
- "@eslint/js": "^9.0.0",
16
- "@stylistic/eslint-plugin": "^1.6.0",
17
- "eslint-plugin-filenames-simple": "^0.9.0",
15
+ "@eslint/js": "^10.0.0",
16
+ "@stylistic/eslint-plugin": "^5.9.0",
17
+ "eslint-plugin-check-file": "^3.3.1",
18
18
  "globals": "^16.5.0",
19
- "typescript-eslint": "^8.0.0"
19
+ "typescript-eslint": "^8.56.1"
20
20
  },
21
21
  "peerDependencies": {
22
- "eslint": "^9.0.0"
22
+ "eslint": "^9.0.0 || ^10.0.0",
23
+ "eslint-plugin-tailwindcss": ">=3.0.0"
23
24
  },
24
25
  "peerDependenciesMeta": {
25
26
  "eslint-plugin-react": {
@@ -30,25 +31,30 @@
30
31
  },
31
32
  "eslint-plugin-react-refresh": {
32
33
  "optional": true
34
+ },
35
+ "eslint-plugin-tailwindcss": {
36
+ "optional": true
33
37
  }
34
38
  },
35
39
  "devDependencies": {
36
40
  "@types/node": "^22.0.0",
37
- "eslint": "^9.0.0",
38
- "eslint-plugin-react": "^7.33.0",
39
- "eslint-plugin-react-hooks": "^4.6.0",
40
- "eslint-plugin-react-refresh": "^0.4.5",
41
+ "eslint": "^10.0.0",
42
+ "eslint-plugin-react": "^7.37.5",
43
+ "eslint-plugin-react-hooks": "^7.0.1",
44
+ "eslint-plugin-react-refresh": "^0.5.2",
45
+ "eslint-plugin-tailwindcss": "^3.18.2",
41
46
  "jiti": "^2.0.0",
42
47
  "tsup": "^8.0.0",
43
48
  "typescript": "^5.4.0"
44
49
  },
45
50
  "scripts": {
46
- "build": "pnpm exec tsup src/index.ts --dts --format esm --external @eslint/js --external @stylistic/eslint-plugin --external typescript-eslint --external eslint-plugin-filenames-simple --external eslint-plugin-react --external eslint-plugin-react-hooks --external eslint-plugin-react-refresh",
51
+ "build": "pnpm exec tsup src/index.ts --dts --format esm --external @eslint/js --external @stylistic/eslint-plugin --external typescript-eslint --external eslint-plugin-check-file --external eslint-plugin-react --external eslint-plugin-react-hooks --external eslint-plugin-react-refresh --external eslint-plugin-tailwindcss",
47
52
  "lint": "eslint .",
48
53
  "lint:fix": "eslint . --fix",
49
54
  "typecheck": "tsc --noEmit",
50
- "release:patch": "pnpm build && pnpm version patch && pnpm publish --no-git-checks",
51
- "release:minor": "pnpm build && pnpm version minor && pnpm publish --no-git-checks",
52
- "release:major": "pnpm build && pnpm version major && pnpm publish --no-git-checks"
55
+ "version:patch": "pnpm build && pnpm version patch",
56
+ "version:minor": "pnpm build && pnpm version minor",
57
+ "version:major": "pnpm build && pnpm version major",
58
+ "push": "git push --follow-tags"
53
59
  }
54
60
  }