Skip to content
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
20 changes: 16 additions & 4 deletions src/internal/create-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Command } from "commander";
import { styleText } from "node:util";
import packageJson from "../../package.json" with { type: "json" };
import { logErrorAndExit } from "./utils/log-error-and-exit.js";
import { stringToInt } from "./utils/string-to-int.js";

export type Entity = "constant" | "object" | "view" | "navItem";

Expand All @@ -15,11 +16,13 @@ const VALID_ENTITIES = new Set<Entity>([
export type CliOptions = {
input: string;
output: string;
entities: Array<Entity>;
constantsDir: string;
objectsDir: string;
viewsDir: string;
navMenuItemsDir: string;
entities: Array<Entity>;
viewsBasePosition: number;
navMenuItemsBasePosition: number;
print: boolean;
dryRun: boolean;
clipboard: boolean;
Expand All @@ -32,6 +35,9 @@ const DEFAULT_OBJECTS_DIR = "objects";
const DEFAULT_VIEWS_DIR = "views";
const DEFAULT_NAV_MENU_ITEMS_DIR = "navigation-menu-items";

const DEFAULT_VIEWS_BASE_POSITION = "0";
const DEFAULT_NAV_MENU_ITEMS_BASE_POSITION = "0";

function validateEntities(entities: Array<string>) {
if (entities.length === 0) return;

Expand All @@ -41,7 +47,7 @@ function validateEntities(entities: Array<string>) {

if (invalidEntities.length > 0) {
logErrorAndExit(
`Invalid entity name(s): ${invalidEntities.join(", ")}.\nAllowed values: ${Array.from(VALID_ENTITIES).join(", ")}.`
`Invalid entity name(s): ${invalidEntities.join(", ")}. Allowed values: ${Array.from(VALID_ENTITIES).join(", ")}.`
);
}
}
Expand Down Expand Up @@ -75,19 +81,25 @@ export function createCLI(argv = process.argv) {
.name("Generate twenty fields from types(Object/Interface)")
.option("-i, --input <path>", "*.ts/*.d.ts file")
.option("-o, --output <dir>", "output root directory", DEFAULT_ROOT_DIR)
.option("-e, --entities [entities...]", `can specify single or multiple entities among: ${styleText("yellow", "(constant | object | view | navItem)")}`)
.option("--constants-dir <dir>", "output constants directory", DEFAULT_CONSTANTS_DIR)
.option("--objects-dir <dir>", "output object directory", DEFAULT_OBJECTS_DIR)
.option("--views-dir <dir>", "output views directory", DEFAULT_VIEWS_DIR)
.option("--nav-menu-items-dir <dir>", "output navigation menu items directory", DEFAULT_NAV_MENU_ITEMS_DIR)
.option("-e, --entities [entities...]", `can specify single or multiple entities among: ${styleText("yellow", "(constant | object | view | navItem)")}`)
.option("--views-base-position <number>", "offset for views starting index", DEFAULT_VIEWS_BASE_POSITION)
.option("--nav-menu-items-base-position <number>", "offset for navigation menu items starting index", DEFAULT_NAV_MENU_ITEMS_BASE_POSITION)
Comment on lines +89 to +90
.option("-p, --print", "print to console", false)
.option("-d, --dry-run", "print outputs to console, do not write on disk", false)
.option("-c, --clipboard", "copy object to clipboard", false)
.version(packageJson.version, "-v, --version")
.helpOption()
.action((parsedOpts: CliOptions) => {
validateEntities(normalizeEntities(parsedOpts.entities));
opts = parsedOpts;

const viewsBasePosition = stringToInt(parsedOpts.viewsBasePosition);
const navMenuItemsBasePosition = stringToInt(parsedOpts.navMenuItemsBasePosition);

opts = { ...parsedOpts, viewsBasePosition, navMenuItemsBasePosition};
})
.parse(argv);

Expand Down
6 changes: 5 additions & 1 deletion src/internal/generators/generate-twenty-nav-menu-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { NavigationMenuItemType } from "twenty-sdk/define";
import { toUidVarName } from "../utils/to-uid-var-name.js";
import { toImportStatement } from "../utils/to-import-statement.js";
import { toKebabCase } from "../utils/case-transformation.js";
import { tempStore } from "../utils/temp-store.js";

export function generateTwentyNavMenuItem(
navItemName: string,
Expand All @@ -25,14 +26,17 @@ export function generateTwentyNavMenuItem(
objectUidVarName
);

const navMenuItemsPositionStore =
tempStore().navMenuItemsPositionStore;

const output = dedent`import { defineNavigationMenuItem, NavigationMenuItemType } from "twenty-sdk/define";
${constantImportStatement}

export default defineNavigationMenuItem({
universalIdentifier: ${navMenuItemUidVarName},
name: "${toKebabCase(navItemName)}",
icon: "IconList",
position: 0,
position: ${navMenuItemsPositionStore.getPositionAndIncrement()},
type: NavigationMenuItemType.${
NavigationMenuItemType.OBJECT
},
Expand Down
13 changes: 10 additions & 3 deletions src/internal/generators/generate-twenty-view-fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { fieldUidVarNames } from "../utils/fields.js";
import { FieldType } from "twenty-sdk/define";
import { toImportStatement } from "../utils/to-import-statement.js";

const fieldSeperator = ",\n";

export function generateTwentyViewFields(
objectFilePath: string,
viewFilePath: string,
Expand All @@ -22,7 +24,7 @@ export function generateTwentyViewFields(
...fieldUidVarNames(fields)
);

let viewFields: Array<string> = [];
let viewFields: string = "";
let labelField: string = "";
let islabelFieldExists = false;
let position = 0;
Expand All @@ -37,7 +39,8 @@ export function generateTwentyViewFields(
}

position += 1;
viewFields.push(getFieldString(position, fieldUidVarName));
viewFields += getFieldString(position, fieldUidVarName);
viewFields += fieldSeperator;
});

if (!islabelFieldExists) {
Expand All @@ -50,9 +53,13 @@ export function generateTwentyViewFields(
);
}

const labelFieldSeperator = islabelFieldExists
? fieldSeperator
: "\n";
Comment on lines +56 to +58

return {
fieldMetadataUidsImportStatement,
viewFields: labelField + "\n" + [viewFields].join(",\n"),
viewFields: labelField + labelFieldSeperator + viewFields,
};
}

Expand Down
5 changes: 4 additions & 1 deletion src/internal/generators/generate-twenty-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { generateTwentyViewFields } from "./generate-twenty-view-fields.js";
import type { IRField } from "../types.js";
import { toUidVarName } from "../utils/to-uid-var-name.js";
import { toImportStatement } from "../utils/to-import-statement.js";
import { tempStore } from "../utils/temp-store.js";

export function generateTwentyView(
viewName: string,
Expand Down Expand Up @@ -31,6 +32,8 @@ export function generateTwentyView(
fields
);

const viewPositionStore = tempStore().viewsPositionStore;

const output = dedent`import { defineView, ViewKey } from "twenty-sdk/define";
${viewUidImportStatement}
${fieldMetadataUidsImportStatement}
Expand All @@ -41,7 +44,7 @@ export function generateTwentyView(
objectUniversalIdentifier: ${objectUidVarName},
icon: "IconList",
key: ViewKey.INDEX,
position: 0,
position: ${viewPositionStore.getPositionAndIncrement()},
fields: [
${viewFields}
],
Expand Down
18 changes: 18 additions & 0 deletions src/internal/utils/string-to-int.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { styleText } from "node:util";

export const stringToInt = (str: any): number => {
let num = parseInt(str as string, 10);

if (isNaN(num)) {
console.error(
styleText(
"red",
`Cannot convert "${str}" to an integer. Falling back to 0.`
)
);

num = 0;
}

return num;
};
Comment on lines +3 to +18
38 changes: 38 additions & 0 deletions src/internal/utils/temp-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createCLI } from "../create-cli.js";

const { viewsBasePosition, navMenuItemsBasePosition } =
createCLI();

Comment on lines +1 to +5
type positionStore = {
position: number;
getPositionAndIncrement: () => number;
};

function getValueAndIncrement(store: positionStore): number {
const currentPosition = store.position;
store.position += 1;
return currentPosition;
}

export const viewsPositionStore: positionStore = {
position: viewsBasePosition,

getPositionAndIncrement: function () {
return getValueAndIncrement(this);
},
};

export const navMenuItemsPositionStore: positionStore = {
position: navMenuItemsBasePosition,

getPositionAndIncrement: function () {
return getValueAndIncrement(this);
},
};

export function tempStore() {
return {
viewsPositionStore,
navMenuItemsPositionStore,
};
}