diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 1dd2836..bb7204f 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -1,10 +1,25 @@
{
- // See https://go.microsoft.com/fwlink/?LinkId=733558
- // for the documentation about the tasks.json format
- "version": "0.1.0",
- "command": "./build.fsx",
- "isShellCommand": true,
- "args": [],
- "showOutput": "always",
- "problemMatcher":"$msCompile"
-}
\ No newline at end of file
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "type": "shell",
+ "command": "dotnet build --configuration Release",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "test",
+ "type": "shell",
+ "command": "dotnet test Tests/Tests.fsproj --configuration Release",
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ },
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bc5b5e0..3466d2f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ Each release has a `## [version]` section. When a `v*.*.*` tag is pushed, the Pu
### Docs
- Caveats document 15-argument `TypeLoadException`, C# optional parameters, and `tryGet` / `exists` on a null target (#110).
+- Copilot leftovers from the 6.0.0 docs pass: why.md examples, operators void `Add`, release checklist, XML docs for `Direct` / `!?` / Operators, DocFX theme alerts and link RGB, SECURITY.md triggers, VS Code task, changelog wording (#114–#126).
## [6.0.0]
@@ -17,7 +18,7 @@ Each release has a `## [version]` section. When a `v*.*.*` tag is pushed, the Pu
### Added
-- `Dyn.tryGet` and `Dyn.exists`: look up a member as `'T option`, or test for it, without throwing (#42, #43).
+- `Dyn.tryGet` and `Dyn.exists`: look up a member as `'T option`, or test for it, without throwing on a missing-member binder exception. Conversion failures and throwing getters still throw (#42, #43, #118).
### Build, security, and docs
@@ -35,7 +36,9 @@ Each release has a `## [version]` section. When a `v*.*.*` tag is pushed, the Pu
## [5.0.0.25] - 2019-09-11
-No release notes were published for this version.
+- Handles more corner cases for dynamic invocation.
+- Rewrite of `Dyn` module functions favoring piping (`|>`).
+- Adds a .NET Standard 2.0 target.
## [4.0.3.130] - 2018-04-05
diff --git a/FSharp.Interop.Dynamic/Dyn.fsi b/FSharp.Interop.Dynamic/Dyn.fsi
index d29aefe..dc0240e 100644
--- a/FSharp.Interop.Dynamic/Dyn.fsi
+++ b/FSharp.Interop.Dynamic/Dyn.fsi
@@ -41,7 +41,9 @@ namespace FSharp.Interop.Dynamic
/// Direct to invoke itself.
///
///
- /// If the inferred result type is not a function, a DLR get converted to that type.
+ /// If the inferred result type is not a function: a DLR get (InvokeGet) for
+ /// Member / GenericMember; for Direct,
+ /// converted to that type (no get).
/// If the inferred result type is a function, a callable: applying it does a DLR invoke
/// (InvokeMember for a named member, Invoke for Direct).
/// A void CLR method is an unit-returning function.
diff --git a/FSharp.Interop.Dynamic/Operators.fsi b/FSharp.Interop.Dynamic/Operators.fsi
index 632837a..af99820 100644
--- a/FSharp.Interop.Dynamic/Operators.fsi
+++ b/FSharp.Interop.Dynamic/Operators.fsi
@@ -1,6 +1,6 @@
namespace FSharp.Interop.Dynamic
///
- /// Dynamic DLR binary operators plus an inferred conversion of the result. Not auto-opened; open FSharp.Interop.Dynamic.Operators.
+ /// Dynamic DLR binary operators. Arithmetic and bitwise operators unbox the DLR result (:?>). Comparisons convert that result to bool with Dyn.explicitConvert. Not auto-opened; open FSharp.Interop.Dynamic.Operators.
///
module Operators = begin
/// Dynamically take modulo of by .
diff --git a/FSharp.Interop.Dynamic/TopLevelOperators.fsi b/FSharp.Interop.Dynamic/TopLevelOperators.fsi
index d9183ae..bcd4196 100644
--- a/FSharp.Interop.Dynamic/TopLevelOperators.fsi
+++ b/FSharp.Interop.Dynamic/TopLevelOperators.fsi
@@ -28,7 +28,9 @@ namespace FSharp.Interop.Dynamic
///
/// Callable object to invoke.
///
- /// The converted invoke result, or a callable if the inferred result type is a function.
+ /// If the inferred result type is not a function, converted
+ /// to that type (no invoke). If it is a function, a callable: applying it invokes
+ /// .
///
val ( !? ) : target:obj -> 'TResult
end
diff --git a/SECURITY.md b/SECURITY.md
index 020c761..dffb0a2 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -96,10 +96,10 @@ required checks below.
| Check | When |
| --- | --- |
| Dependabot | Weekly NuGet and GitHub Actions; 7-day cooldown |
-| OSV-Scanner (full) | `master` only |
-| Scorecard SARIF upload | `master` only |
-| GitHub Pages deploy | `master` only |
-| NuGet publish + Sigstore provenance | Version tags `v*.*.*` only (Trusted Publishing / `NuGet/login`) |
+| OSV-Scanner (full) | Push to `master`, weekly schedule, `workflow_dispatch` |
+| Scorecard SARIF upload | Non-PR events (`master` push, schedule, `workflow_dispatch`) |
+| GitHub Pages deploy | Push to `master` |
+| NuGet publish + Sigstore provenance | Version tags `v*.*.*` and `workflow_dispatch` with a version (Trusted Publishing / `NuGet/login`). `workflow_dispatch` does not create a GitHub release |
Central Package Management (`Directory.Packages.props`) and
`packages.lock.json` pin restore. GitHub Actions `uses:` lines are commit SHAs.
diff --git a/docfx/docs/operators.md b/docfx/docs/operators.md
index 4d3d580..86542b8 100644
--- a/docfx/docs/operators.md
+++ b/docfx/docs/operators.md
@@ -20,7 +20,7 @@ A void CLR method is an `unit`-returning function:
```fsharp
let items = ResizeArray()
-items?Add("1")
+let _: unit = items?Add("1")
```
## `?<-` — set a named member
diff --git a/docfx/docs/releasing.md b/docfx/docs/releasing.md
index 7613c83..a9da30a 100644
--- a/docfx/docs/releasing.md
+++ b/docfx/docs/releasing.md
@@ -17,12 +17,12 @@ git push origin vX.Y.Z
The Publish workflow will:
-1. Extract the `## [6.0.0]` section of `CHANGELOG.md`, and fail if there isn't one
+1. Extract the `## [X.Y.Z]` section of `CHANGELOG.md` for the tagged version, and fail if there isn't one
2. Restore, build `-warnaserror`, test
-3. Pack `FSharp.Interop.Dynamic` at `6.0.0` (nupkg + snupkg)
+3. Pack `FSharp.Interop.Dynamic` at `X.Y.Z` (nupkg + snupkg)
4. Attest SLSA build provenance for the nupkg and snupkg, signed with Sigstore through GitHub's OIDC identity
5. `dotnet nuget push` to nuget.org with `--skip-duplicate`
-6. Create the GitHub release `v6.0.0` with those notes, the packages, and the provenance bundle `FSharp.Interop.Dynamic.6.0.0.intoto.jsonl` attached. A version with a `-` suffix is marked as a prerelease.
+6. Create the GitHub release `vX.Y.Z` with those notes, the packages, and the provenance bundle `FSharp.Interop.Dynamic.X.Y.Z.intoto.jsonl` attached. A version with a `-` suffix is marked as a prerelease.
`workflow_dispatch` with a version input does steps 1–5 without a tag and creates no GitHub release. Prefer the tag.
@@ -31,11 +31,11 @@ The Publish workflow will:
Anyone can check that a package was built by this repository's Publish workflow:
```bash
-gh attestation verify FSharp.Interop.Dynamic.6.0.0.nupkg --repo fsprojects/FSharp.Interop.Dynamic
+gh attestation verify FSharp.Interop.Dynamic.X.Y.Z.nupkg --repo fsprojects/FSharp.Interop.Dynamic
```
Pull requests never publish.
## After it lands
-Update the README / docs callout that nuget.org is still 5.0.1.268. The next patch is `v6.0.1`, not another 5.x.
+Confirm nuget.org lists the new version and that README / getting-started install instructions match it. The next version after 6.0.0 is `v6.0.1` (or `v6.1.0` / `v7.0.0`), not another 5.x.
diff --git a/docfx/docs/why.md b/docfx/docs/why.md
index dd6f9f1..3943f9e 100644
--- a/docfx/docs/why.md
+++ b/docfx/docs/why.md
@@ -1,6 +1,6 @@
# Why this library
-F# has no `dynamic` keyword. C# does. A lot of .NET still hands you objects whose shape is decided at runtime: `ExpandoObject`, `DynamicObject`, COM, pythonnet, SignalR clients, JSON bags deserialized without a type. From F#, without this library, you write a C# helper, sprinkle `:?` casts, or wrap every access in `try/with` on `RuntimeBinderException`.
+F# has no `dynamic` keyword. C# does. A lot of .NET still hands you objects whose shape is decided at runtime: `ExpandoObject`, `DynamicObject`, COM, pythonnet, SignalR clients, JSON bags deserialized without a type. From F#, without this library, you write a C# helper, sprinkle `:?` type tests, or wrap every access in `try/with` on `RuntimeBinderException`.
This library is the F# spelling of that call: `?`, `?<-`, `!?`, and `Dyn.*`, including `tryGet` / `exists` which C# `dynamic` does not have.
@@ -27,8 +27,13 @@ let userId: string = payload?userId
`?` throws `RuntimeBinderException` when the binder cannot find the member. That is the wrong primitive for optional JSON.
```fsharp
-let role: string option = payload |> Dyn.tryGet "role"
-let userId: string option = payload |> Dyn.tryGet "userId"
+open System.Dynamic
+open FSharp.Interop.Dynamic
+
+let payload = ExpandoObject()
+payload?userId <- "u-17"
+let role: string option = payload |> Dyn.tryGet "role" // None
+let userId: string option = payload |> Dyn.tryGet "userId" // Some "u-17"
```
`tryGet` is `None` on a miss and `Some` on a hit, including a present null. A present value that cannot convert to `'T` still throws. See [tryGet and exists](tryget.md).
@@ -69,6 +74,8 @@ pythonnet wraps Python objects as DLR objects. Excel/COM does too. The F# you wr
```fsharp
// Sketch only — pythonnet is not referenced here.
+// open FSharp.Interop.Dynamic
+// open FSharp.Interop.Dynamic.Operators
// np?cos(np?pi ?*? 2)
// np?array([| 6.; 5.; 4. |], Dyn.namedArg "dtype" np?int32)
```
diff --git a/docfx/template/public/main.css b/docfx/template/public/main.css
index adda0de..087037e 100644
--- a/docfx/template/public/main.css
+++ b/docfx/template/public/main.css
@@ -38,6 +38,8 @@
--bs-link-color: var(--fid-cyan-700);
--bs-link-hover-color: var(--fid-cyan-800);
+ --bs-link-color-rgb: 26, 122, 163;
+ --bs-link-hover-color-rgb: 20, 94, 126;
--bs-primary: var(--fid-cyan-700);
--bs-primary-rgb: 26, 122, 163;
@@ -61,6 +63,8 @@
--bs-link-color: #6ec4e4;
--bs-link-hover-color: var(--fid-cyan-300);
+ --bs-link-color-rgb: 110, 196, 228;
+ --bs-link-hover-color-rgb: 126, 200, 232;
--bs-primary: #6ec4e4;
--bs-primary-rgb: 110, 196, 228;
@@ -216,6 +220,11 @@ article table thead th {
border-top: 0;
}
+.NOTE,
+.TIP,
+.WARNING,
+.CAUTION,
+.IMPORTANT,
.alert {
border: 1px solid var(--bs-border-color);
border-left: 3px solid var(--bs-primary);
@@ -224,15 +233,23 @@ article table thead th {
color: var(--bs-body-color);
}
+.WARNING,
+.CAUTION,
.alert.WARNING,
.alert.CAUTION {
border-left-color: #d94f2b;
}
+.IMPORTANT,
.alert.IMPORTANT {
border-left-color: var(--fid-cyan-500);
}
+.NOTE > p:last-child,
+.TIP > p:last-child,
+.WARNING > p:last-child,
+.CAUTION > p:last-child,
+.IMPORTANT > p:last-child,
.alert > p:last-child {
margin-bottom: 0;
}