diff --git a/README.md b/README.md index 76fa52b..5ebfa83 100644 --- a/README.md +++ b/README.md @@ -285,6 +285,8 @@ Issue and pull request templates are reported under `resources.templates` so tha When the citation file is a `CITATION.cff`, `resources.citation` also contains its title, authors, release, identifiers, and preferred citation. The existing `resources.metadata.citation` path is preserved. Human and Markdown output include a short citation summary; `--verbose` adds affiliations, repository URLs, licenses, keywords, and the abstract. Licenses declared in CFF are reported separately from the detected repository license. +Citation discovery checks the repository root before `inst/`, the conventional R package location. An R-format `inst/CITATION` is reported by path under `resources.metadata.citation`. + When the citation file is `CITATION.bib`, `resources.bibtex` lists its entries with type, key, title, authors, year, DOI, URL, version, journal or booktitle, publisher, volume, number, pages, eprint and source line. A `CITATION`, `CITATION.md` or `CITATION.txt` file is reported the same way when it contains a BibTeX entry. BibTeX entries in the README, whether in fenced code blocks, reStructuredText code directives or plain text, are reported in `resources.readme_bibtex`. Values are converted from TeX to plain Unicode, and author names are split into given names, particle, family names and suffix using BibTeX's rules, with braced organisation names reported as `name`. Malformed entries produce diagnostics with line and column and the rest of the file is still read. Human and Markdown output show the first entry of each source; `--verbose` lists every entry. When a project contains `codemeta.json`, `resources.codemeta` contains its name, description, software version, repository, licenses, keywords, programming languages, authors, CodeMeta context version, and validation diagnostics. The existing `resources.metadata.codemeta` path is preserved. Human and Markdown output show a short summary; `--verbose` adds the remaining extracted fields. diff --git a/cmd/brief/citation_test.go b/cmd/brief/citation_test.go index 2660f81..63885e2 100644 --- a/cmd/brief/citation_test.go +++ b/cmd/brief/citation_test.go @@ -58,6 +58,36 @@ func TestCitationCLI(t *testing.T) { } } +func TestCitationCLIInst(t *testing.T) { + root, err := filepath.Abs("../../testdata/r-citation-project") + if err != nil { + t.Fatal(err) + } + var report brief.Report + if err := json.Unmarshal(citationCLI(t, root, "--json"), &report); err != nil { + t.Fatal(err) + } + if report.Resources == nil || report.Resources.Metadata["citation"] != "inst/CITATION" { + t.Fatalf("R citation path missing: %+v", report.Resources) + } + if report.Resources.Citation != nil || report.Resources.BibTeX != nil { + t.Fatalf("R citation treated as CFF or BibTeX: %+v", report.Resources) + } +} + +func TestCitationCLIInstSkipped(t *testing.T) { + root := t.TempDir() + writeScanFixture(t, root, "README.md", "# Example R package\n") + writeScanFixture(t, root, "inst/CITATION", "bibentry(bibtype = \"Article\", title = \"Example\")\n") + var report brief.Report + if err := json.Unmarshal(citationCLI(t, root, "--json --skip inst"), &report); err != nil { + t.Fatal(err) + } + if report.Resources != nil && report.Resources.Metadata["citation"] != "" { + t.Fatalf("skipped citation reported: %+v", report.Resources) + } +} + func TestCitationCLISchema(t *testing.T) { root := t.TempDir() var schema struct { diff --git a/cmd/brief/resources_test.go b/cmd/brief/resources_test.go index e188a46..7d0ac11 100644 --- a/cmd/brief/resources_test.go +++ b/cmd/brief/resources_test.go @@ -53,6 +53,10 @@ func TestScanResourceVariants(t *testing.T) { {"accessibility similar names", []string{"ACCESSIBILITY.md.bak", "docs/Accessibility-Testing.md"}, "community", "accessibility", ""}, {"accessibility unrelated directory", []string{"src/ACCESSIBILITY.md"}, "community", "accessibility", ""}, {"accessibility absent", nil, "community", "accessibility", ""}, + {"citation inst mixed case", []string{"inst/Citation.txt"}, "metadata", "citation", "inst/Citation.txt"}, + {"citation root precedence", []string{"CITATION.txt", "inst/CITATION.cff"}, "metadata", "citation", "CITATION.txt"}, + {"citation inst similar names", []string{"inst/CITATION.bak", "inst/CITATIONS", "inst/CITATION-guide.md"}, "metadata", "citation", ""}, + {"citation unrelated directory", []string{"src/CITATION", "inst/doc/CITATION"}, "metadata", "citation", ""}, } { t.Run(tt.name, func(t *testing.T) { root := t.TempDir() diff --git a/knowledge/_shared/_resources.toml b/knowledge/_shared/_resources.toml index 515d41a..0917dbc 100644 --- a/knowledge/_shared/_resources.toml +++ b/knowledge/_shared/_resources.toml @@ -182,6 +182,7 @@ name = "Citation" field = "citation" group = "metadata" patterns = ["citation.cff", "citation", "citation.bib", "citation.md", "citation.txt"] +dirs = ["inst"] [[resources]] [resources.resource] diff --git a/testdata/r-citation-project/DESCRIPTION b/testdata/r-citation-project/DESCRIPTION new file mode 100644 index 0000000..b6a59d2 --- /dev/null +++ b/testdata/r-citation-project/DESCRIPTION @@ -0,0 +1,5 @@ +Package: example +Title: Example Research Package +Version: 0.1.0 +Description: An example R package with citation instructions. +License: MIT diff --git a/testdata/r-citation-project/inst/CITATION b/testdata/r-citation-project/inst/CITATION new file mode 100644 index 0000000..5dc2968 --- /dev/null +++ b/testdata/r-citation-project/inst/CITATION @@ -0,0 +1,8 @@ +bibentry( + bibtype = "Article", + title = "An Example Research Method", + author = person("Alice", "Example"), + journal = "Example Journal", + year = "2024", + doi = "10.1234/example" +)