@sablier/devkit 1.6.1 → 1.8.0

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/biome/base.jsonc CHANGED
@@ -6,7 +6,7 @@
6
6
  // which files to lint and format. For example:
7
7
  //
8
8
  // {
9
- // "extends": ["@sablier/devkit/biome"],
9
+ // "extends": ["@sablier/devkit/biome/base"],
10
10
  // "files": {
11
11
  // "includes": ["**/*.{css,js,jsx,json,ts,tsx}", "!node_modules"]
12
12
  // }
@@ -38,23 +38,41 @@
38
38
  "linter": {
39
39
  "enabled": true,
40
40
  "rules": {
41
+ "recommended": true,
42
+ "complexity": {
43
+ "noImplicitCoercions": "error", // forbid `!!foo`, allow `Boolean(foo)`
44
+ "noVoid": "off" // void is useful in some cases e.g. `useEffect` callbacks
45
+ },
41
46
  "correctness": {
42
- "noUnusedImports": "off",
43
- "noUnusedVariables": "error",
44
- "useExhaustiveDependencies": "error"
47
+ "noUnusedImports": "off", // allow unused imports during development
48
+ "noUnusedVariables": "error"
45
49
  },
46
50
  "nursery": {
47
- "noFloatingPromises": "error"
51
+ "noFloatingPromises": "error", // floating promises can lead to bugs
52
+ "noUselessUndefined": "off" // we want explicit undefined return values
53
+ },
54
+ "performance": {
55
+ "noBarrelFile": "off", // barrel exports lead to cleaner imports
56
+ "noDelete": "off", // disabled due to https://github.com/biomejs/biome/issues/4093
57
+ "noNamespaceImport": "off" // namespaces are cool
48
58
  },
49
- "recommended": true,
50
59
  "style": {
60
+ "noNamespace": "off", // namespaces are cool
61
+ "useDefaultSwitchClause": "off", // already handled by TypeScript
62
+ "useFilenamingConvention": {
63
+ "level": "error",
64
+ "options": {
65
+ "filenameCases": ["kebab-case", "camelCase", "PascalCase", "export"]
66
+ }
67
+ },
68
+ // disabled due to https://github.com/biomejs/biome/issues/8450
51
69
  "useImportType": {
52
70
  "level": "warn",
53
71
  "options": {
54
72
  "style": "separatedType"
55
73
  }
56
74
  },
57
- "useTemplate": "off"
75
+ "useTemplate": "off" // allow string concatenation using `+`
58
76
  }
59
77
  }
60
78
  },
@@ -70,6 +88,11 @@
70
88
  "includes": ["**/*.{json,json5,jsonc}"]
71
89
  }
72
90
  ],
91
+ "json": {
92
+ "formatter": {
93
+ "lineWidth": 100
94
+ }
95
+ },
73
96
  "vcs": {
74
97
  "clientKind": "git",
75
98
  "enabled": true,
package/biome/ui.jsonc CHANGED
@@ -1,13 +1,13 @@
1
1
  // Sablier Devkit UI configuration for Biome v2
2
2
  //
3
- // Standalone configuration with base rules plus UI-specific rules for
4
- // accessibility, Tailwind CSS class sorting, and CSS modules support.
3
+ // Extends base configuration with UI-specific rules for accessibility,
4
+ // Tailwind CSS class sorting, and CSS modules support.
5
5
  //
6
- // IMPORTANT: Consumers must add their own `files.includes` patterns to specify
7
- // which files to lint and format. For example:
6
+ // IMPORTANT: Consumers must extend BOTH configs and add their own
7
+ // `files.includes` patterns. For example:
8
8
  //
9
9
  // {
10
- // "extends": ["@sablier/devkit/biome/ui"],
10
+ // "extends": ["@sablier/devkit/biome/base", "@sablier/devkit/biome/ui"],
11
11
  // "files": {
12
12
  // "includes": ["**/*.{css,js,jsx,json,ts,tsx}", "!node_modules"]
13
13
  // }
@@ -18,40 +18,28 @@
18
18
  "enabled": true,
19
19
  "actions": {
20
20
  "source": {
21
- "organizeImports": "on",
22
- "useSortedKeys": "on"
21
+ "useSortedAttributes": "on"
23
22
  }
24
23
  }
25
24
  },
26
25
  "css": {
26
+ "formatter": {
27
+ "lineWidth": 100
28
+ },
27
29
  "parser": {
28
30
  "cssModules": true,
29
31
  "tailwindDirectives": true
30
32
  }
31
33
  },
32
- "files": {
33
- "maxSize": 5242880 // 5MB
34
- },
35
- "formatter": {
36
- "enabled": true,
37
- "formatWithErrors": true,
38
- "indentStyle": "space",
39
- "lineWidth": 100
40
- },
41
34
  "linter": {
42
- "enabled": true,
43
35
  "rules": {
44
36
  "a11y": {
45
37
  "noSvgWithoutTitle": "off",
46
38
  "useKeyWithClickEvents": "off"
47
39
  },
48
- "correctness": {
49
- "noUnusedImports": "off",
50
- "noUnusedVariables": "error",
51
- "useExhaustiveDependencies": "error"
52
- },
53
40
  "nursery": {
54
- "noFloatingPromises": "error",
41
+ // Sort Tailwind CSS classes alphabetically
42
+ // See https://github.com/biomejs/biome/issues/1274#issuecomment-3490774696
55
43
  "useSortedClasses": {
56
44
  "fix": "safe",
57
45
  "level": "warn",
@@ -60,34 +48,7 @@
60
48
  "functions": ["clsx", "cva", "cn", "tv", "tw", "tw.*"]
61
49
  }
62
50
  }
63
- },
64
- "recommended": true,
65
- "style": {
66
- "useImportType": {
67
- "level": "warn",
68
- "options": {
69
- "style": "separatedType"
70
- }
71
- },
72
- "useTemplate": "off"
73
51
  }
74
52
  }
75
- },
76
- "overrides": [
77
- {
78
- "assist": {
79
- "actions": {
80
- "source": {
81
- "useSortedKeys": "off"
82
- }
83
- }
84
- },
85
- "includes": ["**/*.{json,json5,jsonc}"]
86
- }
87
- ],
88
- "vcs": {
89
- "clientKind": "git",
90
- "enabled": true,
91
- "useIgnoreFile": true
92
53
  }
93
54
  }
package/just/csv.just ADDED
@@ -0,0 +1,102 @@
1
+ import "./settings.just"
2
+
3
+ # ---------------------------------------------------------------------------- #
4
+ # SCRIPTS #
5
+ # ---------------------------------------------------------------------------- #
6
+
7
+ # Check CSV/TSV files using qsv: https://github.com/dathere/qsv
8
+ [group("checks"), script("python3")]
9
+ _csv-check globs="data/*/*.csv" ext="CSV" schema="" ignore="*.csv.invalid|*.csv.valid|*validation-errors.csv":
10
+ import fnmatch
11
+ import glob as globmod
12
+ import subprocess
13
+ import sys
14
+
15
+ # Check qsv is available
16
+ if subprocess.run(["which", "qsv"], capture_output=True).returncode != 0:
17
+ print("✗ qsv CLI not found")
18
+ print("Install it: https://github.com/dathere/qsv")
19
+ sys.exit(1)
20
+
21
+ ext = "{{ ext }}" or "CSV"
22
+ ignore_patterns = "{{ ignore }}".split("|") if "{{ ignore }}" else []
23
+ schema = "{{ schema }}" or None
24
+ globs = "{{ globs }}"
25
+
26
+ print(f"Validating {ext} files...")
27
+ files = globmod.glob(globs)
28
+
29
+ # Filter ignored files
30
+ files = [f for f in files if not any(fnmatch.fnmatch(f, p) for p in ignore_patterns)]
31
+
32
+ if not files:
33
+ print(f"ℹ️ No {ext} files found to validate")
34
+ sys.exit(0)
35
+
36
+ for file in files:
37
+ cmd = ["qsv", "validate", file]
38
+ if schema:
39
+ cmd.append(schema)
40
+ result = subprocess.run(cmd, capture_output=True)
41
+ if result.returncode != 0:
42
+ print(f"❌ Validation failed for: {file}")
43
+ subprocess.run(["just", "_csv-show-errors", file, ext])
44
+ sys.exit(1)
45
+
46
+ print(f"✅ All {ext} files are valid")
47
+
48
+ # Show validation errors for a CSV/TSV file
49
+ [group("checks"), script("python3")]
50
+ _csv-show-errors file ext="CSV":
51
+ import os
52
+ import subprocess
53
+ import sys
54
+
55
+ file = "{{ file }}"
56
+ error_file = f"{file}.validation-errors.tsv"
57
+
58
+ if not os.path.exists(error_file):
59
+ print(f"Error file not found: {error_file}")
60
+ sys.exit(0)
61
+
62
+ # Count errors (qsv auto-detects .tsv delimiter)
63
+ result = subprocess.run(["qsv", "count", error_file], capture_output=True, text=True)
64
+ try:
65
+ total = int(result.stdout.strip()) if result.returncode == 0 and result.stdout.strip() else 0
66
+ except ValueError:
67
+ total = 0
68
+
69
+ print()
70
+ if total > 0:
71
+ print(f"First 20 validation errors ({total} total):")
72
+ else:
73
+ print("Validation errors:")
74
+ print()
75
+
76
+ # Try qsv table for nice formatting, fall back to reading file directly
77
+ slice_result = subprocess.run(
78
+ ["qsv", "slice", "--start", "0", "--len", "21", error_file],
79
+ capture_output=True, text=True
80
+ )
81
+ if slice_result.returncode == 0:
82
+ table_result = subprocess.run(
83
+ ["qsv", "table"],
84
+ input=slice_result.stdout,
85
+ capture_output=True, text=True
86
+ )
87
+ if table_result.returncode == 0:
88
+ print(table_result.stdout)
89
+ else:
90
+ print(slice_result.stdout)
91
+ else:
92
+ with open(error_file) as f:
93
+ for i, line in enumerate(f):
94
+ if i >= 21:
95
+ break
96
+ print(line, end="")
97
+
98
+ if total > 20:
99
+ print()
100
+ print(f"... and {total - 20} more errors")
101
+ print()
102
+ print(f"Full details: {error_file}")
package/just/tsv.just CHANGED
@@ -1,80 +1,15 @@
1
- import "./settings.just"
1
+ import "./csv.just"
2
2
 
3
3
  # ---------------------------------------------------------------------------- #
4
- # SCRIPTS #
4
+ # TSV WRAPPERS #
5
5
  # ---------------------------------------------------------------------------- #
6
6
 
7
7
  # Check TSV files using qsv: https://github.com/dathere/qsv
8
- [group("checks"), script("bash")]
9
- _tsv-check globs="data/*/*.tsv" schema="" ignore="*.tsv.invalid|*.tsv.valid|*validation-errors.tsv":
10
- if ! command -v qsv >/dev/null 2>&1; then
11
- echo "✗ qsv CLI not found"
12
- echo "Install it: https://github.com/dathere/qsv"
13
- exit 1
14
- fi
15
-
16
- echo "Validating TSV files..."
17
- found=0
18
- for file in {{ globs }}; do
19
- # Skip validation artifact files
20
- case "$file" in
21
- {{ ignore }})
22
- continue
23
- ;;
24
- esac
25
-
26
- # Skip if no files match the pattern
27
- [ -e "$file" ] || continue
28
-
29
- found=$((found + 1))
30
- schema_arg="{{ schema }}"
31
- if ! qsv validate "$file" ${schema_arg:+"$schema_arg"} > /dev/null 2>&1; then
32
- echo "❌ Validation failed for: $file"
33
- just _tsv-show-errors "$file"
34
- exit 1
35
- fi
36
- done
37
-
38
- if [ "$found" -eq 0 ]; then
39
- echo "ℹ️ No TSV files found to validate"
40
- else
41
- echo "✅ All TSV files are valid"
42
- fi
8
+ [group("checks")]
9
+ _tsv-check globs="data/*/*.tsv" ext="TSV" schema="" ignore="*.tsv.invalid|*.tsv.valid|*validation-errors.tsv":
10
+ @just _csv-check "{{ globs }}" "{{ ext }}" "{{ schema }}" "{{ ignore }}"
43
11
 
44
12
  # Show validation errors for a TSV file
45
- [group("checks"), script("bash")]
13
+ [group("checks")]
46
14
  _tsv-show-errors file:
47
- error_file="{{ file }}.validation-errors.tsv"
48
-
49
- if [ ! -f "$error_file" ]; then
50
- echo "Error file not found: $error_file"
51
- exit 0
52
- fi
53
-
54
- # Try to count total errors (subtract 1 for header row)
55
- total_errors=$(qsv count "$error_file" 2>/dev/null || echo "0")
56
- if [ "$total_errors" != "0" ]; then
57
- total_errors=$((total_errors - 1))
58
- fi
59
-
60
- echo ""
61
- if [ "$total_errors" != "0" ] && [ "$total_errors" -gt 0 ]; then
62
- echo "First 20 validation errors (${total_errors} total):"
63
- else
64
- echo "Validation errors:"
65
- fi
66
- echo ""
67
-
68
- # Try to use qsv table for nice formatting, fall back to basic display
69
- if qsv slice --start 0 --len 21 "$error_file" 2>/dev/null | qsv table 2>/dev/null; then
70
- : # Success, output already shown
71
- else
72
- head -n 21 "$error_file"
73
- fi
74
-
75
- if [ "$total_errors" != "0" ] && [ "$total_errors" -gt 20 ]; then
76
- echo ""
77
- echo "... and $((total_errors - 20)) more errors"
78
- fi
79
- echo ""
80
- echo "Full details: $error_file"
15
+ @just _csv-show-errors "{{ file }}" "TSV"
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Configuration files and reusable scripts for Sablier repositories",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
- "version": "1.6.1",
6
+ "version": "1.8.0",
7
7
  "author": {
8
8
  "name": "Sablier Labs Ltd",
9
9
  "url": "https://sablier.com"
@@ -26,6 +26,7 @@
26
26
  },
27
27
  "exports": {
28
28
  "./biome": "./biome/base.jsonc",
29
+ "./biome/base": "./biome/base.jsonc",
29
30
  "./biome/ui": "./biome/ui.jsonc",
30
31
  "./prettier": "./.prettierrc.json",
31
32
  "./tsconfig/base": "./tsconfig/base.json",
package/vitest/base.js CHANGED
@@ -11,7 +11,7 @@ import { defineConfig, mergeConfig } from "vitest/config";
11
11
  * @param {DevkitVitestOptions} [options]
12
12
  */
13
13
  export function defineDevkitConfig(options = {}) {
14
- const isCI = !!process.env.CI;
14
+ const isCI = Boolean(process.env.CI);
15
15
 
16
16
  const baseConfig = {
17
17
  test: {