-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Prashant Patel
committed
Jan 9, 2025
1 parent
00fbcdb
commit 530e544
Showing
15 changed files
with
917 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
*.swp | ||
*.swo | ||
*.swn | ||
*.cursorrules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# TypeScript Code Generation Project | ||
|
||
This directory contains a TypeScript project that demonstrates code generation using `ion-cli` with TypeScript as the target language. | ||
|
||
## Project Structure | ||
|
||
``` | ||
typescript/ | ||
├── src/ | ||
│ ├── models/ # Generated TypeScript interfaces | ||
│ ├── serializers/ # Ion serialization code | ||
│ └── validators/ # Schema validation code | ||
├── tests/ | ||
│ ├── good/ # Valid test cases | ||
│ └── bad/ # Invalid test cases | ||
├── package.json | ||
└── tsconfig.json | ||
``` | ||
|
||
## Build Process | ||
|
||
The TypeScript code generation is integrated into the build process using npm scripts. The build process: | ||
|
||
1. Checks for `ion-cli` availability | ||
2. Generates TypeScript code from schemas | ||
3. Compiles TypeScript to JavaScript | ||
4. Runs tests | ||
|
||
### NPM Scripts | ||
|
||
```json | ||
{ | ||
"scripts": { | ||
"generate": "ion-cli generate -l typescript -d ../../schema -o ./src/models", | ||
"build": "tsc", | ||
"test": "jest", | ||
"clean": "rm -rf ./src/models/*" | ||
} | ||
} | ||
``` | ||
|
||
### Environment Setup | ||
|
||
1. Install ion-cli: | ||
```bash | ||
brew install ion-cli | ||
# or | ||
cargo install ion-cli | ||
``` | ||
|
||
2. Set up environment: | ||
```bash | ||
export ION_CLI=/path/to/ion-cli # Optional, defaults to 'ion' | ||
``` | ||
|
||
## Testing | ||
|
||
The project includes comprehensive tests for the generated code: | ||
|
||
### Unit Tests | ||
- Type guard validation | ||
- Serialization/deserialization | ||
- Null value handling | ||
- Type annotation preservation | ||
|
||
### Integration Tests | ||
- Roundtrip testing with good/bad inputs | ||
- Schema validation | ||
- Error handling | ||
|
||
### Running Tests | ||
|
||
```bash | ||
npm test | ||
``` | ||
|
||
## Type System | ||
|
||
The generated TypeScript code follows these principles: | ||
|
||
1. **Null Safety** | ||
- Explicit null handling | ||
- Optional type support | ||
- Undefined vs null distinction | ||
|
||
2. **Type Guards** | ||
- Runtime type checking | ||
- Custom validation rules | ||
- Schema constraint validation | ||
|
||
3. **Serialization** | ||
- Binary format support | ||
- Text format support | ||
- Type annotation preservation | ||
|
||
## Ion Type Mappings | ||
|
||
| Ion Type | TypeScript Type | | ||
|----------|----------------| | ||
| null | null | | ||
| bool | boolean | | ||
| int | number/bigint | | ||
| float | number | | ||
| decimal | Decimal | | ||
| timestamp| Date | | ||
| string | string | | ||
| symbol | Symbol | | ||
| blob | Uint8Array | | ||
| clob | string | | ||
| struct | interface | | ||
| list | Array | | ||
| sexp | Array | | ||
|
||
## Error Handling | ||
|
||
The generated code includes comprehensive error handling: | ||
|
||
- Schema validation errors | ||
- Type conversion errors | ||
- Serialization errors | ||
- Runtime validation errors |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# TypeScript Code Generation Demo | ||
|
||
This project demonstrates code generation using `ion-cli` with TypeScript as the target language. It uses the schema files from the parent directory and tests the generated code against both good and bad input files. | ||
|
||
## Project Structure | ||
|
||
``` | ||
code-gen-demo/ | ||
├── src/ | ||
│ └── generated/ # Generated TypeScript code from schemas | ||
├── tests/ | ||
│ └── roundtrip.test.ts # Roundtrip tests for generated code | ||
├── package.json | ||
└── tsconfig.json | ||
``` | ||
|
||
## Prerequisites | ||
|
||
1. Install ion-cli: | ||
```bash | ||
brew install ion-cli | ||
# or | ||
cargo install ion-cli | ||
``` | ||
|
||
2. Set up environment: | ||
```bash | ||
export ION_CLI=/path/to/ion-cli # Optional, defaults to 'ion' | ||
export ION_INPUT=/path/to/input # Required for tests | ||
``` | ||
|
||
## Build Process | ||
|
||
The build process is integrated with npm scripts: | ||
|
||
1. `npm run generate` - Generates TypeScript code from schemas | ||
2. `npm run build` - Compiles TypeScript to JavaScript | ||
3. `npm test` - Runs the test suite | ||
|
||
## Running Tests | ||
|
||
The tests verify that the generated code can: | ||
- Read Ion data into TypeScript objects | ||
- Write TypeScript objects back to Ion format | ||
- Handle both valid and invalid input correctly | ||
|
||
To run the tests: | ||
|
||
```bash | ||
# From the code-gen-demo directory | ||
ION_INPUT=../../input npm test | ||
``` | ||
|
||
## Test Cases | ||
|
||
1. Good Input Tests: | ||
- Struct with fields | ||
- Sequences | ||
- Enum types | ||
- Nested structures | ||
- Type annotations | ||
|
||
2. Bad Input Tests: | ||
- Invalid struct fields | ||
- Invalid sequence elements | ||
- Invalid enum values | ||
- Type mismatches | ||
|
||
## Generated Code Features | ||
|
||
The generated TypeScript code includes: | ||
- Type-safe interfaces | ||
- Runtime type guards | ||
- Ion serialization/deserialization | ||
- Null safety | ||
- Type annotations support |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"name": "ion-cli-typescript-demo", | ||
"version": "1.0.0", | ||
"description": "TypeScript code generation demo for ion-cli", | ||
"scripts": { | ||
"pregenerate": "rimraf src/generated/*", | ||
"generate": "ion-cli generate -l typescript -d ../../schema -o ./src/generated", | ||
"prebuild": "npm run generate", | ||
"build": "tsc", | ||
"pretest": "npm run build", | ||
"test": "jest", | ||
"clean": "rimraf dist src/generated/*" | ||
}, | ||
"dependencies": { | ||
"ion-js": "^4.3.0", | ||
"decimal.js": "^10.4.3" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^29.5.0", | ||
"@types/node": "^18.15.11", | ||
"jest": "^29.5.0", | ||
"rimraf": "^5.0.0", | ||
"ts-jest": "^29.1.0", | ||
"typescript": "^5.0.3" | ||
}, | ||
"jest": { | ||
"preset": "ts-jest", | ||
"testEnvironment": "node", | ||
"roots": [ | ||
"<rootDir>/src", | ||
"<rootDir>/tests" | ||
], | ||
"moduleNameMapper": { | ||
"@generated/(.*)": "<rootDir>/src/generated/$1" | ||
} | ||
} | ||
} |
103 changes: 103 additions & 0 deletions
103
code-gen-projects/typescript/code-gen-demo/tests/roundtrip.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { readFileSync } from 'fs'; | ||
import { makeReader, makeWriter } from 'ion-js'; | ||
import path from 'path'; | ||
|
||
// Import all generated types (these will be available after code generation) | ||
import * as generated from '@generated/index'; | ||
|
||
describe('Ion TypeScript Code Generation Tests', () => { | ||
const ION_INPUT = process.env.ION_INPUT || '../../input'; | ||
|
||
const readIonFile = (filePath: string) => { | ||
const fullPath = path.join(ION_INPUT, filePath); | ||
return readFileSync(fullPath); | ||
}; | ||
|
||
describe('Good Input Tests', () => { | ||
test('struct_with_fields roundtrip', () => { | ||
const data = readIonFile('good/struct_with_fields.ion'); | ||
const reader = makeReader(data); | ||
|
||
// Read from Ion | ||
const value = generated.StructWithFields.fromIon(reader); | ||
expect(value).toBeDefined(); | ||
|
||
// Write back to Ion | ||
const writer = makeWriter(); | ||
value.toIon(writer); | ||
const serialized = writer.getBytes(); | ||
|
||
// Read again and compare | ||
const newReader = makeReader(serialized); | ||
const newValue = generated.StructWithFields.fromIon(newReader); | ||
expect(newValue).toEqual(value); | ||
}); | ||
|
||
test('sequence roundtrip', () => { | ||
const data = readIonFile('good/sequence.ion'); | ||
const reader = makeReader(data); | ||
|
||
// Read from Ion | ||
const value = generated.Sequence.fromIon(reader); | ||
expect(value).toBeDefined(); | ||
|
||
// Write back to Ion | ||
const writer = makeWriter(); | ||
value.toIon(writer); | ||
const serialized = writer.getBytes(); | ||
|
||
// Read again and compare | ||
const newReader = makeReader(serialized); | ||
const newValue = generated.Sequence.fromIon(newReader); | ||
expect(newValue).toEqual(value); | ||
}); | ||
|
||
test('enum_type roundtrip', () => { | ||
const data = readIonFile('good/enum_type.ion'); | ||
const reader = makeReader(data); | ||
|
||
// Read from Ion | ||
const value = generated.EnumType.fromIon(reader); | ||
expect(value).toBeDefined(); | ||
|
||
// Write back to Ion | ||
const writer = makeWriter(); | ||
value.toIon(writer); | ||
const serialized = writer.getBytes(); | ||
|
||
// Read again and compare | ||
const newReader = makeReader(serialized); | ||
const newValue = generated.EnumType.fromIon(newReader); | ||
expect(newValue).toEqual(value); | ||
}); | ||
}); | ||
|
||
describe('Bad Input Tests', () => { | ||
test('invalid struct_with_fields', () => { | ||
const data = readIonFile('bad/struct_with_fields.ion'); | ||
const reader = makeReader(data); | ||
|
||
expect(() => { | ||
generated.StructWithFields.fromIon(reader); | ||
}).toThrow(); | ||
}); | ||
|
||
test('invalid sequence', () => { | ||
const data = readIonFile('bad/sequence.ion'); | ||
const reader = makeReader(data); | ||
|
||
expect(() => { | ||
generated.Sequence.fromIon(reader); | ||
}).toThrow(); | ||
}); | ||
|
||
test('invalid enum_type', () => { | ||
const data = readIonFile('bad/enum_type.ion'); | ||
const reader = makeReader(data); | ||
|
||
expect(() => { | ||
generated.EnumType.fromIon(reader); | ||
}).toThrow(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "ES2020", | ||
"module": "commonjs", | ||
"lib": ["ES2020"], | ||
"declaration": true, | ||
"outDir": "./dist", | ||
"rootDir": "./", | ||
"strict": true, | ||
"noImplicitAny": true, | ||
"strictNullChecks": true, | ||
"strictFunctionTypes": true, | ||
"strictBindCallApply": true, | ||
"strictPropertyInitialization": true, | ||
"noImplicitThis": true, | ||
"alwaysStrict": true, | ||
"noUnusedLocals": true, | ||
"noUnusedParameters": true, | ||
"noImplicitReturns": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"moduleResolution": "node", | ||
"baseUrl": "./", | ||
"paths": { | ||
"@generated/*": ["src/generated/*"] | ||
}, | ||
"esModuleInterop": true, | ||
"skipLibCheck": true, | ||
"forceConsistentCasingInFileNames": true | ||
}, | ||
"include": [ | ||
"src/**/*", | ||
"tests/**/*" | ||
], | ||
"exclude": [ | ||
"node_modules", | ||
"dist" | ||
] | ||
} |
Oops, something went wrong.