Refresh the project type registry#2119
Merged
Merged
Conversation
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.
This was referenced Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
angulartype couldnever match anything: its two markers were ANDed, but a project has either
angular.json(Angular 6+) or.angular-cli.json. The Python types shadowedeach other, because
pyproject.tomlwas checked beforedjango,python-poetry,python-pipenvandpython-tox- and nearly every Pythonproject has one, so those four were effectively dead. And
php-symfonyrequired an
appdirectory (gone since Symfony 3) plus avendorone (whichonly exists after someone has run composer).
Then 34 new types. The one most people will notice is
node: apackage.jsonwith 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 beexpressed as data - Bazel's
MODULE.bazel, Gradle's Kotlin DSL,build.zigand 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.