Why this case study matters
Angular is one of the most-watched JavaScript framework repos on GitHub
(~95k stars, ~25k forks) — a TypeScript mega-repo (~3M LoC across 16
published @angular/* packages) wired through a Bazel workspace and
orchestrated by a bespoke in-house CLI (@angular/ng-dev). It’s a
distinct shape from microsoft/typescript (which IS the TS compiler) and
from vercel/next.js (a hybrid pnpm+Cargo dual-workspace). angular sits
in the active TS-monorepo + Bazel segment that no per-language
linter catches end-to-end.
For adopters in enterprise TS-monorepos using Bazel (Google’s internal Angular build, Salesforce’s Lightning Web Runtime, etc.) the same shape is replicated — and the same gaps. A repo this disciplined, with this much custom in-house tooling, is exactly the kind of place where alint is the layer that sees the cross-language API parity contract that no per-language linter does.
Headline catch
6 source files with non-canonical @license header — including
packages/core/src/defer/interfaces.ts with a leading UTF-8 BOM byte
that prettier doesn’t catch and tslint doesn’t see. Plus 5 packages
without an index.api.md golden that pnpm public-api:check
silently no-ops on (the existing tool only diffs against goldens that
already exist; a missing golden is a free pass). Plus 2 packages with
non-canonical version field (zone.js at 0.16.1, benchpress at
0.4.0-PLACEHOLDER — the latter won’t substitute correctly during
release).
These are drifts no existing tool in angular’s pipeline catches: tslint
sees source semantics, prettier sees formatting, pnpm public-api:check only diffs goldens that exist. alint sits exactly
in the gap.
Where alint earns its keep here
goldens/public-api/<pkg>/discipline is THE canonical example of the v0.11+cross_language_implementation_completeshape applied within a single language — TypeScript source ↔ TypeScript API surface golden, 50 goldens locking the public surface of 13 of 16 packages. angular is one of 5 saturated demand sources for this primitive (alongside arrow’s per-language schema parity, TF’s 1,185 textproto goldens, protobuf’s 10 in-tree language bindings, and flutter’s 6 native-OS embedders).- The
.ng-dev/in-house CLI is a fascinating contrast to the more-typical husky+lint-staged+changesets stack. angular built its own toolchain and the structural invariants around its config surface are exactly what alint expresses well. - Per-package manifest discipline — 16
package.jsonfiles enforced in single-digit milliseconds, vs. the ~2-3 s of warm-cache startup that sequentialnode -e "require()"calls would burn. - The same
repository.directoryregression class that bitreact-refreshin the facebook/react case study is caught here at config-parse time.
Future story angles
- Launch tile candidate — position as the canonical “TS-monorepo + Bazel-built mega-framework with strict per-package discipline” data point alongside kubernetes, airflow, microsoft/typescript, vercel/next.js, facebook/react.
- Cross-language parity narrative — pair angular’s
goldens/public-api discipline with arrow’s per-language schema test
fixtures, TF’s textproto goldens, protobuf’s bindings, and flutter’s
embedders for a “5 saturated sources” launch-post on
cross_language_implementation_completeshipping in v0.11+. - Enterprise TS-monorepo angle — same shape replicates in Google internal Angular, Salesforce LWR, and many other Bazel+TS monorepos. A “what alint does for your enterprise TS-monorepo” case study can generalise from this.