diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 2431f00..0b38dc8 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -68,7 +68,8 @@ jobs: dotnet build samples/ContractApi --configuration Release dotnet run --project JsonApiToolkit.TypeGen --configuration Release --no-build -- \ --assembly samples/ContractApi/bin/Release/net10.0/ContractApi.dll \ - --out samples/ContractApi/api-types.gen.ts --check + --out samples/ContractApi/api-types.gen.ts \ + --client-import ../../clients/typescript/src/index.ts --check status: name: Build and Test @@ -83,11 +84,11 @@ jobs: exit 1 publish: - if: github.event_name == 'release' + if: github.event_name == 'release' && !startsWith(github.event.release.tag_name, 'typescript-') runs-on: ubuntu-latest permissions: contents: read - id-token: write # OIDC token for NuGet trusted publishing + id-token: write steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -100,10 +101,14 @@ jobs: - name: Restore run: dotnet restore --locked-mode - - name: Build and Pack + - name: Build and Pack JsonApiToolkit + if: ${{ !startsWith(github.event.release.tag_name, 'typegen-') }} run: dotnet pack JsonApiToolkit/JsonApiToolkit.csproj -c Release --no-restore - # Exchange OIDC token for a short-lived NuGet API key + - name: Build and Pack JsonApiToolkit.TypeGen + if: startsWith(github.event.release.tag_name, 'typegen-') + run: dotnet pack JsonApiToolkit.TypeGen/JsonApiToolkit.TypeGen.csproj -c Release --no-restore + - name: NuGet login id: login uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0 @@ -111,7 +116,7 @@ jobs: user: ${{ secrets.NUGET_USER }} - name: Publish to NuGet.org - run: dotnet nuget push "JsonApiToolkit/bin/Release/*.nupkg" + run: dotnet nuget push "JsonApiToolkit*/bin/Release/*.nupkg" --source https://api.nuget.org/v3/index.json --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --skip-duplicate diff --git a/.github/workflows/next-snapshot.yml b/.github/workflows/next-snapshot.yml new file mode 100644 index 0000000..6ebd26b --- /dev/null +++ b/.github/workflows/next-snapshot.yml @@ -0,0 +1,120 @@ +name: Next Snapshot + +on: + push: + branches: + - next + +concurrency: + group: next-snapshot + cancel-in-progress: false + +jobs: + changes: + name: Detect changes + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + toolkit: ${{ steps.filter.outputs.toolkit }} + typegen: ${{ steps.filter.outputs.typegen }} + typescript: ${{ steps.filter.outputs.typescript }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 + id: filter + with: + base: ${{ github.ref_name }} + filters: | + toolkit: + - 'JsonApiToolkit/**' + - 'Directory.Build.props' + typegen: + - 'JsonApiToolkit.TypeGen/**' + - 'Directory.Build.props' + typescript: + - 'clients/typescript/**' + + dotnet: + name: Publish .NET Snapshot + needs: changes + if: needs.changes.outputs.toolkit == 'true' || needs.changes.outputs.typegen == 'true' + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Setup .NET + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 + with: + dotnet-version: 10.0.x + + - name: Restore + run: dotnet restore --locked-mode + + - name: Test + run: dotnet test --configuration Release --verbosity normal --no-restore + + - name: Pack JsonApiToolkit + if: needs.changes.outputs.toolkit == 'true' + run: | + BASE=$(sed -n 's:.*\(.*\).*:\1:p' JsonApiToolkit/JsonApiToolkit.csproj) + IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE" + dotnet pack JsonApiToolkit/JsonApiToolkit.csproj -c Release --no-restore \ + -p:Version="$MAJOR.$MINOR.$((PATCH + 1))-next.${{ github.run_number }}" + + - name: Pack JsonApiToolkit.TypeGen + if: needs.changes.outputs.typegen == 'true' + run: | + BASE=$(sed -n 's:.*\(.*\).*:\1:p' JsonApiToolkit.TypeGen/JsonApiToolkit.TypeGen.csproj) + IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE" + dotnet pack JsonApiToolkit.TypeGen/JsonApiToolkit.TypeGen.csproj -c Release --no-restore \ + -p:Version="$MAJOR.$MINOR.$((PATCH + 1))-next.${{ github.run_number }}" + + - name: NuGet login + id: login + uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0 + with: + user: ${{ secrets.NUGET_USER }} + + - name: Publish to NuGet.org + run: dotnet nuget push "JsonApiToolkit*/bin/Release/*.nupkg" + --source https://api.nuget.org/v3/index.json + --api-key ${{ steps.login.outputs.NUGET_API_KEY }} + --skip-duplicate + + typescript: + name: Publish TypeScript Snapshot + needs: changes + if: needs.changes.outputs.typescript == 'true' + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + defaults: + run: + working-directory: clients/typescript + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Setup Deno + uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2 + with: + deno-version: v2.x + + - name: Test + run: deno task test + + - name: Set Snapshot Version + run: | + BASE=$(jq -r .version deno.json) + IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE" + jq --arg v "$MAJOR.$MINOR.$((PATCH + 1))-next.${{ github.run_number }}" \ + '.version = $v' deno.json > deno.json.tmp + mv deno.json.tmp deno.json + + - name: Publish to JSR + run: deno publish --allow-dirty diff --git a/.github/workflows/typescript-release.yml b/.github/workflows/typescript-release.yml new file mode 100644 index 0000000..57a8918 --- /dev/null +++ b/.github/workflows/typescript-release.yml @@ -0,0 +1,35 @@ +name: TypeScript Release + +on: + release: + types: [published] + +concurrency: + group: ts-release-${{ github.ref }} + cancel-in-progress: false + +defaults: + run: + working-directory: clients/typescript + +jobs: + publish: + if: startsWith(github.event.release.tag_name, 'typescript-v') + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Checkout Repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Setup Deno + uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2 + with: + deno-version: v2.x + + - name: Test + run: deno task test + + - name: Publish to JSR + run: deno publish diff --git a/JsonApiToolkit.TypeGen.Tests/CliIntegrationTests.cs b/JsonApiToolkit.TypeGen.Tests/CliIntegrationTests.cs index ff78c48..9fe43cb 100644 --- a/JsonApiToolkit.TypeGen.Tests/CliIntegrationTests.cs +++ b/JsonApiToolkit.TypeGen.Tests/CliIntegrationTests.cs @@ -26,9 +26,11 @@ public void Run_resolves_JsonApiResource_types_from_a_separately_built_assembly( Assert.Contains("export interface Author", generated); Assert.Contains("export interface Comment", generated); Assert.Contains( - "Article: { type: \"articles\", relationships: [\"author\", \"comments\"] }", + "export const Article: JsonApiResourceDescriptor
= {", generated ); + Assert.Contains(" toOne: [\"author\"],", generated); + Assert.Contains(" toMany: [\"comments\"],", generated); // --check passes right after generation... Assert.Equal( diff --git a/JsonApiToolkit.TypeGen.Tests/TypeScriptEmitterTests.cs b/JsonApiToolkit.TypeGen.Tests/TypeScriptEmitterTests.cs index ddf15de..3f09fa1 100644 --- a/JsonApiToolkit.TypeGen.Tests/TypeScriptEmitterTests.cs +++ b/JsonApiToolkit.TypeGen.Tests/TypeScriptEmitterTests.cs @@ -51,15 +51,27 @@ public void Generate_maps_attributes_and_relationships_and_skips_unmapped_types( (typeof(Part), "parts"), }; - var ts = TypeScriptEmitter.Generate(resources); + var ts = TypeScriptEmitter.Generate(resources, "@intility/json-api-client"); + Assert.Contains( + "import type { JsonApiResourceDescriptor } from \"@intility/json-api-client\";", + ts + ); Assert.Contains("description: string | null;", ts); Assert.Contains("retiredAt: string | null;", ts); Assert.Contains("tags: string[];", ts); Assert.Contains("ownerId: number;", ts); Assert.Contains("owner: Owner | null;", ts); Assert.Contains("parts: Part[];", ts); - Assert.Contains("Widget: { type: \"widgets\", relationships: [\"owner\", \"parts\"] }", ts); + + Assert.Contains("export const Widget: JsonApiResourceDescriptor = {", ts); + Assert.Contains(" type: \"widgets\",", ts); + Assert.Contains( + " attributes: [\"name\", \"description\", \"retiredAt\", \"tags\", \"ownerId\"],", + ts + ); + Assert.Contains(" toOne: [\"owner\"],", ts); + Assert.Contains(" toMany: [\"parts\"],", ts); // UnmappedThing has no [JsonApiResource]: the property is dropped, not guessed at. Assert.DoesNotContain("extra", ts); diff --git a/JsonApiToolkit.TypeGen/Cli.cs b/JsonApiToolkit.TypeGen/Cli.cs index b128c8d..f615e59 100644 --- a/JsonApiToolkit.TypeGen/Cli.cs +++ b/JsonApiToolkit.TypeGen/Cli.cs @@ -14,6 +14,7 @@ public static int Run(string[] args) { string? assemblyPath = null; string? outPath = null; + string clientImport = "@intility/json-api-client"; bool check = false; for (int i = 0; i < args.Length; i++) @@ -26,6 +27,9 @@ public static int Run(string[] args) case "--out": outPath = args[++i]; break; + case "--client-import": + clientImport = args[++i]; + break; case "--check": check = true; break; @@ -38,7 +42,8 @@ public static int Run(string[] args) if (assemblyPath is null || outPath is null) { Console.Error.WriteLine( - "Usage: jsonapi-typegen --assembly --out [--check]" + "Usage: jsonapi-typegen --assembly --out " + + "[--client-import ] [--check]" ); return 1; } @@ -61,7 +66,7 @@ public static int Run(string[] args) return 1; } - string generated = TypeScriptEmitter.Generate(resources); + string generated = TypeScriptEmitter.Generate(resources, clientImport); if (check) { diff --git a/JsonApiToolkit.TypeGen/JsonApiToolkit.TypeGen.csproj b/JsonApiToolkit.TypeGen/JsonApiToolkit.TypeGen.csproj index 0bab50d..d3b4df2 100644 --- a/JsonApiToolkit.TypeGen/JsonApiToolkit.TypeGen.csproj +++ b/JsonApiToolkit.TypeGen/JsonApiToolkit.TypeGen.csproj @@ -9,12 +9,22 @@ jsonapi-typegen Intility.JsonApiToolkit.TypeGen JsonApiToolkit TypeGen - 2.1.8 + 0.1.0 Intility Intility Generates TypeScript resource types from [JsonApiResource]-attributed C# models. + jsonapi;json-api;typescript;codegen;dotnet-tool + https://github.com/intility/json-api-toolkit + git + https://github.com/intility/json-api-toolkit + intility-logo.png + README.md MIT + + + +