From 49c359e428a75df8532806ac9c875aade3281a2a Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Mon, 14 Sep 2026 11:06:44 -0400 Subject: [PATCH] Add reviewed Linguist corpus conventions --- .github/workflows/ci.yml | 1 - NOTICE | 32 ++ README.md | 15 + benchmark_test.go | 1 + corpus.go | 16 +- corpus/rules.json | 424 ++++++++++++++ corpus_test.go | 9 +- roles.go | 13 +- roles_test.go | 22 +- testdata/linguist-paths.json | 1008 ++++++++++++++++++++++++++++++++++ testdata/paths.json | 4 +- walk_test.go | 3 +- 12 files changed, 1534 insertions(+), 14 deletions(-) create mode 100644 testdata/linguist-paths.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd1e872..dc32341 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,6 @@ on: push: branches: [main] pull_request: - branches: [main] permissions: {} diff --git a/NOTICE b/NOTICE index 3f423a1..baa8c64 100644 --- a/NOTICE +++ b/NOTICE @@ -12,6 +12,15 @@ Adaptations select literal directories and filenames or suffixes, apply them at any package depth, and assign roles and subtypes. They do not evaluate ignore patterns or import template negations. Python bytecode suffixes are limited to .pyc and .pyo. Lockfile names continue to come from manifests. +Vendor, documentation and generated-file conventions: github-linguist/linguist, +revision 16cac170f73c97eb4e4329d66fcb341ef25ef4f0. +Sources: lib/linguist/vendor.yml, documentation.yml and generated.rb. +Adaptations assign roles by repository purpose, narrow broad patterns to +selected names, and apply documentation directories at any package depth. +Document extensions are restricted; lowercase extensionless install/change +commands are excluded. Manifest names, content heuristics and attribute +overrides are not imported. Wrapper scripts receive build evidence; Pods +receives vendor evidence; named minified files receive generated evidence. Rules identified as roles are local conventions or intentional adaptations. MIT License @@ -54,3 +63,26 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Copyright (c) 2017 GitHub, Inc. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index e2b4dc8..dd9946f 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,10 @@ independent evidence. | `test/fixtures/input.json` | `test`, `fixture` | | `testdata/package-lock.json` | `test`, `fixture`, `generated` | | `packages/api/uv.lock` | `generated` | +| `src/Form.Designer.cs` | `source`, `generated` | +| `Pods/library/main.swift` | `vendor` | +| `gradlew` | `build` | +| `.gitattributes` | `configuration` | | `examples/client/main.go` | `example` | | `docs/api.md` | `documentation` | | `.github/SECURITY.md` | `documentation` | @@ -194,17 +198,28 @@ such as `.pytest_cache/`; generic names such as `.cache/` and `build/`, and virtual environments, receive no additional role. Bower, JSPM and vcpkg dependency directories receive `vendor` alongside any roles matched inside them. +Named minified JavaScript/CSS files, source maps and .NET designer files +also receive `generated`. Source-map and designer suffixes accept mixed +case; minified suffixes use lowercase `.min.js`, `-min.js`, `.min.css` and +`-min.css`. A plain `.d.ts` filename or a name such as `jquery.js` does not +establish generated or vendored content. + Named community documents include support, governance, maintainers, authors and roadmaps, using case-insensitive stems and selected document extensions, including `.markdown` and `.rdoc`. For example, `SUPPORT.md`, `support.md` and `Support.md` match, while `support.py` and `SUPPORT.md.bak` do not. Rakefile matching accepts any casing with an optional `.rb` extension. +Citation files, API/manual directories and installation/change documents +provide further documentation conventions. Bare `INSTALL`, `CHANGE` and +`CHANGES` match; their lowercase command names require a document extension. Sources include legal-name matching from [licenses](https://github.com/git-pkgs/licenses), layout and tool conventions from [brief](https://github.com/git-pkgs/brief), manifest, lockfile and dependency-output names from [manifests](https://github.com/git-pkgs/manifests), and selected generated-file and dependency-directory conventions from [GitHub's gitignore templates](https://github.com/github/gitignore). +[GitHub Linguist](https://github.com/github-linguist/linguist) supplies additional +vendor, documentation and generated-file conventions, adapted to these roles. [NOTICE](NOTICE) records source revisions and attribution. `CorpusVersion` identifies the embedded classification semantics for caller caches. diff --git a/benchmark_test.go b/benchmark_test.go index fd6d94f..3e4c1d7 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -16,6 +16,7 @@ func BenchmarkMatch(b *testing.B) { "main.go", "LICENSE", "packages/parser/vendor/src/parser_test.go", "packages/api/src/__pycache__/app.pyc", "packages/ui/project.tsbuildinfo", "packages/api/.pytest_cache/v/cache/nodeids", + "packages/ui/Form.DESIGNER.CS", "packages/ui/app.min.js", } { b.Run(name, func(b *testing.B) { b.ReportAllocs() diff --git a/corpus.go b/corpus.go index e813c8d..99c5ba6 100644 --- a/corpus.go +++ b/corpus.go @@ -31,7 +31,7 @@ var ( filenameRules = map[string][]rule{} foldedStems = map[int][]rule{} foldedDirectories []rule - pathDirectories []rule + pathDirectories = map[string][]rule{} foldedPrefixes []rule suffixRules [256][]rule ) @@ -67,14 +67,22 @@ func init() { case "directory-fold": foldedDirectories = append(foldedDirectories, r) case "directory-path": - pathDirectories = append(pathDirectories, r) + base := r.Pattern[strings.LastIndexByte(r.Pattern, '/')+1:] + pathDirectories[base] = append(pathDirectories[base], r) case "prefix-fold": foldedPrefixes = append(foldedPrefixes, r) - case "suffix": - last := r.Pattern[len(r.Pattern)-1] + case "suffix", "suffix-fold": + last := suffixBucket(r.Pattern[len(r.Pattern)-1]) suffixRules[last] = append(suffixRules[last], r) default: panic(fmt.Sprintf("unknown rule kind %q", r.Kind)) } } } + +func suffixBucket(last byte) byte { + if last >= 'A' && last <= 'Z' { + return last + ('a' - 'A') + } + return last +} diff --git a/corpus/rules.json b/corpus/rules.json index efe51d2..a5e40fd 100644 --- a/corpus/rules.json +++ b/corpus/rules.json @@ -1676,5 +1676,429 @@ "pattern": "vcpkg_installed", "role": "vendor", "source": "gitignore" + }, + { + "id": "vendor.directory.vendors", + "kind": "directory", + "pattern": "vendors", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory.Vendor", + "kind": "directory", + "pattern": "Vendor", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory.3rdparty", + "kind": "directory", + "pattern": "3rdparty", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory.3rd_party", + "kind": "directory", + "pattern": "3rd_party", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory.3rd-party", + "kind": "directory", + "pattern": "3rd-party", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory.third-party", + "kind": "directory", + "pattern": "third-party", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory.ThirdParty", + "kind": "directory", + "pattern": "ThirdParty", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory-path.Godeps/_workspace", + "kind": "directory-path", + "pattern": "Godeps/_workspace", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory-path..yarn/unplugged", + "kind": "directory-path", + "pattern": ".yarn/unplugged", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory-path..yarn/releases", + "kind": "directory-path", + "pattern": ".yarn/releases", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory-path.Carthage/Checkouts", + "kind": "directory-path", + "pattern": "Carthage/Checkouts", + "role": "vendor", + "source": "linguist" + }, + { + "id": "vendor.directory.Pods", + "kind": "directory", + "pattern": "Pods", + "role": "vendor", + "source": "linguist" + }, + { + "id": "documentation.directory.groovydoc", + "kind": "directory", + "pattern": "groovydoc", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.directory.Groovydoc", + "kind": "directory", + "pattern": "Groovydoc", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.directory.javadoc", + "kind": "directory", + "pattern": "javadoc", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.directory.Javadoc", + "kind": "directory", + "pattern": "Javadoc", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.directory.man", + "kind": "directory", + "pattern": "man", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.directory.Man", + "kind": "directory", + "pattern": "Man", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.directory.Doc", + "kind": "directory", + "pattern": "Doc", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.directory.Docs", + "kind": "directory", + "pattern": "Docs", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.directory-path.inst/doc", + "kind": "directory-path", + "pattern": "inst/doc", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.stem-fold.CITATION", + "kind": "stem-fold", + "pattern": "CITATION", + "role": "documentation", + "source": "linguist", + "subtype": "citation", + "extensions": [ + "", + ".cff", + ".bib", + ".md" + ] + }, + { + "id": "documentation.stem-fold.CITATIONS", + "kind": "stem-fold", + "pattern": "CITATIONS", + "role": "documentation", + "source": "linguist", + "subtype": "citation", + "extensions": [ + "", + ".bib", + ".md" + ] + }, + { + "id": "documentation.stem-fold.CHANGE", + "kind": "stem-fold", + "pattern": "CHANGE", + "role": "documentation", + "source": "linguist", + "extensions": [ + ".md", + ".txt", + ".rst", + ".adoc", + ".markdown", + ".rdoc" + ] + }, + { + "id": "documentation.stem-fold.CHANGES", + "kind": "stem-fold", + "pattern": "CHANGES", + "role": "documentation", + "source": "linguist", + "extensions": [ + ".md", + ".txt", + ".rst", + ".adoc", + ".markdown", + ".rdoc" + ] + }, + { + "id": "documentation.stem-fold.INSTALL", + "kind": "stem-fold", + "pattern": "INSTALL", + "role": "documentation", + "source": "linguist", + "extensions": [ + ".md", + ".txt", + ".rst", + ".adoc", + ".markdown", + ".rdoc" + ] + }, + { + "id": "documentation.filename.CHANGE", + "kind": "filename", + "pattern": "CHANGE", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.filename.CHANGES", + "kind": "filename", + "pattern": "CHANGES", + "role": "documentation", + "source": "linguist" + }, + { + "id": "documentation.filename.INSTALL", + "kind": "filename", + "pattern": "INSTALL", + "role": "documentation", + "source": "linguist" + }, + { + "id": "generated.suffix-fold..designer.cs", + "kind": "suffix-fold", + "pattern": ".designer.cs", + "role": "generated", + "source": "linguist", + "subtype": "codegen" + }, + { + "id": "generated.suffix-fold..designer.vb", + "kind": "suffix-fold", + "pattern": ".designer.vb", + "role": "generated", + "source": "linguist", + "subtype": "codegen" + }, + { + "id": "generated.suffix-fold..feature.cs", + "kind": "suffix-fold", + "pattern": ".feature.cs", + "role": "generated", + "source": "linguist", + "subtype": "codegen" + }, + { + "id": "generated.suffix-fold..js.map", + "kind": "suffix-fold", + "pattern": ".js.map", + "role": "generated", + "source": "linguist", + "subtype": "source-map" + }, + { + "id": "generated.suffix-fold..css.map", + "kind": "suffix-fold", + "pattern": ".css.map", + "role": "generated", + "source": "linguist", + "subtype": "source-map" + }, + { + "id": "generated.suffix-fold._tlb.pas", + "kind": "suffix-fold", + "pattern": "_tlb.pas", + "role": "generated", + "source": "linguist", + "subtype": "type-library" + }, + { + "id": "generated.suffix..min.js", + "kind": "suffix", + "pattern": ".min.js", + "role": "generated", + "source": "linguist", + "subtype": "minified" + }, + { + "id": "generated.suffix.-min.js", + "kind": "suffix", + "pattern": "-min.js", + "role": "generated", + "source": "linguist", + "subtype": "minified" + }, + { + "id": "generated.suffix..min.css", + "kind": "suffix", + "pattern": ".min.css", + "role": "generated", + "source": "linguist", + "subtype": "minified" + }, + { + "id": "generated.suffix.-min.css", + "kind": "suffix", + "pattern": "-min.css", + "role": "generated", + "source": "linguist", + "subtype": "minified" + }, + { + "id": "generated.directory.htmlcov", + "kind": "directory", + "pattern": "htmlcov", + "role": "generated", + "source": "linguist", + "subtype": "coverage" + }, + { + "id": "generated.filename..secrets.baseline", + "kind": "filename", + "pattern": ".secrets.baseline", + "role": "generated", + "source": "linguist", + "subtype": "security-baseline" + }, + { + "id": "build.stem-fold.gradlew", + "kind": "stem-fold", + "pattern": "gradlew", + "role": "build", + "source": "linguist", + "subtype": "wrapper", + "extensions": [ + "", + ".bat" + ] + }, + { + "id": "build.stem-fold.mvnw", + "kind": "stem-fold", + "pattern": "mvnw", + "role": "build", + "source": "linguist", + "subtype": "wrapper", + "extensions": [ + "", + ".cmd" + ] + }, + { + "id": "build.filename..gitpod.Dockerfile", + "kind": "filename", + "pattern": ".gitpod.Dockerfile", + "role": "build", + "source": "linguist", + "subtype": "instructions" + }, + { + "id": "configuration.filename..gitignore", + "kind": "filename", + "pattern": ".gitignore", + "role": "configuration", + "source": "linguist" + }, + { + "id": "configuration.filename..gitattributes", + "kind": "filename", + "pattern": ".gitattributes", + "role": "configuration", + "source": "linguist" + }, + { + "id": "configuration.filename.proguard.pro", + "kind": "filename", + "pattern": "proguard.pro", + "role": "configuration", + "source": "linguist" + }, + { + "id": "configuration.filename.proguard-rules.pro", + "kind": "filename", + "pattern": "proguard-rules.pro", + "role": "configuration", + "source": "linguist" + }, + { + "id": "configuration.filename.Vagrantfile", + "kind": "filename", + "pattern": "Vagrantfile", + "role": "configuration", + "source": "linguist" + }, + { + "id": "configuration.filename..indent.pro", + "kind": "filename", + "pattern": ".indent.pro", + "role": "configuration", + "source": "linguist" + }, + { + "id": "tooling.filename.fabfile.py", + "kind": "filename", + "pattern": "fabfile.py", + "role": "tooling", + "source": "linguist" + }, + { + "id": "ci.directory..teamcity", + "kind": "directory", + "pattern": ".teamcity", + "role": "ci", + "source": "linguist" } ] diff --git a/corpus_test.go b/corpus_test.go index 1351c63..5681bd6 100644 --- a/corpus_test.go +++ b/corpus_test.go @@ -14,7 +14,10 @@ func TestEveryRuleIsReachable(t *testing.T) { if err != nil { t.Fatal(err) } - var rules []struct{ ID, Kind, Pattern string } + var rules []struct { + ID, Kind, Pattern string + Extensions []string + } if err := json.Unmarshal(data, &rules); err != nil { t.Fatal(err) } @@ -24,8 +27,10 @@ func TestEveryRuleIsReachable(t *testing.T) { switch rule.Kind { case "directory", "directory-fold", "directory-path": name += "/arbitrary.bin" - case "suffix": + case "suffix", "suffix-fold": name = "file" + name + case "stem-fold": + name += rule.Extensions[0] } got, err := roles.Classify(name) if err != nil { diff --git a/roles.go b/roles.go index 1b2c14e..5cd1d0b 100644 --- a/roles.go +++ b/roles.go @@ -205,7 +205,7 @@ func (c *Classifier) directory(state *matchState, base, full string, explain boo state.add(r, full, explain) } } - for _, r := range pathDirectories { + for _, r := range pathDirectories[base] { if full == r.Pattern || strings.HasSuffix(full, r.directorySuffix) { state.add(r, full, explain) } @@ -236,13 +236,20 @@ func matchFile(state *matchState, base, full string, explain bool) { state.add(r, full, explain) } } - for _, r := range suffixRules[base[len(base)-1]] { - if strings.HasSuffix(base, r.Pattern) { + for _, r := range suffixRules[suffixBucket(base[len(base)-1])] { + if suffixMatches(base, r) { state.add(r, full, explain) } } } +func suffixMatches(base string, r rule) bool { + if r.Kind == "suffix-fold" { + return len(base) >= len(r.Pattern) && strings.EqualFold(base[len(base)-len(r.Pattern):], r.Pattern) + } + return strings.HasSuffix(base, r.Pattern) +} + func extensionMatches(ext string, extensions []string) bool { for _, candidate := range extensions { if strings.EqualFold(ext, candidate) { diff --git a/roles_test.go b/roles_test.go index 6227443..69fb362 100644 --- a/roles_test.go +++ b/roles_test.go @@ -14,7 +14,7 @@ import ( const cargoConfig = ".cargo/config.toml" func TestCorpus(t *testing.T) { - for _, file := range []string{"testdata/paths.json", "testdata/gitignore-paths.json"} { + for _, file := range []string{"testdata/paths.json", "testdata/gitignore-paths.json", "testdata/linguist-paths.json"} { t.Run(file, func(t *testing.T) { testCorpusFile(t, file) }) } } @@ -136,7 +136,7 @@ func TestMatchAllocations(t *testing.T) { } func FuzzClassify(f *testing.F) { - for _, name := range []string{"vendor/LICENSES/NOTICE", "src/a_test.go", "../x", "test/\xff"} { + for _, name := range []string{"vendor/LICENSES/NOTICE", "src/a_test.go", "../x", "test/\xff", "a\xff.CSS.MAP", "a.Designer.cs\xff"} { f.Add(name) } f.Fuzz(func(t *testing.T, name string) { @@ -158,3 +158,21 @@ func FuzzClassify(f *testing.F) { } }) } + +func TestGeneratedSuffixBytes(t *testing.T) { + for name, generated := range map[string]bool{ + "a\xff.CSS.MAP": true, + "a.Designer.cs\xff": false, + "a.PYC": false, + "a.MIN.JS": false, + "a.Designer.cſ": false, + } { + result, err := roles.Classify(name) + if err != nil { + t.Fatal(err) + } + if got := slices.Contains(result.Roles, roles.Generated); got != generated { + t.Errorf("Classify(%q) generated = %v, want %v", name, got, generated) + } + } +} diff --git a/testdata/linguist-paths.json b/testdata/linguist-paths.json new file mode 100644 index 0000000..0e90ae6 --- /dev/null +++ b/testdata/linguist-paths.json @@ -0,0 +1,1008 @@ +[ + { + "path": "vendors/a/file.c", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Vendor/a/file.c", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "3rdparty/a/file.c", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "3rd_party/a/file.c", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "3rd-party/a/file.c", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "third-party/a/file.c", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "ThirdParty/a/file.c", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Godeps/_workspace/a/file.go", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": ".yarn/unplugged/a/file.js", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": ".yarn/releases/yarn.cjs", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Carthage/Checkouts/a/file.swift", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Pods/Alamofire/file.swift", + "roles": [ + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "packages/ui/Pods/lib/file.swift", + "roles": [ + "source", + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "ThirdParty/lib/src/file.c", + "roles": [ + "source", + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "groovydoc/index.html", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Groovydoc/index.html", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "javadoc/index.html", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Javadoc/index.html", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "man/tool.1", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Man/tool.1", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Doc/guide.txt", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Docs/guide.md", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "inst/doc/guide.pdf", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "packages/lib/man/tool.1", + "roles": [ + "source", + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "packages/r/inst/doc/vignette.html", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "CITATION", + "roles": [ + "documentation" + ], + "subtypes": [ + "citation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "CITATION.cff", + "roles": [ + "documentation" + ], + "subtypes": [ + "citation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Citation.bib", + "roles": [ + "documentation" + ], + "subtypes": [ + "citation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "citation.md", + "roles": [ + "documentation" + ], + "subtypes": [ + "citation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "CITATIONS", + "roles": [ + "documentation" + ], + "subtypes": [ + "citation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Citations.bib", + "roles": [ + "documentation" + ], + "subtypes": [ + "citation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "citations.md", + "roles": [ + "documentation" + ], + "subtypes": [ + "citation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "CHANGE", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "CHANGES", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "INSTALL", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Change.md", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "changes.txt", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Install.rst", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "INSTALL.markdown", + "roles": [ + "documentation" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Form.Designer.cs", + "roles": [ + "generated" + ], + "subtypes": [ + "codegen" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "form.DESIGNER.VB", + "roles": [ + "generated" + ], + "subtypes": [ + "codegen" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "login.Feature.CS", + "roles": [ + "generated" + ], + "subtypes": [ + "codegen" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Form.designer.cs", + "roles": [ + "generated" + ], + "subtypes": [ + "codegen" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "bundle.js.map", + "roles": [ + "generated" + ], + "subtypes": [ + "source-map" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "style.CSS.MAP", + "roles": [ + "generated" + ], + "subtypes": [ + "source-map" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "bundle.JS.Map", + "roles": [ + "generated" + ], + "subtypes": [ + "source-map" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Interop_TLB.pas", + "roles": [ + "generated" + ], + "subtypes": [ + "type-library" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "app.min.js", + "roles": [ + "generated" + ], + "subtypes": [ + "minified" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "app-min.js", + "roles": [ + "generated" + ], + "subtypes": [ + "minified" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "app.min.css", + "roles": [ + "generated" + ], + "subtypes": [ + "minified" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "app-min.css", + "roles": [ + "generated" + ], + "subtypes": [ + "minified" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "htmlcov/index.html", + "roles": [ + "generated" + ], + "subtypes": [ + "coverage" + ], + "origins": [ + "linguist" + ] + }, + { + "path": ".secrets.baseline", + "roles": [ + "generated" + ], + "subtypes": [ + "security-baseline" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "gradlew", + "roles": [ + "build" + ], + "subtypes": [ + "wrapper" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "gradlew.bat", + "roles": [ + "build" + ], + "subtypes": [ + "wrapper" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "GRADLEW.BAT", + "roles": [ + "build" + ], + "subtypes": [ + "wrapper" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "mvnw", + "roles": [ + "build" + ], + "subtypes": [ + "wrapper" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "mvnw.cmd", + "roles": [ + "build" + ], + "subtypes": [ + "wrapper" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "MVNW.CMD", + "roles": [ + "build" + ], + "subtypes": [ + "wrapper" + ], + "origins": [ + "linguist" + ] + }, + { + "path": ".gitpod.Dockerfile", + "roles": [ + "build" + ], + "subtypes": [ + "instructions" + ], + "origins": [ + "linguist" + ] + }, + { + "path": ".gitignore", + "roles": [ + "configuration" + ], + "origins": [ + "linguist" + ] + }, + { + "path": ".gitattributes", + "roles": [ + "configuration" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "proguard.pro", + "roles": [ + "configuration" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "proguard-rules.pro", + "roles": [ + "configuration" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Vagrantfile", + "roles": [ + "configuration" + ], + "origins": [ + "linguist" + ] + }, + { + "path": ".indent.pro", + "roles": [ + "configuration" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "fabfile.py", + "roles": [ + "tooling" + ], + "origins": [ + "linguist" + ] + }, + { + "path": ".teamcity/settings.kts", + "roles": [ + "ci" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "test/fixtures/Form.Designer.cs", + "roles": [ + "test", + "fixture", + "generated" + ], + "subtypes": [ + "codegen" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "vendor/app.min.js", + "roles": [ + "vendor", + "generated" + ], + "subtypes": [ + "minified" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "src/app.JS.MAP", + "roles": [ + "source", + "generated" + ], + "subtypes": [ + "source-map" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "Pods/Alamofire/tests/input.json", + "roles": [ + "test", + "vendor" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "vendor/tool/gradlew", + "roles": [ + "vendor", + "build", + "tooling" + ], + "subtypes": [ + "wrapper" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "testdata/main.go", + "roles": [ + "test", + "fixture" + ] + }, + { + "path": "debian/control", + "roles": [ + "packaging" + ] + }, + { + "path": "examples/main.py", + "roles": [ + "example" + ] + }, + { + "path": "LICENSE", + "roles": [ + "legal" + ], + "subtypes": [ + "license" + ] + }, + { + "path": "node_modules/first/index.js", + "roles": [ + "vendor" + ] + }, + { + "path": "vendor/form.DESIGNER.VB", + "roles": [ + "vendor", + "generated" + ], + "subtypes": [ + "codegen" + ], + "origins": [ + "linguist" + ] + }, + { + "path": "vendors", + "roles": [] + }, + { + "path": "Pods", + "roles": [] + }, + { + "path": "man", + "roles": [] + }, + { + "path": ".teamcity", + "roles": [] + }, + { + "path": "htmlcov", + "roles": [] + }, + { + "path": "vendorish/a.c", + "roles": [] + }, + { + "path": "mythird-party/a.c", + "roles": [] + }, + { + "path": "ThirdPartyish/a.c", + "roles": [] + }, + { + "path": ".yarn/patches/fix.patch", + "roles": [] + }, + { + "path": ".yarn/plugins/own.js", + "roles": [] + }, + { + "path": ".yarn/versions/release.yml", + "roles": [] + }, + { + "path": "xGodeps/_workspace/a.go", + "roles": [] + }, + { + "path": "Carthage/Project.swift", + "roles": [] + }, + { + "path": "install", + "roles": [] + }, + { + "path": "change", + "roles": [] + }, + { + "path": "changes", + "roles": [] + }, + { + "path": "INSTALL.sh", + "roles": [] + }, + { + "path": "CHANGE.py", + "roles": [] + }, + { + "path": "CITATION.cff.bak", + "roles": [] + }, + { + "path": "CITATIONS.cff", + "roles": [] + }, + { + "path": "citation.json", + "roles": [] + }, + { + "path": "Form.Designer.cs.bak", + "roles": [] + }, + { + "path": "feature.cs", + "roles": [] + }, + { + "path": "Form.designer.fs", + "roles": [] + }, + { + "path": "style.map", + "roles": [] + }, + { + "path": "styles.CSS.MAP.bak", + "roles": [] + }, + { + "path": "app.MIN.JS", + "roles": [] + }, + { + "path": "app.min.jsx", + "roles": [] + }, + { + "path": "admin.js", + "roles": [] + }, + { + "path": "prototype.js", + "roles": [] + }, + { + "path": "Chart.js", + "roles": [] + }, + { + "path": "mytypes.d.ts", + "roles": [] + }, + { + "path": "schema.proto", + "roles": [] + }, + { + "path": "file.pb.go", + "roles": [] + }, + { + "path": "module.rbi", + "roles": [] + }, + { + "path": "query.json", + "roles": [] + }, + { + "path": ".idea/compiler.xml", + "roles": [] + }, + { + "path": "cache/file.py", + "roles": [] + }, + { + "path": "dist/app.js", + "roles": [] + }, + { + "path": "env/app.py", + "roles": [] + }, + { + "path": ".github/OWNERS", + "roles": [] + }, + { + "path": "inst/extdata/data.csv", + "roles": [] + }, + { + "path": "gradlew.bat.bak", + "roles": [] + }, + { + "path": "mvnw.sh", + "roles": [] + }, + { + "path": "form.DESIGNER.VB.bak", + "roles": [] + }, + { + "path": ".gitattributes.bak", + "roles": [] + }, + { + "path": "fabfile.pyc.old", + "roles": [] + }, + { + "path": ".teamcity-old/settings.kts", + "roles": [] + }, + { + "path": "file.PYC", + "roles": [] + } +] diff --git a/testdata/paths.json b/testdata/paths.json index 8665768..7d4ce11 100644 --- a/testdata/paths.json +++ b/testdata/paths.json @@ -151,7 +151,9 @@ }, { "path": "Vendor/main.go", - "roles": [] + "roles": [ + "vendor" + ] }, { "path": "vendor", diff --git a/walk_test.go b/walk_test.go index c567701..45240ce 100644 --- a/walk_test.go +++ b/walk_test.go @@ -14,6 +14,7 @@ import ( func TestWalk(t *testing.T) { tree := fstest.MapFS{ "packages/api/.buildkite/pipeline.yml": {}, + "packages/api/Form.DESIGNER.CS": {}, "packages/api/.pytest_cache/v/cache/nodeids": {}, "packages/api/Support.markdown": {}, "vendor/src/a_test.go": {Data: []byte("package a")}, @@ -46,7 +47,7 @@ func TestWalk(t *testing.T) { } return nil }) - if err != nil || count != 27 { + if err != nil || count != 28 { t.Fatalf("count %d, error %v", count, err) } }