angularjs-to-angular
Migrate an AngularJS codebase to an Angular codebase
Example
constants:
angular_directory: 'angular'
src_directory: '{{ angular_directory }}/src'
app_directory: '{{ src_directory }}/app'
assets_directory: '{{ src_directory }}/assets'
entry_file_path: '{{ src_directory }}/main.ts'
components_directory: '{{ app_directory }}/components'
services_directory: '{{ app_directory }}/services'
directives_directory: '{{ app_directory }}/directives'
pipes_directory: '{{ app_directory }}/pipes'
modules_directory: '{{ app_directory }}/modules'
context_depth: 3
libraries_to_install:
- 'rxjs'
- '@angular/router'
- '@angular/forms'
- '@angular/common'
- '@angular/platform-browser'
- '@angular/platform-browser-dynamic'
library_mappings: |
- All `$http` and `$httpProvider` usages should be converted/replaced with `HttpClient` from `@angular/common/http`.
- All `$location` usages should be converted/replaced with Angular's `Router`.
- All `$scope` usages should be converted/replaced with component properties and Angular's data binding.
- All `ng-model` usages should be converted/replaced with `[(ngModel)]` for two-way data binding.
- All `ng-repeat` usages should be converted/replaced with `*ngFor` directive.
- All `ng-if` usages should be converted/replaced with `*ngIf` directive.
- All `ng-show` and `ng-hide` usages should be converted/replaced with `*ngIf` or `[hidden]` property binding.
- All `ng-class` usages should be converted/replaced with `[ngClass]` directive.
- All `angular-aria` usages should be handled with Angular's built-in accessibility features.
- All `angular-loader` usages should be converted/replaced with Angular's lazy loading modules.
- All `angular-messages` usages should be converted/replaced with Angular's form validation features.
- All `angular-resource` usages should be converted/replaced with `HttpClient`.
- All `angular-route` usages should be converted/replaced with `@angular/router`.
- All `angular-touch` usages should be converted/replaced with Angular's event handling.
transformation_notes: |
## Codebase Transformation Notes
### Generation Preferences
When generating code, follow these guidelines:
- Only include information from the portion you were told to convert.
- Do not create new configs, components, or example usages.
- Remove AngularJS-specific elements that cannot be converted to Angular.
- Leave empty functions as they are.
- If the current file path was provided above, you should ensure that the import paths are relative to this path.
- At the top of the converted file, you should include a comment with the original file path. Something like `// Converted from <original-file-path>`.
- The resulting code should be DRY and only declare one component per file.
- The resulting code should be written in TypeScript.
- You should always define and export classes or functions as appropriate.
- Prefer Angular's dependency injection and service mechanisms.
- Do not hallucinate!
### AngularJS to Angular Conversion Guidelines
- AngularJS `ng-` directives should be converted to the Angular-equivalent logic. Do not leave these in the template.
- Special built-in AngularJS services and factories, typically defined as `$<service-name>`, should be converted to Angular-equivalent logic.
- AngularJS injectors are no longer needed in Angular (since Angular uses its own dependency injection mechanism).
### New Files
When defining new files based on unconverted files, assume the following naming strategies (useful for imports):
- AngularJS constants and values → TypeScript constants or services in `{{ services_directory }}/<constant-name>.ts`.
- AngularJS services, factories, and providers → Angular services in `{{ services_directory }}/<current-file-name>.service.ts`. Each service should be decorated with `@Injectable()` and properly provided in modules.
- AngularJS directives → Angular directives or components in `{{ directives_directory }}/<current-file-name>.directive.ts` or components in `{{ components_directory }}/<current-file-name>/<current-file-name>.component.ts`.
- AngularJS filters → Angular pipes in `{{ pipes_directory }}/<current-file-name>.pipe.ts`.
- AngularJS controllers and template HTML files → Angular components in `{{ components_directory }}/<current-file-name>/<current-file-name>.component.ts` and the template HTML in `{{ components_directory }}/<current-file-name>/<current-file-name>.component.html`.
- AngularJS config and routes → Angular modules and routing modules in `{{ modules_directory }}/<current-file-name>.module.ts`.
### Libraries
The following libraries are already installed in the project and available for you to use (in addition to the default Angular libraries): {{ libraries_to_install }}
#### Mapping AngularJS libraries to Angular-compatible libraries:
{{ library_mappings }}
ignore_file_paths:
- 'gulpfile.js'
- 'LICENSE'
- '**/test/**'
- 'test/**'
- 'package.json'
- '.gitignore'
- 'tsconfig.json'
- 'README.md'
- '**/{{ angular_directory }}'
- '**/{{ angular_directory }}/**'
- '*.config'
dependency_prompt: |
Acronym Key:
- SDIF: Symbol Defined In File
- SDE: Symbol Defined Externally
- MAP: Mapping
- HRC: HTML Reference Controller
You should find all SDIFs, SDEs, HRCs, and MAPs in the file. Below are some hints to help you determine usage, but also rely on your innate knowledge in case the usage is not explicitly stated below.
You only care about the high-level connections between files like definitions for factories, controllers, services, configs, etc., and their dependencies (declared in the brackets after the name of the Angular declaration type) as well as mappings of controllers to file paths.
Rules:
- If an AngularJS directive is declared in the template, you care about the value the directive is set to, not the directive itself. For example, if you have `ng-controller="ExampleCtrl as example"`, you should only care about `ExampleCtrl` and not `ng-controller`.
- If an AngularJS module is defined in this file, you should return the name of the module as one of the SDIF keys. If it is just used or added to with `.controller`, `.factory`, `.service`, etc., you should include it as an SDE key.
- You should ALWAYS ignore built-in special AngularJS functions, variables, and boilerplate like `$http`, `$timeout`, `.module`, `.controller`, etc.
- You should still include `$rootScope` definitions because it tells us where the global variables are defined.
- NEVER include standard library variables like `window.*` or `document.*`, `console.*`, etc., when looking for SDIFs or SDEs.
- When including nested objects, you should AT MOST include 1 level deep. For example, if you have `PageValue.page.title` and `PageValue.page.content`, you should only include `PageValue.page` once as a SDIF or SDE key, even though more deeply nested sub-fields may be present.
- `directives` defined in JS logic should be converted to kebab-case (e.g., `myDirective` → `my-directive`), then added as a key in either SDIF or SDE.
## MAP Example:
```
var routes = {
"example": {
controller: 'ExampleCtrl',
templateUrl: 'example.html'
}
};
```
- In the above case, in `routes.example`, the controller and template are mapped to each other where the template relies on the controller.
- Note that usages of variables, even if defined externally, would not be considered mappings. Mappings should only be used to allow us to map two files together and should NEVER include two symbol types.
- For now, mappings should ONLY be two paths or a symbol and a path. It should never be a symbol and a symbol.
## SDIF Example:
SDIFs are frequently defined in the controller, service, factory, constant, config, etc. Typically it would look something like `angular.module(...).controller(...);` where controller could be any of the valid AngularJS types.
```
angular.module('app').controller('ExampleCtrl', ['$scope', '$http', function($scope, $http) {
$scope.example = 'example';
$rootScope.exampleGlobal.example = 'example';
}]);
```
In the above case, the controller is `ExampleCtrl` and it is a SDIF, likely to be used in other parts of the application. `$scope` is used to represent local variables in the controller and therefore shouldn't be included. However, `$rootScope.exampleGlobal` should be included as an SDE under the key `$rootScope.exampleGlobal`.
## SDE Example:
SDEs are frequently USED in a controller, service, factory, constant, config, etc.
```
angular.module('app').controller('AnotherCtrl', ['$scope', '$http', function($scope, $http) {
if ($scope.example) {
// ...
}
}]);
```
In the above case, `$scope.example` should not be included in either SDE or SDIF because it is local only to this file and the template. In this case, though, `AnotherCtrl` would be returned as a SDIF, `module("app")` would also be included as an SDE.
## HRC Example:
```
<div ng-controller="someController as vm" ng-init="vm.getCurrentUser()">
...
</div>
```
- In the above case, the referenced controller is `someController`, and it is needed in the template.
- This controller should be seen before the template in the dependency graph.
Be greedy.
steps:
- name: Create Angular app
tools:
- name: run_terminal_command
arguments:
command: 'mkdir {{ angular_directory }}'
- name: run_terminal_command
arguments:
command: 'npx @angular/cli@latest new {{ angular_directory }}'
- name: Install target conversion libraries
tools:
- name: for_each
items: '{{ libraries_to_install }}'
each_item:
item_name: library
tools:
- name: run_terminal_command
arguments:
path_to_directory: '{{ angular_directory }}'
command: 'npm install {{ library }} --save'
- name: Update tsconfig to be stricter
tools:
- name: find_files_by_name_with_regex
arguments:
find_file_name_pattern: 'tsconfig\.json'
returns: tsconfig_file_paths
- name: get_first
arguments:
array: '{{ tsconfig_file_paths }}'
returns: tsconfig_file_path
- name: edit_json
arguments:
path_to_file: '{{ tsconfig_file_path }}'
json_path: 'compilerOptions'
action: 'add'
values:
- key: 'noUnusedLocals'
value: true
- key: 'noUnusedParameters'
value: true
- name: Build a dependency graph of the codebase
tools:
- name: build_dependency_graph_with_ai
arguments:
dependency_prompt: '{{ dependency_prompt }}'
exclude_path_patterns: '{{ ignore_file_paths }}'
- name: Convert files in order
tools:
- name: get_files_in_topological_order
arguments:
top_down: true
returns: conversion_order_by_level
- name: for_each
items: '{{ conversion_order_by_level }}'
each_item:
item_name: level
tools:
- name: async_each
items: '{{ level }}'
each_item:
item_name: file_to_convert
tools:
- name: get_content_from_file
arguments:
path_to_file: '{{ file_to_convert }}'
returns: file_contents
- name: get_file_long_context
arguments:
path_to_file: '{{ file_to_convert }}'
depth: '{{ context_depth }}'
graph_type: 'embedding'
returns: file_context
- name: get_file_name
arguments:
path_to_file: '{{ file_to_convert }}'
include_extension: false
returns: file_name
- name: switch
content: |
## {{ file_to_convert }}
```
{{ file_contents }}
```
cases:
- condition_prompt: Is this the root entry point either logic or template for the AngularJS app that should be put into the `main.ts` Angular file?
break: true
tools:
- name: chunk_prompt
arguments:
contents:
- priority: 3
content: '{{ file_context }}'
- priority: 2
content: |
AngularJS Code to convert to Angular ({{ file_to_convert }}):
```
{{ file_contents }}
```
- priority: 1
content: |
# Instructions
- Extract code from the AngularJS file that should be converted to Angular.
- Merge that code with the existing content in the file and write out the merged content.
- The only time you can fully replace code is if the code in `main.ts` is clearly the dummy text that was generated by Angular CLI.
- If the code already looks like it was converted from AngularJS, you should ensure all previous functionality remains along with the new logic that you will implement.
- Do not just concatenate converted parts together; you should rewrite so that the code is DRY without losing functionality.
- If there are no changes to make, return an empty code block (``````).
- The resulting code should be valid Angular code in TypeScript.
{{ transformation_notes }}
returns: chunked_prompts
- name: edit_file_long_context
arguments:
path_to_file: '{{ entry_file_path }}'
edit_prompts: '{{ chunked_prompts }}'
- name: mark_files_converted_in_context
arguments:
done_converting: false
old_file_path: '{{ file_to_convert }}'
new_file_paths:
- '{{ entry_file_path }}'
# Constants or Values
- condition_prompt: Does this file contain an AngularJS constant or value definition?
tools:
- name: find_content_in_file_with_ai
arguments:
path_to_file: '{{ file_to_convert }}'
find_context_prompt: 'Find and return JUST the name of each constant or value defined in the file. If there are none, return an empty array.'
results_as_array: true
returns: constant_or_value_names
- name: async_each
items: '{{ constant_or_value_names }}'
returns_key: constant_file_paths
each_item:
item_name: constant_or_value_name
tools:
- name: make_variable
arguments:
value: '{{ services_directory }}/{{ constant_or_value_name }}.ts'
returns: constant_file_path
- name: chunk_prompt
arguments:
contents:
- priority: 3
content: '{{ file_context }}'
- priority: 2
content: |
AngularJS Code ({{ file_to_convert }}):
```
{{ file_contents }}
```
- priority: 1
content: |
# Instructions
- Extract `{{ constant_or_value_name }}` from the above AngularJS code and convert it to a TypeScript constant or service for Angular.
- Only extract and convert `{{ constant_or_value_name }}` and its relevant information to make it work in Angular on its own. Ignore anything else.
- The resulting file will be created at {{ constant_file_path }}.
- Constants or services should be properly exported and can be imported and used in other files.
- Use appropriate Angular patterns and modules.
{{ transformation_notes }}
returns: chunked_prompts
- name: edit_file_long_context
arguments:
path_to_file: '{{ constant_file_path }}'
edit_prompts: '{{ chunked_prompts }}'
returns: file_paths
- name: mark_files_converted_in_context
arguments:
done_converting: false
old_file_path: '{{ file_to_convert }}'
new_file_paths: '{{ file_paths }}'
# Filters to Pipes
- condition_prompt: Does this file contain an AngularJS filter definition?
tools:
- name: find_content_in_file_with_ai
arguments:
path_to_file: '{{ file_to_convert }}'
find_context_prompt: 'Find and return JUST the name of each filter defined in the file. If there are none, return an empty array.'
results_as_array: true
returns: filter_names
- name: async_each
items: '{{ filter_names }}'
returns_key: pipe_file_paths
each_item:
item_name: filter_name
tools:
- name: make_variable
arguments:
value: '{{ pipes_directory }}/{{ filter_name }}.pipe.ts'
returns: pipe_file_path
- name: chunk_prompt
arguments:
contents:
- priority: 3
content: '{{ file_context }}'
- priority: 2
content: |
AngularJS Code ({{ file_to_convert }}):
```
{{ file_contents }}
```
- priority: 1
content: |
# Instructions
- Extract `{{ filter_name }}` from the above AngularJS code and convert it to an Angular pipe.
- Only extract and convert `{{ filter_name }}` and its relevant information to make it work in Angular on its own. Ignore anything else.
- The resulting file will be created at {{ pipe_file_path }}.
- Pipes should be properly decorated with `@Pipe` and exported.
{{ transformation_notes }}
returns: chunked_prompts
- name: edit_file_long_context
arguments:
path_to_file: '{{ pipe_file_path }}'
edit_prompts: '{{ chunked_prompts }}'
returns: file_paths
- name: mark_files_converted_in_context
arguments:
done_converting: false
old_file_path: '{{ file_to_convert }}'
new_file_paths: '{{ file_paths }}'
# Services
- condition_prompt: Does this file contain an AngularJS service definition?
tools:
- name: find_content_in_file_with_ai
arguments:
path_to_file: '{{ file_to_convert }}'
find_context_prompt: 'Find and return JUST the name of each service defined in the file. If there are none, return an empty array.'
results_as_array: true
returns: service_names
- name: async_each
items: '{{ service_names }}'
returns_key: service_file_paths
each_item:
item_name: service_name
tools:
- name: make_variable
arguments:
value: '{{ services_directory }}/{{ service_name }}.service.ts'
returns: service_file_path
- name: chunk_prompt
arguments:
contents:
- priority: 3
content: '{{ file_context }}'
- priority: 2
content: |
AngularJS Code ({{ file_to_convert }}):
```
{{ file_contents }}
```
- priority: 1
content: |
# Instructions
- Extract `{{ service_name }}` from the above AngularJS code and convert it to an Angular service.
- Only extract and convert `{{ service_name }}` and its relevant information to make it work in Angular on its own. Ignore anything else.
- The resulting file will be created at {{ service_file_path }}.
- Services should be properly decorated with `@Injectable()` and exported.
{{ transformation_notes }}
returns: chunked_prompts
- name: edit_file_long_context
arguments:
path_to_file: '{{ service_file_path }}'
edit_prompts: '{{ chunked_prompts }}'
returns: file_paths
- name: mark_files_converted_in_context
arguments:
done_converting: false
old_file_path: '{{ file_to_convert }}'
new_file_paths: '{{ file_paths }}'
# Configs to Modules
- condition_prompt: Does this file contain an AngularJS config definition?
tools:
- name: find_content_in_file_with_ai
arguments:
path_to_file: '{{ file_to_convert }}'
find_context_prompt: 'Find and return JUST the name of each config defined in the file. If there is no name defined, create one based on the contents of the config. It is critical that the name could be used as a valid file name. If there are none, return an empty array.'
results_as_array: true
returns: config_names
- name: async_each
items: '{{ config_names }}'
returns_key: module_file_paths
each_item:
item_name: config_name
tools:
- name: make_variable
arguments:
value: '{{ modules_directory }}/{{ config_name }}.module.ts'
returns: module_file_path
- name: chunk_prompt
arguments:
contents:
- priority: 3
content: '{{ file_context }}'
- priority: 2
content: |
AngularJS Code ({{ file_to_convert }}):
```
{{ file_contents }}
```
- priority: 1
content: |
# Instructions
- Extract `{{ config_name }}` from the above AngularJS code and convert it to an Angular module.
- Only extract and convert `{{ config_name }}` and its relevant information to make it work in Angular on its own. Ignore anything else.
- The resulting file will be created at {{ module_file_path }}.
- Modules should be properly decorated with `@NgModule` and include declarations, imports, providers, and exports as necessary.
{{ transformation_notes }}
returns: chunked_prompts
- name: edit_file_long_context
arguments:
path_to_file: '{{ module_file_path }}'
edit_prompts: '{{ chunked_prompts }}'
returns: file_paths
- name: mark_files_converted_in_context
arguments:
done_converting: false
old_file_path: '{{ file_to_convert }}'
new_file_paths: '{{ file_paths }}'
# Directives
- condition_prompt: Does this file contain an AngularJS directive definition?
tools:
- name: find_content_in_file_with_ai
arguments:
path_to_file: '{{ file_to_convert }}'
find_context_prompt: 'Find and return JUST the name of each directive defined in the file. If there are none, return an empty array.'
results_as_array: true
returns: directive_names
- name: async_each
items: '{{ directive_names }}'
returns_key: directive_file_paths
each_item:
item_name: directive_name
tools:
- name: make_variable
arguments:
value: '{{ directives_directory }}/{{ directive_name }}.directive.ts'
returns: directive_file_path
- name: chunk_prompt
arguments:
contents:
- priority: 3
content: '{{ file_context }}'
- priority: 2
content: |
AngularJS Code ({{ file_to_convert }}):
```
{{ file_contents }}
```
- priority: 1
content: |
# Instructions
- Extract `{{ directive_name }}` from the above AngularJS code and convert it to an Angular directive.
- Only extract and convert `{{ directive_name }}` and its relevant information to make it work in Angular on its own. Ignore anything else.
- The resulting file will be created at {{ directive_file_path }}.
- Directives should be properly decorated with `@Directive` and exported.
{{ transformation_notes }}
returns: chunked_prompts
- name: edit_file_long_context
arguments:
path_to_file: '{{ directive_file_path }}'
edit_prompts: '{{ chunked_prompts }}'
returns: file_paths
- name: mark_files_converted_in_context
arguments:
done_converting: false
old_file_path: '{{ file_to_convert }}'
new_file_paths: '{{ file_paths }}'
# Controllers to Components
- condition_prompt: Does this file contain an AngularJS controller definition?
tools:
- name: find_content_in_file_with_ai
arguments:
path_to_file: '{{ file_to_convert }}'
find_context_prompt: 'Find and return JUST the name of each controller defined in the file. If there are none, return an empty array.'
results_as_array: true
returns: controller_names
- name: async_each
items: '{{ controller_names }}'
returns_key: component_file_paths
each_item:
item_name: controller_name
tools:
- name: make_variable
arguments:
value: '{{ components_directory }}/{{ controller_name }}/{{ controller_name }}.component.ts'
returns: component_file_path
- name: chunk_prompt
arguments:
contents:
- priority: 3
content: '{{ file_context }}'
- priority: 2
content: |
AngularJS Code ({{ file_to_convert }}):
```
{{ file_contents }}
```
- priority: 1
content: |
# Instructions
- Extract `{{ controller_name }}` from the above AngularJS code and convert it to an Angular component.
- Only extract and convert `{{ controller_name }}` and its relevant information to make it work in Angular on its own. Ignore anything else.
- The resulting files will be created at:
- Component class: {{ component_file_path }}
- Template HTML: '{{ components_directory }}/{{ controller_name }}/{{ controller_name }}.component.html'
- Components should be properly decorated with `@Component` and include the template and styles as necessary.
{{ transformation_notes }}
returns: chunked_prompts
- name: edit_file_long_context
arguments:
path_to_file: '{{ component_file_path }}'
edit_prompts: '{{ chunked_prompts }}'
returns: file_paths
- name: mark_files_converted_in_context
arguments:
done_converting: false
old_file_path: '{{ file_to_convert }}'
new_file_paths: '{{ file_paths }}'
# Routes
- condition_prompt: Does this file contain AngularJS routes definitions that should be included in the Angular Router?
tools:
- name: truncate_prompt
arguments:
contents:
- priority: 3
content: '{{ file_context }}'
- priority: 2
content: |
AngularJS Code to convert to Angular ({{ file_to_convert }}):
```
{{ file_contents }}
```
- priority: 1
content: |
# Instructions
- Extract the route definitions from the above AngularJS code.
- The only code you care about in this file is the route definitions and the variables that define them. Ignore all other code.
- Convert the extracted router-related code to use Angular Router.
- Ensure all previous functionality remains along with the new logic that you implement.
- Do not just concatenate converted parts together; you should rewrite so that the code is DRY without losing functionality. The result should be a valid Angular routing module.
- If there isn't any code in the AngularJS file that could be converted to valid Angular Router, you should not make any edits to the file—just return an empty string in that case.
- Do not implement anything other than the router. Other logic will be converted in different steps.
{{ transformation_notes }}
returns: truncated_prompt
- name: edit_file
arguments:
path_to_file: '{{ modules_directory }}/{{ file_name }}.routing.module.ts'
edit_prompt: '{{ truncated_prompt }}'
- name: mark_files_converted_in_context
arguments:
done_converting: false
old_file_path: '{{ file_to_convert }}'
new_file_paths:
- '{{ modules_directory }}/{{ file_name }}.routing.module.ts'
# Default case
default:
tools:
- name: echo_one
arguments:
echo_arg: 'Doing nothing with {{ file_to_convert }}'
# Mark file as converted
- name: mark_files_converted_in_context
arguments:
done_converting: true
old_file_path: '{{ file_to_convert }}'
- name: Combine Routes into app-routing.module.ts
tools:
- name: find_files_by_name_with_regex
arguments:
path_to_directory: '{{ modules_directory }}'
find_file_name_pattern: '.*\.routing\.module\.ts$'
returns: routing_module_paths
- name: get_content_from_files
arguments:
paths_to_files: '{{ routing_module_paths }}'
returns: routing_module_contents
- name: edit_file
arguments:
path_to_file: '{{ app_directory }}/app-routing.module.ts'
edit_prompt: |
The below code could contain Angular Router configurations. You should extract and add any routes directly into the `app-routing.module.ts` file, in addition to adding any comments that start with `// Converted from` that are present at the top of the file we are extracting from. Be meticulous and precise. Do not hallucinate.
## Routing Module Files
```
{{ routing_module_contents }}
```
# Delete routing modules now that they have been extracted into app-routing.module.ts
- name: for_each
items: '{{ routing_module_paths }}'
each_item:
item_name: routing_module_path
tools:
- name: delete_file_or_folder
arguments:
path_to_target: '{{ routing_module_path }}'
- name: Copy static assets
tools:
- name: find_files_by_name_with_regex
arguments:
path_to_directory: 'src'
find_file_name_pattern: .*\.(css|svg|png|jpg|jpeg|eot|ttf|otf|woff|woff2|gif|bmp|webp|webm|mp3)$
returns: static_asset_files
- name: for_each
items: '{{ static_asset_files }}'
each_item:
item_name: static_file
tools:
- name: copy_file
arguments:
source_path: '{{ static_file }}'
destination_path: '{{ assets_directory }}/{{ static_file }}'
returns: copied_file_path
- name: Add CSS imports to styles.css
tools:
- name: find_files_by_name_with_regex
arguments:
path_to_directory: '{{ assets_directory }}'
find_file_name_pattern: '.*\.css$'
returns: css_files
- name: edit_file
arguments:
path_to_file: '{{ src_directory }}/styles.css'
edit_prompt: |
Add CSS imports at the top of the file for the following CSS files:
```
{{ css_files }}
```
Use the appropriate syntax to import CSS files in Angular `styles.css`.
- name: Resolve import paths
tools:
- name: resolve_import_paths
arguments:
path_to_directory: '{{ angular_directory }}'
- name: Validate TypeScript Project
tools:
- name: run_terminal_command
arguments:
path_to_directory: '{{ angular_directory }}'
command: 'ng build --aot'
- name: run_terminal_command
arguments:
path_to_directory: '{{ angular_directory }}'
command: 'ng lint'
Last updated