Skip to content
This repository was archived by the owner on Jan 19, 2025. It is now read-only.

feat: None as default value #422

Merged
merged 4 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
};
}
};

Expand All @@ -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,
);
}
}

Expand Down Expand Up @@ -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[];
Expand All @@ -101,6 +112,7 @@ export class InferableGroupAnnotation extends InferableAnnotation {
this.parameters = groupAnnotation.parameters;
}
}

export class InferableEnumAnnotation extends InferableAnnotation {
readonly enumName: string;
readonly pairs: EnumPair[];
Expand All @@ -111,6 +123,7 @@ export class InferableEnumAnnotation extends InferableAnnotation {
this.pairs = enumAnnotation.pairs;
}
}

export class InferableMoveAnnotation extends InferableAnnotation {
readonly destination: string;

Expand All @@ -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;

Expand All @@ -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');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ const TypeValueForm: React.FC<TypeValueFormProps> = function ({
let toUpsert = { ...data };
if (data.defaultType === 'boolean') {
toUpsert = { ...data, defaultValue: data.defaultValue === 'true' };
} else if (data.defaultType === 'none') {
toUpsert = { ...data, defaultValue: null };
}
onUpsertAnnotation(toUpsert);
dispatch(hideAnnotationForms());
Expand Down Expand Up @@ -116,49 +118,52 @@ const TypeValueForm: React.FC<TypeValueFormProps> = function ({
<Radio value="string">String</Radio>
<Radio value="number">Number</Radio>
<Radio value="boolean">Boolean</Radio>
<Radio value="none">None</Radio>
</Stack>
</RadioGroup>

<FormControl isInvalid={Boolean(errors?.defaultValue)}>
<FormLabel>
Default value for &quot;{target.name}&quot;:
</FormLabel>
{watchDefaultType === 'string' && (
<Input
{...register('defaultValue', {
required: 'This is required.',
})}
/>
)}
{watchDefaultType === 'number' && (
<NumberInput>
<NumberInputField
{watchDefaultType !== 'none' && (
<FormControl isInvalid={Boolean(errors?.defaultValue)}>
<FormLabel>
Default value for &quot;{target.name}&quot;:
</FormLabel>
{watchDefaultType === 'string' && (
<Input
{...register('defaultValue', {
required: 'This is required.',
pattern: numberPattern,
})}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
)}
{watchDefaultType === 'boolean' && (
<Select
{...register('defaultValue', {
required: 'This is required.',
pattern: booleanPattern,
})}
>
<option value="true">True</option>
<option value="false">False</option>
</Select>
)}
<FormErrorMessage>
<FormErrorIcon /> {errors.defaultValue?.message}
</FormErrorMessage>
</FormControl>
)}
{watchDefaultType === 'number' && (
<NumberInput>
<NumberInputField
{...register('defaultValue', {
required: 'This is required.',
pattern: numberPattern,
})}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
)}
{watchDefaultType === 'boolean' && (
<Select
{...register('defaultValue', {
required: 'This is required.',
pattern: booleanPattern,
})}
>
<option value="true">True</option>
<option value="false">False</option>
</Select>
)}
<FormErrorMessage>
<FormErrorIcon /> {errors.defaultValue?.message}
</FormErrorMessage>
</FormControl>
)}
</AnnotationForm>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -101,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")
Expand All @@ -111,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() }

Expand All @@ -130,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) }
Expand Down Expand Up @@ -164,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()) {
Expand All @@ -180,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) }
Expand All @@ -211,7 +212,7 @@ internal fun PythonFunction.toPythonCode() = buildString {
}
}

internal fun List<PythonParameter>.toPythonCode(): String {
fun List<PythonParameter>.toPythonCode(): String {
val assignedByToParameter = this@toPythonCode.groupBy { it.assignedBy }
val implicitParametersString = assignedByToParameter[IMPLICIT]
?.joinToString { it.toPythonCode() }
Expand Down Expand Up @@ -246,7 +247,7 @@ internal fun List<PythonParameter>.toPythonCode(): String {
.joinToString()
}

internal fun PythonParameter.toPythonCode() = buildString {
fun PythonParameter.toPythonCode() = buildString {
val typeStringOrNull = type.toPythonCodeOrNull()

append(name)
Expand All @@ -262,13 +263,14 @@ 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() }})"
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
Expand All @@ -279,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 -> {
Expand All @@ -299,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.')")
Expand Down
Loading