Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
dist
.DS_Store
bun.lockb
tester/
bun.lockb
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ To run locally:

```sh
pnpm i
pnpm run dev
pnpm run build

npm install -g . (in a second terminal - this will then make kirimase available across your machine using "kirimase *command*")
```
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "npx tsc",
"build": "npx tsc && rm -rf dist/templates && cp -r src/templates dist/templates",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if there is a better way to do this, but I figured this is at least a quick and dirty way to pull templates into the dist folder.

Copy link

@OmegaHawkeye OmegaHawkeye Mar 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally used a npm package called typescript-cp for it and then just using the watch flag in dev and without it when building it.

Edit: I'm also using npm-run-all to run the dev scripts in parallel. I dont like concurrently so I used npm-run-all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌

"reinstall": "bun run build && npm i -g .",
"createTesterApp": "rm -rf tester/ && bunx create-next-app tester && cd tester/ && kirimase init",
"dev2": "node dist/index.js",
"dev": "tsc -w"
},
Expand All @@ -29,6 +31,7 @@
"chalk": "^5.3.0",
"commander": "^11.0.0",
"consola": "^3.2.3",
"eta": "^3.2.0",
"execa": "^8.0.1",
"figlet": "^1.7.0",
"ora": "^8.0.1",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

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

14 changes: 14 additions & 0 deletions src/commands/add/componentLib/shadcn-ui/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { consola } from "consola";
// import { execa } from "execa";
import { existsSync } from "fs";
import { eta } from "../../../../eta.js";
import {
addPackageToConfig,
createFile,
Expand Down Expand Up @@ -47,6 +48,7 @@ const manualInstallShadCn = async (

addToInstallList({
regular: [
"@tanstack/react-table",
"tailwindcss-animate",
"class-variance-authority",
"clsx",
Expand Down Expand Up @@ -85,6 +87,16 @@ const manualInstallShadCn = async (
rootPath.concat("components/ui/ThemeToggle.tsx"),
generateThemeToggler()
);

// generate base Data Table
createFile(
rootPath.concat("components/ui/DataTable/index.tsx"),
eta.render("DataTable/index.eta", {})
);
createFile(
rootPath.concat("components/ui/DataTable/pagination.tsx"),
eta.render("DataTable/pagination.eta", {})
);
// add context provider to layout
addContextProviderToRootLayout("ThemeProvider");
};
Expand Down Expand Up @@ -131,6 +143,8 @@ export const installShadcnUI = async (
// "label",
// ]);
addToShadcnComponentList([
"table",
"pagination",
"button",
"sonner",
"avatar",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/add/orm/drizzle/generators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ export const addScriptsToPackageJson = (
"db:migrate": `tsx ${libPath}/db/migrate.ts`,
"db:drop": "drizzle-kit drop",
"db:pull": `drizzle-kit introspect:${driver}`,
...(driver !== "pg" ? { "db:push": `drizzle-kit push:${driver}` } : {}),
"db:push": `drizzle-kit push:${driver}`,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the guardrails around db:push for pg, now that it's supported.

"db:studio": "drizzle-kit studio",
"db:check": `drizzle-kit check:${driver}`,
};
Expand Down
1 change: 0 additions & 1 deletion src/commands/add/orm/drizzle/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ ${nanoidContent.split("\n")[1].trim()}
replaceFile(utilsPath, newContent);
}
};

export const checkTimestampsInUtils = () => {
const timestampsContent = `export const timestamps: { createdAt: true; updatedAt: true } = {
createdAt: true,
Expand Down
27 changes: 13 additions & 14 deletions src/commands/generate/generators/views-with-server-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { formatTableName, toCamelCase } from "../utils.js";
import { existsSync, readFileSync } from "fs";
import { consola } from "consola";
import { addToShadcnComponentList } from "../../add/utils.js";
import eta from "../../../eta.js";

export const scaffoldViewsAndComponentsWithServerActions = async (
schema: ExtendedSchema
Expand Down Expand Up @@ -80,6 +81,15 @@ export const scaffoldViewsAndComponentsWithServerActions = async (
createListComponent(schema)
);

// create columns
createFile(
formatFilePath(
`app/(app)/${tableNameKebabCase}/columns.tsx`,
{ prefix: "rootPath", removeExtension: false }
),
eta.render('DataTable/columns.eta', { fields: schema.fields, tableNameKebabCase })
);

// create components/tableName/TableNameForm.tsx
createFile(
formatFilePath(
Expand Down Expand Up @@ -251,7 +261,8 @@ const generateView = (schema: Schema) => {
const relationsFormatted = formatRelations(relations);

return `import { Suspense } from "react";

import { DataTable } from "${formatFilePath(`components/ui/DataTable`, {prefix: "alias", removeExtension: false})}";
import { columns } from "./columns";
import Loading from "${formatFilePath("app/loading", {
prefix: "alias",
removeExtension: false,
Expand Down Expand Up @@ -313,6 +324,7 @@ const ${tableNameCapitalised} = async () => {
.join(" ")
: ""
} />
<DataTable data={${tableNameCamelCase}} columns={columns} />
</Suspense>
);
};
Expand Down Expand Up @@ -469,19 +481,6 @@ export default function ${tableNameSingularCapitalised}List({
+
</Button>
</div>
{optimistic${tableNamePluralCapitalised}.length === 0 ? (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this list since it's taken care of by the table

<EmptyState openModal={openModal} />
) : (
<ul>
{optimistic${tableNamePluralCapitalised}.map((${tableNameSingular}) => (
<${tableNameSingularCapitalised}
${tableNameSingular}={${tableNameSingular}}
key={${entityName}.id}
openModal={openModal}
/>
))}
</ul>
)}
</div>
);
}
Expand Down
61 changes: 58 additions & 3 deletions src/commands/generate/generators/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ import {
toCamelCase,
toNormalEnglish,
} from "../utils.js";
import fs from 'fs';
import { addToShadcnComponentList } from "../../add/utils.js";
import eta from "../../../eta.js";

export const scaffoldViewsAndComponents = async (schema: Schema) => {
const { hasSrc, packages } = readConfigFile();
const {
tableNameCamelCase,
tableNameSingularCapitalised,
tableNameSingular,
tableNameKebabCase,
} = formatTableName(schema.tableName);
// require trpc for these views
Expand All @@ -32,20 +35,34 @@ export const scaffoldViewsAndComponents = async (schema: Schema) => {
rootPath.concat(`app/(app)/${tableNameKebabCase}/page.tsx`),
generateView(schema)
);

// create tableName/[id]/page.tsx
createFile(
formatFilePath(
`app/(app)/${tableNameKebabCase}/[${tableNameSingular}Id]/page.tsx`,
{ removeExtension: false, prefix: "rootPath" }
),
createShowPage(schema)
);
// create components/tableName/TableNameList.tsx
createFile(
rootPath.concat(
`components/${tableNameCamelCase}/${tableNameSingularCapitalised}List.tsx`
),
),
createListComponent(schema)
);
);
// create components/tableName/TableNameForm.tsx
createFile(
rootPath.concat(
`components/${tableNameCamelCase}/${tableNameSingularCapitalised}Form.tsx`
),
createFormComponent(schema)
);
// create components/tableName/columns.tsx
createFile(
rootPath.concat(`components/${tableNameCamelCase}/columns.tsx`),
eta.render('DataTable/columns.eta', { fields: schema.fields, tableNameKebabCase })
);
// create components/tableName/TableNameModal.tsx
createFile(
rootPath.concat(
Expand Down Expand Up @@ -101,6 +118,8 @@ import { api } from "${formatFilePath(trpc.trpcApiTs, {
})}";`
: ""
}
import { DataTable } from "${alias}/components/ui/DataTable";
import { columns } from "${alias}/components/${tableNameCamelCase}/columns";

export default async function ${tableNameCapitalised}() {
${
Expand All @@ -113,13 +132,49 @@ export default async function ${tableNameCapitalised}() {
<h1 className="font-semibold text-2xl my-2">${tableNameNormalEnglishCapitalised}</h1>
<New${tableNameSingularCapitalised}Modal />
</div>
<${tableNameSingularCapitalised}List ${tableNameCamelCase}={${tableNameCamelCase}} />
<DataTable data={${tableNameCamelCase}} columns={columns} />
</main>
);
}
`;
};

const createShowPage = (schema: Schema) => {
const {
tableNameCamelCase,
tableNameSingularCapitalised,
tableNameKebabCase,
tableNameSingular,
tableNameNormalEnglishCapitalised,
} = formatTableName(schema.tableName);
const { trpc } = getFilePaths();
const { alias } = readConfigFile();
const trpcRoute = formatFilePath(trpc.trpcApiTs, {
prefix: "alias",
removeExtension: true,
})
const { fields } = schema;
if (!fs.existsSync(`src/compononents/ui/breadcrumbs.tsx`)) {
createFile(
`src/components/ui/breadcrumbs.tsx`,
eta.render('components/ui/breadcrumbs.eta', {})
)
}

return eta.render(
'resources/show.eta', {
fields,
tableNameSingular,
tableNameSingularCapitalised,
tableNameCamelCase,
tableNameKebabCase,
tableNameNormalEnglishCapitalised,
alias,
trpcRoute
}
)
}

const queryHasJoins = (tableName: string) => {
// const { hasSrc } = readConfigFile();
const { shared } = getFilePaths();
Expand Down
2 changes: 1 addition & 1 deletion src/commands/init/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,4 @@ export const toggleAnalytics = (input: { toggle?: boolean }) => {
`Anonymous analytics are currently ${analytics ? "on" : "off"}`
);
}
};
};
9 changes: 9 additions & 0 deletions src/eta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Eta } from "eta"
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export const eta = new Eta({ views: path.join(__dirname, "templates") });
export default eta;
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ addCommonOptions(program.command("init"))

program
.command("generate")
.alias("g")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alias 😎

.description("Generate a new resource")
.action(buildSchema);

Expand Down
54 changes: 54 additions & 0 deletions src/templates/DataTable/columns.eta
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use client"
import { MoreHorizontal } from "lucide-react"
import {
ColumnDef,
} from "@tanstack/react-table"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { Button } from "@/components/ui/button"
import Link from 'next/link'

export const columns: ColumnDef<TData, TValue>[] = [
<% it.fields.map(function (field) { %>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

templating in action

{
accessorKey: "<%_ = field.name _%>",
header: "<%_ = field.name _%>",
enableHiding: false,
cell: ({ row }) => {
const resource = row.original
return (
<Link href={`/<%= it.tableNameKebabCase %>/${resource.id}`}>
{resource.<%_ = field.name _%>}
</Link>
)
},
},
<% }) %>
{
id: "actions",
enableHiding: false,
cell: ({ row }) => {
const resource = row.original
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="square-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="square-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
},
},
]
Loading