@contractkit/plugin-csharp 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.turbo/turbo-build$colon$ci.log +13 -0
  2. package/.turbo/turbo-build.log +12 -0
  3. package/.turbo/turbo-format.log +34 -0
  4. package/.turbo/turbo-test.log +17 -0
  5. package/CHANGELOG.md +1 -0
  6. package/LICENSE +21 -0
  7. package/README.md +173 -0
  8. package/dist/codegen-client.d.ts +35 -0
  9. package/dist/codegen-client.d.ts.map +1 -0
  10. package/dist/codegen-models.d.ts +75 -0
  11. package/dist/codegen-models.d.ts.map +1 -0
  12. package/dist/codegen-sdk.d.ts +13 -0
  13. package/dist/codegen-sdk.d.ts.map +1 -0
  14. package/dist/hoist.d.ts +53 -0
  15. package/dist/hoist.d.ts.map +1 -0
  16. package/dist/index.d.ts +30 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +2569 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/naming.d.ts +89 -0
  21. package/dist/naming.d.ts.map +1 -0
  22. package/dist/runtime-converters.d.ts +15 -0
  23. package/dist/runtime-converters.d.ts.map +1 -0
  24. package/dist/runtime.d.ts +10 -0
  25. package/dist/runtime.d.ts.map +1 -0
  26. package/dist/scaffold.d.ts +26 -0
  27. package/dist/scaffold.d.ts.map +1 -0
  28. package/eslint.config.js +6 -0
  29. package/package.json +48 -0
  30. package/src/codegen-client.ts +680 -0
  31. package/src/codegen-models.ts +909 -0
  32. package/src/codegen-sdk.ts +52 -0
  33. package/src/hoist.ts +402 -0
  34. package/src/index.ts +373 -0
  35. package/src/naming.ts +262 -0
  36. package/src/runtime-converters.ts +147 -0
  37. package/src/runtime.ts +381 -0
  38. package/src/scaffold.ts +41 -0
  39. package/tests/codegen-client.test.ts +275 -0
  40. package/tests/codegen-models.test.ts +410 -0
  41. package/tests/helpers.ts +202 -0
  42. package/tests/hoist.test.ts +92 -0
  43. package/tests/index.test.ts +124 -0
  44. package/tests/naming.test.ts +133 -0
  45. package/tests/runtime.test.ts +104 -0
  46. package/tests/scaffold.test.ts +28 -0
  47. package/tsconfig.json +9 -0
  48. package/vitest.config.ts +14 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Identifier and file-name conversions for C# output.
3
+ *
4
+ * Kept separate from the codegen modules because both the model and the client generators need the
5
+ * same conversions, and a mismatch between them would produce a client that references a property
6
+ * name the model never declared.
7
+ */
8
+ /**
9
+ * C#'s reserved keywords — illegal as bare identifiers anywhere, so a name that collides with one
10
+ * has to be escaped with `@`. Contextual keywords (`record`, `required`, `init`, `value`, `var`,
11
+ * `async`, `await`, `yield`, `nameof`, `when`) are legal identifiers and are deliberately absent:
12
+ * escaping them would only make the generated code noisier.
13
+ */
14
+ export declare const CSHARP_KEYWORDS: ReadonlySet<string>;
15
+ /**
16
+ * Prefix `name` with `@` when it is a C# keyword, so it can still be used as a parameter or local.
17
+ * The `@` is a lexical escape only: the identifier is still spelled `name` everywhere it matters,
18
+ * including in `nameof` and in reflection, so nothing downstream has to know about it.
19
+ */
20
+ export declare function escapeCSharpIdentifier(name: string): string;
21
+ /**
22
+ * Convert a contract field name to a C# property name in PascalCase.
23
+ *
24
+ * Separators (`-`, `_`, `.`, spaces) introduce a word boundary and are dropped, so `x-request-id`
25
+ * becomes `XRequestId`. A leading digit gets an underscore prefix, since C# identifiers cannot
26
+ * start with one. No keyword escaping is needed: every C# keyword is lowercase and this always
27
+ * produces an initial capital.
28
+ *
29
+ * The original name is preserved on the wire through `[JsonPropertyName]`, so this conversion is
30
+ * free to be lossy as long as it is deterministic.
31
+ */
32
+ export declare function toCSharpPropertyName(name: string): string;
33
+ /**
34
+ * Convert a contract parameter or path placeholder to a C# parameter name in camelCase:
35
+ * `invoice-id` becomes `invoiceId`. Keyword-escaped, because camelCase lands on keywords
36
+ * regularly — a path parameter named `event` or `params` is ordinary in a contract.
37
+ */
38
+ export declare function toCSharpParameterName(name: string): string;
39
+ /**
40
+ * Make a property name safe inside `ownerTypeName`.
41
+ *
42
+ * C# rejects a member whose name matches its enclosing type (CS0542), which a contract hits
43
+ * whenever a model has a field of its own name — `contract Invoice { invoice: ... }`. A record also
44
+ * synthesizes members that a contract field can collide with. Both are resolved by appending
45
+ * `Value`; the wire name is unaffected, since `[JsonPropertyName]` is always emitted.
46
+ */
47
+ export declare function safeMemberName(propertyName: string, ownerTypeName: string): string;
48
+ /**
49
+ * Convert a name to a C# type name in PascalCase. Never escaped: type names are generated (from
50
+ * model names, method names, or status codes) rather than taken verbatim, so a collision with a
51
+ * keyword is a naming bug worth surfacing rather than papering over.
52
+ */
53
+ export declare function toCSharpTypeName(name: string): string;
54
+ /**
55
+ * Make an already-composed name safe to use as a C# type name, without re-casing it.
56
+ *
57
+ * Distinct from {@link toCSharpTypeName}, which splits a source name into words and rebuilds it:
58
+ * running that over a name already assembled from PascalCase parts would fold `MV` back to `Mv`.
59
+ */
60
+ export declare function sanitizeCSharpTypeName(name: string): string;
61
+ /**
62
+ * Convert an enum member value to a C# enum member name in PascalCase: `in-progress` becomes
63
+ * `InProgress`. The value itself always travels via `[JsonStringEnumMemberName]`, so this only has
64
+ * to be a stable identifier.
65
+ */
66
+ export declare function toCSharpEnumMemberName(value: string): string;
67
+ /**
68
+ * Derive the PascalCase base used for a generated file's names from a `.ck` file path:
69
+ * `"ledger.categories.ck"` becomes `"LedgerCategories"`. Both the models file and the client class
70
+ * for one source file are named from this, so they stay visibly paired in the output tree.
71
+ */
72
+ export declare function deriveCSharpFileBase(file: string): string;
73
+ /**
74
+ * Render `text` as an XML doc comment indented by `indent`, wrapped in `tag`. Returns `[]` for
75
+ * empty text so callers can splat unconditionally.
76
+ *
77
+ * `///` is a line comment, so unlike Kotlin's KDoc there is no delimiter to break out of. What does
78
+ * have to be handled is XML: an unescaped `&` or `<` in a description makes the doc file malformed,
79
+ * which the compiler reports as a warning and `-warnaserror` turns into a build failure.
80
+ */
81
+ export declare function xmlDocLines(text: string, indent: string, tag?: string): string[];
82
+ /** Escape the three characters that would otherwise make a doc comment malformed XML. */
83
+ export declare function escapeXml(text: string): string;
84
+ /**
85
+ * Render `value` as a C# string literal. No `$` handling: interpolated strings are the only place
86
+ * `$` is special, and no generated literal built from contract text is interpolated.
87
+ */
88
+ export declare function quoteCSharpString(value: string): string;
89
+ //# sourceMappingURL=naming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CA8E9C,CAAC;AAQH;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ1D;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAGlF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMrD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOzD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAY,GAAG,MAAM,EAAE,CAMnF;AAED,yFAAyF;AACzF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASvD"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The `Runtime/Converters.cs` file: the shared `JsonSerializerOptions` and the converters for the
3
+ * three ContractKit scalars whose BCL type does not serialize the way the contract says it travels.
4
+ *
5
+ * These live in the generated output rather than in a published NuGet package so the SDK has no
6
+ * dependency at all. The same choice the Python plugin makes with `_base_client.py` and the Kotlin
7
+ * plugin with `Serializers.kt`.
8
+ *
9
+ * Enums, unions and tuples are not handled here: each carries a `[JsonConverter]` attribute of its
10
+ * own, so it serializes correctly under any options. These three are options-level, which is why
11
+ * anything serializing a generated model by hand has to pass `SdkJson.Options`.
12
+ */
13
+ /** Generate `Runtime/Converters.cs` for `namespaceName`. Content depends on nothing but the namespace. */
14
+ export declare function generateConvertersCs(namespaceName: string): string;
15
+ //# sourceMappingURL=runtime-converters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-converters.d.ts","sourceRoot":"","sources":["../src/runtime-converters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,0GAA0G;AAC1G,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAoIlE"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The `Runtime/SdkRuntime.cs` file: the `HttpClient` wrapper every generated client is built on.
3
+ *
4
+ * Nothing here comes from outside the BCL, so a generated SDK restores and builds with no NuGet
5
+ * feed at all. The TypeScript, Python and Kotlin SDKs likewise read and write their own bodies
6
+ * rather than delegating to a content-negotiation layer.
7
+ */
8
+ /** Generate `Runtime/SdkRuntime.cs` for `namespaceName`. Content depends on nothing but the namespace. */
9
+ export declare function generateRuntimeCs(namespaceName: string): string;
10
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,0GAA0G;AAC1G,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAmX/D"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The project file a generated SDK needs to build on its own.
3
+ *
4
+ * Emitted with `ifAbsent`, so it is created once and then belongs to the user: a project will add a
5
+ * package id, a version, an analyzer set and a signing key of its own, and regenerating over that
6
+ * would throw the work away. Generated C# sources are rewritten every run; this is not.
7
+ */
8
+ /**
9
+ * What the scaffold pins. One object so a bump is one edit.
10
+ *
11
+ * There is deliberately no dependency list to go with it: the generated SDK uses only
12
+ * `System.Text.Json` and `HttpClient` from the shared framework, so `dotnet build` restores with no
13
+ * NuGet feed reachable at all.
14
+ */
15
+ export declare const SCAFFOLD_VERSIONS: {
16
+ readonly targetFramework: "net10.0";
17
+ };
18
+ /**
19
+ * Generate `<SdkName>.csproj`.
20
+ *
21
+ * `ImplicitUsings` is off because generated files carry an explicit `using` block of their own, and
22
+ * leaving it on would make the output depend on the SDK's implicit set rather than on what the
23
+ * generator wrote.
24
+ */
25
+ export declare function generateCsproj(namespaceName: string, sdkName: string): string;
26
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB;;CAEpB,CAAC;AAEX;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAc7E"}
@@ -0,0 +1,6 @@
1
+ // @ts-check
2
+
3
+ import base from '@repo/config-eslint/base.js';
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export default [...base];
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@contractkit/plugin-csharp",
3
+ "version": "0.0.0",
4
+ "description": "ContractKit built-in plugin: C#/.NET SDK client generation (System.Text.Json + HttpClient, no NuGet dependencies)",
5
+ "license": "MIT",
6
+ "author": {
7
+ "name": "Marooned Software",
8
+ "url": "https://github.com/MaroonedSoftware/contractkit"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/MaroonedSoftware/contractkit/issues"
12
+ },
13
+ "homepage": "https://github.com/MaroonedSoftware/contractkit/packages/plugin-csharp#readme",
14
+ "keywords": [
15
+ "contractkit",
16
+ "csharp",
17
+ "dotnet",
18
+ "system.text.json"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/MaroonedSoftware/contractkit.git"
23
+ },
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "module": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": "./dist/index.js"
30
+ },
31
+ "scripts": {
32
+ "build": "tsup src/index.ts --format esm --sourcemap --dts && tsc --emitDeclarationOnly --declaration",
33
+ "build:ci": "eslint --max-warnings=0 && pnpm run build",
34
+ "lint": "eslint --fix",
35
+ "format": "prettier --write .",
36
+ "test": "vitest run",
37
+ "test:ci": "vitest run --coverage"
38
+ },
39
+ "dependencies": {
40
+ "@contractkit/core": "workspace:*"
41
+ },
42
+ "devDependencies": {
43
+ "@repo/config-eslint": "workspace:*",
44
+ "@repo/config-typescript": "workspace:*",
45
+ "unplugin-swc": "^1.5.9",
46
+ "vitest": "^4.1.5"
47
+ }
48
+ }