import _locreq from "locreq"; import { escape_url_params } from "./utils/escape-url-params.js"; import prompts from "prompts"; import { toKebabCase, toPascalCase } from "js-convert-case"; import { listCollections } from "./utils/list-collections.js"; import { collectionListTemplate } from "./templates/shared/collection-list.js"; import { writeFile } from "./utils/write-file.js"; import { curryImportPath, importPath } from "./utils/import-path.js"; import { sharedCrudFormFields } from "./templates/shared/shared-crud-form-fields.js"; import { generateRoutes } from "./generate-routes.js"; import { createItemFormTemplate } from "./templates/shared/collection-create-form.js"; import { editItemFormTemplate } from "./templates/shared/collection-edit-form.js"; import { itemDeleteTemplate } from "./templates/shared/item-delete.js"; export async function addCRUD( params: Partial<{ [key in "collection" | "url"]: string }>, app_directory: string = process.cwd() ) { const target_locreq = _locreq(app_directory); prompts.override(params); const response = await prompts([ { type: "autocomplete", name: "collection", message: "Which sealious collection do you like to add CRUD forms for?", choices: (await listCollections()).map((collection) => ({ title: collection, value: collection, })), }, { type: "text", name: "url", message: "Enter a full absolute path for the new route (for example: /admin/users/:id/edit): ", validate: (s: string) => s.trim()[0] == "/" ? true : "Should start with a '/'", initial: function (_, { collection }: { collection: string }) { return "/" + toKebabCase(collection); }, }, ]); const collection_name = response.collection as string; const url = response.url as string; const list_action_name = toPascalCase(collection_name) + "CRUDList"; const create_action_name = toPascalCase(collection_name) + "CRUDCreate"; const edit_action_name = toPascalCase(collection_name) + "CRUDEdit"; const delete_action_name = toPascalCase(collection_name) + "CRUDDelete"; /* create the list endpoint */ const list_path = target_locreq.resolve( `src/back/routes/${escape_url_params(url)}/index.list.tsx` ); const list_content = await collectionListTemplate( collection_name, list_action_name, list_path, { post_import_js: `import { ${create_action_name}URL, ${edit_action_name}URL, ${delete_action_name}URL } from "${importPath( list_path, "src/back/routes/urls.ts" )}";`, post_header_html: ` Create `, render_item: ( collection_name: string ) => ` async renderItem(ctx: Context, item: CollectionItem) { return {displayFields.map(({ field, format }) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any const value = item.get(field as any); return {format ? format(value, item) : value}; })}
Edit Delete
; }`, } ); await writeFile(list_path, list_content); /* create the shared fields file */ const fields_path = target_locreq.resolve( `src/back/routes/${escape_url_params(url)}/shared.ts` ); const fields_content = await sharedCrudFormFields(collection_name); await writeFile(fields_path, fields_content); /* create the create endpoint */ const create_path = target_locreq.resolve( `src/back/routes/${escape_url_params(url)}/create.form.ts` ); const create_content = await createItemFormTemplate( create_action_name, create_path, collection_name, list_action_name ); await writeFile(create_path, create_content); /* create the edit endpoint */ const edit_path = target_locreq.resolve( `src/back/routes/${escape_url_params(url)}/[id]/edit.form.ts` ); const edit_content = await editItemFormTemplate( edit_action_name, edit_path, collection_name, list_action_name ); await writeFile(edit_path, edit_content); /* create the actual delete endpoint */ const delete_path = target_locreq.resolve( `src/back/routes/${escape_url_params(url)}/[id]/delete.page.tsx` ); const base_import_path = curryImportPath(delete_path); const delete_content = await itemDeleteTemplate( delete_action_name, collection_name, list_action_name, base_import_path ); await writeFile(delete_path, delete_content); await generateRoutes(); }