Migration tool to help migrating the JavaScript/TypeScript code from one Scout release to another.
To set up the tool, do the following:
- Open the
package.json
of your ui module (e.g.your.project.ui.html
). - Add a devDependency to
@eclipse-scout/migrate
. - Run
pnpm install
to install the new dependency. - Do the required migration as described in the following chapters.
- When you are finished, remove the added dependency and migration script from you
package.json
.
{
"devDependencies": {
"@eclipse-scout/migrate": "~24.2.0"
}
}
Some migrations require a tsconfig.json
. You can add it as follows (do it only if stated in the migration description):
- Add a devDependency to
@eclipse-scout/tsconfig
. - Run
pnpm install
to install the new dependency. - Create a
tsconfig.json
beside yourpackage.json
according to theReadme.md
of the@eclipse-scout/tsconfig
module.
{
"devDependencies": {
"@eclipse-scout/tsconfig": "~24.2.0"
}
}
The module map is used by certain migration tasks to automatically add imports. If a migration task requires a module map, do the following:
- Adjust the
moduleMap
argument by replacingyourNamespace
with the namespace in yourindex.js
file. The moduleMap entry is used to add imports to yourindex.js
automatically. If you omit it, you need to add the imports manually. - If you have dependencies to other Scout based modules, you add them to the
moduleMap
to have the imports to these modules created automatically. Add the namespace of the other module and the name of the npm package as follows:--moduleMap.otherNamespace @other/npm-module
In order to migrate string literals to class references and menu type constants, do the following:
- Add a script in your
package.json
as described below. - Adjust the module map as described in the chapter Module Map
- Run the
migrate
script by pressing the play button next to it in IntelliJ or using the command line:npm run migrate
- Review the changes and add the missing imports, if there are any.
{
"scripts": {
"migrate": "scout-migrate --migrate objectType menuTypes --sources src/main/js/**/*.js --moduleMap.yourNamespace path:src/main/js/index.js"
}
}
In order to create widget and column maps, do the following:
- Create a
tsconfig.json
as described here - Add a rename and a migrate script in your
package.json
as described below. - Run the
rename
script by pressing the play button next to it in IntelliJ or using the command line:npm run rename
. Commit the changes to ensure Git can track the renames correctly. - Run the
migrate
script. - Review and commit the changes.
{
"scripts": {
"rename": "scout-migrate --rename --sources src/main/js/**/*Model.js",
"migrate": "scout-migrate --migrate widgetColumnMap --sources src/main/js/**/*Model.ts"
}
}
If you plan to migrate your Scout JS code base to TypeScript, use the migration tool for the initial migration. From there, you need to add the missing types, fix errors and clean up your code.
Important: if you have dependencies to other Scout based modules, make sure these modules are migrated to TypeScript first. We don't recommend migrating to TypeScript unless all dependencies are migrated.
The automatic migration includes:
- Renaming the files to
*.ts
. - Declaring class properties
- Declaring method parameters and return types based on JsDoc and naming conventions
- Removing types from JsDoc
- Adding imports for the types based on module maps
- Adding method accessors
In order to run the TypeScript migration, do the following:
- Ensure you have a clean Git working tree (no uncommitted files).
- Create a
tsconfig.json
as described here - Add scripts in your
package.json
as described below. - Add an
override
in yourpackage.json
to fix the TypeScript version to 5.3.2 (the migrate tool will skip some migrations and print a warning about the wrong version otherwise). This is only needed for the migration and has to be removed afterwards. - Adjust the module map as described in the chapter Module Map
- Add custom type maps if you have a large code base and would like to automate a little more, see Type Map
- Run the
rename
script by pressing the play button next to it in IntelliJ or using the command line:npm run rename
.- Adjust the paths in
package.json
(toindex.ts
), inwebpack.config.js
(to your entry point file) and inkarma.conf.js
(totest-index.ts
). - Open
index.ts
and replaceimport * as self from './index.js';
withimport * as self from './index'
; - Commit the changes to ensure Git can track the renames correctly.
- Adjust the paths in
- Run the
migrate
script. - Review every file:
- Verify / add the types of the class properties.
- Verify / add the types of the method parameters and return values.
- If you have custom widgets, you should create a
Model
and anEventMap
for each widget. Please use existing widgets as template, e.g.Menu.ts
,MenuModel.ts
,MenuEventMap.ts
.- The model needs to be extracted manually. Copy the relevant class properties to a separate model file. In your widget, implement the model interface and declare a model variable.
- To create the event maps, you can run the
event-maps
script from below and copy the result into a separate event maps file.
- If you use third party libraries, you may want to check if they provide types and add them to the
devDependencies
of yourpackage.json
(e.g. @types/jquery). See also Project Setup for TypeScript - Remove the added
scripts
,overrides
and dependency to@eclipse-scout/migrate
.
{
"scripts": {
"rename": "scout-migrate --rename --sources src/main/js/**/*.js",
"migrate": "scout-migrate --rename false --migrate ts --sources src/main/js/**/*.ts --moduleMap.yourNamespace path:src/main/js/index.ts",
"event-maps": "scout-migrate --print-event-maps --sources src/main/js/**/*.ts"
},
"pnpm": {
"overrides": {
"typescript": "5.3.2"
}
}
}
Type maps are used to add types automatically based on naming rules. Scout provides many rules out of the box that should detect many types. If you have a large code base with custom types, you can add custom type maps.
To do so, create a config file ending with .mjs
, e.g. migrate-config.mjs
and configure your type maps like in the following example:
// The key has no special meaning
// The `name` is the name of the member variable or method parameter.
// If the predicate returns true, the type is used.
// The namespace in the type is used to create the import. To make it work, the module map has to contain an entry for that namespace.
// Example: doSomething(opts) -> doSomething(opts: Options)
const typeMap = {
Options: {
predicate: name => name === 'opts',
type: 'yourNamespace.Options'
}
};
// Compared to the typeMap above, the returnTypeMap is only used to determine the return types of functions.
// The 'name' parameter is the method name
// Example: createOptions() -> createOptions(): Options
const returnTypeMap = {
Options: {
predicate: name => name === 'createOptions',
type: 'yourNamespace.Options'
}
};
// Necessary if the imports should be created automatically.
const moduleMap = {
yourNamespace: '@your-module/core'
};
// The default type that will be used if the parameter has no type.
// Can for example be set to 'any' after the migration to check whether all parameters have been typed.
let defaultParamType;
// The default type that will be used if the function has no return type.
// Can for example be set to 'void' after the migration to check whether all parameters have been typed.
let defaultReturnType;
export {typeMap, returnTypeMap, moduleMap, defaultParamType, defaultReturnType};
You can add as many mappings as you like, or none at all, they are completely optional.
To activate your config, you need to pass the config object to the migrate script by using the --config
option.
For the TypeScript migration, you can do it as follows:
{
"scripts": {
"migrate": "scout-migrate --rename false --migrate ts --sources src/main/js/**/*.ts --config migrate-config.mjs"
}
}
Note: you can either define the module map in the config file or pass it ass arguments to the script. If you do both, they will be merged. If they contain the same keys, the value passed via argument wins.