diff --git a/.all-contributorsrc b/.all-contributorsrc index d8f00878dd..c361fe7f22 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -400,6 +400,18 @@ "example" ] }, + { + "login": "zaytsevand", + "name": "Andrey Zaytsev", + "avatar_url": "https://avatars.githubusercontent.com/u/5207748?v=4", + "profile": "https://github.com/zaytsevand", + "contributions": [ + "code", + "example", + "doc", + "test" + ] + }, { "login": "codingtenshi", "name": "Tenshi Codes", @@ -439,6 +451,17 @@ "test" ] }, + { + "login": "anaysarkar7", + "name": "Anay Sarkar", + "avatar_url": "https://avatars.githubusercontent.com/u/53341181?v=4", + "profile": "https://linktr.ee/anaysarkar7", + "contributions": [ + "example", + "code", + "test" + ] + }, { "login": "LouisXhaferi", "name": "Louis Xhaferi", diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..06ec17bab4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +.github/ +docs/ diff --git a/.eslintignore b/.eslintignore index d82e24ca22..0701a4ffd0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,9 @@ node_modules docs lib -output \ No newline at end of file +output +src/generators/template +test/generators/template +examples/integrate-with-react +src/processors/TemplateInputProcessor.ts +test/processors/TemplateInputProcessor.spec.ts \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 681325a8cc..5efde8c889 100644 --- a/.eslintrc +++ b/.eslintrc @@ -4,14 +4,16 @@ "@typescript-eslint", "sonarjs", "security", - "github" + "github", + "prettier" ], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", "plugin:sonarjs/recommended", - "plugin:security/recommended" + "plugin:security/recommended", + "prettier" ], "rules": { "strict": 0, @@ -78,10 +80,6 @@ ], "no-spaced-func": 2, "semi-spacing": 2, - "quotes": [ - 2, - "single" - ], "key-spacing": [ 2, { @@ -89,19 +87,8 @@ "afterColon": true } ], - "indent": [ - 2, - 2 - ], "no-lonely-if": 2, "no-floating-decimal": 2, - "brace-style": [ - 2, - "1tbs", - { - "allowSingleLine": true - } - ], "comma-style": [ 2, "last" @@ -183,7 +170,9 @@ "prefer-const": 2, "prefer-spread": 2, "prefer-template": 2, - "@typescript-eslint/no-unused-vars": 2 + "@typescript-eslint/no-unused-vars": 2, + "prettier/prettier": 2, + "sonarjs/no-identical-functions": "off" }, "overrides": [ { diff --git a/.github/workflows/if-nodejs-release.yml b/.github/workflows/if-nodejs-release.yml index 73bffb04ad..15eb3ac743 100644 --- a/.github/workflows/if-nodejs-release.yml +++ b/.github/workflows/if-nodejs-release.yml @@ -10,6 +10,7 @@ on: - master # below lines are not enough to have release supported for these branches # make sure configuration of `semantic-release` package mentions these branches + - next - next-spec - next-major - next-major-spec diff --git a/.gitignore b/.gitignore index d6c16e1b48..3cc80de7e1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ node_modules .vscode coverage lib -*.DS_Store \ No newline at end of file +*.DS_Store +.idea +output diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000..fc98bd3760 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": true, + "trailingComma": "none", + "singleQuote": true, + "printWidth": 80 +} \ No newline at end of file diff --git a/API.md b/API.md index 16026a4649..4dbac13865 100644 --- a/API.md +++ b/API.md @@ -15,9 +15,6 @@ https://www.asyncapi.com/docs/specifications/v2.2.0#schemaObject https://www.asyncapi.com/docs/specifications/v2.3.0#schemaObject
-This class is the wrapper for simplified models and the rest of the context needed for further generate typed models.
-Common internal representation for a model.
JSON Draft7Schema Draft 7 model
Since each input processor can create multiple meta models this is a wrapper to a MetaModel to make that possible.
+OpenAPI 3.0 -> 3.0.4 schema model
Based on Draft 6, but with restricted keywords and definitions @@ -77,34 +77,63 @@ Modifications
Class for processing Swagger inputs
Class for processing X input
+Logger class for the model generation library
This class acts as a forefront for any external loggers which is why it also implements the interface itself.
Default property names for different aspects of the common model
+Converts a CommonModel into multiple models wrapped in a union model.
+Because a CommonModel might contain multiple models, it's name for each of those models would be the same, instead we slightly change the model name. +Each model has it's type as a name prepended to the union name.
+If the CommonModel has multiple types
A CommonNamingConvention implementation shared between generators for different languages.
+Determine whether we have a dictionary or an object. because in some cases inputs might be: +{ "type": "object", "additionalProperties": { "$ref": "#" } } which is to be interpreted as a dictionary not an object model.
Recursively find the proper property name.
-This function ensures that the property name is unique for the model
+Return the original input based on additionalProperties and patternProperties.
+Function creating the right meta model based on additionalProperties and patternProperties.
+Because a lot of the other constrain functions (such as NO_NUMBER_START_CHAR, NO_EMPTY_VALUE, etc) they might manipulate the property names by append, prepend, or manipulate it any other way.
+We then need to make sure that they don't clash with any existing properties, this is what this function handles.
+If so, prepend reserved_
to the property name and recheck.
string
Because a lot of the other constrain functions (such as NO_NUMBER_START_CHAR, NO_EMPTY_VALUE, etc) they might manipulate the enum keys by append, prepend, or manipulate it any other way.
+We then need to make sure that they don't clash with any existing enum keys, this is what this function handles.
+If so, prepend reserved_
to the enum key and recheck.
Function to make it easier to render JS/TS dependencies based on module system
+Function to make an array of ConstrainedMetaModels only contain unique values (ignores different in memory instances)
+Convert a string into utf-8 encoding and return the byte size.
Returns true if and only if a given preset is already included in a list of presets Check is done using referential equality
Try split the model
+Overwrite the nested models with references where required.
+Interpreter function for additionalItems keyword.
Interpreter function for allOf keyword.
It either merges allOf schemas into existing model or if allowed, create inheritance.
Interpreter function for anyOf keyword.
+It puts the schema reference into the items field.
+Interpreter function for const keyword for draft version > 4
Interpreter function for not keyword.
Interpreter function for oneOf keyword.
+It puts the schema reference into the items field.
+Interpreter function for oneOf keyword combined with the allOf keyword.
+It merges the allOf schemas into all of the oneOf schemas. Shared properties are merged. The oneOf schemas are then added as union to the model.
+Interpreter function for oneOf keyword combined with properties.
+It merges the properties of the schema into the oneOf schemas. Shared properties are merged. The oneOf schemas are then added as union to the model.
+Interpreter function for patternProperties keyword.
Interpreter function for interpreting properties keyword.
Post process the interpreted model. By applying the following:
-This function splits up a model if needed and add the new model to the list of models.
-Split up all models which should and use ref instead.
-Check if CommonModel is an enum
Find the name for simplified version of schema
Return true or false based on whether the input object is a regular object or a class
+Taken from: https://stackoverflow.com/a/43197340/6803886
+Merge a non optional value with custom optional values to form a full value that has all properties sat.
+AbstractGenerator
](#AbstractGenerator)
-### abstractGenerator.generateCompleteModels(input, options)
+### abstractGenerator.generateCompleteModels()
Generates the full output of a model, instead of a scattered model.
OutputModels result is no longer the model itself, but including package, package dependencies and model dependencies.
**Kind**: instance method of [AbstractGenerator
](#AbstractGenerator)
-
-| Param | Description |
-| --- | --- |
-| input | |
-| options | to use for rendering full output |
-
-### abstractGenerator.generate(input)
+### abstractGenerator.generate()
Generates a scattered model where dependencies and rendered results are separated.
**Kind**: instance method of [AbstractGenerator
](#AbstractGenerator)
-
-| Param |
-| --- |
-| input |
-
### abstractGenerator.processInput(input)
-Process any of the input formats to the appropriate CommonInputModel type.
+Process any of the input formats to the appropriate InputMetaModel type and split out the meta models
+based on the requirements of the generators
**Kind**: instance method of [AbstractGenerator
](#AbstractGenerator)
@@ -213,23 +251,18 @@ Process any of the input formats to the appropriate CommonInputModel type.
| --- |
| input |
+
+
+### abstractGenerator.getPresets()
+Get all presets (default and custom ones from options) for a given preset type (class, enum, etc).
+
+**Kind**: instance method of [AbstractGenerator
](#AbstractGenerator)
## AbstractRenderer
Abstract renderer with common helper methods
**Kind**: global class
-
-
-### abstractRenderer.addDependency(dependency)
-Adds a dependency while ensuring that only one dependency is preset at a time.
-
-**Kind**: instance method of [AbstractRenderer
](#AbstractRenderer)
-
-| Param | Description |
-| --- | --- |
-| dependency | complete dependency string so it can be rendered as is. |
-
## AsyncapiV2Schema
@@ -254,12 +287,6 @@ Takes a deep copy of the input object and converts it to an instance of Asyncapi
| --- |
| object |
-
-
-## CommonInputModel
-This class is the wrapper for simplified models and the rest of the context needed for further generate typed models.
-
-**Kind**: global class
## CommonModel
@@ -276,21 +303,21 @@ Common internal representation for a model.
* [.isRequired(propertyName)](#CommonModel+isRequired) ⇒ boolean
* [.addItem(itemModel, originalInput)](#CommonModel+addItem)
* [.addItemTuple(tupleModel, originalInput, index)](#CommonModel+addItemTuple)
+ * [.addItemUnion(unionModel)](#CommonModel+addItemUnion)
* [.addEnum(enumValue)](#CommonModel+addEnum)
* [.removeEnum(enumValue)](#CommonModel+removeEnum)
* [.addProperty(propertyName, propertyModel, originalInput)](#CommonModel+addProperty)
* [.addAdditionalProperty(additionalPropertiesModel, originalInput)](#CommonModel+addAdditionalProperty)
- * [.addAdditionalItems(additionalItemsModel, originalInput)](#CommonModel+addAdditionalItems)
* [.addPatternProperty(pattern, patternModel, originalInput)](#CommonModel+addPatternProperty)
+ * [.addAdditionalItems(additionalItemsModel, originalInput)](#CommonModel+addAdditionalItems)
* [.addExtendedModel(extendedModel)](#CommonModel+addExtendedModel)
- * [.getNearestDependencies()](#CommonModel+getNearestDependencies)
* _static_
* [.toCommonModel(object)](#CommonModel.toCommonModel) ⇒
* [.mergeProperties(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)](#CommonModel.mergeProperties)
* [.mergeAdditionalProperties(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)](#CommonModel.mergeAdditionalProperties)
* [.mergeAdditionalItems(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)](#CommonModel.mergeAdditionalItems)
- * [.mergePatternProperties(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)](#CommonModel.mergePatternProperties)
* [.mergeItems(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)](#CommonModel.mergeItems)
+ * [.mergePatternProperties(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)](#CommonModel.mergePatternProperties)
* [.mergeTypes(mergeTo, mergeFrom)](#CommonModel.mergeTypes)
* [.mergeCommonModels(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)](#CommonModel.mergeCommonModels)
@@ -380,6 +407,17 @@ If a item already exist it will be merged.
| originalInput | corresponding input that got interpreted to this model |
| index | |
+
+
+### commonModel.addItemUnion(unionModel)
+Adds a union model to the model.
+
+**Kind**: instance method of [CommonModel
](#CommonModel)
+
+| Param |
+| --- |
+| unionModel |
+
### commonModel.addEnum(enumValue)
@@ -431,31 +469,31 @@ If another model already exist the two are merged.
| additionalPropertiesModel | |
| originalInput | corresponding input that got interpreted to this model corresponding input that got interpreted to this model |
-
+
-### commonModel.addAdditionalItems(additionalItemsModel, originalInput)
-Adds additionalItems to the model.
-If another model already exist the two are merged.
+### commonModel.addPatternProperty(pattern, patternModel, originalInput)
+Adds a patternProperty to the model.
+If the pattern already exist the two models are merged.
**Kind**: instance method of [CommonModel
](#CommonModel)
| Param | Description |
| --- | --- |
-| additionalItemsModel | |
+| pattern | |
+| patternModel | |
| originalInput | corresponding input that got interpreted to this model |
-
+
-### commonModel.addPatternProperty(pattern, patternModel, originalInput)
-Adds a patternProperty to the model.
-If the pattern already exist the two models are merged.
+### commonModel.addAdditionalItems(additionalItemsModel, originalInput)
+Adds additionalItems to the model.
+If another model already exist the two are merged.
**Kind**: instance method of [CommonModel
](#CommonModel)
| Param | Description |
| --- | --- |
-| pattern | |
-| patternModel | |
+| additionalItemsModel | |
| originalInput | corresponding input that got interpreted to this model |
@@ -471,12 +509,6 @@ It is only allowed to extend if the other model have $id and is not already bein
| --- |
| extendedModel |
-
-
-### commonModel.getNearestDependencies()
-Returns an array of unique `$id`s from all the CommonModel's this model depends on.
-
-**Kind**: instance method of [CommonModel
](#CommonModel)
### CommonModel.toCommonModel(object) ⇒
@@ -531,10 +563,10 @@ Merge two common model additionalItems together
| originalInput | corresponding input that got interpreted to this model |
| alreadyIteratedModels | |
-
+
-### CommonModel.mergePatternProperties(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)
-Merge two common model pattern properties together
+### CommonModel.mergeItems(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)
+Merge items together, prefer tuples over simple array since it is more strict.
**Kind**: static method of [CommonModel
](#CommonModel)
@@ -545,10 +577,10 @@ Merge two common model pattern properties together
| originalInput | corresponding input that got interpreted to this model |
| alreadyIteratedModels | |
-
+
-### CommonModel.mergeItems(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)
-Merge items together, prefer tuples over simple array since it is more strict.
+### CommonModel.mergePatternProperties(mergeTo, mergeFrom, originalInput, alreadyIteratedModels)
+Merge two common model pattern properties together
**Kind**: static method of [CommonModel
](#CommonModel)
@@ -636,6 +668,12 @@ Takes a deep copy of the input object and converts it to an instance of Draft7Sc
| --- |
| object |
+
+
+## InputMetaModel
+Since each input processor can create multiple meta models this is a wrapper to a MetaModel to make that possible.
+
+**Kind**: global class
## OpenapiV3Schema
@@ -715,8 +753,8 @@ Class for processing AsyncAPI inputs
* [.shouldProcess(input)](#AsyncAPIInputProcessor+shouldProcess)
* [.tryGetVersionOfDocument(input)](#AsyncAPIInputProcessor+tryGetVersionOfDocument)
* _static_
- * [.convertToInternalSchema(schema)](#AsyncAPIInputProcessor.convertToInternalSchema)
* [.isFromParser(input)](#AsyncAPIInputProcessor.isFromParser)
+ * [.isFromNewParser(input)](#AsyncAPIInputProcessor.isFromNewParser)
@@ -751,23 +789,21 @@ Try to find the AsyncAPI version from the input. If it cannot undefined are retu
| --- |
| input |
-
-
-### AsyncAPIInputProcessor.convertToInternalSchema(schema)
-Reflect the name of the schema and save it to `x-modelgen-inferred-name` extension.
+
-This keeps the the id of the model deterministic if used in conjunction with other AsyncAPI tools such as the generator.
+### AsyncAPIInputProcessor.isFromParser(input)
+Figure out if input is from the AsyncAPI parser.
**Kind**: static method of [AsyncAPIInputProcessor
](#AsyncAPIInputProcessor)
-| Param | Description |
-| --- | --- |
-| schema | to reflect name for |
+| Param |
+| --- |
+| input |
-
+
-### AsyncAPIInputProcessor.isFromParser(input)
-Figure out if input is from the AsyncAPI js parser.
+### AsyncAPIInputProcessor.isFromNewParser(input)
+Figure out if input is from the new AsyncAPI parser.
**Kind**: static method of [AsyncAPIInputProcessor
](#AsyncAPIInputProcessor)
@@ -830,6 +866,7 @@ Class for processing JSON Schema
* [.processDraft7(input)](#JsonSchemaInputProcessor+processDraft7)
* [.processDraft4(input)](#JsonSchemaInputProcessor+processDraft4)
* [.processDraft6(input)](#JsonSchemaInputProcessor+processDraft6)
+ * [.handleRootReference()](#JsonSchemaInputProcessor+handleRootReference)
* _static_
* [.reflectSchemaNames(schema, namesStack, name, isRoot)](#JsonSchemaInputProcessor.reflectSchemaNames)
* [.ensureNamePattern(previousName, ...newParts)](#JsonSchemaInputProcessor.ensureNamePattern)
@@ -890,6 +927,14 @@ Process a draft-6 schema
| --- | --- |
| input | to process as draft-6 |
+
+
+### jsonSchemaInputProcessor.handleRootReference()
+This is a hotfix and really only a partial solution as it does not cover all cases.
+
+But it's the best we can do until we find or build a better library to handle references.
+
+**Kind**: instance method of [JsonSchemaInputProcessor
](#JsonSchemaInputProcessor)
### JsonSchemaInputProcessor.reflectSchemaNames(schema, namesStack, name, isRoot)
@@ -1051,6 +1096,12 @@ Converts a Swagger 2.0 Schema to the internal schema format.
| schema | to convert |
| name | of the schema |
+
+
+## TemplateInputProcessor
+Class for processing X input
+
+**Kind**: global class
## LoggerClass
@@ -1070,32 +1121,102 @@ Sets the logger to use for the model generation library
| --- | --- |
| logger | to add |
-
+
+
+## convertToUnionModel()
+Converts a CommonModel into multiple models wrapped in a union model.
+
+Because a CommonModel might contain multiple models, it's name for each of those models would be the same, instead we slightly change the model name.
+Each model has it's type as a name prepended to the union name.
+
+If the CommonModel has multiple types
+
+**Kind**: global function
+
+
+## isDictionary()
+Determine whether we have a dictionary or an object. because in some cases inputs might be:
+{ "type": "object", "additionalProperties": { "$ref": "#" } } which is to be interpreted as a dictionary not an object model.
+
+**Kind**: global function
+
+
+## getOriginalInputFromAdditionalAndPatterns()
+Return the original input based on additionalProperties and patternProperties.
+
+**Kind**: global function
+
+
+## convertAdditionalAndPatterns()
+Function creating the right meta model based on additionalProperties and patternProperties.
+
+**Kind**: global function
+
+
+## NO\_DUPLICATE\_PROPERTIES(constrainedObjectModel, objectModel, propertyName, namingFormatter)
+Because a lot of the other constrain functions (such as NO_NUMBER_START_CHAR, NO_EMPTY_VALUE, etc) they might manipulate the property names by append, prepend, or manipulate it any other way.
+We then need to make sure that they don't clash with any existing properties, this is what this function handles.
+If so, prepend `reserved_` to the property name and recheck.
+
+**Kind**: global function
+
+| Param | Description |
+| --- | --- |
+| constrainedObjectModel | the current constrained object model, which contains already existing constrained properties |
+| objectModel | the raw object model which is non-constrained to the output language. |
+| propertyName | one of the properties in objectModel which might have been manipulated |
+| namingFormatter | the name formatter which are used to format the property key |
-## DefaultPropertyNames
-Default property names for different aspects of the common model
+
-**Kind**: global variable
-
+## NO\_DUPLICATE\_ENUM\_KEYS(constrainedEnumModel, enumModel, enumKey, namingFormatter, enumKeyToCheck, onNameChange, onNameChangeToCheck) ⇒ string
+Because a lot of the other constrain functions (such as NO_NUMBER_START_CHAR, NO_EMPTY_VALUE, etc) they might manipulate the enum keys by append, prepend, or manipulate it any other way.
+We then need to make sure that they don't clash with any existing enum keys, this is what this function handles.
+If so, prepend `reserved_` to the enum key and recheck.
-## CommonNamingConventionImplementation
-A CommonNamingConvention implementation shared between generators for different languages.
+**Kind**: global function
+**Returns**: string
- the potential new enum key that does not clash with existing enum keys.
-**Kind**: global variable
-
+| Param | Description |
+| --- | --- |
+| constrainedEnumModel | the current constrained enum model, which contains already existing constrained enum keys |
+| enumModel | the raw enum model which is non-constrained to the output language. |
+| enumKey | one of the enum keys in enumModel which might have been manipulated. |
+| namingFormatter | the name formatter which are used to format the enum key. |
+| enumKeyToCheck | the enum key to use for checking if it already exist, defaults to enumKey. |
+| onNameChange | callback to change the name of the enum key that needs to be returned. |
+| onNameChangeToCheck | callback to change the enum key which is being checked as part of the existing models. |
-## getUniquePropertyName(rootModel, propertyName)
-Recursively find the proper property name.
+
-This function ensures that the property name is unique for the model
+## renderJavaScriptDependency(toImport, fromModule, moduleSystem)
+Function to make it easier to render JS/TS dependencies based on module system
**Kind**: global function
| Param |
| --- |
-| rootModel |
-| propertyName |
+| toImport |
+| fromModule |
+| moduleSystem |
+
+
+
+## makeUnique(array)
+Function to make an array of ConstrainedMetaModels only contain unique values (ignores different in memory instances)
+
+**Kind**: global function
+| Param | Description |
+| --- | --- |
+| array | to make unique |
+
+
+
+## lengthInUtf8Bytes()
+Convert a string into utf-8 encoding and return the byte size.
+
+**Kind**: global function
## hasPreset(presets, preset)
@@ -1109,6 +1230,34 @@ Check is done using referential equality
| presets | the list to check |
| preset | the preset to check for |
+
+
+## trySplitModel(model, options, models) ⇒
+Try split the model
+
+**Kind**: global function
+**Returns**: whether the new or old MetaModel to use.
+
+| Param |
+| --- |
+| model |
+| options |
+| models |
+
+
+
+## split(model, options, models) ⇒
+Overwrite the nested models with references where required.
+
+**Kind**: global function
+**Returns**: an array of all the split models
+
+| Param |
+| --- |
+| model |
+| options |
+| models |
+
## interpretAdditionalItems(schema, model, interpreter, interpreterOptions)
@@ -1153,6 +1302,22 @@ It either merges allOf schemas into existing model or if allowed, create inherit
| interpreter | |
| interpreterOptions | to control the interpret process |
+
+
+## interpretAnyOf(schema, model, interpreter, interpreterOptions)
+Interpreter function for anyOf keyword.
+
+It puts the schema reference into the items field.
+
+**Kind**: global function
+
+| Param | Description |
+| --- | --- |
+| schema | |
+| model | |
+| interpreter | |
+| interpreterOptions | to control the interpret process |
+
## interpretConst(schema, model)
@@ -1232,10 +1397,12 @@ Interpreter function for not keyword.
| interpreter | |
| interpreterOptions | to control the interpret process |
-
+
-## interpretPatternProperties(schema, model, interpreter, interpreterOptions)
-Interpreter function for patternProperties keyword.
+## interpretOneOf(schema, model, interpreter, interpreterOptions)
+Interpreter function for oneOf keyword.
+
+It puts the schema reference into the items field.
**Kind**: global function
@@ -1246,10 +1413,12 @@ Interpreter function for patternProperties keyword.
| interpreter | |
| interpreterOptions | to control the interpret process |
-
+
-## interpretProperties(schema, model, interpreter, interpreterOptions)
-Interpreter function for interpreting properties keyword.
+## interpretOneOfWithAllOf(schema, model, interpreter, interpreterOptions)
+Interpreter function for oneOf keyword combined with the allOf keyword.
+
+It merges the allOf schemas into all of the oneOf schemas. Shared properties are merged. The oneOf schemas are then added as union to the model.
**Kind**: global function
@@ -1260,41 +1429,49 @@ Interpreter function for interpreting properties keyword.
| interpreter | |
| interpreterOptions | to control the interpret process |
-
+
-## postInterpretModel(model)
-Post process the interpreted model. By applying the following:
-- Ensure models are split as required
+## interpretOneOfWithProperties(schema, model, interpreter, interpreterOptions)
+Interpreter function for oneOf keyword combined with properties.
+
+It merges the properties of the schema into the oneOf schemas. Shared properties are merged. The oneOf schemas are then added as union to the model.
**Kind**: global function
-| Param |
-| --- |
-| model |
+| Param | Description |
+| --- | --- |
+| schema | |
+| model | |
+| interpreter | |
+| interpreterOptions | to control the interpret process |
-
+
-## trySplitModels(model, iteratedModels)
-This function splits up a model if needed and add the new model to the list of models.
+## interpretPatternProperties(schema, model, interpreter, interpreterOptions)
+Interpreter function for patternProperties keyword.
**Kind**: global function
| Param | Description |
| --- | --- |
-| model | check if it should be split up |
-| iteratedModels | which have already been split up |
+| schema | |
+| model | |
+| interpreter | |
+| interpreterOptions | to control the interpret process |
-
+
-## ensureModelsAreSplit(model, iteratedModels)
-Split up all models which should and use ref instead.
+## interpretProperties(schema, model, interpreter, interpreterOptions)
+Interpreter function for interpreting properties keyword.
**Kind**: global function
| Param | Description |
| --- | --- |
-| model | to ensure are split |
-| iteratedModels | which are already split |
+| schema | |
+| model | |
+| interpreter | |
+| interpreterOptions | to control the interpret process |
@@ -1340,3 +1517,22 @@ Find the name for simplified version of schema
| --- | --- |
| schema | to find the name |
+
+
+## isClass(obj)
+Return true or false based on whether the input object is a regular object or a class
+
+Taken from: https://stackoverflow.com/a/43197340/6803886
+
+**Kind**: global function
+
+| Param |
+| --- |
+| obj |
+
+
+
+## mergePartialAndDefault()
+Merge a non optional value with custom optional values to form a full value that has all properties sat.
+
+**Kind**: global function
diff --git a/CODEOWNERS b/CODEOWNERS
index e0ce36c98f..ce4a305a3b 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -7,23 +7,23 @@
# The default owners are automatically added as reviewers when you open a pull request unless different owners are specified in the file.
# Core Champions that does a little of everything
-* @magicmatatjahu @jonaslagoni @asyncapi-bot-eve
+* @magicmatatjahu @jonaslagoni @asyncapi-bot-eve
# Documentation champions
/docs
# Input Champions for AsyncAPI input
-*/processors/AsyncAPIInputProcessor*.ts
+*/processors/AsyncAPIInputProcessor*.ts
# Input Champions for TypeScript input
*/processors/TypeScriptInputProcessor*.ts @ron-debajyoti
# Input Champions for OpenAPI input
-*/processors/OpenAPIInputProcessor*.ts
-*/processors/SwaggerInputProcessor*.ts
+*/processors/OpenAPIInputProcessor*.ts
+*/processors/SwaggerInputProcessor*.ts
# Input Champions for JSON Schema input
-*/processors/JsonSchemaInputProcessor*.ts
+*/processors/JsonSchemaInputProcessor*.ts
# Language Champions for TypeScript and it's presets
*/generators/typescript @Samridhi-98
@@ -41,4 +41,10 @@
*/generators/csharp @ron-debajyoti
# Language Champions for Dart and it's presets
-*/generators/dart
\ No newline at end of file
+*/generators/dart
+
+# Language Champions for Rust and its presets
+*/generators/rust @leigh-johnson
+
+# Language Champions for Kotlin and it's presets
+*/generators/kotlin @LouisXhaferi
diff --git a/Dockerfile b/Dockerfile
index d8c30d2aee..10e5b9a616 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,7 +6,7 @@ RUN apt-get update -yq \
# Install nodejs
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
- && apt-get install -yq nodejs
+ && apt-get install -yq nodejs
# Install golang
RUN curl -fsSL https://golang.org/dl/go1.16.8.linux-amd64.tar.gz | tar -C /usr/local -xz
@@ -17,9 +17,25 @@ RUN apt install apt-transport-https dirmngr gnupg ca-certificates -yq \
&& apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF \
&& echo "deb https://download.mono-project.com/repo/debian stable-buster main" | tee /etc/apt/sources.list.d/mono-official-stable.list \
&& apt update -yq \
- && apt install mono-devel -yq
+ && apt install mono-devel -yq
-# Setup library
-COPY package-lock.json .
+# Install rust
+RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
+
+# Install Python
+RUN apt-get install -yq python
+
+# Install Kotlin
+RUN apt install -yq wget unzip \
+ && cd /usr/lib \
+ && wget -q https://github.com/JetBrains/kotlin/releases/download/v1.8.0/kotlin-compiler-1.8.0.zip \
+ && unzip -qq kotlin-compiler-*.zip
+
+ENV PATH $PATH:/usr/lib/kotlinc/bin
+
+# Setup library
+RUN apt-get install -yq chromium
+
+COPY package.json package-lock.json ./
RUN npm install
-COPY . .
\ No newline at end of file
+COPY . ./
diff --git a/README.md b/README.md
index 0b7e594649..e67d73fda1 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,4 @@
-[![AsyncAPI Modelina](./assets/readme-banner.png)](https://www.asyncapi.com/tools/modelina)
-
-Modelina is the official AsyncAPI SDK to generate data models (i.e. Java/TypeScript classes, Go Structs, etc) from AsyncAPI documents, among other supported inputs.
+[![AsyncAPI Modelina](./docs/img/readme-banner.png)](https://www.asyncapi.com/tools/modelina)
[![blackbox pipeline status](Modelina put YOU in control of your data models, here is how...
+ + + +Modelina lets you generate data models from many types of inputs | ++ +```typescript +const asyncapi = ... +const jsonschema = ... +const openapi = ... +const metamodel = ... +... +const models = await generator.generate( + asyncapi | jsonschema | openapi | metamodel +); +``` + | +
Use the same inputs across a range of different generators | ++ +```typescript +const generator = new TypeScriptGenerator(); +const generator = new CsharpGenerator(); +const generator = new JavaGenerator(); +const generator = new RustGenerator(); +... +const models = await generator.generate(input); +``` + | +
Easily let you interact with the generated models. + +- Want to show the generated models on a website? Sure! +- Want to generate the models into files? Sure! +- Want to combine all the models into one single file? Sure! + +Whatever interaction you need, you can create. | ++ +```typescript +const models = await generator.generate(input); +for (const model in models) { + const generatedCode = generatedModel.result; + const dependencies = generatedModel.dependencies; + const modeltype = generatedModel.model.type; + const modelName = generatedModel.modelName; + ... +} +``` + | +
Easily modify how models are constrained into the output | + ++ +```typescript +const generator = new TypeScriptGenerator({ + constraints: { + modelName: ({modelName}) => { + // Implement your own constraining logic + return modelName; + } + } +}); +``` + | +
Seamlessly layer additional or replacement code on top of each other to customize the models to your use-case | + ++ +```typescript +const generator = new TypeScriptGenerator({ + presets: [ + { + class: { + additionalContent({ content }) { + return `${content} +public myCustomFunction(): string { + return 'A custom function for each class'; +}`; + }, + } + } + ] +}); +const models = await generator.generate(input); +``` + | +
Seamlessly lets you combine multiple layers of additional or replacement code | + ++ +```typescript +const myCustomFunction1 = { + class: { + additionalContent({ content }) { + return `${content} +public myCustomFunction(): string { +return 'A custom function for each class'; +}`; + }, + } +}; +const myCustomFunction2 = {...}; +const generator = new TypeScriptGenerator({ + presets: [ + myCustomFunction1, + myCustomFunction2 + ] +}); +const models = await generator.generate(input); +``` + | +
Supported inputs | -description | +||
---|---|---|---|
AsyncAPI | -We support the following AsyncAPI versions: 2.0.0, 2.1.0, 2.2.0, 2.3.0 and 2.4.0, which generates models for all the defined message payloads. | +We support the following AsyncAPI versions: 2.0.0 -> 2.5.0, which generates models for all the defined message payloads. | |
JSON Schema | @@ -82,8 +194,12 @@ To see the complete feature list for each language, please click the individualWe support the following OpenAPI versions: Swagger 2.0 and OpenAPI 3.0, which generates models for all the defined request and response payloads. | ||
TypeScript file | -We currently support TypeScript type file as input for model generation | +TypeScript | +We currently support TypeScript types as file input for model generation | +
Meta model | +This is the internal representation of a model for Modelina, it is what inputs gets converted to, and what generators are provided to generate code. Instead of relying on an input processor, you can create your own models from scratch and still take advantage on the generators and the features. |
Supported outputs | -Features | +|
---|---|---|
Java | @@ -119,29 +235,69 @@ To see the complete feature list for each language, please click the individualDart | Class and enum generation: json_annotation |
Rust | +Struct/tuple and enum generation: generation of `implement Default`, generate serde macros, custom indentation type and size, etc | +|
Python | +Class and enum generation: custom indentation type and size, etc | +|
Kotlin | +Class and enum generation: use of data classes where appropriate, custom indentation type and size, etc | +
+ +
+ +1. Process the input and transform it into the meta model. See [the meta model](./internal-model.md#the-meta-model) for more information. +2. Split the meta model into separate models that are rendered separately. See [The splitting of meta models](#The-splitting-of-meta-models) for more information. +3. Constrain the meta models to the output. See [The constrained meta model](./internal-model.md#the-constrained-meta-model) for more information. + +## The splitting of meta models +Each generator requires a different splitting of the **meta model**s because it varies which should be rendered as is, and which need to be rendered separately. + +For example with the current TS generator, we split the following models: +- **ObjectModel**, because we want to generate it into interfaces, or classes +- **EnumModel**, because we want to generate a representation for enums + +For the Java generator, we split the following models: +- **ObjectModel**, because we want to generate it into a Java Class +- **EnumModel**, because we want to generate it into a Java Enum. +- **TupleModel** (TS have these models natively supported, Java don't, so we need to generate alternatives) +- **UnionModel** (TS have these models natively supported, Java don't, so we need to generate alternatives) + diff --git a/docs/interpretation_of_JSON_Schema.md b/docs/inputs/JSON_Schema.md similarity index 61% rename from docs/interpretation_of_JSON_Schema.md rename to docs/inputs/JSON_Schema.md index 3e8943ddac..eb0e846c6f 100644 --- a/docs/interpretation_of_JSON_Schema.md +++ b/docs/inputs/JSON_Schema.md @@ -5,6 +5,129 @@ The library transforms JSON Schema from data validation rules to data definition The algorithm tries to get to a model whose data can be validated against the JSON schema document. As of now we only provide the underlying structure of the schema file for the model, where constraints/annotations such as `maxItems`, `uniqueItems`, `multipleOf`, etc. are not interpreted. +## Patterns +Beside the regular interpreter we also look for certain patterns that are interpreted slightly differently. + +### `oneOf` with `allOf` +If both oneOf and allOf is present, each allOf model is merged into the interpreted oneOf. + +For example take this example: +```json +{ + "allOf":[ + { + "title":"Animal", + "type":"object", + "properties":{ + "animalType":{ + "title":"Animal Type", + "type":"string" + }, + "age":{ + "type":"integer", + "min":0 + } + } + } + ], + "oneOf":[ + { + "title":"Cat", + "type":"object", + "properties":{ + "animalType":{ + "const":"Cat" + }, + "huntingSkill":{ + "title":"Hunting Skill", + "type":"string", + "enum":[ + "clueless", + "lazy" + ] + } + } + }, + { + "title":"Dog", + "type":"object", + "additionalProperties":false, + "properties":{ + "animalType":{ + "const":"Dog" + }, + "breed":{ + "title":"Dog Breed", + "type":"string", + "enum":[ + "bulldog", + "bichons frise" + ] + } + } + } + ] +} +``` +Here animal is merged into cat and dog. + +### `oneOf` with `properties` +If both oneOf and properties are both present, it's interpreted exactly like [oneOf with allOf](#oneof-with-allof). That means that the following: + +```json +{ + "title":"Animal", + "type":"object", + "properties":{ + "animalType":{ + "title":"Animal Type", + "type":"string" + }, + "age":{ + "type":"integer", + "min":0 + } + }, + "oneOf":[ + { + "title":"Cat", + "type":"object", + "properties":{ + "animalType":{ + "const":"Cat" + }, + "huntingSkill":{ + "title":"Hunting Skill", + "type":"string", + "enum":[ + "clueless", + "lazy" + ] + } + } + }, + { + "title":"Dog", + "type":"object", + "additionalProperties":false, + "properties":{ + "animalType":{ + "const":"Dog" + }, + "breed":{ + "title":"Dog Breed", + "type":"string", + "enum":[ + "bulldog", + "bichons frise" + ] + } + } + } + ] +} +``` +where all the defined behavior on the root object are merged into the two oneOf models cat and dog. ## Interpreter The main functionality is located in the `Interpreter` class. This class ensures to recursively create (or retrieve from a cache) a `CommonModel` representation of a Schema. We have tried to keep the functionality split out into separate functions to reduce complexity and ensure it is easy to maintain. @@ -13,7 +136,7 @@ The order of interpretation: - `true` boolean schema infers all model types (`object`, `string`, `number`, `array`, `boolean`, `null`, `integer`) schemas. - `type` infers the initial model type. - `required` are interpreted as is. -- `patternProperties` are interpreted as is, where duplicate patterns for the model are [merged](#Merging-models). +- `patternProperties` are merged together with any additionalProperties, where duplicate pattern models are [merged](#Merging-models). - `additionalProperties` are interpreted as is, where duplicate additionalProperties for the model are [merged](#Merging-models). If the schema does not define `additionalProperties` it defaults to `true` schema. - `additionalItems` are interpreted as is, where duplicate additionalItems for the model are [merged](#Merging-models). If the schema does not define `additionalItems` it defaults to `true` schema. - `items` are interpreted as ether tuples or simple array, where more than 1 item are [merged](#Merging-models). Usage of `items` infers `array` model type. @@ -22,7 +145,7 @@ The order of interpretation: - `dependencies` only apply to schema dependencies, since property dependencies adds nothing to the underlying model. Any schema dependencies are interpreted and then [merged](#Merging-models) together with the current interpreted model. - `enum` is interpreted as is, where each `enum`. Usage of `enum` infers the enumerator value type to the model, but only if the schema does not have `type` specified. - `const` interpretation overwrite already interpreted `enum`. Usage of `const` infers the constant value type to the model, but only if the schema does not have `type` specified. -- [oneOf/anyOf/then/else](#Processing-sub-schemas) +- [allOf/oneOf/anyOf/then/else](#Processing-sub-schemas) - [not](#interpreting-not-schemas) ## Interpreting not schemas @@ -36,13 +159,9 @@ Currently, the following `not` model properties are interpreted: - You cannot use nested `not` schemas to infer new model properties, it can only be used to re-allow them. - boolean `not` schemas are not applied. -## allOf sub schemas -`allOf` is a bit different than the other [combination keywords](#Processing-sub-schemas) since it can imply inheritance. - -So dependant on whether the interpreter option `allowInheritance` is true or false we interpret it as inheritance or [merge](#Merging-models) the models. - ## Processing sub schemas The following JSON Schema keywords are [merged](#Merging-models) with the already interpreted model: +- `allOf` - `oneOf` - `anyOf` - `then` @@ -53,7 +172,7 @@ Because of the recursive nature of the interpreter (and the nested nature of JSO If only one side has a property defined, it is used as is, if both have it defined they are merged based on the following logic (look [here](./input_processing.md#Internal-model-representation) for more information about the CommonModel and its properties): - `additionalProperties` if both models contain it the two are recursively merged together. -- `patternProperties` if both models contain a pattern the corresponding models are recursively merged together. +- `patternProperties` if both models contain it each pattern model are recursively merged together. - `properties` if both models contain the same property the corresponding models are recursively merged together. - `items` are merged together based on a couple of rules: - If both models are simple arrays those item models are merged together as is. diff --git a/docs/integration.md b/docs/integration.md index aaa72fb502..a26f66bd91 100644 --- a/docs/integration.md +++ b/docs/integration.md @@ -1,16 +1,30 @@ -## Integrations +# Integrations +This readme file goes into details how to integrate Modelina into various environments. -- [Integrate Modelina in a website](#integrate-modelina-in-a-website) +- [Integrate Modelina in a browser](#integrate-modelina-in-a-browser) + * [Security NOTICE](#security-notice) - [Integrate Modelina in an AsyncAPI generator template](#integrate-modelina-in-an-asyncapi-generator-template) -## Integrate Modelina in a website -TODO +## Integrate Modelina in a browser + +Integrating Modelina into websites is is one of the core features, and each framework is different, so here are some of examples: + +- [Using Modelina in React](../examples/integrate-with-react/) + +There are a few exceptions to the features Modelina support in a website environment. Those are listed here below: + +- You cannot use the [file generator](./advanced.md#generate-models-to-separate-files) to write to the client's disk. + +### Security NOTICE +Do NOT enable users to write their own option callbacks. This includes but not limits to preset hooks and constrain rules. The reason for this is that in some cases it will enable arbitrary code execution on your webserver (which you most probably don't want!). + +To be on the safeside, only enable the user to chose between the internal options and presets, as you can see the [playground does](https://www.asyncapi.com/tools/modelina). ## Integrate Modelina in an AsyncAPI generator template TODO diff --git a/docs/internal-model.md b/docs/internal-model.md new file mode 100644 index 0000000000..1b4d27f3c0 --- /dev/null +++ b/docs/internal-model.md @@ -0,0 +1,40 @@ +# Internal model + +In order to generate data models from all kinds of inputs, we need a common structure for how we interact with one. That structure is called `MetaModel` often referred to as `Modelina Meta Model`, `Raw Meta Model`, or `MMM`. And there are two parts to it, there is the **meta model** and then the **constrained meta model**. + +## The Meta Model +The **meta model** is what inputs (now and in the future) such as Protobuf, JSON Schema, JSON Type Definition, GraphQL types, are gonna be converted into. This is also an input in it'self that you can provide Modelina to create your own input processor. + +These are the meta models and their meaning: +- **ArrayModel** is an unordered collection of a specific **MetaModel**. +- **TupleModel** is an ordered collection of **MetaModel**s. +- **EnumModel** is group of constants. +- **UnionModel** represent that the model can be either/or other **MetaModel**s. +- **ObjectModel** is a structure, that can be generated to class/interface/struct, etc, depending on the output language +- **DictionaryModel** is a map/dictionary of key/value **MetaModel**s. +- **ReferencedModel** is primarily used for when models should be split up ([see the splitting of meta models](#the-splitting-of-data-models)) and referenced, or it could be an external reference to an external entity. +- **BooleanModel** represent boolean values. +- **IntegerModel** represent natural numbers. +- **FloatModel** represent floating-point numbers. +- **StringModel** represent string values. +- **AnyModel** represent generic values that cannot otherwise be represented by one of the other models. + ++ +
+ +## The Constrained Meta Model + +Before the **meta models**s reaches the generator, it needs to be `constrained` to the output. + +For example, constraining the **EnumModel** in Java means taking the raw enum key (for the **meta model** there are no constrains to what values may be used) such as `something% something` and convert it to a compliant Java enum key that can be accessed directly in the generator and presets. + +This means that if you accessed `EnumValueModel.key` you would get `something% something`, and with the Java constrained variant `ConstrainedEnumValueModel.key` you get (example) `SOMETHING_PERCENT_SOMETHING`. + +How and what are constrained? + +The answer to this question is not straightforward, cause each output has unique constraints that the meta models must adhere to. You can read more about [the constraint behavior here](constraints.md). + ++ +
diff --git a/docs/languages/Csharp.md b/docs/languages/Csharp.md index ef0c004226..1d8a757ae1 100644 --- a/docs/languages/Csharp.md +++ b/docs/languages/Csharp.md @@ -6,23 +6,56 @@ There are special use-cases that each language supports; this document pertains -- [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) -- [Generate models with equals and GetHashCode methods](#generate-models-with-equals-and-gethashcode-methods) -- [Generate models with auto-implemented properties](#generate-models-with-auto-implemented-properties) -- [Change the collection type for arrays](#change-the-collection-type-for-arrays) -- [Generate custom enum value names](#generate-custom-enum-value-names) -- [Generate models with inheritance](#generate-models-with-inheritance) + * [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) + + [To and from JSON](#to-and-from-json) + - [Using native System.Text.Json](#using-native-systemtextjson) + - [Using Newtonsoft/Json.NET](#using-newtonsoftjsonnet) + + [To and from XML](#to-and-from-xml) + + [To and from binary](#to-and-from-binary) + * [Generate models with equals and GetHashCode methods](#generate-models-with-equals-and-gethashcode-methods) + * [Generate models with auto-implemented properties](#generate-models-with-auto-implemented-properties) + * [Change the collection type for arrays](#change-the-collection-type-for-arrays) + * [Generate custom enum value names](#generate-custom-enum-value-names) + * [Generate models with inheritance](#generate-models-with-inheritance) +- [FAQ](#faq) + + [Why is the type `dynamic` or `dynamic[]` when it should be `X`?](#why-is-the-type-dynamic-or-dynamic-when-it-should-be-x) ## Generate serializer and deserializer functionality -Sometimes you want to serialize the data models into JSON. In order to do that use the preset `CSHARP_JSON_SERIALIZER_PRESET` +The most widely used usecase for Modelina is to generate models that include serilization and deserialization functionality to convert the models into payload data. This payload data can of course be many different kinds, JSON, XML, raw binary, you name it. -**External dependencies:** +As you normally only need one library to do this, we developers can never get enough with creating new stuff, therefore there might be one specific library you need or want to integrate with. Therefore there is not one specific preset that offers everything. Below is a list of all the supported serialization presets. + +### To and from JSON +Here are all the supported presets and the libraries they use: + +- [Using native System.Text.Json](#using-native-systemtextjson) + +#### Using native System.Text.Json + +To include functionality that convert the models using the [System.Text.Json](https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/), to use this, use the preset `CSHARP_JSON_SERIALIZER_PRESET`. + +Check out this [example for a live demonstration](../../examples/csharp-generate-json-serializer). + +**External dependencies** Requires [System.Text.Json](https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/), [System.Text.Json.Serialization](https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to?pivots=dotnet-6-0) and [System.Text.RegularExpressions](https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions?view=net-6.0) to work. -Check out this [example for a live demonstration](../../examples/csharp-generate-serializer). +#### Using Newtonsoft/Json.NET + +To include functionality that convert the models using the [Newtonsoft/Json.NET](https://www.newtonsoft.com/json) framework, to use this, use the preset `CSHARP_NEWTONSOFT_SERIALIZER_PRESET`. + +Check out this [example for a live demonstration](../../examples/csharp-generate-newtonsoft-serializer). + +**External dependencies** +Requires [`Newtonsoft.Json`, `Newtonsoft.Json.Linq`](https://www.newtonsoft.com/json) and [System.Collections.Generic](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic?view=net-7.0). + +### To and from XML +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! + +### To and from binary +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! ## Generate models with equals and GetHashCode methods @@ -53,4 +86,10 @@ Check out this [example for a live demonstration](../../examples/csharp-overwrit If you want the generated models to inherit from a custom class, you can overwrite the existing rendering behavior and create your own class setup. Check out this [example for a live demonstration](../../examples/csharp-use-inheritance). +# FAQ +This is the most asked questions and answers which should be your GOTO list to check before asking anywhere else. Cause it might already have been answered! + +### Why is the type `dynamic` or `dynamic[]` when it should be `X`? +Often times you might encounter variables which as of type `dynamic` or `dynamic[]`, which is our fallback type when we cannot accurately find the right type. +**If you are encountering this when your input is JSON Schema/OpenAPI/AsyncAPI**, it most likely is because of a property being defined as having multiple types as a union, which the C# generator cannot natively handle and fallback to `dynamic`. For arrays, you have to remember that `additionalItems` is by default `true`, this means that even though you use `items: { type: "string"}` by not setting `additionalItems: false`, it's the same as setting `items: { type: ["array", "boolean", "integer", "null", "number", "object", "string"]}`. \ No newline at end of file diff --git a/docs/languages/Dart.md b/docs/languages/Dart.md index 1d2f1ded6b..5c7e5406d3 100644 --- a/docs/languages/Dart.md +++ b/docs/languages/Dart.md @@ -5,12 +5,33 @@ There are special use-cases that each language supports; this document pertains -- [Include json_annotation for the class and enums](#include-json-annotation-for-the-class) +- [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) + * [To and from JSON](#to-and-from-json) + + [JSON annotation](#json-annotation) + * [To and from XML](#to-and-from-xml) + * [To and from binary](#to-and-from-binary) -## Include Json annotation for the class and enums +## Generate serializer and deserializer functionality -When you generate the models with json annotation, generated files include json_annotation package (https://pub.dev/packages/json_annotation/) and their syntax +The most widely used usecase for Modelina is to generate models that include serilization and deserialization functionality to convert the models into payload data. This payload data can of course be many different kinds, JSON, XML, raw binary, you name it. + +As you normally only need one library to do this, we developers can never get enough with creating new stuff, therefore there might be one specific library you need or want to integrate with. Therefore there is not one specific preset that offers everything. Below is a list of all the supported serialization presets. + +### To and from JSON +Here are all the supported presets and the libraries they use: + +- [JSON annotation](#json-annotation) + +#### JSON annotation + +When you generate the models with json annotation, generated files include json_annotation package (https://pub.dev/packages/json_annotation/) and their syntax. Check out this [example for a live demonstration](../../examples/dart-generate-json-annotation). + +### To and from XML +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! + +### To and from binary +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! diff --git a/docs/languages/Java.md b/docs/languages/Java.md index 3c262fb26d..f8745ec24d 100644 --- a/docs/languages/Java.md +++ b/docs/languages/Java.md @@ -12,8 +12,12 @@ There are special use-cases that each language supports; this document pertains - [Include toString function for the class](#include-tostring-function-for-the-class) - [Include JavaDoc for properties](#include-javadoc-for-properties) - [Include Javax validation constraint annotations for properties](#include-javax-validation-constraint-annotations-for-properties) -- [Include Jackson annotations for the class](#include-jackson-annotations-for-the-class) -- [Include JSON marshaling and unmarshaling methods](#include-json-marshaling-and-unmarshaling-methods) +- [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) + * [To and from JSON](#to-and-from-json) + + [Jackson annotation](#jackson-annotation) + + [JSON marshaling and unmarshaling methods](#json-marshaling-and-unmarshaling-methods) + * [To and from XML](#to-and-from-xml) + * [To and from binary](#to-and-from-binary) @@ -53,17 +57,38 @@ In some cases, when you generate the models from JSON Schema, you may want to in Check out this [example for a live demonstration](../../examples/java-generate-javax-constraint-annotation). -## Include Jackson annotations for the class +## Generate serializer and deserializer functionality + +The most widely used usecase for Modelina is to generate models that include serilization and deserialization functionality to convert the models into payload data. This payload data can of course be many different kinds, JSON, XML, raw binary, you name it. + +As you normally only need one library to do this, we developers can never get enough with creating new stuff, therefore there might be one specific library you need or want to integrate with. Therefore there is not one specific preset that offers everything. Below is a list of all the supported serialization presets. + +### To and from JSON +Here are all the supported presets and the libraries they use: + +- [Jackson annotation](#jackson-annotation) +- [JSON marshaling and unmarshaling methods](#json-marshaling-and-unmarshaling-methods) + +#### Jackson annotation To generate Java data models with Jackson annotation using `JAVA_JACKSON_PRESET` option. Check out this [example for a live demonstration](../../examples/java-generate-jackson-annotation). -## Include JSON marshaling and unmarshaling methods +**External dependencies** +Requires [com.fasterxml.jackson.annotation](https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations) to work. + +#### JSON marshaling and unmarshaling methods Sometimes you just want to convert your class to JSON without the use of annotations such as Jackson. Check out this [example for a live demonstration](../../examples/java-generate-marshalling). -External dependencies -- Requires [org.json package](https://search.maven.org/artifact/org.json/json/20211205/bundle) to work +**External dependencies** +Requires [org.json package](https://search.maven.org/artifact/org.json/json/20211205/bundle) to work. + +### To and from XML +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! + +### To and from binary +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! diff --git a/docs/languages/JavaScript.md b/docs/languages/JavaScript.md index 770ec6137f..5b918724dd 100644 --- a/docs/languages/JavaScript.md +++ b/docs/languages/JavaScript.md @@ -6,7 +6,11 @@ There are special use-cases that each language supports; this document pertains - [Rendering complete models to a specific module system](#rendering-complete-models-to-a-specific-module-system) -- [Generate un/marshal functions for classes](#generate-unmarshal-functions-for-classes) +- [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) + * [To and from JSON](#to-and-from-json) + + [Generate marshalling and unmarshalling functions](#generate-marshalling-and-unmarshalling-functions) + * [To and from XML](#to-and-from-xml) + * [To and from binary](#to-and-from-binary) - [Generate example data function](#generate-example-data-function) @@ -18,15 +22,30 @@ Check out this [example for a live demonstration how to generate the complete Ja Check out this [example for a live demonstration how to generate the complete JavaScript models to use CJS module system](../../examples/javascript-use-cjs). +## Generate serializer and deserializer functionality -## Generate un/marshal functions for classes +The most widely used usecase for Modelina is to generate models that include serilization and deserialization functionality to convert the models into payload data. This payload data can of course be many different kinds, JSON, XML, raw binary, you name it. -Sometimes you want to use the models for data transfers, and while most cases would work out of the box, custom serializer functionality is needed for the advanced cases. If you generated the data models based on a JSON Schema document and you want the serialized data to validate against the schema, this functionality is REQUIRED. +As you normally only need one library to do this, we developers can never get enough with creating new stuff, therefore there might be one specific library you need or want to integrate with. Therefore there is not one specific preset that offers everything. Below is a list of all the supported serialization presets. + +### To and from JSON +Here are all the supported presets and the libraries they use: + +- [Generate marshalling and unmarshalling functions](#generate-marshalling-and-unmarshalling-functions) + +#### Generate marshalling and unmarshalling functions + +Using the preset `JS_COMMON_PRESET` with the option `marshalling` to `true`, renders two function for the class models. One which convert the model to JSON and another which convert the model from JSON to an instance of the class. -Here, this can be done by including the preset `JS_COMMON_PRESET` using the option `marshalling`. Check out this [example out for a live demonstration](../../examples/javascript-generate-marshalling). +### To and from XML +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! + +### To and from binary +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! + ## Generate example data function Generate example instance of the data model including the preset `JS_COMMON_PRESET` using the option `example`. diff --git a/docs/languages/Kotlin.md b/docs/languages/Kotlin.md new file mode 100644 index 0000000000..57fcbc66b0 --- /dev/null +++ b/docs/languages/Kotlin.md @@ -0,0 +1,52 @@ +# Kotlin + +There are special use-cases that each language supports; this document pertains to **Kotlin models**. + +Since `data classes` are used for every model that has got properties, there is no need for additional settings or +features to generate `toString()`, `equals()`, `hashCode()`, getters or setters. + +Classes without properties are depicted by usual `classes`, they get no `toString()`, `equals()` or `hashCode()` +implementation. The default one should suffice here. + + + + + +- [Include KDoc for properties](#include-kdoc-for-properties) +- [Change the collection type for arrays](#change-the-collection-type-for-arrays) +- [Include Javax validation constraint annotations for properties](#include-javax-validation-constraint-annotations-for-properties) +- [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) + * [To and from JSON](#to-and-from-json) + * [To and from XML](#to-and-from-xml) + * [To and from binary](#to-and-from-binary) + + +## Include KDoc for properties +To generate models containing `KDoc` from description and examples, use the `KOTLIN_DESCRIPTION_PRESET` option. + +Check out this [example for a live demonstration](../../examples/kotlin-generate-kdoc). + +## Change the collection type for arrays + +Sometimes, we might want to render a different collection type, and instead of the default `Array` use as `List` type. To do so, provide the option `collectionType: 'List'`. + +Check out this [example for a live demonstration](../../examples/kotlin-change-collection-type). + +## Include Javax validation constraint annotations for properties + +In some cases, when you generate the models from JSON Schema, you may want to include `javax.validation.constraint` annotations. + +Check out this [example for a live demonstration](../../examples/kotlin-generate-javax-constraint-annotation). + +## Generate serializer and deserializer functionality + +The most widely used usecase for Modelina is to generate models that include serialization and deserialization functionality to convert the models into payload data. This payload data can of course be many kinds, JSON, XML, raw binary, you name it. + +As you normally only need one library to do this, we developers can never get enough with creating new stuff, therefore there might be one specific library you need or want to integrate with. Therefore, there is not one specific preset that offers everything. Below is a list of all the supported serialization presets. + +### To and from JSON +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! +### To and from XML +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! +### To and from binary +Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! diff --git a/docs/languages/Python.md b/docs/languages/Python.md new file mode 100644 index 0000000000..91a9173d4c --- /dev/null +++ b/docs/languages/Python.md @@ -0,0 +1,16 @@ +# Python + +There are special use-cases that each language supports; this document pertains to **Python models**. + + + + + +- [Generate Pydantic models](#generate-pydantic-models) + + + +## Generate Pydantic models +In some cases you might want to use [pydantic](https://pypi.org/project/pydantic/) data validation and settings management using Python type hints for the models. + +You can find an example of its use [here](../../examples/generate-python-pydantic-models/index.ts) diff --git a/docs/languages/Rust.md b/docs/languages/Rust.md new file mode 100644 index 0000000000..79cd94aae9 --- /dev/null +++ b/docs/languages/Rust.md @@ -0,0 +1,57 @@ +# Rust + + + + + +- [Language Features](#language-features) +- [Generator Features](#generator-features) +- [Implement `new`](#implement-new) +- [Implement `default`](#implement-default) +- [Implement `From{ +import { DeepPartial, isPresetWithOptions } from '../utils'; +import { AbstractDependencyManager } from './AbstractDependencyManager'; + +export interface CommonGeneratorOptions< + P extends Preset = Preset, + DependencyManager extends AbstractDependencyManager = AbstractDependencyManager +> { indentation?: { type: IndentationTypes; size: number; }; defaultPreset?: P; presets?: Presets
;
- processorOptions?: ProcessorOptions
+ processorOptions?: ProcessorOptions;
+ /**
+ * This dependency manager type serves two functions.
+ * 1. It can be used to provide a factory for generate functions
+ * 2. It can be used to provide a single instance of a dependency manager, to add all dependencies together
+ *
+ * This depends on context and where it's used.
+ */
+ dependencyManager?: (() => DependencyManager) | DependencyManager;
}
export const defaultGeneratorOptions: CommonGeneratorOptions = {
indentation: {
type: IndentationTypes.SPACES,
- size: 2,
+ size: 2
}
};
/**
* Abstract generator which must be implemented by each language
*/
-export abstract class AbstractGenerator