Skip to content

Commit

Permalink
chore(ts-interface-generator): fix lint issues; adapt README
Browse files Browse the repository at this point in the history
  • Loading branch information
akudev committed Sep 25, 2024
1 parent 53ece8b commit 631bb5c
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 27 deletions.
47 changes: 22 additions & 25 deletions packages/ts-interface-generator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,26 @@ This is the list of available command-line arguments, including the ones already
- `--loglevel`: Set the console logging verbosity; options are: `error`, `warn`, `info`, `debug`, `trace`; default level is `info`
- `--jsdoc`: Set the amount of JSDoc which should be generated; options are: `none`, `minimal`, `verbose`; default is `verbose`: by default, the JSDoc documentation written in the control metadata for the properties, aggregations etc. is added to the generated methods, plus generic documentation for the `@param` and `@returns` tags as well as some additional generic documentation like for default values (if any). By setting `--jsdoc none` or `--jsdoc minimal` you can decide to omit all JSDoc or to only add the JSDoc written in the control.

## Why?

When developing UI5 controls, the control metadata declares properties, aggregations, events etc. The methods related to these (like `getText()` for a `text` property or `attachPress(...)` for a `press` event) do not need to be implemented - they are generated by the UI5 framework at runtime.

However, as the TypeScript environment does not know about these methods, a call to any of them will be marked as error in the source code. And on top of this, there is also no code completion for these methods and no type information and in-place documentation for parameters and return values.

This is a problem for application code using controls developed in TypeScript as well as for the development of these controls in TypeScript. Both development scenarios involve calling those API methods which are not known to the TypeScript environment. Thus, there needs to be a way to make TypeScript aware of them.

(Remark: the controls shipped with the UI5 framework are implemented in JavaScript and a complete set of TypeScript type definitions is created during the framework build from the JSDoc comments. So both facets of the problem do not apply to them.)

## How it Works

This tool scans all TypeScript source files for <b>top-level definitions of classes</b> inheriting from `sap.ui.base.ManagedObject` (in most cases those might be sub-classes of `sap.ui.core.Control`, so they will be called "controls" for simplicity).

For any such control, the metadata is parsed, analyzed, and a new TypeScript file is constructed, which contains an interface declaration with the methods generated by UI5 at runtime. This generated interface gets merged with the already existing code using TypeScript's [Declaration Merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html) concept.

Unfortunately, these separate interface declarations cannot define new constructors (see e.g. [this related TS issue](https://github.com/microsoft/TypeScript/issues/2957)). Hence those must be manually added to each control (one-time effort, pasting 3 lines of code). The interface generator writes the required lines to the console.

Oh, and the tool itself is implemented in TypeScript because TypeScript makes development more efficient. ;-)

## Limitations

See the [TODO](#TODO) section for examples of features not yet implemented.
Expand All @@ -75,42 +95,19 @@ To detect whether the required constructor signatures are already present in the

### Second(+)-level Inheritance

When there are at least two levels of custom controls (inheriting from each other), there is the error message: `Class static side 'typeof SomeOtherControl' incorrectly extends base class static side 'typeof MyControl'. The types of 'metadata.properties' are incompatible between these types.`

As a workaround, you can assign a type to the `metadata` field in the parent class. Using type `object` is sufficient, but it can also be more specific:
When there are at least two levels of custom controls (inheriting from each other) and you get the error message: `Class static side 'typeof SomeOtherControl' incorrectly extends base class static side 'typeof MyControl'. The types of 'metadata.properties' are incompatible between these types.`, then you have missed to assign the `MetadataOptions` type to the `metadata` field in the parent class. (Before UI5 version 1.110, you can use the type `object` instead):

```ts
static readonly metadata: object = {
static readonly metadata: MetadataOptions = {
...
```
See [#338](https://github.com/SAP/ui5-typescript/issues/338) for more details.
## Why?
When developing UI5 controls, the control metadata declares properties, aggregations, events etc. The methods related to these (like `getText()` for a `text` property or `attachPress(...)` for a `press` event) do not need to be implemented - they are generated by the UI5 framework at runtime.
However, as the TypeScript environment does not know about these methods, a call to any of them will be marked as error in the source code. And on top of this, there is also no code completion for these methods and no type information and in-place documentation for parameters and return values.
This is a problem for application code using controls developed in TypeScript as well as for the development of these controls in TypeScript. Both development scenarios involve calling those API methods which are not known to the TypeScript environment. Thus, there needs to be a way to make TypeScript aware of them.
(Remark: the controls shipped with the UI5 framework are implemented in JavaScript and a complete set of TypeScript type definitions is created during the framework build from the JSDoc comments. So both facets of the problem do not apply to them.)
## How it Works
This tool scans all TypeScript source files for <b>top-level definitions of classes</b> inheriting from `sap.ui.base.ManagedObject` (in most cases those might be sub-classes of `sap.ui.core.Control`, so they will be called "controls" for simplicity).
For any such control, the metadata is parsed, analyzed, and a new TypeScript file is constructed, which contains an interface declaration with the methods generated by UI5 at runtime.
Unfortunately, these separate interface declarations cannot define new constructors (see e.g. [this related TS issue](https://github.com/microsoft/TypeScript/issues/2957)). Hence those must be manually added to each control (one-time effort, pasting 3 lines of code). The interface generator writes the required lines to the console.
Oh, and the tool itself is implemented in TypeScript because TypeScript makes development more efficient. ;-)
## TODO
- make sure watch mode does it right (also run on deletion? Delete interfaces before-creating? Only create interfaces for updated files?)
- consider further information like deprecation etc.
- it is probably required to check whether the control class being handled is the default export or a named export. Right now it is assumed that it is the default export. Other cases are not tested and likely not working.
- ...
## Support
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export default class SampleControl extends Button {
*/
delay: { type: "int" }
}
}
}
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default class SampleControl extends Button {
*/
delay: { type: "int" }
}
}
}
},
};

Expand Down

0 comments on commit 631bb5c

Please sign in to comment.