Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ijlee2/ember-codemod-args-to-signature

Codemod to convert component Args to Signature
https://github.com/ijlee2/ember-codemod-args-to-signature

codemod ember-codemod emberjs embroider glint typescript

Last synced: 13 days ago
JSON representation

Codemod to convert component Args to Signature

Awesome Lists containing this project

README

        

[![This project uses GitHub Actions for continuous integration.](https://github.com/ijlee2/ember-codemod-args-to-signature/actions/workflows/CI.yml/badge.svg)](https://github.com/ijlee2/ember-codemod-args-to-signature/actions/workflows/CI.yml)

# ember-codemod-args-to-signature

_Codemod to convert component `Args` to `Signature`_1

1. Components without `Args` are also supported.

## What is it?

To introduce Glint, you will need to write the [signature](https://typed-ember.gitbook.io/glint/environments/ember/component-signatures) and [template registry](https://typed-ember.gitbook.io/glint/environments/ember/template-registry) for each component. This can be an error-prone, onerous task for large projects.

You can run this codemod to automate the required change.

## Features

- Scaffolds signature for components
- Adds template registry for components
- Preserves your code whenever possible
- Focuses on maintainability and extensibility



A code diff to show what template-only components can look like before and after running ember-codemod-args-to-signature


Template-only components





A code diff to show what Glimmer components can look like before and after running ember-codemod-args-to-signature
Another code diff for a Glimmer component


Glimmer components

## Usage

Step 1. Quickly migrate.

```sh
cd
npx ember-codemod-args-to-signature
```

Step 2. Review the package.

- [x] Fill in missing type information.
- [x] Confirm that you can run all scripts in `package.json`.

For more information, please check the [FAQ](#frequently-asked-questions).

### Prerequisites

Must:

- Migrate to the Octane layout (flat or nested). You can leverage the codemods for [classic](https://github.com/ember-codemods/ember-component-template-colocation-migrator) and [pod](https://github.com/ijlee2/ember-codemod-pod-to-octane) layouts.
- If you have component classes written in JavaScript, change the file extension to `*.ts` to allow the codemod to add `Signature` and `Registry`.

Nice to do:

- Refactor code (e.g. Glimmerize components, meet the linting rule `no-implicit-this`) to help the codemod parse code.

### Arguments

You must pass `--src` to indicate the location of your components.

```sh
# Apps
npx ember-codemod-args-to-signature --src app/components

# V1 addons
npx ember-codemod-args-to-signature --src addon/components

# V2 addons
npx ember-codemod-args-to-signature --src src/components
```

Optional: Specify the component structure

By default, an Octane project has the flat component structure. Pass `--component-structure` to indicate otherwise.

```sh
npx ember-codemod-args-to-signature --component-structure nested
```

Optional: Specify the project root

Pass `--root` to run the codemod on a project somewhere else (i.e. not in the current directory).

```sh
npx ember-codemod-args-to-signature --root
```

### Limitations

The codemod is designed to cover typical cases. It is not designed to cover one-off cases. (Classic components are not supported.)

To better meet your needs, consider cloning the repo and running the codemod locally.

```sh
cd

# Compile TypeScript
pnpm build

# Run codemod
./dist/bin/ember-codemod-args-to-signature.js --root
```

## Frequently asked questions

How can I introduce Glint incrementally?

In a small project, we may go ahead with replacing `tsc --noEmit`, the default command for `lint:types` that is set by `ember-cli`, with the command `glint`.

```diff
/* package.json */
{
"scripts": {
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
"lint:js": "eslint . --cache",
"lint:js:fix": "eslint . --fix",
- "lint:types": "tsc --noEmit"
+ "lint:types": "glint"
}
}
```

However, in a large project (e.g. a monorepo with many packages), we will want to introduce Glint and fix incorrect types incrementally. A divide-and-conquer strategy will help you parallelize work, make smaller pull requests, and help others avoid merge conflicts.

So, instead, create a script called `_lint:glint`. This script helps you check if Glint is set up right and which errors exist already. The underscore also prevents the `lint` script from running Glint in continuous integration (since the command `glint` will likely fail at first).

```diff
/* package.json */
{
"scripts": {
+ "_lint:glint": "glint",
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
"lint:js": "eslint . --cache",
"lint:js:fix": "eslint . --fix",
"lint:types": "tsc --noEmit"
}
}
```

After you have fixed all type errors in the package, you can remove `_lint:glint` and use `lint:types` to run `glint`.

```diff
/* package.json */
{
"scripts": {
- "_lint:glint": "glint",
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
"lint:js": "eslint . --cache",
"lint:js:fix": "eslint . --fix",
- "lint:types": "tsc --noEmit"
+ "lint:types": "glint"
}
}
```

Passing a signature to templateOnlyComponent() caused a type error with the message, Expected 0 type arguments, but got 1.. What should I do?

Likely, your project relies on `ember-source@v3` and `@types/ember__component@v3`.

Unfortunately, [`@types/ember__component@v3`](https://www.npmjs.com/package/@types/ember__component/v/3.16.6?activeTab=code) doesn't allow passing the signature to `templateOnlyComponent()` (we can see this from the file named `template-only.d.ts`), while [`@types/ember__component@v4`](https://www.npmjs.com/package/@types/ember__component/v/4.0.14?activeTab=code) does. Updating the package to `v4` isn't a viable option when you aren't on `ember-source@v4`.

Until you can update `ember-source`, I can provide three (3) fixes to temporarily address the type error. Each approach has pros and cons.

1. Don't pass the signature to `templateOnlyComponent()`, but keep the signature in the file for reference.

```diff
import templateOnlyComponent from '@ember/component/template-only';

+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
interface NavigationMenuSignature {
// ...
}

- const NavigationMenuComponent = templateOnlyComponent();
+ const NavigationMenuComponent = templateOnlyComponent();

export default NavigationMenuComponent;
```

This will help you focus on updating import paths and fixing formatting issues, e.g. by running the scripts `lint:types`, `lint:js:fix`, and `lint:js`.

The downsides? Assuming the [`@glint-ignore` directive](https://typed-ember.gitbook.io/glint/using-glint/directives#glint-ignore) is not used, the `glint` command (the `_lint:glint` script) can never pass, since template-only components don't provide a signature. Because the signature is missing, `ember-codemod-args-to-signature` will create an extra `Signature` if you run the codemod again.

2. Create an empty backing class.

```diff
- import templateOnlyComponent from '@ember/component/template-only';
+ import Component from '@glimmer/component';

interface NavigationMenuSignature {
// ...
}

- const NavigationMenuComponent = templateOnlyComponent();

- export default NavigationMenuComponent;
+ export default class NavigationMenuComponent extends Component {}
```

The `glint` command can now pass potentially. However, the components are no longer template-only. This might be a concern if maintaining a high performance is a factor.

3. Patch `@types/ember__component@v3`.

If you have experience with patching dependencies, you can patch the file `template-only.d.ts` so that its code matches that from `@types/ember__component@v4`. Note, there may be multiple files of `template-only.d.ts` that you will need to patch.

The `glint` command can pass potentially and the components remain template-only. However, it's unclear if there are files in `ember-source@v3` that assume `template-only.d.ts` to provide types in the way that it does in `v3`.

## Compatibility

- Node.js v18 or above

## Contributing

See the [Contributing](CONTRIBUTING.md) guide for details.

If you have an open-sourced project that I can use for testing, reach out to me on [Discord](https://discord.gg/emberjs) at `ijlee2`. Please star this project so that I can gauge its importance to you and the Ember community. ⭐

## License

This project is licensed under the [MIT License](LICENSE.md).