8000 Files with the same name (without extensions) are not parsable · Issue #955 · typescript-eslint/typescript-eslint · GitHub
[go: up one dir, main page]

Skip to content

Files with the same name (without extensions) are not parsable #955

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

Closed
bradzacher opened this issue Sep 6, 2019 · 8 comments · Fixed by #957
Closed

Files with the same name (without extensions) are not parsable #955

bradzacher opened this issue Sep 6, 2019 · 8 comments · Fixed by #957
Labels
bug Something isn't working has pr there is a PR raised to close this package: typescript-estree Issues related to @typescript-eslint/typescript-estree

Comments

@bradzacher
Copy link
Member

Moving this out of #890 as it's an issue we need to track.

Comment by @toddbluhm:

The issue appears to occur when I have two files with the same name (fixture.ts & fixture.js) in the same folder (src). It only picks up the .ts file and will not pick up the .js file. Instead, it gives the error that fixture.js was not included in the project.

I can confirm that deleting fixture.ts and keeping fixture.js causes the "not included in project" error to go away. So by deleting either fixture.ts or fixture.js causes the "not included in project" error to go away. Keeping both files, causes the error to show up.


**tsconfig.json**
{
  "extends": "./node_modules/tsconfigs/universal",
  "compilerOptions": {
    "esModuleInterop": true,
    "importHelpers": false
  }
}

**tsconfig.eslint.json**
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true
  },
  "include": [
    "src/**/*",
    "*.ts",
    "*.js"
  ]
}

**.eslintrc.json**
{
  "extends": "./lib/index.js",
  "parserOptions": {
    "project": "./tsconfig.eslint.json"
  }
}

**Example file paths that are throwing errors**
  • /Users/toddbluhm/Development/Github/eslint-config-standard-with-typescript/src/fixture.js
    • Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
      The file does not match your project config: /Users/toddbluhm/Development/Github/eslint-config-standard-with-typescript/src/fixture.js.
      The file must be included in at least one of the projects provided

Versions

package version
@typescript-eslint/eslint-plugin 2.0.0 & 2.0.1-alpha.27
@typescript-eslint/parser 2.0.0 & 2.0.1-alpha.27
TypeScript 3.5.3
node 10.15.0
@bradzacher bradzacher added bug Something isn't working package: typescript-estree Issues related to @typescript-eslint/typescript-estree labels Sep 6, 2019
@bradzacher bradzacher mentioned this issue Sep 6, 2019
3 tasks
@bradzacher
Copy link
Member Author

This is because of TS diagnostic 5056 - Cannot write file '{0}' because it would be overwritten by multiple input files.

Perhaps we should whitelist this diagnostic? We're not writing files, so we don't care if they would overwrite one another.

@bradzacher
Copy link
Member Author
bradzacher commented Sep 6, 2019

Digging into this a little bit - it's not a diagnostic that's being thrown that stops this from working.

It looks like the Watch Compiler Host we create via ts.createWatchCompilerHost doesn't even list files with duplicate names, even if you specifically include them within includes.

Logging out of afterProgramCreate, the program just doesn't include the js file.
So there's something internally that the ts api is doing to filter out the duplicate files.
Will require some more digging.

See: #957

@bradzacher
Copy link
Member Author

Digging into this more via the debugger.
There is no way around this, unfortunately.
TS is designed such that each file must have a unique name per directory in this priority order:

  1. .ts
  2. .tsx
  3. .d.ts
  4. .js
  5. .jsx

This is the code which does the check:
https://github.com/microsoft/TypeScript/blob/73a2146583a774d322cfda8531fb22f34b6cc734/src/compiler/commandLineParser.ts#L2782-L2796

Copying the relevant source code comment here because the file's too long for github's preview system:

// If we have already included a literal or wildcard path with a
// higher priority extension, we should skip this file.
//
// This handles cases where we may encounter both <file>.ts and
// <file>.d.ts (or <file>.js if "allowJs" is enabled) in the same
// directory when they are compilation outputs.

This system also works "retroactively" so that it will stop tracking a .js file if it later encounters a .ts file with the same name. I.e. if it encounters fixture.js first, it'll still discard it in favour of fixture.ts later.

So in order to handle this, we'd have to build a system to detect this case, and then create a separate program for this duplicate file.

Which I think is probably way too much effort for an edge case?
I'm thinking - document this in the readme, and move on.

cc @uniqueiniquity as an FYI

@toddbluhm
Copy link

Yeah, that does sound like quite a bit of work. Thanks for looking into this and nice job debugging it 💯

I would suggest maybe filing an issue with typescript to see if they would ever consider adding an option to allow duplicate files at some point in the future, especially if no output files will be generated.

@bradzacher bradzacher added the has pr there is a PR raised to close this label Sep 7, 2019
@rufusraghunath
Copy link

This is interesting - I just came across this myself. I was trying to do:

MyClassName
|-- index.ts
|-- index.d.ts

And became very confused when this resulted in 0:0 error Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.

This can't be that unusual of a usecase, right?

@bradzacher
Copy link
Member Author

It is uncommon because it doesn't actually work in practice.

If you define the above, and then do: import { X } from './index' what should happen? Does typescript merge the two files? Does it pick one over the other?

When you do a build, what should typescript output? If you do "includes": ["MyClassName"] in your tsconfig, what does typescript do?

The answer is that it uses the ordering mentioned above to pick a file.
It will import the .ts file instead of the .d.ts file. Doesn't matter if it's an index file or a local file, the outcome is the same.

With declaration files on, index.ts will generate a index.d.ts, which will clearly overwrite the provided index.d.ts, so typescript just doesn't output the index.d.ts you provide.

I just did some testing to verify all of this.

Typescript doesn't explicitly error on the file like we do, but it doesn't work either.
It will provide typechecking for index.d.ts in the IDE, because the IDE is designed to build this loose "catch-all" program. We don't do that on purpose because it slows everything down when running from the CLI.

Unless I'm missing something about the use case, that is. I'd love to know more about why you want to do this.

@rufusraghunath
Copy link
rufusraghunath commented Nov 1, 2019

@bradzacher thanks for your thoughtful response!

Unless I'm missing something about the use case, that is. I'd love to know more about why you want to do this.

There really isn't an important usecase in my case :) I think ultimately my motivation for wanting this is just that it "feels right" to have an entry point (index) file for my production code and my types. Particularly if I'm organizing my directory structure by component.

When you do a build, what should typescript output?

Well, in this case I could see the compiler failing with a message that warns you about the ambiguous import. I feel like it should be fixable by specifying the file extension in your import, though.

@bradzacher
Copy link
Member Author
bradzacher commented Nov 1, 2019

Yeah typescript acts without a clear error message here, unfortunately.

We could potentially improve the error messaging on our end, but it'd come at a perf cost for the error case, as the only way to tell if typescript has done this is by doing a filesystem lookup when the ts program returns nothing to us.

On one hand, if someone's setup is particularly bad it could slam the hard disk with activity and add a lot of runtime.
On the other hand, the error case should be a rare thing, and it could help with debugging.

Undecided if it's a good idea, or if we just rely on documentation in the readme.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 20, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working has pr there is a PR raised to close this package: typescript-estree Issues related to @typescript-eslint/typescript-estree
Projects
None yet
3 participants
0