Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -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"
}
"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"
}
]
}
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand All @@ -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

Expand All @@ -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

Expand Down
4 changes: 3 additions & 1 deletion FSharp.Interop.Dynamic/Dyn.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ namespace FSharp.Interop.Dynamic
/// <c>Direct</c> to invoke <paramref name="target"/> itself.
/// </param>
/// <returns>
/// 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 (<c>InvokeGet</c>) for
/// <c>Member</c> / <c>GenericMember</c>; for <c>Direct</c>, <paramref name="target"/>
/// converted to that type (no get).
/// If the inferred result type is a function, a callable: applying it does a DLR invoke
/// (<c>InvokeMember</c> for a named member, <c>Invoke</c> for <c>Direct</c>).
/// A void CLR method is an <c>unit</c>-returning function.
Expand Down
2 changes: 1 addition & 1 deletion FSharp.Interop.Dynamic/Operators.fsi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace FSharp.Interop.Dynamic
/// <summary>
/// Dynamic DLR binary operators plus an inferred conversion of the result. Not auto-opened; <c>open FSharp.Interop.Dynamic.Operators</c>.
/// Dynamic DLR binary operators. Arithmetic and bitwise operators unbox the DLR result (<c>:?&gt;</c>). Comparisons convert that result to <c>bool</c> with <c>Dyn.explicitConvert</c>. Not auto-opened; <c>open FSharp.Interop.Dynamic.Operators</c>.
/// </summary>
module Operators = begin
/// <summary>Dynamically take modulo of <paramref name="left"/> by <paramref name="right"/>.</summary>
Expand Down
4 changes: 3 additions & 1 deletion FSharp.Interop.Dynamic/TopLevelOperators.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ namespace FSharp.Interop.Dynamic
/// </summary>
/// <param name="target">Callable object to invoke.</param>
/// <returns>
/// The converted invoke result, or a callable if the inferred result type is a function.
/// If the inferred result type is not a function, <paramref name="target"/> converted
/// to that type (no invoke). If it is a function, a callable: applying it invokes
/// <paramref name="target"/>.
/// </returns>
val ( !? ) : target:obj -> 'TResult
end
8 changes: 4 additions & 4 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion docfx/docs/operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ A void CLR method is an `unit`-returning function:

```fsharp
let items = ResizeArray<string>()
items?Add("1")
let _: unit = items?Add("1")
```

## `?<-` — set a named member
Expand Down
10 changes: 5 additions & 5 deletions docfx/docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.
13 changes: 10 additions & 3 deletions docfx/docs/why.md
Original file line number Diff line number Diff line change
@@ -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.

Expand All @@ -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).
Expand Down Expand Up @@ -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)
```
Expand Down
17 changes: 17 additions & 0 deletions docfx/template/public/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down