From 34209562bc1faac84ad93de32396d7effee1be7c Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 14 May 2026 16:35:07 +0530 Subject: [PATCH 01/32] Added knip config and action for unused files/exports --- .github/scripts/compareKnipReports.ts | 166 ++++ .github/workflows/knip.yml | 63 ++ knip.json | 67 ++ package-lock.json | 920 +++++++++++++++++- package.json | 4 + parse_knip.py | 36 + run_knip_full.sh | 23 + src/components/Skeletons/TableRowSkeleton.tsx | 60 -- src/libs/Network/LoadTest.ts | 2 +- src/libs/actions/IOU/MoneyRequest.ts | 1 - src/types/onyx/OriginalMessage.ts | 1 - 11 files changed, 1249 insertions(+), 94 deletions(-) create mode 100644 .github/scripts/compareKnipReports.ts create mode 100644 .github/workflows/knip.yml create mode 100644 knip.json create mode 100644 parse_knip.py create mode 100755 run_knip_full.sh delete mode 100644 src/components/Skeletons/TableRowSkeleton.tsx diff --git a/.github/scripts/compareKnipReports.ts b/.github/scripts/compareKnipReports.ts new file mode 100644 index 000000000000..203dc5eb5f60 --- /dev/null +++ b/.github/scripts/compareKnipReports.ts @@ -0,0 +1,166 @@ +import fs from 'fs'; +import type {TupleToUnion} from 'type-fest'; + +/** + * Compare two knip JSON reports (main vs PR). + * Exit 1 if the PR introduces any new finding that isn't present on main, regardless + * of whether the PR also resolves others. Findings are matched per `::`, + * so a single file with multiple unused items in the same category counts as one + * finding per item. + * + * Usage: ts-node scripts/compareKnipReports.ts + */ + +const CATEGORIES = [ + 'files', + 'dependencies', + 'devDependencies', + 'optionalPeerDependencies', + 'unlisted', + 'binaries', + 'unresolved', + 'exports', + 'types', + 'nsExports', + 'nsTypes', + 'enumMembers', + 'classMembers', + 'duplicates', +] as const; + +type Category = TupleToUnion; + +type IssueItem = string | {name?: string; symbol?: string}; + +type Entry = { + file?: string; +} & Partial>; + +type Report = { + issues?: Entry[]; +}; + +function parseReport(filepath: string): Report { + if (!fs.existsSync(filepath)) { + return {issues: []}; + } + let raw = fs.readFileSync(filepath, 'utf8'); + // knip writes JSON to stdout, but babel.config.js debug logs can prepend noise. + // Trim everything before the first `{"issues"` token. + const i = raw.indexOf('{"issues"'); + if (i > 0) { + raw = raw.slice(i); + } + if (!raw.trim()) { + return {issues: []}; + } + try { + return JSON.parse(raw) as Report; + } catch (e) { + console.error(`Failed to parse ${filepath}: ${(e as Error).message}`); + return {issues: []}; + } +} + +function flatten(report: Report): Map> { + const out = new Map>(); + for (const cat of CATEGORIES) { + out.set(cat, new Set()); + } + + for (const entry of report.issues ?? []) { + const file = entry.file ?? ''; + for (const cat of CATEGORIES) { + const items = entry[cat]; + if (!Array.isArray(items)) { + continue; + } + for (const item of items) { + const name = typeof item === 'string' ? item : (item.symbol ?? item.name ?? JSON.stringify(item)); + out.get(cat)?.add(`${file}::${name}`); + } + } + } + return out; +} + +function diff(mainMap: Map>, prMap: Map>): {added: Map; resolved: Map} { + const added = new Map(); + const resolved = new Map(); + for (const cat of CATEGORIES) { + const m = mainMap.get(cat) ?? new Set(); + const p = prMap.get(cat) ?? new Set(); + const a: string[] = []; + const r: string[] = []; + for (const x of p) { + if (!m.has(x)) { + a.push(x); + } + } + for (const x of m) { + if (!p.has(x)) { + r.push(x); + } + } + if (a.length) { + added.set(cat, a.sort()); + } + if (r.length) { + resolved.set(cat, r.sort()); + } + } + return {added, resolved}; +} + +function totalCount(map: Map>): number { + let n = 0; + for (const set of map.values()) { + n += set.size; + } + return n; +} + +function printSection(title: string, byCategory: Map): void { + if (byCategory.size === 0) { + return; + } + console.log(`\n${title}`); + for (const [cat, items] of byCategory) { + console.log(` ${cat} (${items.length}):`); + for (const it of items) { + console.log(` ${it}`); + } + } +} + +const [mainPath, prPath] = process.argv.slice(2); +if (!mainPath || !prPath) { + console.error('Usage: ts-node compareKnipReports.ts '); + process.exit(2); +} + +const mainFlat = flatten(parseReport(mainPath)); +const prFlat = flatten(parseReport(prPath)); + +const mainTotal = totalCount(mainFlat); +const prTotal = totalCount(prFlat); +const delta = prTotal - mainTotal; +const {added, resolved} = diff(mainFlat, prFlat); +const addedTotal = [...added.values()].reduce((n, a) => n + a.length, 0); +const resolvedTotal = [...resolved.values()].reduce((n, a) => n + a.length, 0); + +console.log('Knip comparison:'); +console.log(` main : ${mainTotal}`); +console.log(` PR : ${prTotal} (delta ${delta >= 0 ? '+' : ''}${delta})`); +console.log(` added by PR : ${addedTotal}`); +console.log(` resolved by PR : ${resolvedTotal}`); + +printSection('New issues introduced:', added); +printSection('Issues resolved:', resolved); + +if (addedTotal > 0) { + console.log(`\n::error::PR introduces ${addedTotal} new knip finding(s) (resolved ${resolvedTotal}, delta ${delta >= 0 ? '+' : ''}${delta}).`); + process.exit(1); +} + +console.log('\nPR introduces no new knip findings.'); diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml new file mode 100644 index 000000000000..df74ecb15ce3 --- /dev/null +++ b/.github/workflows/knip.yml @@ -0,0 +1,63 @@ +name: Knip check + +on: + pull_request: + types: [opened, synchronize] + branches-ignore: [staging, production] + paths: + - '**.js' + - '**.jsx' + - '**.ts' + - '**.tsx' + - '**.mjs' + - '**.cjs' + - 'knip.json' + - 'package.json' + - 'package-lock.json' + - 'patches/**' + - 'tsconfig.json' + +concurrency: + group: ${{ github.ref == 'refs/heads/main' && format('{0}-{1}', github.ref, github.sha) || github.ref }}-knip + cancel-in-progress: true + +jobs: + knip-compare: + name: Compare knip issues against main + if: ${{ github.actor != 'OSBotify' }} + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - name: Checkout PR + # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Capture PR ref + id: pr-ref + run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - name: Setup Node (PR) + uses: ./.github/actions/composite/setupNode + + - name: Run knip on PR + run: npm run knip:json > /tmp/knip-pr.json + env: + CI: true + + - name: Checkout main + run: | + git fetch origin main --no-tags --depth=1 + git checkout origin/main + + - name: Setup Node (main) + uses: ./.github/actions/composite/setupNode + + - name: Run knip on main + run: npm run knip:json > /tmp/knip-main.json + env: + CI: true + + - name: Restore PR workspace + run: git checkout ${{ steps.pr-ref.outputs.sha }} + + - name: Compare reports + run: npx ts-node .github/scripts/compareKnipReports.ts /tmp/knip-main.json /tmp/knip-pr.json diff --git a/knip.json b/knip.json new file mode 100644 index 000000000000..833cb56cdc05 --- /dev/null +++ b/knip.json @@ -0,0 +1,67 @@ +{ + "entry": [ + "index.js", + "wdyr.ts", + "src/App.tsx", + "src/HybridAppHandler.tsx", + "scripts/**/*.{js,ts}", + "web/proxy.ts", + "config/webpack/**/*.{js,mjs,ts}", + ".github/scripts/**/*.ts", + ".github/actions/javascript/**/*.ts", + ".storybook/**/*.{js,ts,tsx}", + "metro.config.js", + "eslint.changed.config.mjs", + "react-native.config.js", + "rock.config.mjs" + ], + "project": [ + "src/**/*.{js,jsx,ts,tsx}", + "tests/**/*.{js,jsx,ts,tsx}", + "__mocks__/**/*.{js,jsx,ts,tsx}", + "web/**/*.{js,jsx,ts,tsx}", + "config/**/*.{js,mjs,ts,tsx}", + "scripts/**/*.{js,ts}", + "jest/**/*.{js,ts}", + ".storybook/**/*.{js,ts,tsx}", + ".github/actions/javascript/**/*.ts" + ], + "ignore": [".github/actions/**/index.js", "tests/perf-test/**", "web/snippets/gib.js"], + "ignoreDependencies": [ + "@expensify/react-native-hybrid-app", + "group-ib-fp", + "react-native-image-size", + "react-native-picker-select", + "lodash", + "@babel/plugin-proposal-private-methods", + "@babel/plugin-proposal-private-property-in-object", + "babel-plugin-module-resolver", + "babel-plugin-transform-remove-console", + "@fullstory/babel-plugin-react-native", + "eslint-config-airbnb-typescript", + "eslint-config-prettier", + "eslint-plugin-storybook", + "@dword-design/eslint-plugin-import-alias", + "tsconfig-paths", + "@vercel/ncc", + "shellcheck", + "patch-package", + "diff-so-fancy" + ], + "ignoreBinaries": ["metro-symbolicate", "mkcert"], + "eslint": { + "config": ["config/eslint/eslint.config.mjs", "eslint.changed.config.mjs"] + }, + "webpack": { + "config": ["config/webpack/webpack.common.ts", "config/webpack/webpack.dev.ts"] + }, + "babel": { + "config": ["babel.config.js"] + }, + "jest": { + "config": ["jest.config.js"] + }, + "storybook": { + "config": [".storybook/main.ts"] + } +} diff --git a/package-lock.json b/package-lock.json index 5703516b8e6c..3c602aee83f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -259,6 +259,7 @@ "jest-expo": "55.0.6", "jest-transformer-svg": "^2.0.1", "jest-when": "^3.5.2", + "knip": "^6.13.1", "link": "^2.1.1", "memfs": "^4.6.0", "mini-css-extract-plugin": "^2.9.4", @@ -4924,21 +4925,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", - "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.1.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, @@ -4947,9 +4948,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, @@ -10376,20 +10377,22 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", - "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@native-html/css-processor": { @@ -10660,6 +10663,23 @@ "react-native": ">=0.70.0 <1.0.x" } }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.130.0.tgz", + "integrity": "sha512-h/xYU8/7ADWzVSf5I+YalLpj33LOy9CI/zgbJNIZ5eunRBG+Czqa3lZsvuPHHf3rOt6z1c5+UzoxjbAzAvhwVw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-parser/binding-android-arm64": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.99.0.tgz", @@ -10796,6 +10816,23 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.130.0.tgz", + "integrity": "sha512-b+h/lsLLurp756dMGizNs5uPaJfyEdWrTcV5t8M609jWm1DEHB1StpRXCkyvwtkJx3m+qL5BNQ0dEKan/4yGFA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.99.0.tgz", @@ -10813,6 +10850,23 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.130.0.tgz", + "integrity": "sha512-BgXRVC0+83n3YzCscLQjj6nbyeBIVeZYPTI4fFMAE4WNm2+4RXhWp03IVizL7esIz36kgmT48aebk1iM+cs8sw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-parser/binding-linux-s390x-gnu": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.99.0.tgz", @@ -10864,6 +10918,23 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.130.0.tgz", + "integrity": "sha512-I0NCrZV/YZuCGWgqwNN/GO/iXlLF2z+Wgc7u+Aa9N4P51oYeIa0XT+zVBUne4csO9GqxskXgI4g8JzzWGRpfOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-parser/binding-wasm32-wasi": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.99.0.tgz", @@ -10898,6 +10969,23 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.130.0.tgz", + "integrity": "sha512-hRYbv6HhpSTzT4xTiIkadLI7upLQxuOdLPR/9nL1fTjwhgutBTPXrwaAPb/jTFVx6/8C7Jb5HcUKhmNwloTbFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxc-parser/binding-win32-x64-msvc": { "version": "0.99.0", "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.99.0.tgz", @@ -10925,6 +11013,289 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@oxc-resolver/binding-android-arm-eabi": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.19.1.tgz", + "integrity": "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@oxc-resolver/binding-android-arm64": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.19.1.tgz", + "integrity": "sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@oxc-resolver/binding-darwin-arm64": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.19.1.tgz", + "integrity": "sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxc-resolver/binding-darwin-x64": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.19.1.tgz", + "integrity": "sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxc-resolver/binding-freebsd-x64": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.19.1.tgz", + "integrity": "sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.19.1.tgz", + "integrity": "sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.19.1.tgz", + "integrity": "sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.19.1.tgz", + "integrity": "sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm64-musl": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.19.1.tgz", + "integrity": "sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.19.1.tgz", + "integrity": "sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.19.1.tgz", + "integrity": "sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.19.1.tgz", + "integrity": "sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.19.1.tgz", + "integrity": "sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-x64-gnu": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.19.1.tgz", + "integrity": "sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-x64-musl": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.19.1.tgz", + "integrity": "sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-openharmony-arm64": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.19.1.tgz", + "integrity": "sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@oxc-resolver/binding-wasm32-wasi": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.19.1.tgz", + "integrity": "sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.19.1.tgz", + "integrity": "sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxc-resolver/binding-win32-ia32-msvc": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-11.19.1.tgz", + "integrity": "sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxc-resolver/binding-win32-x64-msvc": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.19.1.tgz", + "integrity": "sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@peggyjs/from-mem": { "version": "1.3.0", "dev": true, @@ -25059,6 +25430,16 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/fd-package-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-2.0.0.tgz", + "integrity": "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "walk-up-path": "^4.0.0" + } + }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -25753,6 +26134,22 @@ "node": ">= 6" } }, + "node_modules/formatly": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/formatly/-/formatly-0.3.0.tgz", + "integrity": "sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fd-package-json": "^2.0.0" + }, + "bin": { + "formatly": "bin/index.mjs" + }, + "engines": { + "node": ">=18.3.0" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -26115,9 +26512,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", "dev": true, "license": "MIT", "dependencies": { @@ -30489,6 +30886,415 @@ "node": ">=6" } }, + "node_modules/knip": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/knip/-/knip-6.13.1.tgz", + "integrity": "sha512-hvSnb+YDpDWW1LXub4U0JFfkQhscwgInWuQOv99WTutPZavf1cEP3GwxzEzO2JJpGI9yATk6l0jPLY1V3fp1sQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/webpro" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/knip" + } + ], + "license": "ISC", + "dependencies": { + "fdir": "^6.5.0", + "formatly": "^0.3.0", + "get-tsconfig": "4.14.0", + "jiti": "^2.7.0", + "minimist": "^1.2.8", + "oxc-parser": "^0.130.0", + "oxc-resolver": "^11.19.1", + "picomatch": "^4.0.4", + "smol-toml": "^1.6.1", + "strip-json-comments": "5.0.3", + "tinyglobby": "^0.2.16", + "unbash": "^3.0.0", + "yaml": "^2.9.0", + "zod": "^4.1.11" + }, + "bin": { + "knip": "bin/knip.js", + "knip-bun": "bin/knip-bun.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.130.0.tgz", + "integrity": "sha512-oFWFJrsGv9siFM4HjMqKNB7IuIZD/SMmZdCXl8xyx7lDplGvPKyewpOo272rSWgMXe2Wx7bWI0Yj+gkHv4qbeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.130.0.tgz", + "integrity": "sha512-sGUzupdTplK9jQg7eJZ878HfEgQjJNBc6dAYVWJ9W5aU+J8rLfRJhTVsKThiu1pNwm6Y1qKCcbC6WhNWSXR3Ig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.130.0.tgz", + "integrity": "sha512-PsB4cdCISbC00Uy8eiD8bc2AkGWjZqrSrJnkBFuG2ptrrf6mZ2F5gLFSjOAVMMgZPg8B1D7OydJwLWSfyI2Plg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.130.0.tgz", + "integrity": "sha512-DgABp3l38hS77JbXCV4qk1+n6DPym5u8zzwuweokezm2tX194nDSJDENbDRECxVsiNbprKATLbk+Z5wlHT0OHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.130.0.tgz", + "integrity": "sha512-4Kn3CTEmwFrzhTSC/JuUW16qovmaMdX7jeSKbL8w0pLtLww7To1a2XJi9Z5uD8QWUkfUHhqfV+VD6dVzBnWzoA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.130.0.tgz", + "integrity": "sha512-D35KZM3F4rRu1uAFKyBlg3Gaf/ybCjyaPR1hfgvk5ex8NtcTmRgc0JgSighEyNg96TPrFhemFba68SZuxaha8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.130.0.tgz", + "integrity": "sha512-Q9o7oVlo955KHwS8l1u0bCzIx+JsZUA3XToLXC+MsMhye/9LeBQbt84nh120cl2XLy+TEzvugYDiHShg5yaX6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.130.0.tgz", + "integrity": "sha512-EiJ/gC0ljbcwVpycC8YWw6ggMbtsPX8XMOt0mPx0aqWeMsNR+L9m05Flbvd5T+GlivG+GkSWQL7tM9SRFpM/dw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.130.0.tgz", + "integrity": "sha512-O19Cil83XAyjEFfo8WhkMwY58ALqZ7ckjGL+25mjMIuF84urWBeANH0FC8B8BsSSygWU3/1aY3ADdDbp+wlBnw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.130.0.tgz", + "integrity": "sha512-6tJz0xvnGhsokE7N1WlUSBXibpYmT9xSJFS1Ce41Km/+8gQvdlW8MLhRv8PD0L7ix8vRG0FDDepp3jdOFzdVdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.130.0.tgz", + "integrity": "sha512-9aCWj83dp3heTQGmGnZGdIWgxjZrr/7VQ0TGFHH5PKByxJKF2Hcr4qvaSUHhhGEa3MSsDjTL1YDP8RAgdL5/Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.130.0.tgz", + "integrity": "sha512-afXt87aZBqrUVli8TB/I8H1G50RDWcwirjWtXGXYqJ2ZqWEiErH7V72j3LUSDZaivmtu2OLX0KQ/mbhP81mr7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.130.0.tgz", + "integrity": "sha512-sJgQkGaBX0WJvPUDfwciex6IcTk5O5NLQ1bhEb6f3nBruh1GshKMRSMt2bxZlYrgBzjyBbJzsnO+InPG0bg+fA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.130.0.tgz", + "integrity": "sha512-bjcma99sQrNh6RY4mPO9yTkfxql6TDFoN3HWdK31RCKXwNhcDgJXW/l8PUtzKNiQ+9vpKJfJtQq+LklBuxSOBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.130.0.tgz", + "integrity": "sha512-RBpA9TsRucJq6HNVNCFF1iKg+QeTkLdZf7hi4xaOGCPvMZWvDHjQgSOEZMUpuW4JNciHbxNhLEYmz5CVygjVGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/knip/node_modules/@oxc-project/types": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz", + "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/knip/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/knip/node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/knip/node_modules/oxc-parser": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.130.0.tgz", + "integrity": "sha512-X0PJ+NmOok8qP3vK9uaW431ngkdM9UPEK7KG466urtIL2+EYTEgbZK2yqe2MWKJKBjRlFweP/pJPx0x9muMEVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.130.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.130.0", + "@oxc-parser/binding-android-arm64": "0.130.0", + "@oxc-parser/binding-darwin-arm64": "0.130.0", + "@oxc-parser/binding-darwin-x64": "0.130.0", + "@oxc-parser/binding-freebsd-x64": "0.130.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.130.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.130.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.130.0", + "@oxc-parser/binding-linux-arm64-musl": "0.130.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.130.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.130.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.130.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.130.0", + "@oxc-parser/binding-linux-x64-gnu": "0.130.0", + "@oxc-parser/binding-linux-x64-musl": "0.130.0", + "@oxc-parser/binding-openharmony-arm64": "0.130.0", + "@oxc-parser/binding-wasm32-wasi": "0.130.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.130.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.130.0", + "@oxc-parser/binding-win32-x64-msvc": "0.130.0" + } + }, + "node_modules/knip/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/knip/node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/knip/node_modules/zod": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.1.tgz", + "integrity": "sha512-a6ENMBBGZBsnlSebQ/eKCguSBeGKSf4O7BPnqVPmYGtpBYI7VSqoVqw+QcB7kPRjbqPwhYTpFbVj/RqNz/CT0Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/lan-network": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.2.0.tgz", @@ -33219,6 +34025,38 @@ "@oxc-parser/binding-win32-x64-msvc": "0.99.0" } }, + "node_modules/oxc-resolver": { + "version": "11.19.1", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.19.1.tgz", + "integrity": "sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-resolver/binding-android-arm-eabi": "11.19.1", + "@oxc-resolver/binding-android-arm64": "11.19.1", + "@oxc-resolver/binding-darwin-arm64": "11.19.1", + "@oxc-resolver/binding-darwin-x64": "11.19.1", + "@oxc-resolver/binding-freebsd-x64": "11.19.1", + "@oxc-resolver/binding-linux-arm-gnueabihf": "11.19.1", + "@oxc-resolver/binding-linux-arm-musleabihf": "11.19.1", + "@oxc-resolver/binding-linux-arm64-gnu": "11.19.1", + "@oxc-resolver/binding-linux-arm64-musl": "11.19.1", + "@oxc-resolver/binding-linux-ppc64-gnu": "11.19.1", + "@oxc-resolver/binding-linux-riscv64-gnu": "11.19.1", + "@oxc-resolver/binding-linux-riscv64-musl": "11.19.1", + "@oxc-resolver/binding-linux-s390x-gnu": "11.19.1", + "@oxc-resolver/binding-linux-x64-gnu": "11.19.1", + "@oxc-resolver/binding-linux-x64-musl": "11.19.1", + "@oxc-resolver/binding-openharmony-arm64": "11.19.1", + "@oxc-resolver/binding-wasm32-wasi": "11.19.1", + "@oxc-resolver/binding-win32-arm64-msvc": "11.19.1", + "@oxc-resolver/binding-win32-ia32-msvc": "11.19.1", + "@oxc-resolver/binding-win32-x64-msvc": "11.19.1" + } + }, "node_modules/p-limit": { "version": "3.1.0", "devOptional": true, @@ -36906,9 +37744,9 @@ } }, "node_modules/smol-toml": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.5.2.tgz", - "integrity": "sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", + "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -38233,14 +39071,14 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -38268,9 +39106,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -38924,6 +39762,16 @@ "node": ">=0.8.0" } }, + "node_modules/unbash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unbash/-/unbash-3.0.0.tgz", + "integrity": "sha512-FeFPZ/WFT0mbRCuydiZzpPFlrYN8ZUpphQKoq4EeElVIYjYyGzPMxQR/simUwCOJIyVhpFk4RbtyO7RuMpMnHA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -39326,6 +40174,16 @@ "dev": true, "license": "MIT" }, + "node_modules/walk-up-path": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", + "integrity": "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/walker": { "version": "1.0.8", "license": "Apache-2.0", @@ -40745,9 +41603,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index f990db6cee95..e21873481322 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,9 @@ "lint-changed": "./scripts/lintChanged.sh", "lint-watch": "onchange '**/*.{js,jsx,ts,tsx,mjs,cjs}' -- ./scripts/lint.sh {{changed}}", "eslint-report": "ts-node scripts/eslint-report.ts", + "knip": "KNIP=true knip --include dependencies --exclude unlisted --no-exit-code --reporter compact", + "knip:full": "KNIP=true knip --reporter compact", + "knip:json": "KNIP=true knip --reporter json --no-exit-code", "shellcheck": "./scripts/shellCheck.sh", "spell": "cspell --color **/*", "spell-changed": "cspell --color --no-must-find-files", @@ -323,6 +326,7 @@ "jest-expo": "55.0.6", "jest-transformer-svg": "^2.0.1", "jest-when": "^3.5.2", + "knip": "^6.13.1", "link": "^2.1.1", "memfs": "^4.6.0", "mini-css-extract-plugin": "^2.9.4", diff --git a/parse_knip.py b/parse_knip.py new file mode 100644 index 000000000000..1479a2f0d203 --- /dev/null +++ b/parse_knip.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +import re + +# Read the clean report +with open('knip.full.report.clean.txt', 'r') as f: + lines = f.readlines() + +# Parse the report +sections = {} +current_section = None + +for line in lines: + line = line.rstrip() + if not line: + continue + + # Check if it's a section header (e.g., "Unused files (64)") + match = re.match(r'^([A-Za-z\s]+?)\s*\((\d+)\)$', line) + if match: + current_section = match.group(1).strip() + sections[current_section] = [] + elif current_section is not None: + # This is an item in the current section + sections[current_section].append(line) + +# Write TSV file +with open('knip.full.parsed.tsv', 'w') as f: + f.write("SECTION\tITEM\n") + for section, items in sections.items(): + for item in items: + f.write(f"{section}\t{item}\n") + +# Print parsing summary +print("Parsed sections:") +for section, items in sections.items(): + print(f" {section}: {len(items)} items") diff --git a/run_knip_full.sh b/run_knip_full.sh new file mode 100755 index 000000000000..171806afe20c --- /dev/null +++ b/run_knip_full.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -u + +cd "$(dirname "$0")" + +REPORT="knip.full.report.txt" +CLEAN="knip.full.report.clean.txt" +EXIT="knip.full.exitcode.txt" + +set +e +npm run knip:full >"$REPORT" 2>&1 +code=$? +set -e +echo "$code" >"$EXIT" + +# Strip ANSI escape sequences for the clean copy +sed -E 's/\x1B\[[0-9;]*[A-Za-z]//g' "$REPORT" >"$CLEAN" + +python3 parse_knip.py +python3 build_summary.py + +echo "knip exit code: $code" +echo "Outputs: $REPORT, $CLEAN, $EXIT, knip.full.parsed.tsv, knip.full.summary.md" diff --git a/src/components/Skeletons/TableRowSkeleton.tsx b/src/components/Skeletons/TableRowSkeleton.tsx deleted file mode 100644 index cc9384a104cd..000000000000 --- a/src/components/Skeletons/TableRowSkeleton.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import {Circle} from 'react-native-svg'; -import SkeletonRect from '@components/SkeletonRect'; -import useThemeStyles from '@hooks/useThemeStyles'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; -import useSkeletonSpan from '@libs/telemetry/useSkeletonSpan'; -import ItemListSkeletonView from './ItemListSkeletonView'; - -type TableListItemSkeletonProps = { - shouldAnimate?: boolean; - fixedNumItems?: number; - gradientOpacityEnabled?: boolean; - useCompanyCardsLayout?: boolean; - reasonAttributes: SkeletonSpanReasonAttributes; -}; - -const barHeight = '8'; -const shortBarWidth = '60'; -const longBarWidth = '124'; - -function TableListItemSkeleton({shouldAnimate = true, fixedNumItems, gradientOpacityEnabled = false, useCompanyCardsLayout = false, reasonAttributes}: TableListItemSkeletonProps) { - const styles = useThemeStyles(); - useSkeletonSpan('TableRowSkeleton', reasonAttributes); - - const circleX = useCompanyCardsLayout ? 36 : 40; - const circleY = useCompanyCardsLayout ? 36 : 32; - const rectX = useCompanyCardsLayout ? 68 : 80; - const rectY1 = useCompanyCardsLayout ? 24 : 20; - const rectY2 = useCompanyCardsLayout ? 40 : 36; - - return ( - ( - <> - - - - - )} - /> - ); -} - -export default TableListItemSkeleton; diff --git a/src/libs/Network/LoadTest.ts b/src/libs/Network/LoadTest.ts index 0a977033d6bf..b2b19d616fa1 100644 --- a/src/libs/Network/LoadTest.ts +++ b/src/libs/Network/LoadTest.ts @@ -28,5 +28,5 @@ function triggerDuplicates(request: Request | Pagina } } -export {getDuplicateRequestCount, setLoadTestParameters} from './LoadTestState'; +// eslint-disable-next-line import/prefer-default-export export {triggerDuplicates}; diff --git a/src/libs/actions/IOU/MoneyRequest.ts b/src/libs/actions/IOU/MoneyRequest.ts index f3502a6bd04c..59a2da458f2b 100644 --- a/src/libs/actions/IOU/MoneyRequest.ts +++ b/src/libs/actions/IOU/MoneyRequest.ts @@ -1148,6 +1148,5 @@ export { setMoneyRequestParticipantsFromReport, getIOURequestPolicyID, updateLastLocationPermissionPrompt, - setMultipleMoneyRequestParticipantsFromReport, }; export type {MoneyRequestStepScanParticipantsFlowParams}; diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 8cf29fe9382c..82fd07c352e2 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -1592,7 +1592,6 @@ export type { OriginalMessageExportIntegration, IssueNewCardOriginalMessage, OriginalMessageChangePolicy, - OriginalMessageUnreportedTransaction, OriginalMessageMovedTransaction, PolicyBudgetFrequency, OriginalMessageMarkedReimbursed, From f7d32e1f64252150fce1d0ccb0837ec15dfb9dbe Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 14 May 2026 16:36:09 +0530 Subject: [PATCH 02/32] Removed unused file --- run_knip_full.sh | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100755 run_knip_full.sh diff --git a/run_knip_full.sh b/run_knip_full.sh deleted file mode 100755 index 171806afe20c..000000000000 --- a/run_knip_full.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash -set -u - -cd "$(dirname "$0")" - -REPORT="knip.full.report.txt" -CLEAN="knip.full.report.clean.txt" -EXIT="knip.full.exitcode.txt" - -set +e -npm run knip:full >"$REPORT" 2>&1 -code=$? -set -e -echo "$code" >"$EXIT" - -# Strip ANSI escape sequences for the clean copy -sed -E 's/\x1B\[[0-9;]*[A-Za-z]//g' "$REPORT" >"$CLEAN" - -python3 parse_knip.py -python3 build_summary.py - -echo "knip exit code: $code" -echo "Outputs: $REPORT, $CLEAN, $EXIT, knip.full.parsed.tsv, knip.full.summary.md" From 041c8496f1221ed82e5b6ce49cd1acfd5d332c65 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 14 May 2026 16:37:53 +0530 Subject: [PATCH 03/32] Removed unused file --- parse_knip.py | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 parse_knip.py diff --git a/parse_knip.py b/parse_knip.py deleted file mode 100644 index 1479a2f0d203..000000000000 --- a/parse_knip.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 -import re - -# Read the clean report -with open('knip.full.report.clean.txt', 'r') as f: - lines = f.readlines() - -# Parse the report -sections = {} -current_section = None - -for line in lines: - line = line.rstrip() - if not line: - continue - - # Check if it's a section header (e.g., "Unused files (64)") - match = re.match(r'^([A-Za-z\s]+?)\s*\((\d+)\)$', line) - if match: - current_section = match.group(1).strip() - sections[current_section] = [] - elif current_section is not None: - # This is an item in the current section - sections[current_section].append(line) - -# Write TSV file -with open('knip.full.parsed.tsv', 'w') as f: - f.write("SECTION\tITEM\n") - for section, items in sections.items(): - for item in items: - f.write(f"{section}\t{item}\n") - -# Print parsing summary -print("Parsed sections:") -for section, items in sections.items(): - print(f" {section}: {len(items)} items") From 83fb7635c5b8ab159a9debde9efb1dbf1de31335 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 14 May 2026 16:44:11 +0530 Subject: [PATCH 04/32] Fix action --- .github/workflows/knip.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index df74ecb15ce3..09b970a84c3d 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -39,7 +39,7 @@ jobs: uses: ./.github/actions/composite/setupNode - name: Run knip on PR - run: npm run knip:json > /tmp/knip-pr.json + run: KNIP=true npx knip --reporter json --no-exit-code > /tmp/knip-pr.json env: CI: true @@ -52,7 +52,7 @@ jobs: uses: ./.github/actions/composite/setupNode - name: Run knip on main - run: npm run knip:json > /tmp/knip-main.json + run: KNIP=true npx knip --reporter json --no-exit-code > /tmp/knip-main.json env: CI: true From 1549f3f52c018e566a83b6e05af801a45f10f497 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 14 May 2026 16:48:22 +0530 Subject: [PATCH 05/32] Fix action --- .github/workflows/knip.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index 09b970a84c3d..b2b61aaf6def 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -35,7 +35,7 @@ jobs: id: pr-ref run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - - name: Setup Node (PR) + - name: Setup Node uses: ./.github/actions/composite/setupNode - name: Run knip on PR @@ -48,9 +48,6 @@ jobs: git fetch origin main --no-tags --depth=1 git checkout origin/main - - name: Setup Node (main) - uses: ./.github/actions/composite/setupNode - - name: Run knip on main run: KNIP=true npx knip --reporter json --no-exit-code > /tmp/knip-main.json env: From 5bcad4121ac526f42f22d39dc36b07467a8a9762 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 14 May 2026 16:57:00 +0530 Subject: [PATCH 06/32] Improve action --- .github/scripts/compareKnipReports.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/scripts/compareKnipReports.ts b/.github/scripts/compareKnipReports.ts index 203dc5eb5f60..8f0b09bf3072 100644 --- a/.github/scripts/compareKnipReports.ts +++ b/.github/scripts/compareKnipReports.ts @@ -159,6 +159,17 @@ printSection('New issues introduced:', added); printSection('Issues resolved:', resolved); if (addedTotal > 0) { + // Emit one annotation per new finding so GitHub surfaces them on the PR's Checks tab. + // GitHub renders up to 10 annotations per step; remaining entries stay in the full log above. + for (const [cat, items] of added) { + for (const id of items) { + const sepIdx = id.indexOf('::'); + const file = sepIdx > 0 ? id.slice(0, sepIdx) : ''; + const name = sepIdx > 0 ? id.slice(sepIdx + 2) : id; + const attrs = file ? `file=${file},title=Knip: new ${cat}` : `title=Knip: new ${cat}`; + console.log(`::error ${attrs}::${name}`); + } + } console.log(`\n::error::PR introduces ${addedTotal} new knip finding(s) (resolved ${resolvedTotal}, delta ${delta >= 0 ? '+' : ''}${delta}).`); process.exit(1); } From b13fadf95be3dd83e2abeee87f4c2a6f2b3d7e8e Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 14 May 2026 17:01:32 +0530 Subject: [PATCH 07/32] Improve action --- .github/scripts/compareKnipReports.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/compareKnipReports.ts b/.github/scripts/compareKnipReports.ts index 8f0b09bf3072..4b2ae492ad2d 100644 --- a/.github/scripts/compareKnipReports.ts +++ b/.github/scripts/compareKnipReports.ts @@ -166,8 +166,8 @@ if (addedTotal > 0) { const sepIdx = id.indexOf('::'); const file = sepIdx > 0 ? id.slice(0, sepIdx) : ''; const name = sepIdx > 0 ? id.slice(sepIdx + 2) : id; - const attrs = file ? `file=${file},title=Knip: new ${cat}` : `title=Knip: new ${cat}`; - console.log(`::error ${attrs}::${name}`); + const attrs = file ? `file=${file},title=Knip` : 'title=Knip'; + console.log(`::error ${attrs}::[${cat}] ${name}`); } } console.log(`\n::error::PR introduces ${addedTotal} new knip finding(s) (resolved ${resolvedTotal}, delta ${delta >= 0 ? '+' : ''}${delta}).`); From c18ffad362b7855143bcfa912691f98932c91b7f Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 14 May 2026 17:33:40 +0530 Subject: [PATCH 08/32] Improve action --- .github/scripts/compareKnipReports.ts | 54 +++++++++++++++++++-------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/.github/scripts/compareKnipReports.ts b/.github/scripts/compareKnipReports.ts index 4b2ae492ad2d..8e23e19ede98 100644 --- a/.github/scripts/compareKnipReports.ts +++ b/.github/scripts/compareKnipReports.ts @@ -42,24 +42,39 @@ type Report = { function parseReport(filepath: string): Report { if (!fs.existsSync(filepath)) { - return {issues: []}; - } - let raw = fs.readFileSync(filepath, 'utf8'); - // knip writes JSON to stdout, but babel.config.js debug logs can prepend noise. - // Trim everything before the first `{"issues"` token. - const i = raw.indexOf('{"issues"'); - if (i > 0) { - raw = raw.slice(i); + throw new Error(`Knip report not found: ${filepath}`); } + const raw = fs.readFileSync(filepath, 'utf8'); if (!raw.trim()) { - return {issues: []}; + throw new Error(`Knip report is empty: ${filepath}`); } - try { - return JSON.parse(raw) as Report; - } catch (e) { - console.error(`Failed to parse ${filepath}: ${(e as Error).message}`); - return {issues: []}; + + // knip writes a single top-level JSON object to stdout, but tooling around it + // can prepend noise (npm-run script header, babel.config.js debug logs, + // webpack-plugin warnings, etc.). The object can also be pretty-printed, so + // we can't rely on a fixed token like `{"issues"`. Locate every `{` and try + // to parse from there; accept the first slice that parses AND has an + // `issues` array. Anything else is a hard failure — the CI should not + // silently treat an unparseable report as "no findings". + let searchFrom = 0; + let lastParseError: Error | undefined; + while (true) { + const braceIdx = raw.indexOf('{', searchFrom); + if (braceIdx < 0) { + break; + } + try { + const parsed = JSON.parse(raw.slice(braceIdx)) as unknown; + if (parsed && typeof parsed === 'object' && Array.isArray((parsed as Report).issues)) { + return parsed as Report; + } + } catch (e) { + lastParseError = e as Error; + } + searchFrom = braceIdx + 1; } + const detail = lastParseError ? `: ${lastParseError.message}` : ''; + throw new Error(`Failed to parse knip JSON report at ${filepath}${detail}`); } function flatten(report: Report): Map> { @@ -139,8 +154,15 @@ if (!mainPath || !prPath) { process.exit(2); } -const mainFlat = flatten(parseReport(mainPath)); -const prFlat = flatten(parseReport(prPath)); +let mainFlat: Map>; +let prFlat: Map>; +try { + mainFlat = flatten(parseReport(mainPath)); + prFlat = flatten(parseReport(prPath)); +} catch (e) { + console.log(`::error::Knip comparator could not read a report: ${(e as Error).message}`); + process.exit(2); +} const mainTotal = totalCount(mainFlat); const prTotal = totalCount(prFlat); From e702af10b4b849692018827198ed4398a87a1775 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Fri, 15 May 2026 20:15:58 +0530 Subject: [PATCH 09/32] Improve action --- .github/workflows/knip.yml | 12 ++----- babel.config.js | 16 +++++---- knip.json | 2 +- .../scripts => scripts}/compareKnipReports.ts | 35 +++++++++++++------ 4 files changed, 37 insertions(+), 28 deletions(-) rename {.github/scripts => scripts}/compareKnipReports.ts (86%) diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index b2b61aaf6def..aff3283ae72f 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -31,17 +31,11 @@ jobs: # v6 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - name: Capture PR ref - id: pr-ref - run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - - name: Setup Node uses: ./.github/actions/composite/setupNode - name: Run knip on PR run: KNIP=true npx knip --reporter json --no-exit-code > /tmp/knip-pr.json - env: - CI: true - name: Checkout main run: | @@ -50,11 +44,9 @@ jobs: - name: Run knip on main run: KNIP=true npx knip --reporter json --no-exit-code > /tmp/knip-main.json - env: - CI: true - name: Restore PR workspace - run: git checkout ${{ steps.pr-ref.outputs.sha }} + run: git checkout ${{ github.sha }} - name: Compare reports - run: npx ts-node .github/scripts/compareKnipReports.ts /tmp/knip-main.json /tmp/knip-pr.json + run: npx ts-node ./scripts/compareKnipReports.ts -mainPath /tmp/knip-main.json -prPath /tmp/knip-pr.json diff --git a/babel.config.js b/babel.config.js index a7e8f5cad00e..cc38cc39b9c3 100644 --- a/babel.config.js +++ b/babel.config.js @@ -163,18 +163,22 @@ if (process.env.CAPTURE_METRICS === 'true') { } module.exports = (api) => { - console.debug('babel.config.js'); - console.debug(' - api.version:', api.version); - console.debug(' - api.env:', api.env()); - console.debug(' - process.env.NODE_ENV:', process.env.NODE_ENV); - console.debug(' - process.env.BABEL_ENV:', process.env.BABEL_ENV); + if (!process.env.KNIP) { + console.debug('babel.config.js'); + console.debug(' - api.version:', api.version); + console.debug(' - api.env:', api.env()); + console.debug(' - process.env.NODE_ENV:', process.env.NODE_ENV); + console.debug(' - process.env.BABEL_ENV:', process.env.BABEL_ENV); + } // For `react-native` (iOS/Android) caller will be "metro" // For `webpack` (Web) caller will be "@babel-loader" // For jest, it will be babel-jest // For `storybook` there won't be any config at all so we must give default argument of an empty object const runningIn = api.caller((args = {}) => args.name); - console.debug(' - running in: ', runningIn); + if (!process.env.KNIP) { + console.debug(' - running in: ', runningIn); + } return ['metro', 'babel-jest'].includes(runningIn) ? metro : webpack; }; diff --git a/knip.json b/knip.json index 833cb56cdc05..dafa20756021 100644 --- a/knip.json +++ b/knip.json @@ -53,7 +53,7 @@ "config": ["config/eslint/eslint.config.mjs", "eslint.changed.config.mjs"] }, "webpack": { - "config": ["config/webpack/webpack.common.ts", "config/webpack/webpack.dev.ts"] + "config": ["config/webpack/webpack.common.ts"] }, "babel": { "config": ["babel.config.js"] diff --git a/.github/scripts/compareKnipReports.ts b/scripts/compareKnipReports.ts similarity index 86% rename from .github/scripts/compareKnipReports.ts rename to scripts/compareKnipReports.ts index 8e23e19ede98..d08536765447 100644 --- a/.github/scripts/compareKnipReports.ts +++ b/scripts/compareKnipReports.ts @@ -1,14 +1,18 @@ import fs from 'fs'; import type {TupleToUnion} from 'type-fest'; +import CLI from './utils/CLI'; /** - * Compare two knip JSON reports (main vs PR). - * Exit 1 if the PR introduces any new finding that isn't present on main, regardless - * of whether the PR also resolves others. Findings are matched per `::`, - * so a single file with multiple unused items in the same category counts as one - * finding per item. + * Knip (https://knip.dev) is a static analyzer that flags unused files, exports, + * types, dependencies, and unlisted imports across the codebase. Project-specific + * scope and ignores live in `knip.json`. * - * Usage: ts-node scripts/compareKnipReports.ts + * This script compares two knip JSON reports (main vs PR) and exits 1 if the PR + * introduces any new finding that isn't present on main — even when the PR also + * resolves others. Findings are matched per `::`, so a single file + * with multiple unused items counts as one finding per item. + * + * Usage: ts-node scripts/compareKnipReports.ts --mainPath --prPath */ const CATEGORIES = [ @@ -148,11 +152,20 @@ function printSection(title: string, byCategory: Map): void } } -const [mainPath, prPath] = process.argv.slice(2); -if (!mainPath || !prPath) { - console.error('Usage: ts-node compareKnipReports.ts '); - process.exit(2); -} +const cli = new CLI({ + namedArgs: { + mainPath: { + description: 'Path to the main knip report JSON file', + required: true, + }, + prPath: { + description: 'Path to the PR knip report JSON file', + required: true, + }, + }, +}); + +const {mainPath, prPath} = cli.namedArgs; let mainFlat: Map>; let prFlat: Map>; From 53960635336f21eda6d9bf30bb21db615b3194f7 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Fri, 15 May 2026 20:56:57 +0530 Subject: [PATCH 10/32] Improve action --- .github/workflows/knip.yml | 2 +- scripts/compareKnipReports.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index aff3283ae72f..e406de19734b 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -49,4 +49,4 @@ jobs: run: git checkout ${{ github.sha }} - name: Compare reports - run: npx ts-node ./scripts/compareKnipReports.ts -mainPath /tmp/knip-main.json -prPath /tmp/knip-pr.json + run: npx ts-node ./scripts/compareKnipReports.ts --mainPath=/tmp/knip-main.json --prPath=/tmp/knip-pr.json diff --git a/scripts/compareKnipReports.ts b/scripts/compareKnipReports.ts index d08536765447..029da17e6c0d 100644 --- a/scripts/compareKnipReports.ts +++ b/scripts/compareKnipReports.ts @@ -12,7 +12,7 @@ import CLI from './utils/CLI'; * resolves others. Findings are matched per `::`, so a single file * with multiple unused items counts as one finding per item. * - * Usage: ts-node scripts/compareKnipReports.ts --mainPath --prPath + * Usage: ts-node scripts/compareKnipReports.ts --mainPath= --prPath= */ const CATEGORIES = [ @@ -59,7 +59,7 @@ function parseReport(filepath: string): Report { // we can't rely on a fixed token like `{"issues"`. Locate every `{` and try // to parse from there; accept the first slice that parses AND has an // `issues` array. Anything else is a hard failure — the CI should not - // silently treat an unparseable report as "no findings". + // silently treat a malformed report as "no findings". let searchFrom = 0; let lastParseError: Error | undefined; while (true) { From d938c2db180ccefa7c14bcfc81cf5ee821bdf6a9 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Fri, 15 May 2026 21:17:09 +0530 Subject: [PATCH 11/32] Removed unused export --- config/eslint/eslint.seatbelt.tsv | 1 - .../sections/ReceiptSection.tsx | 1 - .../Table/EditableCell/EditingCellContext.tsx | 3 +- src/components/Table/EditableCell/index.ts | 2 +- src/libs/LauncherStack.ts | 2 +- .../addRootHistoryRouterExtensionUtils.ts | 2 +- src/libs/PolicyUtils.ts | 1 - .../handleFileRetry.ts | 58 ------------------- .../index.android.ts | 21 ------- src/libs/ReceiptUploadRetryHandler/index.ts | 20 ------- src/libs/ScreenFocusArbiter.ts | 1 - src/libs/compoundParamsKey.ts | 2 +- src/selectors/Policy.ts | 3 - src/types/onyx/Policy.ts | 2 - 14 files changed, 5 insertions(+), 114 deletions(-) delete mode 100644 src/libs/ReceiptUploadRetryHandler/handleFileRetry.ts delete mode 100644 src/libs/ReceiptUploadRetryHandler/index.android.ts delete mode 100644 src/libs/ReceiptUploadRetryHandler/index.ts diff --git a/config/eslint/eslint.seatbelt.tsv b/config/eslint/eslint.seatbelt.tsv index 4ab355104f7d..c6b766069dbe 100644 --- a/config/eslint/eslint.seatbelt.tsv +++ b/config/eslint/eslint.seatbelt.tsv @@ -298,7 +298,6 @@ "../../src/libs/PersonalDetailsUtils.ts" "rulesdir/no-onyx-connect" 2 "../../src/libs/Pusher/index.native.ts" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1 "../../src/libs/Pusher/index.ts" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1 -"../../src/libs/ReceiptUploadRetryHandler/handleFileRetry.ts" "no-restricted-syntax" 2 "../../src/libs/ReportActionItemEventHandler/index.android.ts" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1 "../../src/libs/ReportActionsUtils.ts" "@typescript-eslint/no-deprecated/getReportName" 2 "../../src/libs/ReportActionsUtils.ts" "@typescript-eslint/no-deprecated/getReportNameCallback" 1 diff --git a/src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx b/src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx index 1ceb128295bc..f7e3e1ca0ab3 100644 --- a/src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx +++ b/src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx @@ -168,4 +168,3 @@ function ReceiptSection({ } export default ReceiptSection; -export type {ReceiptSectionProps}; diff --git a/src/components/Table/EditableCell/EditingCellContext.tsx b/src/components/Table/EditableCell/EditingCellContext.tsx index 87b0e75246b3..091217bfc591 100644 --- a/src/components/Table/EditableCell/EditingCellContext.tsx +++ b/src/components/Table/EditableCell/EditingCellContext.tsx @@ -79,5 +79,4 @@ function useEditingCellActions(): EditingCellActionsContextType { } export default EditingCellProvider; -export {EditingCellActionsContext, EditingCellStateContext, useEditingCellActions, useEditingCellState}; -export type {EditingCellActionsContextType, EditingCellStateContextType}; +export {useEditingCellActions, useEditingCellState}; diff --git a/src/components/Table/EditableCell/index.ts b/src/components/Table/EditableCell/index.ts index fa46e271a8ad..97412b9e7e7a 100644 --- a/src/components/Table/EditableCell/index.ts +++ b/src/components/Table/EditableCell/index.ts @@ -1,6 +1,6 @@ export {default as EditableCell} from './EditableCell'; export {default as EditingCellProvider} from './EditingCellContext'; -export {useEditingCellActions, useEditingCellState} from './EditingCellContext'; +export {useEditingCellState} from './EditingCellContext'; export {default as useInlineEditState} from './useInlineEditState'; export {default as usePopoverEditState} from './usePopoverEditState'; export type {EditableProps} from './types'; diff --git a/src/libs/LauncherStack.ts b/src/libs/LauncherStack.ts index 3ae73ab9c4eb..963cfafb0b0b 100644 --- a/src/libs/LauncherStack.ts +++ b/src/libs/LauncherStack.ts @@ -100,4 +100,4 @@ function resetLauncherStackForTests(): void { hasWarnedAboutOverflow = false; } -export {pickLauncher, consumeLauncher, setActivePopoverLauncher, scheduleClearActivePopoverLauncher, resetLauncherStackForTests, LAUNCHER_CLEAR_DELAY_MS, LAUNCHER_STACK_MAX}; +export {pickLauncher, consumeLauncher, setActivePopoverLauncher, scheduleClearActivePopoverLauncher, resetLauncherStackForTests}; diff --git a/src/libs/Navigation/AppNavigator/routerExtensions/addRootHistoryRouterExtensionUtils.ts b/src/libs/Navigation/AppNavigator/routerExtensions/addRootHistoryRouterExtensionUtils.ts index f7e3b7a2099e..a7bc45d07600 100644 --- a/src/libs/Navigation/AppNavigator/routerExtensions/addRootHistoryRouterExtensionUtils.ts +++ b/src/libs/Navigation/AppNavigator/routerExtensions/addRootHistoryRouterExtensionUtils.ts @@ -157,7 +157,7 @@ function applyRevealPaddingOffset(state: RootHistoryState, rehydrated: RootHisto return rehydrated; } -export type {PendingReveal, RehydrateRootHistoryState, RootHistoryState}; +export type {PendingReveal, RootHistoryState}; export { applyRevealPaddingOffset, getFrozenHistoryStateForRemoveFullscreenUnderRHP, diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 898ea904b30c..0cc3f0f2261c 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -2356,7 +2356,6 @@ export { getHRConnectionNames, isGustoConnected, isSubmitPolicy, - isPolicyEditor, }; export type {MemberEmailsToAccountIDs}; diff --git a/src/libs/ReceiptUploadRetryHandler/handleFileRetry.ts b/src/libs/ReceiptUploadRetryHandler/handleFileRetry.ts deleted file mode 100644 index 36a4fdee2415..000000000000 --- a/src/libs/ReceiptUploadRetryHandler/handleFileRetry.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type * as IOU from '@userActions/IOU'; -import type {RequestMoneyInformation} from '@userActions/IOU/MoneyRequestBuilder'; -import {replaceReceipt} from '@userActions/IOU/Receipt'; -import {startSplitBill} from '@userActions/IOU/Split'; -import * as TrackExpense from '@userActions/IOU/TrackExpense'; -import CONST from '@src/CONST'; -import type {ReceiptError} from '@src/types/onyx/Transaction'; - -export default function handleFileRetry(message: ReceiptError, file: File, dismissError: () => void, setShouldShowErrorModal: (value: boolean) => void) { - if (!message.action || !message.retryParams) { - setShouldShowErrorModal(true); - return; - } - - const retryParams: IOU.ReplaceReceipt | IOU.StartSplitBilActionParams | TrackExpense.CreateTrackExpenseParams | RequestMoneyInformation = - typeof message.retryParams === 'string' - ? (JSON.parse(message.retryParams) as IOU.ReplaceReceipt | IOU.StartSplitBilActionParams | TrackExpense.CreateTrackExpenseParams | RequestMoneyInformation) - : message.retryParams; - - switch (message.action) { - case CONST.IOU.ACTION_PARAMS.REPLACE_RECEIPT: { - dismissError(); - const replaceReceiptParams = {...retryParams} as IOU.ReplaceReceipt; - replaceReceiptParams.file = file; - replaceReceipt(replaceReceiptParams); - break; - } - case CONST.IOU.ACTION_PARAMS.START_SPLIT_BILL: { - dismissError(); - const startSplitBillParams = {...retryParams} as IOU.StartSplitBilActionParams; - startSplitBillParams.receipt = file; - startSplitBillParams.shouldPlaySound = false; - startSplitBill(startSplitBillParams); - break; - } - case CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE: { - dismissError(); - const trackExpenseParams = {...retryParams} as TrackExpense.CreateTrackExpenseParams; - trackExpenseParams.transactionParams.receipt = file; - trackExpenseParams.isRetry = true; - trackExpenseParams.shouldPlaySound = false; - TrackExpense.trackExpense(trackExpenseParams); - break; - } - case CONST.IOU.ACTION_PARAMS.MONEY_REQUEST: { - dismissError(); - const requestMoneyParams = {...retryParams} as RequestMoneyInformation; - requestMoneyParams.transactionParams.receipt = file; - requestMoneyParams.isRetry = true; - requestMoneyParams.shouldPlaySound = false; - TrackExpense.requestMoney(requestMoneyParams); - break; - } - default: - setShouldShowErrorModal(true); - break; - } -} diff --git a/src/libs/ReceiptUploadRetryHandler/index.android.ts b/src/libs/ReceiptUploadRetryHandler/index.android.ts deleted file mode 100644 index ffaf6f3ce34c..000000000000 --- a/src/libs/ReceiptUploadRetryHandler/index.android.ts +++ /dev/null @@ -1,21 +0,0 @@ -import RNFS from 'react-native-fs'; -import type {ReceiptError} from '@src/types/onyx/Transaction'; -import handleFileRetry from './handleFileRetry'; - -export default function handleRetryPress(message: ReceiptError, dismissError: () => void, setShouldShowErrorModal: (value: boolean) => void) { - if (!message.source) { - return; - } - // Android-specific logic using RNFS - const filePath = message.source.replace('file://', ''); - RNFS.readFile(filePath, 'base64') - .then((fileContent) => { - const file = new File([fileContent], message.filename, {type: 'image/jpeg'}); - file.uri = message.source; - file.source = message.source; - handleFileRetry(message, file, dismissError, setShouldShowErrorModal); - }) - .catch(() => { - setShouldShowErrorModal(true); - }); -} diff --git a/src/libs/ReceiptUploadRetryHandler/index.ts b/src/libs/ReceiptUploadRetryHandler/index.ts deleted file mode 100644 index 7a517fd5ef1c..000000000000 --- a/src/libs/ReceiptUploadRetryHandler/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type {ReceiptError} from '@src/types/onyx/Transaction'; -import handleFileRetry from './handleFileRetry'; - -export default function handleRetryPress(message: ReceiptError, dismissError: () => void, setShouldShowErrorModal: (value: boolean) => void) { - if (!message.source) { - return; - } - - fetch(message.source) - .then((res) => res.blob()) - .then((blob) => { - const reconstructedFile = new File([blob], message.filename); - reconstructedFile.uri = message.source; - reconstructedFile.source = message.source; - handleFileRetry(message, reconstructedFile, dismissError, setShouldShowErrorModal); - }) - .catch(() => { - setShouldShowErrorModal(true); - }); -} diff --git a/src/libs/ScreenFocusArbiter.ts b/src/libs/ScreenFocusArbiter.ts index 020aadd3fd08..c24756f4b9b3 100644 --- a/src/libs/ScreenFocusArbiter.ts +++ b/src/libs/ScreenFocusArbiter.ts @@ -45,4 +45,3 @@ function isCycleIdle(): boolean { } export {tryClaim, resetCycle, isCycleIdle, Priorities, CYCLE_TIMEOUT_MS}; -export type {Priority}; diff --git a/src/libs/compoundParamsKey.ts b/src/libs/compoundParamsKey.ts index 8e20426379fa..0a7529af83c3 100644 --- a/src/libs/compoundParamsKey.ts +++ b/src/libs/compoundParamsKey.ts @@ -65,4 +65,4 @@ function compoundParamsKey(routeKey: string, params: unknown): string { } export default compoundParamsKey; -export {COMPOUND_KEY_DELIMITER, UNDEFINED_SENTINEL, normalizeForKey}; +export {COMPOUND_KEY_DELIMITER, normalizeForKey}; diff --git a/src/selectors/Policy.ts b/src/selectors/Policy.ts index baac00cdb80b..a323beeab05f 100644 --- a/src/selectors/Policy.ts +++ b/src/selectors/Policy.ts @@ -262,9 +262,6 @@ export { groupPaidPoliciesWithExpenseChatEnabledSelector, iouRequestPolicyCollectionSelector, policyMapper, - adminPoliciesConnectedToSageIntacctSelector, - adminPoliciesConnectedToCertiniaSelector, - adminPoliciesConnectedToNetSuiteSelector, adminPoliciesConnectedToQBDSelector, reusablePoliciesConnectedToSelector, hasPoliciesConnectedToQBDSelector, diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 808d698b9e2e..f735516973d0 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -2412,8 +2412,6 @@ export type { SageIntacctDataElement, SageIntacctConnectionsConfig, SageIntacctExportConfig, - FinancialForceConnectionConfig, - FinancialForceConnectionData, ACHAccount, ApprovalRule, ExpenseRule, From 1c3911b271d3928746ca91952d2f1ba02ce92c1f Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Fri, 15 May 2026 21:28:07 +0530 Subject: [PATCH 12/32] Fix ts --- src/types/onyx/Policy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index f735516973d0..9f6aca216ec8 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -2412,6 +2412,7 @@ export type { SageIntacctDataElement, SageIntacctConnectionsConfig, SageIntacctExportConfig, + FinancialForceConnectionConfig, ACHAccount, ApprovalRule, ExpenseRule, From 19bd514fa9b9f6cc9137cdbf9f8d7c5c37aa75e0 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 16 May 2026 10:27:01 +0530 Subject: [PATCH 13/32] Removed unused export --- src/components/GustoSyncResultsModal.tsx | 2 +- src/libs/API/GustoSyncResult.ts | 2 +- src/libs/ReportUtils.ts | 1 - .../report/ReportActionEditMessageContext.tsx | 10 ++-------- .../report/useActiveDraftReportAction.ts | 2 -- .../useDraftMessageVideoAttributeCache.ts | 1 - .../Agents/pendingAgentAvatarStore.ts | 1 - src/selectors/ReportAction.ts | 20 ++----------------- src/types/onyx/Policy.ts | 2 +- 9 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/components/GustoSyncResultsModal.tsx b/src/components/GustoSyncResultsModal.tsx index 7f771b4bdb3c..c768005058f2 100644 --- a/src/components/GustoSyncResultsModal.tsx +++ b/src/components/GustoSyncResultsModal.tsx @@ -4,7 +4,7 @@ import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hook import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {GustoSyncResult} from '@libs/API/GustoSyncResult'; +import type GustoSyncResult from '@libs/API/GustoSyncResult'; import CONST from '@src/CONST'; import Button from './Button'; import FixedFooter from './FixedFooter'; diff --git a/src/libs/API/GustoSyncResult.ts b/src/libs/API/GustoSyncResult.ts index 79c497f0fcc9..425beb7a799f 100644 --- a/src/libs/API/GustoSyncResult.ts +++ b/src/libs/API/GustoSyncResult.ts @@ -10,4 +10,4 @@ type GustoSyncResult = { skippedEmployees?: GustoSyncSkippedEmployee[]; }; -export type {GustoSyncResult, GustoSyncSkippedEmployee}; +export default GustoSyncResult; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8f689fa18919..bd1fe8febe66 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -13735,7 +13735,6 @@ export type { OptionData, TransactionDetails, PartialReportAction, - ParsingDetails, SelfDMParameters, OptimisticReportAction, CreateDraftTransactionParams, diff --git a/src/pages/inbox/report/ReportActionEditMessageContext.tsx b/src/pages/inbox/report/ReportActionEditMessageContext.tsx index 5b6d38fea590..396c18240bfc 100644 --- a/src/pages/inbox/report/ReportActionEditMessageContext.tsx +++ b/src/pages/inbox/report/ReportActionEditMessageContext.tsx @@ -189,11 +189,5 @@ function useReportActionActiveEditActions() { return useContext(ReportActionEditMessageActionsContext); } -export { - ReportActionEditMessageContextProvider, - ReportScreenEditMessageProviderWithTransactionThread, - useReportActionActiveEdit, - useReportActionActiveEditActions, - ReportActionEditMessageContext, -}; -export type {ReportActionActiveEdit, ReportActionEditMessageContextValue, ReportActionEditMessageState}; +export {ReportActionEditMessageContextProvider, ReportScreenEditMessageProviderWithTransactionThread, useReportActionActiveEdit, useReportActionActiveEditActions}; +export type {ReportActionEditMessageState}; diff --git a/src/pages/inbox/report/useActiveDraftReportAction.ts b/src/pages/inbox/report/useActiveDraftReportAction.ts index b1c1657c6467..a58fbfd7e5fe 100644 --- a/src/pages/inbox/report/useActiveDraftReportAction.ts +++ b/src/pages/inbox/report/useActiveDraftReportAction.ts @@ -211,5 +211,3 @@ function useActiveDraftReportAction({reportID, effectiveTransactionThreadReportI } export default useActiveDraftReportAction; - -export type {ResolvedActiveDraftEdit}; diff --git a/src/pages/inbox/report/useDraftMessageVideoAttributeCache.ts b/src/pages/inbox/report/useDraftMessageVideoAttributeCache.ts index 8124ec8b2378..419cf02ec415 100644 --- a/src/pages/inbox/report/useDraftMessageVideoAttributeCache.ts +++ b/src/pages/inbox/report/useDraftMessageVideoAttributeCache.ts @@ -50,4 +50,3 @@ function useDraftMessageVideoAttributeCache({ export default useDraftMessageVideoAttributeCache; export {draftMessageVideoAttributeCache}; -export type {DraftMessageVideoAttributeCache}; diff --git a/src/pages/settings/Agents/pendingAgentAvatarStore.ts b/src/pages/settings/Agents/pendingAgentAvatarStore.ts index b98e0cc98b94..7edce661a4fd 100644 --- a/src/pages/settings/Agents/pendingAgentAvatarStore.ts +++ b/src/pages/settings/Agents/pendingAgentAvatarStore.ts @@ -38,5 +38,4 @@ function consumeNavigationToken(): boolean { return token; } -export type {PendingAvatar, PendingPresetAvatar, PendingFileAvatar}; export {setInitialPresetID, getInitialPresetID, setPendingAvatar, getPendingAvatar, clearPendingAvatar, setNavigationToken, consumeNavigationToken}; diff --git a/src/selectors/ReportAction.ts b/src/selectors/ReportAction.ts index 8c46a3772a26..3b90a3a766a4 100644 --- a/src/selectors/ReportAction.ts +++ b/src/selectors/ReportAction.ts @@ -1,8 +1,7 @@ import lodashFindLast from 'lodash/findLast'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import {filterOutDeprecatedReportActions, getSortedReportActions} from '@libs/ReportActionsUtils'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import type {ReportAction, ReportActions} from '@src/types/onyx'; function getParentReportActionSelector(parentReportActions: OnyxEntry, parentReportActionID?: string): OnyxEntry { @@ -33,21 +32,6 @@ function getLastClosedReportAction(reportActions: OnyxEntry): Ony return lodashFindLast(sortedReportActions, (action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED); } -/** - * Selector that filters a report actions collection to only include actions for the specified report IDs. - */ -function getReportActionsForReportIDs(allReportActions: OnyxCollection, reportIDs: string[]): OnyxCollection { - if (!allReportActions || reportIDs.length === 0) { - return {}; - } - const filteredReportActions: OnyxCollection = {}; - for (const reportID of reportIDs) { - const key = `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`; - filteredReportActions[key] = allReportActions[key]; - } - return filteredReportActions; -} - function getReportActionByIDSelector(reportActions: OnyxEntry, reportActionID?: string): OnyxEntry { if (!reportActions || !reportActionID) { return; @@ -55,4 +39,4 @@ function getReportActionByIDSelector(reportActions: OnyxEntry, re return reportActions[reportActionID]; } -export {getParentReportActionSelector, getLastClosedReportAction, getReportActionsForReportIDs, getReportActionByIDSelector}; +export {getParentReportActionSelector, getLastClosedReportAction, getReportActionByIDSelector}; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 9f6aca216ec8..51194cde0ae6 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1,6 +1,6 @@ import type {CONST as COMMON_CONST} from 'expensify-common'; import type {ValueOf} from 'type-fest'; -import type {GustoSyncResult} from '@libs/API/GustoSyncResult'; +import type GustoSyncResult from '@libs/API/GustoSyncResult'; import type CONST from '@src/CONST'; import type {Country} from '@src/CONST'; import type * as OnyxTypes from '.'; From d000299fddf144498e5937d0be82cdfa27fed484 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 16 May 2026 11:18:34 +0530 Subject: [PATCH 14/32] Add knip-changed script --- package.json | 1 + scripts/knip-changed.sh | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100755 scripts/knip-changed.sh diff --git a/package.json b/package.json index 65c1553728bb..724268e50cdc 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "knip": "KNIP=true knip --include dependencies --exclude unlisted --no-exit-code --reporter compact", "knip:full": "KNIP=true knip --reporter compact", "knip:json": "KNIP=true knip --reporter json --no-exit-code", + "knip-changed": "./scripts/knip-changed.sh", "shellcheck": "./scripts/shellCheck.sh", "spell": "cspell --color **/*", "spell-changed": "cspell --color --no-must-find-files", diff --git a/scripts/knip-changed.sh b/scripts/knip-changed.sh new file mode 100755 index 000000000000..d57e54a287d3 --- /dev/null +++ b/scripts/knip-changed.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# +# Run the same knip delta check the CI workflow runs, against your local main. +# Generates knip reports for the current branch and main, then compares them +# with scripts/compareKnipReports.ts. +# +# Uses a temporary git worktree so your working directory is untouched. +# Reuses your current node_modules (symlinked) — fine for static analysis as +# long as dependencies haven't changed dramatically. If main has drifted +# locally, run `git pull --rebase origin main` first; this script will not +# fetch on your behalf. +# +set -euo pipefail + +WORKTREE_DIR=$(mktemp -d /tmp/knip-main-worktree.XXXXXX) +CURRENT_REPORT=$(mktemp /tmp/knip-current.XXXXXX.json) +MAIN_REPORT=$(mktemp /tmp/knip-main.XXXXXX.json) + +cleanup() { + git worktree remove --force "$WORKTREE_DIR" 2>/dev/null || rm -rf "$WORKTREE_DIR" + rm -f "$CURRENT_REPORT" "$MAIN_REPORT" +} +trap cleanup EXIT + +echo "Running knip on current branch..." +npm run knip:json > "$CURRENT_REPORT" + +echo "Running knip on main..." +git worktree add --detach "$WORKTREE_DIR" main >/dev/null +ln -s "$PWD/node_modules" "$WORKTREE_DIR/node_modules" +(cd "$WORKTREE_DIR" && npm run knip:json) > "$MAIN_REPORT" + +echo "" +npx ts-node ./scripts/compareKnipReports.ts --mainPath="$MAIN_REPORT" --prPath="$CURRENT_REPORT" From 12ddc1aa0024866bb6a3a5bd321e4238077a8ec2 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 16 May 2026 11:21:24 +0530 Subject: [PATCH 15/32] Fix cspell --- cspell.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cspell.json b/cspell.json index 6992446943a2..599c87b01b01 100644 --- a/cspell.json +++ b/cspell.json @@ -930,7 +930,8 @@ "Kolkata", "lintrk", "Fbclid", - "Gclid" + "Gclid", + "knip" ], "ignorePaths": [ ".gitignore", From 93365a8a971f9d7dde663c6a4e2f76312a7c16f0 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 16 May 2026 11:28:06 +0530 Subject: [PATCH 16/32] Update knip version --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a1ed2ae516a..198589f37bd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -259,7 +259,7 @@ "jest-expo": "55.0.6", "jest-transformer-svg": "^2.0.1", "jest-when": "^3.5.2", - "knip": "^6.13.1", + "knip": "^6.14.0", "link": "^2.1.1", "memfs": "^4.6.0", "mini-css-extract-plugin": "^2.9.4", @@ -30887,9 +30887,9 @@ } }, "node_modules/knip": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/knip/-/knip-6.13.1.tgz", - "integrity": "sha512-hvSnb+YDpDWW1LXub4U0JFfkQhscwgInWuQOv99WTutPZavf1cEP3GwxzEzO2JJpGI9yATk6l0jPLY1V3fp1sQ==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/knip/-/knip-6.14.0.tgz", + "integrity": "sha512-yEI9ysdGQ3h77gLObvovH0KUYs6ITtJ1f6owmXRalOO32TbolYvHY7Z+2AEOXqw0ZWeh9219/agh2K/GmtfsxQ==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index 724268e50cdc..5fd4b0bad631 100644 --- a/package.json +++ b/package.json @@ -327,7 +327,7 @@ "jest-expo": "55.0.6", "jest-transformer-svg": "^2.0.1", "jest-when": "^3.5.2", - "knip": "^6.13.1", + "knip": "^6.14.0", "link": "^2.1.1", "memfs": "^4.6.0", "mini-css-extract-plugin": "^2.9.4", From 6844c16dd9e5b385defc4d82b089beddb78dce7e Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 18 May 2026 21:22:42 +0530 Subject: [PATCH 17/32] Removed unused export --- src/hooks/usePersonalDetailSearchSelector/base.ts | 2 +- src/libs/actions/IOU/submitWithDismissFirst.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/usePersonalDetailSearchSelector/base.ts b/src/hooks/usePersonalDetailSearchSelector/base.ts index 10b22dfe2fc9..9ce610b55254 100644 --- a/src/hooks/usePersonalDetailSearchSelector/base.ts +++ b/src/hooks/usePersonalDetailSearchSelector/base.ts @@ -285,4 +285,4 @@ function usePersonalDetailSearchSelectorBase({ } export default usePersonalDetailSearchSelectorBase; -export type {ContactState, UseSearchSelectorConfig, UseSearchSelectorReturn, SearchSelectorSelectionMode}; +export type {ContactState, UseSearchSelectorConfig, UseSearchSelectorReturn}; diff --git a/src/libs/actions/IOU/submitWithDismissFirst.ts b/src/libs/actions/IOU/submitWithDismissFirst.ts index 68174cf762da..2e3e71106a5e 100644 --- a/src/libs/actions/IOU/submitWithDismissFirst.ts +++ b/src/libs/actions/IOU/submitWithDismissFirst.ts @@ -121,4 +121,4 @@ function submitWithDismissFirst({executeWrite, destinationReportID, telemetryCon } export {submitWithDismissFirst}; -export type {DismissFirstSubmitOptions, WriteOverrides}; +export type {WriteOverrides}; From 41294350524bf4b1cd2344c45cb9a4ad83c36965 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 19 May 2026 08:34:10 +0530 Subject: [PATCH 18/32] Improve action --- .github/workflows/knip.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index e406de19734b..5581399c42e5 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -24,7 +24,6 @@ concurrency: jobs: knip-compare: name: Compare knip issues against main - if: ${{ github.actor != 'OSBotify' }} runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout PR From 40de85e8ce59c5ce91586cec80fd32a0328a3db0 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 20 May 2026 22:37:52 +0530 Subject: [PATCH 19/32] Removed unused export --- src/hooks/usePopoverPosition.ts | 1 - src/hooks/useSearchSections.ts | 3 +-- src/libs/PolicyUtils.ts | 2 +- src/libs/actions/IOU/MoneyRequest.ts | 1 - src/libs/actions/Policy/CopyPolicySettings.ts | 2 +- src/types/onyx/Policy.ts | 3 --- 6 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/hooks/usePopoverPosition.ts b/src/hooks/usePopoverPosition.ts index 4910f847f52f..650983b377b1 100644 --- a/src/hooks/usePopoverPosition.ts +++ b/src/hooks/usePopoverPosition.ts @@ -74,4 +74,3 @@ function usePopoverPosition() { export default usePopoverPosition; export {computeAnchorPosition}; -export type {MeasurableRef}; diff --git a/src/hooks/useSearchSections.ts b/src/hooks/useSearchSections.ts index 7c1f1d012377..12d30dc88ce6 100644 --- a/src/hooks/useSearchSections.ts +++ b/src/hooks/useSearchSections.ts @@ -7,7 +7,7 @@ import useActionLoadingReportIDs from './useActionLoadingReportIDs'; import useArchivedReportsIdSet from './useArchivedReportsIdSet'; import {useCurrencyListActions} from './useCurrencyList'; import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; -import useFilterPendingDeleteReports, {selectPendingDeleteReportKeys} from './useFilterPendingDeleteReports'; +import useFilterPendingDeleteReports from './useFilterPendingDeleteReports'; import useLocalize from './useLocalize'; import useOnyx from './useOnyx'; import useReportAttributes from './useReportAttributes'; @@ -72,5 +72,4 @@ function useSearchSections(): UseSearchSectionsResult { return {allReports: useFilterPendingDeleteReports(results), isSearchLoading: !!currentSearchResults?.search?.isLoading, lastSearchQuery}; } -export {selectPendingDeleteReportKeys}; export default useSearchSections; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 888cb5dcd48e..2b405cad3e39 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -2455,4 +2455,4 @@ export { isSubmitPolicy, }; -export type {MemberEmailsToAccountIDs, HRProviderInfo}; +export type {MemberEmailsToAccountIDs}; diff --git a/src/libs/actions/IOU/MoneyRequest.ts b/src/libs/actions/IOU/MoneyRequest.ts index 53ae8e87dd58..bb180ffef86b 100644 --- a/src/libs/actions/IOU/MoneyRequest.ts +++ b/src/libs/actions/IOU/MoneyRequest.ts @@ -1446,7 +1446,6 @@ export { setCustomUnitID, setMoneyRequestDistance, setMoneyRequestDistanceRate, - setMoneyRequestReceiptState, setMoneyRequestAmount, clearMoneyRequestAmount, clearMoneyRequestMerchant, diff --git a/src/libs/actions/Policy/CopyPolicySettings.ts b/src/libs/actions/Policy/CopyPolicySettings.ts index 844408f7c22c..9943001a1072 100644 --- a/src/libs/actions/Policy/CopyPolicySettings.ts +++ b/src/libs/actions/Policy/CopyPolicySettings.ts @@ -297,5 +297,5 @@ function copyPolicySettings( write(WRITE_COMMANDS.COPY_POLICY_SETTINGS, params, {optimisticData, successData, failureData}); } -export {PARTS_TO_POLICY_FIELDS, setCopyPolicySettingsData, clearCopyPolicySettings, requestCopyPolicySettingsNotification, buildCopyPolicySettingsData, copyPolicySettings}; +export {setCopyPolicySettingsData, clearCopyPolicySettings, requestCopyPolicySettingsNotification, buildCopyPolicySettingsData, copyPolicySettings}; export type {Part}; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index dbf0f5de2c36..5b88e901c8b2 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -2435,7 +2435,4 @@ export type { Subrate, ProhibitedExpenses, NetSuiteConnectionData, - HRConnectionConfigBase, - MergeHRConnectionConfig, - MergeHRConnectionData, }; From bc1217e9c85c3f0ee722f4b1cf196e988af172b1 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 20 May 2026 22:46:12 +0530 Subject: [PATCH 20/32] Fix ts --- src/libs/PolicyUtils.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 35a4bd53cf1f..1d1ccacd9fb9 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -2546,8 +2546,4 @@ export { isSubmitPolicy, }; -<<<<<<< knip-config -export type {MemberEmailsToAccountIDs}; -======= -export type {MemberEmailsToAccountIDs, PolicyFeature, PolicyFeatureAccess, HRProviderInfo}; ->>>>>>> main +export type {MemberEmailsToAccountIDs, PolicyFeature}; From d55edaedf752b7292243355b6a146b8dcc1b5d13 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 20 May 2026 23:05:34 +0530 Subject: [PATCH 21/32] Removed unused export --- src/libs/actions/EmojiReactions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/EmojiReactions.ts b/src/libs/actions/EmojiReactions.ts index 9322bde3d539..0064864370c9 100644 --- a/src/libs/actions/EmojiReactions.ts +++ b/src/libs/actions/EmojiReactions.ts @@ -147,4 +147,4 @@ function toggleEmojiReaction( addEmojiReaction(originalReportID, reportAction.reportActionID, emoji, skinTone, currentUserAccountID); } -export {addEmojiReaction, removeEmojiReaction, toggleEmojiReaction}; +export {toggleEmojiReaction}; From 7e2e013e25df6811fe2b10e4173f01b6317f6e9b Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 20 May 2026 23:17:29 +0530 Subject: [PATCH 22/32] Fix ESLint --- src/libs/actions/EmojiReactions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/EmojiReactions.ts b/src/libs/actions/EmojiReactions.ts index 0064864370c9..5a24ae8b329f 100644 --- a/src/libs/actions/EmojiReactions.ts +++ b/src/libs/actions/EmojiReactions.ts @@ -147,4 +147,5 @@ function toggleEmojiReaction( addEmojiReaction(originalReportID, reportAction.reportActionID, emoji, skinTone, currentUserAccountID); } +// eslint-disable-next-line import/prefer-default-export export {toggleEmojiReaction}; From 4898314f0a1c03fbe19ef7b62bd87f3a847a4288 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 23 May 2026 19:26:10 +0530 Subject: [PATCH 23/32] Add more files --- src/CONST/index.ts | 9 +-------- src/components/HRSyncResultsModal.tsx | 2 +- .../VictoryChartRenderer/context/VictoryChartContext.tsx | 1 - .../HTMLRenderers/VictoryChartRenderer/types.ts | 1 - .../MoneyRequestConfirmationList/sections/selectors.ts | 1 - src/libs/API/HrSyncResult.ts | 2 +- src/types/onyx/Policy.ts | 3 +-- 7 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index c069657e93a9..43142ace5520 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -9257,13 +9257,6 @@ const CONTINUATION_DETECTION_SEARCH_FILTER_KEYS = [ CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE, ] as SearchFilterKey[]; -const TASK_TO_FEATURE: Record = { - [CONST.ONBOARDING_TASK_TYPE.SETUP_CATEGORIES]: CONST.POLICY.MORE_FEATURES.ARE_CATEGORIES_ENABLED, - [CONST.ONBOARDING_TASK_TYPE.ADD_ACCOUNTING_INTEGRATION]: CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED, - [CONST.ONBOARDING_TASK_TYPE.CONNECT_CORPORATE_CARD]: CONST.POLICY.MORE_FEATURES.ARE_COMPANY_CARDS_ENABLED, - [CONST.ONBOARDING_TASK_TYPE.SETUP_TAGS]: CONST.POLICY.MORE_FEATURES.ARE_TAGS_ENABLED, -}; - const FRAUD_PROTECTION_EVENT = { START_SUPPORT_SESSION: 'StartSupportSession', STOP_SUPPORT_SESSION: 'StopSupportSession', @@ -9313,6 +9306,6 @@ export type { IOUActionParams, }; -export {CONTINUATION_DETECTION_SEARCH_FILTER_KEYS, TASK_TO_FEATURE, FRAUD_PROTECTION_EVENT, COUNTRIES_US_BANK_FLOW, SUBMIT_FEATURE_IDS}; +export {CONTINUATION_DETECTION_SEARCH_FILTER_KEYS, FRAUD_PROTECTION_EVENT, COUNTRIES_US_BANK_FLOW, SUBMIT_FEATURE_IDS}; export default CONST; diff --git a/src/components/HRSyncResultsModal.tsx b/src/components/HRSyncResultsModal.tsx index 74f4de488d0b..7a3899ec8703 100644 --- a/src/components/HRSyncResultsModal.tsx +++ b/src/components/HRSyncResultsModal.tsx @@ -5,7 +5,7 @@ import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {HrSyncResult} from '@libs/API/HrSyncResult'; +import type HrSyncResult from '@libs/API/HrSyncResult'; import {getConnectedHRProvider} from '@libs/PolicyUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/context/VictoryChartContext.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/context/VictoryChartContext.tsx index 329e8f690e12..1756b0ee6118 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/context/VictoryChartContext.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/context/VictoryChartContext.tsx @@ -76,4 +76,3 @@ function useVictoryChartContext(): VictoryChartContextValue { } export {VictoryChartProvider, useVictoryChartContext}; -export type {VictoryChartContextValue}; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/types.ts b/src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/types.ts index 7fb426a6ef1c..aaed006070f0 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/types.ts +++ b/src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/types.ts @@ -139,7 +139,6 @@ export type { RawAxisStyle, RawLabelStyle, RawLegendStyle, - XKey, YKey, CartesianChartData, CartesianChartProps, diff --git a/src/components/MoneyRequestConfirmationList/sections/selectors.ts b/src/components/MoneyRequestConfirmationList/sections/selectors.ts index ecd6cf509c63..adbcb487048a 100644 --- a/src/components/MoneyRequestConfirmationList/sections/selectors.ts +++ b/src/components/MoneyRequestConfirmationList/sections/selectors.ts @@ -242,4 +242,3 @@ export { timeStateSelector, toggleStateSelector, }; -export type {AmountSlice, AttendeeSlice, CategoryState, DateState, DescriptionState, InvoiceSenderWorkspace, MerchantState, ReportFieldTransactionState, TaxSlice, TimeState, ToggleState}; diff --git a/src/libs/API/HrSyncResult.ts b/src/libs/API/HrSyncResult.ts index 3795653ea647..09a98751863d 100644 --- a/src/libs/API/HrSyncResult.ts +++ b/src/libs/API/HrSyncResult.ts @@ -20,4 +20,4 @@ type HrSyncResult = { skippedEmployees?: HrSyncSkippedEmployee[]; }; -export type {HrSyncResult, HrSyncSkippedEmployee}; +export default HrSyncResult; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index df3899edc1e4..f0f239b1668f 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1,6 +1,6 @@ import type {CONST as COMMON_CONST} from 'expensify-common'; import type {ValueOf} from 'type-fest'; -import type {HrSyncResult} from '@libs/API/HrSyncResult'; +import type HrSyncResult from '@libs/API/HrSyncResult'; import type CONST from '@src/CONST'; import type {Country} from '@src/CONST'; import type {MergeHRProviderSlug} from '@src/CONST/MERGE_HR_PROVIDERS'; @@ -2425,7 +2425,6 @@ export type { XeroTrackingCategory, NetSuiteConnection, ConnectionLastSync, - MergeHRConnectionLastSync, QBDReimbursableExportAccountType, NetSuiteSubsidiary, NetSuiteCustomList, From 42a3c473ab87d8033e3df1431ac559df803117a3 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Sun, 24 May 2026 18:02:16 +0530 Subject: [PATCH 24/32] Apply suggestion from @shubham1206agra --- .github/workflows/knip.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index 5581399c42e5..7b1f94cdf690 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -27,8 +27,7 @@ jobs: runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout PR - # v6 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + uses: useblacksmith/checkout@c9796daa2a4bdebdab5bd16be2c09a70cd4e1121 # v1 - name: Setup Node uses: ./.github/actions/composite/setupNode From 0171f04f050cf86cd7de709df1c612e2ce6f02ec Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 25 May 2026 22:35:49 +0530 Subject: [PATCH 25/32] Add more files --- src/libs/PolicyUtils.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 8469796508f1..7cdab9337918 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -1909,10 +1909,6 @@ function isAccountingConnectionName(connectionName?: ConnectionName): connection return connectionName !== undefined && getAccountingConnectionNames().some((accountingConnectionName) => accountingConnectionName === connectionName); } -function getHRConnectionNames(): HRConnectionName[] { - return [...CONST.POLICY.CONNECTIONS.HR_CONNECTION_NAMES]; -} - function isGustoConnected(policy?: OnyxEntry) { return !!policy?.connections?.gusto; } @@ -2545,7 +2541,6 @@ export { tryNavigateToSubmitWorkspaceUpgrade, canAccessSubmitWorkspaceFeatures, getRulesDocumentSourceURL, - getHRConnectionNames, isGustoConnected, isZenefitsConnected, isMergeHRConnected, From fbf873c1ad4aef437cb0d2ea554ed2944523bcf8 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 27 May 2026 18:59:05 +0530 Subject: [PATCH 26/32] Add more files --- .../MoneyRequestConfirmationFields/context.ts | 1 - src/libs/CopyPolicySettingsUtils.ts | 2 +- src/libs/actions/IOU/SplitExpenseItems.ts | 1 - src/libs/actions/Search.ts | 125 +--------- .../step/IOURequestStepConfirmation.tsx | 3 - .../components/Camera/index.native.tsx | 1 - .../components/Camera/index.tsx | 1 - .../hooks/useCapturePhoto.ts | 236 ------------------ .../utils/buildReceiptFiles.ts | 1 - tests/actions/ReportTest.ts | 3 +- tests/unit/NetworkTest.tsx | 7 +- .../useSearchBulkActionsDuplicateTest.ts | 1 - 12 files changed, 8 insertions(+), 374 deletions(-) delete mode 100644 src/pages/iou/request/step/IOURequestStepScan/hooks/useCapturePhoto.ts diff --git a/src/components/MoneyRequestConfirmationFields/context.ts b/src/components/MoneyRequestConfirmationFields/context.ts index 1d86bc99b164..d8af3e8d262f 100644 --- a/src/components/MoneyRequestConfirmationFields/context.ts +++ b/src/components/MoneyRequestConfirmationFields/context.ts @@ -36,4 +36,3 @@ function useConfirmationFields(): ConfirmationFieldsContextValue { export default ConfirmationFieldsContext; export {useConfirmationFields}; -export type {ConfirmationFieldsContextValue}; diff --git a/src/libs/CopyPolicySettingsUtils.ts b/src/libs/CopyPolicySettingsUtils.ts index 043c4b71e5b1..3e5e82f87325 100644 --- a/src/libs/CopyPolicySettingsUtils.ts +++ b/src/libs/CopyPolicySettingsUtils.ts @@ -236,4 +236,4 @@ export { isCopyPolicySettingsPartEnabledOnSource, FEATURE_ROWS, }; -export type {AccountingConnectionIdentity, CopyPolicySettingsSourceFeatureContext, FeatureRow}; +export type {CopyPolicySettingsSourceFeatureContext}; diff --git a/src/libs/actions/IOU/SplitExpenseItems.ts b/src/libs/actions/IOU/SplitExpenseItems.ts index 7f40ddb292a2..aca25c7e3b5d 100644 --- a/src/libs/actions/IOU/SplitExpenseItems.ts +++ b/src/libs/actions/IOU/SplitExpenseItems.ts @@ -731,5 +731,4 @@ export { updateSplitExpenseField, updateSplitExpenseAmountField, clearSplitTransactionDraftErrors, - getDistanceMerchantFromDistance, }; diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 8ff5aaa72b75..94cfc092632b 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -8,7 +8,7 @@ import type {LocalizedTranslate} from '@components/LocaleContextProvider'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import type {HoldMenuCallback} from '@components/Search'; import type {TransactionListItemType, TransactionReportGroupListItemType} from '@components/Search/SearchList/ListItem/types'; -import type {BankAccountMenuItem, BulkPaySelectionData, PaymentData, SearchQueryJSON, SelectedReports, SelectedTransactionInfo, SelectedTransactions} from '@components/Search/types'; +import type {BankAccountMenuItem, BulkPaySelectionData, PaymentData, SearchQueryJSON, SelectedReports, SelectedTransactions} from '@components/Search/types'; import type {CurrencyListActionsContextType} from '@hooks/useCurrencyList'; import * as API from '@libs/API'; import {waitForWrites} from '@libs/API'; @@ -57,31 +57,17 @@ import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import {FILTER_KEYS} from '@src/types/form/SearchAdvancedFiltersForm'; import type {SearchAdvancedFiltersForm} from '@src/types/form/SearchAdvancedFiltersForm'; -import type { - BankAccountList, - Beta, - BillingGraceEndPeriod, - ExportTemplate, - LastPaymentMethod, - LastPaymentMethodType, - Policy, - Report, - ReportAction, - ReportNameValuePairs, - Transaction, - TransactionViolations, -} from '@src/types/onyx'; +import type {Beta, BillingGraceEndPeriod, ExportTemplate, LastPaymentMethod, LastPaymentMethodType, Policy, Report, ReportAction, Transaction} from '@src/types/onyx'; import type {PaymentInformation} from '@src/types/onyx/LastPaymentMethod'; import type {ConnectionName} from '@src/types/onyx/Policy'; import type {OnyxData} from '@src/types/onyx/Request'; import type Nullable from '@src/types/utils/Nullable'; import SafeString from '@src/utils/SafeString'; import {setPersonalBankAccountContinueKYCOnSuccess} from './BankAccounts'; -import {deleteMoneyRequest} from './IOU/DeleteMoneyRequest'; import {prepareRejectMoneyRequestData, rejectMoneyRequest} from './IOU/RejectMoneyRequest'; import type {RejectMoneyRequestData} from './IOU/RejectMoneyRequest'; import {isCurrencySupportedForGlobalReimbursement} from './Policy/Policy'; -import {deleteAppReport, setOptimisticTransactionThread} from './Report'; +import {setOptimisticTransactionThread} from './Report'; import {saveLastSearchParams} from './ReportNavigation'; type OnyxSearchResponse = { @@ -120,19 +106,6 @@ type HandleActionButtonPressParams = { currentUserAccountID?: number; }; -type BulkDeleteReportsParams = { - reports: OnyxCollection; - selfDMReport: OnyxEntry; - selectedTransactions: Record; - currentUserEmailParam: string; - currentUserAccountIDParam: number; - reportTransactions: Record; - transactionsViolations: Record; - bankAccountList: OnyxEntry; - transactions?: OnyxCollection; - allReportNameValuePairs: OnyxCollection; -}; - function handleActionButtonPress({ hash, item, @@ -912,97 +885,6 @@ function payMoneyRequestOnSearch(hash: number, paymentData: PaymentData[], curre }); } -function bulkDeleteReports({ - reports, - selfDMReport, - selectedTransactions, - currentUserEmailParam, - currentUserAccountIDParam, - reportTransactions, - transactionsViolations, - bankAccountList, - transactions, - allReportNameValuePairs, -}: BulkDeleteReportsParams) { - const transactionIDList: string[] = []; - const reportIDList: string[] = []; - - // Collect all report IDs that are being deleted - for (const key of Object.keys(selectedTransactions)) { - const selectedItem = selectedTransactions[key]; - if (selectedItem.action === CONST.SEARCH.ACTION_TYPES.VIEW && key === selectedItem.reportID) { - reportIDList.push(selectedItem.reportID); - } - } - - // Collect transaction IDs, but exclude any transactions whose reportID is in the list of reports being deleted - for (const key of Object.keys(selectedTransactions)) { - const selectedItem = selectedTransactions[key]; - if (selectedItem.action === CONST.SEARCH.ACTION_TYPES.VIEW && key === selectedItem.reportID) { - continue; - } - if (!selectedItem.reportID || !reportIDList.includes(selectedItem.reportID)) { - transactionIDList.push(key); - } - } - - // Group transaction IDs by IOU report so multi-delete totals and last-expense report removal are correct - const transactionsByReport = transactionIDList.reduce>((acc, transactionID) => { - const reportID = selectedTransactions[transactionID].report?.reportID; - if (!reportID) { - return acc; - } - if (!acc[reportID]) { - acc[reportID] = []; - } - acc[reportID].push(transactionID); - return acc; - }, {}); - - for (const transactionID of transactionIDList) { - const reportAction = selectedTransactions[transactionID].reportAction; - if (!reportAction) { - continue; - } - const reportID = selectedTransactions[transactionID].report?.reportID; - const batchTransactionIDsForReport = reportID ? (transactionsByReport[reportID] ?? []) : []; - const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${selectedTransactions[transactionID].report?.chatReportID}`]; - const transactionThreadReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportAction?.childReportID}`]; - const reportNameValuePair = allReportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${chatReport?.reportID}`]; - - deleteMoneyRequest({ - transactionID, - reportAction, - transactionThreadReport, - transactions, - violations: transactionsViolations, - iouReport: selectedTransactions[transactionID].report, - chatReport, - isChatIOUReportArchived: !!reportNameValuePair?.private_isArchived, - transactionIDsPendingDeletion: batchTransactionIDsForReport.filter((id) => id !== transactionID), - selectedTransactionIDs: batchTransactionIDsForReport.length > 0 ? batchTransactionIDsForReport : undefined, - allTransactionViolationsParam: transactionsViolations, - currentUserAccountID: currentUserAccountIDParam, - currentUserEmail: currentUserEmailParam, - }); - } - - if (reportIDList.length > 0) { - for (const reportID of reportIDList) { - const report = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - deleteAppReport({ - report, - selfDMReport, - currentUserEmailParam, - currentUserAccountIDParam, - reportTransactions, - allTransactionViolations: transactionsViolations, - bankAccountList, - }); - } - } -} - function rejectMoneyRequestInBulk( reportID: string, comment: string, @@ -1573,7 +1455,6 @@ function setOptimisticDataForTransactionThreadPreview(item: TransactionListItemT export { saveSearch, search, - bulkDeleteReports, rejectMoneyRequestsOnSearch, exportSearchItemsToCSV, queueExportSearchItemsToCSV, diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 9afa6ba4bfc0..043eb8830249 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -906,7 +906,4 @@ const IOURequestStepConfirmationWithFullTransactionOrNotFound = withFullTransact const IOURequestStepConfirmationWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepConfirmationWithFullTransactionOrNotFound); -type IOURequestStepConfirmationPublicProps = ComponentProps; - export default IOURequestStepConfirmationWithWritableReportOrNotFound; -export type {IOURequestStepConfirmationPublicProps}; diff --git a/src/pages/iou/request/step/IOURequestStepScan/components/Camera/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/components/Camera/index.native.tsx index 874c1b301499..48be7b4e15ef 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/components/Camera/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/components/Camera/index.native.tsx @@ -268,4 +268,3 @@ function Camera({onCapture, onPicked, shouldAcceptMultipleFiles = false, onLayou Camera.displayName = 'Camera'; export default Camera; -export type {CameraProps}; diff --git a/src/pages/iou/request/step/IOURequestStepScan/components/Camera/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/components/Camera/index.tsx index 31d17462b57d..ddb2f293ea0f 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/components/Camera/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/components/Camera/index.tsx @@ -45,4 +45,3 @@ function Camera(props: CameraProps) { Camera.displayName = 'Camera'; export default Camera; -export type {CameraProps}; diff --git a/src/pages/iou/request/step/IOURequestStepScan/hooks/useCapturePhoto.ts b/src/pages/iou/request/step/IOURequestStepScan/hooks/useCapturePhoto.ts deleted file mode 100644 index bfff91d19da8..000000000000 --- a/src/pages/iou/request/step/IOURequestStepScan/hooks/useCapturePhoto.ts +++ /dev/null @@ -1,236 +0,0 @@ -import type {RefObject} from 'react'; -import {useRef} from 'react'; -import {Alert} from 'react-native'; -import {RESULTS} from 'react-native-permissions'; -import type {Camera, PhotoFile} from 'react-native-vision-camera'; -import useLocalize from '@hooks/useLocalize'; -import {precacheReceiptImage} from '@hooks/useLocalReceiptThumbnail'; -import getPhotoSource from '@libs/fileDownload/getPhotoSource'; -import getReceiptsUploadFolderPath from '@libs/getReceiptsUploadFolderPath'; -import Log from '@libs/Log'; -import {cancelSpan, endSpan, getSpan, startSpan} from '@libs/telemetry/activeSpans'; -import captureReceipt from '@pages/iou/request/step/IOURequestStepScan/captureReceipt'; -import type {ReceiptFile} from '@pages/iou/request/step/IOURequestStepScan/types'; -import {setMoneyRequestReceipt} from '@userActions/IOU/Receipt'; -import {buildOptimisticTransactionAndCreateDraft} from '@userActions/TransactionEdit'; -import CONST from '@src/CONST'; -import type {CurrentUserPersonalDetails} from '@src/types/onyx/PersonalDetails'; -import type Transaction from '@src/types/onyx/Transaction'; -import type {FileObject} from '@src/types/utils/Attachment'; - -type UseCapturePhotoParams = { - /** Ref to the underlying Camera instance */ - cameraRef: RefObject; - - /** Current camera permission status from react-native-permissions */ - cameraPermissionStatus: string | null; - - /** Whether the camera flash is currently on */ - flash: boolean; - - /** Whether the camera device supports flash */ - hasFlash: boolean; - - /** Whether the platform requires muted audio during capture */ - isPlatformMuted: boolean | undefined; - - /** Whether the device is currently in landscape orientation */ - isInLandscapeMode: boolean; - - /** Prompts the user to grant camera permissions */ - askForPermissions: () => void; - - /** Sets whether a photo has been captured */ - setDidCapturePhoto: (value: boolean) => void; - - /** Whether multi-scan mode is currently active */ - isMultiScanEnabled: boolean; - - /** Whether the user is editing an existing receipt */ - isEditing: boolean; - - /** The initial transaction associated with this scan */ - initialTransaction: Transaction | null | undefined; - - /** The transaction ID to use when no optimistic transaction is created */ - initialTransactionID: string; - - /** The current user's personal details for optimistic transaction creation */ - currentUserPersonalDetails: CurrentUserPersonalDetails; - - /** The report ID associated with this expense */ - reportID: string; - - /** Array of receipt files captured so far in the current session */ - receiptFiles: ReceiptFile[]; - - /** Updates the array of captured receipt files */ - setReceiptFiles: (value: ReceiptFile[]) => void; - - /** Replaces the receipt on an existing transaction and navigates back */ - updateScanAndNavigate: (file: FileObject, source: string) => void; - - /** Submits all captured receipts and navigates to the confirmation step */ - submitReceipts: (files: ReceiptFile[]) => void; - - /** Triggers the post-capture blink animation */ - showBlink: () => void; -}; - -/** - * Encapsulates the capturePhoto function: permission guard, telemetry spans, - * photo capture call, multi-scan vs. single-scan branching, editing vs. new-receipt - * branching, optimistic transaction creation, and Onyx receipt merges. - */ -function useCapturePhoto({ - cameraRef, - cameraPermissionStatus, - flash, - hasFlash, - isPlatformMuted, - isInLandscapeMode, - askForPermissions, - setDidCapturePhoto, - isMultiScanEnabled, - isEditing, - initialTransaction, - initialTransactionID, - currentUserPersonalDetails, - reportID, - receiptFiles, - setReceiptFiles, - updateScanAndNavigate, - submitReceipts, - showBlink, -}: UseCapturePhotoParams) { - const {translate} = useLocalize(); - const isCapturingPhoto = useRef(false); - - const resetCapturingState = () => { - isCapturingPhoto.current = false; - }; - - const maybeCancelShutterSpan = () => { - if (isMultiScanEnabled) { - return; - } - - cancelSpan(CONST.TELEMETRY.SPAN_RECEIPT_CAPTURE); - cancelSpan(CONST.TELEMETRY.SPAN_SHUTTER_TO_CONFIRMATION); - }; - - const capturePhoto = () => { - if (!isMultiScanEnabled) { - startSpan(CONST.TELEMETRY.SPAN_SHUTTER_TO_CONFIRMATION, { - name: CONST.TELEMETRY.SPAN_SHUTTER_TO_CONFIRMATION, - op: CONST.TELEMETRY.SPAN_SHUTTER_TO_CONFIRMATION, - attributes: {[CONST.TELEMETRY.ATTRIBUTE_PLATFORM]: 'native'}, - }); - } - - if (!cameraRef.current && (cameraPermissionStatus === RESULTS.DENIED || cameraPermissionStatus === RESULTS.BLOCKED)) { - maybeCancelShutterSpan(); - askForPermissions(); - return; - } - - const showCameraAlert = () => { - Alert.alert(translate('receipt.cameraErrorTitle'), translate('receipt.cameraErrorMessage')); - }; - - if (!cameraRef.current) { - maybeCancelShutterSpan(); - showCameraAlert(); - return; - } - - if (isCapturingPhoto.current) { - maybeCancelShutterSpan(); - return; - } - - startSpan(CONST.TELEMETRY.SPAN_RECEIPT_CAPTURE, { - name: CONST.TELEMETRY.SPAN_RECEIPT_CAPTURE, - op: CONST.TELEMETRY.SPAN_RECEIPT_CAPTURE, - parentSpan: getSpan(CONST.TELEMETRY.SPAN_SHUTTER_TO_CONFIRMATION), - attributes: {[CONST.TELEMETRY.ATTRIBUTE_PLATFORM]: 'native'}, - }); - - isCapturingPhoto.current = true; - showBlink(); - - const path = getReceiptsUploadFolderPath(); - - captureReceipt(cameraRef.current, {flash, hasFlash, isPlatformMuted, path, isInLandscapeMode}) - .then((photo: PhotoFile) => { - setDidCapturePhoto(true); - - const transaction = - isMultiScanEnabled && initialTransaction?.receipt?.source - ? buildOptimisticTransactionAndCreateDraft({ - initialTransaction, - currentUserPersonalDetails, - reportID, - }) - : initialTransaction; - const transactionID = transaction?.transactionID ?? initialTransactionID; - const source = getPhotoSource(photo.path); - const filename = photo.path; - - endSpan(CONST.TELEMETRY.SPAN_RECEIPT_CAPTURE); - - const cameraFile = { - uri: source, - name: filename, - type: 'image/jpeg', - source, - }; - - if (isEditing) { - setMoneyRequestReceipt(transactionID, source, filename, !isEditing, 'image/jpeg'); - updateScanAndNavigate(cameraFile as FileObject, source); - return; - } - - const newReceiptFiles = [...receiptFiles, {file: cameraFile as FileObject, source, transactionID}]; - setReceiptFiles(newReceiptFiles); - - if (isMultiScanEnabled) { - setMoneyRequestReceipt(transactionID, source, filename, !isEditing, 'image/jpeg'); - setDidCapturePhoto(false); - isCapturingPhoto.current = false; - return; - } - - // Fire Onyx merge immediately (non-blocking) while we await thumbnail generation. - // Limit the wait to THUMBNAIL_NAV_TIMEOUT_MS so a slow encode can't block navigation — - // the confirm-screen hook (`useLocalReceiptThumbnail`) generates lazily on mount as a fallback. - setMoneyRequestReceipt(transactionID, source, filename, !isEditing, 'image/jpeg'); - startSpan(CONST.TELEMETRY.SPAN_THUMBNAIL_GATE, { - name: CONST.TELEMETRY.SPAN_THUMBNAIL_GATE, - op: CONST.TELEMETRY.SPAN_THUMBNAIL_GATE, - parentSpan: getSpan(CONST.TELEMETRY.SPAN_SHUTTER_TO_CONFIRMATION), - }); - Promise.race([ - precacheReceiptImage(source), - new Promise((resolve) => { - setTimeout(resolve, CONST.RECEIPT_CAMERA.THUMBNAIL_NAV_TIMEOUT_MS); - }), - ]).then(() => { - endSpan(CONST.TELEMETRY.SPAN_THUMBNAIL_GATE); - submitReceipts(newReceiptFiles); - }); - }) - .catch((error: string) => { - isCapturingPhoto.current = false; - cancelSpan(CONST.TELEMETRY.SPAN_RECEIPT_CAPTURE); - maybeCancelShutterSpan(); - showCameraAlert(); - Log.warn('Error taking photo', error); - }); - }; - - return {capturePhoto, resetCapturingState}; -} - -export default useCapturePhoto; diff --git a/src/pages/iou/request/step/IOURequestStepScan/utils/buildReceiptFiles.ts b/src/pages/iou/request/step/IOURequestStepScan/utils/buildReceiptFiles.ts index cac46a4e3685..9a657f2c449e 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/utils/buildReceiptFiles.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/utils/buildReceiptFiles.ts @@ -70,4 +70,3 @@ function buildReceiptFiles({ } export default buildReceiptFiles; -export type {BuildReceiptFilesParams}; diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts index 5c99b6d11603..1b9cab37f567 100644 --- a/tests/actions/ReportTest.ts +++ b/tests/actions/ReportTest.ts @@ -3,7 +3,6 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it} from '@jest/glob import {renderHook} from '@testing-library/react-native'; import {addSeconds, format, subMinutes} from 'date-fns'; import {toZonedTime} from 'date-fns-tz'; -import type {Mock} from 'jest-mock'; import Onyx from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import OnyxUtils from 'react-native-onyx/dist/OnyxUtils'; @@ -1581,7 +1580,7 @@ describe('actions/Report', () => { jest.runOnlyPendingTimers(); await waitForBatchedUpdates(); - const httpCalls = (HttpUtils.xhr as Mock).mock.calls; + const httpCalls = (HttpUtils.xhr as jest.Mock).mock.calls; const addCommentCalls = httpCalls.filter(([command]) => command === 'AddComment'); const deleteCommentCalls = httpCalls.filter(([command]) => command === 'DeleteComment'); diff --git a/tests/unit/NetworkTest.tsx b/tests/unit/NetworkTest.tsx index c0e178fd541b..bbb9a89f5031 100644 --- a/tests/unit/NetworkTest.tsx +++ b/tests/unit/NetworkTest.tsx @@ -1,4 +1,3 @@ -import type {Mock} from 'jest-mock'; import type {OnyxEntry} from 'react-native-onyx'; import MockedOnyx from 'react-native-onyx'; import {confirmReadyToOpenApp, reconnectApp} from '@libs/actions/App'; @@ -113,7 +112,7 @@ describe('NetworkTests', () => { // Verify: // 1. We attempted to authenticate twice (first failed, retry succeeded) // 2. The session has the new auth token (user wasn't logged out) - const callsToAuthenticate = (HttpUtils.xhr as Mock).mock.calls.filter(([command]) => command === 'Authenticate'); + const callsToAuthenticate = (HttpUtils.xhr as jest.Mock).mock.calls.filter(([command]) => command === 'Authenticate'); expect(callsToAuthenticate.length).toBe(2); expect(sessionState?.authToken).toBe(NEW_AUTH_TOKEN); }); @@ -242,8 +241,8 @@ describe('NetworkTests', () => { }) .then(() => { // Verify: 3 calls to the API, 1 authenticate call, and reconnect was triggered - const callsToOpenPublicProfilePage = (HttpUtils.xhr as Mock).mock.calls.filter(([command]) => command === 'OpenPublicProfilePage'); - const callsToAuthenticate = (HttpUtils.xhr as Mock).mock.calls.filter(([command]) => command === 'Authenticate'); + const callsToOpenPublicProfilePage = (HttpUtils.xhr as jest.Mock).mock.calls.filter(([command]) => command === 'OpenPublicProfilePage'); + const callsToAuthenticate = (HttpUtils.xhr as jest.Mock).mock.calls.filter(([command]) => command === 'Authenticate'); expect(callsToOpenPublicProfilePage.length).toBe(3); expect(callsToAuthenticate.length).toBe(1); expect(reconnectSpy).toHaveBeenCalled(); diff --git a/tests/unit/hooks/useSearchBulkActionsDuplicateTest.ts b/tests/unit/hooks/useSearchBulkActionsDuplicateTest.ts index eeb01c1aa81d..eb35416153ed 100644 --- a/tests/unit/hooks/useSearchBulkActionsDuplicateTest.ts +++ b/tests/unit/hooks/useSearchBulkActionsDuplicateTest.ts @@ -23,7 +23,6 @@ jest.mock('@libs/actions/Search', () => ({ queueExportSearchItemsToCSV: jest.fn(), queueExportSearchWithTemplate: jest.fn(), approveMoneyRequestOnSearch: jest.fn(), - bulkDeleteReports: jest.fn(), getLastPolicyBankAccountID: jest.fn(), getLastPolicyPaymentMethod: jest.fn(), getPayMoneyOnSearchInvoiceParams: jest.fn(), From 0ca80e6136c67e41c87b756ed04ea16a921e36b2 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 27 May 2026 19:07:16 +0530 Subject: [PATCH 27/32] Fix ts --- src/libs/actions/IOU/MoneyRequest.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/IOU/MoneyRequest.ts b/src/libs/actions/IOU/MoneyRequest.ts index b53148ca8ba8..da0ffeb2d869 100644 --- a/src/libs/actions/IOU/MoneyRequest.ts +++ b/src/libs/actions/IOU/MoneyRequest.ts @@ -1424,6 +1424,7 @@ export { setMoneyRequestParticipantsFromReport, getIOURequestPolicyID, updateLastLocationPermissionPrompt, + setMultipleMoneyRequestParticipantsFromReport, setMoneyRequestTaxRate, setMoneyRequestTaxValue, setMoneyRequestTaxAmount, From ce7d886de5c74fbbd8ec8427a0f03d17930d7f77 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 27 May 2026 19:37:04 +0530 Subject: [PATCH 28/32] Fix ESLint --- src/pages/iou/request/step/IOURequestStepConfirmation.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 043eb8830249..feb998bcbed0 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1,5 +1,4 @@ import {validTransactionDraftIDsSelector} from '@selectors/TransactionDraft'; -import type {ComponentProps} from 'react'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import DragAndDropConsumer from '@components/DragAndDrop/Consumer'; From b12e1ad5daccbefe5db028452a4f38ebaec8a7e5 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Wed, 27 May 2026 19:56:20 +0530 Subject: [PATCH 29/32] Add more files --- src/libs/actions/User.ts | 10 ---------- src/types/form/SpendRuleForm.ts | 1 - 2 files changed, 11 deletions(-) diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index 90a829debb56..faae7abbf801 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -1888,14 +1888,6 @@ function clearDraftSpendRule() { Onyx.set(ONYXKEYS.FORMS.SPEND_RULE_FORM, null); } -function updateSpendRuleFormDraft(draftData: Partial) { - Onyx.merge(ONYXKEYS.FORMS.SPEND_RULE_FORM_DRAFT, draftData); -} - -function clearSpendRuleFormDraft() { - Onyx.set(ONYXKEYS.FORMS.SPEND_RULE_FORM_DRAFT, null); -} - export { revokeDevice, clearRevokeError, @@ -1953,8 +1945,6 @@ export { setDraftSpendRule, updateDraftSpendRule, clearDraftSpendRule, - updateSpendRuleFormDraft, - clearSpendRuleFormDraft, openTroubleshootSettingsPage, openMultifactorAuthenticationRevokePage, }; diff --git a/src/types/form/SpendRuleForm.ts b/src/types/form/SpendRuleForm.ts index 4e5f89a092a5..e1d9568b64cc 100644 --- a/src/types/form/SpendRuleForm.ts +++ b/src/types/form/SpendRuleForm.ts @@ -26,4 +26,3 @@ type SpendRuleForm = Form< export {SPEND_RULE_CATEGORIES, isSpendRuleCategory}; export type {SpendRuleForm, SpendRuleCategory}; -export default INPUT_IDS; From bf37d115f2fa2644819b7a2a4fbe302077ed2588 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 28 May 2026 21:49:56 +0530 Subject: [PATCH 30/32] Add more files --- .../Tables/WorkspaceRoomsTable/index.tsx | 2 +- src/hooks/useOdometerReceiptStitcher/index.ts | 2 +- .../parameters/OpenWorkspaceRoomsPageParams.ts | 5 ----- src/libs/API/parameters/index.ts | 1 - src/libs/API/types.ts | 2 -- src/libs/CardUtils.ts | 1 - src/libs/HRUtils.ts | 7 +------ src/libs/OdometerReceipt/index.ts | 3 --- src/libs/OdometerReceipt/stitchTask.ts | 1 - src/libs/actions/Policy/Room.ts | 15 ++------------- 10 files changed, 5 insertions(+), 34 deletions(-) delete mode 100644 src/libs/API/parameters/OpenWorkspaceRoomsPageParams.ts diff --git a/src/components/Tables/WorkspaceRoomsTable/index.tsx b/src/components/Tables/WorkspaceRoomsTable/index.tsx index 04396e8e45d3..bc7957473fb1 100644 --- a/src/components/Tables/WorkspaceRoomsTable/index.tsx +++ b/src/components/Tables/WorkspaceRoomsTable/index.tsx @@ -75,4 +75,4 @@ function WorkspaceRoomsTable({rooms}: WorkspaceRoomsTableProps) { } export default WorkspaceRoomsTable; -export type {WorkspaceRoomRowData, WorkspaceRoomsTableColumnKey}; +export type {WorkspaceRoomRowData}; diff --git a/src/hooks/useOdometerReceiptStitcher/index.ts b/src/hooks/useOdometerReceiptStitcher/index.ts index 41c32943c839..83360b3505e1 100644 --- a/src/hooks/useOdometerReceiptStitcher/index.ts +++ b/src/hooks/useOdometerReceiptStitcher/index.ts @@ -143,5 +143,5 @@ function useOdometerReceiptStitcher({ return {state, isReady, isStitching, error, hasVerifiedBlobs}; } -export type {OdometerReceiptState, UseOdometerReceiptStitcherArgs, UseOdometerReceiptStitcherResult} from './types'; +export type {UseOdometerReceiptStitcherArgs} from './types'; export default useOdometerReceiptStitcher; diff --git a/src/libs/API/parameters/OpenWorkspaceRoomsPageParams.ts b/src/libs/API/parameters/OpenWorkspaceRoomsPageParams.ts deleted file mode 100644 index 4886d21ea33e..000000000000 --- a/src/libs/API/parameters/OpenWorkspaceRoomsPageParams.ts +++ /dev/null @@ -1,5 +0,0 @@ -type OpenWorkspaceRoomsPageParams = { - policyID: string; -}; - -export default OpenWorkspaceRoomsPageParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 4b7eb17a3c3b..0291f68f3e1c 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -184,7 +184,6 @@ export type {default as ConnectPolicyToFinancialForceParams} from './ConnectPoli export type {default as UpdateFinancialForceGenericTypeParams} from './UpdateFinancialForceGenericTypeParams'; export type {default as OpenWorkspaceInvitePageParams} from './OpenWorkspaceInvitePageParams'; export type {default as OpenWorkspaceMembersPageParams} from './OpenWorkspaceMembersPageParams'; -export type {default as OpenWorkspaceRoomsPageParams} from './OpenWorkspaceRoomsPageParams'; export type {default as OpenPolicyRoomsPageParams} from './OpenPolicyRoomsPageParams'; export type {default as OpenPolicyCategoriesPageParams} from './OpenPolicyCategoriesPageParams'; export type {default as OpenPolicyTagsPageParams} from './OpenPolicyTagsPageParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index f6f54e0b9a31..77bf32ca4a44 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -1315,7 +1315,6 @@ const READ_COMMANDS = { GET_POLICY_CATEGORIES: 'GetPolicyCategories', OPEN_WORKSPACE: 'OpenWorkspace', OPEN_WORKSPACE_MEMBERS_PAGE: 'OpenWorkspaceMembersPage', - OPEN_WORKSPACE_ROOMS_PAGE: 'OpenWorkspaceRoomsPage', OPEN_POLICY_MEMBER_PROFILE_PAGE: 'OpenPolicyMemberProfilePage', OPEN_POLICY_CATEGORIES_PAGE: 'OpenPolicyCategoriesPage', OPEN_POLICY_ROOMS_PAGE: 'OpenPolicyRoomsPage', @@ -1419,7 +1418,6 @@ type ReadCommandParameters = { [READ_COMMANDS.GET_POLICY_CATEGORIES]: Parameters.GetPolicyCategoriesParams; [READ_COMMANDS.OPEN_WORKSPACE]: Parameters.OpenWorkspaceParams; [READ_COMMANDS.OPEN_WORKSPACE_MEMBERS_PAGE]: Parameters.OpenWorkspaceMembersPageParams; - [READ_COMMANDS.OPEN_WORKSPACE_ROOMS_PAGE]: Parameters.OpenWorkspaceRoomsPageParams; [READ_COMMANDS.OPEN_POLICY_MEMBER_PROFILE_PAGE]: Parameters.OpenPolicyMemberProfilePageParams; [READ_COMMANDS.OPEN_POLICY_CATEGORIES_PAGE]: Parameters.OpenPolicyCategoriesPageParams; [READ_COMMANDS.OPEN_POLICY_ROOMS_PAGE]: Parameters.OpenPolicyRoomsPageParams; diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index 51d4a0826393..eebd2d22d8f1 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -1842,7 +1842,6 @@ function resolveTransactionCardFields(transactions: T[], export { getAssignedCardSortKey, getCardFeedBackgroundColor, - getCardFeedColors, getCardFeedTextColor, getDefaultExpensifyCardLimitType, isExpensifyCard, diff --git a/src/libs/HRUtils.ts b/src/libs/HRUtils.ts index a36278b0a5dc..d47f963e7995 100644 --- a/src/libs/HRUtils.ts +++ b/src/libs/HRUtils.ts @@ -22,10 +22,6 @@ type HRProviderInfo = { mergeSlug?: MergeHRProviderSlug; }; -function getHRConnectionNames(): HRConnectionName[] { - return [...CONST.POLICY.CONNECTIONS.HR_CONNECTION_NAMES]; -} - function isGustoConnected(policy?: OnyxEntry) { return !!policy?.connections?.gusto; } @@ -161,7 +157,6 @@ function getHRFinalApprover(policy?: OnyxEntry): string | null { export { getConnectedHRProvider, getHRApprovalMode, - getHRConnectionNames, getHRAdvancedModeFinalApprover, getHRFinalApprover, getMergeHRFinalApprover, @@ -173,4 +168,4 @@ export { isZenefitsConnected, }; -export type {HRConnectionName, HRProviderInfo}; +export type {HRConnectionName}; diff --git a/src/libs/OdometerReceipt/index.ts b/src/libs/OdometerReceipt/index.ts index 4613c6ee46db..a1be1ca0d052 100644 --- a/src/libs/OdometerReceipt/index.ts +++ b/src/libs/OdometerReceipt/index.ts @@ -1,7 +1,4 @@ -import type {OdometerReceiptDerivation} from './deriveOdometerReceipt'; import deriveOdometerReceipt from './deriveOdometerReceipt'; -import type {StitchTaskArgs, StitchTaskResult} from './stitchTask'; import stitchTask from './stitchTask'; export {deriveOdometerReceipt, stitchTask}; -export type {OdometerReceiptDerivation, StitchTaskArgs, StitchTaskResult}; diff --git a/src/libs/OdometerReceipt/stitchTask.ts b/src/libs/OdometerReceipt/stitchTask.ts index 23643d2a1a8c..f02465bb54cf 100644 --- a/src/libs/OdometerReceipt/stitchTask.ts +++ b/src/libs/OdometerReceipt/stitchTask.ts @@ -56,4 +56,3 @@ async function stitchTask({startImage, endImage, signal}: StitchTaskArgs): Promi } export default stitchTask; -export type {StitchTaskArgs, StitchTaskResult}; diff --git a/src/libs/actions/Policy/Room.ts b/src/libs/actions/Policy/Room.ts index 133c29db788b..f1d09251713f 100644 --- a/src/libs/actions/Policy/Room.ts +++ b/src/libs/actions/Policy/Room.ts @@ -1,7 +1,6 @@ import {read} from '@libs/API'; -import type {OpenPolicyRoomsPageParams, OpenWorkspaceRoomsPageParams} from '@libs/API/parameters'; +import type {OpenPolicyRoomsPageParams} from '@libs/API/parameters'; import {READ_COMMANDS} from '@libs/API/types'; -import Log from '@libs/Log'; function openPolicyRoomsPage(policyID: string) { const params: OpenPolicyRoomsPageParams = {policyID}; @@ -9,15 +8,5 @@ function openPolicyRoomsPage(policyID: string) { read(READ_COMMANDS.OPEN_POLICY_ROOMS_PAGE, params); } -export default function openWorkspaceRoomsPage(policyID: string) { - if (!policyID) { - Log.warn('openWorkspaceRoomsPage invalid params', {policyID}); - return; - } - - const params: OpenWorkspaceRoomsPageParams = {policyID}; - - read(READ_COMMANDS.OPEN_WORKSPACE_ROOMS_PAGE, params); -} - +// eslint-disable-next-line import/prefer-default-export export {openPolicyRoomsPage}; From 63474e846e6383fa40cc0d0a7952a3f874284f0f Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 30 May 2026 15:26:35 +0530 Subject: [PATCH 31/32] Add more files --- src/components/MoneyReportTransactionThreadContext.tsx | 1 - src/hooks/useDeferredAgentWorkflowReconciliation.ts | 1 - src/hooks/useOutstandingReports.ts | 2 -- src/types/onyx/OriginalMessage.ts | 1 - 4 files changed, 5 deletions(-) diff --git a/src/components/MoneyReportTransactionThreadContext.tsx b/src/components/MoneyReportTransactionThreadContext.tsx index a7c780e72d17..19ad1cea10e1 100644 --- a/src/components/MoneyReportTransactionThreadContext.tsx +++ b/src/components/MoneyReportTransactionThreadContext.tsx @@ -60,5 +60,4 @@ function useMoneyReportTransactionThread() { return useContext(MoneyReportTransactionThreadContext); } -export default MoneyReportTransactionThreadContext; export {MoneyReportTransactionThreadProvider, useMoneyReportTransactionThread}; diff --git a/src/hooks/useDeferredAgentWorkflowReconciliation.ts b/src/hooks/useDeferredAgentWorkflowReconciliation.ts index 131ba8010504..dc1fc17da549 100644 --- a/src/hooks/useDeferredAgentWorkflowReconciliation.ts +++ b/src/hooks/useDeferredAgentWorkflowReconciliation.ts @@ -174,4 +174,3 @@ function useDeferredAgentWorkflowReconciliation(rawApprovalWorkflows: ApprovalWo } export default useDeferredAgentWorkflowReconciliation; -export type {ApprovalWorkflowWithRouting}; diff --git a/src/hooks/useOutstandingReports.ts b/src/hooks/useOutstandingReports.ts index 43bce9cbcd09..cf793b743ef5 100644 --- a/src/hooks/useOutstandingReports.ts +++ b/src/hooks/useOutstandingReports.ts @@ -69,5 +69,3 @@ export default function useOutstandingReports(selectedReportID: string | undefin return getOutstandingReportsForUser(selectedPolicyID, ownerAccountID, outstandingReportsByPolicyID?.[selectedPolicyID ?? CONST.DEFAULT_NUMBER_ID] ?? {}, reportNameValuePairs, isEditing); } - -export {createOutstandingReportsNVPsSelector}; diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 829b89ea9899..1b06611f0096 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -1685,5 +1685,4 @@ export type { OriginalMessageMarkedReimbursed, OriginalMessageReimbursed, OriginalMessageSettlementAccountLocked, - OriginalMessageSpendRuleChangeLog, }; From bdaa81cb0399051884caecda7bb697259dc6a703 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:29:29 +0530 Subject: [PATCH 32/32] Apply suggestions from code review Co-authored-by: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> --- .github/workflows/knip.yml | 2 +- config/eslint/eslint.seatbelt.tsv | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index 7b1f94cdf690..11719e9ce782 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -24,7 +24,7 @@ concurrency: jobs: knip-compare: name: Compare knip issues against main - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: blacksmith-2vcpu-ubuntu-2404 steps: - name: Checkout PR uses: useblacksmith/checkout@c9796daa2a4bdebdab5bd16be2c09a70cd4e1121 # v1 diff --git a/config/eslint/eslint.seatbelt.tsv b/config/eslint/eslint.seatbelt.tsv index 4a1ae093bf48..1b4e69dc718d 100644 --- a/config/eslint/eslint.seatbelt.tsv +++ b/config/eslint/eslint.seatbelt.tsv @@ -289,6 +289,7 @@ "../../src/libs/PersonalDetailsUtils.ts" "rulesdir/no-onyx-connect" 2 "../../src/libs/Pusher/index.native.ts" "no-restricted-imports" 1 "../../src/libs/Pusher/index.ts" "no-restricted-imports" 1 +"../../src/libs/ReceiptUploadRetryHandler/handleFileRetry.ts" "no-restricted-syntax" 1 "../../src/libs/ReportActionItemEventHandler/index.android.ts" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1 "../../src/libs/ReportActionsUtils.ts" "@typescript-eslint/no-deprecated/reportAction.sequenceNumber" 1 "../../src/libs/ReportActionsUtils.ts" "@typescript-eslint/no-deprecated/reportAction?.originalMessage" 2