Repository navigation
feat(biome_js_analyze): useImportExtensions - add importMapping options - #3274
Conversation
useImportExtensions - add importMapping options
| "required": ["componentImportExt", "fileExt", "importExt"], | ||
| "properties": { | ||
| "componentImportExt": { | ||
| "description": "Extension that should be used for component file imports", |
There was a problem hiding this comment.
what is the difference between component file and import in this context?
There was a problem hiding this comment.
Rule defines component files as ones starting with an upper-case letter - I guess it is common for React / Vue components - hence the ability to use a different jsx / tsx extension.
There was a problem hiding this comment.
This was a stop gap solution until Biome has infra to check filesystem. Bit unfortunate we need to expose that option, but not sure more general solution is possible.
Though maybe if user picks .js we could auto pick .jsx for those component imports, and likewise .ts -> .tsx? Or would that be too much magic?
There was a problem hiding this comment.
This is a more or less advanced configuration - personally I would prefer to just have an explicit configuration.
CodSpeed Performance ReportMerging #3274 will not alter performanceComparing Summary
|
| /// | ||
| /// ### Options | ||
| /// | ||
| /// Use the options to specify correct import extensions for your project based on the linted |
There was a problem hiding this comment.
Should we mention difference between browser/deno bun bundler/pure tsc somewhere and when you would use such option?
There was a problem hiding this comment.
Oh, that's a rabbit hole which I don't feel comfortable to describe fully and conclusively. I would be glad to hear suggestions on what we can mention here.
There was a problem hiding this comment.
I agree with @drdaemos here. There's a whole world here, and I don't think the rule should discuss it. However, if there are some useful resources, we could add them in the future.
| /// List of inspected file extensions that are subject to this mapping | ||
| pub file_ext: Vec<String>, | ||
| /// Extension that should be used for module imports | ||
| pub import_ext: String, |
There was a problem hiding this comment.
These extensions are only used for suggestions. I can't really see them used for anything else in a future in this rule (might be wrong).
So should it be named suggested_import_extension?
There was a problem hiding this comment.
What do you mean? Isn't the whole idea behind this PR to fix the auto-fix functionality, which currently uses the extension that is wrong for Node.js environment?
There was a problem hiding this comment.
This rule only checks for imports without extensions. Biome does not have infra yet, to check for filesystem. This PR won't fix wrong extensions. It will only suggested user selected extension when there isn't one.
I can see checking for wrong extensions added in a future, so my naming change can be ignored, though I imagine that won't be easy to get right in all cases.
There was a problem hiding this comment.
OK, so to clarify: biome check --fix --unsafe currently does add missing extension when there isn't one at all. That is expected, and after this change the user-specified extension will be applied. Is that correct?
What you are saying is that if e. g. original file is "file.ts", and the import in code is "file.rtf", then Biome will say that it's perfectly fine, right?
There was a problem hiding this comment.
Yes to both. import { named } from './file.rtf' is valid import as far as this rule sees it.
| "required": ["componentImportExt", "fileExt", "importExt"], | ||
| "properties": { | ||
| "componentImportExt": { | ||
| "description": "Extension that should be used for component file imports", |
There was a problem hiding this comment.
This was a stop gap solution until Biome has infra to check filesystem. Bit unfortunate we need to expose that option, but not sure more general solution is possible.
Though maybe if user picks .js we could auto pick .jsx for those component imports, and likewise .ts -> .tsx? Or would that be too much magic?
Co-authored-by: Justinas Delinda <8914032+minht11@users.noreply.github.com>
|
We could use a hash map for the mapping: {
"rules": {
"nursery": {
"useImportExtensions": {
"level": "error",
"options": {
"suggestedExtensions": {
"ts": {
"import": "js",
"component": "jsx"
}
}
}
}
}
}
}
|
|
@Conaclos So should we keep the explicit mapping? Based on your comment on the issue, I thought you prefer a simple binary toggle. |
I am waiting other feedback before deciding. |
|
I have updated the options format based on @Conaclos' suggestion. I guess having an explicit mapping option is the best bet until Biome can detect actual imports used in runtime or replicates the whole logic of how ES modules should be imported depending on the project configuration and used bundlers. |
| /// "ts": { | ||
| /// "import": "js", | ||
| /// "component": "jsx" | ||
| /// } |
There was a problem hiding this comment.
I believe we should be more descriptive here. We should explain the example, and we should explain what import is and how it affects the code action, and we should explain what component is and how component affects the code action.
Usually, we follow this format:
- Talk about the options
- Explain the example e.g. "If you want to do this ... then you should define this and that", "If you have this other situation ... then you should use define this option in this way"
- Code block of the example
To give you better feedback. I am reading this for the first time, and I still don't understand how these options work. For example "ts" as a key isn't explained. Is it an input? An output?
There was a problem hiding this comment.
I think we could add some rationale. We could inform users that it is a temporary workaround. Ideally we should query the extension of the imported file and choose an extension based on that.
There was a problem hiding this comment.
I have updated the description and tried to provide a deeper explanation for the reasoning and way to use that in a project. Do you mind taking another look?
| #[serde(rename_all = "camelCase", deny_unknown_fields)] | ||
| pub struct SuggestedExtensionMapping { | ||
| /// Extension that should be used for module imports | ||
| pub import: String, |
There was a problem hiding this comment.
I would call this module, because that's exactly what it is.
| #[derive(Clone, Debug, Default, Deserializable, Deserialize, Serialize, Eq, PartialEq)] | ||
| #[cfg_attr(feature = "schemars", derive(JsonSchema))] | ||
| #[serde(rename_all = "camelCase", deny_unknown_fields)] | ||
| pub struct UseImportExtensionsOptions { |
There was a problem hiding this comment.
What do you think about a configuration like this:
{
"suggestedExtensions": [
{
"inputExtensions": ["ts", "tsx"],
"import": "js",
"component": "jsx"
}
]
}There was a problem hiding this comment.
That's what I had intially before this comment: #3274 (comment).
I'm not really sure which option is better, both seem sufficient to case for handling backend code + tsc
There was a problem hiding this comment.
I have no big preference. However, using a hash map is easier to query in the code. I think we should not aim for perfection here, because the mapping should be a temporary workaround. We should not spend too much time on that.
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
|
@ematipico @Conaclos Is anything missing on the PR? |
Some of my comments haven't been addressed. Mainly documentation. |
# Conflicts: # CHANGELOG.md # crates/biome_js_analyze/src/lint/nursery/use_import_extensions.rs
|
@ematipico Documentation was updated now, I believe |
ematipico
left a comment
There was a problem hiding this comment.
Looks good, just one nit around docs and then we can merge it
| /// Mainly, this is a temporary workaround that allows Biome to propose correct import extensions | ||
| /// for TypeScript projects that use ES Modules. TypeScript requires you to specify imports to | ||
| /// the actual files used in runtime: `.js` or `.mjs` (see more here: https://github.com/microsoft/TypeScript/issues/49083#issuecomment-1435399267). |
There was a problem hiding this comment.
I would move this paragraph after the code block of the options. Also, add a :::caution block, so the docs will render this with a warning block:
/// :::caution
/// Mainly, this is a temporary ...
/// :::
There was a problem hiding this comment.
Reordered and added the warning block around.
Summary
This is a solution for #2967.
In TypeScript-based projects that use a ES Module import system,
useImportExtensionsmight suggest an incorrect import extension, depending on the project configuration and runtime used. TypeScript requires you to manually specify.jsor.mjsextensions (see microsoft/TypeScript#49083 (comment)) even in.tsor.mtsfiles.This change allows to specify
importMappingsoption foruseImportExtensionsto override the default Biome suggestions.Test Plan
I have added a separate spec
invalidWithImportMappings.tsto verify that the custom import mappings take precedence over the default logic and apply correct mapping to both JS/TS and *SX components.For the following
linterconfiguration:{ "rules": { "nursery": { "useImportExtensions": { "level": "error", "options": { "importMappings": [ { "fileExt": ["ts"], "importExt": "js", "componentImportExt": "jsx" } ] } } } } }All
.tsfiles will attempt to either import.jsor.jsxfiles, depending on the filename.