Skip to content

Commit

Permalink
Rename ts-codegen to ts-gyb (#57)
Browse files Browse the repository at this point in the history
* Rename ts-codegen to ts-gyb

* Drop @microsoft prefix

* GYB and features
  • Loading branch information
zhuorantan authored Jul 29, 2021
1 parent f9026f0 commit a9b2963
Show file tree
Hide file tree
Showing 14 changed files with 59 additions and 58 deletions.
32 changes: 19 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
# ts-codegen
# ts-gyb

ts-codegen is a multi-purpose code generation tool based on TypeScript interfaces. It was initially designed for generating boilerplate interfacing code between web and mobile platforms in hybrid apps. With custom templates, it can generate code for any use from TypeScript.
ts-gyb is a multi-purpose code generation tool based on TypeScript interfaces. It was initially designed for generating boilerplate interfacing code between web and mobile platforms in hybrid apps. With custom templates, it can generate code for any use from TypeScript.

GYB: Generate Your Boilerplate. Inspired by [swift/gyb.py](https://github.com/apple/swift/blob/main/utils/gyb.py).

## Features

- Generate production ready and well documented code from TypeScript code
- Support most of TypeScript syntax
- Fully customizable template makes the generated code fit perfectly into any project

## Installation

To use ts-codegen with an existing project managed by npm, it is recommended to install ts-codegen as a dev dependency:
To use ts-gyb with an existing project managed by npm, it is recommended to install ts-gyb as a dev dependency:

```shell
npm install --save-dev @microsoft/ts-codegen
npm install --save-dev ts-gyb
```

You can also install ts-codegen globally:
You can also install ts-gyb globally:

```shell
npm install --global @microsoft/ts-codegen
npm install --global ts-gyb
```

## Get Started
Expand All @@ -39,11 +45,11 @@ interface EditorSelection {
}
```

ts-codegen only handles method members like `methodName(): ReturnType;`. If a method needs to take in parameters, it must define one object argument. The type of this object can either be an interface or an object literal. For more information on how to write interfaces for ts-codegen, please refer to [TypeScript Interface Guide](documentation/interface-guide.md).
ts-gyb only handles method members like `methodName(): ReturnType;`. If a method needs to take in parameters, it must define one object argument. The type of this object can either be an interface or an object literal. For more information on how to write interfaces for ts-gyb, please refer to [TypeScript Interface Guide](documentation/interface-guide.md).

### 2. Provide templates

ts-codegen generates code from [mustache](http://mustache.github.io) templates. At least two templates are needed:
ts-gyb generates code from [mustache](http://mustache.github.io) templates. At least two templates are needed:

- **Module template**: used to generate a file for every TypeScript interface
- **Custom type template**: used to generate the file that hosts all TypeScript types found in method parameters or return types
Expand Down Expand Up @@ -80,16 +86,16 @@ Create a json configuration file in your project:

All paths are relative to the configuration file. For all supported options in the configuration file, please refer to [Configuration Reference](documentation/generated/interfaces/Configuration.md).

### 4. Run ts-codegen
### 4. Run ts-gyb

```shell
npx ts-codegen --config path/to/config.json
npx ts-gyb --config path/to/config.json
```

Or if ts-codegen is installed globally:
Or if ts-gyb is installed globally:

```shell
ts-codegen --config path/to/config.json
ts-gyb --config path/to/config.json
```

Generated code can be found at the output directory specified in the configuration file.
Expand All @@ -98,7 +104,7 @@ Generated code can be found at the output directory specified in the configurati

[mini-editor](demo/mini-editor) contains an iOS and an Android rich text editing app. Their editors are powered by the same TypeScript web project.

The web part provides some rich text formatting operations that can be invoked from native code (Kotlin/Swift). The operations are defined in [IEditor.ts](demo/mini-editor/web/src/editor/IEditor.ts). ts-codegen generates [EditorBridge.swift](demo/mini-editor/apple/MiniEditor/Generated/EditorBridge.swift) from that TypeScript interface.
The web part provides some rich text formatting operations that can be invoked from native code (Kotlin/Swift). The operations are defined in [IEditor.ts](demo/mini-editor/web/src/editor/IEditor.ts). ts-gyb generates [EditorBridge.swift](demo/mini-editor/apple/MiniEditor/Generated/EditorBridge.swift) from that TypeScript interface.

## Documentation

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class MainActivity : AppCompatActivity() {

fun onInsertContentButtonClick(view: View) {
bridge.insertContent("[inserted content]", true) { result ->
println("[ts-codegen] result: $result")
println("[ts-gyb] result: $result")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,33 @@ open class EditorBridge(private val webView: WebView, private val gson: Gson) :

override fun toggleBold() {
val javascriptString = "editor.toggleBold()"
println("[ts-codegen] evaluating JavaScript: $javascriptString")
println("[ts-gyb] evaluating JavaScript: $javascriptString")
webView.evaluateJavascript(javascriptString){ evaluationResult ->
println("[ts-codegen] JavaScript result: $evaluationResult")
println("[ts-gyb] JavaScript result: $evaluationResult")
}
}

override fun toggleItalic() {
val javascriptString = "editor.toggleItalic()"
println("[ts-codegen] evaluating JavaScript: $javascriptString")
println("[ts-gyb] evaluating JavaScript: $javascriptString")
webView.evaluateJavascript(javascriptString){ evaluationResult ->
println("[ts-codegen] JavaScript result: $evaluationResult")
println("[ts-gyb] JavaScript result: $evaluationResult")
}
}

override fun toggleUnderline() {
val javascriptString = "editor.toggleUnderline()"
println("[ts-codegen] evaluating JavaScript: $javascriptString")
println("[ts-gyb] evaluating JavaScript: $javascriptString")
webView.evaluateJavascript(javascriptString){ evaluationResult ->
println("[ts-codegen] JavaScript result: $evaluationResult")
println("[ts-gyb] JavaScript result: $evaluationResult")
}
}

override fun clear() {
val javascriptString = "editor.clear()"
println("[ts-codegen] evaluating JavaScript: $javascriptString")
println("[ts-gyb] evaluating JavaScript: $javascriptString")
webView.evaluateJavascript(javascriptString){ evaluationResult ->
println("[ts-codegen] JavaScript result: $evaluationResult")
println("[ts-gyb] JavaScript result: $evaluationResult")
}
}

Expand All @@ -64,7 +64,7 @@ open class EditorBridge(private val webView: WebView, private val gson: Gson) :
)
val jsonString = gson.toJson(args, Args_insertContent::class.java)
val javascriptString = "editor.insertContent($jsonString)"
println("[ts-codegen] evaluating JavaScript: $javascriptString")
println("[ts-gyb] evaluating JavaScript: $javascriptString")
webView.evaluateJavascript(javascriptString){ evaluationResult ->
val result = gson.fromJson(evaluationResult, InsertContentResult::class.java)
callback(result)
Expand Down
10 changes: 5 additions & 5 deletions demo/mini-editor/apple/MiniEditor/Generated/EditorBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class EditorBridge {
public func toggleBold(completion: ((Result<Void, Error>) -> Void)? = nil) {
let javaScriptString = "editor.toggleBold" + "(" + ")"

print("[ts-codegen] evaluating: \(javaScriptString)")
print("[ts-gyb] evaluating: \(javaScriptString)")

webView?.evaluateJavaScript(javaScriptString) { evaluationResult, error in
guard let completion = completion else { return }
Expand All @@ -35,7 +35,7 @@ public class EditorBridge {
public func toggleItalic(completion: ((Result<Void, Error>) -> Void)? = nil) {
let javaScriptString = "editor.toggleItalic" + "(" + ")"

print("[ts-codegen] evaluating: \(javaScriptString)")
print("[ts-gyb] evaluating: \(javaScriptString)")

webView?.evaluateJavaScript(javaScriptString) { evaluationResult, error in
guard let completion = completion else { return }
Expand All @@ -50,7 +50,7 @@ public class EditorBridge {
public func toggleUnderline(completion: ((Result<Void, Error>) -> Void)? = nil) {
let javaScriptString = "editor.toggleUnderline" + "(" + ")"

print("[ts-codegen] evaluating: \(javaScriptString)")
print("[ts-gyb] evaluating: \(javaScriptString)")

webView?.evaluateJavaScript(javaScriptString) { evaluationResult, error in
guard let completion = completion else { return }
Expand All @@ -65,7 +65,7 @@ public class EditorBridge {
public func clear(completion: ((Result<Void, Error>) -> Void)? = nil) {
let javaScriptString = "editor.clear" + "(" + ")"

print("[ts-codegen] evaluating: \(javaScriptString)")
print("[ts-gyb] evaluating: \(javaScriptString)")

webView?.evaluateJavaScript(javaScriptString) { evaluationResult, error in
guard let completion = completion else { return }
Expand All @@ -89,7 +89,7 @@ public class EditorBridge {
let argsString = String(data: try! jsonEncoder.encode(args), encoding: .utf8)!
let javaScriptString = "editor.insertContent" + "(" + "\(argsString)" + ")"

print("[ts-codegen] evaluating: \(javaScriptString)")
print("[ts-gyb] evaluating: \(javaScriptString)")

webView?.evaluateJavaScript(javaScriptString) { [unowned self]evaluationResult, error in
if let error = error {
Expand Down
2 changes: 1 addition & 1 deletion demo/mini-editor/apple/MiniEditor/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ extension ViewController: ToolbarDelegate {
) { result in
switch result {
case .success(let contentString):
print("[ts-codegen] contentString after insertContent(): \(contentString)")
print("[ts-gyb] contentString after insertContent(): \(contentString)")
case .failure(let error):
assertionFailure("\(error)")
}
Expand Down
4 changes: 2 additions & 2 deletions demo/mini-editor/web/code-templates/kotlin.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ open class {{moduleName}}(private val webView: WebView, private val gson: Gson)
val jsonString = gson.toJson(args, Args_{{methodName}}::class.java)
{{/parameters.length}}
val javascriptString = "{{customTags.invokePath}}.{{methodName}}({{#parameters.length}}$jsonString{{/parameters.length}})"
println("[ts-codegen] evaluating JavaScript: $javascriptString")
println("[ts-gyb] evaluating JavaScript: $javascriptString")
webView.evaluateJavascript(javascriptString){ evaluationResult ->
{{#returnType}}
val result = gson.fromJson(evaluationResult, {{{returnType}}}::class.java)
callback(result)
{{/returnType}}
{{^returnType}}
println("[ts-codegen] JavaScript result: $evaluationResult")
println("[ts-gyb] JavaScript result: $evaluationResult")
{{/returnType}}
}
}
Expand Down
2 changes: 1 addition & 1 deletion demo/mini-editor/web/code-templates/swift.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class {{moduleName}} {
{{/parameters.length}}
let javaScriptString = "{{customTags.invokePath}}.{{methodName}}" + "(" {{#parameters.length}}+ "\(argsString)"{{/parameters.length}} + ")"

print("[ts-codegen] evaluating: \(javaScriptString)")
print("[ts-gyb] evaluating: \(javaScriptString)")

webView?.evaluateJavaScript(javaScriptString) { {{#returnType}}[unowned self]{{/returnType}}evaluationResult, error in
{{^returnType}}
Expand Down
2 changes: 1 addition & 1 deletion demo/mini-editor/web/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "mini-editor-web",
"version": "0.0.1",
"description": "An end-to-end example of ts-codegen",
"description": "An end-to-end example of ts-gyb",
"main": "src/main.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
Expand Down
22 changes: 11 additions & 11 deletions documentation/interface-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Method definition

ts-codegen only recognizes interface members defined as methods.
ts-gyb only recognizes interface members defined as methods.

```typescript
/**
Expand Down Expand Up @@ -51,7 +51,7 @@ Refer to [Value types](#value-types) for allowed parameter types.
## Return type

Return type must be explicitly specified. When not provided, TypeScript would use `any` which is not supported by ts-codegen. Use `void` when the method does not return a value.
Return type must be explicitly specified. When not provided, TypeScript would use `any` which is not supported by ts-gyb. Use `void` when the method does not return a value.

Return type can be a `Promise`.

Expand All @@ -65,7 +65,7 @@ Refer to [Value types](#value-types) for allowed types as return type.
- `number`
- `boolean`

> Tips: TypeScript does not distinguish integer from float point number, and ts-codegen would map `number` to the default float point type in the target language. To map a value to integer, refer to the guide in [Integer type](#integer-type).
> Tips: TypeScript does not distinguish integer from float point number, and ts-gyb would map `number` to the default float point type in the target language. To map a value to integer, refer to the guide in [Integer type](#integer-type).
### `interface` and object literal

Expand All @@ -79,7 +79,7 @@ When an interface extends another interface, all members of the parent interface

#### Indexable types

When an interface or an object literal contains an index member, it would be parsed as [index signature](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures) and be mapped to dictionary. ts-codegen only recognizes indexable types with only one index member. Currently the index type can only be `string`. The type of the value can be any type specified in [Value types](#value-types).
When an interface or an object literal contains an index member, it would be parsed as [index signature](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures) and be mapped to dictionary. ts-gyb only recognizes indexable types with only one index member. Currently the index type can only be `string`. The type of the value can be any type specified in [Value types](#value-types).

```typescript
// allowed: indexable interface
Expand Down Expand Up @@ -186,20 +186,20 @@ type AliasDefinedInterface = { stringField: string }
### Predefined type
You can define some types as predefined. ts-codegen would treat these as known types and would assume they exist in the generated code. You must ensure these types can be correctly referenced in your project when using generated code.
You can define some types as predefined. ts-gyb would treat these as known types and would assume they exist in the generated code. You must ensure these types can be correctly referenced in your project when using generated code.
This is helpful for working around types that not supported by TypeScript or ts-codegen. [Workarounds](#workarounds) section introduces some use cases for this type.
This is helpful for working around types that not supported by TypeScript or ts-gyb. [Workarounds](#workarounds) section introduces some use cases for this type.
Refer to [Predefined Type](./predefined-type.md) for how to configure predefined types.
## Tags
ts-codegen parses tags in [JSDoc](https://jsdoc.app) documentation.
ts-gyb parses tags in [JSDoc](https://jsdoc.app) documentation.
### Built-in tags
- `@shouldExport`: Specify whether an `interface` should be exported. Set it to `true` to export.
- `@overrideModuleName`: Change the name of the interface for ts-codegen. This is helpful for dropping the `I` prefix in TypeScript interface name.
- `@overrideModuleName`: Change the name of the interface for ts-gyb. This is helpful for dropping the `I` prefix in TypeScript interface name.
- `@overrideTypeName`: Similar to `@overrideModuleName`, this is used to override the name of custom types used in method parameters or return values.
```typescript
Expand All @@ -217,7 +217,7 @@ interface InterfaceWithTags {

You can also define custom tags and use them in templates. Refer to [module in template](template-guide.md#module) for how to use them.

ts-codegen would try to parse the value of custom tags via `JSON.parse()`. If failed, it would be passed as string.
ts-gyb would try to parse the value of custom tags via `JSON.parse()`. If failed, it would be passed as string.

```typescript
/**
Expand All @@ -233,7 +233,7 @@ interface InterfaceWithTags {

## JSDoc documentation

ts-codegen would read the documentation comment from `interface` and `enum`, and their members. Documentation comment must be placed above all tags.
ts-gyb would read the documentation comment from `interface` and `enum`, and their members. Documentation comment must be placed above all tags.

```typescript
/**
Expand All @@ -254,7 +254,7 @@ interface InterfaceWithTags {

TypeScript does not have an integer type. To generate methods with an integer as a parameter or return value, you can use the combination of [Type alias](#type-alias) and [Predefined type](#predefined-type).

First, define an integer type as an alias to `number`. For basic types like `number`, `string` and `boolean`, the type alias must be branded. This is because [TypeScript interns certain types](https://github.com/microsoft/TypeScript/issues/28197#issuecomment-434027046), and ts-codegen cannot distinguish these types from the target types. Learn more about TypeScript type branding [here](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d).
First, define an integer type as an alias to `number`. For basic types like `number`, `string` and `boolean`, the type alias must be branded. This is because [TypeScript interns certain types](https://github.com/microsoft/TypeScript/issues/28197#issuecomment-434027046), and ts-gyb cannot distinguish these types from the target types. Learn more about TypeScript type branding [here](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d).

```typescript
type CodeGen_Int = number & { _intBrand: never }
Expand Down
10 changes: 5 additions & 5 deletions documentation/template-guide.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
# Template Guide

ts-codegen uses [mustache](http://mustache.github.io) template to generate code. Refer to [mustache Manul](http://mustache.github.io/mustache.5.html) for supported syntax.
ts-gyb uses [mustache](http://mustache.github.io) template to generate code. Refer to [mustache Manul](http://mustache.github.io/mustache.5.html) for supported syntax.

## Required templates

ts-codegen needs two templates: module template and named type template.
ts-gyb needs two templates: module template and named type template.

### Module template

ts-codegen uses this template to generate a file for every module. Typically, generated file includes a module class and all types used in the method parameters and return values of the module.
ts-gyb uses this template to generate a file for every module. Typically, generated file includes a module class and all types used in the method parameters and return values of the module.

### Named type template

When a TypeScript `interface` or an `enum` is used by more than one module, it is not suitable to place the generated type in any module file. ts-codegen uses this template to generate a single file that hosts all shared TypeScript types found in method parameters and return types.
When a TypeScript `interface` or an `enum` is used by more than one module, it is not suitable to place the generated type in any module file. ts-gyb uses this template to generate a single file that hosts all shared TypeScript types found in method parameters and return types.

## Variables

ts-codegen defines some variables that can be directly used in templates.
ts-gyb defines some variables that can be directly used in templates.

### Variables in templates

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@olm/ts-codegen",
"name": "ts-gyb",
"version": "0.3.0",
"description": "Generate Native API based on TS interface",
"scripts": {
Expand All @@ -18,7 +18,7 @@
},
"main": "dist/index.js",
"bin": {
"ts-codegen": "bin/ts-codegen"
"ts-gyb": "bin/ts-gyb"
},
"files": [
"dist/**/*.js",
Expand Down
5 changes: 0 additions & 5 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"paths": {
"@olm/ts-codegen-basic-type": [
"src/basic-types/types.ts"
]
},
"baseUrl": ""
}
}

0 comments on commit a9b2963

Please sign in to comment.