mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-10-20 18:56:16 +00:00
web: make the typecheck a real gate, held to a ratchet (#54)
The typecheck ran with continue-on-error, so it could not fail, and it did not see much of the code it was meant to check: shared/ resolved none of its imports (61 TS2307), which hid every type error behind them. - tsconfig.app.json resolves packages that shared/ imports from web's node_modules (types first), and @pezkuwi/utils subpaths as vite does. Unresolved imports: 61 -> 0. The real errors behind them are now visible: 353 in total, most in production code with little test cover. - Fixing those in one change would be a large edit to that code. Instead ops/typecheck-ratchet.py records them per file and error code in ops/typecheck-baseline.txt and fails when any file gains one, or when errors were fixed without lowering the baseline in the same change. Line numbers are not part of the signature, so unrelated edits do not trip it. Checked: a new error in App.tsx fails (exit 1); an unlowered baseline fails (exit 1); the current tree passes. The CI step runs the ratchet instead of the non-blocking typecheck.
This commit is contained in:
1 parent
b6c2ce3470
commit
c57e7e0ef4
4 files changed
+191
-8
No files matched your search
@@ -72,13 +72,11 @@ jobs:
|
||||
working-directory: ./web
|
||||
run: npm run lint
|
||||
|
||||
# Typecheck gate. Currently non-blocking (continue-on-error) because the
|
||||
# existing codebase still has pre-existing type errors. Once the count
|
||||
# reaches zero, remove `continue-on-error` to make this a hard merge block.
|
||||
- name: Typecheck
|
||||
working-directory: ./web
|
||||
continue-on-error: true
|
||||
run: npm run typecheck
|
||||
# Typecheck gate, held to a ratchet: the type errors that predate the gate
|
||||
# are recorded in ops/typecheck-baseline.txt, and this fails when any file
|
||||
# gains one, or when errors were fixed without lowering the baseline.
|
||||
- name: Typecheck (ratchet)
|
||||
run: python3 ops/typecheck-ratchet.py
|
||||
|
||||
- name: Run Tests
|
||||
working-directory: ./web
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
# count file code — written by ops/typecheck-ratchet.py --update
|
||||
3 ../shared/lib/multisig-operations.ts TS2339
|
||||
3 ../shared/lib/perwerde.ts TS2339
|
||||
6 ../shared/lib/presale.ts TS2339
|
||||
1 ../shared/lib/referral.ts TS2339
|
||||
9 ../shared/lib/scores.ts TS2339
|
||||
3 ../shared/lib/staking.ts TS2339
|
||||
10 ../shared/lib/validator-pool.ts TS2339
|
||||
2 ../shared/lib/welati.ts TS2305
|
||||
24 ../shared/lib/welati.ts TS2339
|
||||
1 ../shared/lib/xcm-bridge.ts TS2353
|
||||
1 ../shared/lib/xcm-bridge.ts TS2554
|
||||
5 ../shared/lib/xcm-wizard.ts TS2339
|
||||
1 ../shared/lib/xcm-wizard.ts TS2345
|
||||
1 src/components/AddLiquidityModal.tsx TS2339
|
||||
4 src/components/AddLiquidityModal.tsx TS2345
|
||||
2 src/components/AddLiquidityModal.tsx TS2352
|
||||
3 src/components/LPStakingModal.tsx TS2352
|
||||
2 src/components/LPStakingModal.tsx TS2554
|
||||
2 src/components/MultisigMembers.tsx TS2322
|
||||
5 src/components/MultisigMembers.tsx TS2339
|
||||
1 src/components/MultisigMembers.tsx TS2345
|
||||
2 src/components/NetworkStats.tsx TS2339
|
||||
1 src/components/PoolDashboard.tsx TS2345
|
||||
3 src/components/PoolDashboard.tsx TS2352
|
||||
1 src/components/RemoveLiquidityModal.tsx TS2345
|
||||
16 src/components/TokenSwap.tsx TS2322
|
||||
7 src/components/TokenSwap.tsx TS2339
|
||||
8 src/components/TokenSwap.tsx TS2345
|
||||
6 src/components/TokenSwap.tsx TS2552
|
||||
1 src/components/TransactionHistory.tsx TS2304
|
||||
3 src/components/TransactionHistory.tsx TS2339
|
||||
1 src/components/XCMTeleportModal.tsx TS2339
|
||||
2 src/components/admin/CommissionSetupTab.tsx TS2339
|
||||
14 src/components/admin/CommissionVotingTab.tsx TS2339
|
||||
1 src/components/admin/CommissionVotingTab.tsx TS2345
|
||||
1 src/components/admin/XCMConfigurationWizard.tsx TS2339
|
||||
5 src/components/admin/XCMConfigurationWizard.tsx TS2345
|
||||
14 src/components/dashboard/CommissionProposalsCard.tsx TS2339
|
||||
1 src/components/delegation/DelegationManager.tsx TS2322
|
||||
1 src/components/delegation/DelegationManager.tsx TS2345
|
||||
1 src/components/dex/AddLiquidityModal.tsx TS2345
|
||||
2 src/components/dex/CreatePoolModal.tsx TS2345
|
||||
1 src/components/dex/InitializeHezPoolModal.tsx TS2339
|
||||
1 src/components/dex/InitializeUsdtModal.tsx TS2339
|
||||
1 src/components/dex/PoolBrowser.tsx TS2339
|
||||
1 src/components/dex/RemoveLiquidityModal.tsx TS2339
|
||||
1 src/components/dex/RemoveLiquidityModal.tsx TS2345
|
||||
3 src/components/dex/SwapInterface.tsx TS2345
|
||||
1 src/components/forum/DiscussionThread.tsx TS2339
|
||||
1 src/components/forum/DiscussionThread.tsx TS2740
|
||||
1 src/components/governance/ElectionsInterface.tsx TS2345
|
||||
2 src/components/governance/GovernanceHistory.tsx TS2339
|
||||
10 src/components/governance/MyVotes.tsx TS2339
|
||||
2 src/components/notifications/NotificationCenter.tsx TS2322
|
||||
2 src/components/notifications/NotificationCenter.tsx TS2739
|
||||
2 src/components/p2p/AdList.tsx TS2322
|
||||
2 src/components/p2p/AdList.tsx TS2339
|
||||
2 src/components/perwerde/CourseList.tsx TS2353
|
||||
1 src/components/security/PermissionEditor.tsx TS2304
|
||||
1 src/components/security/PermissionEditor.tsx TS2552
|
||||
1 src/components/security/SecurityAudit.tsx TS2304
|
||||
1 src/components/security/SessionMonitor.tsx TS2552
|
||||
1 src/components/theme-provider.tsx TS2322
|
||||
1 src/components/trading/PriceChart.tsx TS2345
|
||||
1 src/components/trading/PriceChart.tsx TS2352
|
||||
4 src/components/wallet/WalletButton.tsx TS2339
|
||||
2 src/contexts/AuthContext.tsx TS2322
|
||||
1 src/contexts/ReferralContext.tsx TS2345
|
||||
10 src/hooks/use-toast.ts TS2339
|
||||
2 src/hooks/use-toast.ts TS2395
|
||||
3 src/hooks/useDelegation.ts TS2339
|
||||
6 src/hooks/useGovernance.ts TS2339
|
||||
1 src/hooks/useMobileBridge.ts TS2345
|
||||
8 src/pages/AdminPanel.tsx TS2322
|
||||
3 src/pages/AdminPanel.tsx TS2345
|
||||
1 src/pages/Citizens.tsx TS2345
|
||||
5 src/pages/Dashboard.tsx TS2322
|
||||
2 src/pages/Dashboard.tsx TS2339
|
||||
1 src/pages/Dashboard.tsx TS2769
|
||||
1 src/pages/EducationPlatform.tsx TS2353
|
||||
4 src/pages/Elections.tsx TS2339
|
||||
3 src/pages/Elections.tsx TS2345
|
||||
1 src/pages/Elections.tsx TS2352
|
||||
8 src/pages/Explorer.tsx TS2339
|
||||
2 src/pages/P2PDispute.tsx TS2554
|
||||
2 src/pages/P2PTrade.tsx TS2322
|
||||
3 src/pages/P2PTrade.tsx TS2339
|
||||
2 src/pages/Presale.tsx TS2339
|
||||
2 src/pages/Presale.tsx TS2345
|
||||
4 src/pages/TelegramConnect.tsx TS2339
|
||||
2 src/pages/WalletDashboard.tsx TS2339
|
||||
2 src/pages/citizens/CitizensIssues.tsx TS2339
|
||||
3 src/pages/citizens/GovernmentEntrance.tsx TS2339
|
||||
1 src/pages/education/CertificatesPage.tsx TS2339
|
||||
1 src/pages/education/CertificatesPage.tsx TS2769
|
||||
1 src/pages/finance/TaxZekatPage.tsx TS2339
|
||||
2 src/pages/launchpad/CreatePresale.tsx TS2345
|
||||
29 src/pages/launchpad/PresaleDetail.tsx TS2339
|
||||
6 src/pages/launchpad/PresaleDetail.tsx TS2345
|
||||
1 src/pages/launchpad/PresaleDetail.tsx TS2362
|
||||
4 src/pages/launchpad/PresaleList.tsx TS2339
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Hold web's type errors to a ratchet.
|
||||
|
||||
web/ has type errors that predate its typecheck gate; fixing them all at once
|
||||
would mean editing hundreds of lines of production code with little test
|
||||
cover, so the gate used to run with continue-on-error and could not fail.
|
||||
This makes it a real gate without that big bang: the errors that exist are
|
||||
recorded per file and error code in ops/typecheck-baseline.txt, and the check
|
||||
fails when any file gains an error of any code. It also fails when errors were
|
||||
fixed but the baseline was not lowered with them, so a gain cannot quietly be
|
||||
given back later.
|
||||
|
||||
python3 ops/typecheck-ratchet.py # check (run from the repo root)
|
||||
python3 ops/typecheck-ratchet.py --update # rewrite the baseline (only ever lower it)
|
||||
|
||||
Line numbers are left out of the signature on purpose: they move with every
|
||||
edit above an error, and a gate that fails on that is a gate people disable.
|
||||
"""
|
||||
import collections
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
||||
BASELINE = ROOT / 'ops' / 'typecheck-baseline.txt'
|
||||
ERROR = re.compile(r'^(?P<file>[^(\s][^(]*)\(\d+,\d+\): error (?P<code>TS\d+):')
|
||||
|
||||
|
||||
def current() -> collections.Counter:
|
||||
out = subprocess.run(['npm', 'run', '--silent', 'typecheck'], cwd=ROOT / 'web',
|
||||
capture_output=True, text=True)
|
||||
counts = collections.Counter()
|
||||
for line in (out.stdout + out.stderr).splitlines():
|
||||
m = ERROR.match(line)
|
||||
if m:
|
||||
counts[f"{m['file']} {m['code']}"] += 1
|
||||
if out.returncode != 0 and not counts:
|
||||
sys.exit(f'typecheck failed without reporting type errors:\n{out.stdout}{out.stderr}')
|
||||
return counts
|
||||
|
||||
|
||||
def baseline() -> collections.Counter:
|
||||
counts = collections.Counter()
|
||||
for line in BASELINE.read_text().splitlines():
|
||||
if line and not line.startswith('#'):
|
||||
n, sig = line.split(' ', 1)
|
||||
counts[sig] = int(n)
|
||||
return counts
|
||||
|
||||
|
||||
def main() -> int:
|
||||
now = current()
|
||||
if '--update' in sys.argv:
|
||||
lines = [f'{n} {sig}' for sig, n in sorted(now.items())]
|
||||
BASELINE.write_text('# count file code — written by ops/typecheck-ratchet.py --update\n'
|
||||
+ '\n'.join(lines) + '\n')
|
||||
print(f'baseline: {sum(now.values())} errors in {len(now)} file/code pairs')
|
||||
return 0
|
||||
|
||||
base = baseline()
|
||||
worse = {sig: (base.get(sig, 0), n) for sig, n in now.items() if n > base.get(sig, 0)}
|
||||
better = {sig: (n, now.get(sig, 0)) for sig, n in base.items() if now.get(sig, 0) < n}
|
||||
for sig, (was, isnow) in sorted(worse.items()):
|
||||
print(f'NEW {sig}: {was} -> {isnow}')
|
||||
for sig, (was, isnow) in sorted(better.items()):
|
||||
print(f'fixed {sig}: {was} -> {isnow}')
|
||||
print(f'type errors: {sum(now.values())} (baseline {sum(base.values())})')
|
||||
if worse:
|
||||
print('New type errors. Fix them; the baseline only ever goes down.')
|
||||
return 1
|
||||
if better:
|
||||
# Fail here too: a gain that is not written into the baseline can be
|
||||
# given back later without the gate noticing.
|
||||
print('Fewer errors than the baseline: run with --update and commit the new baseline in this change.')
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -29,10 +29,12 @@
|
||||
"@pezkuwi/lib": ["../shared/lib"],
|
||||
"@pezkuwi/lib/*": ["../shared/lib/*"],
|
||||
"@pezkuwi/utils": ["../shared/utils"],
|
||||
"@pezkuwi/utils/*": ["../shared/utils/*"],
|
||||
"@pezkuwi/theme": ["../shared/theme"],
|
||||
"@pezkuwi/types": ["../shared/types"],
|
||||
"@pezkuwi/components/*": ["../shared/components/*"],
|
||||
"@shared/*": ["../shared/*"]
|
||||
"@shared/*": ["../shared/*"],
|
||||
"*": ["./node_modules/@types/*", "./node_modules/*"]
|
||||
},
|
||||
"types": ["vite/client"]
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user