-
Notifications
You must be signed in to change notification settings - Fork 441
feat: respect tsconfig excludes when using swc #3276
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: master
Are you sure you want to change the base?
Changes from all commits
8b4941b
124eca7
56eef23
99975c4
25f9438
f1107f1
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 |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| import { swcDefaultsFactory } from '../../../../lib/compiler/defaults/swc-defaults'; | ||
|
|
||
| describe('swcDefaultsFactory', () => { | ||
| it('should return default configuration when no options are provided', () => { | ||
| const result = swcDefaultsFactory(); | ||
|
|
||
| expect(result.swcOptions).toEqual({ | ||
| sourceMaps: undefined, | ||
| module: { | ||
| type: 'commonjs', | ||
| }, | ||
| jsc: { | ||
| target: 'es2021', | ||
| parser: { | ||
| syntax: 'typescript', | ||
| decorators: true, | ||
| dynamicImport: true, | ||
| }, | ||
| transform: { | ||
| legacyDecorator: true, | ||
| decoratorMetadata: true, | ||
| useDefineForClassFields: false, | ||
| }, | ||
| keepClassNames: true, | ||
| baseUrl: undefined, | ||
| paths: undefined, | ||
| }, | ||
| minify: false, | ||
| swcrc: true, | ||
| }); | ||
|
|
||
| expect(result.cliOptions).toEqual({ | ||
| outDir: 'dist', | ||
| filenames: ['src'], | ||
| sync: false, | ||
| extensions: ['.js', '.ts'], | ||
| copyFiles: false, | ||
| includeDotfiles: false, | ||
| ignore: undefined, | ||
| quiet: false, | ||
| watch: false, | ||
| stripLeadingPaths: true, | ||
| }); | ||
| }); | ||
|
|
||
| describe('swcOptions', () => { | ||
| it('should set sourceMaps to true if sourceMap is true in tsOptions', () => { | ||
| const result = swcDefaultsFactory({ sourceMap: true, exclude: [] }); | ||
| expect(result.swcOptions.sourceMaps).toBe(true); | ||
| }); | ||
|
|
||
| it('should set sourceMaps to "inline" if inlineSourceMap is true in tsOptions', () => { | ||
| const result = swcDefaultsFactory({ inlineSourceMap: true, exclude: [] }); | ||
| expect(result.swcOptions.sourceMaps).toBe('inline'); | ||
| }); | ||
|
|
||
| it('should set baseUrl and paths from tsOptions', () => { | ||
| const tsOptions = { | ||
| baseUrl: './', | ||
| paths: { | ||
| '@app/*': ['src/*'], | ||
| }, | ||
| exclude: [], | ||
| }; | ||
| const result = swcDefaultsFactory(tsOptions); | ||
| expect(result.swcOptions.jsc.baseUrl).toBe('./'); | ||
| expect(result.swcOptions.jsc.paths).toEqual({ | ||
| '@app/*': ['src/*'], | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('cliOptions', () => { | ||
| it('should use sourceRoot from configuration for filenames', () => { | ||
| const configuration = { sourceRoot: 'custom-src' }; | ||
| const result = swcDefaultsFactory(undefined, configuration); | ||
| expect(result.cliOptions.filenames).toEqual(['custom-src']); | ||
| }); | ||
|
|
||
| it('should use outDir from tsOptions and convert path', () => { | ||
| const tsOptions = { outDir: 'build\\dist', exclude: [] }; | ||
| const result = swcDefaultsFactory(tsOptions); | ||
| expect(result.cliOptions.outDir).toBe('build/dist'); | ||
| }); | ||
|
|
||
| it('should handle Windows specific path prefixes in outDir', () => { | ||
| const tsOptions = { outDir: '\\\\?\\C:\\dist', exclude: [] }; | ||
| const result = swcDefaultsFactory(tsOptions); | ||
| expect(result.cliOptions.outDir).toBe('C:/dist'); | ||
| }); | ||
|
|
||
| it('should set ignore if exclude is provided in tsOptions', () => { | ||
| const tsOptions = { exclude: ['test/**/*.ts'] }; | ||
| const result = swcDefaultsFactory(tsOptions); | ||
| expect(result.cliOptions.ignore).toEqual(['test/**/*.ts']); | ||
| }); | ||
|
|
||
| it('should merge builder options from configuration', () => { | ||
| const configuration = { | ||
| compilerOptions: { | ||
| builder: { | ||
| type: 'swc' as const, | ||
| options: { | ||
| watch: true, | ||
| sync: true, | ||
| copyFiles: true, | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
| const result = swcDefaultsFactory(undefined, configuration); | ||
| expect(result.cliOptions.watch).toBe(true); | ||
| expect(result.cliOptions.sync).toBe(true); | ||
| expect(result.cliOptions.copyFiles).toBe(true); | ||
| }); | ||
|
|
||
| it('should not merge builder options if builder is a string', () => { | ||
| const configuration = { | ||
| compilerOptions: { | ||
| builder: 'swc', | ||
| }, | ||
| }; | ||
|
|
||
| const result = swcDefaultsFactory(undefined, configuration as any); | ||
| expect(result.cliOptions.watch).toBe(false); | ||
| expect(result.cliOptions.sync).toBe(false); | ||
| expect(result.cliOptions.copyFiles).toBe(false); | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| import { TsConfigProvider } from '../../../../lib/compiler/helpers/tsconfig-provider'; | ||
| import { TypeScriptBinaryLoader } from '../../../../lib/compiler/typescript-loader'; | ||
| import { join } from 'path'; | ||
| import * as fs from 'fs'; | ||
|
|
||
| jest.mock('fs'); | ||
|
|
||
| describe('TsConfigProvider', () => { | ||
| let provider: TsConfigProvider; | ||
| let typescriptLoaderMock: {load: jest.SpyInstance}; | ||
| let tsBinaryMock: {getParsedCommandLineOfConfigFile: jest.Mock; sys: object}; | ||
|
|
||
| beforeEach(() => { | ||
| const typescriptLoader = new TypeScriptBinaryLoader(); | ||
| provider = new TsConfigProvider(typescriptLoader); | ||
| tsBinaryMock = { | ||
| getParsedCommandLineOfConfigFile: jest.fn(), | ||
| sys: {}, | ||
| }; | ||
|
|
||
| typescriptLoaderMock = { | ||
| load: jest | ||
| .spyOn(typescriptLoader, 'load') | ||
| .mockReturnValue(tsBinaryMock as any) | ||
| }; | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| jest.restoreAllMocks(); | ||
| jest.clearAllMocks(); | ||
| }); | ||
|
|
||
| describe('getByConfigFilename', () => { | ||
| it('should throw an error if config file does not exist', () => { | ||
| const configFilename = 'tsconfig.json'; | ||
| (fs.existsSync as jest.Mock).mockReturnValue(false); | ||
|
|
||
| expect(() => provider.getByConfigFilename(configFilename)).toThrow( | ||
| 'Could not find TypeScript configuration file', | ||
| ); | ||
| }); | ||
|
|
||
| it('should return parsed command line if config file exists', () => { | ||
| const configFilename = 'tsconfig.json'; | ||
| const configPath = join(process.cwd(), configFilename); | ||
| const mockParsedCmd = { | ||
| options: { outDir: 'dist' }, | ||
| fileNames: ['src/main.ts'], | ||
| projectReferences: [], | ||
| raw: { exclude: ['node_modules'] }, | ||
| }; | ||
|
|
||
| (fs.existsSync as jest.Mock).mockReturnValue(true); | ||
| tsBinaryMock.getParsedCommandLineOfConfigFile.mockReturnValue(mockParsedCmd); | ||
|
|
||
| const result = provider.getByConfigFilename(configFilename); | ||
|
|
||
| expect(fs.existsSync).toHaveBeenCalledWith(configPath); | ||
| expect(typescriptLoaderMock.load).toHaveBeenCalled(); | ||
| expect(tsBinaryMock.getParsedCommandLineOfConfigFile).toHaveBeenCalledWith( | ||
| configPath, | ||
| undefined, | ||
| tsBinaryMock.sys, | ||
| ); | ||
| expect(result).toEqual({ | ||
| options: { | ||
| outDir: 'dist', | ||
| exclude: ['node_modules'], | ||
| }, | ||
| fileNames: ['src/main.ts'], | ||
| projectReferences: [], | ||
| }); | ||
| }); | ||
|
|
||
| it('should handle missing exclude in raw config', () => { | ||
| const configFilename = 'tsconfig.json'; | ||
| const mockParsedCmd = { | ||
| options: { outDir: 'dist' }, | ||
| fileNames: ['src/main.ts'], | ||
| projectReferences: [], | ||
| raw: {}, | ||
| }; | ||
|
|
||
| (fs.existsSync as jest.Mock).mockReturnValue(true); | ||
| tsBinaryMock.getParsedCommandLineOfConfigFile.mockReturnValue(mockParsedCmd); | ||
|
|
||
| const result = provider.getByConfigFilename(configFilename); | ||
|
|
||
| expect(result.options.exclude).toEqual([]); | ||
| }); | ||
|
|
||
| it('should handle wrongly typed exclude in raw config', () => { | ||
| const configFilename = 'tsconfig.json'; | ||
| const mockParsedCmd = { | ||
| options: { outDir: 'dist' }, | ||
| fileNames: ['src/main.ts'], | ||
| projectReferences: [], | ||
| raw: { exclude: 'not-an-array' as unknown as string[] }, | ||
| }; | ||
|
|
||
| (fs.existsSync as jest.Mock).mockReturnValue(true); | ||
| tsBinaryMock.getParsedCommandLineOfConfigFile.mockReturnValue(mockParsedCmd); | ||
|
|
||
| const result1 = provider.getByConfigFilename(configFilename); | ||
|
|
||
| expect(result1.options.exclude).toEqual([]); | ||
|
|
||
| mockParsedCmd.raw.exclude = [0, false] as unknown as string[]; | ||
| tsBinaryMock.getParsedCommandLineOfConfigFile.mockReturnValue(mockParsedCmd); | ||
|
|
||
| const result2 = provider.getByConfigFilename(configFilename); | ||
|
|
||
| expect(result2.options.exclude).toEqual([]); | ||
| }); | ||
|
|
||
| it('should correctly parse the config from the real TS binary', () => { | ||
| const configFilename = 'tsconfig.json'; | ||
| const configPath = join(process.cwd(), configFilename); | ||
| const tsconfigContent = JSON.stringify({ | ||
| compilerOptions: { | ||
| outDir: 'dist', | ||
| }, | ||
| exclude: ['node_modules', 'dist'], | ||
| }); | ||
|
|
||
| (fs.existsSync as jest.Mock).mockReturnValue(true); | ||
| (fs.readFileSync as jest.Mock).mockReturnValue(tsconfigContent); | ||
| typescriptLoaderMock.load.mockRestore(); | ||
|
|
||
| const result = provider.getByConfigFilename(configFilename); | ||
|
|
||
| expect(result.options.outDir).toContain('dist'); | ||
| expect(result.options.exclude).toEqual(['node_modules', 'dist']); | ||
| expect(result.fileNames).toBeDefined(); | ||
|
|
||
| expect(fs.readFileSync).toHaveBeenCalledWith(configPath); | ||
|
||
| }); | ||
| }); | ||
| }); | ||
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.
The
TsConfigProviderOutputtype is imported from'../lib/compiler/helpers/tsconfig-provider'at line 27, butTsConfigProvideris already imported from the same module at line 10. These two imports from the same module should be combined into a single import statement. Additionally, the new import is placed after thewebpackrequire statement, breaking the grouping of ES module imports. It should be merged with the existing import at line 10.