Skip to content

Commit

Permalink
work on class methods
Browse files Browse the repository at this point in the history
  • Loading branch information
narthur committed Apr 8, 2024
1 parent c4c4c31 commit 535dc52
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 56 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"dependencies": {
"axios": "^1.6.7",
"json-schema-to-typescript": "^13.1.2",
"node-emoji": "^2.1.3",
"rc": "^1.2.8",
"typescript": "^5.3.3",
"zod": "^3.22.4"
Expand Down
39 changes: 39 additions & 0 deletions pnpm-lock.yaml

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

10 changes: 9 additions & 1 deletion src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { BaserowSdk } from "./index.js";
import z from "zod";
import fs from "fs";
import makeType from "./codegen/makeType.js";
import makeClassMethods from "./codegen/makeClassMethods.js";

export default async function main(): Promise<void> {
const raw = rc("baserow");
Expand Down Expand Up @@ -34,7 +35,14 @@ export default async function main(): Promise<void> {
console.log(tableId);
console.log(fields);

const typeDef = `export type ${tableName}Row = ${makeType(fields)}`;
//TODO: this may not be correct for all generated files
const typeDef = `export type ${tableName}RowType = ${makeType(fields)}
import { Base } from "../src/base.ts";
export class ${tableName}Row extends Base<${tableName}RowType> {
${makeClassMethods(fields)}
}`;

fs.writeFileSync(`./__generated__/${tableName}.ts`, typeDef);
}),
Expand Down
118 changes: 118 additions & 0 deletions src/codegen/makeClassMethods.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { describe, it, expect } from "vitest";
import makeClassMethods from "./makeClassMethods";
import f from "../test/fixtures/fieldDefinition";

describe("makeClassMethods", () => {
it("returns empty string for empty fields", () => {
expect(makeClassMethods([])).toBe("");
});

it("returns string for single field", () => {
expect(
makeClassMethods([
f({
name: "the_field_name",
}),
]),
).toContain("the_field_name");
});

it("returns string for multiple fields", () => {
expect(
makeClassMethods([
f({
name: "the_field_name",
}),
f({
name: "the_field_name2",
}),
]),
).toContain("the_field_name2");
});

it("handles field names with spaces", () => {
expect(
makeClassMethods([
f({
name: "the field name",
}),
]),
).toContain("getTheFieldName");
});

it("handles field names with spaces in setter", () => {
expect(
makeClassMethods([
f({
name: "the field name",
}),
]),
).toContain("setTheFieldName");
});

it("sets return type", () => {
expect(
makeClassMethods([
f({
name: "the_field_name",
type: "text",
}),
]),
).toContain("(): string");
});

it("uses mapped type for value arg", () => {
expect(
makeClassMethods([
f({
name: "the_field_name",
type: "text",
}),
]),
).toContain("value: string");
});

it("uses mapped type for getField generic", () => {
expect(
makeClassMethods([
f({
name: "the_field_name",
type: "text",
}),
]),
).toContain("<string>");
});

it("handles emoji field name", () => {
expect(
makeClassMethods([
f({
name: "🔥",
}),
]),
).toContain("getFire()");
});

it("handles lookup types", () => {
expect(
makeClassMethods([
f({
name: "the_field_name",
type: "lookup",
formula_type: "number",
}),
]),
).toContain("number");
});

it("parses numbers", () => {
expect(
makeClassMethods([
f({
name: "the_field_name",
type: "number",
}),
]),
).toContain("parseFloat");
});
});
47 changes: 47 additions & 0 deletions src/codegen/makeClassMethods.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { FieldDefinition, ListFieldsResponse } from "../index.js";
import { makeFieldType } from "./makeFieldType.js";
import * as emoji from "node-emoji";

function toCamelCase(str: string): string {
return emoji
.unemojify(str)
.replaceAll(":", "")
.replace(/([-_\s:][a-z])/gi, ($1) => {
return $1
.toUpperCase()
.replace("-", "")
.replace("_", "")
.replace(" ", "");
});
}

function makeGetter(field: FieldDefinition): string {
const t = makeFieldType(field);

if (t.includes("number | string")) {
return `public ${toCamelCase(`get ${field.name}`)}(): number {
return parseFloat(this.getField<${t}>("${field.name}").toString());
}`;
}

return `public ${toCamelCase(`get ${field.name}`)}(): ${t} {
return this.getField<${t}>("${field.name}");
}`;
}

export default function makeClassMethods(fields: ListFieldsResponse): string {
let classMethods = "";

fields.forEach((field) => {
const t = makeFieldType(field);
classMethods += `
${makeGetter(field)}
public ${toCamelCase(`set ${field.name}`)}(value: ${t}): Promise<void> {
return this.setField("${field.name}", value);
}
`;
});

return classMethods;
}
17 changes: 17 additions & 0 deletions src/codegen/makeFieldType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { FieldDefinition } from "../index.js";
import { mapPrimitive } from "./mapPrimitive.js";

export function makeFieldType(field: FieldDefinition): string {
if (field.type === "link_row") {
return '{ "id": number, "value": string }[]';
}
if (["rollup", "formula", "lookup"].includes(field.type)) {
switch (field.formula_type) {
case "array":
return `(${mapPrimitive(field.array_formula_type)})[]`;
default:
return mapPrimitive(field.formula_type);
}
}
return mapPrimitive(field.type);
}
23 changes: 9 additions & 14 deletions src/codegen/makeType.spec.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
import { describe, it, expect } from "vitest";
import makeType from "./makeType";
import { FieldDefinition } from "../index.ts";

function f(field: Partial<FieldDefinition>): FieldDefinition {
return {
id: 1,
name: "the_field_name",
type: "text",
table_id: 1,
order: 1,
primary: false,
read_only: false,
...field,
};
}
import f from "../test/fixtures/fieldDefinition";

describe("makeType", () => {
it("returns string for type text", () => {
Expand Down Expand Up @@ -257,4 +244,12 @@ describe("makeType", () => {
]),
).toContain("string");
});

it("includes id", () => {
expect(makeType([])).toContain("id");
});

it("includes order", () => {
expect(makeType([])).toContain("order");
});
});
46 changes: 6 additions & 40 deletions src/codegen/makeType.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,14 @@
import { ListFieldsResponse, FieldDefinition } from "../index.js";

const DEFAULT_TYPE = "unknown";

function mapPrimitive(baserowPrimitive: string | undefined): string {
switch (baserowPrimitive) {
case "text":
return "string";
case "number":
return "number | string";
case "single_select":
return "boolean";
case "long_text":
return "string";
case "boolean":
return "boolean";
case "button":
return "string";
case "date":
return "string";
default:
return DEFAULT_TYPE;
}
}

function getFieldType(field: FieldDefinition): string {
if (field.type === "link_row") {
return '{ "id": number, "value": string }[]';
}
if (["rollup", "formula", "lookup"].includes(field.type)) {
switch (field.formula_type) {
case "array":
return `(${mapPrimitive(field.array_formula_type)})[]`;
default:
return mapPrimitive(field.formula_type);
}
}
return mapPrimitive(field.type);
}
import { ListFieldsResponse } from "../index.js";
import { makeFieldType } from "./makeFieldType.js";

export default function makeType(fields: ListFieldsResponse): string {
let typeDef = `{\n`;

typeDef += ' "id": number;\n';
typeDef += ' "order": string;\n';

fields.forEach((field) => {
typeDef += ` "${field.name}": ${getFieldType(field)};\n`;
typeDef += ` "${field.name}": ${makeFieldType(field)};\n`;
});

typeDef += `}`;
Expand Down
Loading

0 comments on commit 535dc52

Please sign in to comment.