Skip to content

Conversation

@erik-krogh
Copy link
Contributor

A followup on the .cjs file support.

Adds support for the "type" field from the package.json file in the extractor.
The "type" field determines which module-type (CommonJS/ES2015) a .js file should be treated as.

We need this information in the extractor for e.g. determining strict-mode.
So that is why I put it into the extractor, even though it might have been easier to implement on the .ql side.

I've added a folder->type cache that should hopefully eliminate any potential performance impact.

My previous .cjs support PR had a bug (missing .withPlatform(Platform.NODE)), which is why the .trap file has been updated by this PR.

@erik-krogh erik-krogh added the JS label Aug 20, 2020
@erik-krogh erik-krogh requested a review from a team as a code owner August 20, 2020 12:35
if (cache.containsKey(folder)) {
return cache.get(folder);
}
for (final File file : folder.listFiles()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why iterate over the contents to look for a specific file?

I'd suggest just doing new File(folder, "package.json") and check that it exists and is a file.

}

// cache for `getPackageType`.
private static final Map<File, String> cache = new HashMap<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, we create one ScriptExtractor per file, so this cache isn't helping when it sits here.

Also keep in mind that we extract multiple files in parallel, so when moving it to a shared place, it needs to be thread-safe.

ExtractorState should be the right place to put this cache. It's the place to share data between individual file extractions. I think we can just expose it as a ConcurrentHashMap like we do with snippets (and member to update ExtractorState#reset).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to use Optional<String> because ConcurrentHashMap does not do null values. But it works great now.

private boolean isAlwaysModule(String extension) {
return extension.equals(".mjs") || extension.equals(".es6") || extension.equals(".es");
/** True if the file specified by `locationManager` should always be treated as a module. */
private boolean isAlwaysModule(LocationManager locationManager, String packageType) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why pass in the LocationManager instead of extension? Seems like an unrelated change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At one point I computed the "type" inside isAlwaysModule, and that required the LocationManager.

I've changed it back now.

}
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String result = new Gson().fromJson(reader, PackageJSON.class).type;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a test where type is present but is not a string or null (e.g a number). It seems like this will crash the extractor.

Also catch JsonSyntaxException below in case the file has a syntax error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JsonSyntaxException seems to also catch the case where type is not a string.

@codeql-ci codeql-ci merged commit 844abc5 into github:main Aug 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants