Skip to content

Commit

Permalink
feat(lib): use objects instead of objects in arrays if possible
Browse files Browse the repository at this point in the history
This improves the UI surface so that less arrays are being used and direct access of properties is way easier

BREAKING CHANGE: This changes the API surface of every module / provider

Closes #258
  • Loading branch information
DanielMSchmidt committed Oct 18, 2021
1 parent 3696a51 commit 01bd6b5
Show file tree
Hide file tree
Showing 10 changed files with 337 additions and 228 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { AttributeModel } from "../models";
import { downcaseFirst } from "../../../util";
import { CUSTOM_DEFAULTS } from "../custom-defaults";

function titleCase(value: string) {
return value[0].toUpperCase() + value.slice(1);
}

export class AttributesEmitter {
constructor(private code: CodeMaker) {}

Expand All @@ -12,198 +16,88 @@ export class AttributesEmitter {
`// ${att.terraformName} - computed: ${att.computed}, optional: ${att.isOptional}, required: ${att.isRequired}`
);

switch (true) {
case att.computed &&
!att.isOptional &&
att.type.isComputedComplex &&
att.type.isList &&
att.type.isMap:
return this.emitComputedComplexListMap(att);
case att.computed &&
!att.isOptional &&
att.type.isComputedComplex &&
att.type.isList:
return this.emitComputedComplexList(att);
case att.computed &&
att.isOptional &&
att.type.isComputedComplex &&
att.type.isList:
return this.emitComputedComplexOptional(att, escapeReset, escapeInput);
case att.computed &&
!att.isOptional &&
att.type.isComputedComplex &&
att.type.isMap:
return this.emitComputedComplexMap(att);
case att.computed &&
att.isOptional &&
att.type.isComputedComplex &&
att.type.isMap:
return this.emitComputedComplexOptional(att, escapeReset, escapeInput);
case att.computed &&
att.optional &&
!att.isRequired &&
att.isConfigIgnored:
return this.emitOptionalComputedIgnored(att);
case att.computed && att.isOptional:
return this.emitOptionalComputed(att, escapeReset, escapeInput);
case att.computed:
return this.emitComputed(att);
case att.isOptional:
return this.emitOptional(att, escapeReset, escapeInput);
case att.isRequired:
return this.emitRequired(att, escapeInput);
}
}

private emitOptional(
att: AttributeModel,
escapeReset: boolean,
escapeInput: boolean
) {
this.code.line(`private ${att.storageName}?: ${att.type.name};`);
this.code.openBlock(`public get ${att.name}()`);
this.code.line(
`return ${
att.isProvider
? "this." + att.storageName
: this.determineGetAttCall(att)
};`
);
this.code.closeBlock();

this.code.openBlock(
`public set ${att.name}(value: ${att.type.name} ${
att.isProvider ? " | undefined" : ""
})`
);
this.code.line(`this.${att.storageName} = value;`);
this.code.closeBlock();

this.code.openBlock(`public ${this.getResetName(att.name, escapeReset)}()`);
this.code.line(`this.${att.storageName} = undefined;`);
this.code.closeBlock();

this.code.line(`// Temporarily expose input value. Use with caution.`);
this.code.openBlock(`public get ${this.getInputName(att, escapeInput)}()`);
this.code.line(`return this.${att.storageName}`);
this.code.closeBlock();
}

private emitOptionalComputed(
att: AttributeModel,
escapeReset: boolean,
escapeInput: boolean
) {
this.code.line(`private ${att.storageName}?: ${att.type.name};`);
this.code.openBlock(`public get ${att.name}()`);
this.code.line(`return ${this.determineGetAttCall(att)};`);
this.code.closeBlock();

this.code.openBlock(`public set ${att.name}(value: ${att.type.name})`);
this.code.line(`this.${att.storageName} = value;`);
this.code.closeBlock();

this.code.openBlock(`public ${this.getResetName(att.name, escapeReset)}()`);
this.code.line(`this.${att.storageName} = undefined;`);
this.code.closeBlock();

this.code.line(`// Temporarily expose input value. Use with caution.`);
this.code.openBlock(`public get ${this.getInputName(att, escapeInput)}()`);
this.code.line(`return this.${att.storageName}`);
this.code.closeBlock();
}
const isStored = att.isStored;
const hasResetMethod = isStored && !att.isRequired;
const hasInputMethod = isStored;

private emitOptionalComputedIgnored(att: AttributeModel) {
this.code.openBlock(`public get ${att.name}()`);
this.code.line(`return ${this.determineGetAttCall(att)};`);
this.code.closeBlock();
}
if (isStored) {
this.code.line(`private ${att.storageName}?: ${att.type.storedName}; `);
}

private emitComputed(att: AttributeModel) {
this.code.openBlock(`public get ${att.name}()`);
this.code.line(`return ${this.determineGetAttCall(att)};`);
this.code.closeBlock();
}
switch (att.getterType._type) {
case "plain":
this.code.openBlock(`public get ${att.name}()`);
this.code.line(`return ${this.determineGetAttCall(att)};`);
this.code.closeBlock();
break;

private emitRequired(att: AttributeModel, escapeInput: boolean) {
this.code.line(`private ${att.storageName}: ${att.type.name};`);
this.code.openBlock(`public get ${att.name}()`);
this.code.line(
`return ${
att.isProvider
? "this." + att.storageName
: this.determineGetAttCall(att)
};`
);
this.code.closeBlock();
case "args":
this.code.openBlock(
`public ${att.name}(${att.getterType.args})${
att.getterType.returnType ? ": " + att.getterType.returnType : ""
}`
);
this.code.line(`return ${att.getterType.returnStatement};`);
this.code.closeBlock();
break;

this.code.openBlock(`public set ${att.name}(value: ${att.type.name})`);
this.code.line(`this.${att.storageName} = value;`);
this.code.closeBlock();
case "stored_class":
this.code.line(
`private _${att.storageName}Output = ${this.storedClassInit(att)};`
);
this.code.openBlock(`public get ${att.name}()`);
this.code.line(`return this._${att.storageName}Output;`);
this.code.closeBlock();
break;
}

this.code.line(`// Temporarily expose input value. Use with caution.`);
this.code.openBlock(`public get ${this.getInputName(att, escapeInput)}()`);
this.code.line(`return this.${att.storageName}`);
this.code.closeBlock();
}
if (att.setterType.__type === "set") {
this.code.openBlock(
`public set ${att.name}(value: ${att.setterType.type})`
);
this.code.line(`this.${att.storageName} = value;`);
this.code.closeBlock();
} else if (att.setterType.__type === "put") {
this.code.openBlock(
`public put${titleCase(att.name)}(value: ${att.setterType.type})`
);
this.code.line(`this.${att.storageName} = value;`);
this.code.closeBlock();
}

private emitComputedComplexList(att: AttributeModel) {
this.code.openBlock(`public ${att.name}(index: string)`);
this.code.line(
`return new ${att.type.name}(this, '${att.terraformName}', index);`
);
this.code.closeBlock();
}
if (hasResetMethod) {
this.code.openBlock(
`public ${this.getResetName(att.name, escapeReset)}()`
);
this.code.line(`this.${att.storageName} = undefined;`);
this.code.closeBlock();
}

private emitComputedComplexListMap(att: AttributeModel) {
this.code.openBlock(
`public ${att.name}(index: string, key: string): ${this.determineMapType(
att
)}`
);
this.code.line(
`return new ${att.type.name}(this, \`${att.terraformName}.\${index}\`).lookup(key);`
);
this.code.closeBlock();
if (hasInputMethod) {
this.code.line(`// Temporarily expose input value. Use with caution.`);
this.code.openBlock(
`public get ${this.getInputName(att, escapeInput)}()`
);
this.code.line(`return this.${att.storageName}`);
this.code.closeBlock();
}
}

private emitComputedComplexOptional(
att: AttributeModel,
escapeReset: boolean,
escapeInput: boolean
) {
this.code.line(`private ${att.storageName}?: ${att.type.name}`);
this.code.openBlock(`public get ${att.name}(): ${att.type.name}`);
this.code.line(
`return this.interpolationForAttribute('${att.terraformName}') as any; // Getting the computed value is not yet implemented`
);
this.code.closeBlock();

this.code.openBlock(`public set ${att.name}(value: ${att.type.name})`);
this.code.line(`this.${att.storageName} = value;`);
this.code.closeBlock();

this.code.openBlock(`public ${this.getResetName(att.name, escapeReset)}()`);
this.code.line(`this.${att.storageName} = undefined;`);
this.code.closeBlock();
private storedClassInit(att: AttributeModel) {
let invocation = `new ${att.type.name}${
att.type.isSingleItem ? "Output" : ""
}(this as any, "${att.terraformName}", ${
att.type.isSingleItem ? "true" : "false"
})`;

this.code.line(`// Temporarily expose input value. Use with caution.`);
this.code.openBlock(`public get ${this.getInputName(att, escapeInput)}()`);
this.code.line(`return this.${att.storageName}`);
this.code.closeBlock();
}

private emitComputedComplexMap(att: AttributeModel) {
this.code.openBlock(
`public ${att.name}(key: string): ${this.determineMapType(att)}`
);
this.code.line(
`return new ${att.type.name}(this, '${att.terraformName}').lookup(key);`
);
this.code.closeBlock();
return invocation;
}

public determineGetAttCall(att: AttributeModel): string {
if (att.isProvider) {
return `this.${att.storageName}`;
}

const type = att.type;
if (type.isString) {
return `this.getStringAttribute('${att.terraformName}')`;
Expand All @@ -215,33 +109,16 @@ export class AttributesEmitter {
return `this.getNumberAttribute('${att.terraformName}')`;
}
if (type.isBoolean) {
return `this.getBooleanAttribute('${att.terraformName}')`;
return `this.getBooleanAttribute('${att.terraformName}') as any`;
}
if (process.env.DEBUG) {
console.error(
`The attribute ${JSON.stringify(att)} isn't implemented yet`
);
}
return `this.interpolationForAttribute('${att.terraformName}') as any`;
}

public determineMapType(att: AttributeModel): string {
const type = att.type;
if (type.isStringMap) {
return `string`;
}
if (type.isNumberMap) {
return `number`;
}
if (type.isBooleanMap) {
return `boolean`;
}
if (process.env.DEBUG) {
console.error(
`The attribute ${JSON.stringify(att)} isn't implemented yet`
);
}
return `any`;
this.code.line(`// Getting the computed value is not yet implemented`);
return `this.interpolationForAttribute('${att.terraformName}') as any`;
}

public needsInputEscape(
Expand Down Expand Up @@ -277,9 +154,9 @@ export class AttributesEmitter {
public getResetName(name: string, escape: boolean) {
if (!name) return name;
if (escape) {
return `resetTf${name[0].toUpperCase() + name.slice(1)}`;
return `resetTf${titleCase(name)}`;
} else {
return `reset${name[0].toUpperCase() + name.slice(1)}`;
return `reset${titleCase(name)}`;
}
}

Expand All @@ -298,11 +175,7 @@ export class AttributesEmitter {
switch (true) {
case type.isList && type.isMap:
this.code.line(
`${
att.terraformName
}: ${defaultCheck}cdktf.listMapper(cdktf.hashMapper(cdktf.${this.determineMapType(
att
)}ToTerraform))(${varReference}),`
`${att.terraformName}: ${defaultCheck}cdktf.listMapper(cdktf.hashMapper(cdktf.${att.mapType}ToTerraform))(${varReference}),`
);
break;
case type.isStringList || type.isNumberList || type.isBooleanList:
Expand All @@ -314,7 +187,7 @@ export class AttributesEmitter {
)}ToTerraform)(${varReference}),`
);
break;
case type.isList:
case type.isList && !type.isSingleItem:
this.code.line(
`${
att.terraformName
Expand All @@ -325,11 +198,7 @@ export class AttributesEmitter {
break;
case type.isMap:
this.code.line(
`${
att.terraformName
}: ${defaultCheck}cdktf.hashMapper(cdktf.${this.determineMapType(
att
)}ToTerraform)(${varReference}),`
`${att.terraformName}: ${defaultCheck}cdktf.hashMapper(cdktf.${att.mapType}ToTerraform)(${varReference}),`
);
break;
case type.isString:
Expand Down
Loading

0 comments on commit 01bd6b5

Please sign in to comment.