@sablier/devkit 1.6.0 → 1.7.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,76 @@
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("bash")]
9
+ _csv-check globs="data/*/*.csv" schema="" ignore="*.csv.invalid|*.csv.valid|*validation-errors.csv" ext="CSV":
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 {{ ext }} files..."
17
+ found=0
18
+ for file in {{ globs }}; do
19
+ # Skip validation artifact files (only if ignore pattern is set)
20
+ {{ if ignore != "" { "case \"$file\" in\n " + ignore + ")\n continue\n ;;\n esac" } else { "" } }}
21
+
22
+ # Skip if no files match the pattern
23
+ [ -e "$file" ] || continue
24
+
25
+ found=$((found + 1))
26
+ schema_arg="{{ schema }}"
27
+ if ! qsv validate "$file" ${schema_arg:+"$schema_arg"} > /dev/null 2>&1; then
28
+ echo "❌ Validation failed for: $file"
29
+ just _csv-show-errors "$file" "{{ ext }}"
30
+ exit 1
31
+ fi
32
+ done
33
+
34
+ if [ "$found" -eq 0 ]; then
35
+ echo "ℹ️ No {{ ext }} files found to validate"
36
+ else
37
+ echo "✅ All {{ ext }} files are valid"
38
+ fi
39
+
40
+ # Show validation errors for a CSV/TSV file
41
+ [group("checks"), script("bash")]
42
+ _csv-show-errors file ext="CSV":
43
+ error_file="{{ file }}.validation-errors.tsv"
44
+
45
+ if [ ! -f "$error_file" ]; then
46
+ echo "Error file not found: $error_file"
47
+ exit 0
48
+ fi
49
+
50
+ # Try to count total errors (subtract 1 for header row)
51
+ total_errors=$(qsv count "$error_file" 2>/dev/null || echo "0")
52
+ if [ "$total_errors" != "0" ]; then
53
+ total_errors=$((total_errors - 1))
54
+ fi
55
+
56
+ echo ""
57
+ if [ "$total_errors" != "0" ] && [ "$total_errors" -gt 0 ]; then
58
+ echo "First 20 validation errors (${total_errors} total):"
59
+ else
60
+ echo "Validation errors:"
61
+ fi
62
+ echo ""
63
+
64
+ # Try to use qsv table for nice formatting, fall back to basic display
65
+ if qsv slice --start 0 --len 21 "$error_file" 2>/dev/null | qsv table 2>/dev/null; then
66
+ : # Success, output already shown
67
+ else
68
+ head -n 21 "$error_file"
69
+ fi
70
+
71
+ if [ "$total_errors" != "0" ] && [ "$total_errors" -gt 20 ]; then
72
+ echo ""
73
+ echo "... and $((total_errors - 20)) more errors"
74
+ fi
75
+ echo ""
76
+ echo "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")]
8
+ [group("checks")]
9
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
10
+ @just _csv-check "{{ globs }}" "{{ schema }}" "{{ ignore }}" "TSV"
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.0",
6
+ "version": "1.7.0",
7
7
  "author": {
8
8
  "name": "Sablier Labs Ltd",
9
9
  "url": "https://sablier.com"
@@ -26,15 +26,13 @@
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",
32
33
  "./tsconfig/build": "./tsconfig/build.json",
33
34
  "./tsconfig/next": "./tsconfig/next.json",
34
- "./vitest": {
35
- "import": "./vitest/index.js",
36
- "types": "./vitest/index.d.ts"
37
- }
35
+ "./vitest": "./vitest/base.js"
38
36
  },
39
37
  "engines": {
40
38
  "node": ">=20"
@@ -42,9 +40,9 @@
42
40
  "files": [
43
41
  "biome/",
44
42
  "just/",
45
- ".prettierrc.json",
46
43
  "tsconfig/",
47
- "vitest/"
44
+ "vitest/",
45
+ ".prettierrc.json"
48
46
  ],
49
47
  "keywords": [
50
48
  "biome",
package/vitest/base.js ADDED
@@ -0,0 +1,32 @@
1
+ import { defineConfig, mergeConfig } from "vitest/config";
2
+
3
+ /**
4
+ * @typedef {Object} DevkitVitestOptions
5
+ * @property {"node" | "jsdom" | "happy-dom"} [environment]
6
+ * @property {string[]} [setupFiles]
7
+ * @property {boolean} [coverage]
8
+ */
9
+
10
+ /**
11
+ * @param {DevkitVitestOptions} [options]
12
+ */
13
+ export function defineDevkitConfig(options = {}) {
14
+ const isCI = Boolean(process.env.CI);
15
+
16
+ const baseConfig = {
17
+ test: {
18
+ coverage: options.coverage ? { provider: "v8" } : undefined,
19
+ environment: options.environment ?? "node",
20
+ globals: true,
21
+ reporters: isCI ? ["basic"] : ["verbose"],
22
+ retry: isCI ? 2 : 0,
23
+ setupFiles: options.setupFiles,
24
+ testTimeout: isCI ? 30_000 : 10_000,
25
+ },
26
+ };
27
+
28
+ return defineConfig(baseConfig);
29
+ }
30
+
31
+ // Re-export for merging with existing vite configs
32
+ export { mergeConfig };
package/vitest/index.ts DELETED
@@ -1,29 +0,0 @@
1
- import type { UserConfig } from "vitest/config";
2
- import { defineConfig } from "vitest/config";
3
-
4
- export interface DevkitVitestOptions {
5
- environment?: "node" | "jsdom" | "happy-dom";
6
- setupFiles?: string[];
7
- coverage?: boolean;
8
- }
9
-
10
- export function defineDevkitConfig(options: DevkitVitestOptions = {}) {
11
- const isCI = !!process.env.CI;
12
-
13
- const baseConfig: UserConfig = {
14
- test: {
15
- coverage: options.coverage ? { provider: "v8" } : undefined,
16
- environment: options.environment ?? "node",
17
- globals: true,
18
- reporters: isCI ? ["basic"] : ["verbose"],
19
- retry: isCI ? 2 : 0,
20
- setupFiles: options.setupFiles,
21
- testTimeout: isCI ? 30_000 : 10_000,
22
- },
23
- };
24
-
25
- return defineConfig(baseConfig);
26
- }
27
-
28
- // Re-export for merging with existing vite configs
29
- export { mergeConfig } from "vitest/config";