Skip to main content

๐Ÿงฉ 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! ๐Ÿ˜‰