Skip to content

Commit 47a2002

Browse files
committed
chore: update ultracite to 7.4.3, fix lint-staged for Next.js paths
- Update ultracite 7.3.2 → 7.4.3 (fixes parentheses/brackets in paths) - Remove workaround for square bracket paths in lint-staged - Add JSDoc type annotations to lint-staged config to fix type-safety lint errors - All 34 pre-existing typescript-eslint errors in lint-staged.config.mjs resolved
1 parent 48c7908 commit 47a2002

File tree

10 files changed

+53
-68
lines changed

10 files changed

+53
-68
lines changed

apps/portal/next.config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function getAppVersion(): string {
1919
}
2020
try {
2121
const pkg = JSON.parse(
22-
readFileSync(join(process.cwd(), "package.json"), "utf8")
22+
readFileSync(join(process.cwd(), "package.json"), "utf-8")
2323
);
2424
const ver = pkg.version as string | undefined;
2525
if (ver) {
@@ -30,7 +30,7 @@ function getAppVersion(): string {
3030
}
3131
try {
3232
const result = execSync("git describe --tags --always", {
33-
encoding: "utf8",
33+
encoding: "utf-8",
3434
stdio: ["ignore", "pipe", "ignore"],
3535
}).trim();
3636
if (result) {
@@ -135,7 +135,7 @@ let nextConfig: NextConfig = {
135135
// Try to get git commit hash directly
136136
try {
137137
const gitHash = execSync("git rev-parse --short HEAD", {
138-
encoding: "utf8",
138+
encoding: "utf-8",
139139
stdio: ["ignore", "pipe", "ignore"],
140140
}).trim();
141141

apps/portal/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@
128128
"tsx": "^4.21.0",
129129
"turbo": "^2.8.20",
130130
"typescript": "catalog:",
131-
"ultracite": "7.3.2",
131+
"ultracite": "7.4.3",
132132
"vitest": "^4.1.1"
133133
},
134134
"engines": {

apps/portal/tests/monorepo/monorepo-correctness.test.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function getLibraryPackageDirs(): string[] {
4848
/** Read and parse a package's package.json */
4949
function readPackageJson(pkgDir: string): Record<string, unknown> {
5050
const filePath = path.join(PACKAGES_DIR, pkgDir, "package.json");
51-
return JSON.parse(fs.readFileSync(filePath, "utf8"));
51+
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
5252
}
5353

5454
/** Recursively collect all .ts/.tsx files under a directory */
@@ -254,7 +254,7 @@ describe("Property 2: No stale imports remain", () => {
254254
const violations: { file: string; line: string; pattern: string }[] = [];
255255

256256
for (const file of sourceFiles) {
257-
const content = fs.readFileSync(file, "utf8");
257+
const content = fs.readFileSync(file, "utf-8");
258258
const lines = content.split("\n");
259259

260260
for (const line of lines) {
@@ -286,7 +286,7 @@ describe("Property 2: No stale imports remain", () => {
286286

287287
assert(
288288
property(constantFrom(...sourceFiles), (file) => {
289-
const content = fs.readFileSync(file, "utf8");
289+
const content = fs.readFileSync(file, "utf-8");
290290
return STALE_PATTERNS.every((p) => !p.test(content));
291291
}),
292292
{ numRuns: Math.min(sourceFiles.length, 100) }
@@ -347,7 +347,7 @@ describe("Property 3: Package boundary enforcement", () => {
347347
const violations: { pkg: string; file: string; line: string }[] = [];
348348

349349
for (const { pkgDir, file } of files) {
350-
const content = fs.readFileSync(file, "utf8");
350+
const content = fs.readFileSync(file, "utf-8");
351351
const lines = content.split("\n");
352352
for (const line of lines) {
353353
if (/(?:from|import)\s+["']@\//.test(line)) {
@@ -373,7 +373,7 @@ describe("Property 3: Package boundary enforcement", () => {
373373
const violations: { pkg: string; file: string; line: string }[] = [];
374374

375375
for (const { pkgDir, file } of files) {
376-
const content = fs.readFileSync(file, "utf8");
376+
const content = fs.readFileSync(file, "utf-8");
377377
const imports = extractImports(content);
378378
for (const imp of imports) {
379379
if (imp.startsWith("../") || imp.startsWith("../../")) {
@@ -406,7 +406,7 @@ describe("Property 3: Package boundary enforcement", () => {
406406

407407
assert(
408408
property(constantFrom(...files), ({ pkgDir, file }) => {
409-
const content = fs.readFileSync(file, "utf8");
409+
const content = fs.readFileSync(file, "utf-8");
410410
if (/(?:from|import)\s+["']@\//.test(content)) {
411411
return false;
412412
}
@@ -440,7 +440,7 @@ describe("Property 3: Package boundary enforcement", () => {
440440
describe("Property 8: Environment variable completeness", () => {
441441
/** Extract env var names from a keys.ts file's runtimeEnv block */
442442
function extractEnvVarsFromKeysFile(filePath: string): string[] {
443-
const content = fs.readFileSync(filePath, "utf8");
443+
const content = fs.readFileSync(filePath, "utf-8");
444444
const vars: string[] = [];
445445
const processEnvRegex = /process\.env\.([A-Z_][A-Z0-9_]*)/g;
446446
let match: RegExpExecArray | null;
@@ -467,7 +467,7 @@ describe("Property 8: Environment variable completeness", () => {
467467
/** Get all declared env vars from turbo.json (all task env + globalEnv) */
468468
function getTurboEnvVars(): { exact: Set<string>; wildcards: string[] } {
469469
const turboJson = JSON.parse(
470-
fs.readFileSync(MONOREPO_TURBO_JSON_PATH, "utf8")
470+
fs.readFileSync(MONOREPO_TURBO_JSON_PATH, "utf-8")
471471
);
472472
const exact = new Set<string>();
473473
const wildcards: string[] = [];
@@ -611,7 +611,7 @@ describe("Property 9: No direct process.env access in packages", () => {
611611
continue;
612612
}
613613

614-
const content = fs.readFileSync(file, "utf8");
614+
const content = fs.readFileSync(file, "utf-8");
615615
const strippedContent = stripComments(content);
616616
const lines = strippedContent.split("\n");
617617
for (let i = 0; i < lines.length; i += 1) {
@@ -657,7 +657,7 @@ describe("Property 9: No direct process.env access in packages", () => {
657657

658658
assert(
659659
property(constantFrom(...nonKeysFiles), (file) => {
660-
const content = fs.readFileSync(file, "utf8");
660+
const content = fs.readFileSync(file, "utf-8");
661661
const stripped = stripComments(content);
662662
const lines = stripped.split("\n");
663663
return lines.every((line) => !hasRealProcessEnvAccess(line));
@@ -699,7 +699,7 @@ describe("Property 10: Import path correctness", () => {
699699
const violations: { file: string; importPath: string }[] = [];
700700

701701
for (const file of sourceFiles) {
702-
const content = fs.readFileSync(file, "utf8");
702+
const content = fs.readFileSync(file, "utf-8");
703703
const imports = extractImports(content);
704704

705705
for (const imp of imports) {
@@ -739,7 +739,7 @@ describe("Property 10: Import path correctness", () => {
739739

740740
assert(
741741
property(constantFrom(...sourceFiles), (file) => {
742-
const content = fs.readFileSync(file, "utf8");
742+
const content = fs.readFileSync(file, "utf-8");
743743
const imports = extractImports(content);
744744
for (const imp of imports) {
745745
const isPortal = imp.startsWith("@portal/");
@@ -787,7 +787,7 @@ describe("Property 11: App-internal alias preservation", () => {
787787
let foundAppInternalImports = false;
788788

789789
for (const file of appFiles) {
790-
const content = fs.readFileSync(file, "utf8");
790+
const content = fs.readFileSync(file, "utf-8");
791791
const imports = extractImports(content);
792792

793793
for (const imp of imports) {
@@ -812,7 +812,7 @@ describe("Property 11: App-internal alias preservation", () => {
812812

813813
assert(
814814
property(constantFrom(...appFiles), (file) => {
815-
const content = fs.readFileSync(file, "utf8");
815+
const content = fs.readFileSync(file, "utf-8");
816816
const imports = extractImports(content);
817817
for (const imp of imports) {
818818
for (const pattern of APP_INTERNAL_PATTERNS) {
@@ -924,7 +924,7 @@ describe("Property 14: Package dependency completeness", () => {
924924
// dependencies since they resolve through the app's bundler
925925
if (PACKAGES_WITH_APP_IMPORTS.has(pkgDir)) {
926926
const appPkgPath = path.join(ROOT_DIR, "package.json");
927-
const appPkg = JSON.parse(fs.readFileSync(appPkgPath, "utf8"));
927+
const appPkg = JSON.parse(fs.readFileSync(appPkgPath, "utf-8"));
928928
for (const dep of Object.keys(
929929
(appPkg.dependencies ?? {}) as Record<string, string>
930930
)) {
@@ -942,7 +942,7 @@ describe("Property 14: Package dependency completeness", () => {
942942
const undeclared: { file: string; importPkg: string }[] = [];
943943

944944
for (const file of files) {
945-
const content = fs.readFileSync(file, "utf8");
945+
const content = fs.readFileSync(file, "utf-8");
946946
// Use strict imports (ES only) to skip optional require() in try/catch
947947
const imports = extractStrictImports(content);
948948

apps/portal/tests/monorepo/package-structure.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function getPackageDirs(): string[] {
2626
/** Read and parse a package's package.json */
2727
function readPackageJson(pkgDir: string): Record<string, unknown> {
2828
const filePath = path.join(PACKAGES_DIR, pkgDir, "package.json");
29-
return JSON.parse(fs.readFileSync(filePath, "utf8"));
29+
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
3030
}
3131

3232
/** Non-config packages that should follow the standard library pattern */
@@ -121,7 +121,7 @@ describe("Property 6: TypeScript config inheritance (extends library.json)", ()
121121
`tsconfig.json should exist in packages/${pkgDir}`
122122
).toBe(true);
123123

124-
const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, "utf8"));
124+
const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, "utf-8"));
125125
expect(tsconfig.extends).toBe("@portal/typescript-config/library.json");
126126
}
127127
);

apps/web/scripts/generate-code-of-conduct.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ let lastUpdated;
4848

4949
try {
5050
// Read and process the README.md content
51-
readmeContent = processMarkdownContent(fs.readFileSync(readmePath, "utf8"));
51+
readmeContent = processMarkdownContent(fs.readFileSync(readmePath, "utf-8"));
5252

5353
// Get the last updated date
5454
const gitCommand = `git -C ${path.join(

apps/web/src/lib/integrations/quickbooks.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ function updateLocalEnvFiles(tokens: {
10061006
// Update .env.local (for Next.js dev on port 3000)
10071007
if (existsSync(envLocalPath)) {
10081008
try {
1009-
const content = readFileSync(envLocalPath, "utf8");
1009+
const content = readFileSync(envLocalPath, "utf-8");
10101010
const lines = content.split("\n");
10111011
const updatedLines = lines.map((line) => {
10121012
if (line.startsWith("QUICKBOOKS_REFRESH_TOKEN=")) {
@@ -1033,7 +1033,7 @@ function updateLocalEnvFiles(tokens: {
10331033
updatedLines.push(`QUICKBOOKS_REALM_ID=${tokens.realmId}`);
10341034
}
10351035

1036-
writeFileSync(envLocalPath, updatedLines.join("\n"), "utf8");
1036+
writeFileSync(envLocalPath, updatedLines.join("\n"), "utf-8");
10371037
updatedAny = true;
10381038
console.log("[QuickBooks] ✅ Updated .env.local");
10391039
} catch (error) {
@@ -1044,7 +1044,7 @@ function updateLocalEnvFiles(tokens: {
10441044
// Update .dev.vars (for Wrangler dev on port 8787)
10451045
if (existsSync(devVarsPath)) {
10461046
try {
1047-
const content = readFileSync(devVarsPath, "utf8");
1047+
const content = readFileSync(devVarsPath, "utf-8");
10481048
const lines = content.split("\n");
10491049
const updatedLines = lines.map((line) => {
10501050
if (line.startsWith("QUICKBOOKS_REFRESH_TOKEN=")) {
@@ -1071,7 +1071,7 @@ function updateLocalEnvFiles(tokens: {
10711071
updatedLines.push(`QUICKBOOKS_REALM_ID=${tokens.realmId}`);
10721072
}
10731073

1074-
writeFileSync(devVarsPath, updatedLines.join("\n"), "utf8");
1074+
writeFileSync(devVarsPath, updatedLines.join("\n"), "utf-8");
10751075
updatedAny = true;
10761076
console.log("[QuickBooks] ✅ Updated .dev.vars");
10771077
} catch (error) {

lint-staged.config.mjs

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* behaviour matches `pnpm lint`.
99
*/
1010

11+
/** @type {string[]} */
1112
const ULTRACITE_IGNORE_PREFIXES = [
1213
"apps/portal/references/",
1314
"apps/portal/drizzle/",
@@ -18,7 +19,11 @@ const ULTRACITE_IGNORE_PREFIXES = [
1819
"references/",
1920
];
2021

21-
/** Normalise a path and strip the cwd prefix to get a repo-relative path. */
22+
/**
23+
* Normalise a path and strip the cwd prefix to get a repo-relative path.
24+
* @param {string} file Absolute file path
25+
* @returns {string} Repo-relative path
26+
*/
2227
function toRelative(file) {
2328
const normalised = file.replaceAll("\\", "/");
2429
const cwd = process.cwd().replaceAll("\\", "/");
@@ -27,27 +32,27 @@ function toRelative(file) {
2732
: normalised;
2833
}
2934

30-
/** Return true if the file should be skipped by ultracite. */
35+
/**
36+
* Return true if the file should be skipped by ultracite.
37+
* @param {string} file Absolute file path
38+
* @returns {boolean} Whether the file should be skipped
39+
*/
3140
function isUltraciteIgnored(file) {
3241
const rel = toRelative(file);
33-
// Skip files with square brackets — ultracite/oxlint treats them as glob patterns
34-
if (/[[\]]/.test(rel)) {
35-
return true;
36-
}
3742
return ULTRACITE_IGNORE_PREFIXES.some(
3843
(prefix) => rel.startsWith(prefix) || rel.includes(`/${prefix}`)
3944
);
4045
}
4146

4247
export default {
4348
// Python — ruff check + format (uv handles its own path resolution)
44-
"*.py": (files) => {
49+
"*.py": (/** @type {string[]} */ files) => {
4550
const args = files.map((f) => JSON.stringify(toRelative(f))).join(" ");
4651
return [`uv run ruff check --fix ${args}`, `uv run ruff format ${args}`];
4752
},
4853

4954
// Shell — shellcheck + shfmt
50-
"*.sh": (files) => {
55+
"*.sh": (/** @type {string[]} */ files) => {
5156
const args = files.map((f) => JSON.stringify(toRelative(f))).join(" ");
5257
return [
5358
`shellcheck ${args}`,
@@ -60,33 +65,12 @@ export default {
6065

6166
// JS/TS/JSON/CSS/MD — run ultracite fix (oxfmt + oxlint) on relative paths
6267
"*.{ts,tsx,js,jsx,mjs,cjs,json,jsonc,css,md,mdx,html,graphql,yaml,yml,toml}":
63-
(files) => {
68+
(/** @type {string[]} */ files) => {
6469
const filtered = files.filter((f) => !isUltraciteIgnored(f));
6570
if (filtered.length === 0) {
6671
return [];
6772
}
68-
69-
// Ultracite can't handle parentheses in paths (e.g. Next.js route groups).
70-
// Split into files ultracite can handle vs ones needing direct oxfmt+oxlint.
71-
const hasParens = (f) => /[()]/.test(toRelative(f));
72-
const normal = filtered.filter((f) => !hasParens(f));
73-
const parenFiles = filtered.filter((f) => hasParens(f));
74-
75-
const cmds = [];
76-
77-
if (normal.length > 0) {
78-
const args = normal.map((f) => JSON.stringify(toRelative(f))).join(" ");
79-
cmds.push(`pnpm exec ultracite fix ${args}`);
80-
}
81-
82-
if (parenFiles.length > 0) {
83-
const args = parenFiles
84-
.map((f) => JSON.stringify(toRelative(f)))
85-
.join(" ");
86-
cmds.push(`pnpm exec oxfmt ${args}`);
87-
cmds.push(`pnpm exec oxlint --fix ${args}`);
88-
}
89-
90-
return cmds;
73+
const args = filtered.map((f) => JSON.stringify(toRelative(f))).join(" ");
74+
return `pnpm exec ultracite fix ${args}`;
9175
},
9276
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"oxlint-tsgolint": "^0.17.2",
4040
"turbo": "^2.8.20",
4141
"typescript": "catalog:",
42-
"ultracite": "7.3.2"
42+
"ultracite": "7.4.3"
4343
},
4444
"engines": {
4545
"node": ">=24.0.0",

packages/fibery/vitest.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { defineConfig } from "vitest/config";
66
function loadEnv(dir: string): Record<string, string> {
77
const env: Record<string, string> = {};
88
try {
9-
const contents = readFileSync(resolve(dir, ".env"), "utf8");
9+
const contents = readFileSync(resolve(dir, ".env"), "utf-8");
1010
for (const line of contents.split("\n")) {
1111
const eqIdx = line.indexOf("=");
1212
if (eqIdx === -1) {

pnpm-lock.yaml

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)