Complint
A static analysis CLI that parses TypeScript and JavaScript into an AST and flags GDPR and privacy risks where the code is written, before it reaches production.
Summary
- Role
- TODO: role
- When
- TODO: timeframe (ongoing)
- Stack
- TypeScript · Node.js · typescript-estree (AST) · npm workspaces · tsup · Changesets · GitHub Actions · SARIF
- Links
Problem
Developers rarely read privacy regulation, and compliance officers don't review pull requests. Personal-data risks such as logging PII, storing unhashed passwords, or exposing unprotected export routes reach production because nothing checks for them where the code is written.
What I built
- Parse each file into an AST with @typescript-eslint/typescript-estree and walk it once, calling each rule's visitors per node type.
- Express each regulatory requirement as a rule that matches names, decorators and local syntax patterns in NestJS, Express, TypeORM and Sequelize code, then cite the legal context in the finding (e.g. GDPR Article 5(1)(c)).
- Make everything a plugin: the built-in GDPR rules use the same plugin shape as third-party packs, and language adapters separate parsing from rules, so new regulations and languages don't touch the engine.
- Key the result cache on tool version, plugins, rule ids and severities so a plugin upgrade or config change never serves stale results.
- Report as console, JSON or SARIF 2.1.0, and use exit codes (0, 1 for errors, 2 for config, plugin or parse failures) so CI pipelines can gate on it.
- Ship it as complinter on npm from an npm workspaces monorepo with enforced package boundaries, bundled into one package and released through Changesets and npm trusted publishing.
Results
- Published to npm (v1.1.0) with provenance, released through an OIDC trusted-publishing pipeline.
- 10 built-in GDPR rules plus 2 NestJS plugin rules.
- 200 passing automated tests, including golden-output tests and a test that packs and installs the real tarball.
- 3 output formats: console, JSON and SARIF for GitHub code scanning.
What I learned
- Heuristic, name-based rules trade precision for reach. A clean scan can't prove compliance, so the tool has to say so, and false-positive rates need measuring, not assuming.
- Golden-output tests made it safe to refactor from a hardcoded rule set to a plugin architecture without changing any user-visible behaviour.
- Treating built-in rules as a plugin forced the plugin API to be real, and designing the language adapter early made future languages a plugin concern instead of an engine rewrite.