Skip to content

Commit 6226224

Browse files
author
Prashant Patel
committed
Adding Typescript support
1 parent 00fbcdb commit 6226224

32 files changed

+1894
-6
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33
*.swp
44
*.swo
55
*.swn
6+
*.cursorrules
7+
*/node_modules/*
8+
code-gen-projects/typescript/code-gen-demo/node_modules
9+
code-gen-projects/typescript/code-gen-demo/package-lock.json
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# TypeScript Code Generation Project
2+
3+
This directory contains a TypeScript project that demonstrates code generation using `ion-cli` with TypeScript as the target language.
4+
5+
## Project Structure
6+
7+
```
8+
typescript/
9+
├── src/
10+
│ ├── models/ # Generated TypeScript interfaces
11+
│ ├── serializers/ # Ion serialization code
12+
│ └── validators/ # Schema validation code
13+
├── tests/
14+
│ ├── good/ # Valid test cases
15+
│ └── bad/ # Invalid test cases
16+
├── package.json
17+
└── tsconfig.json
18+
```
19+
20+
## Build Process
21+
22+
The TypeScript code generation is integrated into the build process using npm scripts. The build process:
23+
24+
1. Checks for `ion-cli` availability
25+
2. Generates TypeScript code from schemas
26+
3. Compiles TypeScript to JavaScript
27+
4. Runs tests
28+
29+
### NPM Scripts
30+
31+
```json
32+
{
33+
"scripts": {
34+
"generate": "ion-cli generate -l typescript -d ../../schema -o ./src/models",
35+
"build": "tsc",
36+
"test": "jest",
37+
"clean": "rm -rf ./src/models/*"
38+
}
39+
}
40+
```
41+
42+
### Environment Setup
43+
44+
1. Install ion-cli:
45+
```bash
46+
brew install ion-cli
47+
# or
48+
cargo install ion-cli
49+
```
50+
51+
2. Set up environment:
52+
```bash
53+
export ION_CLI=/path/to/ion-cli # Optional, defaults to 'ion'
54+
```
55+
56+
## Testing
57+
58+
The project includes comprehensive tests for the generated code:
59+
60+
### Unit Tests
61+
- Type guard validation
62+
- Serialization/deserialization
63+
- Null value handling
64+
- Type annotation preservation
65+
66+
### Integration Tests
67+
- Roundtrip testing with good/bad inputs
68+
- Schema validation
69+
- Error handling
70+
71+
### Running Tests
72+
73+
```bash
74+
npm test
75+
```
76+
77+
## Type System
78+
79+
The generated TypeScript code follows these principles:
80+
81+
1. **Null Safety**
82+
- Explicit null handling
83+
- Optional type support
84+
- Undefined vs null distinction
85+
86+
2. **Type Guards**
87+
- Runtime type checking
88+
- Custom validation rules
89+
- Schema constraint validation
90+
91+
3. **Serialization**
92+
- Binary format support
93+
- Text format support
94+
- Type annotation preservation
95+
96+
## Ion Type Mappings
97+
98+
| Ion Type | TypeScript Type |
99+
|----------|----------------|
100+
| null | null |
101+
| bool | boolean |
102+
| int | number/bigint |
103+
| float | number |
104+
| decimal | Decimal |
105+
| timestamp| Date |
106+
| string | string |
107+
| symbol | Symbol |
108+
| blob | Uint8Array |
109+
| clob | string |
110+
| struct | interface |
111+
| list | Array |
112+
| sexp | Array |
113+
114+
## Error Handling
115+
116+
The generated code includes comprehensive error handling:
117+
118+
- Schema validation errors
119+
- Type conversion errors
120+
- Serialization errors
121+
- Runtime validation errors
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"root": true,
3+
"parser": "@typescript-eslint/parser",
4+
"plugins": ["@typescript-eslint"],
5+
"extends": [
6+
"eslint:recommended",
7+
"plugin:@typescript-eslint/recommended",
8+
"plugin:@typescript-eslint/recommended-requiring-type-checking"
9+
],
10+
"parserOptions": {
11+
"project": "./tsconfig.json"
12+
},
13+
"rules": {
14+
"@typescript-eslint/explicit-function-return-type": "error",
15+
"@typescript-eslint/no-explicit-any": "error",
16+
"@typescript-eslint/no-unused-vars": "error",
17+
"@typescript-eslint/strict-boolean-expressions": "error"
18+
},
19+
"ignorePatterns": ["src/generated/**/*"]
20+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# TypeScript Code Generation Demo
2+
3+
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.
4+
5+
## Project Structure
6+
7+
```
8+
code-gen-demo/
9+
├── src/
10+
│ └── generated/ # Generated TypeScript code from schemas
11+
├── tests/
12+
│ └── roundtrip.test.ts # Roundtrip tests for generated code
13+
├── package.json
14+
└── tsconfig.json
15+
```
16+
17+
## Prerequisites
18+
19+
1. Install ion-cli:
20+
```bash
21+
brew install ion-cli
22+
# or
23+
cargo install ion-cli
24+
```
25+
26+
2. Set up environment:
27+
```bash
28+
export ION_CLI=/path/to/ion-cli # Optional, defaults to 'ion'
29+
export ION_INPUT=/path/to/input # Required for tests
30+
```
31+
32+
## Build Process
33+
34+
The build process is integrated with npm scripts:
35+
36+
1. `npm run generate` - Generates TypeScript code from schemas
37+
2. `npm run build` - Compiles TypeScript to JavaScript
38+
3. `npm test` - Runs the test suite
39+
40+
## Running Tests
41+
42+
The tests verify that the generated code can:
43+
- Read Ion data into TypeScript objects
44+
- Write TypeScript objects back to Ion format
45+
- Handle both valid and invalid input correctly
46+
47+
To run the tests:
48+
49+
```bash
50+
# From the code-gen-demo directory
51+
ION_INPUT=../../input npm test
52+
```
53+
54+
## Test Cases
55+
56+
1. Good Input Tests:
57+
- Struct with fields
58+
- Sequences
59+
- Enum types
60+
- Nested structures
61+
- Type annotations
62+
63+
2. Bad Input Tests:
64+
- Invalid struct fields
65+
- Invalid sequence elements
66+
- Invalid enum values
67+
- Type mismatches
68+
69+
## Generated Code Features
70+
71+
The generated TypeScript code includes:
72+
- Type-safe interfaces
73+
- Runtime type guards
74+
- Ion serialization/deserialization
75+
- Null safety
76+
- Type annotations support
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"name": "ion-cli-typescript-demo",
3+
"version": "1.0.0",
4+
"description": "TypeScript code generation demo for ion-cli",
5+
"scripts": {
6+
"pregenerate": "rimraf src/generated/*",
7+
"generate": "ion-cli generate -l typescript -d ../../schema -o ./src/generated",
8+
"prebuild": "npm run generate",
9+
"build": "tsc --noEmit && tsc",
10+
"lint": "eslint . --ext .ts",
11+
"pretest": "npm run build",
12+
"test": "jest --coverage",
13+
"clean": "rimraf dist src/generated/* coverage"
14+
},
15+
"dependencies": {
16+
"ion-js": "^4.3.0",
17+
"decimal.js": "^10.4.3"
18+
},
19+
"devDependencies": {
20+
"@types/jest": "^29.5.0",
21+
"@types/node": "^18.15.11",
22+
"@typescript-eslint/eslint-plugin": "^6.4.0",
23+
"@typescript-eslint/parser": "^6.4.0",
24+
"eslint": "^8.47.0",
25+
"jest": "^29.5.0",
26+
"rimraf": "^5.0.0",
27+
"ts-jest": "^29.1.0",
28+
"typescript": "^5.0.3"
29+
},
30+
"jest": {
31+
"preset": "ts-jest",
32+
"testEnvironment": "node",
33+
"roots": [
34+
"<rootDir>/src",
35+
"<rootDir>/tests"
36+
],
37+
"moduleNameMapper": {
38+
"@generated/(.*)": "<rootDir>/src/generated/$1"
39+
},
40+
"collectCoverageFrom": [
41+
"src/**/*.ts",
42+
"!src/generated/**/*.ts"
43+
],
44+
"coverageThreshold": {
45+
"global": {
46+
"branches": 80,
47+
"functions": 80,
48+
"lines": 80,
49+
"statements": 80
50+
}
51+
}
52+
}
53+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import * as ion from 'ion-js';
2+
import { IonSerializable } from './ion_generated_code';
3+
4+
5+
6+
export enum EnumType {FOO_BAR_BAZ = "FooBarBaz", BAR = "bar", BAZ = "baz", FOO = "foo"
7+
}
8+
9+
/**
10+
* Type guard for EnumType
11+
* @param value - Value to check
12+
* @returns True if value is EnumType
13+
*/
14+
export function isEnumType(value: any): value is EnumType {
15+
return Object.values(EnumType).includes(value);
16+
}
17+
18+
/**
19+
* Implementation class for EnumType serialization
20+
*/
21+
export class EnumTypeImpl implements IonSerializable {
22+
private value: EnumType;
23+
24+
constructor(value: EnumType) {
25+
this.value = value;
26+
}
27+
28+
/**
29+
* Serialize to Ion format
30+
* @returns Serialized bytes
31+
*/
32+
public toIon(): any {
33+
const writer = ion.makeTextWriter();
34+
writer.writeSymbol(this.value);
35+
return writer.getBytes();
36+
}
37+
38+
/**
39+
* Deserialize from Ion format
40+
* @param reader - Ion reader
41+
* @returns Deserialized EnumType
42+
* @throws Error if value is invalid
43+
*/
44+
public static fromIon(reader: ion.Reader): EnumType {
45+
const value = reader.stringValue();
46+
if (!value || !isEnumType(value)) {
47+
throw new Error(`Invalid enum value for EnumType: ${value}`);
48+
}
49+
return value as EnumType;
50+
}
51+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as ion from 'ion-js';
2+
import { Decimal } from 'decimal.js';
3+
4+
export interface IonSerializable {
5+
toIon(): any;
6+
}
7+
8+
export interface IonSymbol {
9+
text: string;
10+
sid?: number;
11+
local_sid?: number;
12+
}
13+
14+
export interface IonTimestamp {
15+
value: Date;
16+
}
17+
18+
export interface IonDecimal {
19+
value: string;
20+
coefficient: bigint;
21+
exponent: number;
22+
}
23+
24+
// Re-export the Ion types we need
25+
export const { LIST: ListType, STRUCT: StructType } = ion.IonTypes;

0 commit comments

Comments
 (0)