# fsxpired ## Docs ### [JSON output](/fsxpired/json.md) JSON output --json writes one document to stdout and everything else to stderr, so fsxpired --json | jq never breaks. The shape is not a contract; the exit code is the promise. It mirrors the table with the fields a script needs to act on a reference. { "command": "outdated", "workingDirectory": "/home/me/repo", "exitCode": 1, "error": null, "summary": { "outdated": 1, "floating": 1, "unknown": 0, "updated": 0, "files": 1 }, "files": [ { "path": "build.fsx", "references": [ { "id": "Fun.Build", "line": 3, "version": "1.1.18", "resolved": "1.1.18", "latest": "1.1.20", "status": "outdated", "note": null }, { "id": "Humanizer.Core", "line": 4, "version": null, "resolved": "3.0.10", "latest": "3.0.10", "status": "floating", "note": "no version pinned, resolves to latest on every run" } ] } ] } command is outdated or update. error is always present, null when the run got to a report. When it is set, files is empty and the same message went to stderr. path is relative to workingDirectory, with forward slashes on every platform. version is the text as written, null for a floating reference. resolved is what FSI resolves the reference to today; latest is the newest version it may move to under the run's prerelease rule. Either is null when nuget.org does not know the id. status is one of outdated, current, floating, unknown, updated. ### [Version and prerelease rules](/fsxpired/versions.md) Version and prerelease rules How a version text is read Written as Kind Resolves to -u 1.2.3 exact pin that version rewrites it 6.*, * wildcard the highest match leaves it [1.0.0], [1.0,2.0) range the lowest match, as NuGet does leaves it nothing floating the latest at every run leaves it Versions and ranges are parsed with NuGet.Versioning, so what NuGet accepts, fsxpired accepts. Outdated An exact pin is outdated when a newer version exists that it may move to. Which versions count depends on the prerelease rule: A stable pin is compared against stable versions only. 1.0.0 is up to date when the only newer version is 1.1.0-beta. With -pre / --prerelease, a stable pin is compared against everything, and -u moves it to a prerelease when that is the newest. A prerelease pin is always compared against everything. 8.0.0-beta-001 is outdated once 8.0.0-beta-002 exists, and again once 8.0.0 exists, with no flag needed: the pin already opted in. A range is never outdated. It is shown with what it resolves to today and the latest version that exists, so the gap is visible, and left alone. Update -u replaces the version text of each outdated exact pin with the version it may move to. Only that span changes: spacing, quoting, line endings and the byte order mark stay as written. Files reached through #load are rewritten too. The run without -u is the dry run. ### [fsxpired](/fsxpired/index.md) fsxpired Reports which #r "nuget: ..." references in your F# scripts have a newer version on nuget.org, and updates them when asked. Install Run it once without installing anything (needs the .NET 10 SDK, which ships dnx): dnx fsxpired Or keep it around as a global tool: dotnet tool install -g fsxpired Or as a local tool in a repository that has a dotnet-tools.json: dotnet tool install fsxpired dotnet fsxpired Use fsxpired # every .fsx under the current folder fsxpired build.fsx # one script, and everything it #loads fsxpired scripts docs # files and folders, mixed fsxpired -u # rewrite outdated exact pins in place fsxpired -pre # let stable pins move to prereleases fsxpired --json # one JSON document on stdout, for scripts and agents fsxpired doctor build.fsx # walk one script through every step and say what happened A folder is searched recursively for .fsx files, skipping bin, obj, node_modules, .git and whatever .gitignore excludes. Each script's #load chain is followed, so a helper that holds the references is reported under its own name, once. What the report says One table per file, then a summary line: build.fsx ╭────────────────┬─────────┬────────┬────────────┬────────────────────────────────────────────────────╮ │ Package │ Current │ Latest │ Status │ Note │ ├────────────────┼─────────┼────────┼────────────┼────────────────────────────────────────────────────┤ │ Fun.Build │ 1.1.18 │ 1.1.20 │ outdated │ │ │ FSharp.Data │ 6.3.0 │ 6.3.0 │ up to date │ │ │ Humanizer.Core │ │ 3.0.10 │ floating │ no version pinned, resolves to latest on every run │ ╰────────────────┴─────────┴────────┴────────────┴────────────────────────────────────────────────────╯ 1 outdated, 1 floating in 1 file The Note column only appears when a row has something to say. outdated: a newer version exists that the pin may move to. -u rewrites it. up to date: nothing newer, under the prerelease rule of the run. floating: no version pinned, so it resolves to the latest at every run. Shown in yellow, never counted, never rewritten. unknown: nuget.org does not know the package, or nothing satisfies the range. updated: rewritten by this run. A range or wildcard such as 6.* or [1.0,2.0) is a deliberate choice: it is shown with what it resolves to today, reported as up to date, and left alone by -u. Exit codes Code Meaning 0 Nothing outdated, or every outdated pin was rewritten 1 At least one reference is outdated 2 Unexpected error: unreadable file, missing #load target, nuget.org unreachable, or a directive fsxpired does not support 3 -u could not write a file What stops a run fsxpired stops with exit 2 rather than guess: #i "nuget: ": only nuget.org is queried. A script that adds a feed would get wrong answers, and a wrong "up to date" is worse than none. A version text that is not a NuGet version, such as the {{fsdocs-package-version}} placeholder fsdocs substitutes in literate scripts. If you need either, open an issue. Also Version and prerelease rules JSON output llms.txt and llms-full.txt for agents: the index, and every page in one file.