From b9263fc9748d28742142e4c49840298bda36160b Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Thu, 17 Feb 2022 12:00:10 +0100 Subject: [PATCH 1/4] feat: None as default value --- .../model/InferableAnnotation.ts | 66 ++++++----- .../features/annotations/AnnotationView.tsx | 28 ++--- .../features/annotations/annotationSlice.ts | 4 +- .../annotations/forms/TypeValueForm.tsx | 106 +++++++++--------- .../api_editor/codegen/PythonCodeGenerator.kt | 2 + .../api_editor/model/editorAnnotations.kt | 7 ++ .../api_editor/mutable_model/PythonAst.kt | 1 + .../ParameterAnnotationProcessor.kt | 3 + .../PythonCodeGeneratorTest.kt | 7 ++ 9 files changed, 134 insertions(+), 90 deletions(-) diff --git a/api-editor/client/src/features/annotatedPackageData/model/InferableAnnotation.ts b/api-editor/client/src/features/annotatedPackageData/model/InferableAnnotation.ts index f4748d84e..da8a83850 100644 --- a/api-editor/client/src/features/annotatedPackageData/model/InferableAnnotation.ts +++ b/api-editor/client/src/features/annotatedPackageData/model/InferableAnnotation.ts @@ -16,14 +16,27 @@ import { const dataPathPrefix = 'com.larsreimann.api_editor.model.'; -const getDefaultValueTypeSuffix = (type: DefaultType) => { +const convertDefaultValue = (type: DefaultType, value: DefaultValue) => { switch (type) { case 'string': - return 'DefaultString'; + return { + type: `${dataPathPrefix}DefaultString`, + value, + }; case 'boolean': - return 'DefaultBoolean'; + return { + type: `${dataPathPrefix}DefaultBoolean`, + value, + }; case 'number': - return 'DefaultNumber'; + return { + type: `${dataPathPrefix}DefaultNumber`, + value, + }; + case 'none': + return { + type: `${dataPathPrefix}DefaultNone` + }; } }; @@ -36,16 +49,14 @@ export class InferableAnnotation { } export class InferableAttributeAnnotation extends InferableAnnotation { - readonly defaultValue: { type: string; value: DefaultValue }; + readonly defaultValue: { type: string; value?: DefaultValue }; constructor(attributeAnnotation: AttributeAnnotation) { super(dataPathPrefix + 'AttributeAnnotation'); - this.defaultValue = { - type: - dataPathPrefix + - getDefaultValueTypeSuffix(attributeAnnotation.defaultType), - value: attributeAnnotation.defaultValue, - }; + this.defaultValue = convertDefaultValue( + attributeAnnotation.defaultType, + attributeAnnotation.defaultValue + ); } } @@ -78,19 +89,19 @@ export class InferableCalledAfterAnnotation extends InferableAnnotation { this.calledAfterName = calledAfterAnnotation.calledAfterName; } } + export class InferableConstantAnnotation extends InferableAnnotation { - readonly defaultValue: { type: string; value: DefaultValue }; + readonly defaultValue: { type: string; value?: DefaultValue }; constructor(constantAnnotation: ConstantAnnotation) { super(dataPathPrefix + 'ConstantAnnotation'); - this.defaultValue = { - type: - dataPathPrefix + - getDefaultValueTypeSuffix(constantAnnotation.defaultType), - value: constantAnnotation.defaultValue, - }; + this.defaultValue = convertDefaultValue( + constantAnnotation.defaultType, + constantAnnotation.defaultValue + ); } } + export class InferableGroupAnnotation extends InferableAnnotation { readonly groupName: string; readonly parameters: string[]; @@ -101,6 +112,7 @@ export class InferableGroupAnnotation extends InferableAnnotation { this.parameters = groupAnnotation.parameters; } } + export class InferableEnumAnnotation extends InferableAnnotation { readonly enumName: string; readonly pairs: EnumPair[]; @@ -111,6 +123,7 @@ export class InferableEnumAnnotation extends InferableAnnotation { this.pairs = enumAnnotation.pairs; } } + export class InferableMoveAnnotation extends InferableAnnotation { readonly destination: string; @@ -119,24 +132,25 @@ export class InferableMoveAnnotation extends InferableAnnotation { this.destination = moveAnnotation.destination; } } + export class InferableOptionalAnnotation extends InferableAnnotation { - readonly defaultValue: { type: string; value: DefaultValue }; + readonly defaultValue: { type: string; value?: DefaultValue }; constructor(optionalAnnotation: OptionalAnnotation) { super(dataPathPrefix + 'OptionalAnnotation'); - this.defaultValue = { - type: - dataPathPrefix + - getDefaultValueTypeSuffix(optionalAnnotation.defaultType), - value: optionalAnnotation.defaultValue, - }; + this.defaultValue = convertDefaultValue( + optionalAnnotation.defaultType, + optionalAnnotation.defaultValue + ); } } + export class InferablePureAnnotation extends InferableAnnotation { constructor() { super(dataPathPrefix + 'PureAnnotation'); } } + export class InferableRenameAnnotation extends InferableAnnotation { readonly newName: string; @@ -145,11 +159,13 @@ export class InferableRenameAnnotation extends InferableAnnotation { this.newName = renameAnnotation.newName; } } + export class InferableRequiredAnnotation extends InferableAnnotation { constructor() { super(dataPathPrefix + 'RequiredAnnotation'); } } + export class InferableUnusedAnnotation extends InferableAnnotation { constructor() { super(dataPathPrefix + 'UnusedAnnotation'); diff --git a/api-editor/client/src/features/annotations/AnnotationView.tsx b/api-editor/client/src/features/annotations/AnnotationView.tsx index 00982f308..b33df9f4b 100644 --- a/api-editor/client/src/features/annotations/AnnotationView.tsx +++ b/api-editor/client/src/features/annotations/AnnotationView.tsx @@ -6,8 +6,8 @@ import { Text as ChakraText, } from '@chakra-ui/react'; import React from 'react'; -import { FaTrash, FaWrench } from 'react-icons/fa'; -import { useAppDispatch, useAppSelector } from '../../app/hooks'; +import {FaTrash, FaWrench} from 'react-icons/fa'; +import {useAppDispatch, useAppSelector} from '../../app/hooks'; import { BoundaryAnnotation, ComparisonOperator, @@ -51,7 +51,7 @@ interface AnnotationViewProps { target: string; } -const AnnotationView: React.FC = function ({ target }) { +const AnnotationView: React.FC = function ({target}) { const dispatch = useAppDispatch(); const attributeAnnotation = useAppSelector(selectAttribute(target)); @@ -112,7 +112,7 @@ const AnnotationView: React.FC = function ({ target }) { name={calledAfterName} key={calledAfterName} onDelete={() => - dispatch(removeCalledAfter({ target, calledAfterName })) + dispatch(removeCalledAfter({target, calledAfterName})) } /> ))} @@ -141,10 +141,10 @@ const AnnotationView: React.FC = function ({ target }) { type="group" name={groupName} onEdit={() => - dispatch(showGroupAnnotationForm({ target, groupName })) + dispatch(showGroupAnnotationForm({target, groupName})) } onDelete={() => - dispatch(removeGroup({ target, groupName })) + dispatch(removeGroup({target, groupName})) } /> ))} @@ -205,6 +205,8 @@ const valueToString = (value: DefaultValue, type: DefaultType): string => { return String(value); case 'boolean': return value === true ? 'True' : 'False'; + case 'none': + return "None"; } }; @@ -241,15 +243,15 @@ interface AnnotationProps { } const Annotation: React.FC = function ({ - name, - onDelete, - onEdit, - type, -}) { + name, + onDelete, + onEdit, + type, + }) { return ( } + icon={} aria-label="Delete annotation" colorScheme="red" onClick={onDelete} diff --git a/api-editor/client/src/features/annotations/annotationSlice.ts b/api-editor/client/src/features/annotations/annotationSlice.ts index 992dfb531..f8d09e1b7 100644 --- a/api-editor/client/src/features/annotations/annotationSlice.ts +++ b/api-editor/client/src/features/annotations/annotationSlice.ts @@ -60,8 +60,8 @@ export interface AttributeAnnotation { readonly defaultValue: DefaultValue; } -export type DefaultType = 'string' | 'number' | 'boolean'; -export type DefaultValue = string | number | boolean; +export type DefaultType = 'string' | 'number' | 'boolean' | 'none'; +export type DefaultValue = string | number | boolean | null; export interface BoundaryAnnotation { /** diff --git a/api-editor/client/src/features/annotations/forms/TypeValueForm.tsx b/api-editor/client/src/features/annotations/forms/TypeValueForm.tsx index 8694f5bf0..42a6a42f9 100644 --- a/api-editor/client/src/features/annotations/forms/TypeValueForm.tsx +++ b/api-editor/client/src/features/annotations/forms/TypeValueForm.tsx @@ -14,11 +14,11 @@ import { Select, Stack, } from '@chakra-ui/react'; -import React, { useEffect } from 'react'; -import { useForm } from 'react-hook-form'; -import { useAppDispatch } from '../../../app/hooks'; -import { Optional } from '../../../common/util/types'; -import { booleanPattern, numberPattern } from '../../../common/validation'; +import React, {useEffect} from 'react'; +import {useForm} from 'react-hook-form'; +import {useAppDispatch} from '../../../app/hooks'; +import {Optional} from '../../../common/util/types'; +import {booleanPattern, numberPattern} from '../../../common/validation'; import PythonDeclaration from '../../packageData/model/PythonDeclaration'; import { DefaultType, @@ -41,12 +41,12 @@ export interface TypeValueFormState { } const TypeValueForm: React.FC = function ({ - target, - annotationType, - previousDefaultType, - previousDefaultValue, - onUpsertAnnotation, -}) { + target, + annotationType, + previousDefaultType, + previousDefaultValue, + onUpsertAnnotation, + }) { const dispatch = useAppDispatch(); const { @@ -55,7 +55,7 @@ const TypeValueForm: React.FC = function ({ reset, setValue, watch, - formState: { errors }, + formState: {errors}, } = useForm({ defaultValues: { defaultType: 'string', @@ -83,9 +83,11 @@ const TypeValueForm: React.FC = function ({ }; const handleSave = (data: TypeValueFormState) => { - let toUpsert = { ...data }; + let toUpsert = {...data}; if (data.defaultType === 'boolean') { - toUpsert = { ...data, defaultValue: data.defaultValue === 'true' }; + toUpsert = {...data, defaultValue: data.defaultValue === 'true'}; + } else if (data.defaultType === "none") { + toUpsert = {...data, defaultValue: null} } onUpsertAnnotation(toUpsert); dispatch(hideAnnotationForms()); @@ -116,49 +118,53 @@ const TypeValueForm: React.FC = function ({ String Number Boolean + None - - - Default value for "{target.name}": - - {watchDefaultType === 'string' && ( - - )} - {watchDefaultType === 'number' && ( - - + + Default value for "{target.name}": + + {watchDefaultType === 'string' && ( + - - - - - - )} - {watchDefaultType === 'boolean' && ( - - )} - - {errors.defaultValue?.message} - - + )} + {watchDefaultType === 'number' && ( + + + + + + + + )} + {watchDefaultType === 'boolean' && ( + + )} + + {errors.defaultValue?.message} + + + )} + ); }; diff --git a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGenerator.kt b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGenerator.kt index f76a31f36..489447af2 100644 --- a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGenerator.kt +++ b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGenerator.kt @@ -24,6 +24,7 @@ import com.larsreimann.api_editor.mutable_model.PythonInt import com.larsreimann.api_editor.mutable_model.PythonMemberAccess import com.larsreimann.api_editor.mutable_model.PythonModule import com.larsreimann.api_editor.mutable_model.PythonNamedType +import com.larsreimann.api_editor.mutable_model.PythonNone import com.larsreimann.api_editor.mutable_model.PythonParameter import com.larsreimann.api_editor.mutable_model.PythonReference import com.larsreimann.api_editor.mutable_model.PythonString @@ -269,6 +270,7 @@ internal fun PythonExpression.toPythonCode(): String { is PythonFloat -> value.toString() is PythonInt -> value.toString() is PythonMemberAccess -> "${receiver!!.toPythonCode()}.${member!!.toPythonCode()}" + is PythonNone -> "None" is PythonReference -> declaration!!.name is PythonString -> "'$value'" is PythonStringifiedExpression -> string diff --git a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/model/editorAnnotations.kt b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/model/editorAnnotations.kt index 9aa59f7af..cebc64998 100644 --- a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/model/editorAnnotations.kt +++ b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/model/editorAnnotations.kt @@ -147,6 +147,13 @@ class DefaultString(val value: String) : DefaultValue() { } } +@Serializable +object DefaultNone : DefaultValue() { + override fun toString(): String { + return "None" + } +} + enum class AnnotationTarget(private val target: String) { CLASS("class"), GLOBAL_FUNCTION("global function"), diff --git a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/mutable_model/PythonAst.kt b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/mutable_model/PythonAst.kt index 2930625b0..e1f16afb8 100644 --- a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/mutable_model/PythonAst.kt +++ b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/mutable_model/PythonAst.kt @@ -245,6 +245,7 @@ data class PythonBoolean(val value: Boolean) : PythonLiteral() data class PythonFloat(val value: Double) : PythonLiteral() data class PythonInt(val value: Int) : PythonLiteral() data class PythonString(val value: String) : PythonLiteral() +object PythonNone : PythonLiteral() class PythonMemberAccess( receiver: PythonExpression, diff --git a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/transformation/ParameterAnnotationProcessor.kt b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/transformation/ParameterAnnotationProcessor.kt index d09f3f8ab..f7a6d2b72 100644 --- a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/transformation/ParameterAnnotationProcessor.kt +++ b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/transformation/ParameterAnnotationProcessor.kt @@ -3,6 +3,7 @@ package com.larsreimann.api_editor.transformation import com.larsreimann.api_editor.model.AttributeAnnotation import com.larsreimann.api_editor.model.ConstantAnnotation import com.larsreimann.api_editor.model.DefaultBoolean +import com.larsreimann.api_editor.model.DefaultNone import com.larsreimann.api_editor.model.DefaultNumber import com.larsreimann.api_editor.model.DefaultString import com.larsreimann.api_editor.model.DefaultValue @@ -16,6 +17,7 @@ import com.larsreimann.api_editor.mutable_model.PythonClass import com.larsreimann.api_editor.mutable_model.PythonFloat import com.larsreimann.api_editor.mutable_model.PythonInt import com.larsreimann.api_editor.mutable_model.PythonLiteral +import com.larsreimann.api_editor.mutable_model.PythonNone import com.larsreimann.api_editor.mutable_model.PythonPackage import com.larsreimann.api_editor.mutable_model.PythonParameter import com.larsreimann.api_editor.mutable_model.PythonReference @@ -118,5 +120,6 @@ private fun DefaultValue.toPythonLiteral(): PythonLiteral { } } is DefaultString -> PythonString(this.value) + is DefaultNone -> PythonNone } } diff --git a/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/PythonCodeGeneratorTest.kt b/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/PythonCodeGeneratorTest.kt index 52d2d9211..d2a6ce4ab 100644 --- a/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/PythonCodeGeneratorTest.kt +++ b/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/PythonCodeGeneratorTest.kt @@ -21,6 +21,7 @@ import com.larsreimann.api_editor.mutable_model.PythonInt import com.larsreimann.api_editor.mutable_model.PythonMemberAccess import com.larsreimann.api_editor.mutable_model.PythonModule import com.larsreimann.api_editor.mutable_model.PythonNamedType +import com.larsreimann.api_editor.mutable_model.PythonNone import com.larsreimann.api_editor.mutable_model.PythonParameter import com.larsreimann.api_editor.mutable_model.PythonReference import com.larsreimann.api_editor.mutable_model.PythonString @@ -1051,6 +1052,12 @@ class PythonCodeGeneratorTest { expression.toPythonCode() shouldBe "param.value" } + @Test + fun `should handle None`() { + val expression = PythonNone + expression.toPythonCode() shouldBe "None" + } + @Test fun `should handle references`() { val expression = PythonReference(PythonParameter("param")) From b9e15dbaf6450b3a55c151a76141de070297b273 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Thu, 17 Feb 2022 12:15:18 +0100 Subject: [PATCH 2/4] fix: errors shown in IDE only --- .../api_editor/codegen/PythonCodeGenerator.kt | 24 +++++++++---------- .../api_editor/codegen/StubCodeGenerator.kt | 24 +++++++++---------- .../PythonCodeGeneratorTest.kt | 4 +--- 3 files changed, 25 insertions(+), 27 deletions(-) rename api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/{python_code_gen => }/PythonCodeGeneratorTest.kt (99%) diff --git a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGenerator.kt b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGenerator.kt index 489447af2..06f4f913f 100644 --- a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGenerator.kt +++ b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGenerator.kt @@ -102,7 +102,7 @@ private fun String.parentQualifiedName(): String { return substring(0, separationPosition) } -internal fun PythonAttribute.toPythonCode() = buildString { +fun PythonAttribute.toPythonCode() = buildString { append("self.$name") type?.toPythonCodeOrNull()?.let { append(": $it") @@ -112,7 +112,7 @@ internal fun PythonAttribute.toPythonCode() = buildString { } } -internal fun PythonClass.toPythonCode() = buildString { +fun PythonClass.toPythonCode() = buildString { val constructorString = constructor?.toPythonCode() ?: "" val methodsString = methods.joinToString("\n\n") { it.toPythonCode() } @@ -131,7 +131,7 @@ internal fun PythonClass.toPythonCode() = buildString { } } -internal fun PythonConstructor.toPythonCode() = buildString { +fun PythonConstructor.toPythonCode() = buildString { val parametersString = parameters.toPythonCode() val boundariesString = parameters .mapNotNull { it.boundary?.toPythonCode(it.name) } @@ -165,7 +165,7 @@ internal fun PythonConstructor.toPythonCode() = buildString { } } -internal fun PythonEnum.toPythonCode() = buildString { +fun PythonEnum.toPythonCode() = buildString { appendLine("class $name(Enum):") appendIndented { if (instances.isEmpty()) { @@ -181,11 +181,11 @@ internal fun PythonEnum.toPythonCode() = buildString { } } -internal fun PythonEnumInstance.toPythonCode(): String { +fun PythonEnumInstance.toPythonCode(): String { return "$name = ${value!!.toPythonCode()}" } -internal fun PythonFunction.toPythonCode() = buildString { +fun PythonFunction.toPythonCode() = buildString { val parametersString = parameters.toPythonCode() val boundariesString = parameters .mapNotNull { it.boundary?.toPythonCode(it.name) } @@ -212,7 +212,7 @@ internal fun PythonFunction.toPythonCode() = buildString { } } -internal fun List.toPythonCode(): String { +fun List.toPythonCode(): String { val assignedByToParameter = this@toPythonCode.groupBy { it.assignedBy } val implicitParametersString = assignedByToParameter[IMPLICIT] ?.joinToString { it.toPythonCode() } @@ -247,7 +247,7 @@ internal fun List.toPythonCode(): String { .joinToString() } -internal fun PythonParameter.toPythonCode() = buildString { +fun PythonParameter.toPythonCode() = buildString { val typeStringOrNull = type.toPythonCodeOrNull() append(name) @@ -263,7 +263,7 @@ internal fun PythonParameter.toPythonCode() = buildString { * Expressions * ********************************************************************************************************************/ -internal fun PythonExpression.toPythonCode(): String { +fun PythonExpression.toPythonCode(): String { return when (this) { is PythonBoolean -> value.toString().replaceFirstChar { it.uppercase() } is PythonCall -> "${receiver!!.toPythonCode()}(${arguments.joinToString { it.toPythonCode() }})" @@ -281,7 +281,7 @@ internal fun PythonExpression.toPythonCode(): String { * Types * ********************************************************************************************************************/ -internal fun PythonType?.toPythonCodeOrNull(): String? { +fun PythonType?.toPythonCodeOrNull(): String? { return when (this) { is PythonNamedType -> this.declaration?.name is PythonStringifiedType -> { @@ -301,14 +301,14 @@ internal fun PythonType?.toPythonCodeOrNull(): String? { * Other * ********************************************************************************************************************/ -internal fun PythonArgument.toPythonCode() = buildString { +fun PythonArgument.toPythonCode() = buildString { if (name != null) { append("$name=") } append(value!!.toPythonCode()) } -internal fun Boundary.toPythonCode(parameterName: String) = buildString { +fun Boundary.toPythonCode(parameterName: String) = buildString { if (isDiscrete) { appendLine("if not (isinstance($parameterName, int) or (isinstance($parameterName, float) and $parameterName.is_integer())):") appendIndented("raise ValueError(f'$parameterName needs to be an integer, but {$parameterName} was assigned.')") diff --git a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/StubCodeGenerator.kt b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/StubCodeGenerator.kt index 2dcd2f247..62aaa169d 100644 --- a/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/StubCodeGenerator.kt +++ b/api-editor/server/src/main/kotlin/com/larsreimann/api_editor/codegen/StubCodeGenerator.kt @@ -69,7 +69,7 @@ fun PythonModule.toStubCode(): String { /** * Creates a Simple-ML compilation unit that corresponds to the Python module. */ -internal fun PythonModule.toSmlCompilationUnit(): SmlCompilationUnit { +fun PythonModule.toSmlCompilationUnit(): SmlCompilationUnit { val classes = classes.map { it.toSmlClass() } val functions = functions.map { it.toSmlFunction() } val enums = enums.map { it.toSmlEnum() } @@ -85,7 +85,7 @@ internal fun PythonModule.toSmlCompilationUnit(): SmlCompilationUnit { /** * Creates a Simple-ML class that corresponds to the Python class. */ -internal fun PythonClass.toSmlClass(): SmlClass { +fun PythonClass.toSmlClass(): SmlClass { val stubName = name.snakeCaseToUpperCamelCase() val attributes = attributes.map { it.toSmlAttribute() } @@ -116,7 +116,7 @@ private fun PythonClass.buildConstructor(): List { /** * Creates a Simple-ML attribute that corresponds to the Python attribute. */ -internal fun PythonAttribute.toSmlAttribute(): SmlAttribute { +fun PythonAttribute.toSmlAttribute(): SmlAttribute { val stubName = name.snakeCaseToLowerCamelCase() return createSmlAttribute( @@ -133,7 +133,7 @@ internal fun PythonAttribute.toSmlAttribute(): SmlAttribute { ) } -internal fun PythonFunction.toSmlFunction(): SmlFunction { +fun PythonFunction.toSmlFunction(): SmlFunction { val stubName = name.snakeCaseToLowerCamelCase() return createSmlFunction( @@ -169,7 +169,7 @@ private fun createSmlPythonNameAnnotationUse(name: String): SmlAnnotationUse { ) } -internal fun PythonParameter.toSmlParameterOrNull(): SmlParameter? { +fun PythonParameter.toSmlParameterOrNull(): SmlParameter? { if (assignedBy == IMPLICIT) { return null } @@ -191,7 +191,7 @@ internal fun PythonParameter.toSmlParameterOrNull(): SmlParameter? { ) } -internal fun PythonResult.toSmlResult(): SmlResult { +fun PythonResult.toSmlResult(): SmlResult { val stubName = name.snakeCaseToLowerCamelCase() return createSmlResult( @@ -211,7 +211,7 @@ internal fun PythonResult.toSmlResult(): SmlResult { /** * Creates a Simple-ML enum that corresponds to the Python enum. */ -internal fun PythonEnum.toSmlEnum(): SmlEnum { +fun PythonEnum.toSmlEnum(): SmlEnum { val stubName = name.snakeCaseToUpperCamelCase() return createSmlEnum( @@ -231,7 +231,7 @@ internal fun PythonEnum.toSmlEnum(): SmlEnum { /** * Creates a Simple-ML enum variant that corresponds to the Python enum instance. */ -internal fun PythonEnumInstance.toSmlEnumVariant(): SmlEnumVariant { +fun PythonEnumInstance.toSmlEnumVariant(): SmlEnumVariant { val stubName = name.snakeCaseToUpperCamelCase() return createSmlEnumVariant( @@ -249,11 +249,11 @@ internal fun PythonEnumInstance.toSmlEnumVariant(): SmlEnumVariant { // Name conversions ---------------------------------------------------------------------------------------------------- -internal fun String.snakeCaseToLowerCamelCase(): String { +fun String.snakeCaseToLowerCamelCase(): String { return this.snakeCaseToCamelCase().replaceFirstChar { it.lowercase() } } -internal fun String.snakeCaseToUpperCamelCase(): String { +fun String.snakeCaseToUpperCamelCase(): String { return this.snakeCaseToCamelCase().replaceFirstChar { it.uppercase() } } @@ -263,7 +263,7 @@ private fun String.snakeCaseToCamelCase(): String { // Type conversions ---------------------------------------------------------------------------------------------------- -internal fun PythonType?.toSmlType(): SmlAbstractType { +fun PythonType?.toSmlType(): SmlAbstractType { return when (this) { is PythonNamedType -> { createSmlNamedType( @@ -299,7 +299,7 @@ internal fun PythonType?.toSmlType(): SmlAbstractType { // Value conversions --------------------------------------------------------------------------------------------------- -internal fun PythonExpression.toSmlExpression(): SmlAbstractExpression? { +fun PythonExpression.toSmlExpression(): SmlAbstractExpression? { if (this !is PythonStringifiedExpression) { return createSmlString("###invalid###$this###") } diff --git a/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/PythonCodeGeneratorTest.kt b/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGeneratorTest.kt similarity index 99% rename from api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/PythonCodeGeneratorTest.kt rename to api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGeneratorTest.kt index d2a6ce4ab..799a39eb8 100644 --- a/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/PythonCodeGeneratorTest.kt +++ b/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/PythonCodeGeneratorTest.kt @@ -1,7 +1,5 @@ -package com.larsreimann.api_editor.codegen.python_code_gen +package com.larsreimann.api_editor.codegen -import com.larsreimann.api_editor.codegen.toPythonCode -import com.larsreimann.api_editor.codegen.toPythonCodeOrNull import com.larsreimann.api_editor.model.Boundary import com.larsreimann.api_editor.model.ComparisonOperator.LESS_THAN import com.larsreimann.api_editor.model.ComparisonOperator.LESS_THAN_OR_EQUALS From ec63d0ac06dcb4ba775c7f0747486821198c7822 Mon Sep 17 00:00:00 2001 From: lars-reimann Date: Thu, 17 Feb 2022 11:19:22 +0000 Subject: [PATCH 3/4] style: apply automatic fixes of linters --- .../model/InferableAnnotation.ts | 8 ++-- .../features/annotations/AnnotationView.tsx | 28 ++++++------- .../annotations/forms/TypeValueForm.tsx | 41 +++++++++---------- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/api-editor/client/src/features/annotatedPackageData/model/InferableAnnotation.ts b/api-editor/client/src/features/annotatedPackageData/model/InferableAnnotation.ts index da8a83850..1110b84d7 100644 --- a/api-editor/client/src/features/annotatedPackageData/model/InferableAnnotation.ts +++ b/api-editor/client/src/features/annotatedPackageData/model/InferableAnnotation.ts @@ -35,7 +35,7 @@ const convertDefaultValue = (type: DefaultType, value: DefaultValue) => { }; case 'none': return { - type: `${dataPathPrefix}DefaultNone` + type: `${dataPathPrefix}DefaultNone`, }; } }; @@ -55,7 +55,7 @@ export class InferableAttributeAnnotation extends InferableAnnotation { super(dataPathPrefix + 'AttributeAnnotation'); this.defaultValue = convertDefaultValue( attributeAnnotation.defaultType, - attributeAnnotation.defaultValue + attributeAnnotation.defaultValue, ); } } @@ -97,7 +97,7 @@ export class InferableConstantAnnotation extends InferableAnnotation { super(dataPathPrefix + 'ConstantAnnotation'); this.defaultValue = convertDefaultValue( constantAnnotation.defaultType, - constantAnnotation.defaultValue + constantAnnotation.defaultValue, ); } } @@ -140,7 +140,7 @@ export class InferableOptionalAnnotation extends InferableAnnotation { super(dataPathPrefix + 'OptionalAnnotation'); this.defaultValue = convertDefaultValue( optionalAnnotation.defaultType, - optionalAnnotation.defaultValue + optionalAnnotation.defaultValue, ); } } diff --git a/api-editor/client/src/features/annotations/AnnotationView.tsx b/api-editor/client/src/features/annotations/AnnotationView.tsx index b33df9f4b..c36a0ca98 100644 --- a/api-editor/client/src/features/annotations/AnnotationView.tsx +++ b/api-editor/client/src/features/annotations/AnnotationView.tsx @@ -6,8 +6,8 @@ import { Text as ChakraText, } from '@chakra-ui/react'; import React from 'react'; -import {FaTrash, FaWrench} from 'react-icons/fa'; -import {useAppDispatch, useAppSelector} from '../../app/hooks'; +import { FaTrash, FaWrench } from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from '../../app/hooks'; import { BoundaryAnnotation, ComparisonOperator, @@ -51,7 +51,7 @@ interface AnnotationViewProps { target: string; } -const AnnotationView: React.FC = function ({target}) { +const AnnotationView: React.FC = function ({ target }) { const dispatch = useAppDispatch(); const attributeAnnotation = useAppSelector(selectAttribute(target)); @@ -112,7 +112,7 @@ const AnnotationView: React.FC = function ({target}) { name={calledAfterName} key={calledAfterName} onDelete={() => - dispatch(removeCalledAfter({target, calledAfterName})) + dispatch(removeCalledAfter({ target, calledAfterName })) } /> ))} @@ -141,10 +141,10 @@ const AnnotationView: React.FC = function ({target}) { type="group" name={groupName} onEdit={() => - dispatch(showGroupAnnotationForm({target, groupName})) + dispatch(showGroupAnnotationForm({ target, groupName })) } onDelete={() => - dispatch(removeGroup({target, groupName})) + dispatch(removeGroup({ target, groupName })) } /> ))} @@ -206,7 +206,7 @@ const valueToString = (value: DefaultValue, type: DefaultType): string => { case 'boolean': return value === true ? 'True' : 'False'; case 'none': - return "None"; + return 'None'; } }; @@ -243,15 +243,15 @@ interface AnnotationProps { } const Annotation: React.FC = function ({ - name, - onDelete, - onEdit, - type, - }) { + name, + onDelete, + onEdit, + type, +}) { return ( } + icon={} aria-label="Delete annotation" colorScheme="red" onClick={onDelete} diff --git a/api-editor/client/src/features/annotations/forms/TypeValueForm.tsx b/api-editor/client/src/features/annotations/forms/TypeValueForm.tsx index 42a6a42f9..64b76acd8 100644 --- a/api-editor/client/src/features/annotations/forms/TypeValueForm.tsx +++ b/api-editor/client/src/features/annotations/forms/TypeValueForm.tsx @@ -14,11 +14,11 @@ import { Select, Stack, } from '@chakra-ui/react'; -import React, {useEffect} from 'react'; -import {useForm} from 'react-hook-form'; -import {useAppDispatch} from '../../../app/hooks'; -import {Optional} from '../../../common/util/types'; -import {booleanPattern, numberPattern} from '../../../common/validation'; +import React, { useEffect } from 'react'; +import { useForm } from 'react-hook-form'; +import { useAppDispatch } from '../../../app/hooks'; +import { Optional } from '../../../common/util/types'; +import { booleanPattern, numberPattern } from '../../../common/validation'; import PythonDeclaration from '../../packageData/model/PythonDeclaration'; import { DefaultType, @@ -41,12 +41,12 @@ export interface TypeValueFormState { } const TypeValueForm: React.FC = function ({ - target, - annotationType, - previousDefaultType, - previousDefaultValue, - onUpsertAnnotation, - }) { + target, + annotationType, + previousDefaultType, + previousDefaultValue, + onUpsertAnnotation, +}) { const dispatch = useAppDispatch(); const { @@ -55,7 +55,7 @@ const TypeValueForm: React.FC = function ({ reset, setValue, watch, - formState: {errors}, + formState: { errors }, } = useForm({ defaultValues: { defaultType: 'string', @@ -83,11 +83,11 @@ const TypeValueForm: React.FC = function ({ }; const handleSave = (data: TypeValueFormState) => { - let toUpsert = {...data}; + let toUpsert = { ...data }; if (data.defaultType === 'boolean') { - toUpsert = {...data, defaultValue: data.defaultValue === 'true'}; - } else if (data.defaultType === "none") { - toUpsert = {...data, defaultValue: null} + toUpsert = { ...data, defaultValue: data.defaultValue === 'true' }; + } else if (data.defaultType === 'none') { + toUpsert = { ...data, defaultValue: null }; } onUpsertAnnotation(toUpsert); dispatch(hideAnnotationForms()); @@ -122,7 +122,7 @@ const TypeValueForm: React.FC = function ({ - {watchDefaultType !== "none" && ( + {watchDefaultType !== 'none' && ( Default value for "{target.name}": @@ -143,8 +143,8 @@ const TypeValueForm: React.FC = function ({ })} /> - - + + )} @@ -160,11 +160,10 @@ const TypeValueForm: React.FC = function ({ )} - {errors.defaultValue?.message} + {errors.defaultValue?.message} )} - ); }; From 920ae7a687fab2fe1fe00ad4586493c1e9097330 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Thu, 17 Feb 2022 12:21:49 +0100 Subject: [PATCH 4/4] test: some tests using strings/none as default values --- .../python_code_gen/ConstructorPythonCodeGeneratorTest.kt | 7 +++---- .../python_code_gen/FunctionPythonCodeGeneratorTest.kt | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/ConstructorPythonCodeGeneratorTest.kt b/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/ConstructorPythonCodeGeneratorTest.kt index d6c32e7a3..b7b85a7d3 100644 --- a/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/ConstructorPythonCodeGeneratorTest.kt +++ b/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/ConstructorPythonCodeGeneratorTest.kt @@ -4,6 +4,7 @@ import com.larsreimann.api_editor.codegen.toPythonCode import com.larsreimann.api_editor.model.BoundaryAnnotation import com.larsreimann.api_editor.model.ComparisonOperator import com.larsreimann.api_editor.model.DefaultBoolean +import com.larsreimann.api_editor.model.DefaultNone import com.larsreimann.api_editor.model.DefaultNumber import com.larsreimann.api_editor.model.EnumAnnotation import com.larsreimann.api_editor.model.EnumPair @@ -559,9 +560,7 @@ class ConstructorPythonCodeGeneratorTest { fun `should process Group-, Required- and OptionalAnnotation on constructor level`() { // given testParameter2.annotations.add( - OptionalAnnotation( - DefaultBoolean(false) - ) + OptionalAnnotation(DefaultNone) ) testParameter3.annotations.add( RequiredAnnotation @@ -592,7 +591,7 @@ class ConstructorPythonCodeGeneratorTest { | self.instance = testModule.testClass(testParameter1, testGroup.testParameter2, testGroup.testParameter3) | |class TestGroup: - | def __init__(self, testParameter3, *, testParameter2=False): + | def __init__(self, testParameter3, *, testParameter2=None): | self.testParameter3 = testParameter3 | self.testParameter2 = testParameter2 | diff --git a/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/FunctionPythonCodeGeneratorTest.kt b/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/FunctionPythonCodeGeneratorTest.kt index 117dbeca1..d96348877 100644 --- a/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/FunctionPythonCodeGeneratorTest.kt +++ b/api-editor/server/src/test/kotlin/com/larsreimann/api_editor/codegen/python_code_gen/FunctionPythonCodeGeneratorTest.kt @@ -5,6 +5,7 @@ import com.larsreimann.api_editor.model.BoundaryAnnotation import com.larsreimann.api_editor.model.ComparisonOperator import com.larsreimann.api_editor.model.DefaultBoolean import com.larsreimann.api_editor.model.DefaultNumber +import com.larsreimann.api_editor.model.DefaultString import com.larsreimann.api_editor.model.EnumAnnotation import com.larsreimann.api_editor.model.EnumPair import com.larsreimann.api_editor.model.GroupAnnotation @@ -472,7 +473,7 @@ class FunctionPythonCodeGeneratorTest { // given testParameter2.annotations.add( OptionalAnnotation( - DefaultBoolean(false) + DefaultString("string") ) ) testFunction.annotations.add( @@ -493,7 +494,7 @@ class FunctionPythonCodeGeneratorTest { |from __future__ import annotations | |class TestGroup: - | def __init__(self, testParameter3, *, testParameter2=False): + | def __init__(self, testParameter3, *, testParameter2='string'): | self.testParameter3 = testParameter3 | self.testParameter2 = testParameter2 |