Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(typescript-estree): allow projectService to type-check virtual processor children#11827

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Conversation

@CyberT33N
Copy link

This pull request teaches the@typescript-eslint/typescript-estree project-service integration to recognize virtual processor child paths (for exampledocs/example.md/0.ts orfile.mdc/0_0.ts) and automatically treat them as eligible for the TypeScript default project, enabling typed linting for code blocks extracted by processors such as@eslint/markdown.

Motivation

Typed linting for code extracted by processors (Markdown/MDX/.mdc fenced TS blocks) previously failed with errors like:

<path>/file.mdc/0_0.ts was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject.

because the TypeScript project service only understoodreal filesystem paths, whereas ESLint processors only exposevirtual child paths (e.g.file.mdc/0_0.ts) that do not exist on disk and cannot be added totsconfig.json.

My original attempt to solve this in ESLint core and@eslint/markdown was to introduce aphysicalFilename concept and to materialize temporary.ts files on disk (seeeslint/eslint#20378,eslint/eslint#20375, andeslint/markdown#595). As discussed in the RFC, that pushed responsibility for creating and cleaning up temp files into every processor.

Inthe review discussion,@DMartens pointed out that:

I also do not think it should be the responsibility of the processor to create and delete files as that would require each processor to do it and it is error-prone (e.g. no cleanup when there is an error).
The main motivation for this change is that TypeScript types work which should be possible with the TypeScript Compiler API.

and suggested instead that the TypeScript integration itself (i.e.@typescript-eslint/parser /typescript-estree via the Compiler API / project service) should be made aware of virtual child paths.

This PR implements that suggestion intypescript-estree: virtual child paths nested under a real file on disk are detected and automatically allowed to use the default project, without requiring processors to materialize temp files or ESLint core to grow aphysicalFilename API.

Type of Change

  • [] 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📝 Documentation update
  • 🔧 Refactoring (no functional changes, no api changes)

Detailed Changes

  • packages/typescript-estree/src/useProgramFromProjectService.ts:

    • Introduced a new helperisVirtualFilePath(filePathAbsolute: string): boolean that:
      • Immediately returnsfalse if the exactfilePathAbsolute exists on disk.
      • Otherwise walks up the path towards the filesystem root and checks ancestors withfs.statSync.
      • Treats the path asvirtual if it finds a parent that is an actual file, which matches processor-style layouts such as:
        • <project>/docs/example.md/0.ts
        • <project>/rules/EXAMPLE.mdc/0_0.ts
      • Falls back tofalse on any unexpected error, preserving robustness.
    • Adjusted the project-service decision logic inuseProgramFromProjectService:
      • Previously:
        • isDefaultProjectAllowed was derived solely fromallowDefaultProject globs.
        • Virtual child paths likefile.mdc/0_0.ts were not recognized and thus caused “not found by the project service” errors unless manually allow-listed.
      • Now:
        • isDefaultProjectAllowed is computed as:
          constisVirtualFile=isVirtualFilePath(filePathAbsolute);constisDefaultProjectAllowed=isVirtualFile||filePathMatchedBy(filePathRelative,serviceAndSettings.allowDefaultProject);
        • This means:
          • Real files behave exactly as before and still rely onallowDefaultProject.
          • Virtual children under a real file are implicitly allowed to use the default project without additional configuration.
    • Left all existing semantics for:
      • Non-standard extensions (DEFAULT_EXTRA_FILE_EXTENSIONS /extraFileExtensions checks).
      • Default-project file count enforcement and error messages.
      • Reload behavior (reloadProjects) andsingleRun handling.
    • The overall behavior change is narrowly scoped to virtual child paths that are:
      • Not present on disk, but
      • Have a real-file ancestor in the path.
  • packages/typescript-estree/tests/lib/useProgramFromProgramService.test.ts:

    • Added a focused unit test:

      it('treats virtual child paths under an existing file as allowed by the default project',()=>{const{ service}=createMockProjectService();constprogram={getSourceFile:vi.fn()};constvirtualFilePath=`path/docs/example.md/0.ts`;mockGetProgram.mockReturnValueOnce(program);mockCreateProjectProgram.mockReturnValueOnce(program);// Simulate that the project service does not associate the virtual path with a specific tsconfig.service.openClientFile.mockReturnValueOnce({});constfilePathAbsolute=path.normalize(`${currentDirectory}/${virtualFilePath}`);constparentMarkdownPath=path.normalize(`${currentDirectory}/path/docs/example.md`,);constexistsSpy=vi.spyOn(fs,'existsSync');conststatSpy=vi.spyOn(fs,'statSync');existsSpy.mockImplementation(p=>{constnormalized=path.normalize(String(p));if(normalized===filePathAbsolute){// The virtual child itself does not exist on disk.returnfalse;}returnfalse;});statSpy.mockImplementation(p=>{constnormalized=path.normalize(String(p));if(normalized===parentMarkdownPath){// Pretend the parent Markdown file exists on disk.return{isFile:()=>true,}asunknownasfs.Stats;}// Simulate a missing path for all other ancestors.consterror=newError('ENOENT');//@ts-expect-error - augmenting error for realism; not important to the testerror.code='ENOENT';throwerror;});constactual=useProgramFromProjectService(createProjectServiceSettings({// No allowDefaultProject globs: virtual children should still be allowed.allowDefaultProject:[],      service,}),{      ...mockParseSettings,filePath:virtualFilePath,},true,newSet(),);expect(actual).toBe(program);existsSpy.mockRestore();statSpy.mockRestore();});
    • This test explicitly verifies the new behavior:

      • WithnoallowDefaultProject globs configured.
      • For a virtual child pathpath/docs/example.md/0.ts whose parentpath/docs/example.md is treated as a real file.
      • The call touseProgramFromProjectService returns theprogram from the project service instead of throwing a “not found by the project service” error.
    • Existing tests around:

      • allowDefaultProject glob handling.
      • Non-standard extensions andextraFileExtensions.
      • Default-project matching limits.
      • setHostConfiguration behavior.
        remain unchanged and continue to validate the original behaviors.

Testing & Verification

  • Unit Tests added/passed
    • New test intests/lib/useProgramFromProjectService.test.ts for virtual child paths under an existing file.
    • ExistinguseProgramFromProjectService test suite continues to pass.
  • Manual verification steps:
    • Integrate a processor such as@eslint/markdown that produces virtual child paths (file.md/0.ts,file.mdc/0_0.ts).
    • Configure@typescript-eslint/parser withparserOptions.projectService: true.
    • Run ESLint on a Markdown / MDX /.mdc file containing TypeScript code blocks.
    • Observe that:
      • Type-aware rules now run successfully on code blocks.
      • The project service no longer reports “was not found by the project service” for virtual child paths.
      • Diagnostics continue to report thevirtual child filename (e.g.file.mdc/0_0.ts), preserving existing UX.

Breaking Changes (if any)

N/A

This change is designed to be backwards compatible:

  • Only non-existent paths that arenested under an existing file are treated as virtual children and implicitly allowed to use the default project.
  • Real files on disk and existingallowDefaultProject behavior are unchanged.
  • Processors and configs that do not rely on virtual child paths (or do not useprojectService) continue to behave as before.

@typescript-eslint
Copy link
Contributor

Thanks for the PR,@CyberT33N!

typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community.

The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately.

Thanks again!


🙏Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently onhttps://opencollective.com/typescript-eslint.

@netlify
Copy link

netlifybot commentedDec 8, 2025
edited
Loading

Deploy Preview fortypescript-eslint ready!

NameLink
🔨 Latest commit3d44e5d
🔍 Latest deploy loghttps://app.netlify.com/projects/typescript-eslint/deploys/69362c4810a2100008d91d3a
😎 Deploy Previewhttps://deploy-preview-11827--typescript-eslint.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 80 (🔴 down 15 from production)
Accessibility: 97 (no change from production)
Best Practices: 100 (no change from production)
SEO: 92 (no change from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to yourNetlify project configuration.

@nx-cloud
Copy link

nx-cloudbot commentedDec 8, 2025
edited
Loading

View yourCI Pipeline Execution ↗ for commit3d44e5d

CommandStatusDurationResult
nx run-many -t lint✅ Succeeded3m 11sView ↗
nx run-many -t typecheck✅ Succeeded2mView ↗
nx test typescript-estree --coverage=false✅ Succeeded20sView ↗
nx run integration-tests:test✅ Succeeded5sView ↗
nx test eslint-plugin-internal --coverage=false✅ Succeeded3sView ↗
nx test eslint-plugin --coverage=false✅ Succeeded3sView ↗
nx run types:build✅ Succeeded2sView ↗
nx run generate-configs✅ Succeeded6sView ↗
Additional runs (29)✅ Succeeded...View ↗

☁️Nx Cloud last updated this comment at2025-12-08 01:47:11 UTC

@codecov
Copy link

codecovbot commentedDec 8, 2025
edited
Loading

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.54%. Comparing base (32b7e89) to head (3d44e5d).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@##             main   #11827   +/-   ##=======================================  Coverage   90.53%   90.54%           =======================================  Files         523      523             Lines       53096    53122   +26       Branches     8838     8851   +13     =======================================+ Hits        48073    48099   +26  Misses       5010     5010             Partials       13       13
FlagCoverage Δ
unittest90.54% <100.00%> (+<0.01%)⬆️

Flags with carried forward coverage won't be shown.Click here to find out more.

Files with missing linesCoverage Δ
...escript-estree/src/useProgramFromProjectService.ts100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@CyberT33NCyberT33Nforce-pushed thefeat/ts-compiler-api-virtual-files-for-processor-children/main branch fromcea94af to3d44e5dCompareDecember 8, 2025 01:39
@JoshuaKGoldbergJoshuaKGoldberg marked this pull request as draftDecember 10, 2025 16:53
@JoshuaKGoldberg
Copy link
Member

Hey thanks for the PR@CyberT33N! You've clearly put a lot of work + thought into this, and it's impressive to see a first PR touch some of the most technically intricate parts of the codebase (typed linting + virtual files).

Per theContributing > Pull Requests guide linked in the PR template that you cleared, we ask that non-trivial PRs only be sent for open, accepted issues. This way we have a chance to discuss the design and desirability of changesbefore authors like you spend a lot of time implementing.

I'll also note that this PR body isvery verbose. We have a very limited maintainer bandwidth and deeply reading through the whole thing would take up an unnecessarily large amount of time in it. We're working on docs in#11416 ->#11836. The tl;dr is: regardless of whether you use AI, excessively long descriptions actually harm understandability. Pithiness is good.

Pleasefile an ✨Enhance Another Package issue and fill out the template there so we can have that discussion. I've switched this PR to a draft in the meantime, to remove it from our review queue.


To be clear, I'm not saying I/we are against fixing the root issue around virtual children. I've actually hit this problem a lot in my own repos that use both@eslint/markdown and typed linting. I'm saying that we have good + necessary process points that we need to follow to make sure we're solving the issue in the right way.

Cheers!

kirkwaiblinger reacted with thumbs up emoji

@CyberT33N
Copy link
Author

Hey thanks for the PR@CyberT33N! You've clearly put a lot of work + thought into this, and it's impressive to see a first PR touch some of the most technically intricate parts of the codebase (typed linting + virtual files).

Per theContributing > Pull Requests guide linked in the PR template that you cleared, we ask that non-trivial PRs only be sent for open, accepted issues. This way we have a chance to discuss the design and desirability of changesbefore authors like you spend a lot of time implementing.

I'll also note that this PR body isvery verbose. We have a very limited maintainer bandwidth and deeply reading through the whole thing would take up an unnecessarily large amount of time in it. We're working on docs in#11416 ->#11836. The tl;dr is: regardless of whether you use AI, excessively long descriptions actually harm understandability. Pithiness is good.

Pleasefile an ✨Enhance Another Package issue and fill out the template there so we can have that discussion. I've switched this PR to a draft in the meantime, to remove it from our review queue.

To be clear, I'm not saying I/we are against fixing the root issue around virtual children. I've actually hit this problem a lot in my own repos that use both@eslint/markdown and typed linting. I'm saying that we have good + necessary process points that we need to follow to make sure we're solving the issue in the right way.

Cheers!

Thank you very much for taking the time to write such a detailed and kind reply, and for pointing me to the correct contributing / PR process. I now understand that I should first open an ✨ Enhance Another Package issue and only then follow up with a PR, and I’ve done so for this change. I also really appreciate that you’d already been thinking about this area in the context of @eslint/markdown – that background was very helpful to me.

@JoshuaKGoldberg
Copy link
Member

Closing per#11838 (comment).

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

2 participants

@CyberT33N@JoshuaKGoldberg

[8]ページ先頭

©2009-2025 Movatter.jp