-
-
Notifications
You must be signed in to change notification settings - Fork 643
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
Add package support to typescript/javascript dependency inference #21556
base: main
Are you sure you want to change the base?
Add package support to typescript/javascript dependency inference #21556
Conversation
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.
Thanks for this. Is it possible to add some tests to the adjacent rules_test.py
files?
find_owning_package(OwningNodePackageRequest(address)), | ||
find_parent_ts_config(ParentTSConfigRequest(file_path, "jsconfig.json"), **implicitly()), | ||
) | ||
async def _prepare_inference_metadata(owning_pkg, maybe_config, spec_path) -> InferenceMetadata: |
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.
It'd be good to ensure there's type annotations on these args if possible.
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.
Ah yep, meant to get back around to that and never did...
@@ -128,7 +127,8 @@ async def infer_typescript_source_dependencies( | |||
_determine_import_from_candidates( | |||
candidates, | |||
candidate_pkgs, | |||
file_extensions=TS_FILE_EXTENSIONS + JS_FILE_EXTENSIONS, | |||
tsconfig=maybe_config.ts_config, | |||
file_extensions=TS_FILE_EXTENSIONS + JS_FILE_EXTENSIONS + TSX_FILE_EXTENSIONS, |
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.
If we're supporting TSX here, should we also support JSX? I'm not sure, just pattern matching.
# Try prepending the tsconfig root dir to the package import. | ||
first_party_packge_imports = frozenset( | ||
os.path.join(tsconfig.resolution_root_dir, pkg_import) | ||
for pkg_import in candidates.package_imports | ||
) if tsconfig and tsconfig.resolution_root_dir else frozenset() | ||
paths = await path_globs_to_paths( | ||
_add_extensions( | ||
first_party_packge_imports, | ||
file_extensions, | ||
) | ||
) | ||
local_owners = await Get(Owners, OwnersRequest(paths.files)) |
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.
This should be handled in the rust parser. If it isn't, it is a bug. See https://github.com/pantsbuild/pants/blob/6f8e16e0a2b78d9b3feeb860b38782b92abd1848/src/rust/engine/dep_inference/src/javascript/tests.rs#L473C4-L473C35
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.
This might also explain why I find the if-clause ill-formed. I think you might have misunderstood or been tricked by a bug in what the intention of ParsedJavascriptDependencyCandidate
was. The parser can produce candidates on either form or both, but the separation you do here assumes it knows which case it found. It doesn't. That is why the method is named _determine_import_from_candidates
. But like I said, the parser or my assumptions on how to read tsconfig might be bugged.
for non_path_string in candidates.package_imports | ||
addresses = Addresses(()) | ||
# 1. handle relative imports | ||
if candidates.file_imports: |
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.
This if-clause is ill-formed. It discards too much information.
find_owning_package(OwningNodePackageRequest(request.field_set.address)), | ||
find_parent_ts_config(ParentTSConfigRequest(source.file_path, "tsconfig.json"), **implicitly()), | ||
) | ||
metadata = await _prepare_inference_metadata(owning_pkg, maybe_config, request.field_set.address.spec_path) | ||
|
||
import_strings, candidate_pkgs = await concurrently( | ||
parse_javascript_deps(NativeDependenciesRequest(sources.snapshot.digest, metadata)), |
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.
Word of warning that this parses javascript and JSX files, and will fail to parse as soon as it encounters the type
keyword, which is a valid qualifier for typescript imports but not JS.
You need to provide the tsconfig or full repro to be able to validate your example. "Adds support for imports relative to tsconfig root", this is not a default of the ts resolution spec, but might be for your tooling. If it is, I'm going to encourage you set your tsconfig to match what the tooling is implicitly doing, instead of merging "1a" of this change. You generally need to supply If tests prove "2a" I think that would be a good bug fix. 3a should adhere to https://www.typescriptlang.org/docs/handbook/modules/reference.html#file-extension-substitution. I just want to reiterate that the parser is a javascript parser, not a typescript parser. It is not up to the task of parsing any typescript specifics, so please tread lightly. |
non_path_string_bases = FrozenOrderedSet( | ||
f"{non_path_string.split('/')[0]}/{non_path_string.split('/')[1]}" | ||
if non_path_string.startswith("@") | ||
else non_path_string.partition(os.path.sep)[0] | ||
for non_path_string in candidates.package_imports | ||
) |
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.
Good catch!
This adds better dependency inference to typescript/javascript.
a. i.e.
utils/stringUtils
->frontend/src/utils/stringUtils.ts
a.
@apollo/client
->:package#__apollo/client
.tsx
from.ts
filesa. This is a weird one, I had to add this to support my usecase but I'm not sure the "right" way to handle js/jsx/ts/tsx cross-imports.
I'm not how much of the javascript "spec" I covered
Sample file
Produces