Skip to content

Commit

Permalink
Merge branch 'next' into cli_update_readme_and_usage
Browse files Browse the repository at this point in the history
  • Loading branch information
jonaslagoni committed Apr 19, 2024
2 parents 72b552f + 981823c commit 6699975
Show file tree
Hide file tree
Showing 31 changed files with 939 additions and 34 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/upload-release-assets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
if: startsWith(github.event.commits[0].message, 'chore(release):')
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
Expand Down Expand Up @@ -65,6 +66,7 @@ jobs:
- name: Build project
run: npm run prepublishOnly
- name: Assets generation
shell: bash
run: cd modelina-cli && npm run ${{ matrix.npm_script }}
- name: Update release
uses: softprops/action-gh-release@v1
Expand Down
25 changes: 25 additions & 0 deletions docs/migrations/version-3-to-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,28 @@ class Address:
### File names

In v4, file names for go will be formatted as `snake_case.go`. This is the "standard" in go: https://github.com/golang/go/issues/36060


### Union types will be generated correctly with struct embeddings

Modelina now supports union types for `Go`. Since `Go` does not have native union types support modelina uses `struct embeddings` to mock union types.

```go
type Union struct {
CustomStruct
int
string
ModelinaArrType []string
ModelinaDictType map[string] interface{}
ModelinaAnyType interface {}
}
```
`ModelinaArrType`, `ModelinaDictType`, `ModelinaAnyType` are generated by default by modelina, users can change the names by passing different names to the `GoGenerator Options`, for example:

```ts
const generator = new GoGenerator({
unionAnyModelName: 'ModelinaAnyType',
unionArrModelName: 'ModelinaArrType',
unionDictModelName: 'ModelinaDictType'
});
```
26 changes: 26 additions & 0 deletions examples/go-union-type/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Go Union Types

Modelina now supports union types for `Go`. Since `Go` does not have native union types support modelina uses `struct embeddings` to mock union types. Modelina has custom names for models that are not directly embedded in structs. Users can update the default names by passing custom values.


```ts
const generator = new GoGenerator({
unionAnyModelName: 'ModelinaAnyType',
unionArrModelName: 'ModelinaArrType',
unionDictModelName: 'ModelinaDictType'
});
```

## How to run this example

Run this example using:

```sh
npm i && npm run start
```

If you are on Windows, use the `start:windows` script instead:

```sh
npm i && npm run start:windows
```
64 changes: 64 additions & 0 deletions examples/go-union-type/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Should be able to render union types and should log expected output to console 1`] = `
Array [
"// AdditionalProperty represents a AdditionalProperty model.
type AdditionalProperty struct {
AdditionalPropertyOneOf_0
AdditionalPropertyOneOf_1
string
float64
ModelinaArrType []string
ModelinaArrType []Union
AdditionalPropertyOneOf_6
}",
]
`;

exports[`Should be able to render union types and should log expected output to console 2`] = `
Array [
"// Union represents a Union model.
type Union struct {
string
float64
ModelinaAnyType interface{}
}",
]
`;

exports[`Should be able to render union types and should log expected output to console 3`] = `
Array [
"// AdditionalPropertyOneOf_6 represents a AdditionalPropertyOneOf_6 model.
type AdditionalPropertyOneOf_6 struct {
string
float64
bool
}",
]
`;

exports[`Should be able to render union types and should log expected output to console 4`] = `
Array [
"",
]
`;

exports[`Should be able to render union types and should log expected output to console 5`] = `
Array [
"// AdditionalPropertyOneOf_0 represents a AdditionalPropertyOneOf_0 model.
type AdditionalPropertyOneOf_0 struct {
Ref string
AdditionalProperties map[string]interface{}
}",
]
`;

exports[`Should be able to render union types and should log expected output to console 6`] = `
Array [
"// AdditionalPropertyOneOf_1 represents a AdditionalPropertyOneOf_1 model.
type AdditionalPropertyOneOf_1 struct {
Id string
AdditionalProperties map[string]interface{}
}",
]
`;
20 changes: 20 additions & 0 deletions examples/go-union-type/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const spy = jest.spyOn(global.console, 'log').mockImplementation(() => {
return;
});
import { generate } from './index';

describe('Should be able to render union types', () => {
afterAll(() => {
jest.restoreAllMocks();
});
test('and should log expected output to console', async () => {
await generate();
expect(spy.mock.calls.length).toEqual(6);
expect(spy.mock.calls[0]).toMatchSnapshot();
expect(spy.mock.calls[1]).toMatchSnapshot();
expect(spy.mock.calls[2]).toMatchSnapshot();
expect(spy.mock.calls[3]).toMatchSnapshot();
expect(spy.mock.calls[4]).toMatchSnapshot();
expect(spy.mock.calls[5]).toMatchSnapshot();
});
});
33 changes: 33 additions & 0 deletions examples/go-union-type/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { GoGenerator } from '../../src';

const generator = new GoGenerator({
unionAnyModelName: 'ModelinaAnyType',
unionArrModelName: 'ModelinaArrType',
unionDictModelName: 'ModelinaDictType'
});

const jsonSchemaDraft7 = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
additionalProperties: {
oneOf: [
{ type: 'object', properties: { ref: { type: 'string' } } },
{ type: 'object', properties: { Id: { type: 'string' } } },
{ type: 'string' },
{ type: 'number' },
{ type: 'array', items: { type: 'string' } },
{ type: 'array', items: [{ type: 'string' }, { type: 'number' }] },
{ oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }] }
]
}
};

export async function generate(): Promise<void> {
const models = await generator.generate(jsonSchemaDraft7);
for (const model of models) {
console.log(model.result);
}
}
if (require.main === module) {
generate();
}
10 changes: 10 additions & 0 deletions examples/go-union-type/package-lock.json

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

10 changes: 10 additions & 0 deletions examples/go-union-type/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"config" : { "example_name" : "go-union-type" },
"scripts": {
"install": "cd ../.. && npm i",
"start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts",
"start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts",
"test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts",
"test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts"
}
}
4 changes: 2 additions & 2 deletions modelina-cli/package-lock.json

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

2 changes: 1 addition & 1 deletion modelina-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@asyncapi/modelina-cli",
"description": "CLI to work with Modelina",
"version": "4.0.0-next.24",
"version": "4.0.0-next.27",
"bin": {
"modelina": "./bin/run"
},
Expand Down
3 changes: 2 additions & 1 deletion modelina-cli/scripts/releasePackagesRename.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ async function checkAndRenameFile(generatedPath, newPath) {
}

async function createDirectory(directoryPath) {
if (await fileExists(directoryPath)) {
const exists = await fileExists(directoryPath);
if (!exists) {
await mkdir(directoryPath);
}
}
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@asyncapi/modelina",
"version": "4.0.0-next.24",
"version": "4.0.0-next.27",
"description": "Library for generating data models based on inputs such as AsyncAPI, OpenAPI, or JSON Schema documents",
"license": "Apache-2.0",
"homepage": "https://www.modelina.org",
Expand Down
4 changes: 2 additions & 2 deletions src/generators/go/GoConstrainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ export const GoDefaultTypeMapping: GoTypeMapping = {
Enum({ constrainedModel }): string {
return constrainedModel.name;
},
Union(): string {
Union({ constrainedModel }): string {
//Because Go have no notion of unions (and no custom implementation), we have to render it as any value.
return 'interface{}';
return constrainedModel.name;
},
Dictionary({ constrainedModel }): string {
return `map[${constrainedModel.key.type}]${constrainedModel.value.type}`;
Expand Down
54 changes: 49 additions & 5 deletions src/generators/go/GoGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ConstrainedObjectModel,
ConstrainedEnumModel,
ConstrainedMetaModel,
ConstrainedUnionModel,
MetaModel
} from '../../models';
import {
Expand All @@ -32,10 +33,20 @@ import { Logger } from '../../utils/LoggingInterface';
import { GoDefaultConstraints, GoDefaultTypeMapping } from './GoConstrainer';
import { DeepPartial, mergePartialAndDefault } from '../../utils/Partials';
import { GoDependencyManager } from './GoDependencyManager';
import { UnionRenderer } from './renderers/UnionRenderer';

/**
* @typedef GoOptions
* @prop {string} unionAnyModelName Change default name for any models.
* @prop {string} unionDictModelName Change default name for Dictionary Models.
* @prop {string} unionArrModelName Change default name for Array models.
*/
export interface GoOptions extends CommonGeneratorOptions<GoPreset> {
typeMapping: TypeMapping<GoOptions, GoDependencyManager>;
constraints: Constraints<GoOptions>;
unionAnyModelName: string;
unionDictModelName: string;
unionArrModelName: string;
}
export type GoConstantConstraint = ConstantConstraint<GoOptions>;
export type GoEnumKeyConstraint = EnumKeyConstraint<GoOptions>;
Expand All @@ -48,9 +59,6 @@ export interface GoRenderCompleteModelOptions {
packageName: string;
}

/**
* Generator for Go
*/
export class GoGenerator extends AbstractGenerator<
GoOptions,
GoRenderCompleteModelOptions
Expand All @@ -59,7 +67,10 @@ export class GoGenerator extends AbstractGenerator<
...defaultGeneratorOptions,
defaultPreset: GO_DEFAULT_PRESET,
typeMapping: GoDefaultTypeMapping,
constraints: GoDefaultConstraints
constraints: GoDefaultConstraints,
unionAnyModelName: 'ModelinaAnyType',
unionDictModelName: 'ModelinaDictType',
unionArrModelName: 'ModelinaArrType'
};

static defaultCompleteModelOptions: GoRenderCompleteModelOptions = {
Expand Down Expand Up @@ -99,7 +110,8 @@ export class GoGenerator extends AbstractGenerator<
//These are the models that we have separate renderers for
const metaModelsToSplit: SplitOptions = {
splitEnum: true,
splitObject: true
splitObject: true,
splitUnion: true
};
return split(model, metaModelsToSplit);
}
Expand Down Expand Up @@ -142,6 +154,12 @@ export class GoGenerator extends AbstractGenerator<
args.inputModel,
optionsToUse
);
} else if (args.constrainedModel instanceof ConstrainedUnionModel) {
return this.renderUnion(
args.constrainedModel,
args.inputModel,
optionsToUse
);
}
Logger.warn(
`Go generator, cannot generate this type of model, ${args.constrainedModel.name}`
Expand Down Expand Up @@ -255,4 +273,30 @@ ${outputModel.result}`;
dependencies: dependencyManagerToUse.dependencies
});
}
async renderUnion(
model: ConstrainedUnionModel,
inputModel: InputMetaModel,
options?: DeepPartial<GoOptions>
): Promise<RenderOutput> {
const optionsToUse = GoGenerator.getGoOptions({
...this.options,
...options
});
const dependencyManagerToUse = this.getDependencyManager(optionsToUse);
const presets = this.getPresets('union');
const renderer = new UnionRenderer(
optionsToUse,
this,
presets,
model,
inputModel,
dependencyManagerToUse
);
const result = await renderer.runSelfPreset();
return RenderOutput.toRenderOutput({
result,
renderedName: model.name,
dependencies: dependencyManagerToUse.dependencies
});
}
}
Loading

0 comments on commit 6699975

Please sign in to comment.