-
Notifications
You must be signed in to change notification settings - Fork 613
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
[eslint-plugin-packlets] Check imports from tsconfig#compilerOptions.paths #3122
base: main
Are you sure you want to change the base?
[eslint-plugin-packlets] Check imports from tsconfig#compilerOptions.paths #3122
Conversation
The packlets plugin checks local imports to ensure that we only import local code from other packlets — but there is a common edge case in Typescript repositories for which this fails. Imagine this directory structure: ``` repo ├── app └── src └── packlets ├── logger └── metrics ``` Now take this import statment in `src/packlets/logger/log.ts`: ```ts import { Thing } from '../../app' // ERROR ``` However, if your `tsconfig.json` had the following configuration: ```json { "compilerOptions": { "paths": { "@app": ["app"], } } } ``` An alias in your `src/packlets/logger/log.ts` would pass linting: ```ts import { Thing } from '@app' // ALLOWED ``` This change extends the packlets plugin definition of a local import to include Typescript path aliases. It is also common to have aliases for `node_modules` and packlets themselves, so this filters out path aliases for these cases. Take this `tsconfig.json` example: ```json { "compilerOptions": { "paths": { "@app": ["app"], "@myorg/packlets/*": ["src/packlets/*"], "jquery": ["node_modules/jquery/dist/jquery"], } } } ``` The following would happen to these imports in your `src/packlets/logger/log.ts`: ```ts import { Thing } from '@app' // ERROR import * as jquery from 'jquery' // ALLOWED import * as metrics from '@myorg/packlets/metrics' // ALLOWED ```
I thought I'd check in on this PR to see if there is any additional work I can do to make it ready to merge. |
Note: PR #3337 has renamed our GitHub |
@iclanton do we have a chance to merge this PR? Looks like branch doesn't have conflicts with This update will be helpful for our project I can help with PR if we need to update/refresh something |
// Example [[alias, paths], ...] | ||
const nonPackletMappings: [string, string[]][] = Object.entries(tsconfigPaths).filter( | ||
([, paths]) => | ||
!paths.some((path) => path.startsWith('src/packlets') || path.startsWith('node_modules/')) |
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.
Should we consider other equivalent forms such as ./src/packlets
instead of src/packlets
?
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.
Also IIRC baseUrl
affects the interpretation of these paths. (If so it would be okay to simply report an error if baseUrl
is present rather than trying to implement the full semantics.)
// Example [[alias, paths], ...] | ||
const nonPackletMappings: [string, string[]][] = Object.entries(tsconfigPaths).filter( | ||
([, paths]) => | ||
!paths.some((path) => path.startsWith('src/packlets') || path.startsWith('node_modules/')) |
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.
Seems like path.startsWith('src/packlets')
would incorrectly match src/packletsDocs/index.ts
In my experience, tsconfig.json paths seem to be a poor practice for large scale code bases, due to the following chain of reasoning:
That said, we're happy to accept this feature if it doesn't break anything, since not every code base is a large scale code base. 🙂 |
@zouxuoz are you still available to help? We can merge this PR if someone can fix the path-calculation bugs that I pointed out. |
Fixes #3121
Summary
The packlets plugin checks local imports to ensure that we only import local code from other packlets — but there is a common edge case in Typescript repositories for which this fails: imports that use aliases defined in the
tsconfig.json
'scompilerOptions.paths
. This change extends the packlets plugin definition of a local import to include Typescript path aliases.Details
Imagine this directory structure:
Now take this import statment in
src/packlets/logger/log.ts
:However, if your
tsconfig.json
had the following configuration:An alias in your
src/packlets/logger/log.ts
would pass linting:It is also common to have aliases for
node_modules
and packlets themselves, so this filters out path aliases for these cases. So, take this more workedtsconfig.json
example:The following would happen to these imports in your
src/packlets/logger/log.ts
:Details
Alternatives
I considered a few alternatives (or extensions):
tsconfig.json
, but allow configuration of the plugin which specifies a list of import path prefixes that should be seen as "local". The downside here is that additional maintenance is required for repo maintainers whencompilerOptions.paths
gets updated they must also remember to update the plugin configuration.src/packlets
andnode_modules
asignored
, this is in the spirit of this change.compilerOptions.paths
aliases they want to opt-in to the linter — explicitly failing the linting step if the alias is not present. This reduces the maintenance overhead of alternative (1), making it so there isn't a silent failure.Missing cases
This implementation ignores
compilerOptions.paths
which containsrc/packlets
andnode_modules
, but, it is likely that users will want to opt-out of more than these paths. This could be achieved by alternative (2).Backwards compatibility
It will cause previously hidden local imports to be surfaced in codebases.
How it was tested
.isModulePathAnAlias
function