ts-runtime-validation 1.6.16 → 1.8.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 (83) hide show
  1. package/CONTRIBUTING.md +430 -0
  2. package/README.md +505 -62
  3. package/dist/ICommandOptions.js +3 -0
  4. package/dist/ICommandOptions.js.map +1 -0
  5. package/dist/SchemaGenerator.deterministic-extended.test.js +420 -0
  6. package/dist/SchemaGenerator.deterministic-extended.test.js.map +1 -0
  7. package/dist/SchemaGenerator.deterministic.test.js +251 -0
  8. package/dist/SchemaGenerator.deterministic.test.js.map +1 -0
  9. package/dist/SchemaGenerator.integration.test.js +323 -0
  10. package/dist/SchemaGenerator.integration.test.js.map +1 -0
  11. package/dist/SchemaGenerator.js +120 -0
  12. package/dist/SchemaGenerator.js.map +1 -0
  13. package/dist/SchemaGenerator.test.js +226 -0
  14. package/dist/SchemaGenerator.test.js.map +1 -0
  15. package/dist/cli.test.js +155 -0
  16. package/dist/cli.test.js.map +1 -0
  17. package/dist/errors/index.js +95 -0
  18. package/dist/errors/index.js.map +1 -0
  19. package/dist/errors/index.test.js +232 -0
  20. package/dist/errors/index.test.js.map +1 -0
  21. package/dist/getPosixPath.js +13 -0
  22. package/dist/getPosixPath.js.map +1 -0
  23. package/dist/index.js +27 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/lib.js.map +1 -0
  26. package/dist/services/CodeGenerator.js +321 -0
  27. package/dist/services/CodeGenerator.js.map +1 -0
  28. package/dist/services/FileDiscovery.js +123 -0
  29. package/dist/services/FileDiscovery.js.map +1 -0
  30. package/dist/services/FileDiscovery.test.js +184 -0
  31. package/dist/services/FileDiscovery.test.js.map +1 -0
  32. package/dist/services/SchemaProcessor.js +198 -0
  33. package/dist/services/SchemaProcessor.js.map +1 -0
  34. package/dist/services/SchemaProcessor.test.js +455 -0
  35. package/dist/services/SchemaProcessor.test.js.map +1 -0
  36. package/dist/services/SchemaWriter.js +76 -0
  37. package/dist/services/SchemaWriter.js.map +1 -0
  38. package/dist/services/SchemaWriter.test.js +255 -0
  39. package/dist/services/SchemaWriter.test.js.map +1 -0
  40. package/dist/test/basic-scenario/types.jsonschema.js +3 -0
  41. package/dist/test/basic-scenario/types.jsonschema.js.map +1 -0
  42. package/dist/test/duplicate-symbols-different-implementation/IBaseType.js +3 -0
  43. package/dist/test/duplicate-symbols-different-implementation/IBaseType.js.map +1 -0
  44. package/dist/test/duplicate-symbols-different-implementation/IBaseTypeDefinitionReplicated.js +3 -0
  45. package/dist/test/duplicate-symbols-different-implementation/IBaseTypeDefinitionReplicated.js.map +1 -0
  46. package/dist/test/duplicate-symbols-different-implementation/IBasicTypesA.jsonschema.js +3 -0
  47. package/dist/test/duplicate-symbols-different-implementation/IBasicTypesA.jsonschema.js.map +1 -0
  48. package/dist/test/duplicate-symbols-different-implementation/IBasicTypesB.jsonschema.js +3 -0
  49. package/dist/test/duplicate-symbols-different-implementation/IBasicTypesB.jsonschema.js.map +1 -0
  50. package/dist/test/duplicate-symbols-identitcal-implementation/IBaseType.js +3 -0
  51. package/dist/test/duplicate-symbols-identitcal-implementation/IBaseType.js.map +1 -0
  52. package/dist/test/duplicate-symbols-identitcal-implementation/IBaseTypeDefinitionReplicated.js +3 -0
  53. package/dist/test/duplicate-symbols-identitcal-implementation/IBaseTypeDefinitionReplicated.js.map +1 -0
  54. package/dist/test/duplicate-symbols-identitcal-implementation/IBasicTypesA.jsonschema.js +3 -0
  55. package/dist/test/duplicate-symbols-identitcal-implementation/IBasicTypesA.jsonschema.js.map +1 -0
  56. package/dist/test/duplicate-symbols-identitcal-implementation/IBasicTypesB.jsonschema.js +3 -0
  57. package/dist/test/duplicate-symbols-identitcal-implementation/IBasicTypesB.jsonschema.js.map +1 -0
  58. package/dist/utils/ProgressReporter.js +67 -0
  59. package/dist/utils/ProgressReporter.js.map +1 -0
  60. package/dist/utils/ProgressReporter.test.js +267 -0
  61. package/dist/utils/ProgressReporter.test.js.map +1 -0
  62. package/dist/writeLine.js +12 -0
  63. package/dist/writeLine.js.map +1 -0
  64. package/package.json +2 -2
  65. package/src/ICommandOptions.ts +7 -0
  66. package/src/SchemaGenerator.deterministic-extended.test.ts +429 -0
  67. package/src/SchemaGenerator.deterministic.test.ts +276 -0
  68. package/src/SchemaGenerator.integration.test.ts +411 -0
  69. package/src/SchemaGenerator.test.ts +118 -0
  70. package/src/SchemaGenerator.ts +112 -298
  71. package/src/cli.test.ts +130 -0
  72. package/src/errors/index.test.ts +319 -0
  73. package/src/errors/index.ts +92 -0
  74. package/src/index.ts +8 -1
  75. package/src/services/CodeGenerator.ts +370 -0
  76. package/src/services/FileDiscovery.test.ts +216 -0
  77. package/src/services/FileDiscovery.ts +140 -0
  78. package/src/services/SchemaProcessor.test.ts +536 -0
  79. package/src/services/SchemaProcessor.ts +194 -0
  80. package/src/services/SchemaWriter.test.ts +304 -0
  81. package/src/services/SchemaWriter.ts +75 -0
  82. package/src/utils/ProgressReporter.test.ts +357 -0
  83. package/src/utils/ProgressReporter.ts +76 -0
@@ -0,0 +1,430 @@
1
+ # Contributing to ts-runtime-validation
2
+
3
+ Thank you for your interest in contributing to ts-runtime-validation! This guide will help you understand the project architecture and how to contribute effectively.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Project Architecture](#project-architecture)
8
+ - [Development Setup](#development-setup)
9
+ - [Code Structure](#code-structure)
10
+ - [Testing](#testing)
11
+ - [Making Changes](#making-changes)
12
+ - [Pull Request Process](#pull-request-process)
13
+ - [Code Style](#code-style)
14
+
15
+ ## Project Architecture
16
+
17
+ ### Overview
18
+
19
+ ts-runtime-validation is a TypeScript-first tool that generates JSON Schema validators from TypeScript interfaces and type aliases. The architecture follows a service-oriented pipeline approach:
20
+
21
+ ```
22
+ TypeScript Files → FileDiscovery → SchemaProcessor → CodeGenerator → Output Files
23
+
24
+ SchemaWriter ← Orchestrated by SchemaGenerator
25
+ ```
26
+
27
+ ### Core Components
28
+
29
+ #### 1. CLI Entry Point (`src/index.ts`)
30
+
31
+ - **Purpose**: Command-line interface entry point
32
+ - **Responsibilities**:
33
+ - Parses command-line arguments using Commander.js
34
+ - Instantiates SchemaGenerator with user options
35
+ - Triggers the generation process
36
+
37
+ #### 2. Library Entry Point (`src/lib.ts`)
38
+
39
+ - **Purpose**: Programmatic API for library consumers
40
+ - **Exports**: SchemaGenerator class and ICommandOptions interface
41
+ - **Usage**: Allows integration into build tools and custom scripts
42
+
43
+ #### 3. Schema Generator (`src/SchemaGenerator.ts`)
44
+
45
+ - **Purpose**: Core orchestrator that coordinates all services
46
+ - **Architecture**: Uses dependency injection pattern with specialized services
47
+ - **Key Methods**:
48
+ - `Generate()`: Main entry point with comprehensive error handling
49
+ - `clearCache()`: Clears file cache for fresh builds
50
+ - `cleanOutput()`: Removes previously generated files
51
+ - **Services Used**:
52
+ - FileDiscovery: File system operations and caching
53
+ - SchemaProcessor: TypeScript to JSON Schema conversion
54
+ - CodeGenerator: TypeScript helper file generation
55
+ - SchemaWriter: File writing operations
56
+ - ProgressReporter: User feedback and progress tracking
57
+
58
+ #### 4. Command Options (`src/ICommandOptions.ts`)
59
+
60
+ - **Purpose**: Comprehensive configuration interface for all features
61
+ - **Core Fields**:
62
+ - `glob`: Pattern for finding schema files
63
+ - `rootPath`: Source directory root
64
+ - `output`: Output directory for generated files
65
+ - `helpers`: Whether to generate TypeScript helpers
66
+ - `additionalProperties`: JSON Schema validation strictness
67
+ - `tsconfigPath`: Custom TypeScript configuration
68
+ - **Performance Fields**:
69
+ - `verbose`: Enable detailed logging
70
+ - `progress`: Show progress indicators
71
+ - `parallel`: Enable parallel file processing (default: true)
72
+ - `cache`: Enable incremental builds with caching
73
+ - **Output Optimization Fields**:
74
+ - `minify`: Minify generated output
75
+ - `treeShaking`: Generate tree-shaking friendly exports
76
+ - `lazyLoad`: Generate lazy-loaded validators
77
+
78
+ #### 5. Service Layer (`src/services/`)
79
+
80
+ - **FileDiscovery.ts**: File system operations, glob matching, caching
81
+ - **SchemaProcessor.ts**: TypeScript AST processing, parallel schema generation
82
+ - **CodeGenerator.ts**: TypeScript file generation with optimization options
83
+ - **SchemaWriter.ts**: File writing operations with output management
84
+
85
+ #### 6. Error Handling (`src/errors/`)
86
+
87
+ - **Custom Error Classes**: Specific error types for different failure scenarios
88
+ - **Error Formatting**: User-friendly error messages with context
89
+ - **Error Recovery**: Partial generation on non-critical errors
90
+
91
+ #### 7. Utility Functions
92
+
93
+ - `getPosixPath.ts`: Cross-platform path compatibility
94
+ - `writeLine.ts`: Console output utilities (legacy)
95
+ - `utils/ProgressReporter.ts`: Progress tracking and user feedback
96
+
97
+ ### Dependencies
98
+
99
+ #### Core Dependencies
100
+
101
+ - **ts-json-schema-generator**: Converts TypeScript AST to JSON Schema
102
+ - **ts-morph**: TypeScript AST manipulation for generating helper files
103
+ - **commander**: CLI argument parsing
104
+ - **fdir**: Fast file system traversal
105
+ - **picomatch**: Glob pattern matching
106
+
107
+ #### Peer Dependencies
108
+
109
+ - **ajv**: Runtime JSON Schema validation (required by generated code)
110
+
111
+ ### Generated Files
112
+
113
+ The tool generates four main files in the output directory:
114
+
115
+ 1. **validation.schema.json**
116
+ - Contains all JSON Schema definitions
117
+ - Single source of truth for validation rules
118
+ - Structure: `{ "$schema": "...", "definitions": { ... } }`
119
+
120
+ 2. **SchemaDefinition.ts**
121
+ - TypeScript interface mapping schema paths to types
122
+ - Exports `ISchema` interface and `schemas` constant
123
+ - Enables type-safe schema references
124
+
125
+ 3. **isValidSchema.ts**
126
+ - Runtime validation function with type guards
127
+ - Integrates with AJV for actual validation
128
+ - Provides type narrowing: `data is ISchema[T]`
129
+
130
+ 4. **ValidationType.ts**
131
+ - Namespace containing all validated types
132
+ - Re-exports types from source files
133
+ - Provides centralized type access
134
+
135
+ ## Development Setup
136
+
137
+ ### Prerequisites
138
+
139
+ - Node.js >= 12
140
+ - Yarn or npm
141
+ - TypeScript >= 4.0
142
+
143
+ ### Installation
144
+
145
+ ```bash
146
+ # Clone the repository
147
+ git clone https://github.com/thegalah/ts-runtime-validation.git
148
+ cd ts-runtime-validation
149
+
150
+ # Install dependencies
151
+ yarn install
152
+
153
+ # Build the project
154
+ yarn build
155
+
156
+ # Run tests
157
+ yarn test
158
+
159
+ # Link for local development
160
+ yarn link
161
+ ```
162
+
163
+ ### Development Workflow
164
+
165
+ 1. Make changes to source files in `src/`
166
+ 2. Run `yarn build` to compile TypeScript
167
+ 3. Run `yarn test` to ensure tests pass
168
+ 4. Test your changes locally using `yarn link`
169
+
170
+ ## Testing
171
+
172
+ ### Test Structure
173
+
174
+ Tests are located in `src/SchemaGenerator.test.ts` and use Jest as the testing framework.
175
+
176
+ ### Test Scenarios
177
+
178
+ 1. **Basic Scenario**: Validates simple interface generation
179
+ 2. **Duplicate Symbols (Different)**: Ensures error on conflicting definitions
180
+ 3. **Duplicate Symbols (Identical)**: Allows identical definitions across files
181
+
182
+ ### Running Tests
183
+
184
+ ```bash
185
+ # Run all tests
186
+ yarn test
187
+
188
+ # Run tests in watch mode
189
+ yarn test --watch
190
+
191
+ # Run tests with coverage
192
+ yarn test --coverage
193
+ ```
194
+
195
+ ### Writing Tests
196
+
197
+ When adding new features:
198
+
199
+ 1. Create a test scenario in `src/test/`
200
+ 2. Add test cases to `SchemaGenerator.test.ts`
201
+ 3. Ensure both positive and negative cases are covered
202
+
203
+ ## Making Changes
204
+
205
+ ### Adding Features
206
+
207
+ 1. **Identify the component** affected (CLI, SchemaGenerator, output files)
208
+ 2. **Update interfaces** if adding new options
209
+ 3. **Implement the feature** following existing patterns
210
+ 4. **Add tests** for the new functionality
211
+ 5. **Update documentation** (README.md and inline comments)
212
+
213
+ ### Common Modification Points
214
+
215
+ #### Adding a new CLI option:
216
+
217
+ 1. Update `ICommandOptions.ts` with the new field
218
+ 2. Add the option in `index.ts` using Commander
219
+ 3. Handle the option in the relevant service (FileDiscovery, SchemaProcessor, CodeGenerator, etc.)
220
+ 4. Update the SchemaGenerator constructor to pass the option to the service
221
+ 5. Update README.md with usage information and examples
222
+
223
+ #### Modifying generated output:
224
+
225
+ 1. Identify which service handles the output (CodeGenerator or SchemaWriter)
226
+ 2. Modify the appropriate service method
227
+ 3. Update the service interface if new options are needed
228
+ 4. Test with different configuration options (minify, treeShaking, lazyLoad)
229
+ 5. Ensure backward compatibility
230
+
231
+ #### Supporting new TypeScript features:
232
+
233
+ 1. Check ts-json-schema-generator compatibility
234
+ 2. Update SchemaProcessor if custom handling is needed
235
+ 3. Add test cases for the new feature in multiple scenarios
236
+ 4. Handle edge cases in schema validation and deduplication
237
+ 5. Update error handling for new failure modes
238
+
239
+ ### Code Patterns to Follow
240
+
241
+ #### Service Integration
242
+
243
+ ```typescript
244
+ // Use services instead of direct implementation
245
+ class MyNewService {
246
+ constructor(private options: MyServiceOptions) {}
247
+
248
+ async processData(): Promise<Result> {
249
+ try {
250
+ // Implementation
251
+ } catch (error) {
252
+ throw new CustomError(`Processing failed: ${error.message}`);
253
+ }
254
+ }
255
+ }
256
+
257
+ // Integrate with SchemaGenerator
258
+ this.myService = new MyNewService({
259
+ option1: options.option1,
260
+ option2: options.option2,
261
+ });
262
+ ```
263
+
264
+ #### File System Operations
265
+
266
+ ```typescript
267
+ // Use FileDiscovery service for file operations
268
+ const files = await this.fileDiscovery.discoverFiles();
269
+
270
+ // Use SchemaWriter for output operations
271
+ await this.schemaWriter.writeJsonSchema(schema, outputFile);
272
+
273
+ // Always use path utilities
274
+ const posixPath = getPosixPath(rawPath);
275
+ ```
276
+
277
+ #### AST Manipulation
278
+
279
+ ```typescript
280
+ // Use CodeGenerator service for TypeScript generation
281
+ await this.codeGenerator.generateSchemaDefinition(schemaMap, outputFile);
282
+
283
+ // For custom AST manipulation
284
+ const project = new Project(defaultTsMorphProjectSettings);
285
+ const sourceFile = project.createSourceFile(filePath, {}, { overwrite: true });
286
+
287
+ // Follow existing patterns for imports and structure
288
+ sourceFile.addImportDeclaration({
289
+ namedImports: ["Type"],
290
+ moduleSpecifier: getPosixPath("./module"),
291
+ });
292
+ ```
293
+
294
+ #### Error Handling
295
+
296
+ ```typescript
297
+ // Use custom error classes
298
+ throw new FileDiscoveryError(`No files found matching: ${glob}`, rootPath);
299
+
300
+ // Provide context with errors
301
+ throw new DuplicateSymbolError(`Symbol '${symbol}' defined differently`, symbol, filePath, existingDef, newDef);
302
+
303
+ // Format errors consistently
304
+ const message = formatError(error, verbose);
305
+ console.error(message);
306
+
307
+ // Handle errors gracefully
308
+ try {
309
+ await this.processFiles(files);
310
+ } catch (error) {
311
+ if (isKnownError(error)) {
312
+ // Handle known errors
313
+ } else {
314
+ // Handle unexpected errors
315
+ }
316
+ }
317
+ ```
318
+
319
+ ## Pull Request Process
320
+
321
+ ### Before Submitting
322
+
323
+ 1. **Fork the repository** and create a feature branch
324
+ 2. **Write tests** for your changes
325
+ 3. **Run the test suite** to ensure nothing is broken
326
+ 4. **Format your code** using Prettier: `yarn prettier`
327
+ 5. **Update documentation** if needed
328
+
329
+ ### PR Guidelines
330
+
331
+ 1. **Title**: Use a clear, descriptive title
332
+ 2. **Description**: Explain what changes you made and why
333
+ 3. **Breaking Changes**: Clearly mark if your change breaks existing functionality
334
+ 4. **Tests**: Include test results or screenshots if applicable
335
+ 5. **Issues**: Reference any related issues
336
+
337
+ ### Review Process
338
+
339
+ 1. Maintainers will review your PR
340
+ 2. Address any requested changes
341
+ 3. Once approved, your PR will be merged
342
+
343
+ ## Code Style
344
+
345
+ ### TypeScript Guidelines
346
+
347
+ - Use TypeScript strict mode
348
+ - Prefer `readonly` for immutable properties
349
+ - Use interfaces for object shapes, type aliases for unions/primitives
350
+ - Avoid `any` type; use `unknown` if type is truly unknown
351
+
352
+ ### Formatting
353
+
354
+ The project uses Prettier for consistent formatting:
355
+
356
+ ```bash
357
+ # Format all files
358
+ yarn prettier
359
+
360
+ # Check formatting without changing files
361
+ yarn prettier --check
362
+ ```
363
+
364
+ ### Naming Conventions
365
+
366
+ - **Files**: camelCase for `.ts` files, PascalCase for React components
367
+ - **Interfaces**: Prefix with `I` (e.g., `ICommandOptions`)
368
+ - **Types**: PascalCase without prefix (e.g., `UserRole`)
369
+ - **Functions**: camelCase (e.g., `generateSchema`)
370
+ - **Constants**: UPPER_SNAKE_CASE for true constants, camelCase for configuration
371
+
372
+ ### Comments and Documentation
373
+
374
+ - Use JSDoc for public APIs
375
+ - Include inline comments for complex logic
376
+ - Keep comments up-to-date with code changes
377
+
378
+ ## Debugging Tips
379
+
380
+ ### Local Testing
381
+
382
+ ```bash
383
+ # Link the package locally
384
+ yarn link
385
+
386
+ # In another project
387
+ yarn link ts-runtime-validation
388
+
389
+ # Test the CLI
390
+ ts-runtime-validation --glob "*.types.ts" --rootPath ./src
391
+ ```
392
+
393
+ ### Common Issues
394
+
395
+ 1. **Path resolution issues**: Check Windows vs POSIX paths (use `getPosixPath`)
396
+ 2. **Duplicate symbols**: Check error details in verbose mode for conflicting definitions
397
+ 3. **Missing dependencies**: Verify peer dependencies are installed
398
+ 4. **Performance issues**: Enable caching and check parallel processing settings
399
+ 5. **Memory issues**: Use lazy loading for large projects
400
+ 6. **Cache corruption**: Clear cache with `generator.clearCache()` if builds seem stale
401
+
402
+ ### Debug Output
403
+
404
+ Use the verbose flag and progress reporting:
405
+
406
+ ```typescript
407
+ // Enable verbose logging in options
408
+ const options = { ...otherOptions, verbose: true, progress: true };
409
+
410
+ // Use progress reporter for user feedback
411
+ this.progressReporter.start("Starting operation...");
412
+ this.progressReporter.update(1, "Processing files...");
413
+ this.progressReporter.complete("Operation completed");
414
+
415
+ // Log detailed information in verbose mode
416
+ if (this.options.verbose) {
417
+ console.log(`Processing file: ${file.path}`);
418
+ console.log(`Cache hit: ${!this.fileDiscovery.hasFileChanged(file.path, file.hash)}`);
419
+ }
420
+ ```
421
+
422
+ ## Getting Help
423
+
424
+ - **Issues**: Open an issue on GitHub for bugs or feature requests
425
+ - **Discussions**: Use GitHub Discussions for questions and ideas
426
+ - **Documentation**: Check the README and inline code comments
427
+
428
+ ## License
429
+
430
+ By contributing to ts-runtime-validation, you agree that your contributions will be licensed under the MIT License.