schemantic 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.
Files changed (131) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/LICENSE +21 -0
  3. package/README.md +827 -0
  4. package/dist/__tests__/setup.d.ts +6 -0
  5. package/dist/__tests__/setup.d.ts.map +1 -0
  6. package/dist/__tests__/setup.js +30 -0
  7. package/dist/__tests__/setup.js.map +1 -0
  8. package/dist/__tests__/test-config.d.ts +36 -0
  9. package/dist/__tests__/test-config.d.ts.map +1 -0
  10. package/dist/__tests__/test-config.js +563 -0
  11. package/dist/__tests__/test-config.js.map +1 -0
  12. package/dist/cli/index.d.ts +118 -0
  13. package/dist/cli/index.d.ts.map +1 -0
  14. package/dist/cli/index.js +657 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/core/index.d.ts +5 -0
  17. package/dist/core/index.d.ts.map +1 -0
  18. package/dist/core/index.js +21 -0
  19. package/dist/core/index.js.map +1 -0
  20. package/dist/core/schemantic.d.ts +95 -0
  21. package/dist/core/schemantic.d.ts.map +1 -0
  22. package/dist/core/schemantic.js +543 -0
  23. package/dist/core/schemantic.js.map +1 -0
  24. package/dist/generators/api-client-generator.d.ts +145 -0
  25. package/dist/generators/api-client-generator.d.ts.map +1 -0
  26. package/dist/generators/api-client-generator.js +856 -0
  27. package/dist/generators/api-client-generator.js.map +1 -0
  28. package/dist/generators/base.d.ts +117 -0
  29. package/dist/generators/base.d.ts.map +1 -0
  30. package/dist/generators/base.js +232 -0
  31. package/dist/generators/base.js.map +1 -0
  32. package/dist/generators/enum-generator.d.ts +52 -0
  33. package/dist/generators/enum-generator.d.ts.map +1 -0
  34. package/dist/generators/enum-generator.js +178 -0
  35. package/dist/generators/enum-generator.js.map +1 -0
  36. package/dist/generators/factory.d.ts +59 -0
  37. package/dist/generators/factory.d.ts.map +1 -0
  38. package/dist/generators/factory.js +127 -0
  39. package/dist/generators/factory.js.map +1 -0
  40. package/dist/generators/hook-generator.d.ts +36 -0
  41. package/dist/generators/hook-generator.d.ts.map +1 -0
  42. package/dist/generators/hook-generator.js +495 -0
  43. package/dist/generators/hook-generator.js.map +1 -0
  44. package/dist/generators/index.d.ts +10 -0
  45. package/dist/generators/index.d.ts.map +1 -0
  46. package/dist/generators/index.js +26 -0
  47. package/dist/generators/index.js.map +1 -0
  48. package/dist/generators/object-generator.d.ts +48 -0
  49. package/dist/generators/object-generator.d.ts.map +1 -0
  50. package/dist/generators/object-generator.js +280 -0
  51. package/dist/generators/object-generator.js.map +1 -0
  52. package/dist/generators/primitive-generator.d.ts +40 -0
  53. package/dist/generators/primitive-generator.d.ts.map +1 -0
  54. package/dist/generators/primitive-generator.js +150 -0
  55. package/dist/generators/primitive-generator.js.map +1 -0
  56. package/dist/index.d.ts +17 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +42 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/parsers/base.d.ts +101 -0
  61. package/dist/parsers/base.d.ts.map +1 -0
  62. package/dist/parsers/base.js +77 -0
  63. package/dist/parsers/base.js.map +1 -0
  64. package/dist/parsers/factory.d.ts +64 -0
  65. package/dist/parsers/factory.d.ts.map +1 -0
  66. package/dist/parsers/factory.js +116 -0
  67. package/dist/parsers/factory.js.map +1 -0
  68. package/dist/parsers/index.d.ts +7 -0
  69. package/dist/parsers/index.d.ts.map +1 -0
  70. package/dist/parsers/index.js +23 -0
  71. package/dist/parsers/index.js.map +1 -0
  72. package/dist/parsers/openapi.d.ts +52 -0
  73. package/dist/parsers/openapi.d.ts.map +1 -0
  74. package/dist/parsers/openapi.js +396 -0
  75. package/dist/parsers/openapi.js.map +1 -0
  76. package/dist/plugins/branded-types.d.ts +28 -0
  77. package/dist/plugins/branded-types.d.ts.map +1 -0
  78. package/dist/plugins/branded-types.js +568 -0
  79. package/dist/plugins/branded-types.js.map +1 -0
  80. package/dist/plugins/builtin.d.ts +38 -0
  81. package/dist/plugins/builtin.d.ts.map +1 -0
  82. package/dist/plugins/builtin.js +283 -0
  83. package/dist/plugins/builtin.js.map +1 -0
  84. package/dist/plugins/index.d.ts +7 -0
  85. package/dist/plugins/index.d.ts.map +1 -0
  86. package/dist/plugins/index.js +23 -0
  87. package/dist/plugins/index.js.map +1 -0
  88. package/dist/plugins/loader.d.ts +92 -0
  89. package/dist/plugins/loader.d.ts.map +1 -0
  90. package/dist/plugins/loader.js +245 -0
  91. package/dist/plugins/loader.js.map +1 -0
  92. package/dist/plugins/manager.d.ts +99 -0
  93. package/dist/plugins/manager.d.ts.map +1 -0
  94. package/dist/plugins/manager.js +233 -0
  95. package/dist/plugins/manager.js.map +1 -0
  96. package/dist/plugins/performance-monitoring.d.ts +98 -0
  97. package/dist/plugins/performance-monitoring.d.ts.map +1 -0
  98. package/dist/plugins/performance-monitoring.js +596 -0
  99. package/dist/plugins/performance-monitoring.js.map +1 -0
  100. package/dist/plugins/request-deduplication.d.ts +27 -0
  101. package/dist/plugins/request-deduplication.d.ts.map +1 -0
  102. package/dist/plugins/request-deduplication.js +650 -0
  103. package/dist/plugins/request-deduplication.js.map +1 -0
  104. package/dist/plugins/zod-validation.d.ts +63 -0
  105. package/dist/plugins/zod-validation.d.ts.map +1 -0
  106. package/dist/plugins/zod-validation.js +743 -0
  107. package/dist/plugins/zod-validation.js.map +1 -0
  108. package/dist/types/core.d.ts +203 -0
  109. package/dist/types/core.d.ts.map +1 -0
  110. package/dist/types/core.js +24 -0
  111. package/dist/types/core.js.map +1 -0
  112. package/dist/types/index.d.ts +7 -0
  113. package/dist/types/index.d.ts.map +1 -0
  114. package/dist/types/index.js +23 -0
  115. package/dist/types/index.js.map +1 -0
  116. package/dist/types/openapi.d.ts +250 -0
  117. package/dist/types/openapi.d.ts.map +1 -0
  118. package/dist/types/openapi.js +8 -0
  119. package/dist/types/openapi.js.map +1 -0
  120. package/dist/types/schema.d.ts +68 -0
  121. package/dist/types/schema.d.ts.map +1 -0
  122. package/dist/types/schema.js +22 -0
  123. package/dist/types/schema.js.map +1 -0
  124. package/docs/ADVANCED_PLUGINS_IMPLEMENTATION.md +355 -0
  125. package/docs/ADVANCED_PLUGIN_DEVELOPMENT.md +309 -0
  126. package/docs/API.md +600 -0
  127. package/docs/CONFIGURATION.md +722 -0
  128. package/docs/FASTAPI_TUTORIAL.md +1497 -0
  129. package/docs/PLUGINS.md +683 -0
  130. package/docs/PLUGIN_DEVELOPMENT.md +720 -0
  131. package/package.json +90 -0
@@ -0,0 +1,683 @@
1
+ # Plugin Development Guide
2
+
3
+ This guide explains how to create custom plugins for Schemantic to extend its functionality.
4
+
5
+ ## Plugin Overview
6
+
7
+ Plugins in Schemantic allow you to:
8
+
9
+ - Transform schemas before type generation
10
+ - Modify generated types and API clients
11
+ - Add custom type generators
12
+ - Add custom client generators
13
+ - Execute code at various stages of the generation process
14
+
15
+ ## Plugin Interface
16
+
17
+ All plugins must implement the `SchemanticPlugin` interface:
18
+
19
+ ```typescript
20
+ interface SchemanticPlugin {
21
+ name: string;
22
+ version: string;
23
+ description: string;
24
+
25
+ // Lifecycle hooks
26
+ beforeGeneration?(context: GenerationContext): Promise<void> | void;
27
+ afterGeneration?(
28
+ context: GenerationContext,
29
+ result: GenerationResult
30
+ ): Promise<void> | void;
31
+
32
+ // Type generation hooks
33
+ beforeTypeGeneration?(
34
+ typeName: string,
35
+ schema: ResolvedSchema,
36
+ context: GenerationContext
37
+ ): Promise<void> | void;
38
+ afterTypeGeneration?(
39
+ typeName: string,
40
+ generatedType: GeneratedType,
41
+ context: GenerationContext
42
+ ): Promise<void> | void;
43
+
44
+ // Client generation hooks
45
+ beforeClientGeneration?(context: GenerationContext): Promise<void> | void;
46
+ afterClientGeneration?(
47
+ generatedClient: GeneratedApiClient,
48
+ context: GenerationContext
49
+ ): Promise<void> | void;
50
+
51
+ // Schema transformation hooks
52
+ transformSchema?(
53
+ schema: ResolvedSchema,
54
+ context: GenerationContext
55
+ ): ResolvedSchema;
56
+
57
+ // Custom generators
58
+ customTypeGenerators?: Record<
59
+ string,
60
+ (schema: ResolvedSchema, context: GenerationContext) => GeneratedType
61
+ >;
62
+ customClientGenerators?: Record<
63
+ string,
64
+ (context: GenerationContext) => GeneratedApiClient
65
+ >;
66
+ }
67
+ ```
68
+
69
+ ## Basic Plugin Structure
70
+
71
+ Here's a minimal plugin:
72
+
73
+ ```typescript
74
+ import { SchemanticPlugin, GenerationContext, GeneratedType } from "schemantic";
75
+
76
+ const myPlugin: SchemanticPlugin = {
77
+ name: "my-plugin",
78
+ version: "1.0.0",
79
+ description: "My custom plugin",
80
+
81
+ beforeGeneration: async (context: GenerationContext) => {
82
+ console.log("Starting generation...");
83
+ },
84
+
85
+ afterGeneration: async (context: GenerationContext, result: any) => {
86
+ console.log("Generation completed!");
87
+ },
88
+ };
89
+ ```
90
+
91
+ ## Plugin Hooks
92
+
93
+ ### Lifecycle Hooks
94
+
95
+ #### `beforeGeneration`
96
+
97
+ Called before the generation process starts. Use this to:
98
+
99
+ - Validate configuration
100
+ - Set up plugin-specific state
101
+ - Modify the generation context
102
+
103
+ ```typescript
104
+ beforeGeneration: async (context: GenerationContext) => {
105
+ // Validate configuration
106
+ if (!context.config.customOption) {
107
+ throw new Error('Custom option is required');
108
+ }
109
+
110
+ // Set up plugin state
111
+ context.pluginState = { myData: 'value' };
112
+ },
113
+ ```
114
+
115
+ #### `afterGeneration`
116
+
117
+ Called after the generation process completes. Use this to:
118
+
119
+ - Clean up resources
120
+ - Generate additional files
121
+ - Post-process results
122
+
123
+ ```typescript
124
+ afterGeneration: async (context: GenerationContext, result: any) => {
125
+ // Generate additional files
126
+ if (result.success) {
127
+ await generateAdditionalFiles(context);
128
+ }
129
+
130
+ // Clean up
131
+ delete context.pluginState;
132
+ },
133
+ ```
134
+
135
+ ### Type Generation Hooks
136
+
137
+ #### `beforeTypeGeneration`
138
+
139
+ Called before generating a specific type. Use this to:
140
+
141
+ - Transform the schema
142
+ - Add metadata
143
+ - Skip generation for certain types
144
+
145
+ ```typescript
146
+ beforeTypeGeneration: async (typeName: string, schema: ResolvedSchema, context: GenerationContext) => {
147
+ // Add custom metadata
148
+ schema._customMetadata = { processed: true };
149
+
150
+ // Skip certain types
151
+ if (typeName.includes('Internal')) {
152
+ return;
153
+ }
154
+ },
155
+ ```
156
+
157
+ #### `afterTypeGeneration`
158
+
159
+ Called after generating a specific type. Use this to:
160
+
161
+ - Modify the generated type content
162
+ - Add imports
163
+ - Post-process the type
164
+
165
+ ```typescript
166
+ afterTypeGeneration: async (typeName: string, generatedType: GeneratedType, context: GenerationContext) => {
167
+ // Add custom imports
168
+ generatedType.content = `import { CustomType } from './custom';\n\n${generatedType.content}`;
169
+
170
+ // Add custom decorators
171
+ if (generatedType.isInterface) {
172
+ generatedType.content = generatedType.content.replace(
173
+ /export interface (\w+)/g,
174
+ '@CustomDecorator\nexport interface $1'
175
+ );
176
+ }
177
+ },
178
+ ```
179
+
180
+ ### Client Generation Hooks
181
+
182
+ #### `beforeClientGeneration`
183
+
184
+ Called before generating API clients. Use this to:
185
+
186
+ - Set up client-specific configuration
187
+ - Modify the generation context
188
+
189
+ ```typescript
190
+ beforeClientGeneration: async (context: GenerationContext) => {
191
+ // Add custom configuration
192
+ context.clientConfig = {
193
+ baseUrl: 'https://api.example.com',
194
+ timeout: 30000,
195
+ };
196
+ },
197
+ ```
198
+
199
+ #### `afterClientGeneration`
200
+
201
+ Called after generating API clients. Use this to:
202
+
203
+ - Modify the generated client
204
+ - Add custom methods
205
+ - Post-process the client
206
+
207
+ ```typescript
208
+ afterClientGeneration: async (generatedClient: GeneratedApiClient, context: GenerationContext) => {
209
+ // Add custom methods
210
+ const customMethods = `
211
+ async customMethod(): Promise<string> {
212
+ return 'custom result';
213
+ }
214
+ `;
215
+
216
+ generatedClient.content = generatedClient.content.replace(
217
+ /}\s*$/,
218
+ `${customMethods}\n}`
219
+ );
220
+ },
221
+ ```
222
+
223
+ ### Schema Transformation
224
+
225
+ #### `transformSchema`
226
+
227
+ Transform schemas before type generation. Use this to:
228
+
229
+ - Add custom properties
230
+ - Modify type information
231
+ - Standardize schema format
232
+
233
+ ```typescript
234
+ transformSchema: (schema: ResolvedSchema, context: GenerationContext): ResolvedSchema => {
235
+ // Add custom properties
236
+ if (schema.properties) {
237
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
238
+ if (typeof propSchema === 'object' && propSchema !== null) {
239
+ // Add custom metadata
240
+ propSchema._customProperty = true;
241
+
242
+ // Transform specific types
243
+ if (propSchema.format === 'uuid') {
244
+ propSchema._customType = 'CustomUuid';
245
+ }
246
+ }
247
+ }
248
+ }
249
+
250
+ return schema;
251
+ },
252
+ ```
253
+
254
+ ## Custom Generators
255
+
256
+ ### Custom Type Generators
257
+
258
+ Add custom type generators for specific schema types:
259
+
260
+ ```typescript
261
+ customTypeGenerators: {
262
+ 'custom-type': (schema: ResolvedSchema, context: GenerationContext): GeneratedType => {
263
+ return {
264
+ name: 'CustomType',
265
+ content: `export type CustomType = string;`,
266
+ dependencies: [],
267
+ exports: ['CustomType'],
268
+ isInterface: false,
269
+ isEnum: false,
270
+ isUnion: false,
271
+ sourceSchema: schema,
272
+ };
273
+ },
274
+
275
+ 'date-time': (schema: ResolvedSchema, context: GenerationContext): GeneratedType => {
276
+ return {
277
+ name: 'DateTime',
278
+ content: `export type DateTime = string; // ISO 8601 format`,
279
+ dependencies: [],
280
+ exports: ['DateTime'],
281
+ isInterface: false,
282
+ isEnum: false,
283
+ isUnion: false,
284
+ sourceSchema: schema,
285
+ };
286
+ },
287
+ },
288
+ ```
289
+
290
+ ### Custom Client Generators
291
+
292
+ Add custom client generators:
293
+
294
+ ```typescript
295
+ customClientGenerators: {
296
+ 'react-query': (context: GenerationContext): GeneratedApiClient => {
297
+ const hooks = generateReactQueryHooks(context);
298
+
299
+ return {
300
+ name: 'ReactQueryHooks',
301
+ content: hooks,
302
+ dependencies: ['react-query'],
303
+ exports: ['useApiHooks'],
304
+ endpoints: [],
305
+ };
306
+ },
307
+
308
+ 'axios': (context: GenerationContext): GeneratedApiClient => {
309
+ const client = generateAxiosClient(context);
310
+
311
+ return {
312
+ name: 'AxiosClient',
313
+ content: client,
314
+ dependencies: ['axios'],
315
+ exports: ['AxiosApiClient'],
316
+ endpoints: [],
317
+ };
318
+ },
319
+ },
320
+ ```
321
+
322
+ ## Plugin Examples
323
+
324
+ ### JSDoc Plugin
325
+
326
+ Adds JSDoc comments to generated types:
327
+
328
+ ```typescript
329
+ const jsdocPlugin: SchemanticPlugin = {
330
+ name: "jsdoc",
331
+ version: "1.0.0",
332
+ description: "Adds JSDoc comments to generated types",
333
+
334
+ afterTypeGeneration: async (
335
+ typeName: string,
336
+ generatedType: GeneratedType,
337
+ context: GenerationContext
338
+ ) => {
339
+ if (!generatedType.content.includes("/**")) {
340
+ const comment = `/**\n * ${
341
+ generatedType.sourceSchema.description || `Generated type: ${typeName}`
342
+ }\n */\n`;
343
+ generatedType.content = comment + generatedType.content;
344
+ }
345
+ },
346
+ };
347
+ ```
348
+
349
+ ### Validation Plugin
350
+
351
+ Adds validation decorators for class-validator:
352
+
353
+ ```typescript
354
+ const validationPlugin: SchemanticPlugin = {
355
+ name: "validation",
356
+ version: "1.0.0",
357
+ description: "Adds validation decorators to generated types",
358
+
359
+ afterTypeGeneration: async (
360
+ typeName: string,
361
+ generatedType: GeneratedType,
362
+ context: GenerationContext
363
+ ) => {
364
+ if (generatedType.isInterface) {
365
+ // Add validation imports
366
+ const imports = `import { IsString, IsNumber, IsOptional, IsNotEmpty } from 'class-validator';\n\n`;
367
+
368
+ // Add validation decorators to properties
369
+ let content = generatedType.content;
370
+ content = content.replace(
371
+ /(\w+)(\?)?: (\w+);/g,
372
+ (match, propName, optional, type) => {
373
+ const decorators = [];
374
+
375
+ if (type === "string") decorators.push("@IsString()");
376
+ if (type === "number") decorators.push("@IsNumber()");
377
+ if (optional) decorators.push("@IsOptional()");
378
+ else decorators.push("@IsNotEmpty()");
379
+
380
+ return `${decorators.join("\n ")}\n ${match}`;
381
+ }
382
+ );
383
+
384
+ generatedType.content = imports + content;
385
+ }
386
+ },
387
+ };
388
+ ```
389
+
390
+ ### React Hooks Plugin
391
+
392
+ Generates React hooks for API endpoints:
393
+
394
+ ```typescript
395
+ const reactHooksPlugin: SchemanticPlugin = {
396
+ name: "react-hooks",
397
+ version: "1.0.0",
398
+ description: "Generates React hooks for API endpoints",
399
+
400
+ customClientGenerators: {
401
+ "react-hooks": (context: GenerationContext): GeneratedApiClient => {
402
+ const hooks = generateReactHooks(context);
403
+
404
+ return {
405
+ name: "ApiHooks",
406
+ content: hooks,
407
+ dependencies: ["react-query"],
408
+ exports: ["useApiHooks"],
409
+ endpoints: [],
410
+ };
411
+ },
412
+ },
413
+ };
414
+
415
+ function generateReactHooks(context: GenerationContext): string {
416
+ let hooks = `import { useQuery, useMutation, useQueryClient } from 'react-query';\n`;
417
+ hooks += `import { ApiClient } from './api-client';\n\n`;
418
+
419
+ hooks += `export const useApiHooks = (client: ApiClient) => {\n`;
420
+ hooks += ` const queryClient = useQueryClient();\n\n`;
421
+
422
+ // Generate hooks for each endpoint
423
+ for (const [path, pathItem] of Object.entries(context.schema.paths)) {
424
+ if (typeof pathItem === "object" && pathItem !== null) {
425
+ const operations = ["get", "post", "put", "delete", "patch"] as const;
426
+
427
+ for (const method of operations) {
428
+ const operation = pathItem[method];
429
+ if (operation) {
430
+ const hookName = generateHookName(
431
+ operation.operationId || `${method}${path}`
432
+ );
433
+ const hook = generateHook(operation, method, path);
434
+ hooks += ` ${hookName} = ${hook};\n`;
435
+ }
436
+ }
437
+ }
438
+ }
439
+
440
+ hooks += `};\n`;
441
+ return hooks;
442
+ }
443
+ ```
444
+
445
+ ## Plugin Loading
446
+
447
+ ### From File
448
+
449
+ ```typescript
450
+ import { PluginLoader } from "schemantic";
451
+
452
+ const loader = new PluginLoader();
453
+ const plugin = await loader.loadPluginFromFile("./my-plugin.js");
454
+ ```
455
+
456
+ ### From Package
457
+
458
+ ```typescript
459
+ const plugin = await loader.loadPluginFromPackage("my-Schemantic-plugin");
460
+ ```
461
+
462
+ ### From Directory
463
+
464
+ ```typescript
465
+ const plugins = await loader.loadPluginsFromDirectory("./plugins");
466
+ ```
467
+
468
+ ## Plugin Registration
469
+
470
+ ### In Code
471
+
472
+ ```typescript
473
+ import { Schemantic } from "schemantic";
474
+
475
+ const Schemantic = new Schemantic(config);
476
+ const pluginManager = Schemantic.getPluginManager();
477
+
478
+ pluginManager.registerPlugin(myPlugin);
479
+ pluginManager.enablePlugin("my-plugin");
480
+ ```
481
+
482
+ ### Via Configuration
483
+
484
+ ```typescript
485
+ const config: SchemanticConfig = {
486
+ // ... other config
487
+ plugins: [
488
+ { name: "my-plugin", enabled: true },
489
+ { name: "jsdoc", enabled: true },
490
+ ],
491
+ };
492
+ ```
493
+
494
+ ### Via CLI
495
+
496
+ ```bash
497
+ npx schemantic generate --plugins my-plugin,jsdoc
498
+ ```
499
+
500
+ ## Best Practices
501
+
502
+ ### 1. Error Handling
503
+
504
+ Always handle errors gracefully:
505
+
506
+ ```typescript
507
+ beforeTypeGeneration: async (typeName: string, schema: ResolvedSchema, context: GenerationContext) => {
508
+ try {
509
+ // Plugin logic
510
+ } catch (error) {
511
+ console.warn(`Plugin ${this.name} failed for type ${typeName}:`, error);
512
+ // Don't throw - let generation continue
513
+ }
514
+ },
515
+ ```
516
+
517
+ ### 2. Performance
518
+
519
+ Consider performance implications:
520
+
521
+ ```typescript
522
+ // Cache expensive operations
523
+ const cache = new Map();
524
+
525
+ transformSchema: (schema: ResolvedSchema, context: GenerationContext): ResolvedSchema => {
526
+ const cacheKey = JSON.stringify(schema);
527
+
528
+ if (cache.has(cacheKey)) {
529
+ return cache.get(cacheKey);
530
+ }
531
+
532
+ const result = expensiveTransformation(schema);
533
+ cache.set(cacheKey, result);
534
+ return result;
535
+ },
536
+ ```
537
+
538
+ ### 3. Documentation
539
+
540
+ Document your plugin thoroughly:
541
+
542
+ ```typescript
543
+ const myPlugin: SchemanticPlugin = {
544
+ name: "my-plugin",
545
+ version: "1.0.0",
546
+ description: `
547
+ My custom plugin that adds special functionality.
548
+
549
+ Features:
550
+ - Adds custom decorators
551
+ - Transforms specific types
552
+ - Generates additional files
553
+
554
+ Usage:
555
+ Enable via configuration or CLI: --plugins my-plugin
556
+ `,
557
+
558
+ // ... implementation
559
+ };
560
+ ```
561
+
562
+ ### 4. Testing
563
+
564
+ Test your plugins:
565
+
566
+ ```typescript
567
+ import { Schemantic, SchemanticConfig } from "schemantic";
568
+
569
+ describe("My Plugin", () => {
570
+ it("should transform schemas correctly", async () => {
571
+ const config: SchemanticConfig = {
572
+ schemaData: testSchema,
573
+ outputDir: "./test-output",
574
+ plugins: [{ name: "my-plugin", enabled: true }],
575
+ };
576
+
577
+ const Schemantic = new Schemantic(config);
578
+ const result = await Schemantic.generate();
579
+
580
+ expect(result.success).toBe(true);
581
+ expect(result.generatedFiles).toHaveLength(1);
582
+ });
583
+ });
584
+ ```
585
+
586
+ ### 5. Versioning
587
+
588
+ Use semantic versioning for your plugins:
589
+
590
+ ```typescript
591
+ const myPlugin: SchemanticPlugin = {
592
+ name: "my-plugin",
593
+ version: "1.2.3", // Major.Minor.Patch
594
+ description: "My plugin description",
595
+
596
+ // ... implementation
597
+ };
598
+ ```
599
+
600
+ ## Publishing Plugins
601
+
602
+ ### As NPM Package
603
+
604
+ 1. Create a package.json:
605
+
606
+ ```json
607
+ {
608
+ "name": "Schemantic-my-plugin",
609
+ "version": "1.0.0",
610
+ "description": "My custom Schemantic plugin",
611
+ "main": "dist/index.js",
612
+ "types": "dist/index.d.ts",
613
+ "keywords": ["Schemantic", "plugin", "typescript", "openapi"],
614
+ "peerDependencies": {
615
+ "schemantic": "^1.0.0"
616
+ }
617
+ }
618
+ ```
619
+
620
+ 2. Export your plugin:
621
+
622
+ ```typescript
623
+ // src/index.ts
624
+ export { myPlugin } from "./plugin";
625
+ export * from "./types";
626
+ ```
627
+
628
+ 3. Build and publish:
629
+
630
+ ```bash
631
+ npm run build
632
+ npm publish
633
+ ```
634
+
635
+ ### Usage
636
+
637
+ Users can install and use your plugin:
638
+
639
+ ```bash
640
+ npm install Schemantic-my-plugin
641
+ ```
642
+
643
+ ```typescript
644
+ import { myPlugin } from "Schemantic-my-plugin";
645
+ import { Schemantic } from "schemantic";
646
+
647
+ const Schemantic = new Schemantic(config);
648
+ Schemantic.getPluginManager().registerPlugin(myPlugin);
649
+ ```
650
+
651
+ ## Troubleshooting
652
+
653
+ ### Common Issues
654
+
655
+ 1. **Plugin not loading**: Check that the plugin exports the correct interface
656
+ 2. **Type errors**: Ensure your plugin implements all required interface properties
657
+ 3. **Performance issues**: Use caching and avoid expensive operations in hooks
658
+ 4. **Conflicts**: Check for naming conflicts with other plugins
659
+
660
+ ### Debug Mode
661
+
662
+ Enable debug mode to see plugin execution:
663
+
664
+ ```typescript
665
+ const config: SchemanticConfig = {
666
+ // ... other config
667
+ plugins: [{ name: "my-plugin", enabled: true, options: { debug: true } }],
668
+ };
669
+ ```
670
+
671
+ ### Logging
672
+
673
+ Add logging to your plugin:
674
+
675
+ ```typescript
676
+ beforeTypeGeneration: async (typeName: string, schema: ResolvedSchema, context: GenerationContext) => {
677
+ console.log(`[My Plugin] Processing type: ${typeName}`);
678
+
679
+ // Plugin logic
680
+
681
+ console.log(`[My Plugin] Completed processing: ${typeName}`);
682
+ },
683
+ ```