diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfd3127..108b43d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,60 +16,63 @@ on: jobs: build: - # Skip this job on push events when the head commit message contains [skip ci] if: ${{ github.event_name != 'push' || !contains(github.event.head_commit.message, '[skip ci]') }} permissions: contents: write runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v3 + - name: Checkout computorg.github.io site + uses: actions/checkout@v4 with: fetch-depth: 0 persist-credentials: true + - name: Setup Quarto uses: quarto-dev/quarto-actions/setup@v2 - name: Setup .NET + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force == 'true' }} uses: actions/setup-dotnet@v4 with: dotnet-version: "10.0.x" - - name: Restore build tooling + - name: Install Computo CLI tools + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force == 'true' }} + env: + API_GITHUB_TOKEN: ${{ secrets.API_GITHUB_TOKEN }} run: | - dotnet tool restore - dotnet tool run paket restore - - - name: Run tests - run: dotnet run --project src/Build.fsproj -- -t Test + dotnet nuget add source "https://nuget.pkg.github.com/computorg/index.json" \ + --name "GitHubPackages" \ + --username "fradav" \ + --password "$API_GITHUB_TOKEN" \ + --store-password-in-clear-text + dotnet tool install --global Computo.PublicationUpdater.Cli + echo "$HOME/.dotnet/tools" >> $GITHUB_PATH - name: refresh publications and commit changes if: ${{ github.event_name == 'workflow_dispatch' || github.event.inputs.force == 'true' }} env: API_GITHUB_TOKEN: ${{ secrets.API_GITHUB_TOKEN }} run: | - dotnet run --project src/Build.fsproj -- -t UpdatePublications + computo-publish . git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - # Stage the generated files (ignore errors if files missing) git add site/published.{yml,xml} site/pipeline.yml site/mock-papers.yml || true - # Only commit if there are staged changes if git diff --staged --quiet; then echo "No publication changes to commit" else git commit -m "Refresh publication metadata [skip ci]" - # push to the branch that triggered the workflow git push origin HEAD:${{ github.ref_name }} fi - name: Build site - run: dotnet run --project src/Build.fsproj -- -t RenderSite + run: quarto render - name: Upload artifact uses: actions/upload-pages-artifact@v3 + with: + path: ./_site - # Deployment job deploy: - # skip this job if the event is a pull request or if the branch is not master if: github.event_name != 'pull_request' permissions: pages: write diff --git a/.gitignore b/.gitignore index bf1c3b6..634fbde 100644 --- a/.gitignore +++ b/.gitignore @@ -15,454 +15,5 @@ vendor .env-secret .fake *_files/ -.vscode/ -**/*.quarto_ipynb -#.config/dotnet-tools.json -src/getcomputo-pub-refactored.fsx -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -!.vscode/*.code-snippets -!*.code-workspace - -# Built Visual Studio Code Extensions -*.vsix - -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates -*.env - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ - -[Dd]ebug/x64/ -[Dd]ebugPublic/x64/ -[Rr]elease/x64/ -[Rr]eleases/x64/ -bin/x64/ -obj/x64/ - -[Dd]ebug/x86/ -[Dd]ebugPublic/x86/ -[Rr]elease/x86/ -[Rr]eleases/x86/ -bin/x86/ -obj/x86/ - -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -[Aa][Rr][Mm]64[Ee][Cc]/ -bld/ -[Oo]bj/ -[Oo]ut/ -[Ll]og/ -[Ll]ogs/ - -# Build results on 'Bin' directories -**/[Bb]in/* -# Uncomment if you have tasks that rely on *.refresh files to move binaries -# (https://github.com/github/gitignore/pull/3736) -#!**/[Bb]in/*.refresh - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* -*.trx - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Approval Tests result files -*.received.* - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.idb -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -# but not Directory.Build.rsp, as it configures directory-level build defaults -!Directory.Build.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.tlog -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio 6 workspace and project file (working project files containing files to include in project) -*.dsw -*.dsp - -# Visual Studio 6 technical files -*.ncb -*.aps - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -**/.paket/paket.exe -paket-files/ - -# FAKE - F# Make -**/.fake/ - -# CodeRush personal settings -**/.cr/personal - -# Python Tools for Visual Studio (PTVS) -**/__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -#tools/** -#!tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog -MSBuild_Logs/ - -# AWS SAM Build and Temporary Artifacts folder -.aws-sam - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -**/.mfractor/ - -# Local History for Visual Studio -**/.localhistory/ - -# Visual Studio History (VSHistory) files -.vshistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -**/.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd - -# VS Code files for those working on multiple tools -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -!.vscode/*.code-snippets - -# Local History for Visual Studio Code -.history/ - -# Built Visual Studio Code Extensions -*.vsix - -# Windows Installer files from build outputs -*.cab -*.msi -*.msix -*.msm -*.msp - -**/*/bin -**/*/obj -.venv*/ -packages/ -.paket/ -.zed/ +/.luarc.json diff --git a/.python-version b/.python-version deleted file mode 100644 index 24ee5b1..0000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.13 diff --git a/docs/DEV-REPORTS/00-START-HERE.md b/docs/DEV-REPORTS/00-START-HERE.md deleted file mode 100644 index 429b10a..0000000 --- a/docs/DEV-REPORTS/00-START-HERE.md +++ /dev/null @@ -1,100 +0,0 @@ -# Start Here - -Use this folder in the following order: - -1. [INDEX.md](INDEX.md) -2. [QUICK_REFERENCE.md](QUICK_REFERENCE.md) -3. [SCHEMA_BASED_PROVIDERS.md](SCHEMA_BASED_PROVIDERS.md) -4. [QUARTO_PROVIDER_IMPLEMENTATION.md](QUARTO_PROVIDER_IMPLEMENTATION.md) - -## Fast Commands - -Build: - -```bash -cd src/QuartoInspect -dotnet build -``` - -Run tests: - -```bash -cd src/QuartoInspect.Tests -dotnet restore && dotnet test -``` - -## Notes - -- Top-level DEV reports are intentionally minimal. -- Historical and correction-heavy reports are in [archive/](archive). - 13+ tests covering API, schemas, and integration - -4. Graceful Degradation - Tests skip if prerequisites unavailable - -5. Full Documentation - 6 guides covering every aspect - -6. Production Ready - Clean architecture, well-tested, extensible - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -🎯 Success Checklist - ALL COMPLETE: -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -User Requirements: -✅ Leverage FSharp.Data JSON type providers -✅ Use official Quarto schemas -✅ Create Expecto tests -✅ Test GitHub API availability -✅ Test Quarto inspect compliance -✅ Test with mock repository example - -Implementation: -✅ Core library created and documented -✅ Type providers based on official schemas -✅ Comprehensive test suite with 13+ tests -✅ All test categories implemented -✅ Graceful error handling throughout -✅ Production-ready code quality -✅ Full documentation suite - -Testing: -✅ GitHub API tests (4 tests) -✅ Quarto installation tests (1 test) -✅ Schema compliance tests (6 tests) -✅ Integration tests (2 tests) -✅ Execution tests (2 tests) - -Documentation: -✅ Quick reference guide -✅ Visual overview with diagrams -✅ Complete implementation guide -✅ Schema architecture explained -✅ Library usage guide -✅ Navigation hub - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -🚀 READY TO USE! -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Everything is complete, tested, and documented. - -Next Steps: -1. cd QuartoInspect.Tests -2. dotnet run -3. ✓ See tests pass -4. Read INDEX.md for full navigation - -Questions? Check the relevant .md file: - INDEX.md → QUICK_REFERENCE.md → Full docs as needed - -Status: ✅ PRODUCTION READY -Date: January 20, 2026 -Tests: 13+ (comprehensive) -Docs: 6 guides + code comments -Quality: Professional - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/docs/DEV-REPORTS/INDEX.md b/docs/DEV-REPORTS/INDEX.md deleted file mode 100644 index b826824..0000000 --- a/docs/DEV-REPORTS/INDEX.md +++ /dev/null @@ -1,146 +0,0 @@ -# DEV Reports - -This folder has been simplified to keep only current, high-signal docs at the top level. - -## Read In This Order - -1. [00-START-HERE.md](00-START-HERE.md) -2. [QUICK_REFERENCE.md](QUICK_REFERENCE.md) -3. [SCHEMA_BASED_PROVIDERS.md](SCHEMA_BASED_PROVIDERS.md) -4. [QUARTO_PROVIDER_IMPLEMENTATION.md](QUARTO_PROVIDER_IMPLEMENTATION.md) - -## Scope Of Active Docs - -- `00-START-HERE.md`: Fast onboarding and commands. -- `QUICK_REFERENCE.md`: Day-to-day commands and paths. -- `SCHEMA_BASED_PROVIDERS.md`: Schema and type-provider design. -- `QUARTO_PROVIDER_IMPLEMENTATION.md`: Detailed implementation notes. - -## Archive - -Older reports, correction logs, and one-off migration notes are in: - -- [archive/](archive) - -These are preserved for traceability but are no longer required for normal development. - -## Canonical Paths - -- Schemas: `src/quarto-inspect-project-json-schema.json`, `src/quarto-inspect-document-json-schema.json` -- Library: `src/QuartoInspect/` -- Tests: `src/QuartoInspect.Tests/` - -## Conventions - -- Keep new docs short and task-oriented. -- Prefer updating active docs over adding new top-level files. -- Put temporary investigations and postmortems in `archive/`. -Result<'Success, string> // Explicit, composable error handling -``` - -### Async Operations -```fsharp -Async> // Non-blocking I/O with error handling -``` - -## 💡 Common Patterns - -### Validate and Parse -```fsharp -let validateAndParse json = - result { - let! _ = QuartoClient.validateProjectSchema json - return! QuartoTypes.parseProjectJson json - } -``` - -### Extract Version Safely -```fsharp -QuartoTypes.parseProjectJson json -|> Result.map (fun p -> p.Quarto.Version) -``` - -### Check Quarto Availability -```fsharp -async { - let! version = QuartoClient.checkQuartoAvailable() - match version with - | Ok v -> printfn "Quarto %s" v - | Error _ -> printfn "Quarto not available" -} -``` - -## 📚 Reference Materials - -| Resource | Link | -|----------|------| -| Quarto Inspect | https://quarto.org/docs/advanced/inspect/ | -| FSharp.Data | https://fsprojects.github.io/FSharp.Data/ | -| Expecto | https://github.com/haf/expecto | -| JSON Schema | https://json-schema.org/ | - -## ❓ FAQ - -**Q: Why type providers instead of manual JSON parsing?** -A: Type safety at compile-time, better IDE support, less error-prone, cleaner code. - -**Q: What if Quarto updates the schema?** -A: Update `sample-*.json` files and rebuild - type providers auto-update. - -**Q: Can I use this without Quarto installed?** -A: Yes! Only schema validation tests are skipped. Type providers work without Quarto. - -**Q: What about GitHub API rate limits?** -A: Set `API_GITHUB_TOKEN` env var for 5000 requests/hour vs 60/hour unauthenticated. - -**Q: Are tests required?** -A: No, tests are optional. Use just the library for type-safe JSON parsing. - -**Q: How do I handle missing fields?** -A: All Result returns are explicit - pattern match on Ok/Error. - -## 🔍 Troubleshooting - -### Tests fail to compile -```bash -cd QuartoInspect && dotnet build # Check library builds first -``` - -### Type provider errors -- Ensure `sample-*.json` files exist in `QuartoInspect/` -- Run `dotnet clean && dotnet build` -- Validate JSON: `jq . < sample-project.json` - -### Tests skip unexpectedly -This is **expected and fine**! Tests gracefully skip when: -- Quarto not installed -- GitHub token not set -- Mock repository not available - -## 📞 Support - -For issues or questions: -1. Check relevant `.md` file in documentation -2. Review error messages in test output -3. Check Quarto documentation: https://quarto.org/docs/advanced/inspect/ - -## ✨ Summary - -You have a **complete, tested, production-ready infrastructure** for: -- ✅ Type-safe Quarto JSON parsing -- ✅ Schema validation -- ✅ GitHub API testing -- ✅ Quarto inspect compliance testing -- ✅ Full API documentation - -Everything is **ready to use immediately**. Start with [QUICK_REFERENCE.md](QUICK_REFERENCE.md) or [QuartoInspect/README.md](QuartoInspect/README.md). - ---- - -**Implementation Date**: January 20, 2026 -**Status**: ✅ **COMPLETE & READY TO USE** -**Test Coverage**: 13+ comprehensive tests -**Documentation**: 5 detailed guides -**Schemas**: Official Quarto schemas integrated - -🎉 Everything is ready. Run `cd QuartoInspect.Tests && dotnet run` to verify! diff --git a/docs/DEV-REPORTS/QUARTO_PROVIDER_IMPLEMENTATION.md b/docs/DEV-REPORTS/QUARTO_PROVIDER_IMPLEMENTATION.md deleted file mode 100644 index acb9cb0..0000000 --- a/docs/DEV-REPORTS/QUARTO_PROVIDER_IMPLEMENTATION.md +++ /dev/null @@ -1,315 +0,0 @@ -# Quarto Inspect Type Provider & Expecto Tests - Implementation Summary - -## Overview - -I've created a comprehensive F# infrastructure for the Computo project that: - -1. **Leverages FSharp.Data JSON type providers** for compile-time type safety and schema validation -2. **Includes Expecto tests** for GitHub API availability and Quarto inspect compliance -3. **Refactors the main script** to use type providers - -## What Was Created - -### Directory Structure - -``` -QuartoInspect/ # Main library -├── QuartoInspect.fsproj # Library project file -├── QuartoTypes.fs # Type providers and domain types -├── QuartoClient.fs # Quarto inspection client -├── sample-project.json # Example project inspect output -├── sample-document.json # Example document inspect output -└── README.md # Comprehensive documentation - -QuartoInspect.Tests/ # Test suite -├── QuartoInspect.Tests.fsproj # Test project file -└── QuartoInspectTests.fs # All tests - -getcomputo-pub-refactored.fsx # Refactored main script with type providers -``` - -## Key Components - -### 1. Type Providers (QuartoTypes.fs) - -**QuartoProjectProvider** and **QuartoDocumentProvider**: -- Use FSharp.Data's **JSON Schema validation mode** (`Schema=` syntax) -- Based directly on official Quarto JSON schemas -- Provide compile-time type safety with schema constraints -- Full IntelliSense support based on schema definition -- Enable schema validation at compile time - -**Type Provider Declaration**: -```fsharp -type QuartoProjectProvider = - JsonProvider - -type QuartoDocumentProvider = - JsonProvider -``` - -**Benefits**: -- Validates against official JSON Schema specification -- Type errors caught at compile time -- No runtime overhead -- IDE integration with schema-aware IntelliSense -- Strict validation ensures schema compliance - -### 2. Quarto Client (QuartoClient.fs) - -Provides: -- `runInspect`: Execute `quarto inspect` and return typed results -- `checkQuartoAvailable`: Verify Quarto installation -- `validateDocumentSchema`: Validate JSON against document schema -- `validateProjectSchema`: Validate JSON against project schema - -All functions return `Result<'T, string>` for explicit error handling. - -### 3. Comprehensive Test Suite (QuartoInspectTests.fs) - -**5 Test Categories with 13+ tests**: - -#### GitHub API Availability Tests -- ✓ API reachability -- ✓ Repository retrieval -- ✓ Repository details fetching -- ✓ Rate limit handling - -#### Quarto Installation Tests -- ✓ Quarto availability check - -#### Schema Compliance Tests -- ✓ Valid document schema parsing -- ✓ Invalid document detection (missing fields) -- ✓ Valid project schema parsing -- ✓ Invalid project detection (missing fields) -- ✓ Type provider document parsing -- ✓ Type provider project parsing - -#### Mock Repository Integration Tests -- ✓ Mock repository retrieval -- ✓ Repository structure validation -- ✓ Graceful skip if repository not found - -#### Quarto Inspect Execution Tests -- ✓ Real quarto inspect execution -- ✓ Schema compliance validation -- ✓ Non-Quarto directory error handling - -**Features**: -- Parallel execution (4 workers) -- Graceful skipping when prerequisites unavailable -- Comprehensive error messages -- Timeout handling - -### 4. Refactored Main Script (getcomputo-pub-refactored.fsx) - -Enhanced version of `getcomputo-pub.fsx` with: -- Inline type providers for compile-time validation -- Improved JSON parsing with schema validation -- Better error messages -- Same functionality as original -- Cleaner code organization - -## How to Use - -### Quick Start - Run Tests - -```bash -cd QuartoInspect.Tests -dotnet restore -dotnet build -dotnet run -``` - -Expected output: -``` -Tests run: 13 -Passed: 10-13 (depending on environment) -Skipped: 0-3 (if GitHub token or Quarto unavailable) -Failed: 0 -``` - -### Run Specific Test Categories - -```bash -dotnet run -- --filter "GitHub API" # GitHub tests only -dotnet run -- --filter "Schema Compliance" # Schema tests only -dotnet run -- --parallel 1 # Run serially -``` - -### Use in Your F# Scripts - -```fsharp -#r "nuget: FSharp.Data" -#load "../QuartoInspect/QuartoTypes.fs" -open QuartoInspect.QuartoTypes - -let json = System.IO.File.ReadAllText("output.json") -match parseProjectJson json with -| Ok parsed -> printfn "Version: %s" parsed.Quarto.Version -| Error msg -> printfn "Error: %s" msg -``` - -### Use in the Main Script - -Simply replace the original `getcomputo-pub.fsx` with `getcomputo-pub-refactored.fsx`: - -```bash -dotnet fsi getcomputo-pub-refactored.fsx -``` - -## Type Provider Advantages Over Manual Parsing - -### Before (Manual JsonElement navigation): -```fsharp -let mutable prop = Unchecked.defaultof -if element.TryGetProperty(key, &prop) then - match prop.ValueKind with - | JsonValueKind.String -> prop.GetString() - | _ -> "" -``` - -### After (Type provider with IntelliSense): -```fsharp -let parsed = QuartoProjectProvider.Parse(jsonStr) -let version = parsed.Quarto.Version // Autocomplete, type-safe -``` - -**Benefits**: -- Type-safe - no string keys -- Faster development -- Better IDE support -- Compile-time validation -- Fewer runtime errors - -## Schema Validation - -The implementation validates against the official Quarto schemas: -- **Document Schema**: `src/quarto-inspect-document-json-schema.json` -- **Project Schema**: `src/quarto-inspect-project-json-schema.json` - -Reference: https://quarto.org/docs/advanced/inspect/ - -### Validated Fields - -**Project Schema**: -- ✓ quarto (version info) -- ✓ dir (directory path) -- ✓ engines (list of engines) -- ✓ files (input, resources, config) -- ✓ fileInformation (per-document metadata) -- ✓ extensions - -**Document Schema**: -- ✓ quarto (version info) -- ✓ engines (list of engines) -- ✓ formats (output formats) -- ✓ resources (resource files) -- ✓ fileInformation (document metadata) - -## Environment Setup - -### Requirements: -- .NET 8.0 or later -- Quarto (for integration tests) -- GitHub API token (optional, for authenticated requests) - -### Optional Configuration: -```bash -export API_GITHUB_TOKEN="ghp_your_token_here" -``` - -## Test Results Interpretation - -### All Pass ✓ -Environment is fully configured. All features available. - -### Some Skip ⊗ -This is expected! Tests gracefully skip when: -- Quarto not installed -- GitHub API token not provided -- Mock repository doesn't exist - -### Any Fail ✗ -Indicates a real issue: -- Schema mismatch -- Quarto malfunction -- API unavailability -- JSON parsing error - -## Performance - -- **Type providers**: Compile-time only, zero runtime overhead -- **Tests**: Run in ~30-60 seconds (parallel) -- **GitHub API**: Rate limited at ~60/hour (unauthenticated) or ~5000/hour (authenticated) -- **Quarto inspect**: Typically 2-5 seconds per repository - -## Next Steps - -1. **Run the tests** to verify setup: - ```bash - cd QuartoInspect.Tests && dotnet run - ``` - -2. **Review test results** - note any skips or failures - -3. **Update getcomputo-pub.fsx** - either: - - Use the refactored version directly, or - - Integrate type provider patterns into your script - -4. **Extend as needed** - add more tests or type provider functionality - -## Files Reference - -| File | Purpose | -|------|---------| -| `QuartoInspect/QuartoTypes.fs` | Type providers (using Schema= mode) | -| `QuartoInspect/QuartoClient.fs` | Quarto execution client | -| `QuartoInspect.Tests/QuartoInspectTests.fs` | All test cases (13 tests) | -| `getcomputo-pub-refactored.fsx` | Enhanced main script | -| `QuartoInspect/README.md` | Detailed documentation | -| `src/quarto-inspect-document-json-schema.json` | Official document schema | -| `src/quarto-inspect-project-json-schema.json` | Official project schema | - -## Debugging Tips - -### If tests fail to run: -```bash -cd QuartoInspect -dotnet build # Check library builds first -cd ../QuartoInspect.Tests -dotnet build -``` - -### If GitHub API tests skip: -```bash -export API_GITHUB_TOKEN="your_token" -# Tests will run with authentication -``` - -### If Quarto tests skip: -```bash -quarto --version # Verify installation -quarto inspect test.json # Test command manually -``` - -### View detailed test output: -```bash -dotnet run -- --verbose -``` - -## Architecture Decisions - -1. **Type Providers over manual parsing**: Compile-time safety and better DX -2. **Separate library and tests**: Clean separation of concerns -3. **Result<'T, string> for errors**: Explicit error handling -4. **Expecto for testing**: Lightweight, expressive, good parallelization -5. **Async/await for I/O**: Non-blocking GitHub and Quarto operations - -All decisions optimize for: -- Type safety -- Error visibility -- Development experience -- Maintainability -- Performance diff --git a/docs/DEV-REPORTS/QUICK_REFERENCE.md b/docs/DEV-REPORTS/QUICK_REFERENCE.md deleted file mode 100644 index 29bc199..0000000 --- a/docs/DEV-REPORTS/QUICK_REFERENCE.md +++ /dev/null @@ -1,94 +0,0 @@ -# Quick Reference - -## Core Paths - -- Library: `src/QuartoInspect/` -- Tests: `src/QuartoInspect.Tests/` -- Schemas: - - `src/quarto-inspect-project-json-schema.json` - - `src/quarto-inspect-document-json-schema.json` - -## Build And Test - -```bash -cd src/QuartoInspect -dotnet build - -cd ../QuartoInspect.Tests -dotnet restore -dotnet test -``` - -## Run Build Pipeline - -```bash -dotnet run --project src/Build.fsproj -- -t UpdatePublications -dotnet run --project src/Build.fsproj -- -t Test -dotnet run --project src/Build.fsproj -- -t RenderSite -``` - -## Key F# Modules - -- `QuartoInspect.QuartoTypes` - - `parseProjectJson : string -> Result<_, string>` - - `parseDocumentJson : string -> Result<_, string>` - -- `QuartoInspect.QuartoClient` - - `checkQuartoAvailable : unit -> Async>` - - `runInspect : string -> Async>` - - `validateProjectSchema : string -> Result<_, string>` - - `validateDocumentSchema : string -> Result<_, string>` - -## Typical Snippet - -```fsharp -open QuartoInspect.QuartoTypes - -match parseProjectJson jsonText with -| Ok parsed -> printfn "%s" parsed.Quarto.Version -| Error msg -> eprintfn "%s" msg -``` - -## Troubleshooting - -- If tests fail unexpectedly, run `dotnet restore` in both projects. -- If Quarto checks fail, verify with `quarto --version`. -- If schema parsing fails, validate JSON shape against files in `src/`. - -## Documentation Map - -- Architecture: [SCHEMA_BASED_PROVIDERS.md](SCHEMA_BASED_PROVIDERS.md) -- Deep implementation notes: [QUARTO_PROVIDER_IMPLEMENTATION.md](QUARTO_PROVIDER_IMPLEMENTATION.md) -- Historical reports: [archive/](archive) - -# Run with custom options -dotnet run -- --filter "GitHub" --verbose - -# Check Quarto -quarto --version -quarto inspect - -# Check GitHub token -echo $API_GITHUB_TOKEN - -# Validate JSON -jq . < sample-project.json -``` - -## Next Steps - -1. **Try the tests**: `cd QuartoInspect.Tests && dotnet run` -2. **Read the docs**: Start with `QuartoInspect/README.md` -3. **Explore samples**: Check `sample-project.json` and `sample-document.json` -4. **Integrate**: Use `getcomputo-pub-refactored.fsx` or adapt patterns - -## Resources - -- **Quarto Docs**: https://quarto.org/docs/advanced/inspect/ -- **FSharp.Data**: https://fsprojects.github.io/FSharp.Data/ -- **Expecto**: https://github.com/haf/expecto - ---- - -**Implementation Date**: January 20, 2026 -**Status**: ✅ Complete and ready to use diff --git a/docs/DEV-REPORTS/SCHEMA_BASED_PROVIDERS.md b/docs/DEV-REPORTS/SCHEMA_BASED_PROVIDERS.md deleted file mode 100644 index 675ad57..0000000 --- a/docs/DEV-REPORTS/SCHEMA_BASED_PROVIDERS.md +++ /dev/null @@ -1,223 +0,0 @@ -# Schema-Based Type Providers Implementation - -This document explains how the type providers use FSharp.Data's JSON Schema validation mode with the official Quarto JSON schemas. - -## FSharp.Data JSON Provider Modes - -FSharp.Data's JsonProvider supports two distinct modes: - -### 1. Sample Mode (Type Inference) -```fsharp -type MyProvider = JsonProvider<"sample.json"> -``` -- Infers types from actual JSON sample data -- Types are based on what's in the sample -- Good for exploring JSON structure - -### 2. Schema Mode (Schema Validation) -```fsharp -type MyProvider = JsonProvider -``` -- Validates against JSON Schema specification -- Types are based on schema constraints -- Provides strict validation and better IDE support -- **This is what we use** ✅ - -## Official Quarto Schemas - -The project uses two official JSON schemas published by Quarto: - -### Project Schema -**File**: `src/quarto-inspect-project-json-schema.json` - -Source: https://quarto.org/docs/advanced/inspect/ - -Defines the structure returned by `quarto inspect ` - -**Key validated fields**: -- `quarto.version` - String, Quarto version -- `dir` - String, project directory path -- `engines` - Array of strings, rendering engines -- `config` - Object, project configuration -- `files` - Object with input, resources, configResources, config arrays -- `fileInformation` - Object with per-document metadata -- `extensions` - Array of extension objects - -### Document Schema -**File**: `src/quarto-inspect-document-json-schema.json` - -Source: https://quarto.org/docs/advanced/inspect/ - -Defines the structure returned by `quarto inspect ` - -**Key validated fields**: -- `quarto.version` - String, Quarto version -- `engines` - Array of strings, rendering engines -- `formats` - Object, output formats -- `resources` - Array of strings, resource files -- `fileInformation` - Object with document metadata -- `project` - (Optional) parent project information - -## Type Provider Declaration - -In `QuartoTypes.fs`, the type providers use `Schema=` mode: - -```fsharp -/// Uses JSON Schema validation directly -type QuartoProjectProvider = - JsonProvider - -type QuartoDocumentProvider = - JsonProvider -``` - -## How Schema Mode Works - -1. **Schema Definition**: JSON Schema file specifies allowed structure -2. **Type Generation**: FSharp.Data generates F# types matching schema constraints -3. **Compile-time Validation**: Invalid JSON detected at compile time -4. **Runtime Parsing**: JSON is parsed with validation against schema - -Example schema excerpt: -```json -{ - "type": "object", - "properties": { - "quarto": { - "type": "object", - "properties": { - "version": { "type": "string" } - } - }, - "dir": { "type": "string" }, - "engines": { - "type": "array", - "items": { "type": "string" } - } - } -} -``` - -Generated F# types would be: -```fsharp -parsed.Quarto.Version : string -parsed.Dir : string -parsed.Engines : string[] -``` - -## Validation Chain - -``` -Official JSON Schema (Quarto publishes) - ↓ -FSharp.Data Type Provider (Schema= mode) - ↓ -Compile-time Type Generation - ↓ -F# Strongly-Typed Access - ↓ -Runtime Validation via ParseAsync -``` - -## Benefits of Schema Mode - -| Aspect | Sample Mode | Schema Mode | -|--------|------------|------------| -| Type Source | JSON sample data | JSON Schema spec | -| Validation | Inferred from sample | Schema specification | -| Strictness | Loose (sample-dependent) | Strict (schema-enforced) | -| IDE Support | Good (sample-based) | Excellent (schema-defined) | -| Unknown Fields | Accepted | Rejected | -| Type Safety | Good | Excellent | -| Updates | Require sample update | Schema change only | - -## Sample Files as Documentation - -While we use `Schema=` mode, we maintain sample JSON files for documentation: -- **sample-project.json** - Valid example of project inspect output -- **sample-document.json** - Valid example of document inspect output - -These serve as: -- Documentation of schema structure -- Test data for integration tests -- Examples for developers -- Validation that schemas match reality - -## Type Provider Usage - -```fsharp -// Parse with schema validation -let parseProjectJson (jsonStr: string) : Result = - try - Ok (QuartoProjectProvider.Parse(jsonStr)) - with ex -> - Error $"Schema validation failed: {ex.Message}" - -// Type-safe access with IntelliSense -let parsed = QuartoProjectProvider.Parse(jsonStr) -let version = parsed.Quarto.Version // String, validated by schema -let engines = parsed.Engines // string[], validated by schema -let files = parsed.Files.Input // string[], validated by schema -``` - -## Updating for Quarto Schema Changes - -When Quarto updates their schemas: - -1. Update the schema files locally: - - `src/quarto-inspect-project-json-schema.json` - - `src/quarto-inspect-document-json-schema.json` - -2. Rebuild the project: - ```bash - cd QuartoInspect - dotnet clean - dotnet build - ``` - -3. Type provider automatically generates new types -4. Compiler shows any incompatibilities -5. All new fields are available with IntelliSense - -## Differences from Sample Mode - -### Schema Mode (What We Use) -```fsharp -type QuartoProjectProvider = - JsonProvider - -// Type safety based on schema specification -let parsed = QuartoProjectProvider.Parse(jsonStr) -let version = parsed.Quarto.Version // Validated against schema -``` - -### Sample Mode (Alternative) -```fsharp -type QuartoProjectProvider = - JsonProvider<"sample-project.json"> - -// Type safety based on sample structure -let parsed = QuartoProjectProvider.Parse(jsonStr) -let version = parsed.Quarto.Version // Validated against sample -``` - -**Key Difference**: Schema mode validates against the JSON Schema specification, which is more authoritative and comprehensive than relying on a single sample. - -## Reference Materials - -- **Quarto Inspect**: https://quarto.org/docs/advanced/inspect/ -- **FSharp.Data JSON Schema**: https://fsprojects.github.io/FSharp.Data/library/JsonSchema.html -- **JSON Schema**: https://json-schema.org/ -- **FSharp.Data Documentation**: https://fsprojects.github.io/FSharp.Data/ - -## Summary - -The implementation uses **FSharp.Data's JSON Schema validation mode** (`Schema=` syntax) with the official Quarto JSON schemas. This provides: - -✅ Type safety based on official specifications -✅ Strict validation against JSON Schema -✅ Excellent IDE IntelliSense support -✅ Clear compile-time error messages -✅ Direct alignment with Quarto's published interface -✅ Automatic updates when Quarto updates schemas - diff --git a/docs/DEV-REPORTS/archive/CORRECTION_INDEX.md b/docs/DEV-REPORTS/archive/CORRECTION_INDEX.md deleted file mode 100644 index 90ba763..0000000 --- a/docs/DEV-REPORTS/archive/CORRECTION_INDEX.md +++ /dev/null @@ -1,210 +0,0 @@ -# 📋 Correction Documentation Index - -**Topic**: FSharp.Data JSON Type Provider Mode Correction -**Date**: January 20, 2026 -**Status**: ✅ Corrected and Verified - ---- - -## Documents Related to This Correction - -### Quick Overview -👉 **Start here for a quick summary:** -- **CORRECTION_SUMMARY.md** - Executive summary of what was corrected - -### Detailed Explanation -👉 **Read this for complete understanding:** -- **SCHEMA_MODE_CORRECTION.md** - Comprehensive explanation of: - - What was wrong - - Why it was wrong - - How it was fixed - - Benefits of the correction - - Detailed comparison tables - -### Verification -👉 **Read this to verify correctness:** -- **CORRECTION_VERIFIED.md** - Detailed verification checklist: - - Files changed - - Code samples - - Documentation updates - - Testing status - - References to official docs - ---- - -## What Was Corrected - -**From**: Using FSharp.Data in Sample Mode -```fsharp -type QuartoProjectProvider = JsonProvider<"sample-project.json"> -``` - -**To**: Using FSharp.Data in JSON Schema Validation Mode -```fsharp -type QuartoProjectProvider = JsonProvider -``` - ---- - -## The Two FSharp.Data JsonProvider Modes - -### Mode 1: Sample Mode (Type Inference) -```fsharp -JsonProvider<"sample.json"> -``` -- ❌ What we were incorrectly using -- Infers types from JSON sample -- Loose validation - -### Mode 2: Schema Mode (JSON Schema Validation) -```fsharp -JsonProvider -``` -- ✅ What we should use -- Validates against JSON Schema spec -- Strict validation -- Better IDE support - ---- - -## Files Updated - -### Core Implementation -- ✅ `QuartoInspect/QuartoTypes.fs` - Type provider declarations -- ✅ `getcomputo-pub-refactored.fsx` - Type provider declarations -- ✅ `QuartoInspect/QuartoInspect.fsproj` - Schema file references - -### Documentation -- ✅ `QuartoInspect/README.md` - Explains schema mode -- ✅ `SCHEMA_BASED_PROVIDERS.md` - Complete schema mode guide -- ✅ `QUARTO_PROVIDER_IMPLEMENTATION.md` - Updated descriptions -- ✅ `QUICK_REFERENCE.md` - Shows correct syntax -- ✅ `MANIFEST.md` - Updated descriptions -- ✅ `SCHEMA_MODE_CORRECTION.md` - NEW: Detailed correction -- ✅ `CORRECTION_SUMMARY.md` - NEW: Summary of changes -- ✅ `CORRECTION_VERIFIED.md` - NEW: Verification details - ---- - -## Quick Facts About the Correction - -| Fact | Details | -|------|---------| -| **What** | Changed from sample-based to schema-based type providers | -| **Why** | Sample mode was incorrect; schema mode is the proper way | -| **When** | January 20, 2026 | -| **Impact** | Type providers now validate against official schemas | -| **Breaking Changes** | None - usage remains identical | -| **Tests** | All 13+ tests still pass | -| **IDE Support** | Improved with schema-based types | - ---- - -## Reading Guide - -### If you have 2 minutes: -→ Read **CORRECTION_SUMMARY.md** - -### If you have 5 minutes: -→ Read **CORRECTION_SUMMARY.md** + quick skim of **SCHEMA_MODE_CORRECTION.md** - -### If you have 10 minutes: -→ Read **SCHEMA_MODE_CORRECTION.md** completely - -### If you want full verification: -→ Read **CORRECTION_VERIFIED.md** for detailed checklist - -### If you want context: -→ Read **SCHEMA_BASED_PROVIDERS.md** for architecture explanation - ---- - -## Key Improvements From Correction - -✅ **Uses Official Specifications** - - Type providers validate against official JSON schemas - - Not dependent on example JSON - -✅ **Better Type Safety** - - Schema mode provides stricter validation - - Better compile-time error messages - -✅ **Proper API Usage** - - Using FSharp.Data's JSON Schema mode correctly - - Professional-grade implementation - -✅ **Future-Proof** - - When Quarto updates schemas, types automatically update - - Single source of truth for type definitions - -✅ **Better IDE Support** - - IntelliSense based on schema definition - - More complete type information - ---- - -## Code Examples - -### Before (Incorrect) -```fsharp -// ❌ Sample mode - infers from example JSON -type QuartoProjectProvider = JsonProvider<"sample-project.json"> -``` - -### After (Correct) -```fsharp -// ✅ Schema mode - validates against JSON Schema spec -type QuartoProjectProvider = JsonProvider -``` - -### Usage (Unchanged) -```fsharp -// Usage is identical - type checking improved internally -let parsed = QuartoProjectProvider.Parse(jsonString) -let version = parsed.Quarto.Version // Type-safe, validated -``` - ---- - -## Official References - -✅ **FSharp.Data JSON Schema Mode Documentation** - https://fsprojects.github.io/FSharp.Data/library/JsonSchema.html - -✅ **JSON Schema Official Specification** - https://json-schema.org/ - -✅ **Quarto Inspect Documentation** - https://quarto.org/docs/advanced/inspect/ - ---- - -## Testing & Verification - -✅ **Tests**: All 13+ tests remain valid and passing -✅ **Code**: Syntax verified and correct -✅ **Documentation**: All guides updated -✅ **Compatibility**: No breaking changes -✅ **Quality**: Professional-grade implementation - ---- - -## Summary - -This correction ensures the implementation uses **FSharp.Data's proper JSON Schema validation mode** with the `Schema=` syntax. This is the correct, authoritative approach to type-safe JSON parsing with official specifications. - -### Status: ✅ COMPLETE AND VERIFIED - -The implementation now demonstrates professional-grade understanding and usage of: -- FSharp.Data type providers -- JSON Schema specifications -- Type-safe JSON parsing -- Official schema-driven development - -All documentation has been updated to reflect the correct approach. - ---- - -**Thank you for catching this important distinction!** - -The correction improves code quality, type safety, and maintainability. diff --git a/docs/DEV-REPORTS/archive/CORRECTION_SUMMARY.md b/docs/DEV-REPORTS/archive/CORRECTION_SUMMARY.md deleted file mode 100644 index 741d495..0000000 --- a/docs/DEV-REPORTS/archive/CORRECTION_SUMMARY.md +++ /dev/null @@ -1,178 +0,0 @@ -✅ SCHEMA MODE CORRECTION APPLIED -==================================== - -**Date**: January 20, 2026 -**Change**: Updated to use FSharp.Data's JSON Schema validation mode -**Status**: ✅ COMPLETE - -What Was Fixed -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Initial Implementation (Sample Mode): - ❌ JsonProvider<"sample-project.json"> - - Inferred types from JSON sample data - - Not using proper schema validation - -Corrected Implementation (Schema Mode): - ✅ JsonProvider - - Validates against official JSON Schema spec - - Proper FSharp.Data schema mode usage - -FSharp.Data Modes -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Mode 1: Sample Mode (Type Inference) - Syntax: JsonProvider<"sample.json"> - - Infers types from JSON sample - - Loose validation - - Good for exploration - -Mode 2: Schema Mode (JSON Schema Validation) ✅ WHAT WE USE - Syntax: JsonProvider - - Validates against JSON Schema specification - - Strict validation - - Better IDE support - - More authoritative - -Files Updated -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -✅ QuartoInspect/QuartoTypes.fs - - Changed to: JsonProvider - - Changed to: JsonProvider - -✅ getcomputo-pub-refactored.fsx - - Updated type provider declarations with Schema= syntax - - Updated comments to reflect schema mode - -✅ QuartoInspect/QuartoInspect.fsproj - - Changed references from sample files to schema files - -✅ Documentation Files - - QuartoInspect/README.md (explains schema mode) - - SCHEMA_BASED_PROVIDERS.md (detailed schema mode documentation) - - QUARTO_PROVIDER_IMPLEMENTATION.md (updated descriptions) - - QUICK_REFERENCE.md (shows correct syntax) - - MANIFEST.md (updated component descriptions) - -Key Improvements -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -✅ Direct Schema Compliance - Type providers now validate against official JSON schemas - Alignment with Quarto's published specifications - -✅ Stricter Validation - Schema mode enforces constraints defined in JSON Schema - More reliable type checking - -✅ Better IDE Support - IntelliSense based on schema definition - Not dependent on sample data being complete - -✅ Future-Proof Design - When Quarto updates schemas, types automatically update - No need to create new samples - -✅ Authoritative Foundation - Types derived from official specifications - Not from arbitrary example JSON - -Type Provider Declaration Before/After -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -BEFORE (Sample Mode - Incorrect): - type QuartoProjectProvider = JsonProvider<"sample-project.json"> - type QuartoDocumentProvider = JsonProvider<"sample-document.json"> - -AFTER (Schema Mode - Correct): - type QuartoProjectProvider = - JsonProvider - - type QuartoDocumentProvider = - JsonProvider - -Usage Remains Identical -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -```fsharp -// Usage is the same - parsing and type-safe access unchanged -let parsed = QuartoProjectProvider.Parse(jsonString) -let version = parsed.Quarto.Version // Type-safe -let engines = parsed.Engines // Type-safe -let dir = parsed.Dir // Type-safe -``` - -The change is at the type provider definition level, not usage level. - -Documentation Added -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -✅ SCHEMA_MODE_CORRECTION.md - Complete explanation of the correction - Detailed comparison of both modes - Rationale for the change - -Architecture Impact -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -``` -Official JSON Schema Files (Quarto publishes) - ↓ -FSharp.Data JsonProvider (Schema= mode) - ↓ -Compile-time Type Generation - ↓ -Type-Safe F# Code - ↓ -Runtime JSON Parsing with Schema Validation -``` - -All Tests Still Pass -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -✅ 13+ tests unchanged -✅ Test logic unaffected -✅ Error handling unchanged -✅ Type checking improved - -What This Means -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -You now have: -✅ Proper JSON Schema validation via FSharp.Data -✅ Direct alignment with official Quarto schemas -✅ Stronger compile-time type safety -✅ Better IDE support based on schema -✅ More maintainable code -✅ More professional implementation - -Reference -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -FSharp.Data JSON Schema Mode: -https://fsprojects.github.io/FSharp.Data/library/JsonSchema.html - -Details of correction in: -SCHEMA_MODE_CORRECTION.md (see detailed explanation) - -Details of schema-based design in: -SCHEMA_BASED_PROVIDERS.md (comprehensive guide) - -Summary -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -The implementation has been corrected to use **FSharp.Data's proper -JSON Schema validation mode** with the `Schema=` syntax. - -This provides the correct, authoritative approach to type-safe JSON -parsing with official Quarto schemas. - -✅ Implementation Status: CORRECTED AND COMPLETE -✅ Tests: 13+ (still passing) -✅ Documentation: 7 guides (updated) -✅ Code Quality: Professional-grade -✅ Ready to Use: YES - -Thank you for pointing out this important distinction! -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/docs/DEV-REPORTS/archive/CORRECTION_VERIFIED.md b/docs/DEV-REPORTS/archive/CORRECTION_VERIFIED.md deleted file mode 100644 index 5de7964..0000000 --- a/docs/DEV-REPORTS/archive/CORRECTION_VERIFIED.md +++ /dev/null @@ -1,212 +0,0 @@ -# ✅ Correction Verified - JSON Schema Mode Implementation - -**Correction Date**: January 20, 2026 -**Status**: ✅ COMPLETE AND VERIFIED - -## What Was Corrected - -Changed from FSharp.Data's **Sample Mode** to the proper **JSON Schema Validation Mode**. - -### The Mistake -```fsharp -// ❌ WRONG - Sample mode (type inference) -type QuartoProjectProvider = JsonProvider<"sample-project.json"> -``` - -### The Correction -```fsharp -// ✅ CORRECT - Schema mode (schema validation) -type QuartoProjectProvider = JsonProvider -``` - -## Verification Checklist - -### Core Files ✅ -- [x] `QuartoInspect/QuartoTypes.fs` - Uses `Schema=` syntax -- [x] `getcomputo-pub-refactored.fsx` - Uses `Schema=` syntax -- [x] `QuartoInspect/QuartoInspect.fsproj` - References schema files - -### Documentation ✅ -- [x] `QuartoInspect/README.md` - Explains schema mode -- [x] `SCHEMA_BASED_PROVIDERS.md` - Detailed schema mode guide -- [x] `QUARTO_PROVIDER_IMPLEMENTATION.md` - Updated descriptions -- [x] `QUICK_REFERENCE.md` - Shows correct syntax -- [x] `MANIFEST.md` - Updated component info -- [x] `SCHEMA_MODE_CORRECTION.md` - NEW: Detailed correction explanation -- [x] `CORRECTION_SUMMARY.md` - NEW: Summary of changes - -### Tests ✅ -- [x] Test code unchanged (still 13+ tests) -- [x] Test data valid for both modes -- [x] Schema validation still works - -## Key Differences - Schema Mode vs Sample Mode - -### JSON Schema Mode (✅ What We Use Now) -```fsharp -JsonProvider -``` -- Validates against official JSON Schema specification -- Strict type enforcement based on schema -- Types defined by schema constraints -- **Proper way to use schemas** ✅ - -### Sample Mode (❌ What We Were Using) -```fsharp -JsonProvider<"sample-project.json"> -``` -- Infers types from JSON sample data -- Loose validation based on sample -- Types inferred from example -- Less strict, less authoritative - -## Type Provider Generation - -### Before (Sample Mode) -``` -sample-project.json (example data) - ↓ -Type inference - ↓ -F# types based on sample structure -``` - -### After (Schema Mode) ✅ -``` -src/quarto-inspect-project-json-schema.json (official schema) - ↓ -Schema validation - ↓ -F# types based on schema constraints -``` - -## Code Samples Showing Correctness - -### Correct Declaration in QuartoTypes.fs -```fsharp -namespace QuartoInspect - -open FSharp.Data - -/// Type provider for Quarto project-level inspect output -/// Based directly on official JSON Schema: src/quarto-inspect-project-json-schema.json -type QuartoProjectProvider = JsonProvider - -/// Type provider for Quarto document-level inspect output -/// Based directly on official JSON Schema: src/quarto-inspect-document-json-schema.json -type QuartoDocumentProvider = JsonProvider -``` - -### Correct Declaration in getcomputo-pub-refactored.fsx -```fsharp -/// Type provider for Quarto project inspection output -/// Based directly on official JSON Schema: src/quarto-inspect-project-json-schema.json -type QuartoProjectProvider = JsonProvider - -/// Type provider for Quarto document inspection output -/// Based directly on official JSON Schema: src/quarto-inspect-document-json-schema.json -type QuartoDocumentProvider = JsonProvider -``` - -## References to Official Documentation - -✅ **FSharp.Data JSON Schema Mode** - https://fsprojects.github.io/FSharp.Data/library/JsonSchema.html - - Quote from docs: - > "The JsonProvider also supports JSON Schema files. When you provide - > a schema file using the Schema property, the type provider generates - > types based on the schema constraints rather than inferring from data." - -✅ **JSON Schema Official Specification** - https://json-schema.org/ - -✅ **Quarto Inspect Documentation** - https://quarto.org/docs/advanced/inspect/ - (References the official JSON schemas) - -## Why This Matters - -1. **Correctness** - - Schema mode is the proper way to use JSON schemas with FSharp.Data - - Not just using schemas for documentation - -2. **Validation** - - Type provider validates against official JSON Schema spec - - More authoritative and strict - -3. **Authority** - - Types come from official Quarto specifications - - Not inferred from arbitrary example JSON - -4. **Maintainability** - - When Quarto updates schemas, types automatically update - - Clear source of truth - -5. **IDE Support** - - IntelliSense based on schema definition - - More complete and accurate - -## Implementation Quality - -The implementation now demonstrates: -- ✅ Proper understanding of FSharp.Data capabilities -- ✅ Correct use of JSON Schema mode -- ✅ Direct alignment with Quarto specifications -- ✅ Professional-grade type safety -- ✅ Best practices for schema-driven development - -## No Breaking Changes - -Usage of the type providers remains identical: - -```fsharp -// This works the same in both sample and schema mode -let parsed = QuartoProjectProvider.Parse(jsonString) -let version = parsed.Quarto.Version -let engines = parsed.Engines -``` - -The improvement is internal (how types are generated), not in the API. - -## Testing Status - -- ✅ All 13+ tests remain valid -- ✅ Test data compatible with both modes -- ✅ No test code changes required -- ✅ Type checking improved - -## Documentation Updates - -New documents created to explain the correction: -- `SCHEMA_MODE_CORRECTION.md` - Detailed explanation -- `CORRECTION_SUMMARY.md` - Quick summary - -Updated documents: -- `QuartoInspect/README.md` -- `SCHEMA_BASED_PROVIDERS.md` -- `QUARTO_PROVIDER_IMPLEMENTATION.md` -- `QUICK_REFERENCE.md` -- `MANIFEST.md` - -## Summary of Correction - -| Aspect | Before | After | -|--------|--------|-------| -| **Syntax** | `JsonProvider<"sample.json">` | `JsonProvider` | -| **Validation Type** | Sample-based inference | Schema specification validation | -| **Authority** | Example-dependent | Official specification | -| **Type Safety** | Good | Excellent | -| **IDE Support** | Good | Excellent | -| **Correctness** | Partial | Complete ✅ | - -## Conclusion - -The implementation has been **corrected to use the proper JSON Schema validation mode** -of FSharp.Data's JsonProvider. This is the correct, authoritative approach to working -with official JSON schemas in F#. - -**Status**: ✅ **CORRECTION COMPLETE AND VERIFIED** - -The code is now production-ready with professional-grade implementation of schema-driven -type providers. diff --git a/docs/DEV-REPORTS/archive/FSDATA_SCHEMA_LIMITATIONS.md b/docs/DEV-REPORTS/archive/FSDATA_SCHEMA_LIMITATIONS.md deleted file mode 100644 index ee9a6d2..0000000 --- a/docs/DEV-REPORTS/archive/FSDATA_SCHEMA_LIMITATIONS.md +++ /dev/null @@ -1,252 +0,0 @@ -# FSharp.Data JSON Schema Limitations - Pragmatic Solution - -**Date**: January 20, 2026 -**Status**: ✅ Resolved with practical approach -**Issue**: FSharp.Data's JSON Schema support has limitations - ---- - -## The Problem - -We initially tried to use FSharp.Data's JSON Schema validation mode (`Schema=` parameter): - -```fsharp -// ❌ Attempted but problematic -type QuartoProjectProvider = JsonProvider -``` - -However, FSharp.Data's JSON Schema support has significant limitations: - -### FSharp.Data JSON Schema Limitations - -1. **Limited to Draft-07**: Only supports JSON Schema Draft-07 -2. **No External $ref**: Cannot handle `$ref` to external files -3. **Limited Feature Support**: Missing support for: - - `dependencies` - - `conditionals` (if/then/else) - - `unevaluatedProperties` -4. **Mutual Exclusivity**: Cannot use Schema and SampleIsList together - -### Our Schemas Have Incompatibilities - -The document schema uses an external reference: -```json -"project": { - "$ref": "src/quarto-inspect-project-json-schema.json" // ❌ External file reference -} -``` - -This external `$ref` is **not supported** by FSharp.Data's schema validator. - ---- - -## The Solution - -We're using a **pragmatic hybrid approach**: - -### What We Use Now -```fsharp -// ✅ Sample mode - reliable and well-supported -type QuartoProjectProvider = JsonProvider<"sample-project.json"> -type QuartoDocumentProvider = JsonProvider<"sample-document.json"> -``` - -### Benefits of This Approach - -1. **Reliable**: FSharp.Data fully supports sample mode -2. **Type-Safe**: Still provides compile-time type checking -3. **Well-Tested**: Sample mode is battle-tested -4. **No Workarounds**: Works without limitations -5. **Still Schema-Compliant**: Samples conform to official schemas - ---- - -## How This Works - -### The Architecture - -``` -Official Quarto Schemas (JSON Schema format) - ↓ -Representative Sample JSON Files (conform to schemas) - ↓ -FSharp.Data JsonProvider (sample mode) - ↓ -Type-Safe F# Types - ↓ -Runtime Schema Validation (via QuartoClient) -``` - -### Two Levels of Validation - -1. **Compile-Time**: Type provider validates JSON structure -2. **Runtime**: `QuartoClient.validateProjectSchema()` validates against actual schema - -```fsharp -// Compile-time type checking (via sample) -let parsed = QuartoProjectProvider.Parse(jsonStr) -let version = parsed.Quarto.Version - -// Runtime schema validation (against actual schema) -match QuartoClient.validateProjectSchema jsonStr with -| Ok _ -> printfn "✓ Schema valid" -| Error msg -> printfn "✗ Schema invalid: %s" msg -``` - ---- - -## Files Updated - -✅ **QuartoInspect/QuartoTypes.fs** -- Reverted from Schema mode to Sample mode -- Using `sample-project.json` and `sample-document.json` - -✅ **getcomputo-pub-refactored.fsx** -- Reverted from Schema mode to Sample mode -- Using sample files instead of schema files - -✅ **QuartoInspect/QuartoInspect.fsproj** -- Changed to include sample JSON files -- Updated comments to explain approach - ---- - -## Why This is Actually Better - -### Schema Mode Pros/Cons -| Aspect | Schema Mode | -|--------|-----------| -| Pros | Direct schema validation | -| Cons | Limited support, external $ref fails | -| Cons | Complex workarounds needed | -| Cons | Fragile with schema changes | - -### Sample Mode Pros/Cons -| Aspect | Sample Mode | -|--------|-----------| -| Pros | Well-supported by FSharp.Data | -| Pros | No limitations or workarounds | -| Pros | Reliable and tested | -| Cons | Depends on sample being representative | -| Mitigation | Samples explicitly conform to schemas | - -**We get reliability without compromising validation.** - ---- - -## Type Safety is Maintained - -```fsharp -// Same API, same type safety -let json = """{"quarto": {"version": "1.3.0"}, "dir": "/path", ...}""" - -let parsed = QuartoProjectProvider.Parse(json) -let version = parsed.Quarto.Version // ✅ Type-safe -let dir = parsed.Dir // ✅ Type-safe -let engines = parsed.Engines // ✅ Type-safe -``` - ---- - -## Sample Files are Schema-Aligned - -The sample files are maintained to be **representative and schema-compliant**: - -### sample-project.json -- Includes all major fields from the schema -- Follows the schema structure exactly -- Valid example of project inspect output - -### sample-document.json -- Includes all major fields from the schema -- Follows the schema structure exactly -- Valid example of document inspect output - ---- - -## Runtime Validation Still Works - -The `QuartoClient` module provides runtime schema validation: - -```fsharp -match QuartoClient.validateProjectSchema jsonStr with -| Ok element -> printfn "✓ Valid according to schema" -| Error msg -> printfn "✗ Schema violation: %s" msg -``` - -This validates against the **actual JSON schema**, not just the sample. - ---- - -## Tests Remain Unchanged - -All 13+ tests continue to work: -- ✅ Schema compliance tests (validate against actual schema) -- ✅ Type provider tests (parse sample data) -- ✅ Integration tests (test with real data) - ---- - -## Documentation Updated - -Files explaining the approach: - -- **README.md**: Explains sample-based type providers -- **SCHEMA_BASED_PROVIDERS.md**: Explains the dual-layer approach -- **FSharp.Data Limitations**: This document - ---- - -## The Best of Both Worlds - -We get: - -✅ **Type Safety** from type providers -✅ **Schema Validation** from runtime checks -✅ **Reliability** from well-supported sample mode -✅ **No Workarounds** or fragile code -✅ **Professional Implementation** with clear approach - ---- - -## FSharp.Data Limitations Context - -These limitations are documented in FSharp.Data itself: - -> "When using the Schema parameter: -> - You cannot use the Sample parameter -> - Currently supports JSON Schema Draft-07 -> - JSON Schema references ($ref) support is limited to local references within the schema -> - Some advanced schema features like dependencies, conditionals, and unevaluatedProperties are not fully supported" - -This is a known limitation of the library, not a bug in our implementation. - ---- - -## Conclusion - -By using **sample mode with representative samples**, we maintain: - -- ✅ Full type safety -- ✅ Schema compliance -- ✅ Runtime validation -- ✅ No technical debt -- ✅ Reliable, well-tested approach - -This is a **pragmatic, professional solution** that acknowledges the limitations of tools and uses them effectively within their constraints. - ---- - -## Summary Table - -| Aspect | Schema Mode (Attempted) | Sample Mode (Current) | -|--------|----------------------|------------------| -| **FSharp.Data Support** | Limited | Full ✅ | -| **External $ref** | Not supported ❌ | N/A (samples) | -| **Type Safety** | Yes | Yes ✅ | -| **Schema Validation** | Type Provider | Runtime ✅ | -| **Reliability** | Fragile | Solid ✅ | -| **Documentation** | Complex | Clear ✅ | -| **Maintainability** | Difficult | Easy ✅ | - -**Result**: Sample mode is the right choice for this use case. diff --git a/docs/DEV-REPORTS/archive/IMPLEMENTATION_COMPLETE.md b/docs/DEV-REPORTS/archive/IMPLEMENTATION_COMPLETE.md deleted file mode 100644 index 7e21ff2..0000000 --- a/docs/DEV-REPORTS/archive/IMPLEMENTATION_COMPLETE.md +++ /dev/null @@ -1,264 +0,0 @@ -# Implementation Complete: Schema-Based Type Providers with Tests - -## Summary - -I have successfully implemented a complete F# infrastructure for the Computo project that: - -✅ **Leverages official Quarto JSON schemas** via FSharp.Data type providers -✅ **Includes comprehensive Expecto tests** (13+ test cases) -✅ **Tests GitHub API availability** and Quarto inspect compliance -✅ **Uses sample JSON files** that conform to official schemas -✅ **Provides compile-time type safety** for JSON parsing - -## What Was Created - -### 1. Core Library (`QuartoInspect/`) - -#### QuartoTypes.fs -- Type providers using FSharp.Data's **JSON Schema validation mode** (`Schema=` syntax) -- Direct validation against official Quarto schemas -- Domain types for Quarto inspection results -- Safe parsing functions - -#### QuartoClient.fs -- `runInspect()` - Execute quarto inspect commands -- `checkQuartoAvailable()` - Verify Quarto installation -- `validateDocumentSchema()` - Validate against document schema -- `validateProjectSchema()` - Validate against project schema - -#### Official Schema Files (Referenced) -- **src/quarto-inspect-project-json-schema.json** - Official project schema -- **src/quarto-inspect-document-json-schema.json** - Official document schema - -### 2. Test Suite (`QuartoInspect.Tests/`) - -13 comprehensive tests organized in 5 categories: - -**GitHub API Availability Tests** -- ✓ API reachability -- ✓ Repository retrieval -- ✓ Repository details -- ✓ Rate limit handling - -**Quarto Installation Tests** -- ✓ Quarto availability verification - -**Schema Compliance Tests** -- ✓ Valid document schema parsing -- ✓ Invalid document detection -- ✓ Valid project schema parsing -- ✓ Invalid project detection -- ✓ Type provider document parsing -- ✓ Type provider project parsing - -**Mock Repository Integration Tests** -- ✓ Mock repository retrieval -- ✓ Repository structure validation - -**Quarto Inspect Execution Tests** -- ✓ Real quarto inspect execution -- ✓ Non-Quarto directory handling - -### 3. Enhanced Main Script - -**getcomputo-pub-refactored.fsx** - Refactored version with: -- Embedded type providers for schema validation -- Improved JSON parsing -- Better error messages -- Original functionality preserved - -### 4. Documentation - -- **QuartoInspect/README.md** - Comprehensive usage guide -- **QUARTO_PROVIDER_IMPLEMENTATION.md** - Implementation details -- **SCHEMA_BASED_PROVIDERS.md** - Schema architecture explanation - -## Key Features - -### Type Safety -```fsharp -// Compile-time type checking using JSON Schema validation -let parsed = QuartoProjectProvider.Parse(jsonString) -let version = parsed.Quarto.Version // Schema-validated, type-safe, autocomplete works -``` - -### Schema Compliance -Type providers use FSharp.Data's **JSON Schema mode** with official Quarto schemas: -- `src/quarto-inspect-project-json-schema.json` -- `src/quarto-inspect-document-json-schema.json` - -This validates JSON against the official JSON Schema specification. - -### Runtime Validation -```fsharp -match QuartoClient.validateProjectSchema jsonString with -| Ok element -> // Valid according to schema -| Error msg -> // Schema violation found -``` - -### Comprehensive Testing -All tests handle missing prerequisites gracefully: -- Skips GitHub tests if token not available -- Skips Quarto tests if not installed -- Skips mock repo tests if not found - -## File Structure - -``` -/QuartoInspect/ - ├── QuartoInspect.fsproj - ├── QuartoTypes.fs # Type providers - ├── QuartoClient.fs # Quarto client - ├── sample-project.json # Schema example - ├── sample-document.json # Schema example - └── README.md # Usage guide - -/QuartoInspect.Tests/ - ├── QuartoInspect.Tests.fsproj - └── QuartoInspectTests.fs # 13+ tests - -/QuartoInspect.Tests/ - ├── QuartoInspect.Tests.fsproj - └── QuartoInspectTests.fs - -Documentation: - ├── QUARTO_PROVIDER_IMPLEMENTATION.md # Implementation overview - └── SCHEMA_BASED_PROVIDERS.md # Schema architecture -``` - -## Quick Start - -### Build the Library -```bash -cd QuartoInspect -dotnet build -``` - -### Run Tests -```bash -cd QuartoInspect.Tests -dotnet restore -dotnet build -dotnet run -``` - -### Run Specific Tests -```bash -dotnet run -- --filter "GitHub API" # GitHub tests only -dotnet run -- --filter "Schema" # Schema tests only -dotnet run -- --parallel 1 # Run serially -``` - -### Use in Your Scripts -```fsharp -#r "nuget: FSharp.Data" -#load "../QuartoInspect/QuartoTypes.fs" -open QuartoInspect.QuartoTypes - -let json = System.IO.File.ReadAllText("output.json") -match parseProjectJson json with -| Ok parsed -> printfn "Version: %s" parsed.Quarto.Version -| Error msg -> printfn "Error: %s" msg -``` - -## Integration with Existing Code - -The refactored `getcomputo-pub-refactored.fsx` can be used as a drop-in replacement for `getcomputo-pub.fsx`: - -```bash -dotnet fsi getcomputo-pub-refactored.fsx -``` - -Or gradually integrate the type provider patterns into your existing script. - -## Benefits - -### For Development -- **Type Safety**: Compile-time checking prevents runtime JSON parsing errors -- **IntelliSense**: Full IDE support with autocomplete -- **Refactoring**: Safe to rename fields - compiler catches issues -- **Documentation**: Types serve as schema documentation - -### For Maintenance -- **Schema Aligned**: Always matches official Quarto specs -- **Versioning**: Easy to track schema changes -- **Extensibility**: Add new fields by updating samples -- **Testing**: Comprehensive tests catch regressions - -### For Production -- **Performance**: No runtime overhead - compilation only -- **Reliability**: Schema validation ensures data integrity -- **Debugging**: Type errors caught before runtime -- **Scalability**: Easy to process many Quarto projects - -## Technical Decisions - -1. **Schema Samples vs. Inline JSON**: Used separate files for clarity and maintainability -2. **Type Providers vs. Manual Parsing**: Type providers provide compile-time safety -3. **Result<'T, string> Error Handling**: Explicit error handling with clear messages -4. **Expecto for Testing**: Lightweight, expressive, good parallelization -5. **Async/Await for I/O**: Non-blocking operations for better performance - -## Next Steps - -1. **Run tests to verify setup**: - ```bash - cd QuartoInspect.Tests && dotnet run - ``` - -2. **Review test output** - note any skips/failures - -3. **Choose integration approach**: - - Use refactored script directly, or - - Integrate type provider patterns into existing script - -4. **Extend as needed** - add more tests or functionality - -## Environment Setup - -**Requirements**: -- .NET 8.0 or later -- Quarto (for integration tests - optional) -- GitHub API token (for authenticated tests - optional) - -**Optional Configuration**: -```bash -export API_GITHUB_TOKEN="ghp_your_token_here" -``` - -## Support & Documentation - -- **Usage**: See `QuartoInspect/README.md` -- **Implementation**: See `QUARTO_PROVIDER_IMPLEMENTATION.md` -- **Architecture**: See `SCHEMA_BASED_PROVIDERS.md` -- **Quarto Docs**: https://quarto.org/docs/advanced/inspect/ - -## Troubleshooting - -**Tests skip unexpectedly?** -- This is normal! Tests gracefully skip when prerequisites unavailable -- Missing GitHub token: Tests skip GitHub API tests -- Quarto not installed: Tests skip execution tests -- Mock repo not found: Tests skip integration tests - -**Build fails?** -- Ensure .NET 8.0 is installed: `dotnet --version` -- Clear build cache: `dotnet clean` -- Restore dependencies: `dotnet restore` - -**Type errors in IDE?** -- Rebuild project: `dotnet build` -- Reload editor window -- Check sample JSON files exist in correct location - -## Summary - -The implementation is complete and ready to use. It provides: -- ✅ Official schema-based type providers -- ✅ Comprehensive test suite (13+ tests) -- ✅ GitHub API availability tests -- ✅ Quarto inspect schema compliance tests -- ✅ Full documentation and examples -- ✅ Production-ready code quality - -All tests handle missing prerequisites gracefully and can be run immediately in any environment. diff --git a/docs/DEV-REPORTS/archive/MANIFEST.md b/docs/DEV-REPORTS/archive/MANIFEST.md deleted file mode 100644 index db7d99c..0000000 --- a/docs/DEV-REPORTS/archive/MANIFEST.md +++ /dev/null @@ -1,385 +0,0 @@ -# 📋 Implementation Manifest - -**Date**: January 20, 2026 -**Status**: ✅ COMPLETE -**Quality**: Production-Ready - ---- - -## 📦 Core Library Files - -### QuartoInspect/ -- **QuartoInspect.fsproj** ✅ - - Project configuration for .NET 8.0 - - References to FSharp.Data, Octokit - - Includes official schema files as content - -- **QuartoTypes.fs** ✅ - - Type providers using JSON Schema validation mode (`Schema=` syntax) - - `QuartoProjectProvider` (based on `src/quarto-inspect-project-json-schema.json`) - - `QuartoDocumentProvider` (based on `src/quarto-inspect-document-json-schema.json`) - - Domain types for type-safe parsing - - Helper functions: `parseProjectJson`, `parseDocumentJson` - - ~30 lines of type-safe F# code - -- **QuartoClient.fs** ✅ - - Async Quarto inspection API - - `runInspect()` - Execute quarto inspect commands - - `checkQuartoAvailable()` - Verify Quarto installation - - `validateProjectSchema()` - Runtime schema validation - - `validateDocumentSchema()` - Runtime schema validation - - Error handling with Result type - - 120 lines of well-tested code - -- **sample-project.json** ✅ - - Representative project inspection example - - Conforms to `src/quarto-inspect-project-json-schema.json` - - Includes: quarto, dir, engines, config, files, fileInformation, extensions - - 48 lines of valid JSON - -- **sample-document.json** ✅ - - Representative document inspection example - - Conforms to `src/quarto-inspect-document-json-schema.json` - - Includes: quarto, engines, formats, resources, fileInformation - - 32 lines of valid JSON - -- **README.md** ✅ - - Comprehensive usage guide - - Building instructions - - Type provider documentation - - Schema information - - Error handling guide - - Troubleshooting tips - - 400+ lines of documentation - ---- - -## 🧪 Test Suite Files - -### QuartoInspect.Tests/ -- **QuartoInspect.Tests.fsproj** ✅ - - Project configuration for .NET 8.0 - - References QuartoInspect library - - Expecto framework integration - - 20+ lines of project configuration - -- **QuartoInspectTests.fs** ✅ - - 13+ comprehensive tests organized in 5 categories - - **GitHub API Availability Tests** (4 tests) - - ✓ API Reachability - - ✓ Repository Retrieval - - ✓ Repository Details - - ✓ Rate Limit Handling - - **Quarto Installation Tests** (1 test) - - ✓ Quarto Availability Check - - **Schema Compliance Tests** (6 tests) - - ✓ Valid Document Schema - - ✓ Invalid Document Detection - - ✓ Valid Project Schema - - ✓ Invalid Project Detection - - ✓ Type Provider Document Parsing - - ✓ Type Provider Project Parsing - - **Mock Repository Integration Tests** (2 tests) - - ✓ Repository Retrieval - - ✓ Repository Structure - - **Quarto Inspect Execution Tests** (2 tests) - - ✓ Real Inspect Execution - - ✓ Non-Quarto Directory Handling - - 400+ lines of production test code - - Expecto configuration for parallel execution - - Graceful test skipping for missing prerequisites - ---- - -## 🔄 Enhanced Script - -- **getcomputo-pub-refactored.fsx** ✅ - - Refactored version of `getcomputo-pub.fsx` - - Includes embedded type providers - - Schema validation integration - - Improved error messages - - Full original functionality preserved - - 550+ lines of enhanced F# code - ---- - -## 📚 Documentation Files - -### Navigation & Quick Reference -- **00-START-HERE.md** ✅ (This file) - - Quick summary of everything - - 3-step quick start - - Command reference - - Success checklist - -- **INDEX.md** ✅ - - Navigation hub for all documentation - - File organization overview - - Architecture highlights - - Links to all other guides - -- **QUICK_REFERENCE.md** ✅ - - 1-page cheat sheet - - Common patterns and commands - - Troubleshooting tips - - File locations and functions - - ~150 lines of dense reference material - -### Detailed Guides -- **VISUAL_OVERVIEW.md** ✅ - - ASCII diagrams and flow charts - - Data flow visualization - - Test architecture diagram - - Integration path options - - Type provider benefits matrix - - ~200 lines with visual aids - -- **SCHEMA_BASED_PROVIDERS.md** ✅ - - Architecture explanation - - Official schema integration details - - How type providers work - - Validation chain explanation - - Schema update procedures - - ~200 lines of architecture documentation - -- **QUARTO_PROVIDER_IMPLEMENTATION.md** ✅ - - Complete implementation overview - - Project structure explanation - - Component descriptions - - Type provider advantages - - Schema validation details - - Performance considerations - - ~300 lines of detailed documentation - -- **IMPLEMENTATION_COMPLETE.md** ✅ - - Executive summary - - What was created - - Quick start guide - - File structure overview - - Benefits summary - - Next steps - - ~250 lines of summary documentation - ---- - -## 📋 Schema Files (Reference) - -- **src/quarto-inspect-project-json-schema.json** ✓ (Already in repo) - - Official Quarto project schema - - Referenced by implementation - - Source: https://quarto.org/docs/advanced/inspect/ - -- **src/quarto-inspect-document-json-schema.json** ✓ (Already in repo) - - Official Quarto document schema - - Referenced by implementation - - Source: https://quarto.org/docs/advanced/inspect/ - ---- - -## 📊 Statistics - -### Code -- **Core Library**: ~195 lines (QuartoTypes.fs + QuartoClient.fs) -- **Tests**: ~400 lines (13+ comprehensive tests) -- **Refactored Script**: ~550 lines (drop-in replacement) -- **Total Code**: ~1,145 lines of production F# - -### Documentation -- **Navigation**: ~150 lines (INDEX.md) -- **Quick Reference**: ~150 lines (QUICK_REFERENCE.md) -- **Visual Guide**: ~200 lines (VISUAL_OVERVIEW.md) -- **Architecture**: ~200 lines (SCHEMA_BASED_PROVIDERS.md) -- **Implementation**: ~300 lines (QUARTO_PROVIDER_IMPLEMENTATION.md) -- **Summary**: ~250 lines (IMPLEMENTATION_COMPLETE.md) -- **Start Here**: ~150 lines (00-START-HERE.md) -- **Library Guide**: ~400 lines (QuartoInspect/README.md) -- **Total Documentation**: ~1,800 lines - -### Tests -- **GitHub API**: 4 tests -- **Quarto Installation**: 1 test -- **Schema Compliance**: 6 tests -- **Integration**: 2 tests -- **Execution**: 2 tests -- **Total Tests**: 15+ comprehensive tests - ---- - -## ✅ Requirements Fulfillment - -### User Requirements -✅ **Leverage FSharp.Data json type provider with both provided schemas** - - Implemented in QuartoTypes.fs - - Uses sample-project.json and sample-document.json - - Based on official Quarto schemas - -✅ **Make some f# expecto tests** - - 15+ tests implemented - - Organized in 5 categories - - Comprehensive coverage - -✅ **Check github api availability** - - 4 dedicated GitHub API tests - - Includes authentication handling - - Rate limit graceful degradation - -✅ **Quarto inspect compliance of one repo example (mock)** - - Mock repository integration tests - - Schema validation tests - - Real execution tests with error handling - ---- - -## 🔍 File Locations - -``` -QuartoInspect/ [Library] -├── QuartoTypes.fs [Type providers] -├── QuartoClient.fs [Client API] -├── sample-project.json [Schema example] -├── sample-document.json [Schema example] -├── QuartoInspect.fsproj [Project] -└── README.md [Docs] - -QuartoInspect.Tests/ [Tests] -├── QuartoInspectTests.fs [15+ tests] -└── QuartoInspect.Tests.fsproj [Project] - -Documentation/ -├── 00-START-HERE.md ← Entry point -├── INDEX.md ← Navigation -├── QUICK_REFERENCE.md ← Cheat sheet -├── VISUAL_OVERVIEW.md ← Diagrams -├── SCHEMA_BASED_PROVIDERS.md ← Architecture -├── QUARTO_PROVIDER_IMPLEMENTATION.md ← Details -└── IMPLEMENTATION_COMPLETE.md ← Summary - -Scripts/ -└── getcomputo-pub-refactored.fsx [Enhanced script] - -Schemas/ -├── src/quarto-inspect-project-json-schema.json -└── src/quarto-inspect-document-json-schema.json -``` - ---- - -## 🎯 Quality Metrics - -### Code Quality -- ✅ Type-safe F# with Result error handling -- ✅ Follows F# style guidelines -- ✅ Comprehensive error messages -- ✅ Async/await for I/O operations -- ✅ Clean separation of concerns -- ✅ Extensible architecture - -### Test Coverage -- ✅ 15+ tests covering all features -- ✅ GitHub API tests with auth handling -- ✅ Schema compliance validation -- ✅ Integration tests with real repos -- ✅ Graceful test skipping -- ✅ Parallel execution support - -### Documentation -- ✅ 6 detailed guides -- ✅ 1,800+ lines of documentation -- ✅ Code examples throughout -- ✅ Visual diagrams included -- ✅ Quick reference available -- ✅ Troubleshooting guides - -### Maintainability -- ✅ Clear code structure -- ✅ Comprehensive comments -- ✅ Schema-based design -- ✅ Easy to extend -- ✅ Well-organized files -- ✅ Production-ready - ---- - -## 🚀 Quick Start - -```bash -# 1. Build -cd QuartoInspect && dotnet build - -# 2. Test -cd ../QuartoInspect.Tests -dotnet restore && dotnet build && dotnet run - -# 3. Read -# Start with: 00-START-HERE.md or INDEX.md -``` - ---- - -## ✨ Key Features Implemented - -✅ **Type Providers** -- Based on official Quarto schemas -- Compile-time type safety -- Full IDE IntelliSense support - -✅ **Schema Validation** -- Runtime validation functions -- Compile-time validation via type providers -- Clear error messages - -✅ **Comprehensive Testing** -- GitHub API availability tests -- Quarto installation verification -- Schema compliance validation -- Real repository integration -- Quarto inspect execution tests - -✅ **Error Handling** -- Result<'T, string> throughout -- Graceful error degradation -- Explicit error messages - -✅ **Documentation** -- Quick reference guide -- Visual diagrams and flows -- Complete architecture documentation -- Usage examples -- Troubleshooting guides - -✅ **Production Ready** -- Well-tested code -- Clear error messages -- Comprehensive documentation -- Extensible design -- Performance optimized - ---- - -## 📞 Support - -For questions, refer to: -- **Quick Start**: 00-START-HERE.md -- **Navigation**: INDEX.md -- **Quick Reference**: QUICK_REFERENCE.md -- **Full Docs**: See relevant .md file -- **Code Comments**: In source files - ---- - -## 🎉 Summary - -**Implementation Date**: January 20, 2026 -**Status**: ✅ COMPLETE AND READY -**Quality Level**: Production-Ready -**Test Coverage**: 15+ comprehensive tests -**Documentation**: 1,800+ lines across 6 guides -**Code**: 1,145 lines of F# - -Everything is complete, tested, documented, and ready for production use. - -👉 **Next Step**: Read `00-START-HERE.md` or `INDEX.md` - ---- - -**Created with attention to detail for production quality and ease of use.** diff --git a/docs/DEV-REPORTS/archive/README.md b/docs/DEV-REPORTS/archive/README.md deleted file mode 100644 index 0cd894a..0000000 --- a/docs/DEV-REPORTS/archive/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# DEV Reports Archive - -This folder contains historical DEV reports kept for traceability. - -## What Is Archived - -- One-off correction notes -- Verification logs -- Large implementation snapshots -- Transitional documents no longer needed for day-to-day work - -## Active Docs - -Use the top-level files in `docs/DEV-REPORTS/` for current guidance: - -- `00-START-HERE.md` -- `INDEX.md` -- `QUICK_REFERENCE.md` -- `SCHEMA_BASED_PROVIDERS.md` -- `QUARTO_PROVIDER_IMPLEMENTATION.md` diff --git a/docs/DEV-REPORTS/archive/SCHEMA_MODE_CORRECTION.md b/docs/DEV-REPORTS/archive/SCHEMA_MODE_CORRECTION.md deleted file mode 100644 index b909873..0000000 --- a/docs/DEV-REPORTS/archive/SCHEMA_MODE_CORRECTION.md +++ /dev/null @@ -1,156 +0,0 @@ -# JSON Schema Mode Correction - -**Date**: January 20, 2026 -**Status**: ✅ Updated to use proper `Schema=` syntax - -## The Issue - -The initial implementation incorrectly used sample JSON files with type providers: - -```fsharp -// ❌ WRONG - This infers types from sample data -type QuartoProjectProvider = JsonProvider<"sample-project.json"> -``` - -While this technically works, it's not the proper way to leverage JSON schemas with FSharp.Data. - -## The Correction - -FSharp.Data's JsonProvider has **two distinct modes**: - -### 1. **Sample Mode** (Type Inference) -```fsharp -// Infers types from JSON sample -type Provider = JsonProvider<"sample.json"> -``` -- Types are inferred from actual JSON data -- Loose validation -- Good for exploration - -### 2. **Schema Mode** (Schema Validation) ✅ CORRECT -```fsharp -// Validates against JSON Schema specification -type Provider = JsonProvider -``` -- Types are defined by JSON Schema -- Strict validation against schema spec -- Better IDE support -- **This is what we should use** - -## What Was Updated - -### QuartoTypes.fs -```fsharp -// ✅ CORRECT - Uses official JSON Schema files -type QuartoProjectProvider = - JsonProvider - -type QuartoDocumentProvider = - JsonProvider -``` - -### Key Changes: -- Changed from sample mode to `Schema=` mode -- Type providers now directly reference official Quarto schemas -- Validation happens against JSON Schema specification -- More authoritative and strict validation - -### Files Updated: -✅ `QuartoInspect/QuartoTypes.fs` - Uses `Schema=` syntax -✅ `QuartoInspect/QuartoInspect.fsproj` - References schema files -✅ `getcomputo-pub-refactored.fsx` - Updated comments -✅ `QuartoInspect/README.md` - Explains schema mode -✅ `SCHEMA_BASED_PROVIDERS.md` - Full documentation of schema mode -✅ All other documentation updated with correct terminology - -## Why Schema Mode is Better - -| Aspect | Sample Mode | Schema Mode | -|--------|------------|------------| -| **Source of Truth** | JSON sample | JSON Schema spec | -| **Validation Level** | Loose | Strict | -| **Based On** | Specific example | Complete specification | -| **Type Constraints** | Example-dependent | Schema-defined | -| **IDE Support** | Good | Excellent | -| **Authority** | Arbitrary | Official spec | -| **Update Process** | Need new sample | Schema definition | - -## Type Provider Behavior - -### With Schema Mode: -```fsharp -let parsed = QuartoProjectProvider.Parse(jsonStr) - -// Type-safe access with schema validation -let version = parsed.Quarto.Version // String (from schema) -let dir = parsed.Dir // String (from schema) -let engines = parsed.Engines // string[] (from schema) - -// ✅ Schema validates the structure matches specification -// ✅ Compiler provides type-safe access -// ✅ IDE IntelliSense based on schema definition -``` - -## Sample Files (Still Maintained) - -We still maintain sample files for documentation purposes: -- `sample-project.json` - Example of valid project output -- `sample-document.json` - Example of valid document output - -However, **these are now documentation** rather than the source of type definitions. - -## Benefits Realized - -✅ **Direct Schema Compliance** - - Type providers validate against official specifications - - Not dependent on a sample being representative - -✅ **Authoritative Types** - - Types come from official JSON Schema - - Changes to schema automatically update types - -✅ **Better Error Messages** - - Schema violations clearly documented - - Type errors reference schema constraints - -✅ **Future-Proof** - - When Quarto updates schemas, just update files - - Type provider automatically uses new definitions - -## Reference - -**FSharp.Data JSON Schema Documentation:** -https://fsprojects.github.io/FSharp.Data/library/JsonSchema.html - -**JSON Schema Specification:** -https://json-schema.org/ - -## Code Locations - -All code now uses the correct `Schema=` syntax: - -``` -QuartoInspect/ -├── QuartoTypes.fs ................. JsonProvider -├── README.md ....................... Explains schema mode -└── QuartoInspect.fsproj ........... References schema files - -getcomputo-pub-refactored.fsx ....... Uses Schema= syntax (via QuartoTypes) - -Documentation/ -├── SCHEMA_BASED_PROVIDERS.md ....... Detailed schema mode explanation -├── QUARTO_PROVIDER_IMPLEMENTATION.md Updated to schema mode -└── QUICK_REFERENCE.md ............. Shows correct syntax -``` - -## Summary - -The implementation has been **corrected to use FSharp.Data's proper JSON Schema validation mode** with the `Schema=` syntax. This provides: - -- ✅ Direct validation against official Quarto schemas -- ✅ Stricter compile-time type safety -- ✅ Better alignment with JSON Schema specification -- ✅ More authoritative and maintainable code -- ✅ Excellent IDE IntelliSense support - -Thank you for catching this! The implementation is now using the correct, more robust approach. diff --git a/docs/DEV-REPORTS/archive/VISUAL_OVERVIEW.md b/docs/DEV-REPORTS/archive/VISUAL_OVERVIEW.md deleted file mode 100644 index 4655b8c..0000000 --- a/docs/DEV-REPORTS/archive/VISUAL_OVERVIEW.md +++ /dev/null @@ -1,326 +0,0 @@ -# Implementation Overview - Visual Guide - -## 🎯 What Was Built - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ QUARTO TYPE PROVIDERS & TESTS │ -│ Based on Official Schemas │ -└─────────────────────────────────────────────────────────────────┘ - - Official Schemas - ↓ - ┌────────────────────────────────────────┐ - │ src/quarto-inspect-project-json-schema.json│ - │ src/quarto-inspect-document-json-schema.json - └────────────────────────────────────────┘ - ↓ - Sample JSON Files - ↓ - ┌────────────────────────────────────────┐ - │ sample-project.json │ - │ sample-document.json │ - └────────────────────────────────────────┘ - ↓ - Type Providers (Compile-time) - ↓ - ┌────────────────────────────────────────┐ - │ QuartoProjectProvider │ - │ QuartoDocumentProvider │ - └────────────────────────────────────────┘ - ↓ - Type-Safe F# Code - ↓ - ┌────────────────────────────────────────┐ - │ Compile-Time Validation │ - │ Runtime Type Safety │ - │ Full IntelliSense Support │ - └────────────────────────────────────────┘ -``` - -## 📁 Project Structure - -``` -computorg.github.io/ -│ -├── 🏗️ QuartoInspect/ [Core Library] -│ ├── QuartoTypes.fs [Type Providers] -│ ├── QuartoClient.fs [Quarto Client API] -│ ├── sample-project.json [Project Schema Example] -│ ├── sample-document.json [Document Schema Example] -│ ├── QuartoInspect.fsproj [Project File] -│ └── README.md [Library Documentation] -│ -├── 🧪 QuartoInspect.Tests/ [Test Suite] -│ ├── QuartoInspectTests.fs [13+ Tests] -│ └── QuartoInspect.Tests.fsproj [Project File] -│ -├── 🔄 getcomputo-pub-refactored.fsx [Enhanced Main Script] -│ -├── 📚 Documentation: -│ ├── INDEX.md ← Navigation Hub -│ ├── QUICK_REFERENCE.md ← 1-Page Cheat Sheet -│ ├── SCHEMA_BASED_PROVIDERS.md ← Architecture -│ ├── QUARTO_PROVIDER_IMPLEMENTATION.md ← Full Details -│ └── IMPLEMENTATION_COMPLETE.md ← Summary -│ -└── 📋 Official Schemas: - ├── src/quarto-inspect-project-json-schema.json - └── src/quarto-inspect-document-json-schema.json -``` - -## 🔄 Data Flow - -``` -User JSON Input - ↓ -QuartoClient.runInspect() or File.ReadAllText() - ↓ -QuartoClient.validateProjectSchema() [Runtime Validation] - ↓ -QuartoTypes.parseProjectJson() [Type Provider Parsing] - ↓ -Result - ↓ -IF OK: QuartoProjectProvider with autocomplete - ├─ parsed.Quarto.Version - ├─ parsed.Dir - ├─ parsed.Engines - ├─ parsed.Files - ├─ parsed.FileInformation - └─ parsed.Extensions - ↓ -IF ERROR: Clear error message -``` - -## 🧪 Test Architecture - -``` -QuartoInspectTests -│ -├── 📡 GitHub API Availability Tests (4 tests) -│ ├─ API Reachability -│ ├─ Repository Retrieval -│ ├─ Repository Details -│ └─ Rate Limit Handling -│ -├── ⚙️ Quarto Installation Tests (1 test) -│ └─ Quarto Availability Check -│ -├── ✅ Schema Compliance Tests (6 tests) -│ ├─ Valid Document Schema -│ ├─ Invalid Document Detection -│ ├─ Valid Project Schema -│ ├─ Invalid Project Detection -│ ├─ Type Provider Document Parse -│ └─ Type Provider Project Parse -│ -├── 🔗 Mock Repository Integration Tests (2 tests) -│ ├─ Mock Repository Retrieval -│ └─ Repository Structure Validation -│ -└── 🚀 Quarto Inspect Execution Tests (2 tests) - ├─ Real Quarto Inspect Execution - └─ Non-Quarto Directory Handling -``` - -## 🎯 Type Provider Declaration - -```fsharp -// In QuartoTypes.fs: - -// Uses official schema conformance example -type QuartoProjectProvider = - JsonProvider<"sample-project.json"> - -// Uses official schema conformance example -type QuartoDocumentProvider = - JsonProvider<"sample-document.json"> - -// Usage with type safety: -let parsed = QuartoProjectProvider.Parse(jsonString) -let version = parsed.Quarto.Version // ✅ Type-safe! - // ✅ Autocomplete works! -``` - -## 🔄 Integration Paths - -``` -Option 1: Direct Replacement -┌─────────────────────────────────┐ -│ getcomputo-pub-refactored.fsx │ (drop-in replacement) -└────────┬────────────────────────┘ - ↓ - $ dotnet fsi getcomputo-pub-refactored.fsx - -Option 2: Library Integration -┌─────────────────────────────────┐ -│ Your Script/Application │ -└────────┬────────────────────────┘ - ↓ -┌─────────────────────────────────┐ -│ #r "QuartoInspect.dll" │ -│ open QuartoInspect.QuartoTypes │ -│ open QuartoInspect.QuartoClient │ -└────────┬────────────────────────┘ - ↓ - Use Type Providers & Client - -Option 3: Pattern Copying -┌─────────────────────────────────┐ -│ getcomputo-pub-refactored.fsx │ -│ (read examples & patterns) │ -└────────┬────────────────────────┘ - ↓ -┌─────────────────────────────────┐ -│ Integrate patterns into │ -│ your existing script │ -└────────┬────────────────────────┘ - ↓ - Enhanced error handling + types -``` - -## 📊 Type Provider Benefits Matrix - -``` - Manual Parsing Type Providers -──────────────────────────────────────────────────────── -Compile-time safety ❌ ✅ -IDE IntelliSense ⚠️ Partial ✅ Full -Error discovery ⏱️ Runtime ✅ Compile -Code refactoring risk ⚠️ High ✅ Low -Schema validation ❌ ✅ -Lines of code 😞 More ✅ Less -Development speed ⏱️ Slow ✅ Fast -Runtime performance ✅ ✅ Same -``` - -## 🚀 Quick Start Checklist - -``` -□ Read INDEX.md (2 min) -□ Read QUICK_REFERENCE.md (3 min) -□ Navigate to QuartoInspect.Tests (1 min) -□ Run: dotnet restore (2 min) -□ Run: dotnet build (1 min) -□ Run: dotnet run (1 min) -□ ✅ Tests pass/skip gracefully (should happen!) -□ Explore sample files (5 min) -□ Try type provider in IDE (5 min) -□ Read full docs if needed (as needed) -``` - -## 🔌 API Reference Quick Look - -```fsharp -// Parsing -QuartoTypes.parseProjectJson(jsonStr) : Result -QuartoTypes.parseDocumentJson(jsonStr) : Result - -// Validation -QuartoClient.validateProjectSchema(json): Result -QuartoClient.validateDocumentSchema(json): Result - -// Execution -QuartoClient.runInspect(path) : Async> -QuartoClient.checkQuartoAvailable() : Async> - -// Type Access (after parsing) -parsed.Quarto.Version : string -parsed.Dir : string -parsed.Engines : string[] -parsed.Files.Input : string[] -parsed.FileInformation : JsonProvider<...>[] -parsed.Extensions : JsonProvider<...>[] -``` - -## 🎯 Key Decision Points - -``` -Question: Should I use type providers? -Answer: YES - for production code needing type safety - -Question: Can I skip the tests? -Answer: YES - but they validate your setup - -Question: Must I install Quarto? -Answer: NO - only needed for integration tests - -Question: Is GitHub token required? -Answer: NO - tests skip without it, just get rate limited - -Question: Can I use the refactored script as-is? -Answer: YES - it's a drop-in replacement with improvements - -Question: How do I extend the schemas? -Answer: Update sample-*.json files, rebuild, done! -``` - -## 📈 Implementation Timeline - -``` -January 20, 2026: -│ -├─ 🏗️ Created QuartoInspect library -│ ├─ QuartoTypes.fs (type providers) -│ └─ QuartoClient.fs (client API) -│ -├─ 📝 Created sample JSON files -│ ├─ sample-project.json -│ └─ sample-document.json -│ -├─ 🧪 Created comprehensive tests (13+) -│ ├─ GitHub API tests -│ ├─ Schema compliance tests -│ └─ Integration tests -│ -├─ 🔄 Created refactored script -│ └─ getcomputo-pub-refactored.fsx -│ -└─ 📚 Created documentation - ├─ INDEX.md - ├─ QUICK_REFERENCE.md - ├─ SCHEMA_BASED_PROVIDERS.md - ├─ QUARTO_PROVIDER_IMPLEMENTATION.md - ├─ IMPLEMENTATION_COMPLETE.md - └─ QuartoInspect/README.md -``` - -## ✨ Success Criteria - All Met! ✅ - -``` -✅ Leverage FSharp.Data JSON type providers -✅ Use official Quarto schemas -✅ Provide schema-based type safety -✅ Create Expecto tests -✅ Test GitHub API availability -✅ Test Quarto inspect compliance -✅ Handle mock repository example -✅ Comprehensive documentation -✅ Production-ready code -✅ Graceful error handling -``` - -## 🎉 Ready to Use! - -``` - ╔════════════════════════════════════════╗ - ║ Implementation Complete & Verified ║ - ║ Tests Ready to Run ║ - ║ Documentation Complete ║ - ║ Ready for Production Use ║ - ╚════════════════════════════════════════╝ - - 👉 Start: cd QuartoInspect.Tests - 👉 Build: dotnet build - 👉 Test: dotnet run - 👉 Docs: INDEX.md -``` - ---- - -**Status**: ✅ Complete -**Date**: January 20, 2026 -**Quality**: Production-Ready -**Test Coverage**: 13+ Tests -**Documentation**: 5 Guides diff --git a/paket.dependencies b/paket.dependencies deleted file mode 100644 index a90d67a..0000000 --- a/paket.dependencies +++ /dev/null @@ -1,25 +0,0 @@ -source https://api.nuget.org/v3/index.json - -group Main - framework: net10.0 - source https://api.nuget.org/v3/index.json - nuget FSharp.Core == 10.1.202 - nuget DotNetEnv == 3.1.1 - nuget DrBiber == 0.1.0 - nuget FSharp.Data == 6.4.0 - nuget Octokit == 1.0.0 - nuget YamlDotNet == 16.3.0 - -group Test - framework: net10.0 - source https://api.nuget.org/v3/index.json - nuget Microsoft.NET.Test.Sdk == 18.4.0 - nuget YoloDev.Expecto.TestSdk == 0.15.6 - nuget expecto == 10.2.3 - -group Build - framework: net10.0 - source https://api.nuget.org/v3/index.json - nuget Fake.Core.Target == 6.1.4 - nuget Fake.DotNet.Cli == 6.1.4 - nuget Fake.IO.FileSystem == 6.1.4 diff --git a/paket.lock b/paket.lock deleted file mode 100644 index 2b8c1e1..0000000 --- a/paket.lock +++ /dev/null @@ -1,614 +0,0 @@ -RESTRICTION: == net10.0 -NUGET - remote: https://api.nuget.org/v3/index.json - DotNetEnv (3.1.1) - Microsoft.Extensions.Configuration (>= 1.1.2) - Microsoft.Extensions.Configuration.Abstractions (>= 1.1.2) - NETStandard.Library (>= 1.6.1) - Sprache (>= 2.3.1) - System.Net.Http (>= 4.3.4) - System.Text.RegularExpressions (>= 4.3.1) - DrBiber (0.1) - DynamicObj (>= 4.0.3) - Fable.Core (>= 4.3) - FSharp.Core (>= 8.0.400) - FSharpAux.Core (>= 2.0) - DynamicObj (7.1) - Fable.Core (>= 4.3) - FSharp.Core (>= 8.0.403) - Fable.Core (4.5) - FSharp.Core (10.1.202) - FSharp.Data (6.4) - FSharp.Core (>= 6.0.1) - FSharp.Data.Csv.Core (>= 6.4) - FSharp.Data.Html.Core (>= 6.4) - FSharp.Data.Http (>= 6.4) - FSharp.Data.Json.Core (>= 6.4) - FSharp.Data.Runtime.Utilities (>= 6.4) - FSharp.Data.WorldBank.Core (>= 6.4) - FSharp.Data.Xml.Core (>= 6.4) - FSharp.Data.Csv.Core (8.1.8) - FSharp.Core (>= 6.0.1) - FSharp.Data.Runtime.Utilities (>= 8.1.8) - FSharp.Data.Html.Core (8.1.8) - FSharp.Core (>= 6.0.1) - FSharp.Data.Csv.Core (>= 8.1.8) - FSharp.Data.Json.Core (>= 8.1.8) - FSharp.Data.Runtime.Utilities (>= 8.1.8) - FSharp.Data.Http (8.1.8) - FSharp.Core (>= 6.0.1) - FSharp.Data.Json.Core (8.1.8) - FSharp.Core (>= 6.0.1) - FSharp.Data.Http (>= 8.1.8) - FSharp.Data.Runtime.Utilities (>= 8.1.8) - FSharp.Data.Runtime.Utilities (8.1.8) - FSharp.Core (>= 6.0.1) - FSharp.Data.Http (>= 8.1.8) - FSharp.Data.WorldBank.Core (8.1.8) - FSharp.Core (>= 6.0.1) - FSharp.Data.Http (>= 8.1.8) - FSharp.Data.Json.Core (>= 8.1.8) - FSharp.Data.Runtime.Utilities (>= 8.1.8) - FSharp.Data.Xml.Core (8.1.8) - FSharp.Core (>= 6.0.1) - FSharp.Data.Http (>= 8.1.8) - FSharp.Data.Json.Core (>= 8.1.8) - FSharp.Data.Runtime.Utilities (>= 8.1.8) - FSharpAux.Core (2.1) - FSharp.Core (>= 8.0.100) - Microsoft.Extensions.Configuration (10.0.6) - Microsoft.Extensions.Configuration.Abstractions (>= 10.0.6) - Microsoft.Extensions.Primitives (>= 10.0.6) - Microsoft.Extensions.Configuration.Abstractions (10.0.6) - Microsoft.Extensions.Primitives (>= 10.0.6) - Microsoft.Extensions.Primitives (10.0.6) - Microsoft.NETCore.Platforms (7.0.4) - Microsoft.NETCore.Targets (5.0) - NETStandard.Library (2.0.3) - Microsoft.NETCore.Platforms (>= 1.1) - Octokit (1.0) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.native.System (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Net.Http (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - Sprache (2.3.1) - System.Globalization (>= 4.3) - System.Linq (>= 4.3) - System.Private.Uri (>= 4.3.2) - System.Runtime (>= 4.3) - System.Text.RegularExpressions (>= 4.3) - System.Collections (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Collections.Concurrent (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Diagnostics.Debug (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Diagnostics.DiagnosticSource (10.0.6) - System.Diagnostics.Tracing (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Formats.Asn1 (10.0.6) - System.Globalization (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Globalization.Calendars (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Runtime (>= 4.3) - System.Globalization.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.IO (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem.Primitives (4.3) - System.Runtime (>= 4.3) - System.Linq (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Net.Http (4.3.4) - Microsoft.NETCore.Platforms (>= 1.1.1) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Http (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.DiagnosticSource (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Extensions (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Security.Cryptography.X509Certificates (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Net.Primitives (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime (>= 4.3.1) - System.Runtime.Handles (>= 4.3) - System.Private.Uri (4.3.2) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Reflection (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Resources.ResourceManager (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime.Extensions (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime (>= 4.3.1) - System.Runtime.Handles (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Runtime.InteropServices (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.Numerics (4.3) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Security.Cryptography.Algorithms (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Numerics (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Security.Cryptography.Cng (5.0) - System.Formats.Asn1 (>= 5.0) - System.Security.Cryptography.Csp (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.IO (>= 4.3) - System.Reflection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Security.Cryptography.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3) - System.Collections (>= 4.3) - System.Collections.Concurrent (>= 4.3) - System.Linq (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (5.0) - System.Formats.Asn1 (>= 5.0) - System.Security.Cryptography.Primitives (4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Security.Cryptography.X509Certificates (4.3.2) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Http (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Calendars (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Numerics (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Cng (>= 4.3) - System.Security.Cryptography.Csp (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Text.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.RegularExpressions (4.3.1) - System.Runtime (>= 4.3.1) - System.Threading (4.3) - System.Runtime (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Tasks (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - YamlDotNet (16.3) - -GROUP Build -RESTRICTION: == net10.0 -NUGET - remote: https://api.nuget.org/v3/index.json - BlackFox.VsWhere (1.1) - FSharp.Core (>= 4.2.3) - Microsoft.Win32.Registry (>= 4.7) - Fake.Core.CommandLineParsing (6.1.4) - FParsec (>= 1.1.1) - FSharp.Core (>= 8.0.400) - Fake.Core.Context (6.1.4) - FSharp.Core (>= 8.0.400) - Fake.Core.Environment (6.1.4) - FSharp.Core (>= 8.0.400) - Fake.Core.FakeVar (6.1.4) - Fake.Core.Context (>= 6.1.4) - FSharp.Core (>= 8.0.400) - Fake.Core.Process (6.1.4) - Fake.Core.Environment (>= 6.1.4) - Fake.Core.FakeVar (>= 6.1.4) - Fake.Core.String (>= 6.1.4) - Fake.Core.Trace (>= 6.1.4) - Fake.IO.FileSystem (>= 6.1.4) - FSharp.Core (>= 8.0.400) - System.Collections.Immutable (>= 8.0) - Fake.Core.SemVer (6.1.4) - FSharp.Core (>= 8.0.400) - Fake.Core.String (6.1.4) - FSharp.Core (>= 8.0.400) - Fake.Core.Target (6.1.4) - Fake.Core.CommandLineParsing (>= 6.1.4) - Fake.Core.Context (>= 6.1.4) - Fake.Core.Environment (>= 6.1.4) - Fake.Core.FakeVar (>= 6.1.4) - Fake.Core.Process (>= 6.1.4) - Fake.Core.String (>= 6.1.4) - Fake.Core.Trace (>= 6.1.4) - FSharp.Control.Reactive (>= 5.0.2) - FSharp.Core (>= 8.0.400) - Fake.Core.Tasks (6.1.4) - Fake.Core.Trace (>= 6.1.4) - FSharp.Core (>= 8.0.400) - Fake.Core.Trace (6.1.4) - Fake.Core.Environment (>= 6.1.4) - Fake.Core.FakeVar (>= 6.1.4) - FSharp.Core (>= 8.0.400) - Fake.Core.Xml (6.1.4) - Fake.Core.String (>= 6.1.4) - FSharp.Core (>= 8.0.400) - Fake.DotNet.Cli (6.1.4) - Fake.Core.Environment (>= 6.1.4) - Fake.Core.Process (>= 6.1.4) - Fake.Core.String (>= 6.1.4) - Fake.Core.Trace (>= 6.1.4) - Fake.DotNet.MSBuild (>= 6.1.4) - Fake.DotNet.NuGet (>= 6.1.4) - Fake.IO.FileSystem (>= 6.1.4) - FSharp.Core (>= 8.0.400) - Mono.Posix.NETStandard (>= 1.0) - Fake.DotNet.MSBuild (6.1.4) - BlackFox.VsWhere (>= 1.1) - Fake.Core.Environment (>= 6.1.4) - Fake.Core.Process (>= 6.1.4) - Fake.Core.String (>= 6.1.4) - Fake.Core.Trace (>= 6.1.4) - Fake.IO.FileSystem (>= 6.1.4) - FSharp.Core (>= 8.0.400) - MSBuild.StructuredLogger (>= 2.1.815) - Fake.DotNet.NuGet (6.1.4) - Fake.Core.Environment (>= 6.1.4) - Fake.Core.Process (>= 6.1.4) - Fake.Core.SemVer (>= 6.1.4) - Fake.Core.String (>= 6.1.4) - Fake.Core.Tasks (>= 6.1.4) - Fake.Core.Trace (>= 6.1.4) - Fake.Core.Xml (>= 6.1.4) - Fake.IO.FileSystem (>= 6.1.4) - Fake.Net.Http (>= 6.1.4) - FSharp.Core (>= 8.0.400) - Newtonsoft.Json (>= 13.0.3) - NuGet.Protocol (>= 6.12.4) - Fake.IO.FileSystem (6.1.4) - Fake.Core.String (>= 6.1.4) - Fake.Core.Trace (>= 6.1.4) - FSharp.Core (>= 8.0.400) - Fake.Net.Http (6.1.4) - Fake.Core.Trace (>= 6.1.4) - FSharp.Core (>= 8.0.400) - FParsec (1.1.1) - FSharp.Core (>= 4.3.4) - FSharp.Control.Reactive (6.1.2) - FSharp.Core (>= 6.0.7) - System.Reactive (>= 6.0.1) - FSharp.Core (10.1.202) - Microsoft.Build.Framework (18.4) - Microsoft.Build.Utilities.Core (18.4) - Microsoft.Build.Framework (>= 18.4) - Microsoft.NET.StringTools (>= 18.4) - System.Configuration.ConfigurationManager (>= 10.0.1) - System.Diagnostics.EventLog (>= 10.0.1) - System.Security.Cryptography.ProtectedData (>= 10.0.1) - Microsoft.NET.StringTools (18.4) - Microsoft.Win32.Registry (5.0) - System.Security.AccessControl (>= 5.0) - System.Security.Principal.Windows (>= 5.0) - Mono.Posix.NETStandard (1.0) - MSBuild.StructuredLogger (2.3.154) - Microsoft.Build.Framework (>= 17.5) - Microsoft.Build.Utilities.Core (>= 17.5) - Newtonsoft.Json (13.0.4) - NuGet.Common (7.3.1) - NuGet.Frameworks (>= 7.3.1) - NuGet.Configuration (7.3.1) - NuGet.Common (>= 7.3.1) - System.Security.Cryptography.ProtectedData (>= 8.0) - NuGet.Frameworks (7.3.1) - NuGet.Packaging (7.3.1) - Newtonsoft.Json (>= 13.0.3) - NuGet.Configuration (>= 7.3.1) - NuGet.Versioning (>= 7.3.1) - System.Security.Cryptography.Pkcs (>= 8.0.1) - NuGet.Protocol (7.3.1) - NuGet.Packaging (>= 7.3.1) - NuGet.Versioning (7.3.1) - System.Collections.Immutable (10.0.6) - System.Configuration.ConfigurationManager (10.0.6) - System.Diagnostics.EventLog (>= 10.0.6) - System.Security.Cryptography.ProtectedData (>= 10.0.6) - System.Diagnostics.EventLog (10.0.6) - System.Reactive (6.1) - System.Security.AccessControl (6.0.1) - System.Security.Cryptography.Pkcs (10.0.6) - System.Security.Cryptography.ProtectedData (10.0.6) - System.Security.Principal.Windows (5.0) - -GROUP Test -RESTRICTION: == net10.0 -NUGET - remote: https://api.nuget.org/v3/index.json - Azure.Core (1.53) - Microsoft.Bcl.AsyncInterfaces (>= 10.0.3) - Microsoft.Extensions.Configuration.Abstractions (>= 10.0.3) - Microsoft.Extensions.Hosting.Abstractions (>= 10.0.3) - Microsoft.Identity.Client (>= 4.83.1) - Microsoft.Identity.Client.Extensions.Msal (>= 4.83.1) - System.ClientModel (>= 1.10) - System.Memory.Data (>= 10.0.3) - Azure.Monitor.OpenTelemetry.Exporter (1.7) - Azure.Core (>= 1.52) - OpenTelemetry.Extensions.Hosting (>= 1.15.1) - OpenTelemetry.PersistentStorage.FileSystem (>= 1.0.2) - Expecto (10.2.3) - FSharp.Core (>= 7.0.200) - Mono.Cecil (>= 0.11.4 < 1.0) - FSharp.Core (10.1.202) - Microsoft.ApplicationInsights (3.1) - Azure.Monitor.OpenTelemetry.Exporter (>= 1.7) - Microsoft.Bcl.AsyncInterfaces (10.0.6) - Microsoft.CodeCoverage (18.4) - Microsoft.Extensions.Configuration (10.0.6) - Microsoft.Extensions.Configuration.Abstractions (>= 10.0.6) - Microsoft.Extensions.Primitives (>= 10.0.6) - Microsoft.Extensions.Configuration.Abstractions (10.0.6) - Microsoft.Extensions.Primitives (>= 10.0.6) - Microsoft.Extensions.Configuration.Binder (10.0.6) - Microsoft.Extensions.Configuration (>= 10.0.6) - Microsoft.Extensions.Configuration.Abstractions (>= 10.0.6) - Microsoft.Extensions.DependencyInjection (10.0.6) - Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.6) - Microsoft.Extensions.DependencyInjection.Abstractions (10.0.6) - Microsoft.Extensions.Diagnostics.Abstractions (10.0.6) - Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.6) - Microsoft.Extensions.Options (>= 10.0.6) - Microsoft.Extensions.FileProviders.Abstractions (10.0.6) - Microsoft.Extensions.Primitives (>= 10.0.6) - Microsoft.Extensions.Hosting.Abstractions (10.0.6) - Microsoft.Extensions.Configuration.Abstractions (>= 10.0.6) - Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.6) - Microsoft.Extensions.Diagnostics.Abstractions (>= 10.0.6) - Microsoft.Extensions.FileProviders.Abstractions (>= 10.0.6) - Microsoft.Extensions.Logging.Abstractions (>= 10.0.6) - Microsoft.Extensions.Logging (10.0.6) - Microsoft.Extensions.DependencyInjection (>= 10.0.6) - Microsoft.Extensions.Logging.Abstractions (>= 10.0.6) - Microsoft.Extensions.Options (>= 10.0.6) - Microsoft.Extensions.Logging.Abstractions (10.0.6) - Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.6) - Microsoft.Extensions.Logging.Configuration (10.0.6) - Microsoft.Extensions.Configuration (>= 10.0.6) - Microsoft.Extensions.Configuration.Abstractions (>= 10.0.6) - Microsoft.Extensions.Configuration.Binder (>= 10.0.6) - Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.6) - Microsoft.Extensions.Logging (>= 10.0.6) - Microsoft.Extensions.Logging.Abstractions (>= 10.0.6) - Microsoft.Extensions.Options (>= 10.0.6) - Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.6) - Microsoft.Extensions.Options (10.0.6) - Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.6) - Microsoft.Extensions.Primitives (>= 10.0.6) - Microsoft.Extensions.Options.ConfigurationExtensions (10.0.6) - Microsoft.Extensions.Configuration.Abstractions (>= 10.0.6) - Microsoft.Extensions.Configuration.Binder (>= 10.0.6) - Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.6) - Microsoft.Extensions.Options (>= 10.0.6) - Microsoft.Extensions.Primitives (>= 10.0.6) - Microsoft.Extensions.Primitives (10.0.6) - Microsoft.Identity.Client (4.83.3) - Microsoft.IdentityModel.Abstractions (>= 8.14) - System.Diagnostics.DiagnosticSource (>= 6.0.1) - System.ValueTuple (>= 4.5) - Microsoft.Identity.Client.Extensions.Msal (4.83.3) - Microsoft.Identity.Client (>= 4.83.3) - System.Security.Cryptography.ProtectedData (>= 4.5) - Microsoft.IdentityModel.Abstractions (8.17) - Microsoft.NET.Test.Sdk (18.4) - Microsoft.CodeCoverage (>= 18.4) - Microsoft.TestPlatform.TestHost (>= 18.4) - Microsoft.Testing.Extensions.Telemetry (2.2.1) - Microsoft.ApplicationInsights (>= 2.23) - Microsoft.Testing.Platform (>= 2.2.1) - Microsoft.Testing.Extensions.TrxReport.Abstractions (2.2.1) - Microsoft.Testing.Platform (>= 2.2.1) - Microsoft.Testing.Extensions.VSTestBridge (2.2.1) - Microsoft.Testing.Extensions.Telemetry (>= 2.2.1) - Microsoft.Testing.Extensions.TrxReport.Abstractions (>= 2.2.1) - Microsoft.Testing.Platform (>= 2.2.1) - Microsoft.TestPlatform.ObjectModel (>= 18.3) - Microsoft.Testing.Platform (2.2.1) - Microsoft.Testing.Platform.MSBuild (2.2.1) - Microsoft.Testing.Platform (>= 2.2.1) - Microsoft.TestPlatform.ObjectModel (18.4) - System.Reflection.Metadata (>= 8.0) - Microsoft.TestPlatform.TestHost (18.4) - Microsoft.TestPlatform.ObjectModel (>= 18.4) - Newtonsoft.Json (>= 13.0.3) - Mono.Cecil (0.11.6) - Newtonsoft.Json (13.0.4) - OpenTelemetry (1.15.2) - Microsoft.Extensions.Diagnostics.Abstractions (>= 10.0) - Microsoft.Extensions.Logging.Configuration (>= 10.0) - OpenTelemetry.Api.ProviderBuilderExtensions (>= 1.15.2) - OpenTelemetry.Api (1.15.2) - OpenTelemetry.Api.ProviderBuilderExtensions (1.15.2) - Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0) - OpenTelemetry.Api (>= 1.15.2) - OpenTelemetry.Extensions.Hosting (1.15.2) - Microsoft.Extensions.Hosting.Abstractions (>= 10.0) - OpenTelemetry (>= 1.15.2) - OpenTelemetry.PersistentStorage.Abstractions (1.0.2) - OpenTelemetry.PersistentStorage.FileSystem (1.0.2) - OpenTelemetry.PersistentStorage.Abstractions (>= 1.0.2) - System.ClientModel (1.10) - Microsoft.Extensions.Configuration.Abstractions (>= 10.0.3) - Microsoft.Extensions.Hosting.Abstractions (>= 10.0.3) - Microsoft.Extensions.Logging.Abstractions (>= 10.0.3) - System.Memory.Data (>= 10.0.3) - System.Diagnostics.DiagnosticSource (10.0.6) - System.Memory.Data (10.0.6) - System.Reflection.Metadata (10.0.6) - System.Security.Cryptography.ProtectedData (10.0.6) - System.ValueTuple (4.6.2) - YoloDev.Expecto.TestSdk (0.15.6) - Expecto (>= 10.2.2 < 11.0) - FSharp.Core (>= 7.0.200) - Microsoft.Testing.Extensions.VSTestBridge (>= 1.9.1) - Microsoft.Testing.Platform.MSBuild (>= 1.9.1) diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 21db17a..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,9 +0,0 @@ -[project] -name = "computorg-github-io" -version = "0.1.0" -description = "Add your description here" -readme = "README.md" -requires-python = ">=3.13" -dependencies = [ - "pyyaml>=6.0.2", -] diff --git a/site/mock-papers.yml b/site/mock-papers.yml index bba48cf..cdd8ad3 100644 --- a/site/mock-papers.yml +++ b/site/mock-papers.yml @@ -1,6 +1,6 @@ - title: Visualizing Data using t-SNE (mock contribution) name: published-paper-tsne - authors: '' + authors: Laurens van der Maaten and Geoffrey Hinton journal: Computo doi: '' year: 2008 @@ -64,10 +64,10 @@ pdf: '' url: http://computo-journal.org/published-paper-tsne/ - draft: false + status: published - title: Visualizing Data using t-SNE (mock contribution) name: published-paper-tsne-R - authors: '' + authors: Laurens van der Maaten and Geoffrey Hinton journal: Computo doi: '' year: 2008 @@ -131,4 +131,4 @@ pdf: '' url: http://computo-journal.org/published-paper-tsne-R/ - draft: false + status: published diff --git a/site/published.xml b/site/published.xml deleted file mode 100644 index 9114eca..0000000 --- a/site/published.xml +++ /dev/null @@ -1,223 +0,0 @@ - - - - Computo Journal - Recent Articles - https://computo-journal.org/ - Latest published articles from Computo Journal - - Should we correct the bias in Confidence Bands for Repeated Functional Data? - https://computo-journal.org/published-202606-devijver-scb/ - https://computo-journal.org/published-202606-devijver-scb/ - Mon, 20 Jul 2026 00:00:00 GMT - While confidence intervals for finite quantities are - well-established, constructing confidence bands for objects of - infinite dimension, such as functions, is challenging. In this - paper, we explore the concept of parametric confidence bands for - functional data with an orthonormal basis. Specifically, we revisit - the method proposed by Sun and Loader, which yields confidence bands - for the projection of the regression function in a fixed-dimensional - space. This approach can introduce bias into the confidence bands - when the dimension of the basis is misspecified. Building on this - insight, we introduce a corrected, unbiased confidence band. - Surprisingly, our corrected band tends to be wider than that - suggested by a naive approach. To address this, we propose a model - selection criterion that allows for data-driven estimation of the - basis dimension. The bias is then automatically corrected after - dimension selection. We illustrate these strategies through an - extensive simulation study. We conclude with an application to real - data. - - - Variational inference for approximate objective priors using neural networks - https://computo-journal.org/published-202512-baillie-varp/ - https://computo-journal.org/published-202512-baillie-varp/ - Mon, 01 Dec 2025 00:00:00 GMT - In Bayesian statistics, the choice of the prior can have - an important influence on the posterior and the parameter - estimation, especially when few data samples are available. To limit - the added subjectivity from a priori information, one can use the - framework of objective priors, more particularly, we focus on - reference priors in this work. However, computing such priors is a - difficult task in general. Hence, we consider cases where the - reference prior simplifies to the Jeffreys prior. We develop in this - paper a flexible algorithm based on variational inference which - computes approximations of priors from a set of parametric - distributions using neural networks. We also show that our algorithm - can retrieve modified Jeffreys priors when constraints are specified - in the optimization problem to ensure the solution is proper. We - propose a simple method to recover a relevant approximation of the - parametric posterior distribution using Markov Chain Monte Carlo - (MCMC) methods even if the density function of the parametric prior - is not known in general. Numerical experiments on several - statistical models of increasing complexity are presented. We show - the usefulness of this approach by recovering the target - distribution. The performance of the algorithm is evaluated on both - prior and posterior distributions, jointly using variational - inference and MCMC sampling. - - - `regMMD`: an `R` package for parametric estimation and regression with maximum mean discrepancy - https://computo-journal.org/published-202511-alquier-regmmd/ - https://computo-journal.org/published-202511-alquier-regmmd/ - Tue, 18 Nov 2025 00:00:00 GMT - The Maximum Mean Discrepancy (MMD) is a kernel-based - metric widely used for nonparametric tests and estimation. Recently, - it has also been studied as an objective function for parametric - estimation, as it has been shown to yield robust estimators. We have - implemented MMD minimization for parameter inference in a wide range - of statistical models, including various regression models, within - an `R` package called `regMMD`. This paper provides an introduction - to the `regMMD` package. We describe the available kernels and - optimization procedures, as well as the default settings. Detailed - applications to simulated and real data are provided. - - - Fast confidence bounds for the false discovery proportion over a path of hypotheses - https://computo-journal.org/published-202510-durand-fast/ - https://computo-journal.org/published-202510-durand-fast/ - Thu, 09 Oct 2025 00:00:00 GMT - This paper presents a new algorithm (and an additional - trick) that allows to compute fastly an entire curve of post hoc - bounds for the False Discovery Proportion when the underlying bound - \$V\_\{\textbackslash mathfrak\{R\}\}\^{}\{\textbackslash ast\}\$ - construction is based on a reference family \$\textbackslash - mathfrak\{R\}\$ with a forest structure à la @MR4178188. By an - entire curve, we mean the values \$V\_\{\textbackslash - mathfrak\{R\}\}\^{}\{\textbackslash ast\}(S\_1),\textbackslash - dotsc,V\_\{\textbackslash mathfrak\{R\}\}\^{}\{\textbackslash - ast\}(S\_m)\$ computed on a path of increasing selection sets - \$S\_1\textbackslash subsetneq\textbackslash dotsb\textbackslash - subsetneq S\_m\$, \$\textbar S\_t\textbar=t\$. The new algorithm - leverages the fact that going from \$S\_t\$ to \$S\_\{t+1\}\$ is - done by adding only one hypothesis. Compared to a more naive - approach, the new algorithm has a complexity in - \$O(\textbar\textbackslash mathcal K\textbar m)\$ instead of - \$O(\textbar\textbackslash mathcal K\textbar m\^{}2)\$, where - \$\textbar\textbackslash mathcal K\textbar\$ is the cardinality of - the family. - - - Draw Me a Simulator - https://computo-journal.org/published-202509-boulet-simulator/ - https://computo-journal.org/published-202509-boulet-simulator/ - Mon, 08 Sep 2025 00:00:00 GMT - This study investigates the use of Variational - Auto-Encoders to build a simulator that approximates the law of - genuine observations. Using both simulated and real data in - scenarios involving counterfactuality, we discuss the general task - of evaluating a simulator’s quality, with a focus on comparisons of - statistical properties and predictive performance. While the - simulator built from simulated data shows minor discrepancies, the - results with real data reveal more substantial challenges. Beyond - the technical analysis, we reflect on the broader implications of - simulator design, and consider its role in modeling reality. - - - Model-Based Clustering and Variable Selection for Multivariate Count Data - https://computo-journal.org/published-202507-jacques-count-data/ - https://computo-journal.org/published-202507-jacques-count-data/ - Tue, 01 Jul 2025 00:00:00 GMT - Model-based clustering provides a principled way of - developing clustering methods. We develop a new model-based - clustering methods for count data. The method combines clustering - and variable selection for improved clustering. The method is based - on conditionally independent Poisson mixture models and Poisson - generalized linear models. The method is demonstrated on simulated - data and data from an ultra running race, where the method yields - excellent clustering and variable selection performance. - - - Reservoir Computing in R: a Tutorial for Using reservoirnet to Predict Complex Time-Series - http://computo-journal.org/published-202505-ferte-reservoirnet/ - http://computo-journal.org/published-202505-ferte-reservoirnet/ - Fri, 27 Jun 2025 00:00:00 GMT - Reservoir Computing (RC) is a machine learning method - based on neural networks that efficiently process information - generated by dynamical systems. It has been successful in solving - various tasks including time series forecasting, language processing - or voice processing. RC is implemented in `Python` and `Julia` but - not in `R`. This article introduces `reservoirnet`, an `R` package - providing access to the `Python` API `ReservoirPy`, allowing `R` - users to harness the power of reservoir computing. This article - provides an introduction to the fundamentals of RC and showcases its - real-world applicability through three distinct sections. First, we - cover the foundational concepts of RC, setting the stage for - understanding its capabilities. Next, we delve into the practical - usage of `reservoirnet` through two illustrative examples. These - examples demonstrate how it can be applied to real-world problems, - specifically, regression of COVID-19 hospitalizations and - classification of Japanese vowels. Finally, we present a - comprehensive analysis of a real-world application of - `reservoirnet`, where it was used to forecast COVID-19 - hospitalizations at Bordeaux University Hospital using public data - and electronic health records. - - - Efficient simulation of individual-based population models - http://computo-journal.org/published-202412-giorgi-efficient/ - http://computo-journal.org/published-202412-giorgi-efficient/ - Mon, 27 Jan 2025 00:00:00 GMT - The `R` Package `IBMPopSim` facilitates the simulation of - the random evolution of heterogeneous populations using stochastic - Individual-Based Models (IBMs). The package enables users to - simulate population evolution, in which individuals are - characterized by their age and some characteristics, and the - population is modified by different types of events, including - births/arrivals, death/exit events, or changes of characteristics. - The frequency at which an event can occur to an individual can - depend on their age and characteristics, but also on the - characteristics of other individuals (interactions). Such models - have a wide range of applications in fields including actuarial - science, biology, ecology or epidemiology. `IBMPopSim` overcomes the - limitations of time-consuming IBMs simulations by implementing new - efficient algorithms based on thinning methods, which are compiled - using the `Rcpp` package while providing a user-friendly interface. - - - Spectral Bridges - http://computo-journal.org/published-202412-ambroise-spectral/ - http://computo-journal.org/published-202412-ambroise-spectral/ - Fri, 13 Dec 2024 00:00:00 GMT - In this paper, Spectral Bridges, a novel clustering - algorithm, is introduced. This algorithm builds upon the traditional - k-means and spectral clustering frameworks by subdividing data into - small Voronoï regions, which are subsequently merged according to a - connectivity measure. Drawing inspiration from Support Vector - Machine’s margin concept, a non-parametric clustering approach is - proposed, building an affinity margin between each pair of Voronoï - regions. This approach delineates intricate, non-convex cluster - structures and is robust to hyperparameter choice. The numerical - experiments underscore Spectral Bridges as a fast, robust, and - versatile tool for clustering tasks spanning diverse domains. Its - efficacy extends to large-scale scenarios encompassing both - real-world and synthetic datasets. The Spectral Bridge algorithm is - implemented both in Python (\textless - https://pypi.org/project/spectral-bridges\textgreater) and R - \textless - https://github.com/cambroise/spectral-bridges-Rpackage\textgreater). - - - AdaptiveConformal: An `R` Package for Adaptive Conformal Inference - http://computo-journal.org/published-202407-susmann-adaptive-conformal/ - http://computo-journal.org/published-202407-susmann-adaptive-conformal/ - Thu, 18 Jul 2024 00:00:00 GMT - Conformal Inference (CI) is a popular approach for - generating finite sample prediction intervals based on the output of - any point prediction method when data are exchangeable. Adaptive - Conformal Inference (ACI) algorithms extend CI to the case of - sequentially observed data, such as time series, and exhibit strong - theoretical guarantees without having to assume exchangeability of - the observed data. The common thread that unites algorithms in the - ACI family is that they adaptively adjust the width of the generated - prediction intervals in response to the observed data. We provide a - detailed description of five ACI algorithms and their theoretical - guarantees, and test their performance in simulation studies. We - then present a case study of producing prediction intervals for - influenza incidence in the United States based on black-box point - forecasts. Implementations of all the algorithms are released as an - open-source `R` package, `AdaptiveConformal`, which also includes - tools for visualizing and summarizing conformal prediction - intervals. - - - diff --git a/site/published.yml b/site/published.yml index b4bf484..c8e191f 100644 --- a/site/published.yml +++ b/site/published.yml @@ -1,6 +1,6 @@ - title: Should we correct the bias in Confidence Bands for Repeated Functional Data? name: published-202606-devijver-scb - authors: '' + authors: Emilie Devijver and Adeline Samson journal: Computo doi: '' year: 2026 @@ -58,10 +58,10 @@ pdf: '' url: https://computo-journal.org/published-202606-devijver-scb/ - draft: false + status: published - title: Variational inference for approximate objective priors using neural networks name: published-202512-baillie-varp - authors: '' + authors: Nils Baillie, Antoine Van Biesbroeck and Clément Gauchy journal: Computo doi: '' year: 2025 @@ -130,10 +130,10 @@ pdf: '' url: https://computo-journal.org/published-202512-baillie-varp/ - draft: false + status: published - title: '`regMMD`: an `R` package for parametric estimation and regression with maximum mean discrepancy' name: published-202511-alquier-regmmd - authors: '' + authors: Pierre Alquier and Mathieu Gerber journal: Computo doi: '' year: 2025 @@ -177,10 +177,10 @@ pdf: '' url: https://computo-journal.org/published-202511-alquier-regmmd/ - draft: false + status: published - title: Fast confidence bounds for the false discovery proportion over a path of hypotheses name: published-202510-durand-fast - authors: '' + authors: Guillermo Durand journal: Computo doi: '' year: 2025 @@ -242,10 +242,10 @@ pdf: '' url: https://computo-journal.org/published-202510-durand-fast/ - draft: false + status: published - title: Draw Me a Simulator name: published-202509-boulet-simulator - authors: '' + authors: Sandrine Boulet and Antoine Chambaz journal: Computo doi: '' year: 2025 @@ -288,10 +288,10 @@ pdf: '' url: https://computo-journal.org/published-202509-boulet-simulator/ - draft: false + status: published - title: Model-Based Clustering and Variable Selection for Multivariate Count Data name: published-202507-jacques-count-data - authors: '' + authors: Julien Jacques and Thomas Brendan Murphy journal: Computo doi: '' year: 2025 @@ -331,10 +331,10 @@ pdf: '' url: https://computo-journal.org/published-202507-jacques-count-data/ - draft: false + status: published - title: 'Reservoir Computing in R: a Tutorial for Using reservoirnet to Predict Complex Time-Series' name: published-202505-ferte-reservoirnet - authors: '' + authors: Thomas Ferté, Kalidou Ba, Dan Dutartre, Pierrick Legrand, Vianney Jouhet, Rodolphe Thiébaut, Xavier Hinaut and Boris P Hejblum journal: Computo doi: '' year: 2025 @@ -400,10 +400,10 @@ pdf: '' url: http://computo-journal.org/published-202505-ferte-reservoirnet/ - draft: false + status: published - title: Efficient simulation of individual-based population models name: published-202412-giorgi-efficient - authors: '' + authors: Daphné Giorgi, Sarah Kaakai and Vincent Lemaire journal: Computo doi: '' year: 2025 @@ -456,10 +456,10 @@ pdf: '' url: http://computo-journal.org/published-202412-giorgi-efficient/ - draft: false + status: published - title: Spectral Bridges name: published-202412-ambroise-spectral - authors: '' + authors: Félix Laplante and Christophe Ambroise journal: Computo doi: '' year: 2024 @@ -516,10 +516,10 @@ pdf: '' url: http://computo-journal.org/published-202412-ambroise-spectral/ - draft: false + status: published - title: 'AdaptiveConformal: An `R` Package for Adaptive Conformal Inference' name: published-202407-susmann-adaptive-conformal - authors: '' + authors: Herbert Susmann, Antoine Chambaz and Julie Josse journal: Computo doi: '' year: 2024 @@ -577,10 +577,10 @@ pdf: '' url: http://computo-journal.org/published-202407-susmann-adaptive-conformal/ - draft: false + status: published - title: Bayesian spatiotemporal modelling of wildfire occurrences and sizes for projections under climate change name: published-202407-legrand-wildfires - authors: '' + authors: Juliette Legrand, François Pimont, Jean-Luc Dupuy and Thomas Opitz journal: Computo doi: '' year: 2024 @@ -664,10 +664,10 @@ pdf: '' url: http://computo-journal.org/published-202407-legrand-wildfires/ - draft: false + status: published - title: Geometric-Based Pruning Rules for Change Point Detection in Multiple Independent Time Series name: published-202406-pishchagina-change-point - authors: '' + authors: Liudmila Pishchagina, Guillem Rigaill and Vincent Runge journal: Computo doi: '' year: 2024 @@ -732,10 +732,10 @@ pdf: '' url: http://computo-journal.org/published-202406-pishchagina-change-point/ - draft: false + status: published - title: 'Peerannot: classification for crowdsourced image datasets with Python' name: published-202402-lefort-peerannot - authors: '' + authors: Tanguy Lefort, Benjamin Charlier, Alexis Joly and Joseph Salmon journal: Computo doi: '' year: 2024 @@ -780,10 +780,10 @@ pdf: '' url: http://computo-journal.org/published-202402-lefort-peerannot/ - draft: false + status: published - title: Optimal projection for parametric importance sampling in high dimensions name: published-202402-elmasri-optimal - authors: '' + authors: Maxime El Masri, Jérôme Morio and Florian Simatos journal: Computo doi: '' year: 2024 @@ -838,10 +838,10 @@ pdf: '' url: http://computo-journal.org/published-202402-elmasri-optimal/ - draft: false + status: published - title: Point Process Discrimination According to Repulsion name: published-202401-adrat-repulsion - authors: '' + authors: Hamza Adrat and Laurent Decreusefond journal: Computo doi: '' year: 2024 @@ -878,10 +878,10 @@ pdf: '' url: https://computo-journal.org/published-202401-adrat-repulsion/ - draft: false + status: published - title: A hierarchical model to evaluate pest treatments from prevalence and intensity data name: published-202312-favrot-hierarchical - authors: '' + authors: Armand Favrot and David Makowski journal: Computo doi: '' year: 2024 @@ -989,10 +989,10 @@ pdf: '' url: https://computo-journal.org/published-202312-favrot-hierarchical/ - draft: false + status: published - title: 'Local tree methods for classification: a review and some dead ends' name: published-202312-cleynen-local - authors: '' + authors: Alice Cleynen, Louis Raynal and Jean-Michel Marin journal: Computo doi: '' year: 2023 @@ -1062,10 +1062,10 @@ pdf: '' url: http://computo-journal.org/published-202312-cleynen-local/ - draft: false + status: published - title: Computing an empirical Fisher information matrix estimate in latent variable models through stochastic approximation name: published-202311-delattre-fim - authors: '' + authors: Maud Delattre and Estelle Kuhn journal: Computo doi: '' year: 2023 @@ -1129,10 +1129,10 @@ pdf: '' url: http://computo-journal.org/published-202311-delattre-fim/ - draft: false + status: published - title: Inference of Multiscale Gaussian Graphical Models name: published-202306-sanou-multiscale_glasso - authors: '' + authors: Edmond Sanou, Christophe Ambroise and Geneviève Robin journal: Computo doi: '' year: 2023 @@ -1199,10 +1199,10 @@ pdf: '' url: http://computo-journal.org/published-202306-sanou-multiscale_glasso/ - draft: false + status: published - title: 'Macrolitter video counting on riverbanks using state space models and moving cameras ' name: published-202301-chagneux-macrolitter - authors: '' + authors: Mathis Chagneux, Sylvain Le Corff, Pierre Gloaguen, Charles Ollion, Océane Lepâtre and Antoine Bruge journal: Computo doi: '' year: 2023 @@ -1265,10 +1265,10 @@ pdf: '' url: http://computo-journal.org/published-202301-chagneux-macrolitter/ - draft: false + status: published - title: 'A Python Package for Sampling from Copulae: clayton' name: published-202301-boulin-clayton - authors: '' + authors: Alexis Boulin journal: Computo doi: '' year: 2023 @@ -1316,10 +1316,10 @@ pdf: '' url: http://computo-journal.org/published-202301-boulin-clayton/ - draft: false + status: published - title: Trade-off between deep learning for species identification and inference about predator-prey co-occurrence name: published-202204-deeplearning-occupancy-lynx - authors: '' + authors: Olivier Gimenez, Maëlis Kervellec, Jean-Baptiste Fanjul, Anna Chaine, Lucile Marescot, Yoann Bollet and Christophe Duchamp journal: Computo doi: '' year: 2022 @@ -1396,4 +1396,4 @@ pdf: '' url: https://computo-journal.org/published-202204-deeplearning-occupancy-lynx/ - draft: false + status: published diff --git a/src/Build.fs b/src/Build.fs deleted file mode 100644 index 9638ade..0000000 --- a/src/Build.fs +++ /dev/null @@ -1,53 +0,0 @@ -open System.IO -open Fake.Core -open Fake.DotNet - -let repoRoot = Path.GetFullPath(Path.Combine(__SOURCE_DIRECTORY__, "..")) - -let buildOptions (options: DotNet.Options) = - { options with - WorkingDirectory = repoRoot } - -let fakeArgs = - System.Environment.GetCommandLineArgs() |> Array.skip 1 |> Array.toList - -Context.FakeExecutionContext.Create false "Build.fs" fakeArgs -|> Context.RuntimeContext.Fake -|> Context.setExecutionContext - -let ensureExitCode exitCode context = - if exitCode <> 0 then - failwithf "%s failed with exit code %d" context exitCode - -Target.create "UpdatePublications" (fun _ -> - let result = - DotNet.exec buildOptions "run" "--project src/PublicationUpdater.Cli/PublicationUpdater.Cli.fsproj -- ." - - ensureExitCode result.ExitCode "Publication updater") - -Target.create "Test" (fun _ -> - let publicationUpdaterTests = - DotNet.exec buildOptions "test" "src/PublicationUpdater.Tests/PublicationUpdater.Tests.fsproj" - - ensureExitCode publicationUpdaterTests.ExitCode "PublicationUpdater tests" - - let quartoInspectTests = - DotNet.exec buildOptions "test" "src/QuartoInspect.Tests/QuartoInspect.Tests.fsproj" - - ensureExitCode quartoInspectTests.ExitCode "QuartoInspect tests") - -Target.create "RenderSite" (fun _ -> - let result = - CreateProcess.fromRawCommand "quarto" [ "render" ] - |> CreateProcess.withWorkingDirectory repoRoot - |> Proc.run - - ensureExitCode result.ExitCode "quarto render") - -Target.create "Default" ignore - -open Fake.Core.TargetOperators - -"RenderSite" ==> "Default" |> ignore - -Target.runOrDefaultWithArguments "Default" diff --git a/src/Build.fsproj b/src/Build.fsproj deleted file mode 100644 index 0fe6924..0000000 --- a/src/Build.fsproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - Exe - net10.0 - false - - - - - - - - - \ No newline at end of file diff --git a/src/PublicationUpdater.Cli/Program.fs b/src/PublicationUpdater.Cli/Program.fs deleted file mode 100644 index c289e3c..0000000 --- a/src/PublicationUpdater.Cli/Program.fs +++ /dev/null @@ -1,13 +0,0 @@ -open System -open System.IO -open PublicationUpdater - -[] -let main argv = - let rootDir = - if argv.Length > 0 then - argv.[0] - else - Directory.GetCurrentDirectory() - - Generator.run rootDir diff --git a/src/PublicationUpdater.Cli/PublicationUpdater.Cli.fsproj b/src/PublicationUpdater.Cli/PublicationUpdater.Cli.fsproj deleted file mode 100644 index 2afabb6..0000000 --- a/src/PublicationUpdater.Cli/PublicationUpdater.Cli.fsproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - Exe - net10.0 - false - - - - - - - - - - - - \ No newline at end of file diff --git a/src/PublicationUpdater.Cli/paket.references b/src/PublicationUpdater.Cli/paket.references deleted file mode 100644 index 0317ba3..0000000 --- a/src/PublicationUpdater.Cli/paket.references +++ /dev/null @@ -1,2 +0,0 @@ -group Main -FSharp.Core \ No newline at end of file diff --git a/src/PublicationUpdater.Tests/PublicationUpdater.Tests.fsproj b/src/PublicationUpdater.Tests/PublicationUpdater.Tests.fsproj deleted file mode 100644 index 28f5f01..0000000 --- a/src/PublicationUpdater.Tests/PublicationUpdater.Tests.fsproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - net10.0 - true - false - - - - - - - - - - - - \ No newline at end of file diff --git a/src/PublicationUpdater.Tests/PublicationUpdaterTests.fs b/src/PublicationUpdater.Tests/PublicationUpdaterTests.fs deleted file mode 100644 index cb74f88..0000000 --- a/src/PublicationUpdater.Tests/PublicationUpdaterTests.fs +++ /dev/null @@ -1,191 +0,0 @@ -module PublicationUpdaterTests - -open System -open System.Text.Json -open Expecto -open PublicationUpdater - -let private parseJsonElement (json: string) = - use doc = JsonDocument.Parse(json) - doc.RootElement.Clone() - -[] -let tests = - testList - "PublicationUpdater" - [ testCase "normalizeDraftValue uses lowercase booleans" - <| fun _ -> - Expect.equal (Generator.normalizeDraftValue "True") "true" "True should normalize to true" - Expect.equal (Generator.normalizeDraftValue "FALSE") "false" "FALSE should normalize to false" - Expect.equal (Generator.normalizeDraftValue "") "false" "empty should default to false" - - testCase "buildRssTitle appends authors" - <| fun _ -> - Expect.equal - (Generator.buildRssTitle "Paper" "Alice and Bob") - "Paper - Alice and Bob" - "authors should be appended" - - Expect.equal (Generator.buildRssTitle "Paper" "") "Paper" "empty authors should keep title" - - testCase "getAuthorsFromJson formats author object arrays" - <| fun _ -> - let metadata = - parseJsonElement - """ - [ - { "name": "Alice" }, - { "name": "Bob" }, - { "name": "Charlie" } - ] - """ - - Expect.equal - (Generator.getAuthorsFromJson (Some metadata)) - "Alice, Bob and Charlie" - "author objects should be formatted as a human-readable list" - - testCase "getAuthorsFromJson handles single string author" - <| fun _ -> - let metadata = parseJsonElement "\"Alice\"" - - Expect.equal - (Generator.getAuthorsFromJson (Some metadata)) - "Alice" - "single string author should be returned directly" - - testCase "extractCitationForRepoName uses root metadata when present" - <| fun _ -> - let metadata = - parseJsonElement - """ - { - "title": "Root title", - "authors": ["Alice"] - } - """ - - match Generator.extractCitationForRepoName metadata "demo-repo" with - | Ok result -> - let title = result.GetProperty("title").GetString() - Expect.equal title "Root title" "root metadata should be selected first" - | Error msg -> failtestf "expected citation extraction to succeed, got: %s" msg - - testCase "extractCitationForRepoName falls back to config metadata" - <| fun _ -> - let metadata = - parseJsonElement - """ - { - "config": { - "metadata": { - "title": "Config title", - "authors": ["Alice"] - } - } - } - """ - - match Generator.extractCitationForRepoName metadata "demo-repo" with - | Ok result -> - let title = result.GetProperty("title").GetString() - Expect.equal title "Config title" "config metadata should be used when root metadata is absent" - | Error msg -> failtestf "expected citation extraction to succeed, got: %s" msg - - testCase "extractCitationForRepoName prefers index.qmd in fileInformation" - <| fun _ -> - let metadata = - parseJsonElement - """ - { - "fileInformation": { - "about.qmd": { - "metadata": { - "title": "About title" - } - }, - "index.qmd": { - "metadata": { - "title": "Index title" - } - } - } - } - """ - - match Generator.extractCitationForRepoName metadata "demo-repo" with - | Ok result -> - let title = result.GetProperty("title").GetString() - Expect.equal title "Index title" "index.qmd metadata should be preferred over other files" - | Error msg -> failtestf "expected citation extraction to succeed, got: %s" msg - - testCase "extractCitationForRepoName returns error when no metadata exists" - <| fun _ -> - let metadata = - parseJsonElement - """ - { - "quarto": { "version": "1.0.0" }, - "files": { "input": [] } - } - """ - - match Generator.extractCitationForRepoName metadata "demo-repo" with - | Ok _ -> failtest "expected citation extraction to fail when no metadata fields are present" - | Error msg -> Expect.stringContains msg "No metadata found" "error should explain missing metadata" - - testCase "extractCitationForRepoName errors when fileInformation has no usable metadata" - <| fun _ -> - let metadata = - parseJsonElement - """ - { - "fileInformation": { - "about.qmd": { - "something": "else" - } - } - } - """ - - match Generator.extractCitationForRepoName metadata "demo-repo" with - | Ok _ -> failtest "expected citation extraction to fail when fileInformation has no metadata" - | Error msg -> - Expect.stringContains - msg - "No metadata found in fileInformation" - "error should mention missing metadata in fileInformation" - - testCase "serializeToYaml preserves lowercase draft values" - <| fun _ -> - let publication: Generator.Publication = - { title = "Paper" - name = "paper-repo" - authors = "Alice and Bob" - journal = "Computo" - doi = "10.0000/example" - year = 2025 - date = "2025-01-02" - description = "Description" - ``abstract`` = "Abstract" - repo = "paper-repo" - bibtex = "@article{paper}" - pdf = "paper.pdf" - url = "https://example.test/paper" - draft = "false" } - - let yaml = Generator.serializeToYaml [ publication ] - Expect.stringContains yaml "draft: false" "draft should stay lowercase in YAML output" - Expect.stringContains yaml "title: Paper" "serialized YAML should contain the title" - - testCase "formatRssDate formats valid input as RFC1123" - <| fun _ -> - let formatted = Generator.formatRssDate "2025-01-02" - Expect.stringContains formatted "2025" "formatted RSS date should contain the year" - Expect.stringContains formatted "GMT" "formatted RSS date should be RFC1123-like" - - testCase "formatRssDate falls back on invalid input" - <| fun _ -> - let formatted = Generator.formatRssDate "not-a-date" - Expect.isGreaterThan formatted.Length 0 "fallback date should still be a non-empty string" - Expect.stringContains formatted "GMT" "fallback should still be RFC1123-like" ] diff --git a/src/PublicationUpdater.Tests/paket.references b/src/PublicationUpdater.Tests/paket.references deleted file mode 100644 index 3665ded..0000000 --- a/src/PublicationUpdater.Tests/paket.references +++ /dev/null @@ -1,4 +0,0 @@ -group Test -Microsoft.NET.Test.Sdk -YoloDev.Expecto.TestSdk -expecto \ No newline at end of file diff --git a/src/PublicationUpdater/AssemblyInfo.fs b/src/PublicationUpdater/AssemblyInfo.fs deleted file mode 100644 index 3965e3a..0000000 --- a/src/PublicationUpdater/AssemblyInfo.fs +++ /dev/null @@ -1,6 +0,0 @@ -namespace System - -open System.Runtime.CompilerServices - -[] -do () diff --git a/src/PublicationUpdater/PublicationUpdater.fs b/src/PublicationUpdater/PublicationUpdater.fs deleted file mode 100644 index da1daf7..0000000 --- a/src/PublicationUpdater/PublicationUpdater.fs +++ /dev/null @@ -1,477 +0,0 @@ -namespace PublicationUpdater - -open Octokit -open System -open System.Globalization -open System.IO -open System.Text -open System.Text.Json -open System.Text.RegularExpressions -open System.Threading.Tasks -open DotNetEnv -open FSharp.Data -open DrBiber -open YamlDotNet.Serialization -open YamlDotNet.Serialization.NamingConventions - -module Generator = - open QuartoInspect.QuartoClient - - type Publication = - { title: string - name: string - authors: string - journal: string - doi: string - year: int - date: string - description: string - ``abstract``: string - repo: string - bibtex: string - pdf: string - url: string - draft: string } - - let private computoUrl = "https://computo-journal.org/" - let private publishedRe = Regex(@"^published(_|-)\d+") - let private redirectStringRe = Regex(@"URL='(.*)'") - - let (|Empty|True|False|Other|) (raw: string) = - match raw with - | _ when String.IsNullOrWhiteSpace raw -> Empty - | _ when raw.Equals("true", StringComparison.OrdinalIgnoreCase) -> True - | _ when raw.Equals("false", StringComparison.OrdinalIgnoreCase) -> False - | _ -> Other raw - - let normalizeDraftValue raw = - match raw with - | Empty -> "false" - | True -> "true" - | False -> "false" - | Other s -> s.ToLowerInvariant() - - let buildRssTitle (title: string) (authors: string) = - if String.IsNullOrWhiteSpace(authors) then - title - else - title + " - " + authors - - let private getJsonString (element: JsonElement) (key: string) : string = - try - let mutable prop = Unchecked.defaultof - - if element.TryGetProperty(key, &prop) then - match prop.ValueKind with - | JsonValueKind.String -> prop.GetString() - | JsonValueKind.Null -> "" - | _ -> prop.ToString() - else - "" - with _ -> - "" - - let private getJsonObject (element: JsonElement) (key: string) : JsonElement option = - try - let mutable prop = Unchecked.defaultof - - if element.TryGetProperty(key, &prop) then - Some prop - else - None - with _ -> - None - - let internal getAuthorsFromJson (authorsElement: JsonElement option) : string = - match authorsElement with - | None -> "" - | Some elem when elem.ValueKind = JsonValueKind.Array -> - let authors = - elem.EnumerateArray() - |> Seq.choose (fun authorElem -> - match getJsonObject authorElem "name" with - | Some nameElem when nameElem.ValueKind = JsonValueKind.String -> Some(nameElem.GetString()) - | _ when authorElem.ValueKind = JsonValueKind.String -> Some(authorElem.GetString()) - | _ -> None) - |> Seq.toList - - match authors with - | [] -> "" - | [ single ] -> single - | list -> - let lastAuthor = List.last list - let otherAuthors = List.take (List.length list - 1) list - (String.concat ", " otherAuthors) + " and " + lastAuthor - | Some elem when elem.ValueKind = JsonValueKind.String -> elem.GetString() - | _ -> "" - - let private getBibTeX (page: string) = - let htmlFirst = HtmlDocument.Load(page) - - let html = - htmlFirst.CssSelect("meta[http-equiv='refresh']") - |> Seq.tryHead - |> Option.map (fun m -> - printfn "Found meta refresh: %A at %s" m page - - m.Attributes() - |> Seq.find (fun a -> a.Name() = "content") - |> fun a -> a.Value() - |> redirectStringRe.Match - |> fun mm -> mm.Groups[1].Value - |> fun p -> - printfn "new url to fetch %s" (page + p) - HtmlDocument.Load(page + p)) - |> Option.defaultValue htmlFirst - - let bibtexCls = ".bibtex" - - try - html.CssSelect(bibtexCls).Head.InnerText() - |> DirtyParser.bibTeXFromString - |> _.Head - |> Result.Ok - with e -> - Result.Error e.Message - - let private getAbstract (entry: BibTeXEntry) : string = - try - entry.Properties["abstract"] |> string - with _ -> - "" - - let private getBibTeXFromRepo (repo: Repository) : string = - match repo.Homepage with - | null - | "" -> "" - | homepage -> - getBibTeX homepage - |> function - | Ok a -> DrBiber.DirtyParser.bibTeXToString [ a ] - | Error _ -> "" - - let private getAbstractFromRepo (repo: Repository) : string = - match repo.Homepage with - | null - | "" -> "" - | homepage -> - getBibTeX homepage - |> Result.map getAbstract - |> function - | Ok a -> a - | Error _ -> "" - - let internal extractCitationForRepoName (quartoJson: JsonElement) (repoName: string) : Result = - try - let hasMetadataFields (elem: JsonElement) = - (elem.TryGetProperty("title") |> fst) - || (elem.TryGetProperty("author") |> fst) - || (elem.TryGetProperty("authors") |> fst) - || (elem.TryGetProperty("citation") |> fst) - || (elem.TryGetProperty("formats") |> fst) - - let tryGetMetadataFromElement (elem: JsonElement) = - if hasMetadataFields elem then - Some elem - else - match getJsonObject elem "metadata" with - | Some md when hasMetadataFields md -> Some md - | _ -> None - - let preferIndex (candidates: (string * JsonElement) list) = - candidates - |> List.tryFind (fun (name, _) -> name.EndsWith("index.qmd")) - |> Option.orElse (candidates |> List.tryHead) - - match tryGetMetadataFromElement quartoJson with - | Some rootMetadata -> Ok rootMetadata - | None -> - match getJsonObject quartoJson "config" |> Option.bind tryGetMetadataFromElement with - | Some cfg -> Ok cfg - | None -> - match getJsonObject quartoJson "fileInformation" with - | Some fileInfo -> - let candidates = - fileInfo.EnumerateObject() - |> Seq.toList - |> List.choose (fun prop -> - tryGetMetadataFromElement prop.Value - |> Option.map (fun elem -> (prop.Name, elem))) - - match preferIndex candidates with - | Some(_, elem) -> Ok elem - | None -> Error $"No metadata found in fileInformation for {repoName}" - | None -> - let keys = - quartoJson.EnumerateObject() |> Seq.map (fun p -> p.Name) |> String.concat ", " - - Error $"No metadata found. Available keys: {keys}" - with e -> - Error $"Error extracting citation from quarto inspect for {repoName}: {e.Message}" - - let private extractCitation (quartoJson: JsonElement) (repo: Repository) : Result = - extractCitationForRepoName quartoJson repo.Name - - let private runQuartoInspect (repoPath: string) : Task> = - task { - let! inspectResult = runInspect repoPath |> Async.StartAsTask - - match inspectResult with - | Error e when e.Contains("not a Quarto project") -> return Error "Not a Quarto project (this is expected)" - | Error e -> return Error e - | Ok r -> - try - let doc = JsonDocument.Parse(r.jsonContent) - return Ok doc.RootElement - with ex -> - return Error $"JSON parse failed: {ex.Message}" - } - - let private getQuartoFilePathsViaGitTree - (client: GitHubClient) - (owner: string) - (repo: string) - (defaultBranch: string) - : Task = - task { - try - let! reference = - client.Git.Reference.Get(owner, repo, $"heads/{defaultBranch}") - |> Async.AwaitTask - - let sha = reference.Object.Sha - let! tree = client.Git.Tree.GetRecursive(owner, repo, sha) |> Async.AwaitTask - - return - tree.Tree - |> Seq.filter (fun item -> item.Type.Value = TreeType.Blob) - |> Seq.map (fun item -> item.Path) - |> Seq.filter (fun path -> path.EndsWith(".qmd") || path.EndsWith(".yml") || path.EndsWith(".yaml")) - |> Seq.toList - with _ -> - return [] - } - - let private getCitationStructure (quartoJson: JsonElement) (repo: Repository) : Result = - try - match extractCitation quartoJson repo with - | Ok metadata -> - let dateStr = getJsonString metadata "date" - - let date = - if String.IsNullOrWhiteSpace(dateStr) then - DateTime.Now.ToString("yyyy-MM-dd") - else - dateStr - - let year = - try - DateTime.Parse(date).Year - with _ -> - DateTime.Now.Year - - Ok - { title = getJsonString metadata "title" - name = repo.Name - authors = getAuthorsFromJson (getJsonObject metadata "authors") - journal = "Computo" - doi = getJsonString metadata "doi" - year = year - date = date - description = getJsonString metadata "description" - ``abstract`` = getAbstractFromRepo repo - repo = repo.Name - bibtex = getBibTeXFromRepo repo - pdf = getJsonString metadata "pdf" - url = - match repo.Homepage with - | null - | "" -> repo.HtmlUrl - | h -> h - draft = normalizeDraftValue (getJsonString metadata "draft") } - | Error e -> Error e - with e -> - Error $"Error processing citation structure for {repo.Name}: {e.Message}" - - let internal serializeToYaml (items: seq) = - let serializer = - SerializerBuilder() - .WithNamingConvention(CamelCaseNamingConvention.Instance) - .ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull) - .Build() - - serializer.Serialize(items) - - let private xmlEscape (s: string) = - s.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace("\"", """).Replace("'", "'") - - let internal formatRssDate (s: string) = - try - DateTime.Parse(s).ToString("r") - with _ -> - DateTime.Now.ToString("r") - - let run (rootDir: string) : int = - try - CultureInfo.DefaultThreadCurrentCulture <- Globalization.CultureInfo("en-US") - - let envPath = Path.Combine(rootDir, ".env-secret") - - if File.Exists(envPath) then - Env.Load(envPath) |> ignore - - let client = - let c = GitHubClient(ProductHeaderValue("computo")) - - match Environment.GetEnvironmentVariable("API_GITHUB_TOKEN") with - | null - | "" -> c - | token -> - c.Credentials <- Credentials(token = token) - c - - printfn "================================================" - printfn "Starting Computo Publication Collection" - printfn "================================================" - - let repos = - client.Repository.GetAllForOrg("computorg") - |> Async.AwaitTask - |> Async.RunSynchronously - - let getReposContents (filter: Repository -> bool) (inputRepos: seq) = - inputRepos - |> Seq.filter filter - |> Seq.map (fun repo -> - task { - let uniqueId = Guid.NewGuid().ToString().Substring(0, 8) - let tempDir = Path.Combine(Path.GetTempPath(), $"{repo.Name}-{uniqueId}") - Directory.CreateDirectory(tempDir) |> ignore - - try - let! paths = - getQuartoFilePathsViaGitTree client repo.Owner.Login repo.Name repo.DefaultBranch - - if paths.IsEmpty then - return Error $"No Quarto files found in {repo.Name}" - else - for p in paths do - try - let! rawBytes = - client.Repository.Content.GetRawContent(repo.Owner.Login, repo.Name, p) - |> Async.AwaitTask - - let localPath = Path.Combine(tempDir, p) - let localDir = Path.GetDirectoryName(localPath) - - if not (String.IsNullOrWhiteSpace(localDir)) then - Directory.CreateDirectory(localDir) |> ignore - - File.WriteAllBytes(localPath, rawBytes) - with _ -> - () - - let! result = runQuartoInspect tempDir - return result |> Result.map (fun json -> (json, repo)) - finally - try - Directory.Delete(tempDir, true) - with _ -> - () - } - |> Async.AwaitTask) - |> Async.Parallel - |> Async.RunSynchronously - |> Array.toList - - let published = - repos - |> getReposContents (fun r -> r.Name |> publishedRe.IsMatch) - |> List.choose (function - | Ok(json, repo) -> - match getCitationStructure json repo with - | Ok p -> Some p - | Error e -> - if not (e.Contains("Not a Quarto project")) then - printfn " Error: %s" e - - None - | Error e -> - if not (e.Contains("Not a Quarto project")) then - printfn " Error: %s" e - - None) - |> List.sortBy _.date - |> List.rev - - let drafts, publishedOnly = published |> List.partition (fun d -> d.draft = "true") - printfn " Found %d published and %d draft papers" publishedOnly.Length drafts.Length - - let writeYaml (relativePath: string) (content: string) = - let outPath = Path.Combine(rootDir, relativePath) - File.WriteAllText(outPath, content) - printfn " Wrote %s" outPath - - writeYaml "site/published.yml" (serializeToYaml publishedOnly) - - if drafts.IsEmpty then - writeYaml "site/pipeline.yml" "[]\n" - else - writeYaml "site/pipeline.yml" (serializeToYaml drafts) - - let rssItems = publishedOnly |> List.truncate 10 - - let rss = - let sb = StringBuilder() - sb.AppendLine("") |> ignore - sb.AppendLine("") |> ignore - sb.AppendLine("") |> ignore - sb.AppendLine(" Computo Journal - Recent Articles") |> ignore - sb.AppendLine($" {computoUrl}") |> ignore - - sb.AppendLine(" Latest published articles from Computo Journal") - |> ignore - - for item in rssItems do - let desc = - if item.``abstract`` <> "" then - item.``abstract`` - else - item.description - - sb.AppendLine(" ") |> ignore - - sb.AppendLine($" {xmlEscape (buildRssTitle item.title item.authors)}") - |> ignore - - sb.AppendLine($" {xmlEscape item.url}") |> ignore - sb.AppendLine($" {xmlEscape item.url}") |> ignore - sb.AppendLine($" {formatRssDate item.date}") |> ignore - - if desc <> "" then - sb.AppendLine($" {xmlEscape desc}") |> ignore - - sb.AppendLine(" ") |> ignore - - sb.AppendLine("") |> ignore - sb.AppendLine("") |> ignore - sb.ToString() - - writeYaml "site/published.xml" rss - - let mock = - repos - |> getReposContents (fun r -> r.Name.StartsWith("published-paper")) - |> List.choose (function - | Ok(json, repo) -> getCitationStructure json repo |> Result.toOption - | Error _ -> None) - - writeYaml "site/mock-papers.yml" (serializeToYaml mock) - - printfn "================================================" - printfn "Done" - printfn "================================================" - 0 - with e -> - eprintfn "Publication update failed: %s" e.Message - 1 diff --git a/src/PublicationUpdater/PublicationUpdater.fsproj b/src/PublicationUpdater/PublicationUpdater.fsproj deleted file mode 100644 index ca2dd8c..0000000 --- a/src/PublicationUpdater/PublicationUpdater.fsproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net10.0 - true - false - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/PublicationUpdater/paket.references b/src/PublicationUpdater/paket.references deleted file mode 100644 index 7d45010..0000000 --- a/src/PublicationUpdater/paket.references +++ /dev/null @@ -1,6 +0,0 @@ -group Main -DotNetEnv -DrBiber -FSharp.Data -Octokit -YamlDotNet \ No newline at end of file diff --git a/src/QuartoInspect.Tests/QuartoInspect.Tests.fsproj b/src/QuartoInspect.Tests/QuartoInspect.Tests.fsproj deleted file mode 100644 index 2c1872a..0000000 --- a/src/QuartoInspect.Tests/QuartoInspect.Tests.fsproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - net10.0 - true - false - - - - - - - - - - - - \ No newline at end of file diff --git a/src/QuartoInspect.Tests/QuartoInspectTests.fs b/src/QuartoInspect.Tests/QuartoInspectTests.fs deleted file mode 100644 index 9f4bce7..0000000 --- a/src/QuartoInspect.Tests/QuartoInspectTests.fs +++ /dev/null @@ -1,572 +0,0 @@ -module QuartoInspectTests - -open System -open System.IO -open System.Text.RegularExpressions -open Expecto -open Octokit -open QuartoInspect -open QuartoInspect.QuartoClient -open QuartoInspect.QuartoTypes - -// Test configuration -let mockRepoOwner = "computorg" -let testTimeoutMs = 60000 // 60 seconds - -// Helper to get GitHub client -let getGitHubClient () = - let client = new GitHubClient(new ProductHeaderValue("computo-tests")) - - match System.Environment.GetEnvironmentVariable("API_GITHUB_TOKEN") with - | null - | "" -> client - | token -> - client.Credentials <- Credentials(token = token) - client - -let private isNotFound (ex: exn) = - ex.Message.Contains("Not Found", StringComparison.OrdinalIgnoreCase) - || ex.Message.Contains("not found", StringComparison.OrdinalIgnoreCase) - -let private tryFindFileUpwards (startDir: string) (relativePath: string) = - let rec loop (dir: DirectoryInfo) = - let candidate = Path.Combine(dir.FullName, relativePath) - - if File.Exists(candidate) then Some candidate - elif isNull dir.Parent then None - else loop dir.Parent - - loop (DirectoryInfo(startDir)) - -let private mockRepoCandidates = - lazy - (let fromEnv = - match Environment.GetEnvironmentVariable("MOCK_REPO_NAME") with - | null - | "" -> [] - | value -> [ value ] - - let fromMockPapers = - let repoRegex = Regex("^\\s*repo:\\s*([^\\s]+)\\s*$") - - match tryFindFileUpwards Environment.CurrentDirectory "site/mock-papers.yml" with - | None -> [] - | Some path -> - File.ReadAllLines(path) - |> Seq.choose (fun line -> - let m = repoRegex.Match(line) - - if m.Success then Some(m.Groups[1].Value.Trim()) else None) - |> Seq.distinct - |> Seq.toList - - fromEnv @ fromMockPapers @ [ "published-paper-example" ] |> List.distinct) - -let private resolveMockRepo (client: GitHubClient) = - async { - let mutable found: Repository option = None - - for repoName in mockRepoCandidates.Value do - if found.IsNone then - try - let! repo = client.Repository.Get(mockRepoOwner, repoName) |> Async.AwaitTask - found <- Some repo - with - | :? NotFoundException -> () - | ex when isNotFound ex -> () - - return found - } - -// ============================================================================ -// GitHub API Availability Tests -// ============================================================================ - -let githubApiTests = - testList - "GitHub API Availability" - [ - - testAsync "GitHub API is reachable" { - let client = getGitHubClient () - - try - let! user = client.User.Get("computorg") |> Async.AwaitTask - Expect.isNotNull user "Should retrieve computorg user" - Expect.equal user.Login "computorg" "Should get correct user login" - with - | :? NotFoundException as ex -> - Tests.skiptest $"User not found (expected in some environments): {ex.Message}" - | ex -> failtest $"GitHub API call failed: {ex.Message}" - } - - testAsync "GitHub API can fetch repositories" { - let client = getGitHubClient () - - try - let! repos = client.Repository.GetAllForOrg("computorg") |> Async.AwaitTask - Expect.isGreaterThan repos.Count 0 "Should retrieve at least one repository" - with - | :? RateLimitExceededException -> Tests.skiptest "GitHub API rate limit exceeded" - | ex -> failtest $"Failed to fetch repositories: {ex.Message}" - } - - testAsync "GitHub API can retrieve repository details" { - let client = getGitHubClient () - - try - let! repoOpt = resolveMockRepo client - - match repoOpt with - | None -> - let candidates = String.concat ", " mockRepoCandidates.Value - Tests.skiptest $"No accessible mock repository found in {mockRepoOwner}. Candidates: {candidates}" - | Some repo -> - Expect.isNotNull repo "Should retrieve repository" - Expect.equal repo.Owner.Login mockRepoOwner "Owner should be computorg" - Expect.isGreaterThan repo.Name.Length 0 "Repository name should be non-empty" - with - | :? NotFoundException -> Tests.skiptest $"No accessible mock repository found in {mockRepoOwner}" - | ex when isNotFound ex -> - Tests.skiptest $"No accessible mock repository found in {mockRepoOwner}: {ex.Message}" - | ex -> failtest $"Failed to retrieve repository details: {ex.Message}" - } ] - -// ============================================================================ -// Quarto Installation Tests -// ============================================================================ - -let quartoInstallationTests = - testList - "Quarto Installation" - [ - - testAsync "Quarto is installed and available" { - let! result = QuartoClient.checkQuartoAvailable () - - match result with - | Ok version -> Expect.isGreaterThan version.Length 0 "Quarto version output should be non-empty" - | Error msg -> Tests.skiptest $"Quarto not available: {msg}" - } ] - -// ============================================================================ -// Quarto Inspect Schema Compliance Tests -// ============================================================================ - -let quartoSchemaComplianceTests = - testList - "Quarto Inspect Schema Compliance" - [ - - test "Document schema accepts valid minimal document" { - let validJson = - """ - { - "quarto": { "version": "1.3.0" }, - "engines": ["python"], - "formats": { "html": {} }, - "resources": [], - "fileInformation": {} - } - """ - - match QuartoClient.validateDocumentSchema validJson with - | Ok _ -> () - | Error msg -> failtest $"Valid document should parse: {msg}" - } - - test "Document schema rejects missing engines field" { - let invalidJson = - """ - { - "quarto": { "version": "1.3.0" }, - "formats": { "html": {} }, - "resources": [], - "fileInformation": {} - } - """ - - match QuartoClient.validateDocumentSchema invalidJson with - | Ok _ -> failtest "Should reject document without engines" - | Error msg -> Expect.stringContains msg "engines" "Error should mention missing engines field" - } - - test "Document schema rejects missing quarto field" { - let invalidJson = - """ - { - "engines": ["python"], - "formats": { "html": {} }, - "resources": [], - "fileInformation": {} - } - """ - - match QuartoClient.validateDocumentSchema invalidJson with - | Ok _ -> failtest "Should reject document without quarto" - | Error msg -> Expect.stringContains msg "quarto" "Error should mention missing quarto field" - } - - test "Document schema rejects missing formats field" { - let invalidJson = - """ - { - "quarto": { "version": "1.3.0" }, - "engines": ["python"], - "resources": [], - "fileInformation": {} - } - """ - - match QuartoClient.validateDocumentSchema invalidJson with - | Ok _ -> failtest "Should reject document without formats" - | Error msg -> Expect.stringContains msg "formats" "Error should mention missing formats field" - } - - test "Document schema rejects malformed JSON" { - let invalidJson = "{ \"quarto\": {" - - match QuartoClient.validateDocumentSchema invalidJson with - | Ok _ -> failtest "Should reject malformed document JSON" - | Error msg -> Expect.stringContains msg "Invalid JSON" "Error should report invalid JSON" - } - - test "Project schema accepts valid minimal project" { - let validJson = - """ - { - "quarto": { "version": "1.3.0" }, - "dir": "/path/to/project", - "engines": ["python"], - "files": { - "input": [], - "resources": [], - "configResources": [], - "config": [] - }, - "fileInformation": {}, - "extensions": [] - } - """ - - match QuartoClient.validateProjectSchema validJson with - | Ok _ -> () - | Error msg -> failtest $"Valid project should parse: {msg}" - } - - test "Project schema rejects missing files field" { - let invalidJson = - """ - { - "quarto": { "version": "1.3.0" }, - "dir": "/path/to/project", - "engines": ["python"], - "fileInformation": {}, - "extensions": [] - } - """ - - match QuartoClient.validateProjectSchema invalidJson with - | Ok _ -> failtest "Should reject project without files" - | Error msg -> Expect.stringContains msg "files" "Error should mention missing files field" - } - - test "Project schema rejects missing quarto field" { - let invalidJson = - """ - { - "dir": "/path/to/project", - "engines": ["python"], - "files": { - "input": [], - "resources": [], - "configResources": [], - "config": [] - }, - "fileInformation": {}, - "extensions": [] - } - """ - - match QuartoClient.validateProjectSchema invalidJson with - | Ok _ -> failtest "Should reject project without quarto" - | Error msg -> Expect.stringContains msg "quarto" "Error should mention missing quarto field" - } - - test "Project schema rejects missing dir field" { - let invalidJson = - """ - { - "quarto": { "version": "1.3.0" }, - "engines": ["python"], - "files": { - "input": [], - "resources": [], - "configResources": [], - "config": [] - }, - "fileInformation": {}, - "extensions": [] - } - """ - - match QuartoClient.validateProjectSchema invalidJson with - | Ok _ -> failtest "Should reject project without dir" - | Error msg -> Expect.stringContains msg "dir" "Error should mention missing dir field" - } - - test "Project schema rejects missing engines field" { - let invalidJson = - """ - { - "quarto": { "version": "1.3.0" }, - "dir": "/path/to/project", - "files": { - "input": [], - "resources": [], - "configResources": [], - "config": [] - }, - "fileInformation": {}, - "extensions": [] - } - """ - - match QuartoClient.validateProjectSchema invalidJson with - | Ok _ -> failtest "Should reject project without engines" - | Error msg -> Expect.stringContains msg "engines" "Error should mention missing engines field" - } - - test "Project schema rejects malformed JSON" { - let invalidJson = "{ \"quarto\": {" - - match QuartoClient.validateProjectSchema invalidJson with - | Ok _ -> failtest "Should reject malformed project JSON" - | Error msg -> Expect.stringContains msg "Invalid JSON" "Error should report invalid JSON" - } - - test "JSON type provider parses document schema sample" { - let jsonStr = - """ - { - "quarto": { - "version": "1.3.0" - }, - "engines": ["python"], - "formats": { - "html": { - "theme": "default" - } - }, - "resources": [], - "fileInformation": { - "document.qmd": { - "includeMap": [], - "codeCells": [ - { - "start": 1, - "end": 10, - "file": "document.qmd", - "source": "import pandas as pd", - "language": "python", - "metadata": {} - } - ] - } - } - } - """ - - match parseDocumentJson jsonStr with - | Ok parsed -> Expect.isNotNull (box parsed) "Should parse document JSON successfully" - | Error msg -> failtest $"Should parse document JSON: {msg}" - } - - test "JSON type provider parses project schema sample" { - let jsonStr = - """ - { - "quarto": { - "version": "1.3.0" - }, - "dir": "/path/to/project", - "engines": ["python", "r"], - "config": { - "project": { - "type": "website" - } - }, - "files": { - "input": ["index.qmd", "about.qmd"], - "resources": [], - "configResources": [], - "config": ["_quarto.yml"] - }, - "fileInformation": { - "index.qmd": { - "includeMap": [], - "codeCells": [ - { - "start": 1, - "end": 15, - "file": "index.qmd", - "source": "import pandas as pd", - "language": "python", - "metadata": { - "eval": "false" - } - } - ] - } - }, - "extensions": [] - } - """ - - match parseProjectJson jsonStr with - | Ok parsed -> - Expect.isNotNull (box parsed) "Should parse project JSON successfully" - Expect.equal parsed.Dir "/path/to/project" "Directory should match" - | Error msg -> failtest $"Should parse project JSON: {msg}" - } - - test "JSON type provider returns error on invalid project JSON" { - match parseProjectJson "{ bad json" with - | Ok _ -> failtest "Expected parseProjectJson to fail on malformed JSON" - | Error msg -> - Expect.stringContains msg "Failed to parse project JSON" "Error should include parse failure context" - } - - test "JSON type provider returns error on invalid document JSON" { - match parseDocumentJson "{ bad json" with - | Ok _ -> failtest "Expected parseDocumentJson to fail on malformed JSON" - | Error msg -> - Expect.stringContains msg "Failed to parse document JSON" "Error should include parse failure context" - } ] - -// ============================================================================ -// Integration Tests with Mock Repository -// ============================================================================ - -let mockRepoIntegrationTests = - testList - "Mock Repository Integration" - [ - - testAsync "Can fetch mock repository from GitHub" { - let client = getGitHubClient () - - try - let! repoOpt = resolveMockRepo client - - match repoOpt with - | None -> - let candidates = String.concat ", " mockRepoCandidates.Value - Tests.skiptest $"No accessible mock repository found in {mockRepoOwner}. Candidates: {candidates}" - | Some repo -> - Expect.isNotNull repo "Mock repository should exist" - Expect.equal repo.Owner.Login mockRepoOwner "Repository owner should match" - Expect.isGreaterThan repo.Name.Length 0 "Repository name should be non-empty" - with - | :? NotFoundException -> - Tests.skiptest $"No accessible mock repository found in {mockRepoOwner} organization" - | ex when isNotFound ex -> - Tests.skiptest $"No accessible mock repository found in {mockRepoOwner}: {ex.Message}" - | ex -> failtest $"Failed to fetch mock repository: {ex.Message}" - } - - testAsync "Mock repository has expected structure" { - let client = getGitHubClient () - - try - let! repoOpt = resolveMockRepo client - - match repoOpt with - | None -> - let candidates = String.concat ", " mockRepoCandidates.Value - Tests.skiptest $"No accessible mock repository found in {mockRepoOwner}. Candidates: {candidates}" - | Some repo -> - Expect.isNotNull repo.DefaultBranch "Should have default branch" - Expect.isGreaterThan (repo.CreatedAt.UtcTicks) 0L "Should have creation date" - - // Check for typical Quarto project files - let! contents = - client.Repository.Content.GetAllContents(mockRepoOwner, repo.Name) - |> Async.AwaitTask - - let fileNames = contents |> Seq.map (fun c -> c.Name.ToLower()) |> Set.ofSeq - - Expect.isTrue - (fileNames.Contains("_quarto.yml") || fileNames.Contains("index.qmd")) - "Should contain Quarto project files" - with - | :? NotFoundException -> - Tests.skiptest $"Mock repository structure check skipped - no accessible repository found" - | ex when isNotFound ex -> Tests.skiptest $"Mock repository structure check skipped: {ex.Message}" - | ex -> failtest $"Failed to check repository structure: {ex.Message}" - } ] - -// ============================================================================ -// Quarto Inspect Execution Tests (when available locally) -// ============================================================================ - -let quartoExecutionTests = - testList - "Quarto Inspect Execution" - [ - - testAsync "Can run quarto inspect on current project" { - let! quartoAvailable = QuartoClient.checkQuartoAvailable () - - match quartoAvailable with - | Error _ -> Tests.skiptest "Quarto not installed, skipping execution tests" - | Ok _ -> - // Try to run inspect on the parent directory (the website project) - let parentDir = Directory.GetParent(AppContext.BaseDirectory).Parent.FullName - - // Only run if we're in the right directory structure - if File.Exists(Path.Combine(parentDir, "_quarto.yml")) then - let! result = QuartoClient.runInspect parentDir - - match result with - | Ok inspectResult -> - Expect.equal inspectResult.exitCode 0 "Quarto inspect should succeed" - Expect.isGreaterThan inspectResult.jsonContent.Length 0 "Should produce JSON output" - - // Validate output conforms to schema - match QuartoClient.validateProjectSchema inspectResult.jsonContent with - | Ok _ -> () - | Error msg -> failtest $"Output doesn't conform to project schema: {msg}" - | Error msg -> Tests.skiptest $"Quarto inspect execution skipped: {msg}" - else - Tests.skiptest "Quarto project not found in expected location" - } - - testAsync "Quarto inspect handles non-Quarto directories gracefully" { - let! quartoAvailable = QuartoClient.checkQuartoAvailable () - - match quartoAvailable with - | Error _ -> Tests.skiptest "Quarto not installed" - | Ok _ -> - // Try a temp directory that's not a Quarto project - let tempDir = Path.GetTempPath() - let! result = QuartoClient.runInspect tempDir - - match result with - | Ok _ -> Tests.skiptest "Quarto might have treated temp directory as project" - | Error msg -> Expect.stringContains msg "Quarto" "Error message should mention Quarto or project" - } ] - -// ============================================================================ -// Main Test Suite -// ============================================================================ - -[] -let allTests = - testList - "Quarto Inspect Test Suite" - [ githubApiTests - quartoInstallationTests - quartoSchemaComplianceTests - mockRepoIntegrationTests - quartoExecutionTests ] diff --git a/src/QuartoInspect.Tests/paket.references b/src/QuartoInspect.Tests/paket.references deleted file mode 100644 index 3665ded..0000000 --- a/src/QuartoInspect.Tests/paket.references +++ /dev/null @@ -1,4 +0,0 @@ -group Test -Microsoft.NET.Test.Sdk -YoloDev.Expecto.TestSdk -expecto \ No newline at end of file diff --git a/src/QuartoInspect/QuartoClient.fs b/src/QuartoInspect/QuartoClient.fs deleted file mode 100644 index bd92984..0000000 --- a/src/QuartoInspect/QuartoClient.fs +++ /dev/null @@ -1,132 +0,0 @@ -namespace QuartoInspect - -open System -open System.Diagnostics -open System.IO -open System.Text.Json - -/// Client for running Quarto inspect commands -module QuartoClient = - - /// Result of running quarto inspect - type InspectResult = - { jsonContent: string - exitCode: int - stderr: string - stdout: string - executionTime: TimeSpan } - - /// Utility function for erroring with about missing fields - let errorMissingFields (has: string -> bool) (fields: string list) = - let missingFields = fields |> List.filter (fun f -> not (has f)) - - if missingFields.Length > 0 then - let missingFieldNames = missingFields |> String.concat ", " - Result.Error $"Missing required fields: {missingFieldNames}" - else - Ok() - - /// Run quarto inspect on a given path - let runInspect (path: string) : Async> = - async { - try - let startTime = DateTime.Now - let tempDir = Path.GetTempPath() - let outputFile = Path.Combine(tempDir, $"quarto-inspect-{Guid.NewGuid()}.json") - - let processInfo = ProcessStartInfo() - processInfo.FileName <- "quarto" - processInfo.Arguments <- $"inspect \"{path}\" \"{outputFile}\"" - processInfo.RedirectStandardOutput <- true - processInfo.RedirectStandardError <- true - processInfo.UseShellExecute <- false - processInfo.CreateNoWindow <- true - - use proc = Process.Start(processInfo) - do! Async.Sleep(100) // Give process time to start - - let! _ = proc.WaitForExitAsync() |> Async.AwaitTask - - let stdout = proc.StandardOutput.ReadToEnd() - let stderr = proc.StandardError.ReadToEnd() - let executionTime = DateTime.Now - startTime - - if proc.ExitCode <> 0 then - return Error $"quarto inspect failed (exit code {proc.ExitCode}): {stderr}" - else if not (File.Exists(outputFile)) then - return Error $"quarto inspect output file not found at {outputFile}" - else - let jsonContent = File.ReadAllText(outputFile) - - try - File.Delete(outputFile) - with _ -> - () - - return - Ok - { jsonContent = jsonContent - exitCode = proc.ExitCode - stderr = stderr - stdout = stdout - executionTime = executionTime } - with ex -> - return Error $"Error running quarto inspect: {ex.Message}" - } - - /// Validate JSON against document schema - let validateDocumentSchema (jsonStr: string) : Result = - try - let doc = JsonDocument.Parse(jsonStr) - let root = doc.RootElement - - let has (key: string) = - let mutable elem = Unchecked.defaultof - root.TryGetProperty(key, &elem) - // Check required fields - [ "quarto"; "engines"; "formats" ] - |> errorMissingFields has - |> Result.bind (fun () -> Ok root) - with ex -> - Error $"Invalid JSON: {ex.Message}" - - /// Validate JSON against project schema - let validateProjectSchema (jsonStr: string) : Result = - try - let doc = JsonDocument.Parse(jsonStr) - let root = doc.RootElement - - let has (key: string) = - let mutable elem = Unchecked.defaultof - root.TryGetProperty(key, &elem) - // Check required fields - [ "quarto"; "dir"; "engines"; "files" ] - |> errorMissingFields has - |> Result.bind (fun () -> Ok root) - with ex -> - Error $"Invalid JSON: {ex.Message}" - - /// Check if Quarto is installed and accessible - let checkQuartoAvailable () : Async> = - async { - try - let processInfo = ProcessStartInfo() - processInfo.FileName <- "quarto" - processInfo.Arguments <- "--version" - processInfo.RedirectStandardOutput <- true - processInfo.RedirectStandardError <- true - processInfo.UseShellExecute <- false - processInfo.CreateNoWindow <- true - - use proc = Process.Start(processInfo) - let! _ = proc.WaitForExitAsync() |> Async.AwaitTask - - if proc.ExitCode = 0 then - let version = proc.StandardOutput.ReadToEnd().Trim() - return Ok version - else - let error = proc.StandardError.ReadToEnd() - return Error $"Quarto version check failed: {error}" - with ex -> - return Error $"Quarto not available: {ex.Message}" - } diff --git a/src/QuartoInspect/QuartoInspect.fsproj b/src/QuartoInspect/QuartoInspect.fsproj deleted file mode 100644 index f997b23..0000000 --- a/src/QuartoInspect/QuartoInspect.fsproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - net10.0 - true - false - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/QuartoInspect/QuartoTypes.fs b/src/QuartoInspect/QuartoTypes.fs deleted file mode 100644 index c0bfaac..0000000 --- a/src/QuartoInspect/QuartoTypes.fs +++ /dev/null @@ -1,77 +0,0 @@ -namespace QuartoInspect - -open FSharp.Data - -module QuartoTypes = - - /// Type provider for Quarto project-level inspect output - [] - let ProjectSamplePath = __SOURCE_DIRECTORY__ + "/sample-project.json" - - type QuartoProjectProvider = JsonProvider - - /// Type provider for Quarto document-level inspect output - [] - let DocumentSamplePath = __SOURCE_DIRECTORY__ + "/sample-document.json" - - type QuartoDocumentProvider = JsonProvider - - /// Represents a Quarto version - type QuartoVersion = { version: string } - - /// Represents a code cell in a document - type CodeCell = - { start: int - ``end``: int - file: string - source: string - language: string - metadata: Map } - - /// Represents an include mapping - type IncludeMapping = { source: string; target: string } - - /// Represents file-level information - type FileInfo = - { includeMap: IncludeMapping list - codeCells: CodeCell list } - - /// Represents project file information - type ProjectFiles = - { input: string list - resources: string list - configResources: string list - config: string list } - - /// Represents a Quarto project inspection result - type QuartoProjectInfo = - { quarto: QuartoVersion - dir: string - engines: string list - config: Map - files: ProjectFiles - fileInformation: Map - extensions: Map list } - - /// Represents a Quarto document inspection result - type QuartoDocumentInfo = - { quarto: QuartoVersion - engines: string list - formats: Map - resources: string list - fileInformation: Map - project: QuartoProjectInfo option } - - /// Parse JSON string to QuartoProjectInfo - let parseProjectJson (jsonStr: string) : Result = - try - Ok(QuartoProjectProvider.Parse(jsonStr)) - with ex -> - Error $"Failed to parse project JSON: {ex.Message}" - - /// Parse JSON string to QuartoDocumentInfo - let parseDocumentJson (jsonStr: string) : Result = - try - Ok(QuartoDocumentProvider.Parse(jsonStr)) - with ex -> - Error $"Failed to parse document JSON: {ex.Message}" diff --git a/src/QuartoInspect/README.md b/src/QuartoInspect/README.md deleted file mode 100644 index 1e72a24..0000000 --- a/src/QuartoInspect/README.md +++ /dev/null @@ -1,266 +0,0 @@ -# Quarto Inspect Type Provider & Tests - -This directory contains a refactored F# infrastructure for working with Quarto inspect output, leveraging FSharp.Data's JSON type provider for compile-time type safety. - -## Project Structure - -### QuartoInspect/ -Core library providing: -- **QuartoTypes.fs**: Type definitions and JSON type providers - - `QuartoProjectProvider`: Type provider for project-level inspect output (based on `quarto-inspect-project-json-schema.json` using `Schema=` mode) - - `QuartoDocumentProvider`: Type provider for document-level inspect output (based on `quarto-inspect-document-json-schema.json` using `Schema=` mode) - - Helper functions for parsing and validation - -- **QuartoClient.fs**: Client for executing Quarto commands - - `runInspect`: Execute `quarto inspect` on a given path - - `checkQuartoAvailable`: Verify Quarto installation - - `validateDocumentSchema`: Validate JSON against document schema - - `validateProjectSchema`: Validate JSON against project schema - -### QuartoInspect.Tests/ -Comprehensive test suite using Expecto framework: -- **GitHub API Availability Tests**: Verify GitHub API connectivity and authentication -- **Quarto Installation Tests**: Check Quarto availability -- **Schema Compliance Tests**: Validate JSON against schemas -- **Mock Repository Integration**: Test with actual computorg repositories -- **Quarto Inspect Execution**: Integration tests with real Quarto commands - -## Building - -### Build the library: -```bash -cd src/QuartoInspect -dotnet build -``` - -### Build and run tests: -```bash -cd src/QuartoInspect.Tests -dotnet restore -dotnet build -dotnet run -``` - -### Run specific test categories: -```bash -# Run only GitHub API tests -dotnet run -- --filter "GitHub API" - -# Run only schema compliance tests -dotnet run -- --filter "Schema Compliance" - -# Run with verbose output -dotnet run -- --verbose -``` - -## Usage in Your Scripts - -### Using the Type Providers - -```fsharp -#r "nuget: FSharp.Data" -#load "../QuartoInspect/QuartoTypes.fs" -open QuartoInspect.QuartoTypes - -// Parse and validate JSON -let jsonStr = System.IO.File.ReadAllText("output.json") -match parseProjectJson jsonStr with -| Ok parsed -> - printfn "Version: %s" parsed.Quarto.Version - printfn "Directory: %s" parsed.Dir -| Error msg -> printfn "Error: %s" msg -``` - -### Using the Quarto Client - -```fsharp -#r "nuget: FSharp.Data" -#load "../QuartoInspect/QuartoClient.fs" -open QuartoInspect.QuartoClient - -// Check Quarto availability -let! version = QuartoClient.checkQuartoAvailable() -match version with -| Ok v -> printfn "Quarto version: %s" v -| Error msg -> printfn "Error: %s" msg - -// Run quarto inspect -let! result = QuartoClient.runInspect "/path/to/project" -match result with -| Ok inspectResult -> - printfn "Execution time: %A" inspectResult.executionTime - // Validate schema - match QuartoClient.validateProjectSchema inspectResult.jsonContent with - | Ok json -> printfn "Valid project schema" - | Error msg -> printfn "Schema error: %s" msg -| Error msg -> printfn "Inspect failed: %s" msg -``` - -## Type Providers - -The type providers use FSharp.Data's **JSON Schema mode** with the official Quarto JSON schemas: -- **quarto-inspect-project-json-schema.json**: Official project schema -- **quarto-inspect-document-json-schema.json**: Official document schema - -The type providers are declared with `Schema=` syntax, which validates JSON against the actual JSON Schema specification rather than inferring from samples. - -### Using JSON Schema Mode -```fsharp -// Direct schema validation via type provider -type QuartoProjectProvider = JsonProvider -``` - -This approach: -- Validates against official JSON Schema specification -- Provides compile-time type safety based on schema constraints -- Ensures conformance to Quarto's published interface -- **Compile-time type safety**: Errors caught at compile time, not runtime -- **IntelliSense support**: Full IDE support in VS Code and Visual Studio -- **Schema validation**: Ensures conformance to Quarto specifications -- **Type inference**: F# infers types from JSON structure - -### Project Schema Fields: -- `quarto`: Version information -- `dir`: Project directory path -- `engines`: List of rendering engines (python, r, julia, etc.) -- `config`: Project configuration metadata -- `files`: Input, resource, and config files -- `fileInformation`: Per-document metadata including code cells -- `extensions`: Installed extensions - -### Document Schema Fields: -- `quarto`: Version information -- `engines`: List of rendering engines -- `formats`: Available output formats -- `resources`: Resource files -- `fileInformation`: Document metadata including code cells -- `project`: (Optional) Parent project info if document is in a project - -## Testing - -### Test Categories - -1. **GitHub API Availability** - - Verifies GitHub API connectivity - - Tests repository retrieval - - Handles rate limiting gracefully - -2. **Quarto Installation** - - Checks if Quarto is installed and accessible - - Retrieves Quarto version - -3. **Schema Compliance** - - Validates sample JSON against schemas - - Tests type provider parsing - - Ensures required fields presence - -4. **Mock Repository Integration** - - Tests with `published-paper-example` repository - - Verifies repository structure - - Skips gracefully if repository not found - -5. **Quarto Inspect Execution** - - Runs actual `quarto inspect` commands - - Validates output schema compliance - - Tests error handling for non-Quarto directories - -### Running Tests - -Tests use Expecto and support various options: - -```bash -# Run all tests -dotnet run - -# Run with specific parallelism -dotnet run -- --parallel 2 - -# List available tests -dotnet run -- --list-tests - -# Run tests matching a pattern -dotnet run -- --filter "GitHub" -``` - -## Environment Setup - -### Required: -- **.NET 8.0** or later -- **Quarto** (for inspect command tests) -- **GitHub API Token** (optional, set via `API_GITHUB_TOKEN` environment variable for authenticated requests) - -### Environment Variables: -```bash -# For authenticated GitHub API requests -export API_GITHUB_TOKEN="ghp_your_token_here" -``` - -## Integration with getcomputo-pub.fsx - -A refactored version of the main script is provided as `getcomputo-pub-refactored.fsx`. It includes: - -- Embedded type providers for compile-time validation -- Improved error handling with schema validation -- Better separation of concerns -- Cleaner JSON parsing using type providers - -To use the refactored version: -```bash -dotnet fsi src/getcomputo-pub-refactored.fsx -``` - -## Schema Files - -The JSON schemas are included in the repository: -- `quarto-inspect-document-json-schema.json`: Document inspection schema -- `quarto-inspect-project-json-schema.json`: Project inspection schema - -These match the official schemas from https://quarto.org/docs/advanced/inspect/. - -## Extending the Type Providers - -To add support for new fields returned by Quarto inspect: - -1. Update the official Quarto JSON Schema files (or wait for Quarto to update them) -2. Rebuild the project - type provider automatically updates to match schema -3. New fields are now available with full IntelliSense support - -The type provider uses JSON Schema mode, so it strictly validates against the schema specification. - -## Error Handling - -The library uses `Result<'T, string>` for error handling, making error cases explicit: - -```fsharp -let validate (jsonStr: string) = - match QuartoClient.validateProjectSchema jsonStr with - | Ok element -> printfn "Valid" - | Error msg -> printfn "Invalid: %s" msg -``` - -## Performance Considerations - -- Type providers are evaluated at compile time, so there's no runtime overhead -- JSON parsing is fast due to FSharp.Data's optimized implementation -- Tests run in parallel (4 workers by default) -- GitHub API calls may be rate-limited (~60 req/hour unauthenticated, ~5000/hour with token) - -## Troubleshooting - -### "Quarto not available" -- Ensure Quarto is installed: `quarto --version` -- Verify Quarto is in PATH -- Tests will skip gracefully if Quarto is not available - -### "GitHub API rate limit exceeded" -- Set GitHub API token: `export API_GITHUB_TOKEN="..."` -- This increases limit from 60 to 5000 requests per hour - -### "Mock repository not found" -- Tests skip gracefully if `published-paper-example` doesn't exist -- This is expected in development environments - -### Schema validation errors -- Check that JSON matches Quarto's official schemas -- Review error message for missing required fields -- Validate raw JSON: `jq . < output.json` diff --git a/src/QuartoInspect/paket.references b/src/QuartoInspect/paket.references deleted file mode 100644 index 714d935..0000000 --- a/src/QuartoInspect/paket.references +++ /dev/null @@ -1,3 +0,0 @@ -group Main -FSharp.Data -Octokit \ No newline at end of file diff --git a/src/QuartoInspect/sample-document.json b/src/QuartoInspect/sample-document.json deleted file mode 100644 index 00d0155..0000000 --- a/src/QuartoInspect/sample-document.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "quarto": { - "version": "1.3.0" - }, - "engines": ["python"], - "formats": { - "html": { - "theme": "default" - } - }, - "resources": [], - "fileInformation": { - "document.qmd": { - "includeMap": [], - "codeCells": [ - { - "start": 1, - "end": 10, - "file": "document.qmd", - "source": "import pandas as pd", - "language": "python", - "metadata": {} - } - ] - } - } -} diff --git a/src/QuartoInspect/sample-project.json b/src/QuartoInspect/sample-project.json deleted file mode 100644 index 7269feb..0000000 --- a/src/QuartoInspect/sample-project.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "quarto": { - "version": "1.3.0" - }, - "dir": "/path/to/project", - "engines": ["python", "r"], - "config": { - "project": { - "type": "website" - } - }, - "files": { - "input": ["index.qmd", "about.qmd"], - "resources": [], - "configResources": [], - "config": ["_quarto.yml"] - }, - "fileInformation": { - "index.qmd": { - "includeMap": [], - "codeCells": [ - { - "start": 1, - "end": 15, - "file": "index.qmd", - "source": "import pandas as pd\npd.read_csv('data.csv')", - "language": "python", - "metadata": { - "eval": "false" - } - } - ] - }, - "about.qmd": { - "includeMap": [], - "codeCells": [] - } - }, - "extensions": [] -} diff --git a/src/getcomputo-pub.fsx b/src/getcomputo-pub.fsx deleted file mode 100644 index f2a63db..0000000 --- a/src/getcomputo-pub.fsx +++ /dev/null @@ -1,837 +0,0 @@ -#r "nuget: Octokit" -#r "nuget: DotNetEnv" -#r "nuget: FSharp.Data" -#r "nuget: DrBiber" -#r "nuget: YamlDotNet" - -open Octokit -open System.Collections.Generic -open System.Text.RegularExpressions -open System.IO -open DotNetEnv -open FSharp.Data -open DrBiber -open System.Threading.Tasks -open System.Text.Json -open System.Text.Json.Serialization -open System.Text -open YamlDotNet.Serialization -open YamlDotNet.Serialization.NamingConventions - -let repoRoot = Path.GetFullPath(Path.Combine(__SOURCE_DIRECTORY__, "..")) - -System.Globalization.CultureInfo.DefaultThreadCurrentCulture <- System.Globalization.CultureInfo("en-US") -// exit if QUARTO_PROJECT_RENDER_ALL is set in the environment -// if System.Environment.GetEnvironmentVariable("QUARTO_PROJECT_RENDER_ALL") = null then -// printfn "QUARTO_PROJECT_RENDER_ALL is not set, exiting." -// exit 0 -// Load environment variables from .env file -Env.Load(".env-secret") - -let client = - let client = new GitHubClient(new ProductHeaderValue("computo")) - // Using environment variable for token is a good security practice - match System.Environment.GetEnvironmentVariable("API_GITHUB_TOKEN") with - | null - | "" -> client // No authentication - | token -> - client.Credentials <- Credentials(token = token) - client - -let computoGithubReposUrl = "https://api.github.com/users/computorg/repos" -let computoUrl = "https://computo-journal.org/" -let publishedRe = Regex(@"^published(_|-)\d+") - -printfn "================================================" -printfn "Starting Computo Publication Collection Script" -printfn "================================================" -printfn "" - -printfn "[1/5] Fetching repositories from computorg organization..." - -let repos = - client.Repository.GetAllForOrg("computorg") - |> Async.AwaitTask - |> Async.RunSynchronously - -printfn "✓ Found %d repositories" repos.Count -printfn "" - -// Helper to get values from JSON elements with safe type casting -let getJsonString (element: JsonElement) (key: string) : string = - try - let mutable prop = Unchecked.defaultof - - if element.TryGetProperty(key, &prop) then - match prop.ValueKind with - | JsonValueKind.String -> prop.GetString() - | JsonValueKind.Null -> "" - | _ -> prop.ToString() - else - "" - with _ -> - "" - -let getJsonObject (element: JsonElement) (key: string) : JsonElement option = - try - let mutable prop = Unchecked.defaultof - - if element.TryGetProperty(key, &prop) then - Some prop - else - None - with _ -> - None - -let getJsonArray (element: JsonElement) (key: string) : JsonElement seq = - try - let mutable prop = Unchecked.defaultof - - if element.TryGetProperty(key, &prop) && prop.ValueKind = JsonValueKind.Array then - prop.EnumerateArray() - else - Seq.empty - with _ -> - Seq.empty - -// Very lightweight front matter parser for fallback (mock papers) -let tryParseFrontMatter (path: string) : Map option = - try - let content = System.IO.File.ReadAllText(path) - let pattern = "(?s)^---\s*(.*?)\s*---" - let m = System.Text.RegularExpressions.Regex.Match(content, pattern) - - if not m.Success then - None - else - let fm = m.Groups[1].Value.Split('\n') |> Array.toList - let mutable currentKey = "" - let dict = System.Collections.Generic.Dictionary() - - for line in fm do - let trimmed = line.Trim() - - if trimmed.StartsWith("#") || trimmed = "" then - () - else if trimmed.StartsWith("-") && currentKey <> "" then - let v = trimmed.TrimStart('-').Trim() - - let existing = - if dict.ContainsKey(currentKey) then - dict[currentKey] - else - "" - - let combined = if existing = "" then v else existing + "; " + v - dict[currentKey] <- combined - else - let parts = trimmed.Split([| ':' |], 2) - - if parts.Length = 2 then - currentKey <- parts[0].Trim() - dict[currentKey] <- parts[1].Trim() - - dict |> Seq.map (fun kv -> kv.Key, kv.Value) |> Map.ofSeq |> Some - with _ -> - None - - -type RepoBaseError = Repo of string - -type RepoError = - | NoQmdFound of RepoBaseError - | NoContentFound of RepoBaseError - | NoFrontMatterFound of RepoBaseError - | BogusFrontMatter of RepoBaseError - -let redirectStringRe = Regex(@"URL='(.*)'") - -let getBibTeX (page: string) = - let htmlFirst = HtmlDocument.Load(page) - - let html = - // handle the case of http redirect - htmlFirst.CssSelect("meta[http-equiv='refresh']") - |> Seq.tryHead - |> Option.map (fun m -> - printfn "Found meta refresh: %A at %s" m page - - m.Attributes() - |> Seq.find (fun a -> a.Name() = "content") - |> fun a -> a.Value() - |> redirectStringRe.Match - |> fun m -> m.Groups[1].Value - |> fun p -> - printfn "new url to fetch %s" (page + p) - HtmlDocument.Load(page + p)) - |> Option.defaultValue htmlFirst - - try - html.CssSelect(".bibtex").Head.InnerText() - |> DirtyParser.bibTeXFromString - |> _.Head - |> Result.Ok - with e -> - printfn "Error getting BibTeX from %s: %s" page e.Message - Result.Error e.Message - -let getAbstract (entry: BibTeXEntry) : string = - try - entry.Properties["abstract"] |> string - with _ -> - "" - -// Helper to parse author list from JSON element -let getAuthorsFromJson (authorsElement: JsonElement option) : string = - match authorsElement with - | None -> "" - | Some elem when elem.ValueKind = JsonValueKind.Array -> - let authors = - elem.EnumerateArray() - |> Seq.choose (fun authorElem -> - match getJsonObject authorElem "name" with - | Some nameElem when nameElem.ValueKind = JsonValueKind.String -> Some(nameElem.GetString()) - | _ -> - if authorElem.ValueKind = JsonValueKind.String then - Some(authorElem.GetString()) - else - None) - |> Seq.toList - - match authors with - | [] -> "" - | [ last ] -> last - | list -> - let lastAuthor = List.last list - let otherAuthors = List.take (List.length list - 1) list - (String.concat ", " otherAuthors) + " and " + lastAuthor - | Some elem when elem.ValueKind = JsonValueKind.String -> elem.GetString() - | _ -> "" - -let extractCitation (quartoJson: JsonElement) (repo: Repository) : Result = - try - let hasMetadataFields (elem: JsonElement) = - (elem.TryGetProperty("title") |> fst) - || (elem.TryGetProperty("author") |> fst) - || (elem.TryGetProperty("authors") |> fst) - || (elem.TryGetProperty("citation") |> fst) - || (elem.TryGetProperty("formats") |> fst) - - let tryGetMetadataFromElement (elem: JsonElement) = - if hasMetadataFields elem then - Some elem - else - match getJsonObject elem "metadata" with - | Some md when hasMetadataFields md -> Some md - | _ -> None - - let preferIndex (candidates: (string * JsonElement) list) = - candidates - |> List.tryFind (fun (name, _) -> name.EndsWith("index.qmd")) - |> Option.orElse (candidates |> List.tryHead) - - match tryGetMetadataFromElement quartoJson with - | Some rootMetadata -> Ok rootMetadata - | None -> - // If config itself holds metadata (common when metadata is only in _quarto.yml) - match getJsonObject quartoJson "config" |> Option.bind tryGetMetadataFromElement with - | Some cfg -> Ok cfg - | None -> - match getJsonObject quartoJson "fileInformation" with - | Some fileInfo -> - let candidates = - fileInfo.EnumerateObject() - |> Seq.choose (fun p -> - match tryGetMetadataFromElement p.Value with - | Some md -> Some(p.Name, md) - | None -> None) - |> Seq.toList - - match preferIndex candidates with - | Some(_, md) -> Ok md - | None -> - // Fallback: check 'files' array entries that may carry metadata - let fileMetadata = - getJsonArray quartoJson "files" - |> Seq.choose (fun f -> - match getJsonObject f "metadata" with - | Some md when tryGetMetadataFromElement md |> Option.isSome -> - Some(getJsonString f "path", md) - | Some md -> Some(getJsonString f "path", md) - | _ -> None) - |> Seq.toList - - match preferIndex fileMetadata with - | Some(_, md) -> Ok md - | None -> - // Check config.metadata (e.g., project-level metadata in _quarto.yml) - match - getJsonObject quartoJson "config" - |> Option.bind (fun c -> getJsonObject c "metadata") - with - | Some cfgMeta when tryGetMetadataFromElement cfgMeta |> Option.isSome -> Ok cfgMeta - | _ -> - let sampleInfo = - getJsonObject quartoJson "fileInformation" - |> Option.bind (fun fi -> - fi.EnumerateObject() |> Seq.tryHead |> Option.map (fun p -> p.Value)) - |> Option.map (fun v -> System.Text.Json.JsonSerializer.Serialize(v)) - |> Option.defaultValue "" - - let keys = - quartoJson.EnumerateObject() |> Seq.map (fun p -> p.Name) |> String.concat ", " - - Error - $"No metadata found. Available keys: {keys}. Sample fileInformation entry: {sampleInfo}" - | None -> - let keys = - quartoJson.EnumerateObject() |> Seq.map (fun p -> p.Name) |> String.concat ", " - - Error $"No metadata found. Available keys: {keys}" - with e -> - Error $"Error extracting citation from quarto inspect for {repo.Name}: {e.Message}" - -let getBibTeXFromRepo (repo: Repository) : string = - match repo.Homepage with - | null - | "" -> "" - | homepage -> - getBibTeX homepage - |> function - | Ok a -> DrBiber.DirtyParser.bibTeXToString [ a ] - | Error e -> - printfn "Error getting BibTeX from %s: %s" repo.Name e - "" - -let getAbstractFromRepo (repo: Repository) : string = - match repo.Homepage with - | null - | "" -> "" - | homepage -> - getBibTeX homepage - |> Result.map (fun bibTeX -> getAbstract bibTeX) - |> function - | Ok a -> a - | Error e -> - printfn "Error getting abstract from %s: %s" repo.Name e - "" - -// Run quarto inspect on a repository -let runQuartoInspect (repoPath: string) : Task> = - task { - try - let startTime = System.DateTime.Now - let tempDir = System.IO.Path.GetTempPath() - - let outputFile = - System.IO.Path.Combine(tempDir, $"quarto-inspect-{System.Guid.NewGuid()}.json") - - // Run quarto inspect and capture output - let processInfo = System.Diagnostics.ProcessStartInfo() - processInfo.FileName <- "quarto" - processInfo.Arguments <- $"inspect \"{repoPath}\" \"{outputFile}\"" - processInfo.RedirectStandardOutput <- true - processInfo.RedirectStandardError <- true - processInfo.UseShellExecute <- false - processInfo.CreateNoWindow <- true - - printfn " Starting quarto inspect process..." - use proc = System.Diagnostics.Process.Start(processInfo) - do! proc.WaitForExitAsync() - printfn " Quarto inspect process completed in %A" (System.DateTime.Now - startTime) - - if proc.ExitCode <> 0 then - let error = proc.StandardError.ReadToEnd() - let output = proc.StandardOutput.ReadToEnd() - - // Check if it's a "not a Quarto project" error - this is expected for non-Quarto repos - if error.Contains("not a Quarto project") then - return Error $"Not a Quarto project (this is expected)" - else - return Error $"quarto inspect failed (exit code {proc.ExitCode}): {error} {output}" - else if System.IO.File.Exists(outputFile) then - // Read the output JSON file - let json = System.IO.File.ReadAllText(outputFile) - System.IO.File.Delete(outputFile) - - let doc = JsonDocument.Parse(json) - return Ok doc.RootElement - else - return Error $"quarto inspect output file not found at {outputFile}" - with e -> - return Error $"Error running quarto inspect: {e.Message}" - } - -let getQuartoFilePathsViaGitTree (owner: string) (repo: string) (defaultBranch: string) : Task = - task { - try - let! reference = - client.Git.Reference.Get(owner, repo, $"heads/{defaultBranch}") - |> Async.AwaitTask - - let sha = reference.Object.Sha - let! tree = client.Git.Tree.GetRecursive(owner, repo, sha) |> Async.AwaitTask - - let quartoFiles = - tree.Tree - |> Seq.filter (fun item -> item.Type.Value = TreeType.Blob) - |> Seq.map (fun item -> item.Path) - |> Seq.filter (fun path -> path.EndsWith(".qmd") || path.EndsWith(".yml") || path.EndsWith(".yaml")) - |> Seq.toList - - return quartoFiles - with _ -> - return [] - } - -let getPublishedRepoContent - (repo: Repository) - : Task option, string>> = - task { - try - let startTime = System.DateTime.Now - printfn " Processing repo: %s" repo.Name - - // Create a temporary directory for this repo with unique identifier - let uniqueId = System.Guid.NewGuid().ToString().Substring(0, 8) - - let tempDir = - System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"{repo.Name}-{uniqueId}") - - // Clean up any existing directory first - try - if System.IO.Directory.Exists(tempDir) then - System.IO.Directory.Delete(tempDir, true) - with _ -> - () - - System.IO.Directory.CreateDirectory(tempDir) |> ignore - - printfn " [%s] Fetching repository content via API..." (System.DateTime.Now.ToString("HH:mm:ss")) - - // Get all Quarto file paths via Git tree (fast, no recursion) - let! quartoFiles = getQuartoFilePathsViaGitTree repo.Owner.Login repo.Name repo.DefaultBranch - - if quartoFiles.IsEmpty then - printfn " [%s] ⚠ No Quarto files found, skipping" (System.DateTime.Now.ToString("HH:mm:ss")) - - try - System.IO.Directory.Delete(tempDir, true) - with _ -> - () - - return Error $"No Quarto files found in {repo.Name}" - else - printfn - " [%s] Found %d Quarto files, downloading..." - (System.DateTime.Now.ToString("HH:mm:ss")) - quartoFiles.Length - - // Download each Quarto file - let mutable downloadedCount = 0 - let mutable firstQmdPath: string option = None - - for path in quartoFiles do - try - let! rawBytes = - client.Repository.Content.GetRawContent(repo.Owner.Login, repo.Name, path) - |> Async.AwaitTask - - let localPath = System.IO.Path.Combine(tempDir, path) - let localDir = System.IO.Path.GetDirectoryName(localPath) - - if not (System.String.IsNullOrEmpty(localDir)) then - System.IO.Directory.CreateDirectory(localDir) |> ignore - - System.IO.File.WriteAllBytes(localPath, rawBytes) - - if localPath.EndsWith(".qmd") && firstQmdPath.IsNone then - firstQmdPath <- Some localPath - - downloadedCount <- downloadedCount + 1 - with ex -> - printfn - " [%s] Warning: Could not download %s: %s" - (System.DateTime.Now.ToString("HH:mm:ss")) - path - ex.Message - - let downloadElapsed = System.DateTime.Now - startTime - - printfn - " [%s] Downloaded %d files (%A elapsed)" - (System.DateTime.Now.ToString("HH:mm:ss")) - downloadedCount - downloadElapsed - - if downloadedCount = 0 then - try - System.IO.Directory.Delete(tempDir, true) - with _ -> - () - - return Error $"Could not download any Quarto files from {repo.Name}" - else - let frontMatter = - match firstQmdPath with - | Some p -> tryParseFrontMatter p - | None -> None - - // Run quarto inspect on the repo - printfn " [%s] Running quarto inspect..." (System.DateTime.Now.ToString("HH:mm:ss")) - let! quartoResult = runQuartoInspect tempDir - - // Clean up - try - System.IO.Directory.Delete(tempDir, true) - with _ -> - () - - match quartoResult with - | Ok json -> - let elapsed = System.DateTime.Now - startTime - - printfn - " [%s] ✓ Successfully inspected (total: %A)" - (System.DateTime.Now.ToString("HH:mm:ss")) - elapsed - - return Ok(json, repo, frontMatter) - | Error e -> - printfn " [%s] ✗ Quarto inspect error: %s" (System.DateTime.Now.ToString("HH:mm:ss")) e - return Error e - with e -> - printfn " [%s] ✗ Exception: %s" (System.DateTime.Now.ToString("HH:mm:ss")) e.Message - return Error $"Error processing repo {repo.Name}: {e.Message}" - } - -let getReposContents filter repos = - repos - |> List.ofSeq - |> List.filter filter - |> fun filtered -> - printfn "[2/5] Processing %d repositories..." filtered.Length - filtered - |> List.map (getPublishedRepoContent >> Async.AwaitTask) - |> Async.Parallel - |> Async.RunSynchronously - |> Array.toList - - -let publishedRepos: Result<(JsonElement * Repository * Map option), string> list = - repos |> getReposContents (fun r -> r.Name |> publishedRe.IsMatch) - -printfn "" -printfn "[3/5] Extracting citation structures..." - -// Publication record used for YAML and RSS outputs -type Publication = - { title: string - name: string - authors: string - journal: string - doi: string - year: int - date: string - description: string - ``abstract``: string - repo: string - bibtex: string - pdf: string - url: string - draft: string } - -let getCitationStructure (result: Result option, string>) = - result - |> Result.mapError (fun e -> $"Error getting citation structure: {e}") - |> Result.bind (fun (quartoJson, repo, frontMatter) -> - try - match extractCitation quartoJson repo with - | Ok metadata -> - let dateStr = getJsonString metadata "date" - - let dateTime = - if dateStr = "last-modified" || dateStr = "" then - System.DateTime.Now - else - try - System.DateTime.Parse(dateStr) - with _ -> - System.DateTime.Now - - let title = getJsonString metadata "title" - - let repoName = - let fromMeta = getJsonString metadata "repo" - - if System.String.IsNullOrWhiteSpace(fromMeta) then - repo.Name - else - fromMeta - - let description = getJsonString metadata "description" - - let draft = - let raw = getJsonString metadata "draft" - - if System.String.IsNullOrWhiteSpace(raw) then - "false" - elif raw.Equals("true", System.StringComparison.OrdinalIgnoreCase) then - "true" - elif raw.Equals("false", System.StringComparison.OrdinalIgnoreCase) then - "false" - else - raw.ToLowerInvariant() - - let authors = - let primary = getAuthorsFromJson (getJsonObject metadata "author") - - if System.String.IsNullOrWhiteSpace(primary) then - getAuthorsFromJson (getJsonObject metadata "authors") - else - primary - - let citationObj = getJsonObject metadata "citation" - - let journal = - citationObj - |> Option.bind (fun c -> getJsonObject c "container-title") - |> Option.map (fun j -> j.GetString()) - |> Option.defaultValue "" - - let doi = - citationObj - |> Option.bind (fun c -> getJsonObject c "doi") - |> Option.map (fun d -> d.GetString()) - |> Option.defaultValue "" - - let pdfUrl = - citationObj - |> Option.bind (fun c -> getJsonObject c "pdf-url") - |> Option.map (fun p -> p.GetString()) - |> Option.defaultValue "" - - let bibtexFromMeta = - citationObj - |> Option.bind (fun c -> - let b1 = getJsonString c "bibtex" - let b2 = getJsonString c "citation-entry" - - if not (System.String.IsNullOrWhiteSpace b1) then Some b1 - elif not (System.String.IsNullOrWhiteSpace b2) then Some b2 - else None) - |> Option.defaultValue "" - - let bibtex = - if bibtexFromMeta <> "" then - bibtexFromMeta - else - getBibTeXFromRepo repo - - if draft = "true" then - printfn " [DRAFT] %s" title - else - printfn " [PUBLISHED] %s" title - - { title = title - name = title - authors = authors - journal = journal - doi = doi - year = dateTime.Year - date = dateTime.ToString("yyyy-MM-dd") - description = description - ``abstract`` = getAbstractFromRepo repo - repo = repoName - bibtex = bibtex - pdf = pdfUrl - url = computoUrl + repoName - draft = draft } - |> Ok - | Error _ -> - // Fallback to front matter if available - match frontMatter with - | None -> Error "No metadata found" - | Some fm -> - let tryGet key = - fm |> Map.tryFind key |> Option.defaultValue "" - - let title = tryGet "title" - let authors = tryGet "author" - let dateStr = tryGet "date" - - let dateTime = - if dateStr = "" then - System.DateTime.Now - else - try - System.DateTime.Parse(dateStr) - with _ -> - System.DateTime.Now - - let bibtex = tryGet "bibtex" - let desc = tryGet "description" - - { title = title - name = title - authors = authors - journal = "" - doi = "" - year = dateTime.Year - date = dateTime.ToString("yyyy-MM-dd") - description = desc - ``abstract`` = "" - repo = repo.Name - bibtex = if bibtex = "" then getBibTeXFromRepo repo else bibtex - pdf = "" - url = computoUrl + repo.Name - draft = "true" } - |> Ok - with e -> - Error $"Error processing citation structure for {repo.Name}: {e.Message}") - -let serializer = - let options = JsonSerializerOptions() - options.DefaultIgnoreCondition <- JsonIgnoreCondition.WhenWritingNull - options.WriteIndented <- true - options - -let publishedYML = - publishedRepos - |> List.map getCitationStructure - |> List.choose (function - | Ok d -> Some d - | Error e -> - // Suppress "not a Quarto project" errors as they're expected - if not (e.Contains("Not a Quarto project")) then - printfn " ✗ Error: %s" e - - None) - |> List.sortBy _.date - |> List.rev - |> List.partition (fun d -> d.draft = "true") - -printfn "" -printfn "[4/5] Writing output files..." - -// Partition results -let drafts = publishedYML |> fst -let publishedOnly = publishedYML |> snd -let draftCount = drafts |> List.length -let publishedCount = publishedOnly |> List.length - -printfn " Found %d published and %d draft papers" publishedCount draftCount - -// Serialize to YAML using YamlDotNet -let serializeToYaml (items: seq) = - let serializer = - SerializerBuilder() - .WithNamingConvention(CamelCaseNamingConvention.Instance) - .ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull) - .Build() - - serializer.Serialize(items) - -publishedOnly -|> serializeToYaml -|> (fun n -> - let path = Path.Combine(repoRoot, "site", "published.yml") - File.WriteAllText(path, n) - printfn " ✓ Wrote %s (%d published papers)" path publishedCount) - -let pipelinePath = Path.Combine(repoRoot, "site", "pipeline.yml") - -if draftCount = 0 then - File.WriteAllText(pipelinePath, "[]\n") - printfn " ✓ Wrote %s (%d draft papers)" pipelinePath draftCount -else - drafts - |> serializeToYaml - |> (fun n -> - File.WriteAllText(pipelinePath, n) - printfn " ✓ Wrote %s (%d draft papers)" pipelinePath draftCount) - -// Generate RSS (top 10 most recent published) -let xmlEscape (s: string) = - s.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace("\"", """).Replace("'", "'") - -let formatRssDate (s: string) = - try - System.DateTime.Parse(s).ToString("r") - with _ -> - System.DateTime.Now.ToString("r") - -let rssContent = - let items = publishedOnly |> List.truncate 10 - let sb = StringBuilder() - sb.AppendLine("") |> ignore - sb.AppendLine("") |> ignore - sb.AppendLine("") |> ignore - sb.AppendLine(" Computo Journal - Recent Articles") |> ignore - sb.AppendLine($" {computoUrl}") |> ignore - - sb.AppendLine(" Latest published articles from Computo Journal") - |> ignore - - sb.AppendLine(" getcomputo-pub.fsx") |> ignore - - for item in items do - let desc = - if item.``abstract`` <> "" then - item.``abstract`` - else - item.description - - let titleWithAuthors = - if System.String.IsNullOrWhiteSpace(item.authors) then - item.title - else - item.title + " — " + item.authors - - sb.AppendLine(" ") |> ignore - sb.AppendLine($" {xmlEscape titleWithAuthors}") |> ignore - sb.AppendLine($" {xmlEscape item.url}") |> ignore - sb.AppendLine($" {xmlEscape item.url}") |> ignore - sb.AppendLine($" {formatRssDate item.date}") |> ignore - - if desc <> "" then - sb.AppendLine($" {xmlEscape desc}") |> ignore - - sb.AppendLine(" ") |> ignore - - sb.AppendLine("") |> ignore - sb.AppendLine("") |> ignore - sb.ToString() - -let rssPath = Path.Combine(repoRoot, "site", "published.xml") -File.WriteAllText(rssPath, rssContent) -printfn " ✓ Wrote %s (10 most recent)" rssPath - -printfn "" -printfn "[5/5] Processing mock papers..." - -repos -|> getReposContents (fun r -> r.Name.StartsWith("published-paper")) -|> List.map getCitationStructure -|> List.choose (function - | Ok d -> Some d - | Error e -> - // Suppress "not a Quarto project" errors as they're expected - if not (e.Contains("Not a Quarto project")) then - printfn " ✗ Error: %s" e - - None) -|> fun mockPapers -> - let count = List.length mockPapers - printfn " Found %d mock papers" count - mockPapers -|> serializeToYaml -|> (fun n -> - let path = Path.Combine(repoRoot, "site", "mock-papers.yml") - File.WriteAllText(path, n) - printfn " ✓ Wrote %s" path) - -printfn "" -printfn "================================================" -printfn "✓ Script completed successfully!" -printfn "================================================" diff --git a/src/paket.references b/src/paket.references deleted file mode 100644 index 2b3a086..0000000 --- a/src/paket.references +++ /dev/null @@ -1,4 +0,0 @@ -group Build -Fake.Core.Target -Fake.DotNet.Cli -Fake.IO.FileSystem diff --git a/src/quarto-inspect-document-json-schema.json b/src/quarto-inspect-document-json-schema.json deleted file mode 100644 index 6e63e83..0000000 --- a/src/quarto-inspect-document-json-schema.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "additionalProperties": false, - "properties": { - "quarto": { - "type": "object", - "additionalProperties": false, - "properties": { - "version": { "type": "string" } - }, - "description": "The version of Quarto used to inspect the document" - }, - "engines": { - "type": "array", - "items": { "type": "string" }, - "description": "The engines used in the document" - }, - "formats": { - "type": "object", - "properties": {}, - "additionalProperties": false, - "description": "An object representing the formats used in the document (keys) and their configuration (values)" - }, - "resources": { - "type": "array", - "items": { "type": "string" }, - "description": "The resource files explicitly provided in the document" - }, - "fileInformation": { - "type": "object", - "properties": {}, - "additionalProperties": false - }, - "project": { - "type": "object", - "description": "Project inspection payload (kept inline for FSharp.Data schema compatibility)", - "properties": {}, - "additionalProperties": false - } - } -} \ No newline at end of file diff --git a/src/quarto-inspect-project-json-schema.json b/src/quarto-inspect-project-json-schema.json deleted file mode 100644 index 189af03..0000000 --- a/src/quarto-inspect-project-json-schema.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "title": "Project Information", - "description": "Information about a Quarto project", - "properties": { - "quarto": { - "type": "object", - "properties": { - "version": { "type": "string" } - } - }, - "dir": { - "type": "string", - "description": "The path of the project directory" - }, - "engines": { - "type": "array", - "items": { "type": "string" }, - "description": "The engines used in the project" - }, - "config": { - "type": "object", - "description": "Resolved project configuration in JSON format" - }, - "files": { - "type": "object", - "properties": { - "input": { - "type": "array", - "items": { "type": "string" }, - "description": "The input files in the project" - }, - "resources": { - "type": "array", - "items": { "type": "string" }, - "description": "The resource files explicitly provided in the project" - }, - "configResources": { - "type": "array", - "items": { "type": "string" }, - "description": "The resource files implied by the project configuration" - }, - "config": { - "type": "array", - "items": { "type": "string" }, - "description": "The configuration files in the project" - } - } - }, - "fileInformation": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "includeMap": { - "type": "array", - "items": { - "type": "object", - "properties": { - "source": { "type": "string" }, - "target": { "type": "string" } - } - } - }, - "codeCells": { - "type": "array", - "items": { - "type": "object", - "properties": { - "start": { "type": "integer" }, - "end": { "type": "integer" }, - "file": { "type": "string" }, - "source": { "type": "string" }, - "language": { "type": "string" }, - "metadata": { "type": "object" } - } - } - } - } - } - }, - "extensions": { "type": "array", "items": { "type": "object" } } - } -} \ No newline at end of file diff --git a/src/reorganize-posts.fsx b/src/reorganize-posts.fsx deleted file mode 100755 index f5c1260..0000000 --- a/src/reorganize-posts.fsx +++ /dev/null @@ -1,53 +0,0 @@ -#r "nuget: Microsoft.Extensions.FileSystemGlobbing" -#r "nuget: YamlDotNet" - -open System.IO -open Microsoft.Extensions.FileSystemGlobbing -open YamlDotNet.Serialization -open System.Collections.Generic - -let blogDir = "blog" - -let deserializer = DeserializerBuilder().Build() - -let extractDate: string -> string = - deserializer.Deserialize> - >> (fun x -> x["date"] :?> string) - -let extractFrontMatter = - File.ReadAllText - >> _.Split("---\n") - >> function - | [| _; frontMatter; content |] -> frontMatter, content - | _ -> "", "" - -let addDatetoDirNameAndRenameIt dir (fileName: string) = - let date = fileName |> extractFrontMatter |> fst |> extractDate - let dirName = Path.GetRelativePath(dir, Path.GetDirectoryName(fileName)) - let newDirName = Path.Combine(dir, date + "-" + dirName) - let oldDirName = Path.Combine(dir, dirName) - printfn "Renaming %s to %s" oldDirName newDirName - Directory.Move(oldDirName, newDirName) - -let matcher = Matcher() -matcher.AddInclude("*/*.qmd") - - -blogDir -|> matcher.GetResultsInFullPath -|> Seq.iter (addDatetoDirNameAndRenameIt blogDir) - - -let newsDir = "news" -let serializer = SerializerBuilder().Build() - - -newsDir -|> matcher.GetResultsInFullPath -|> Seq.map ( - extractFrontMatter - >> (fun (f, c) -> [ ("date", extractDate f); ("description", c) ] |> Map) -) -|> Seq.sortBy (fun x -> x.["date"]) -|> serializer.Serialize -|> (fun n -> File.WriteAllText(Path.Combine("site", "news.yml"), n)) diff --git a/uv.lock b/uv.lock deleted file mode 100644 index 21e9e18..0000000 --- a/uv.lock +++ /dev/null @@ -1,31 +0,0 @@ -version = 1 -revision = 1 -requires-python = ">=3.13" - -[[package]] -name = "computorg-github-io" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "pyyaml" }, -] - -[package.metadata] -requires-dist = [{ name = "pyyaml", specifier = ">=6.0.2" }] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, -]