Skip to content

Refresh the project type registry#2119

Merged
bbatsov merged 15 commits into
masterfrom
feature/project-type-refresh
Jul 25, 2026
Merged

Refresh the project type registry#2119
bbatsov merged 15 commits into
masterfrom
feature/project-type-refresh

Conversation

@bbatsov

@bbatsov bbatsov commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Projectile's type registry had fallen a good way behind the ecosystems it
covers, so this brings it up to date and fills in the gaps.

Three of these are outright bugs rather than gaps. The angular type could
never match anything: its two markers were ANDed, but a project has either
angular.json (Angular 6+) or .angular-cli.json. The Python types shadowed
each other, because pyproject.toml was checked before django,
python-poetry, python-pipenv and python-tox - and nearly every Python
project has one, so those four were effectively dead. And php-symfony
required an app directory (gone since Symfony 3) plus a vendor one (which
only exists after someone has run composer).

Then 34 new types. The one most people will notice is node: a package.json
with no committed lock file matched nothing at all and came out as a generic
project. The rest are Bun, Deno, Nx, Turborepo, uv, PDM, plain Composer,
Laravel, Xcode, Flutter, the infrastructure tools (Terraform, Pulumi, Helm,
Ansible, Compose), the task runners (just, mise, Buck2, Pants), nine more
languages and five static site generators.

The (:any "a" "b") marker clause is new and is what lets most of that be
expressed as data - Bazel's MODULE.bazel, Gradle's Kotlin DSL, build.zig
and the four Taskfile spellings would each have needed a predicate function
otherwise, which also loses the single-directory-listing fast path detection
uses.

The types table in the manual is generated from the registry now. It had
drifted well behind even before this - Go, .NET, Nim and Elixir were all
missing from it.

bbatsov added 15 commits July 25, 2026 09:21
Marker lists are ANDed, so a build tool with several spellings of its
build file (build.gradle vs build.gradle.kts) couldn't be expressed
without dropping down to a predicate function, which also loses the
single-directory-listing fast path detection uses for plain names.

A marker element can now be an (:any FILE...) clause, satisfied by any
one of its files. All of the alternatives seed the project root files,
so either spelling anchors a root.
Angular's two markers were ANDed, but a project has either angular.json
(Angular 6+) or .angular-cli.json, never both, so the type could never
match. The rest had fallen behind their ecosystems: Bazel 8 builds
around MODULE.bazel, new Gradle builds use the Kotlin DSL, a Zig project
only grows a build.zig.zon once it declares dependencies, and go-task
reads three more Taskfile spellings.
Symfony's console moved to bin/ in Symfony 3 and server:run left the
framework entirely; the Dart CLI subsumed pub in 2.10; setup.py build is
deprecated by the PyPA; and poetry projects run pytest, not unittest
discovery. Rails had its server wired to compile, which left run empty -
the server is now the run command and compile is rake, matching the
other Ruby types.
Detection walks the types in reverse registration order, so pyproject.toml
- registered last and present in nearly every Python project these days -
matched before django, poetry, pipenv and tox ever got a look in. Those
four types were effectively dead, and a Django project lost its file kinds
along with its commands.

The block is now ordered generic-manifest first, tool lock file next,
framework last. Django's server moved to the run command while it was
being rewritten; collectstatic is the closest thing it has to a build.
A package.json with no committed lock file matched nothing at all and
came out as a generic project, and neither Bun nor Deno was recognized.
Nx and Turborepo sit above whichever package manager a monorepo uses, so
they're registered last and win over it.
uv has become the default choice for new Python projects and we had no
type for it, so those projects fell through to the bare pyproject.toml
entry and were told to build with python -m build.
Symfony was the only PHP type we shipped, so every other PHP project -
Laravel included - fell back to generic, or to npm once you counted the
package.json its asset pipeline ships. The PHP types now sit after the
JavaScript ones for the same reason Rails does.
Neither Apple's own project format nor Flutter was recognized, which
left iOS and mobile work as generic projects. Flutter is detected off
the Flutter SDK dependency in pubspec.yaml, since a Flutter app is a
Dart project as far as its manifest name goes.
Terraform, Pulumi, Helm, Ansible and Compose repositories all came out
as generic projects. They're registered before everything else, so they
only match when a repository has no build tool of its own - plenty of
projects ship a Compose file alongside their real manifest.
The first two are fallbacks - a justfile normally sits next to a real
build tool - while Buck2 and Pants are build systems in their own right
and are registered alongside Bazel.
Gleam, Babashka, scala-cli, D, Fortran, Ada, Foundry, Godot and
PlatformIO. Babashka gets no lifecycle commands on purpose - its tasks
are whatever a project defines in bb.edn.
Hugo, Jekyll, Zola, MkDocs and Quarto. Zola is detected but deliberately
doesn't anchor a project root: its marker is a bare config.toml, which
is far too common a file name to treat as one.
The hand-maintained table had drifted well behind the registry - it was
missing Go, .NET, Nim and Elixir among others, and every type added in
this batch would have had to be typed in by hand. It's now generated from
projectile-project-types, listing each type with its markers, and says
how ties between overlapping types are broken.
@bbatsov
bbatsov merged commit 3fcd3d4 into master Jul 25, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant