projectdetect

package module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 13 Imported by: 0

README

projectdetect

CI Go Reference

Detect what kind of project a directory is — pure Go, no cgo.

projectdetect answers two questions over a filesystem:

  • Detect(fsys, dir) — what project type(s) does this directory look like? (a directory can match several at once — a Go module that also ships a docker-compose.yml matches both)
  • Find(ctx, root, opts) — walk a tree and report every project root under it.

A type matches by indicators: an exact filename (HasFile), a file-basename glob (HasGlob), a subdirectory-basename glob (HasSubdirGlob, for directory markers like *.xcodeproj), or — optionally — a CEL expression over the directory's files / subdirs.

Built-in types

go, node, rust, python, ruby, java-maven, java-gradle, dotnet, terraform, docker-compose, the language / build-tool ecosystems swift, php, scala-sbt, scala-mill, cmake, autotools, r, zig, perl, matlab, and the static-site generators hugo, jekyll, eleventy, astro, gatsby, mkdocs, docusaurus, pelican (28 total). The dotnet type covers *.csproj / *.fsproj / *.vbproj / *.sln / *.slnx plus global.json / Directory.Build.props / Directory.Packages.props / nuget.config. swift matches Package.swift (SwiftPM), *.podspec (CocoaPods), and the *.xcodeproj / *.xcworkspace bundles (Xcode); cmake matches CMakeLists.txt (C/C++).

Each type also declares its canonical build-artefact dirs (bin/obj, node_modules, target, …) — see CollectBuildExcludes.

Detect a file's language

A separate axis from project types: project types answer "what kind of project is this directory?", while LanguageForPath answers "what language is this single file?" by its extension. A language commonly has several extensions (C++ alone has a dozen header/source spellings), so the mapping is one-to-many.

projectdetect.LanguageForPath("src/app.py")   // "python"
projectdetect.LanguageForPath("Widget.cpp")   // "cpp"
projectdetect.LanguageForExt(".rs")           // "rust"  (".rs", "rs", ".RS" all work)
projectdetect.LanguageForPath("README.md")    // ""      (unrecognised)

projectdetect.Languages()                      // sorted ids
projectdetect.ExtensionsForLanguage("python")  // [".pxd" ".py" ".pyi" ".pyw" ".pyx"]

Recognised ids: go, python, javascript, typescript, java, rust, c, cpp, csharp, kotlin, php, ruby, scala, r, matlab, perl, swift. A few ambiguous extensions are assigned to a single language by convention — .hc, .mmatlab, .scscala, .tperl — so the extension→language map is 1:1.

Skip vendored / minified files

A third axis: "is this file third-party content an analysis tool should skip?" Unlike a project type's BuildExcludes (which prune whole directories), this classifies individual file paths — so a bundled jquery.min.js or a vendored library committed anywhere (even under docs/) is caught. The default patterns are a curated subset of GitHub Linguist's vendor.yml.

projectdetect.IsVendored("docs/js/jquery.min.js")     // true (minified)
projectdetect.IsVendored("node_modules/x/index.js")   // true (dependency dir)
projectdetect.IsVendored("website/scripts/prism.js")  // true (known library)
projectdetect.IsVendored("src/main.go")               // false (real source)

Flexible — extend the built-ins, or build your own set:

// Add patterns to the process-wide default used by IsVendored:
projectdetect.RegisterVendorPattern(`\.pb\.go$`, `(^|/)generated/`)

// Or a fully custom matcher (regexps over the slash-separated path):
m := projectdetect.NewVendorMatcher()          // empty; DefaultVendorMatcher() preloads built-ins
_ = m.Add(`(^|/)my-vendor/`)
m.Match("libs/my-vendor/thing.js")             // true

For bundles with no telltale name, IsMinified(content []byte) judges by shape (a meaningfully-sized file whose average line length far exceeds normal source):

projectdetect.IsMinified(data) // true for a packed one-liner, false for hand-written source

Install

go get github.com/richardwooding/projectdetect

Usage

package main

import (
	"fmt"
	"os"

	"github.com/richardwooding/projectdetect"
)

func main() {
	for _, m := range projectdetect.Detect(os.DirFS("."), ".") {
		fmt.Printf("%s (via %s)\n", m.Type, m.Indicator)
	}
}

Recursively find project roots under a tree:

res, err := projectdetect.Find(ctx, "/path/to/code", projectdetect.FindOptions{})

Pruning the walk

Find, CollectBuildExcludes, and the resolver walk-up all prune version-control metadata directories (.git, .hg, .svn) by default — they never hold project roots and walking them is wasted I/O. Set IncludeVCSDirs: true to descend into them.

To mirror an external walker's exclusions exactly, pass a SkipDir predicate. It's consulted for every directory below the walk root; returning true prunes that whole subtree:

res, err := projectdetect.Find(ctx, root, projectdetect.FindOptions{
    SkipDir: func(relPath, name string) bool {
        return name == "node_modules" || name == "target"
    },
})

// Same hook on the build-artefact collector …
ex, err := projectdetect.CollectBuildExcludesWithOptions(ctx, root, projectdetect.FindOptions{
    SkipDir: skip,
})

// … and on the per-file resolver walk-up.
r := projectdetect.NewResolverWithOptions(root, nil, projectdetect.ResolveOptions{SkipDir: skip})

Custom types (YAML)

Load extra project types from YAML — has_file, has_glob, has_subdir_glob, or cel:

project_types:
  - name: my-stack
    indicators:
      - has_file: "my.config"
      - has_glob: "*.mytool"
      - has_subdir_glob: "*.bundle"
      - cel: '"services" in subdirs && "compose.yaml" in files'
n, err := projectdetect.LoadFromFile("project-types.yaml") // registers into the default registry

CEL indicators are opt-in (no cel-go unless you want it)

The base package has no CEL dependency. cel: indicators are compiled by the celindicators sub-package — enable them with a blank import:

import _ "github.com/richardwooding/projectdetect/celindicators"

Without it, HasFile / HasGlob indicators and all built-ins work as normal; registering a type that uses a cel: indicator returns a clear error telling you to add the import. This keeps cel-go (and its transitive deps) out of the build for consumers that only need filename/glob matching.

Provenance

Extracted from file-search-on, where it powers the detect-project / find-projects / which-project commands.

License

MIT — see LICENSE.

Documentation

Overview

Package projecttype detects what kind of project lives in a directory — Go module, Node app, Rust crate, Terraform stack, etc. — by checking for canonical indicator files (go.mod, package.json, Cargo.toml, *.tf, …) in the directory's own listing (not recursive).

Mirrors the FilenameMatcher pattern from internal/content but at a directory granularity. A directory can match multiple project types at once: a Go module that also ships docker-compose.yml matches both `go` and `docker-compose` simultaneously, exactly like the cross-predicate firing for file content types (PR #95).

Custom user-registered project types via CEL expressions are NOT in this MVP — a follow-up PR will add a CEL-driven extension path over the same registry.

Index

Constants

View Source
const ConfigDirName = "file-search-on"

ConfigDirName is the per-platform user-config-dir subdirectory project-type configs live under. Joined with os.UserConfigDir() → $XDG_CONFIG_HOME/file-search-on / $HOME/Library/Application Support/file-search-on / %APPDATA%\file-search-on depending on platform.

View Source
const ConfigFileName = "project-types.yaml"

ConfigFileName is the basename project-type YAML config files use in both the user-wide and per-project search locations. Wrapped in a `.file-search-on/` directory rather than living as a dotfile at the top level so future companion configs (cache prefs, default flags, …) can sit alongside without further filename inflation.

View Source
const PerProjectDirName = ".file-search-on"

PerProjectDirName is the directory project-type configs live in when colocated with a checkout. Walked from the current working directory only — git-style ancestor walk-up is a follow-up.

Variables

This section is empty.

Functions

func CollectBuildExcludes

func CollectBuildExcludes(ctx context.Context, root string) ([]string, error)

CollectBuildExcludes is the package-level shortcut over DefaultRegistry.

func CollectBuildExcludesWithOptions added in v0.4.0

func CollectBuildExcludesWithOptions(ctx context.Context, root string, opts FindOptions) ([]string, error)

CollectBuildExcludesWithOptions is the package-level shortcut over DefaultRegistry.

func DiscoveryPaths

func DiscoveryPaths() []string

DiscoveryPaths is the legacy plain-paths shortcut over DiscoveryEntries — kept because LoadDiscovered (and external callers) only need the path strings. New code that wants scope labels should call DiscoveryEntries directly.

func ExtensionsForLanguage added in v0.5.0

func ExtensionsForLanguage(lang string) []string

ExtensionsForLanguage returns the extensions mapped to a language id, sorted and each with a leading dot, or nil for an unknown id. The returned slice is a fresh copy the caller may modify. (langExtensions slices are sorted in place at init, so no re-sort is needed here.)

func IsMinified added in v0.6.0

func IsMinified(content []byte) bool

IsMinified reports whether content looks minified from its shape alone — useful for bundles that carry no telltale name (e.g. a minified prism.js). It is a heuristic: content of a meaningful size whose average line length far exceeds normal source. Files under 512 bytes are never considered minified, and binary content (a NUL byte in the first 512 bytes) is rejected outright so images/PDFs/archives — which also have few newlines — aren't mistaken for minified text. Only the first maxMinifiedScan bytes are examined.

func IsVendored added in v0.6.0

func IsVendored(path string) bool

IsVendored reports whether path looks like vendored/minified/third-party content, using the built-in pattern set (plus anything added via RegisterVendorPattern). For a matcher you fully control, use a VendorMatcher.

func LanguageForExt added in v0.5.0

func LanguageForExt(ext string) string

LanguageForExt returns the language id for a single file extension, or "" when unrecognised. The argument is normalised, so "go", ".go", and ".GO" are all accepted.

func LanguageForPath added in v0.5.0

func LanguageForPath(path string) string

LanguageForPath returns the canonical language id for a file path, derived from its extension, or "" when the extension is not recognised. Matching is case-insensitive, so "Main.GO" and "x.R" resolve like "main.go" and "x.r".

func Languages added in v0.5.0

func Languages() []string

Languages returns the sorted set of language ids known to the detector. The returned slice is a fresh copy the caller may modify.

func LoadDiscovered

func LoadDiscovered() (int, error)

LoadDiscovered is the package-level shortcut targeting DefaultRegistry(). The CLI's main() calls this before kong dispatches the subcommand (when --no-config-search isn't set).

func LoadFromFile

func LoadFromFile(path string) (int, error)

LoadFromFile is the package-level shortcut that targets DefaultRegistry(). The CLI's --project-type-config flag uses this directly.

func Register

func Register(t *ProjectType)

Register adds a project type to the package-level default registry. Panics on CEL compile failure — appropriate for init() callers (built-in types) where a bad indicator is a programming bug. Config-driven callers should use Registry.Register on DefaultRegistry() directly to get an error return.

func RegisterVendorPattern added in v0.6.0

func RegisterVendorPattern(patterns ...string) error

RegisterVendorPattern adds patterns to the process-wide matcher used by IsVendored. Safe for concurrent use; returns the first compile error.

func SetCELCompiler

func SetCELCompiler(fn func(expr string) (DirEvaluator, error))

SetCELCompiler installs the CEL indicator compiler. Called from celindicators' init(); apps enable CEL indicators with a blank import:

import _ "github.com/richardwooding/projectdetect/celindicators"

Types

type Config

type Config struct {
	ProjectTypes []ConfigEntry `yaml:"project_types"`
}

Config is the YAML schema accepted by LoadFromFile. Each entry registers a new ProjectType alongside the built-ins.

project_types:
  - name: my-app
    description: Internal Foo app
    indicators:
      - cel: '"services" in subdirs && "foo.yaml" in files'
  - name: helm-chart
    indicators:
      - has_file: Chart.yaml
      - has_file: values.yaml

type ConfigEntry

type ConfigEntry struct {
	Name        string            `yaml:"name"`
	Description string            `yaml:"description"`
	Indicators  []ConfigIndicator `yaml:"indicators"`
}

ConfigEntry is one project type declared in the config file.

type ConfigIndicator

type ConfigIndicator struct {
	HasFile       string `yaml:"has_file,omitempty"`
	HasGlob       string `yaml:"has_glob,omitempty"`
	HasSubdirGlob string `yaml:"has_subdir_glob,omitempty"`
	CEL           string `yaml:"cel,omitempty"`
}

ConfigIndicator is the YAML representation of an Indicator. Exactly one of HasFile / HasGlob / HasSubdirGlob / CEL should be set per entry.

type DirEvaluator

type DirEvaluator interface {
	Eval(files, subdirs []string) bool
}

DirEvaluator evaluates a compiled directory predicate (a CELExpr indicator) against a directory's file/subdir basenames. The base package stays free of any CEL dependency by going through this interface; the concrete implementation is supplied by the optional github.com/richardwooding/projectdetect/celindicators sub-package.

type DiscoveryEntry

type DiscoveryEntry struct {
	Scope string // "user-wide" | "per-project"
	Path  string
}

DiscoveryEntry annotates a single discovery path with its scope ("user-wide" or "per-project") so consumers can label / order without re-deriving the meaning from the path itself.

func DiscoveryEntries

func DiscoveryEntries() []DiscoveryEntry

DiscoveryEntries returns the project-type config search locations in load order (later layers register on top of earlier), each annotated with its scope. Paths whose anchor can't be resolved (UserConfigDir unset, Getwd fails) are omitted so the caller never sees an empty / suspicious entry.

type FindOptions

type FindOptions struct {
	// Types, when non-empty, restricts results to projects matching
	// at least one of the named types. Empty means accept all.
	Types []string
	// Excludes is a list of basename globs that prune directories
	// during the walk. Same semantics as search.Options.Excludes.
	Excludes []string
	// SkipDir, when non-nil, is consulted for every directory below
	// root: returning true prunes that subtree. It runs in addition to
	// Excludes and VCS pruning — any one of them firing prunes the
	// directory. nil means no extra pruning (backward-compatible).
	SkipDir SkipDirFunc
	// IncludeVCSDirs, when false (the default), prunes version-control
	// metadata directories (.git, .hg, .svn) from the walk — they never
	// contain project roots and walking them is wasted I/O. Set true to
	// restore descending into them.
	IncludeVCSDirs bool
	// Nested, when true, keeps walking inside a matched project
	// root so nested sub-projects (monorepo workspaces, vendored
	// dependencies) are also reported. Default (false) stops at the
	// first match, which is the common "find me all my Go repos"
	// shape.
	Nested bool
	// RespectGitignore parses a .gitignore at the walk root and
	// prunes matching paths. Nested .gitignore files are not
	// consulted (same caveat as search).
	RespectGitignore bool
	// Timeout bounds the walk. Zero means no timeout. On expiry,
	// FindResult.Cancelled is set with the partial result.
	Timeout time.Duration
}

FindOptions configures a recursive search for project roots under a starting directory.

type FindResult

type FindResult struct {
	Projects           []FoundProject `json:"projects"`
	Count              int            `json:"count"`
	Cancelled          bool           `json:"cancelled,omitempty"`
	CancellationReason string         `json:"cancellation_reason,omitempty"`
	ElapsedSeconds     float64        `json:"elapsed_seconds,omitempty"`
}

FindResult is the structured output of Find.

func Find

func Find(ctx context.Context, root string, opts FindOptions) (*FindResult, error)

Find is the package-level shortcut over DefaultRegistry.

type FoundProject

type FoundProject struct {
	Path  string  `json:"path"`
	Types []Match `json:"types"`
}

FoundProject is one project root found during a Find walk.

type Indicator

type Indicator struct {
	// HasFile is a case-insensitive exact basename match. Most
	// built-in project indicators are this shape (go.mod,
	// package.json, Cargo.toml, pyproject.toml, Gemfile, pom.xml).
	HasFile string
	// HasGlob is a glob (filepath.Match) over FILE basenames. Used by
	// Terraform (`*.tf`), .NET (`*.csproj`), and similar
	// extension-based project signals. Directories are never matched
	// — use HasSubdirGlob for those.
	HasGlob string
	// HasSubdirGlob is a glob (filepath.Match) over immediate
	// SUBDIRECTORY basenames. Used by project types whose canonical
	// marker is a directory bundle rather than a file — e.g. Xcode's
	// `*.xcodeproj` / `*.xcworkspace`. HasFile / HasGlob only ever see
	// files, so a directory marker can only fire through this rule.
	HasSubdirGlob string
	// CELExpr is a CEL expression evaluated against a directory
	// context with two list-of-string variables:
	//
	//   files    — basenames of files in the inspected dir
	//   subdirs  — basenames of immediate subdirectories
	//
	// Example: `"services" in subdirs && "foo.yaml" in files`. The
	// expression must compile at Register() time; bad CEL fails
	// the registration. Used by user-defined custom project types
	// loaded from --project-type-config YAML.
	CELExpr string
}

Indicator is a single match rule against a directory's contents. Exactly one of HasFile / HasGlob / HasSubdirGlob / CELExpr should be set per indicator.

func (Indicator) String

func (i Indicator) String() string

String describes the indicator in a human-readable form, surfaced to MCP / CLI consumers so they can see WHY a project matched.

type Match

type Match struct {
	Type      string `json:"type"`
	Indicator string `json:"indicator"`
}

Match couples a matched ProjectType with the indicator that fired. Surfaced in detect_project and find_projects output so consumers can audit detection decisions.

func Detect

func Detect(fsys fs.FS, dir string) []Match

Detect is the package-level shortcut over DefaultRegistry.

func ResolveForPath

func ResolveForPath(filePath string, reg *Registry) (string, []Match)

ResolveForPath is the single-shot, no-cache, unbounded-walk-up counterpart to ProjectResolver.Resolve. Given an absolute file path, it walks up the directory chain (no root limit — terminates at the filesystem root) and returns the first ancestor that matches a registered project type plus the matched types.

Returns ("", nil) when no ancestor matches. Use this for one-off "which project does this file belong to?" lookups (e.g. the MCP resolve_project_for_path tool, the CLI which-project subcommand). For batch walks where multiple files share an ancestor, prefer ProjectResolver — it caches per-directory.

reg may be nil; nil means DefaultRegistry(). VCS metadata dirs are skipped as candidates by default — use ResolveForPathWithOptions for a SkipDir predicate or to opt back into them.

func ResolveForPathWithOptions added in v0.4.0

func ResolveForPathWithOptions(filePath string, reg *Registry, opts ResolveOptions) (string, []Match)

ResolveForPathWithOptions is ResolveForPath with caller control over which ancestor directories are considered. Because the walk is unbounded (no enclosing root), the SkipDir predicate receives the directory's full path as relPath.

reg may be nil; nil means DefaultRegistry().

type ProjectResolver

type ProjectResolver struct {
	// contains filtered or unexported fields
}

ProjectResolver answers "what project does this file belong to?" by walking up the file's directory chain to the nearest ancestor that matches a registered ProjectType. Cached per-directory via sync.Map so a walk of 1000 files in one project root costs one Detect call, not 1000.

Worker-safe: every concurrent search worker can call Resolve without coordination beyond the sync.Map.

func NewResolver

func NewResolver(root string, reg *Registry) *ProjectResolver

NewResolver returns a resolver rooted at root. Resolve will walk up no higher than root — files at the root with no project indicators return an empty match slice.

reg may be nil; nil means DefaultRegistry(). VCS metadata dirs are pruned by default — use NewResolverWithOptions for a SkipDir predicate or to opt back into them.

func NewResolverWithOptions added in v0.4.0

func NewResolverWithOptions(root string, reg *Registry, opts ResolveOptions) *ProjectResolver

NewResolverWithOptions is NewResolver with caller control over which ancestor directories are considered during the walk-up.

func (*ProjectResolver) Resolve

func (r *ProjectResolver) Resolve(filePath string) []Match

Resolve walks up from filePath's directory looking for the nearest ancestor that matches a registered project type. Returns the matched types for the closest project (alphabetically sorted by Detect), or nil if no ancestor matches up to the walk root.

Cached: each unique directory is detected at most once for the resolver's lifetime.

type ProjectType

type ProjectType struct {
	// Name is the stable identifier, lowercase + dashes (e.g. "go",
	// "node", "java-maven"). Used as the bucket key in MCP / CLI
	// output and the future is_X_project predicate root.
	Name string
	// Description is a short human-readable label.
	Description string
	// Indicators is the OR-list. The first one that matches wins
	// (and is returned to the caller for "why did this match"
	// debuggability).
	Indicators []Indicator

	// BuildExcludes is the list of canonical build-artefact
	// basenames typically present in this kind of project (e.g.
	// "vendor" for Go, "node_modules" for Node, "target" for Rust).
	// The walker unions these into its excludes when
	// search.Options.PruneBuildArtefacts is set, so a search over a
	// monorepo doesn't grovel through dependency caches by default.
	// Empty for project types that have no canonical artefact dir.
	BuildExcludes []string
	// contains filtered or unexported fields
}

ProjectType describes a kind of project and the indicators that identify it. Indicators are evaluated against a directory's own listing (basenames only — no recursion into subdirectories). Any single indicator matching is enough to count the directory as this project type (OR semantics across the list).

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry holds the registered project types. Built-in types self-register via init() into DefaultRegistry; future custom-type registration (CEL-driven) will use the same path.

func DefaultRegistry

func DefaultRegistry() *Registry

DefaultRegistry returns the package-level registry — the singleton every consumer (MCP tool, CLI subcommand) uses.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty Registry — useful for tests that want isolation from the package-level defaultRegistry. Production code almost always uses DefaultRegistry().

func (*Registry) CollectBuildExcludes

func (r *Registry) CollectBuildExcludes(ctx context.Context, root string) ([]string, error)

CollectBuildExcludes walks root and returns the sorted, deduped union of BuildExcludes from every project type detected at or below root (Nested-style — every project, not just outer roots). Used by the search walker when Options.PruneBuildArtefacts is set to pre-populate the basename excluder before the main walk starts, so e.g. `vendor/` inside a Go module is pruned even when the file-search walker would have visited it before recognising the project.

Cheap: only directories that contain at least one project indicator contribute. Empty result when no projects are detected (or the registry has no built-ins with BuildExcludes set).

Prunes VCS dirs by default (.git/.hg/.svn). To pass a SkipDir predicate or other walk options, use CollectBuildExcludesWithOptions.

func (*Registry) CollectBuildExcludesWithOptions added in v0.4.0

func (r *Registry) CollectBuildExcludesWithOptions(ctx context.Context, root string, opts FindOptions) ([]string, error)

CollectBuildExcludesWithOptions is CollectBuildExcludes with caller control over the walk. opts.Nested is forced on (CollectBuildExcludes is inherently a nested collect — every project below root contributes), but opts.SkipDir, opts.Excludes, and opts.IncludeVCSDirs are honoured so the collect walk prunes exactly the same subtrees the caller's own walker does. opts.Types is honoured too — restrict to the project types whose excludes you care about.

func (*Registry) Detect

func (r *Registry) Detect(fsys fs.FS, dir string) []Match

Detect inspects a single directory and returns the project types it matches. A directory can match multiple types simultaneously (e.g. a Go module with a docker-compose.yml). Returns an empty slice when no project type fires.

Reads the directory's listing once (non-recursive); HasFile / HasGlob indicators run against file basenames, HasSubdirGlob against immediate subdirectory basenames, and CELExpr indicators see both `files` and `subdirs` lists. fsys=nil uses os.ReadDir for the production filesystem path.

func (*Registry) Find

func (r *Registry) Find(ctx context.Context, root string, opts FindOptions) (*FindResult, error)

Find walks root recursively and returns every directory that matches at least one project type (subject to Options.Types). By default the walker does NOT descend into matched roots (Nested=false) — set Nested=true to also surface sub-projects.

Honours ctx cancellation and Options.Timeout; on expiry the partial result is returned with Cancelled=true (same contract as the file search tool).

func (*Registry) LoadDiscovered

func (r *Registry) LoadDiscovered() (int, error)

LoadDiscovered loads every project-type config found via DiscoveryPaths into this registry, in precedence order. Missing files (most common case: the user has no custom types) are NOT errors. Returns the total number of types registered + the first real error encountered.

Real errors (YAML parse failure, bad CEL, missing indicators) are fatal — they indicate a misconfiguration the user should fix before any subcommand runs.

func (*Registry) LoadFromFile

func (r *Registry) LoadFromFile(path string) (int, error)

LoadFromFile parses path as YAML and registers every project type into this registry. Validates each entry (non-empty name + at least one indicator) and surfaces CEL compile errors with the offending entry's name. Returns the number of types registered.

Idempotent: calling LoadFromFile twice with the same config registers the types twice (caller's responsibility to avoid).

func (*Registry) Register

func (r *Registry) Register(t *ProjectType) error

Register adds a project type to this registry. Compiles any CEL-expression indicators eagerly — bad CEL is returned as an error so callers (config loaders, tests) can surface it cleanly.

func (*Registry) Types

func (r *Registry) Types() []*ProjectType

Types returns a snapshot of every registered project type, sorted by Name. Used by --list-style help output and tests.

type ResolveOptions added in v0.4.0

type ResolveOptions struct {
	// SkipDir, when non-nil, is consulted for each ancestor directory:
	// returning true skips it as a project-root candidate (the walk
	// continues to its parent). Use it to keep a resolver in step with
	// a caller's own exclusions.
	SkipDir SkipDirFunc
	// IncludeVCSDirs, when false (the default), skips version-control
	// metadata directories (.git, .hg, .svn) as project-root
	// candidates. Set true to consider them.
	IncludeVCSDirs bool
}

ResolveOptions tunes which ancestor directories a resolver walk-up considers. The zero value matches the historical behaviour except that VCS metadata dirs are pruned by default (see IncludeVCSDirs).

type SkipDirFunc added in v0.4.0

type SkipDirFunc func(relPath, name string) bool

SkipDirFunc reports whether a directory should be pruned from a walk (the directory and its whole subtree are skipped). It is consulted for every directory except the walk root, which is never pruned.

relPath is the directory's path relative to the walk root (e.g. "vendor", "a/node_modules"); name is its base name. For the unbounded ResolveForPathWithOptions walk-up there is no enclosing root, so relPath is the directory's full path.

Wire it into FindOptions.SkipDir or ResolveOptions.SkipDir to mirror an external walker's exclusions — so projectdetect visits exactly the same tree as the caller (e.g. file-search-on's own walkers).

type VendorMatcher added in v0.6.0

type VendorMatcher struct {
	// contains filtered or unexported fields
}

VendorMatcher tests a file path against a set of patterns identifying vendored, minified, or otherwise third-party content. Matching is purely path-based (no file I/O) and runs against the slash-separated path, so it is cross-platform. The zero value is not usable; construct one with NewVendorMatcher or DefaultVendorMatcher.

func DefaultVendorMatcher added in v0.6.0

func DefaultVendorMatcher() *VendorMatcher

DefaultVendorMatcher returns a new matcher preloaded with the curated built-in patterns (see defaultVendorPatterns). The returned matcher is independent, so Add-ing to it does not affect the package-level IsVendored.

func NewVendorMatcher added in v0.6.0

func NewVendorMatcher() *VendorMatcher

NewVendorMatcher returns an empty matcher — it matches nothing until you Add patterns. Use it to opt out of the built-in set entirely.

func (*VendorMatcher) Add added in v0.6.0

func (m *VendorMatcher) Add(patterns ...string) error

Add compiles and appends regexp patterns, each matched against the slash-separated path. It returns the first compile error and adds nothing in that case.

func (*VendorMatcher) Match added in v0.6.0

func (m *VendorMatcher) Match(path string) bool

Match reports whether path matches any registered pattern. Paths are normalised to forward slashes before matching.

Directories

Path Synopsis
Package celindicators provides the CEL backend for projectdetect's CELExpr indicators.
Package celindicators provides the CEL backend for projectdetect's CELExpr indicators.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL