Skip to content

Commit

Permalink
feat: BYO config
Browse files Browse the repository at this point in the history
  • Loading branch information
mrgrain committed May 2, 2024
1 parent aecd7b9 commit 21c115f
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 8 deletions.
55 changes: 51 additions & 4 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ const LOG = log4js.getLogger('jsii/compiler');
export const DIAGNOSTICS = 'diagnostics';
export const JSII_DIAGNOSTICS_CODE = 9999;

export enum TypeScriptConfigValidationRuleSet {
STRICT = 'strict',
GENERATED = 'generated',
OFF = 'off',
}

export interface CompilerOptions {
/** The information about the project to be built */
projectInfo: ProjectInfo;
Expand All @@ -57,10 +63,23 @@ export interface CompilerOptions {
/** Whether to add warnings for deprecated elements */
addDeprecationWarnings?: boolean;
/**
* The name of the tsconfig file to generate
* The name of the tsconfig file to generate.
* Cannot be used at the same time as `typeScriptConfig`.
* @default "tsconfig.json"
*/
generateTypeScriptConfig?: string;
/**
* The name of the tsconfig file to use.
* Cannot be used at the same time as `generateTypeScriptConfig`.
* @default - generate the tsconfig file
*/
typeScriptConfig?: string;
/**
* The ruleset to validate the provided tsconfig file against.
* Can only be used when `typeScriptConfig` is provided.
* @default TypeScriptConfigValidationRuleSet.STRICT - if `typeScriptConfig` is provided
*/
validateTypeScriptConfig?: TypeScriptConfigValidationRuleSet;
/**
* Whether to compress the assembly
* @default false
Expand All @@ -78,12 +97,21 @@ export interface TypescriptConfig {
export class Compiler implements Emitter {
private readonly system: ts.System;
private readonly compilerHost: ts.CompilerHost;
private readonly userProvidedTypeScriptConfig: boolean;
private typescriptConfig?: TypescriptConfig;
private rootFiles: string[] = [];
private readonly configPath: string;
private readonly projectReferences: boolean;

public constructor(private readonly options: CompilerOptions) {
if (options.generateTypeScriptConfig != null && options.typeScriptConfig != null) {
throw new Error(
'Cannot use `generateTypeScriptConfig` and `typeScriptConfig` together. Provide only one of them.',
);
}

this.userProvidedTypeScriptConfig = Boolean(options.typeScriptConfig);

const rootDir = this.options.projectInfo.projectRoot;
this.system = {
...ts.sys,
Expand All @@ -102,7 +130,7 @@ export class Compiler implements Emitter {
};
this.compilerHost = ts.createIncrementalCompilerHost(BASE_COMPILER_OPTIONS, this.system);

const configFileName = options.generateTypeScriptConfig ?? 'tsconfig.json';
const configFileName = options.typeScriptConfig ?? options.generateTypeScriptConfig ?? 'tsconfig.json';

this.configPath = path.join(this.options.projectInfo.projectRoot, configFileName);

Expand Down Expand Up @@ -192,11 +220,23 @@ export class Compiler implements Emitter {
* @param files the files that were specified as input in the CLI invocation.
*/
private _prepareForBuild(...files: string[]) {
this.buildTypeScriptConfig();
this.writeTypeScriptConfig();
if (this.userProvidedTypeScriptConfig) {
this.loadTypeScriptConfig();
this.validateTypeScriptConfig();
} else {
this.buildTypeScriptConfig();
this.validateTypeScriptConfig();
this.writeTypeScriptConfig();
}

this.rootFiles = this.determineSources(files);
}

/**
* Validate the computed tsconfig against the determined ruleset
*/
validateTypeScriptConfig() {}

/**
* Do a single build
*/
Expand Down Expand Up @@ -337,6 +377,13 @@ export class Compiler implements Emitter {
};
}

/**
* Load the TypeScript config object from a provided file
*/
private loadTypeScriptConfig() {
this.typescriptConfig = JSON.parse(fs.readFileSync(this.configPath, 'utf-8'));
}

/**
* Creates a `tsconfig.json` file to improve the IDE experience.
*
Expand Down
9 changes: 8 additions & 1 deletion src/jsii-diagnostic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,14 @@ export class JsiiDiagnostic implements ts.Diagnostic {
});

//////////////////////////////////////////////////////////////////////////////
// 4000 => 4999 -- RESERVED
// 4000 => 4999 -- TYPESCRIPT & JSII CONFIG ERRORS

public static readonly JSII_4999_DISABLED_TSCONFIG_VALIDATION = Code.warning({
code: 4999,
formatter: (config) =>
`Validation of typescript config "${config}" is disabled. This is intended for experimental setups only. Compilation might fail or produce incompatible artifacts.`,
name: 'typescript-config/disabled-tsconfig-validation',
});

//////////////////////////////////////////////////////////////////////////////
// 5000 => 5999 -- LANGUAGE COMPATIBILITY ERRORS
Expand Down
61 changes: 58 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as log4js from 'log4js';
import { version as tsVersion } from 'typescript/package.json';
import * as yargs from 'yargs';

import { Compiler } from './compiler';
import { Compiler, TypeScriptConfigValidationRuleSet } from './compiler';
import { configureCategories } from './jsii-diagnostic';
import { loadProjectInfo } from './project-info';
import { emitSupportPolicyInformation } from './support';
Expand All @@ -16,6 +16,24 @@ import { enabledWarnings } from './warnings';

const warningTypes = Object.keys(enabledWarnings);

function choiceWithDesc(
choices: { [choice: string]: string },
desc: string,
): {
choices: string[];
desc: string;
} {
return {
choices: Object.keys(choices),
desc: [desc, ...Object.entries(choices).map(([choice, docs]) => `${choice}: ${docs}`)].join('\n'),
};
}

enum OPTION_GROUP {
JSII = 'jsii compiler options:',
TS = 'TypeScript config options:',
}

(async () => {
await emitSupportPolicyInformation();

Expand All @@ -38,9 +56,10 @@ const warningTypes = Object.keys(enabledWarnings);
desc: 'Watch for file changes and recompile automatically',
})
.option('project-references', {
group: OPTION_GROUP.JSII,
alias: 'r',
type: 'boolean',
desc: 'Generate TypeScript project references (also [package.json].jsii.projectReferences)',
desc: 'Generate TypeScript project references (also [package.json].jsii.projectReferences)\nHas no effect if --tsconfig is provided',
})
.option('fix-peer-dependencies', {
type: 'boolean',
Expand All @@ -49,30 +68,58 @@ const warningTypes = Object.keys(enabledWarnings);
hidden: true,
})
.options('fail-on-warnings', {
group: OPTION_GROUP.JSII,
alias: 'Werr',
type: 'boolean',
desc: 'Treat warnings as errors',
})
.option('silence-warnings', {
group: OPTION_GROUP.JSII,
type: 'array',
default: [],
desc: `List of warnings to silence (warnings: ${warningTypes.join(',')})`,
})
.option('strip-deprecated', {
group: OPTION_GROUP.JSII,
type: 'string',
desc: '[EXPERIMENTAL] Hides all @deprecated members from the API (implementations remain). If an optional file name is given, only FQNs present in the file will be stripped.',
})
.option('add-deprecation-warnings', {
group: OPTION_GROUP.JSII,
type: 'boolean',
default: false,
desc: '[EXPERIMENTAL] Injects warning statements for all deprecated elements, to be printed at runtime',
})
.option('generate-tsconfig', {
group: OPTION_GROUP.TS,
type: 'string',
default: 'tsconfig.json',
defaultDescription: 'tsconfig.json',
desc: 'Name of the typescript configuration file to generate with compiler settings',
})
.option('tsconfig', {
group: OPTION_GROUP.TS,
alias: 'c',
type: 'string',
desc: '[EXPERIMENTAL] Use this typescript configuration file to compile the jsii project.',
})
.conflicts('tsconfig', ['generate-tsconfig', 'project-references'])
.option('validate-tsconfig', {
group: OPTION_GROUP.TS,
...choiceWithDesc(
{
[TypeScriptConfigValidationRuleSet.STRICT]:
'Validates the provided config against the strict ruleset designed for maximum backwards-compatibility.',
[TypeScriptConfigValidationRuleSet.GENERATED]:
'Enforces the same settings as used by --generate-tsconfig. Use this to stay compatible with the generated config, but have full ownership over the file.',
[TypeScriptConfigValidationRuleSet.OFF]:
'Disables all config validation. Intended for experimental setups only. Use at your own risk.',
},
'[EXPERIMENTAL] Validate the provided typescript configuration file against a set of rules.',
),
default: TypeScriptConfigValidationRuleSet.STRICT,
})
.option('compress-assembly', {
group: OPTION_GROUP.JSII,
type: 'boolean',
default: false,
desc: 'Emit a compressed version of the assembly',
Expand All @@ -86,6 +133,10 @@ const warningTypes = Object.keys(enabledWarnings);
async (argv) => {
_configureLog4js(argv.verbose);

if (argv['generate-tsconfig'] != null && argv.tsconfig != null) {
throw new Error('Options --generate-tsconfig and --tsconfig are mutually exclusive');
}

const projectRoot = path.normalize(path.resolve(process.cwd(), argv.PROJECT_ROOT));

const { projectInfo, diagnostics: projectInfoDiagnostics } = loadProjectInfo(projectRoot);
Expand All @@ -109,6 +160,10 @@ const warningTypes = Object.keys(enabledWarnings);
stripDeprecatedAllowListFile: argv['strip-deprecated'],
addDeprecationWarnings: argv['add-deprecation-warnings'],
generateTypeScriptConfig: argv['generate-tsconfig'],
typeScriptConfig: argv.tsconfig ?? projectInfo.packageJson.jsii?.tsconfig,
validateTypeScriptConfig:
(argv['validate-tsconfig'] as TypeScriptConfigValidationRuleSet) ??
projectInfo.packageJson.jsii?.validateTsConfig,
compressAssembly: argv['compress-assembly'],
});

Expand Down
8 changes: 8 additions & 0 deletions src/project-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as semver from 'semver';
import * as ts from 'typescript';

import { findDependencyDirectory } from './common/find-utils';
import { TypeScriptConfigValidationRuleSet } from './compiler';
import { JsiiDiagnostic } from './jsii-diagnostic';
import { parsePerson, parseRepository } from './utils';

Expand Down Expand Up @@ -112,15 +113,22 @@ export interface PackageJson {
readonly bundledDependencies?: readonly string[];

readonly jsii?: {
// main jsii config
readonly diagnostics?: { readonly [id: string]: 'error' | 'warning' | 'suggestion' | 'message' };
readonly metadata?: { readonly [key: string]: unknown };
readonly targets?: { readonly [name: string]: unknown };
readonly versionFormat?: 'short' | 'full';

// Either BYO config ...
readonly tsconfig?: string;
readonly validateTsConfig?: TypeScriptConfigValidationRuleSet;

// ... or configure tsc here
readonly excludeTypescript?: readonly string[];
readonly projectReferences?: boolean;
readonly tsc?: TSCompilerOptions;

// unexpected options
readonly [key: string]: unknown;
};

Expand Down

0 comments on commit 21c115f

Please sign in to comment.