New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(language-service): merge compiler options, watch extended configs #39134
Conversation
64d3b51
to
86ce5ec
Compare
Currently the language service watches only the root config file of a configured project for changes. However, since the Angular CLI merges compiler options across all referenced config files, the Angular LS should do the same, and watch for changes in any relevant config file. This commit does the following: - Defer compiler option parsing to `perform_compile.readConfiguration`, which already merges compiler options across extended config files. Furthermore, return all extended config files from `readConfiguration`. - Attach file watchers to the project root config file, and all known extended config files as determined by `readConfiguration`. On a change to any config file, refresh the compiler options known by the Angular LS, and attach file watchers for any newly-extended config files. - Also: properly clean up file watchers, closing them when a file is deleted. To test these changes, the mock server host is extended to support a mock filesystem. This is needed because ngtsc reads files from a file system interface, which the mock service does not provide. Furthermore, methods on the mock filesystem defer to the mock host, so the host was chosen to implement a filesystem rather than the service doing so.
86ce5ec
to
4134ea6
Compare
* File system mocking is needed to test dynamic changes of non-script files (namely, config files) | ||
* that are watched and read from the file system rather than from a project service. | ||
* NB: If you need to modify TS and template file contents, use the methods | ||
* provided the `MockService` rather than this mock filesystem. | ||
*/ | ||
export class MockHost extends NodeJSFileSystem implements ts.server.ServerHost { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to merge the mock filesystem with the mocking that happens in the MockService, lmk if you have any ideas. Otherwise this can be a follow-up cleanup after some more thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that the mock file system/mock service rely on the host, but the host also relies on the mock FS to watch files, so if we pull the mock FS down to the mock service then we required shared state b/w the host and the mock service/fs.
Currently the `readConfiguration` function in the compiler relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (angular#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. As discussed in the LS sync, we decided to provide to `readConfiguration` a host that would take of reading configuration as needed for the use case of the caller. A first attempt was to put this on `NgCompilerAdapter`, but this is not elegant because it introduces a `CompilerAdatpter` dependency where there is no need for one (e.g. when creating a watch mode host). To be honest, I am not in love with the `ReadConfigurationHost` delivered in this patch. I think it may be less hassle in the long term and more ergonomic to create a `FileSystem` abstraction on a per-project basis, delivered to the compiler whenever a new langauge service is created. Let me know what you think. Unblocks angular#39134
Currently the `readConfiguration` function in the compiler relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (angular#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. As discussed in the LS sync, we decided to provide to `readConfiguration` a host that would take of reading configuration as needed for the use case of the caller. A first attempt was to put this on `NgCompilerAdapter`, but this is not elegant because it introduces a `CompilerAdatpter` dependency where there is no need for one (e.g. when creating a watch mode host). To be honest, I am not in love with the `ReadConfigurationHost` delivered in this patch. I think it may be less hassle in the long term and more ergonomic to create a `FileSystem` abstraction on a per-project basis, delivered to the compiler whenever a new langauge service is created. Let me know what you think. Unblocks angular#39134
Currently the `readConfiguration` function in the compiler relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (angular#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. As discussed in the LS sync, we decided to provide to `readConfiguration` a host that would take of reading configuration as needed for the use case of the caller. A first attempt was to put this on `NgCompilerAdapter`, but this is not elegant because it introduces a `CompilerAdatpter` dependency where there is no need for one (e.g. when creating a watch mode host). To be honest, I am not in love with the `ReadConfigurationHost` delivered in this patch. I think it may be less hassle in the long term and more ergonomic to create a `FileSystem` abstraction on a per-project basis, delivered to the compiler whenever a new langauge service is created. Let me know what you think. Unblocks angular#39134
Currently the `readConfiguration` function in the compiler relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (angular#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. This patch alleviates the concern by directly providing to the compiler a file system derived from the project owned by the language service. Furthermore, the langauge service file system is "specialized" in some sense - for one, it avoids implementing APIs that would change the state of the underlying system, as no path in the language service (server-side) should do this.
Currently the `readConfiguration` function in the compiler relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (angular#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. This patch alleviates the concern by directly providing to the compiler a file system derived from the project owned by the language service. Furthermore, the langauge service file system is "specialized" in some sense - for one, it avoids implementing APIs that would change the state of the underlying system, as no path in the language service (server-side) should do this.
Currently `readConfiguration` relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (angular#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. This patch alleviates the concern by directly providing to the compiler a "ParseConfigurationHost" with read-only "file system"-like utilties. For the language service, this host is derived from the project owned by the language service. For more discussion see https://docs.google.com/document/d/1TrbT-m7bqyYZICmZYHjnJ7NG9Vzt5Rd967h43Qx8jw0/edit?usp=sharing
Currently `readConfiguration` relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (angular#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. This patch alleviates the concern by directly providing to the compiler a "ParseConfigurationHost" with read-only "file system"-like utilties. For the language service, this host is derived from the project owned by the language service. For more discussion see https://docs.google.com/document/d/1TrbT-m7bqyYZICmZYHjnJ7NG9Vzt5Rd967h43Qx8jw0/edit?usp=sharing
Currently `readConfiguration` relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (angular#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. This patch alleviates the concern by directly providing to the compiler a "ParseConfigurationHost" with read-only "file system"-like utilties. For the language service, this host is derived from the project owned by the language service. For more discussion see https://docs.google.com/document/d/1TrbT-m7bqyYZICmZYHjnJ7NG9Vzt5Rd967h43Qx8jw0/edit?usp=sharing
Currently `readConfiguration` relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (angular#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. This patch alleviates the concern by directly providing to the compiler a "ParseConfigurationHost" with read-only "file system"-like utilties. For the language service, this host is derived from the project owned by the language service. For more discussion see https://docs.google.com/document/d/1TrbT-m7bqyYZICmZYHjnJ7NG9Vzt5Rd967h43Qx8jw0/edit?usp=sharing
Currently `readConfiguration` relies on the file system to perform disk utilities needed to read determine a project configuration file and read it. This poses a challenge for the language service, which would like to use `readConfiguration` to watch and read configurations dependent on extended tsconfigs (#39134). Challenges are at least twofold: 1. To test this, the langauge service would need to provide to the compiler a mock file system. 2. The language service uses file system utilities primarily through TypeScript's `Project` abstraction. In general this should correspond to the underlying file system, but it may differ and it is better to go through one channel when possible. This patch alleviates the concern by directly providing to the compiler a "ParseConfigurationHost" with read-only "file system"-like utilties. For the language service, this host is derived from the project owned by the language service. For more discussion see https://docs.google.com/document/d/1TrbT-m7bqyYZICmZYHjnJ7NG9Vzt5Rd967h43Qx8jw0/edit?usp=sharing PR Close #39619
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Currently the language service watches only the root config file of a
configured project for changes. However, since the Angular CLI merges
compiler options across all referenced config files, the Angular LS
should do the same, and watch for changes in any relevant config file.
This commit does the following:
perform_compile.readConfiguration
, which already merges compileroptions across extended config files. Furthermore, return all
extended config files from
readConfiguration
.extended config files as determined by
readConfiguration
. On achange to any config file, refresh the compiler options known by
the Angular LS, and attach file watchers for any newly-extended
config files.
is deleted.
To test these changes, the mock server host is extended to support a
mock filesystem. This is needed because ngtsc reads files from a file
system interface, which the mock service does not provide. Furthermore,
methods on the mock filesystem defer to the mock host, so the host was
chosen to implement a filesystem rather than the service doing so.