@siyavuyachagi/typesharp 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Siyavuya Chagi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,389 @@
1
+ # TypeSharp
2
+
3
+ Generate TypeScript types from C# models with ease! TypeSharp scans your ASP.NET Core projects and automatically generates TypeScript interfaces from your C# classes decorated with the `[TypeSharp]` attribute.
4
+
5
+ ## Features
6
+
7
+ ✨ **Automatic Type Generation** – Convert C# models to TypeScript interfaces
8
+ 🎯 **Custom Attribute Targeting** – Use `[TypeSharp]` or any custom attribute
9
+ πŸ”„ **Nullable Support** – `string?` β†’ `string | null`
10
+ πŸ“¦ **Collection Handling** – Supports `List<T>`, `IEnumerable<T>`, arrays **and generic collections**
11
+ 🧬 **Generic Types** – Preserves generic type definitions like `Response<T>` β†’ `Response<T>`
12
+ 🧬 **Inheritance** – Preserves class inheritance using `extends`
13
+ 🎨 **Naming Conventions** – Convert property names (camel, pascal, snake, kebab)
14
+ πŸ“ **Flexible Output** – Single file or multiple files
15
+ πŸ”’ **Enum Support** – Converts C# enums to TypeScript string enums
16
+ πŸ—‚οΈ **File Grouping** – Preserves C# file organization (multiple classes per file stay together)
17
+
18
+
19
+ ## How TypeSharp Compares
20
+ This is not an OpenApi-based tool !
21
+ | Feature | TypeSharp | NSwag | openapi-typescript | TypeGen |
22
+ | --------------------- | --------- | ----- | ------------------ | ------- |
23
+ | Direct C# parsing | βœ… | ❌ | ❌ | βœ… |
24
+ | Attribute targeting | βœ… | ⚠️ | ❌ | ⚠️ |
25
+ | Non-API models | βœ… | ❌ | ❌ | βœ… |
26
+ | Generics preserved | βœ… | ⚠️ | ⚠️ | ⚠️ |
27
+ | File grouping | βœ… | ❌ | ❌ | ❌ |
28
+ | Naming control | βœ… | ⚠️ | ⚠️ | ❌ |
29
+ | API client generation | ❌ | βœ… | ❌ | ❌ |
30
+
31
+ For more [docs/why-typesharp](docs/why-typesharp.md)
32
+
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ npm install -D @siyavuyachagi/typesharp
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ### 1. Create an attribute to target
43
+
44
+ In your target project create the following attribute (`TypeSharp`)
45
+
46
+ ```cs
47
+ namespace YourProject.Attribute
48
+ {
49
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum)]
50
+ public class TypeSharpAttribute : Attribute { }
51
+ }
52
+ ```
53
+
54
+ ### 2. Decorate your C# models or DTOs
55
+
56
+ ```csharp
57
+ [TypeSharp]
58
+ public class User
59
+ {
60
+ public int Id { get; set; }
61
+ public string? Name { get; set; }
62
+ public string Email { get; set; }
63
+ public List<UserRole> Roles { get; set; }
64
+ public List<string> Permissions { get; set; }
65
+ public DateTime CreatedAt { get; set; }
66
+ }
67
+
68
+ [TypeSharp]
69
+ public enum UserRole
70
+ {
71
+ Admin,
72
+ User,
73
+ Guest
74
+ }
75
+
76
+ [TypeSharp]
77
+ public class ApiResponse<T>
78
+ {
79
+ public bool Success { get; set; }
80
+ public string? Message { get; set; }
81
+ public T Data { get; set; }
82
+ public List<string> Errors { get; set; }
83
+ }
84
+ ```
85
+
86
+ ### 3. Create a configuration file
87
+
88
+ In your frontend end project run the following script
89
+
90
+ ```bash
91
+ # Create TypeScript config
92
+ npx typesharp init
93
+
94
+ # ----- OR -------
95
+
96
+ # Create JSON config (default)
97
+ npx typesharp init --format json
98
+
99
+ # Create TypeScript config
100
+ npx typesharp init --format ts
101
+
102
+ # Create JavaScript config
103
+ npx typesharp init --format js
104
+
105
+ ```
106
+
107
+ This creates `typesharp.config.json`:
108
+
109
+ ```json
110
+ {
111
+ "projectFile": [
112
+ "C:/Users/User/Desktop/MyApp/Api/Api.csproj",
113
+ "C:/Users/User/Desktop/MyApp/Domain/Domain.csproj"
114
+ ],
115
+ "outputPath": "./app/types",
116
+ "targetAnnotation": "TypeSharp",
117
+ "singleOutputFile": false,
118
+ "fileNamingConvention": "kebab",
119
+ "namingConvention": "camel"
120
+ }
121
+ ```
122
+
123
+ ### 4. Generate TypeScript types
124
+
125
+ ```bash
126
+ npx typesharp
127
+
128
+ # ----- OR -------
129
+
130
+ npx typesharp generate
131
+ # or with custom config
132
+ npx typesharp generate --config ./custom-config.ts
133
+ ```
134
+
135
+ Output (`app/types/user.ts`):
136
+
137
+ ```typescript
138
+ /**
139
+ * Auto-generated by TypeSharp
140
+ * Generated at: 2024-12-12T10:30:00.000Z
141
+ * Do not edit this file manually
142
+ */
143
+
144
+ export interface User {
145
+ id: number;
146
+ name: string | null;
147
+ email: string;
148
+ roles: UserRole[];
149
+ permissions: string[];
150
+ createdAt: string;
151
+ }
152
+ ```
153
+
154
+ Output (`app/types/user-role.ts`):
155
+
156
+ ```ts
157
+ /**
158
+ * Auto-generated by TypeSharp
159
+ * Generated at: 2024-12-12T10:30:00.000Z
160
+ * Do not edit this file manually
161
+ */
162
+
163
+ export enum UserRole {
164
+ Admin = "Admin",
165
+ User = "User",
166
+ Guest = "Guest",
167
+ }
168
+ ```
169
+
170
+ Output (`app/types/api-response.ts`):
171
+
172
+ ```ts
173
+ /**
174
+ * Auto-generated by TypeSharp
175
+ * Generated at: 2024-12-12T10:30:00.000Z
176
+ * Do not edit this file manually
177
+ */
178
+
179
+ export interface ApiResponse<T> {
180
+ success: boolean;
181
+ message: string | null;
182
+ data: T;
183
+ errors: string[];
184
+ }
185
+ ```
186
+ For more advanced usage [docs/usage](docs/usage.md)
187
+
188
+ ## Configuration
189
+
190
+ ### 1. Configuration Options
191
+
192
+ | Option | Type | Default | Description |
193
+ | ---------------------- | ---------- | ------------- | ------------------------------------------------ |
194
+ | `projectFiles` | `string[]` | _required_ | Full path(s) to your C# .csproj file |
195
+ | `outputPath` | `string` | _required_ | Where to generate TypeScript files |
196
+ | `targetAnnotation` | `string` | `'TypeSharp'` | C# attribute name to look for |
197
+ | `singleOutputFile` | `boolean` | `false` | Generate one file or multiple files (see below) |
198
+ | `fileNamingConvention` | `string` | `'kebab'` | File naming: `kebab`, `camel`, `pascal`, `snake` |
199
+ | `namingConvention` | `string` | `'camel'` | Property naming: `camel`, `pascal`, `snake` |
200
+ | `fileSuffix` | `string` | `optional` | Suffix for file names: `user-dto.ts` |
201
+
202
+ ### 2. Output File Behavior
203
+
204
+ TypeSharp preserves your C# file organization. Here's how it works:
205
+
206
+ | C# File Structure | `singleOutputFile: false` | `singleOutputFile: true` |
207
+ | ---------------------------------------------------------- | ------------------------------------------------ | ------------------------- |
208
+ | **One class per file**<br>`User.cs` β†’ 1 class | `user.ts` (1 interface) | All classes in `types.ts` |
209
+ | **Multiple classes per file**<br>`UserDtos.cs` β†’ 3 classes | `user-dtos.ts` (3 interfaces) | All classes in `types.ts` |
210
+ | **Mixed structure**<br>Various C# files | Each C# file β†’ 1 TS file<br>(preserves grouping) | All classes in `types.ts` |
211
+
212
+ **Example:**
213
+
214
+ ```
215
+ C# Structure: TypeScript Output (singleOutputFile: false):
216
+ Backend/ src/types/
217
+ β”œβ”€β”€ DTOs/ └── DTOs/
218
+ β”‚ β”œβ”€β”€ UserDtos.cs β”‚ β”œβ”€β”€ user-dtos.ts ← All 3 classes together
219
+ β”‚ β”‚ β”œβ”€β”€ UserCreateDto β”‚ └── product-dtos.ts ← All 2 classes together
220
+ β”‚ β”‚ β”œβ”€β”€ UserUpdateDto
221
+ β”‚ β”‚ └── UserResponseDto
222
+ β”‚ └── ProductDtos.cs
223
+ β”‚ β”œβ”€β”€ ProductDto
224
+ β”‚ └── ProductCreateDto
225
+ ```
226
+
227
+ **This means if you organize related DTOs in one C# file, they'll stay together in the generated TypeScript file!** 🎯
228
+
229
+ ### 3. Configuration File Formats
230
+
231
+ TypeSharp supports multiple configuration formats:
232
+
233
+ **JSON** (`typesharp.config.json`): (recommended)
234
+
235
+ ```json
236
+ {
237
+ "projectFiles": ["C:/Users/User/Desktop/MyApp/Domain/Domain.csproj"],
238
+ "outputPath": "./src/types"
239
+ }
240
+ ```
241
+
242
+ **TypeScript** (`typesharp.config.ts`):
243
+
244
+ ```typescript
245
+ import { TypeSharpConfig } from "typesharp";
246
+
247
+ const config: TypeSharpConfig = {
248
+ projectFiles: ["C:/Users/User/Desktop/MyApp/Domain/Domain.csproj"],
249
+ outputPath: "./src/types",
250
+ };
251
+
252
+ export default config;
253
+ ```
254
+
255
+ **JavaScript** (`typesharp.config.js`):
256
+
257
+ ```javascript
258
+ module.exports = {
259
+ projectFiles: ["C:/Users/User/Desktop/MyApp/Domain/Domain.csproj"],
260
+ outputPath: "./src/types",
261
+ };
262
+ ```
263
+
264
+ ## Usage in package.json
265
+
266
+ Add TypeSharp to your build scripts:
267
+
268
+ ```json
269
+ {
270
+ "scripts": {
271
+ "generate-types": "typesharp",
272
+ "dev": "typesharp && nuxt dev",
273
+ "build": "typesharp && nuxt build"
274
+ }
275
+ }
276
+ ```
277
+
278
+ ## Advanced Examples
279
+
280
+ ### 1. With Inheritance
281
+
282
+ **C#:**
283
+
284
+ ```csharp
285
+ [TypeSharp]
286
+ public class BaseEntity
287
+ {
288
+ public int Id { get; set; }
289
+ public DateTime CreatedAt { get; set; }
290
+ }
291
+
292
+ [TypeSharp]
293
+ public class Product : BaseEntity
294
+ {
295
+ public string Name { get; set; }
296
+ public decimal Price { get; set; }
297
+ }
298
+ ```
299
+
300
+ **Generated TypeScript:**
301
+
302
+ ```typescript
303
+ export interface BaseEntity {
304
+ id: number;
305
+ createdAt: string;
306
+ }
307
+
308
+ export interface Product extends BaseEntity {
309
+ name: string;
310
+ price: number;
311
+ }
312
+ ```
313
+
314
+ ### 2. Single Output File
315
+
316
+ **Config:**
317
+
318
+ ```typescript
319
+ const config: TypeSharpConfig = {
320
+ projectFile: "./Backend/Backend.csproj",
321
+ outputPath: "./src/types",
322
+ singleOutputFile: true,
323
+ };
324
+ ```
325
+
326
+ All types will be generated in `src/types/index.ts`
327
+
328
+ ### 3. Custom Naming Conventions
329
+
330
+ **Config:**
331
+
332
+ ```typescript
333
+ const config: TypeSharpConfig = {
334
+ projectFile: "./Backend/Backend.csproj",
335
+ outputPath: "./src/types",
336
+ fileNamingConvention: "snake", // user_model.ts
337
+ namingConvention: "pascal", // UserName, not userName
338
+ };
339
+ ```
340
+
341
+ ## Type Mappings
342
+
343
+ | C# Type | TypeScript Type |
344
+ | ------------------------------------------- | ---------------- |
345
+ | `string` | `string` |
346
+ | `int`, `long`, `double`, `float`, `decimal` | `number` |
347
+ | `bool` | `boolean` |
348
+ | `DateTime`, `DateOnly`, `TimeOnly` | `string` |
349
+ | `Guid` | `string` |
350
+ | `List<T>`, `IEnumerable<T>`, `T[]` | `T[]` |
351
+ | `string?` | `string \| null` |
352
+
353
+ ## Programmatic Usage
354
+
355
+ You can also use TypeSharp programmatically:
356
+
357
+ ```typescript
358
+ import { generate } from "typesharp";
359
+
360
+ async function generateTypes() {
361
+ await generate("./path/to/config.ts");
362
+ }
363
+
364
+ generateTypes();
365
+ ```
366
+
367
+ ## Requirements
368
+
369
+ - Node.js >= 14
370
+ - TypeScript >= 4.5 (if using TypeScript config)
371
+
372
+ <!-- ## Contributing
373
+
374
+ Contributions are welcome! Please feel free to submit a Pull Request. -->
375
+
376
+ ## License
377
+
378
+ MIT Β© Siyavuya Chagi
379
+
380
+ ## Author
381
+
382
+ **Siyavuya Chagi (CeeJay)**
383
+
384
+ - GitHub: [@siyavuyachagi](https://github.com/siyavuyachagi)
385
+ - Email: syavuya08@gmail.com
386
+
387
+ ---
388
+
389
+ Built with ❀️ in South Africa πŸ‡ΏπŸ‡¦
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../dist/cli/index.js');
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const core_1 = require("../core");
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const program = new commander_1.Command();
11
+ program
12
+ .name('typesharp')
13
+ .description('Generate TypeScript types from C# models with TypeSharp attribute')
14
+ .version('1.0.0')
15
+ .usage('[command] [options]');
16
+ // Generate command (default)
17
+ program
18
+ .command('generate', { isDefault: true })
19
+ .description('Generate TypeScript types from C# files')
20
+ .option('-c, --config <path>', 'Path to configuration file')
21
+ .action(async (options) => {
22
+ try {
23
+ await (0, core_1.generate)(options.config);
24
+ process.exit(0);
25
+ }
26
+ catch (error) {
27
+ process.exit(1);
28
+ }
29
+ });
30
+ // Init command
31
+ program
32
+ .command('init')
33
+ .description('Create a sample configuration file')
34
+ .option('-f, --format <format>', 'Configuration file format (ts, js, json)', 'json') // default to 'json'
35
+ .action((options) => {
36
+ try {
37
+ const format = options.format;
38
+ if (!['ts', 'js', 'json'].includes(format)) {
39
+ console.error(chalk_1.default.red.bold('❌ Invalid format.') + ' Use: ' + chalk_1.default.yellow('json, ts, ') + 'or' + chalk_1.default.yellow(' js'));
40
+ process.exit(1);
41
+ }
42
+ (0, core_1.createSampleConfig)(format);
43
+ process.exit(0);
44
+ }
45
+ catch (error) {
46
+ if (error instanceof Error) {
47
+ console.error(chalk_1.default.red.bold(`❌ Error:`), chalk_1.default.white(error.message));
48
+ }
49
+ process.exit(1);
50
+ }
51
+ });
52
+ program.parse();
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;;;;AAEA,yCAAoC;AACpC,kCAAuD;AACvD,kDAA0B;AAE1B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,mEAAmE,CAAC;KAChF,OAAO,CAAC,OAAO,CAAC;KAChB,KAAK,CAAC,qBAAqB,CAAC,CAAC;AAEhC,6BAA6B;AAC7B,OAAO;KACJ,OAAO,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACxC,WAAW,CAAC,yCAAyC,CAAC;KACtD,MAAM,CAAC,qBAAqB,EAAE,4BAA4B,CAAC;KAC3D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,IAAA,eAAQ,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,eAAe;AACf,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,uBAAuB,EAAE,0CAA0C,EAAE,MAAM,CAAC,CAAC,oBAAoB;KACxG,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;IAClB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,CAAC,MAA8B,CAAC;QAEtD,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3C,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,QAAQ,GAAG,eAAK,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,IAAI,GAAG,eAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACxH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAA,yBAAkB,EAAC,MAAM,CAAC,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,eAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACxE,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { TypeSharpConfig } from '../types/typesharp-config';
2
+ export declare function generate(configPath?: string): Promise<void>;
3
+ /**
4
+ * Deletes all contents of a directory but keeps the directory itself.
5
+ * @param dir Path to the directory to clean
6
+ */
7
+ export declare function cleanOutputDirectory(dir: string): void;
8
+ /**
9
+ * Load configuration from file or use provided config
10
+ */
11
+ export declare function loadConfig(configPath?: string): TypeSharpConfig;
12
+ /**
13
+ * Create a sample configuration file
14
+ */
15
+ export declare function createSampleConfig(format?: 'ts' | 'js' | 'json'): void;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAuD5D,wBAAsB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiEjE;AASD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,QAiB/C;AAUD;;GAEG;AACH,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,eAAe,CAqB/D;AA2CD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,IAAI,GAAG,IAAI,GAAG,MAAe,GAAG,IAAI,CAwC9E"}