๐งฉ aim33 CLI
With this feature, you can develop your own code generation tool, perfectly adapted to your project.
๐ Getting Startedโ
Visit the GitHub repository for aim33-cli or clone the repo via SSH: git@github.com:bamlab/aim33-cli.git
Follow the readme at the root of the project.
๐ค What Can You Do with This Tool?โ
๐ Launch a suite of generations in one time for repetitive tasksโ
If you have repetitive tasks in your project that require several steps, this tool can help automate those steps via templates. Each step is represented by a template and executed sequentially.
Simply store the templates in .md files at the root of your project in a aim33/templates folder. Once they are ready, launch aim33 in your terminal and press 's' to select the template suite option to generate the files.
If your template suite doesn't completely match your current use case, you can select individual templates during the template selection step.
๐ For example, in our project, for each API call, we need to create a schema, an API file, a hook, and fixtures. We created four templates for this purpose. Here is what they look like:
Schema Template
# Context
You are a React Native expert developer. You are currently developing the schema which will be used to define the type used in an api call. Do not make any comment in the code.
# Instructions
You focus here on the schema and the type definition
First, you need to use zod.object or zod.array depending on the type of the answer to create the schema of the answer in a .schema.ts file
Then, in the same generation, in a .types.ts file, you need to create a type corresponding to the schema with infer.
You can take inspiration from shipmentOverviewSchema/shimpentOverviewTypes or searchShipmentSchema/searchShipmentTypes if you want.
# Architecture
Create the schema file src/modules/[module]/features/[feature]/domain/[routeObjectName].schema.ts
Create the types file src/modules/[module]/features/[feature]/domain/[routeObjectName].types.ts
Where feature is the name of the feature associated to the api call and routeObjectName is a description of the object which is fetched or sent
# Technical Strategy
API Template
# Context
You are a React Native expert developer. You are currently developing the api file to call a route
# Instructions
You focus here on the .api file specifically, it calls the route with the right parameters and handle the errors.
The schema and the types corresponding to the route have already been created. You must use them here.
In order to create this api file, you must, in a try catch
- call the specified route using unauthenticatedHttpClient
- parse the data using the corresponding schema
- return the data parsed
If an error occured (so in the catch) :
- use the Logger service to display the erorr
- throw the error
You can take searchShipment.api.ts or shipmentOverview.api.ts as examples
# Architecture
Create the api file in src/modules/[module]/features/[feature]/infra/[routeObjectName].api.ts
Where feature is the name of the feature associated to the api call and routeObjectName is a description of the object which is fetched or sent
# Technical Strategy
Hook Template
# Context
You are a React Native expert developer. You are currently developing the hook which will handle the logic of an api call.
The schema, types and api files have already been created. You need to use them.
# Instructions
So here you focus on the hook creation. This hook named use[routeObjectName]Query.ts uses useSuspenseQuery with a query key and a call to the api file as a query fn. It returns the query.
You can take useShipmentOverviewQuery and useSearchShipmentQuery as inspiration
# Architecture
Create the api file in src/modules/[module]/features/[feature]/infra/use[routeObjectName]Query.ts
Where feature is the name of the feature associated to the api call and routeObjectName is a description of the object which is fetched or sent
# Technical Strategy
Fixtures Template
# Context
You are a React Native expert developer. You are currently developing the fixtures which will represent the api calls in tests.
# Instructions
The schema, types, api file and hook have already been created, you only need to create fixtures here with the right type of object. You can take a look at shipmentOverviewFixtures or searchShipmentFixtures as inspiration.
# Architecture
Create the fixtures file in src/modules/[module]/features/[feature]/domain/[routeObjectName].fixtures.ts
Where feature is the name of the feature associated to the api call and routeObjectName is a description of the object which is fetched or sent
# Technical Strategy
๐ฃ๏ธ Generate code for specific tasksโ
If you encounter occasional tasks where AI can assist, you can also generate code from a technical strategy without a template.
To do this, launch aim33 in your terminal and press 'a' to select the technical strategy option.
We recommend using this for tasks that typically represent one commit (approximately one or two files, one action).
Here are examples of prompts executed to generate code for different tasks:
Handle a New Option in a Screen: Add Status and Update UI
In GoodsItem:
Add a possible status โUnexpectedโ Display the name of the unexpected goods in white with a mention โUnexpectedโ below (don't forget the translations and take inspiration from what is done for other statuses) In the modal, when the item is Unexpected, add a link warning โRemove itโ (with translations) that does nothing for now
Add Translations for Displayed Strings
In GoodsItem, add translations for the labels of the links in the modal.
Add a Function in a Store: Implement Removal Logic
In GoodsStore, add a function removeHandlingUnit that removes a good from the store (take inspiration from setHandlingUnitStatus).
Add a Modal: UI Using Existing Components
In GoodsItem, on clicking โRemove itโ, display a modal (use GenericModal) with:
- ExclamationTriangleOutline as the topIcon in white,
- a title โRemove a Goodโ,
- a message โYou are about to remove the good ${goodBarcode}โ,
- an onCancel โkeep itโ that closes the modal,
- an onConfirm โRemove itโ that removes the good using the removeHandlingUnit function from GoodsStore.
Refactor: Extract a Component
In GoodsItem, extract the BottomSheet, the Modal, and all the status management that goes with it into a component GoodsItemBottomSheet. I expect you to generate both. the updated GoodsItem and the new component in the same generation
Refactor: Extract Hooks from a Component
Can you extract all the hooks called in CameraScanSection in a general hook useCameraScanSection that is called in the component to get all the values necessary for the render. You must generate both the hook and the updated component.
โน๏ธ When extracting components, adding "You must generate both the extracted lines and the updated component" usually ensures better results.
โน ๏ธ Sometimes, letting the tool guide itself without too much direction might yield better results, as it may have better practices in mind.
Fix TypeScript Errors
Can you fix all these typescript errors for the declareHandlingUnits connector? (see GoodsStore and handlingUnits.types for the types definition)
โโโ src/modules/declaration/goods/handlingUnits/infra/uploadPhotosAndDeclareHandlingUnit.connector.ts:18:40 - error TS2339: Property 'photos' does not exist on type 'GoodStatus'. Property 'photos' does not exist on type ${ status: "compliant"; justification: "compliant"; }. 18 if (handlingUnit.declaredStatus?.photos)
src/modules/declaration/goods/handlingUnits/infra/uploadPhotosAndDeclareHandlingUnit.connector.ts:20:47 - error TS2339: Property 'photos' does not exist on type 'GoodStatus'. Property 'photos' does not exist on type '${ status: "compliant"; justification: "compliant"; }'.
20 photos: handlingUnit.declaredStatus.photos,
src/modules/declaration/goods/handlingUnits/infra/uploadPhotosAndDeclareHandlingUnit.connector.ts:25:66 - error TS2339: Property 'photos' does not exist on type 'GoodStatus'. Property 'photos' does not exist on type '${ status: "compliant"; justification: "compliant"; }'. 25 backendPhotosId.length !== handlingUnit.declaredStatus.photos.length
src/modules/declaration/goods/handlingUnits/infra/uploadPhotosAndDeclareHandlingUnit.connector.ts:35:37 - error TS2339: Property 'photos' does not exist on type 'GoodStatus'. Property 'photos' does not exist on type '${ status: "compliant"; justification: "compliant"; }'.
35 handlingUnit.declaredStatus.photos.forEach((photo, index) => ${
src/modules/declaration/goods/handlingUnits/infra/uploadPhotosAndDeclareHandlingUnit.connector.ts:35:53 - error TS7006: Parameter 'photo' implicitly has an 'any' type. 35 handlingUnit.declaredStatus.photos.forEach((photo, index) => ${
src/modules/declaration/goods/handlingUnits/infra/uploadPhotosAndDeclareHandlingUnit.connector.ts:35:60 - error TS7006: Parameter 'index' implicitly has an 'any' type.
35 handlingUnit.declaredStatus.photos.forEach((photo, index) => ${
Found 6 errors in the same file, starting at: src/modules/declaration/goods/handlingUnits/infra/uploadPhotosAndDeclareHandlingUnit.connector.ts:18 โโโ
Other possibilities recommended by chatGPT :
- Generate Unit tests
- Generate API endpoints
- Generate Documentation
- Implement Error Handling
- Refactor Code for Performance
๐ง๐ปโ๐ซ Customize the Knowledge of Your Toolโ
Some information is useful for the tool to know regardless of what it is generating. For example, how to implement translations, type functions, or write basic tests. To avoid repeating this information in each prompt, you can create a pre-prompt file that is automatically given to the tool every time.
Create a pre-prompt.md file in your aim33 folder at the root of your project and add the necessary information.
Here is an example of a pre-prompt:
Details
You are a senior React Native developer with 20 years of experience. Your goal is to help me develop features given files as examples, files to modify, and a technical strategy.
Include all the necessary code in the files you generate, no shortcuts, even for code you did not change. Use absolute paths to avoid confusion.
Translate all displayed strings (except logged errors). If you find untranslated strings in the existing code, please fix them.
To implement translations, import ${ t } from "@linqui/macro" and useLingui from "@lingui/react". The translations look like this:
const { _ } = useLingui();
_(
t({
id: "id.of.the.message",
message: "Content of the message",
context: "Context of the message",
})
);
You work in a TypeScript environment, so always type functions' and components' props. Avoid using the type "any" as much as possible.
Start with this example and modify it to fit your needs.
๐ Create Your Own Toolsโ
We made this CLI easy to modify; you have access to everything.
You can modify:
- The prompts used
- The files sent
- The templates
- The context given
- Everything else
You can add steps, remove others, and customize it to fit your needs. Feel free to suggest PRs to improve the tool for everyone.
For feedback, contact MatthieuBe, EricM, or SarahG on Slack. Thanks for your help! ๐