- 
                Notifications
    
You must be signed in to change notification settings  - Fork 11
 
Fix types for gjs extensions with explicit imports #134
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
base: main
Are you sure you want to change the base?
Changes from all commits
6cd56e8
              4730d4f
              4859c0e
              2d84c22
              459d9cd
              d480b24
              e51759d
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| 
          
            
          
           | 
    @@ -2,7 +2,81 @@ const fs = require('node:fs'); | |
| const { transformForLint } = require('./transforms'); | ||
| const { replaceRange } = require('./transforms'); | ||
| 
     | 
||
| let patchTs, replaceExtensions, syncMtsGtsSourceFiles, typescriptParser, isPatched, allowGjs; | ||
| let patchTs, | ||
| replaceExtensions, | ||
| syncMtsGtsSourceFiles, | ||
| typescriptParser, | ||
| isPatched, | ||
| allowGjs, | ||
| allowArbitraryExtensions; | ||
| 
     | 
||
| /** | ||
| * Helper function to find the first existing file among possible variants | ||
| * @param {string} fileName - The original file name to resolve | ||
| * @param {boolean} allowGjs - Whether .gjs files are allowed | ||
| * @param {boolean} allowArbitraryExtensions - Whether allowArbitraryExtensions is enabled | ||
| * @returns {string|null} - The first existing file path, or null if none exist | ||
| */ | ||
| function findExistingFile(fileName, allowGjs, allowArbitraryExtensions) { | ||
| // Check .gts first | ||
| const gtsFile = fileName.replace(/\.m?ts$/, '.gts'); | ||
| if (fs.existsSync(gtsFile)) return gtsFile; | ||
| 
     | 
||
| // Check .gjs (if allowed) | ||
| if (allowGjs) { | ||
| const gjsFile = fileName.replace(/\.m?js$/, '.gjs'); | ||
| if (fs.existsSync(gjsFile)) return gjsFile; | ||
| 
     | 
||
| // Check .gjs.d.ts (multiple patterns) | ||
| const gjsDtsFile1 = fileName.replace(/\.mjs\.d\.ts$/, '.gjs.d.ts'); | ||
| const gjsDtsFile2 = fileName.replace(/\.d\.mts$/, '.gjs.d.ts'); | ||
| if (fs.existsSync(gjsDtsFile1)) return gjsDtsFile1; | ||
| if (fs.existsSync(gjsDtsFile2)) return gjsDtsFile2; | ||
| 
     | 
||
| // Check .d.gjs.ts pattern (only if allowArbitraryExtensions is enabled) | ||
| if (allowArbitraryExtensions) { | ||
| const dGjsFile = fileName.replace(/\.d\.mts$/, '.d.gjs.ts'); | ||
| if (fs.existsSync(dGjsFile)) return dGjsFile; | ||
| } | ||
| } | ||
| 
     | 
||
| // Check original file | ||
| if (fs.existsSync(fileName)) return fileName; | ||
| 
     | 
||
| return null; | ||
| } | ||
| 
     | 
||
| /** | ||
| * Helper function to resolve the actual file path for reading | ||
| * @param {string} fileName - The original file name to resolve | ||
| * @param {boolean} allowGjs - Whether .gjs files are allowed | ||
| * @param {boolean} allowArbitraryExtensions - Whether allowArbitraryExtensions is enabled | ||
| * @returns {string} - The resolved file path to read from | ||
| */ | ||
| function resolveFileForReading(fileName, allowGjs, allowArbitraryExtensions) { | ||
| // Handle declaration files first (more specific patterns) | ||
| if (fileName.endsWith('.d.mts')) { | ||
| // .d.mts files could map to .gjs declaration patterns | ||
| // Only check .d.gjs.ts if allowArbitraryExtensions is enabled | ||
| if ( | ||
| allowGjs && | ||
| allowArbitraryExtensions && | ||
| fs.existsSync(fileName.replace(/\.d\.mts$/, '.d.gjs.ts')) | ||
| ) { | ||
| return fileName.replace(/\.d\.mts$/, '.d.gjs.ts'); | ||
| } else if (allowGjs && fs.existsSync(fileName.replace(/\.d\.mts$/, '.gjs.d.ts'))) { | ||
| return fileName.replace(/\.d\.mts$/, '.gjs.d.ts'); | ||
| } | ||
| } else if (allowGjs && fileName.endsWith('.mjs.d.ts')) { | ||
| return fileName.replace(/\.mjs\.d\.ts$/, '.gjs.d.ts'); | ||
| } else if (fileName.match(/\.m?ts$/) && !fileName.endsWith('.d.ts')) { | ||
| return fileName.replace(/\.m?ts$/, '.gts'); | ||
| } else if (allowGjs && fileName.match(/\.m?js$/) && !fileName.endsWith('.d.ts')) { | ||
| return fileName.replace(/\.m?js$/, '.gjs'); | ||
| } | ||
| 
     | 
||
| return fileName; | ||
| } | ||
| 
     | 
||
| try { | ||
| const parserPath = require.resolve('@typescript-eslint/parser'); | ||
| 
        
          
        
         | 
    @@ -11,9 +85,11 @@ try { | |
| const ts = require(tsPath); | ||
| typescriptParser = require('@typescript-eslint/parser'); | ||
| patchTs = function patchTs(options = {}) { | ||
| if (isPatched) return { allowGjs }; | ||
| if (isPatched) return { allowGjs, allowArbitraryExtensions }; | ||
| isPatched = true; | ||
| allowGjs = options.allowGjs !== undefined ? options.allowGjs : true; | ||
| allowArbitraryExtensions = | ||
| options.allowArbitraryExtensions !== undefined ? options.allowArbitraryExtensions : false; | ||
| const sys = { ...ts.sys }; | ||
| const newSys = { | ||
| ...ts.sys, | ||
| 
        
          
        
         | 
    @@ -25,12 +101,27 @@ try { | |
| const gjsVirtuals = allowGjs | ||
| ? results.filter((x) => x.endsWith('.gjs')).map((f) => f.replace(/\.gjs$/, '.mjs')) | ||
| : []; | ||
| return results.concat(gtsVirtuals, gjsVirtuals); | ||
| // Map .gjs.d.ts to both .mjs.d.ts AND .d.mts patterns | ||
| // Also handle .d.gjs.ts (allowArbitraryExtensions pattern for .gjs files) | ||
| const gjsDtsVirtuals = allowGjs | ||
| ? results | ||
| .filter((x) => x.endsWith('.gjs.d.ts')) | ||
| .flatMap((f) => [ | ||
| f.replace(/\.gjs\.d\.ts$/, '.mjs.d.ts'), | ||
| f.replace(/\.gjs\.d\.ts$/, '.d.mts'), | ||
| ]) | ||
| : []; | ||
| // Handle .d.gjs.ts pattern (allowArbitraryExtensions for .gjs files only) | ||
| const dGjsVirtuals = | ||
| allowGjs && allowArbitraryExtensions | ||
| ? results | ||
| .filter((x) => x.endsWith('.d.gjs.ts')) | ||
| .map((f) => f.replace(/\.d\.gjs\.ts$/, '.d.mts')) | ||
| : []; | ||
| return results.concat(gtsVirtuals, gjsVirtuals, gjsDtsVirtuals, dGjsVirtuals); | ||
| }, | ||
| fileExists(fileName) { | ||
| const gtsExists = fs.existsSync(fileName.replace(/\.m?ts$/, '.gts')); | ||
| const gjsExists = allowGjs ? fs.existsSync(fileName.replace(/\.m?js$/, '.gjs')) : false; | ||
| return gtsExists || gjsExists || fs.existsSync(fileName); | ||
| return findExistingFile(fileName, allowGjs, allowArbitraryExtensions) !== null; | ||
| }, | ||
| readFile(fname) { | ||
| let fileName = fname; | ||
| 
        
          
        
         | 
    @@ -42,25 +133,26 @@ try { | |
| try { | ||
| content = fs.readFileSync(fileName).toString(); | ||
| } catch { | ||
| if (fileName.match(/\.m?ts$/)) { | ||
| fileName = fileName.replace(/\.m?ts$/, '.gts'); | ||
| } else if (allowGjs && fileName.match(/\.m?js$/)) { | ||
| fileName = fileName.replace(/\.m?js$/, '.gjs'); | ||
| } | ||
| fileName = resolveFileForReading(fileName, allowGjs, allowArbitraryExtensions); | ||
| content = fs.readFileSync(fileName).toString(); | ||
| } | ||
| if (fileName.endsWith('.gts') || (allowGjs && fileName.endsWith('.gjs'))) { | ||
| // Only transform template files, not declaration files | ||
| if ( | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this need to account for  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, but we should clean it up. Since a file can't both end with   | 
||
| (fileName.endsWith('.gts') && !fileName.endsWith('.d.ts')) || | ||
| (allowGjs && fileName.endsWith('.gjs') && !fileName.endsWith('.d.ts')) | ||
| ) { | ||
| try { | ||
| content = transformForLint(content).output; | ||
| } catch (e) { | ||
| console.error('failed to transformForLint for gts/gjs processing'); | ||
| console.error(e); | ||
| } | ||
| } | ||
| // Only replace extensions in non-declaration files | ||
| if ( | ||
| (!fileName.endsWith('.d.ts') && fileName.endsWith('.ts')) || | ||
| fileName.endsWith('.gts') || | ||
| (allowGjs && fileName.endsWith('.gjs')) | ||
| (fileName.endsWith('.gts') && !fileName.endsWith('.d.ts')) || | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should clean this up too.  | 
||
| (allowGjs && fileName.endsWith('.gjs') && !fileName.endsWith('.d.ts')) | ||
| ) { | ||
| try { | ||
| content = replaceExtensions(content); | ||
| 
        
          
        
         | 
    @@ -73,17 +165,32 @@ try { | |
| }, | ||
| }; | ||
| ts.setSys(newSys); | ||
| return { allowGjs }; | ||
| return { allowGjs, allowArbitraryExtensions }; | ||
| }; | ||
| 
     | 
||
| replaceExtensions = function replaceExtensions(code) { | ||
| let jsCode = code; | ||
| const sourceFile = ts.createSourceFile('__x__.ts', code, ts.ScriptTarget.Latest); | ||
| const length = jsCode.length; | ||
| for (const b of sourceFile.statements) { | ||
| if (b.kind === ts.SyntaxKind.ImportDeclaration && b.moduleSpecifier.text.endsWith('.gts')) { | ||
| const value = b.moduleSpecifier.text.replace(/\.gts$/, '.mts'); | ||
| jsCode = replaceRange(jsCode, b.moduleSpecifier.pos + 2, b.moduleSpecifier.end - 1, value); | ||
| if (b.kind === ts.SyntaxKind.ImportDeclaration) { | ||
| if (b.moduleSpecifier.text.endsWith('.gts')) { | ||
| const value = b.moduleSpecifier.text.replace(/\.gts$/, '.mts'); | ||
| jsCode = replaceRange( | ||
| jsCode, | ||
| b.moduleSpecifier.pos + 2, | ||
| b.moduleSpecifier.end - 1, | ||
| value | ||
| ); | ||
| } else if (allowGjs && b.moduleSpecifier.text.endsWith('.gjs')) { | ||
| const value = b.moduleSpecifier.text.replace(/\.gjs$/, '.mjs'); | ||
| jsCode = replaceRange( | ||
| jsCode, | ||
| b.moduleSpecifier.pos + 2, | ||
| b.moduleSpecifier.end - 1, | ||
| value | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| if (length !== jsCode.length) { | ||
| 
          
            
          
           | 
    ||
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.
how does this situation happen?
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.
I'm not sure. I wish I knew! I've seen it actually happen with allowGjs.