diff --git a/packages/wbfy/src/generators/oxfmtConfig.ts b/packages/wbfy/src/generators/oxfmtConfig.ts index 12bb1a44..32d93f73 100644 --- a/packages/wbfy/src/generators/oxfmtConfig.ts +++ b/packages/wbfy/src/generators/oxfmtConfig.ts @@ -42,10 +42,10 @@ function getConfigContent(config: PackageConfig): string { `// oxlint-disable unicorn/prefer-module -- Oxfmt config files are only auto-discovered as .ts, and CommonJS avoids Node typeless ESM warnings. const oxfmtConfig = require('@willbooster/oxfmt-config'); -const config = oxfmtConfig.default ?? oxfmtConfig;` +const oxfmtResolvedConfig = oxfmtConfig.default ?? oxfmtConfig;` )} -${managedConfigBlocks.getBlock('export', 'module.exports = config;')} +${managedConfigBlocks.getBlock('export', 'module.exports = oxfmtResolvedConfig;')} `; } diff --git a/packages/wbfy/src/generators/oxlintConfig.ts b/packages/wbfy/src/generators/oxlintConfig.ts index 3dffba99..60c7cf58 100644 --- a/packages/wbfy/src/generators/oxlintConfig.ts +++ b/packages/wbfy/src/generators/oxlintConfig.ts @@ -26,11 +26,13 @@ export async function generateOxlintConfig(config: PackageConfig, _rootConfig: P const desiredContent = shouldPreservePublishedLinterConfig && existingContent ? existingContent - : managedConfigBlocks.getConfigContent({ - desiredContent: getConfigContent(config), - existingContent, - filePath, - }); + : replaceLegacyConfigReferences( + managedConfigBlocks.getConfigContent({ + desiredContent: getConfigContent(config), + existingContent, + filePath, + }) + ); const promises: Promise[] = []; if (!shouldPreservePublishedLinterConfig) { @@ -57,6 +59,10 @@ export async function generateOxlintConfig(config: PackageConfig, _rootConfig: P }); } +function replaceLegacyConfigReferences(content: string): string { + return content.replaceAll('config.', 'oxlintResolvedConfig.'); +} + function getConfigContent(config: PackageConfig): string { // Do not collapse this to a static import for every package. CommonJS packages // type-check auto-discovered oxlint.config.ts as CommonJS, so importing the ESM @@ -68,15 +74,15 @@ function getConfigContent(config: PackageConfig): string { `// oxlint-disable unicorn/prefer-module -- Oxlint only auto-discovers .ts config files, and CommonJS avoids Node typeless ESM warnings. const oxlintBaseConfig = require('@willbooster/oxlint-config'); -const config = oxlintBaseConfig.default ?? oxlintBaseConfig;` +const oxlintResolvedConfig = oxlintBaseConfig.default ?? oxlintBaseConfig;` )} -${managedConfigBlocks.getBlock('export', 'module.exports = config;')} +${managedConfigBlocks.getBlock('export', 'module.exports = oxlintResolvedConfig;')} `; } - return `${managedConfigBlocks.getBlock('base', "import config from '@willbooster/oxlint-config';")} + return `${managedConfigBlocks.getBlock('base', "import oxlintResolvedConfig from '@willbooster/oxlint-config';")} -${managedConfigBlocks.getBlock('export', 'export default config;')} +${managedConfigBlocks.getBlock('export', 'export default oxlintResolvedConfig;')} `; } diff --git a/packages/wbfy/src/generators/tsconfig.ts b/packages/wbfy/src/generators/tsconfig.ts index 56f47b8a..c16da806 100644 --- a/packages/wbfy/src/generators/tsconfig.ts +++ b/packages/wbfy/src/generators/tsconfig.ts @@ -141,6 +141,7 @@ async function cleanupLegacyTsconfigModuleSettings(config: PackageConfig): Promi const settings = JSON.parse(await fs.promises.readFile(filePath, 'utf8')) as TsConfigJson; normalizeNextTsconfigModuleSettings(settings.compilerOptions); normalizeNextTsconfigPathAliases(settings.compilerOptions); + addScriptsIncludeForFrameworkProject(settings); await promisePool.run(() => fsUtil.generateFile(filePath, JSON.stringify(settings, undefined, 2))); } catch { // Next/Blitz own their tsconfig shape, but TypeScript 6 no longer accepts @@ -148,6 +149,16 @@ async function cleanupLegacyTsconfigModuleSettings(config: PackageConfig): Promi } } +function addScriptsIncludeForFrameworkProject(settings: TsConfigJson): void { + // Omitting include lets framework tsconfigs keep TypeScript's default + // "all TS/TSX files" behavior, which already covers scripts. + if (!settings.include) return; + if (settings.include.includes('scripts/**/*')) return; + + settings.include.push('scripts/**/*'); + settings.include.sort(); +} + function normalizeNextTsconfigModuleSettings(compilerOptions: TsConfigJson.CompilerOptions | undefined): void { if (!compilerOptions) return; if ( diff --git a/packages/wbfy/test/oxlintConfigGenerator.test.ts b/packages/wbfy/test/oxlintConfigGenerator.test.ts index f108406a..af7fd25f 100644 --- a/packages/wbfy/test/oxlintConfigGenerator.test.ts +++ b/packages/wbfy/test/oxlintConfigGenerator.test.ts @@ -35,8 +35,8 @@ export default config; expect(content).toContain('// wbfy:start oxlint-base'); expect(content).toContain('// wbfy:start oxlint-export'); expect(content).toContain("const oxlintBaseConfig = require('@willbooster/oxlint-config');"); - expect(content).toContain('const config = oxlintBaseConfig.default ?? oxlintBaseConfig;'); - expect(content).toContain('module.exports = config;'); + expect(content).toContain('const oxlintResolvedConfig = oxlintBaseConfig.default ?? oxlintBaseConfig;'); + expect(content).toContain('module.exports = oxlintResolvedConfig;'); expect(content).not.toContain("config.ignorePatterns?.push('generated/**');"); }); @@ -61,8 +61,8 @@ module.exports = staleConfig; const content = await readOxlintConfig(dirPath); expect(content).toContain("const oxlintBaseConfig = require('@willbooster/oxlint-config');"); - expect(content).toContain("config.ignorePatterns?.push('generated/**');"); - expect(content).toContain('module.exports = config;'); + expect(content).toContain("oxlintResolvedConfig.ignorePatterns?.push('generated/**');"); + expect(content).toContain('module.exports = oxlintResolvedConfig;'); expect(content).not.toContain('staleConfig'); }); @@ -73,8 +73,8 @@ test('generates esm oxlint config for esm packages', async () => { await promisePool.promiseAll(); const content = await readOxlintConfig(dirPath); - expect(content).toContain("import config from '@willbooster/oxlint-config';"); - expect(content).toContain('export default config;'); + expect(content).toContain("import oxlintResolvedConfig from '@willbooster/oxlint-config';"); + expect(content).toContain('export default oxlintResolvedConfig;'); }); function createTempDir(): string { diff --git a/packages/wbfy/test/tsconfigGenerator.test.ts b/packages/wbfy/test/tsconfigGenerator.test.ts index 1711be24..55aaf050 100644 --- a/packages/wbfy/test/tsconfigGenerator.test.ts +++ b/packages/wbfy/test/tsconfigGenerator.test.ts @@ -219,6 +219,60 @@ test('normalizes Next.js aliases for TypeScript 6 linting', async () => { expect(tsconfig.compilerOptions.paths).toEqual({ '@/*': ['./src/*'] }); }); +test('adds scripts include for Next.js projects', async () => { + const dirPath = createTempDir(); + await fs.promises.writeFile( + path.join(dirPath, 'tsconfig.json'), + JSON.stringify({ + compilerOptions: { + moduleResolution: 'bundler', + }, + include: ['src/**/*'], + }) + ); + + await generateTsconfig( + createConfig({ + dirPath, + depending: { + ...createConfig().depending, + next: true, + }, + }) + ); + await promisePool.promiseAll(); + + const tsconfig = await readTsconfig(dirPath); + expect(tsconfig.include).toEqual(['scripts/**/*', 'src/**/*']); +}); + +test('does not duplicate scripts include for Next.js projects', async () => { + const dirPath = createTempDir(); + await fs.promises.writeFile( + path.join(dirPath, 'tsconfig.json'), + JSON.stringify({ + compilerOptions: { + moduleResolution: 'bundler', + }, + include: ['scripts/**/*', 'src/**/*'], + }) + ); + + await generateTsconfig( + createConfig({ + dirPath, + depending: { + ...createConfig().depending, + next: true, + }, + }) + ); + await promisePool.promiseAll(); + + const tsconfig = await readTsconfig(dirPath); + expect(tsconfig.include).toEqual(['scripts/**/*', 'src/**/*']); +}); + function createTempDir(): string { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'wbfy-tsconfig-')); tempDirs.push(tempDir);