Skip to content

Commit

Permalink
feat: overwrite other fields in tsconfig.json (#440)
Browse files Browse the repository at this point in the history
As we have full control over the config file content, we can easily overwrite other fields like `include` or `exclude`. It can be useful, for example, if you don't want to type-check storybook files in your webpack compilation. Now you don't have to create a separate tsconfig.json file to accomplish that.

BREAKING CHANGE: 🧨 `typescript.compilerOptions` option changed to the
`typescript.configOverwrite.compilerOptions` option
  • Loading branch information
piotr-oles committed Jun 6, 2020
1 parent 2b72fd0 commit e812f18
Show file tree
Hide file tree
Showing 14 changed files with 178 additions and 141 deletions.
24 changes: 12 additions & 12 deletions README.md
Expand Up @@ -153,18 +153,18 @@ Options passed to the plugin constructor will overwrite options from the cosmico

Options for the TypeScript checker (`typescript` option object).

| Name | Type | Default value | Description |
| -------------------- | --------- | -------------------------------------------------------------------------------------- | ----------- |
| `enabled` | `boolean` | `true` | If `true`, it enables TypeScript checker. |
| `memoryLimit` | `number` | `2048` | Memory limit for the checker process in MB. If the process exits with the allocation failed error, try to increase this number. |
| `configFile` | `string` | `'tsconfig.json'` | Path to the `tsconfig.json` file (path relative to the `compiler.options.context` or absolute path) |
| `context` | `string` | `dirname(configuration.configFile)` | The base path for finding files specified in the `tsconfig.json`. Same as the `context` option from the [ts-loader](https://github.com/TypeStrong/ts-loader#context). Useful if you want to keep your `tsconfig.json` in an external package. Keep in mind that **not** having a `tsconfig.json` in your project root can cause different behaviour between `fork-ts-checker-webpack-plugin` and `tsc`. When using editors like `VS Code` it is advised to add a `tsconfig.json` file to the root of the project and extend the config file referenced in option `configFile`. |
| `build` | `boolean` | `false` | The equivalent of the `--build` flag for the `tsc` command. |
| `mode` | `'readonly'` or `'write-tsbuildinfo'` or `'write-references'` | `'write-tsbuildinfo'` | If you use the `babel-loader`, it's recommended to use `write-references` mode to improve initial compilation time. If you use `ts-loader`, it's recommended to use `write-tsbuildinfo` mode to not overwrite filed emitted by the `ts-loader`. |
| `compilerOptions` | `object` | `{ skipLibCheck: true, sourceMap: false, inlineSourceMap: false, incremental: true }` | These options will overwrite compiler options from the `tsconfig.json` file. |
| `diagnosticsOptions` | `object` | `{ syntactic: false, semantic: true, declaration: false, global: false }` | Settings to select which diagnostics do we want to perform. |
| `extensions` | `object` | `{}` | See [TypeScript extensions options](#typescript-extensions-options). |
| `profile` | `boolean` | `false` | Measures and prints timings related to the TypeScript performance. |
| Name | Type | Default value | Description |
| -------------------- | --------- | ---------------------------------------------------------------------------------------------------------- | ----------- |
| `enabled` | `boolean` | `true` | If `true`, it enables TypeScript checker. |
| `memoryLimit` | `number` | `2048` | Memory limit for the checker process in MB. If the process exits with the allocation failed error, try to increase this number. |
| `configFile` | `string` | `'tsconfig.json'` | Path to the `tsconfig.json` file (path relative to the `compiler.options.context` or absolute path) |
| `configOverwrite` | `object` | `{ compilerOptions: { skipLibCheck: true, sourceMap: false, inlineSourceMap: false, incremental: true } }` | This configuration will overwrite configuration from the `tsconfig.json` file. Supported fields are: `extends`, `compilerOptions`, `include`, `exclude`, `files`, and `references`. |
| `context` | `string` | `dirname(configuration.configFile)` | The base path for finding files specified in the `tsconfig.json`. Same as the `context` option from the [ts-loader](https://github.com/TypeStrong/ts-loader#context). Useful if you want to keep your `tsconfig.json` in an external package. Keep in mind that **not** having a `tsconfig.json` in your project root can cause different behaviour between `fork-ts-checker-webpack-plugin` and `tsc`. When using editors like `VS Code` it is advised to add a `tsconfig.json` file to the root of the project and extend the config file referenced in option `configFile`. |
| `build` | `boolean` | `false` | The equivalent of the `--build` flag for the `tsc` command. |
| `mode` | `'readonly'` or `'write-tsbuildinfo'` or `'write-references'` | `'write-tsbuildinfo'` | If you use the `babel-loader`, it's recommended to use `write-references` mode to improve initial compilation time. If you use `ts-loader`, it's recommended to use `write-tsbuildinfo` mode to not overwrite filed emitted by the `ts-loader`. |
| `diagnosticsOptions` | `object` | `{ syntactic: false, semantic: true, declaration: false, global: false }` | Settings to select which diagnostics do we want to perform. |
| `extensions` | `object` | `{}` | See [TypeScript extensions options](#typescript-extensions-options). |
| `profile` | `boolean` | `false` | Measures and prints timings related to the TypeScript performance. |

#### TypeScript extensions options

Expand Down
10 changes: 10 additions & 0 deletions src/typescript-reporter/TypeScriptConfigurationOverwrite.ts
@@ -0,0 +1,10 @@
interface TypeScriptConfigurationOverwrite {
extends?: string;
compilerOptions?: object;
include?: string[];
exclude?: string[];
files?: string[];
references?: { path: string; prepend?: boolean }[];
}

export { TypeScriptConfigurationOverwrite };
15 changes: 9 additions & 6 deletions src/typescript-reporter/TypeScriptReporterConfiguration.ts
Expand Up @@ -8,16 +8,16 @@ import {
createTypeScriptVueExtensionConfiguration,
TypeScriptVueExtensionConfiguration,
} from './extension/vue/TypeScriptVueExtensionConfiguration';
import { TypeScriptConfigurationOverwrite } from './TypeScriptConfigurationOverwrite';

interface TypeScriptReporterConfiguration {
enabled: boolean;
memoryLimit: number;
configFile: string;
configOverwrite: TypeScriptConfigurationOverwrite;
build: boolean;
context: string;
mode: 'readonly' | 'write-tsbuildinfo' | 'write-references';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
compilerOptions: any;
diagnosticOptions: TypeScriptDiagnosticsOptions;
extensions: {
vue: TypeScriptVueExtensionConfiguration;
Expand Down Expand Up @@ -62,11 +62,14 @@ function createTypeScriptReporterConfiguration(
profile: false,
...optionsAsObject,
configFile: configFile,
context: optionsAsObject.context || path.dirname(configFile),
compilerOptions: {
...defaultCompilerOptions,
...(optionsAsObject.compilerOptions || {}),
configOverwrite: {
...(optionsAsObject.configOverwrite || {}),
compilerOptions: {
...defaultCompilerOptions,
...((optionsAsObject.configOverwrite || {}).compilerOptions || {}),
},
},
context: optionsAsObject.context || path.dirname(configFile),
extensions: {
vue: createTypeScriptVueExtensionConfiguration(
optionsAsObject.extensions ? optionsAsObject.extensions.vue : undefined
Expand Down
3 changes: 2 additions & 1 deletion src/typescript-reporter/TypeScriptReporterOptions.ts
@@ -1,16 +1,17 @@
import { TypeScriptDiagnosticsOptions } from './TypeScriptDiagnosticsOptions';
import { TypeScriptVueExtensionOptions } from './extension/vue/TypeScriptVueExtensionOptions';
import { TypeScriptConfigurationOverwrite } from './TypeScriptConfigurationOverwrite';

type TypeScriptReporterOptions =
| boolean
| {
enabled?: boolean;
memoryLimit?: number;
configFile?: string;
configOverwrite?: TypeScriptConfigurationOverwrite;
context?: string;
build?: boolean;
mode?: 'readonly' | 'write-tsbuildinfo' | 'write-references';
compilerOptions?: object;
diagnosticOptions?: Partial<TypeScriptDiagnosticsOptions>;
extensions?: {
vue?: TypeScriptVueExtensionOptions;
Expand Down
30 changes: 16 additions & 14 deletions src/typescript-reporter/reporter/TypeScriptConfigurationParser.ts
@@ -1,34 +1,36 @@
import * as ts from 'typescript';
import { TypeScriptConfigurationOverwrite } from '../TypeScriptConfigurationOverwrite';

function parseTypeScriptConfiguration(
configFileName: string,
configFileContext: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
customCompilerOptions: any,
configOverwriteJSON: TypeScriptConfigurationOverwrite,
parseConfigFileHost: ts.ParseConfigFileHost
): ts.ParsedCommandLine {
// convert jsonCompilerOptions to ts.CompilerOptions
const customCompilerOptionsConvertResults = ts.convertCompilerOptionsFromJson(
customCompilerOptions,
configFileContext
);
const parsedConfigFileJSON = ts.readConfigFile(configFileName, parseConfigFileHost.readFile);

const overwrittenConfigFileJSON = {
...(parsedConfigFileJSON.config || {}),
...configOverwriteJSON,
compilerOptions: {
...((parsedConfigFileJSON.config || {}).compilerOptions || {}),
...(configOverwriteJSON.compilerOptions || {}),
},
};

const parsedConfigFile = ts.parseJsonSourceFileConfigFileContent(
ts.readJsonConfigFile(configFileName, parseConfigFileHost.readFile),
const parsedConfigFile = ts.parseJsonConfigFileContent(
overwrittenConfigFileJSON,
parseConfigFileHost,
configFileContext,
customCompilerOptionsConvertResults.options || {}
configFileContext
);
if (customCompilerOptionsConvertResults.errors) {
parsedConfigFile.errors.push(...customCompilerOptionsConvertResults.errors);
}

return {
...parsedConfigFile,
options: {
...parsedConfigFile.options,
configFilePath: configFileName,
},
errors: parsedConfigFileJSON.error ? [parsedConfigFileJSON.error] : parsedConfigFile.errors,
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/typescript-reporter/reporter/TypeScriptReporter.ts
Expand Up @@ -119,7 +119,7 @@ function createTypeScriptReporter(configuration: TypeScriptReporterConfiguration
parsedConfiguration = parseTypeScriptConfiguration(
configuration.configFile,
configuration.context,
configuration.compilerOptions,
configuration.configOverwrite,
{
...system,
onUnRecoverableConfigFileDiagnostic: (diagnostic) => {
Expand Down
63 changes: 0 additions & 63 deletions test/e2e/TypeScriptCompilerOptions.spec.ts

This file was deleted.

2 changes: 1 addition & 1 deletion test/e2e/TypeScriptConfigurationChange.spec.ts
Expand Up @@ -60,7 +60,7 @@ describe('TypeScript Configuration Change', () => {
expect(errors.length).toBeGreaterThan(0);

// revert the change
await sandbox.patch('tsconfig.json', '"lib": ["ES6"]', '"lib": ["DOM", "ES6"],');
await sandbox.patch('tsconfig.json', '"lib": ["ES6"],', '"lib": ["DOM", "ES6"]');

await driver.waitForNoErrors();
}
Expand Down
70 changes: 70 additions & 0 deletions test/e2e/TypeScriptConfigurationOverwrite.spec.ts
@@ -0,0 +1,70 @@
import { createSandbox, FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION, Sandbox } from './sandbox/Sandbox';
import { readFixture } from './sandbox/Fixture';
import { join } from 'path';
import {
createWebpackDevServerDriver,
WEBPACK_CLI_VERSION,
WEBPACK_DEV_SERVER_VERSION,
WebpackDevServerDriver,
} from './sandbox/WebpackDevServerDriver';

describe('TypeScript Compiler Options parsing', () => {
let sandbox: Sandbox;

beforeAll(async () => {
sandbox = await createSandbox();
});

beforeEach(async () => {
await sandbox.reset();
});

afterAll(async () => {
await sandbox.cleanup();
});

it.each([
{ typescript: '2.7.1' },
{ typescript: '~3.0.0' },
{ typescript: '~3.6.0' },
{ typescript: '^3.8.0' },
])('reports errors because of the misconfiguration', async ({ typescript }) => {
await sandbox.load([
await readFixture(join(__dirname, 'fixtures/environment/typescript-basic.fixture'), {
FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION: JSON.stringify(
FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION
),
TS_LOADER_VERSION: JSON.stringify('^5.0.0'),
TYPESCRIPT_VERSION: JSON.stringify(typescript),
WEBPACK_VERSION: JSON.stringify('^4.0.0'),
WEBPACK_CLI_VERSION: JSON.stringify(WEBPACK_CLI_VERSION),
WEBPACK_DEV_SERVER_VERSION: JSON.stringify(WEBPACK_DEV_SERVER_VERSION),
ASYNC: JSON.stringify(false),
}),
await readFixture(join(__dirname, 'fixtures/implementation/typescript-basic.fixture')),
]);

let driver: WebpackDevServerDriver;
let errors: string[];

await sandbox.write(
'fork-ts-checker.config.js',
'module.exports = { typescript: { configOverwrite: { compilerOptions: { target: "ES3", lib: ["ES3"] } } } };'
);

driver = createWebpackDevServerDriver(sandbox.spawn('npm run webpack-dev-server'), false);
errors = await driver.waitForErrors();
expect(errors.length).toBeGreaterThan(0);
await sandbox.kill(driver.process);

await sandbox.write(
'fork-ts-checker.config.js',
'module.exports = { typescript: { configOverwrite: { include: [] } } };'
);

driver = createWebpackDevServerDriver(sandbox.spawn('npm run webpack-dev-server'), false);
errors = await driver.waitForErrors();
expect(errors.length).toBeGreaterThan(0);
await sandbox.kill(driver.process);
});
});
4 changes: 2 additions & 2 deletions test/e2e/sandbox/GenericProcessDriver.ts
Expand Up @@ -3,9 +3,9 @@ import { createQueuedListener, Listener, QueuedListener } from './Listener';
import stripAnsi from 'strip-ansi';

interface GenericProcessDriver {
process: ChildProcess;
waitForStdoutIncludes: (string: string, timeout?: number) => Promise<void>;
waitForStderrIncludes: (string: string, timeout?: number) => Promise<void>;
close: () => Promise<boolean>;
}

interface StringListener extends Listener {
Expand Down Expand Up @@ -66,6 +66,7 @@ function createGenericProcessDriver(
}

return {
process,
waitForStdoutIncludes: (string, timeout = defaultTimeout) =>
new Promise<void>((resolve, reject) => {
const timeoutId = setTimeout(() => {
Expand Down Expand Up @@ -106,7 +107,6 @@ function createGenericProcessDriver(
string,
});
}),
close: async () => process.kill(),
};
}

Expand Down

0 comments on commit e812f18

Please sign in to comment.