jsii 5.4.16-dev.2 → 5.4.16-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/lib/case.d.ts +1 -0
  2. package/lib/case.js +2 -1
  3. package/lib/case.js.map +1 -1
  4. package/lib/compiler.d.ts +38 -14
  5. package/lib/compiler.js +114 -108
  6. package/lib/compiler.js.map +1 -1
  7. package/lib/jsii-diagnostic.d.ts +3 -0
  8. package/lib/jsii-diagnostic.js +15 -1
  9. package/lib/jsii-diagnostic.js.map +1 -1
  10. package/lib/main.js +45 -2
  11. package/lib/main.js.map +1 -1
  12. package/lib/project-info.d.ts +5 -0
  13. package/lib/project-info.js +13 -0
  14. package/lib/project-info.js.map +1 -1
  15. package/lib/tsconfig/compiler-options.d.ts +54 -0
  16. package/lib/tsconfig/compiler-options.js +136 -0
  17. package/lib/tsconfig/compiler-options.js.map +1 -0
  18. package/lib/tsconfig/index.d.ts +18 -0
  19. package/lib/tsconfig/index.js +11 -0
  20. package/lib/tsconfig/index.js.map +1 -0
  21. package/lib/tsconfig/rulesets/configurable.d.ts +4 -0
  22. package/lib/tsconfig/rulesets/configurable.js +22 -0
  23. package/lib/tsconfig/rulesets/configurable.js.map +1 -0
  24. package/lib/tsconfig/rulesets/generated.public.d.ts +4 -0
  25. package/lib/tsconfig/rulesets/generated.public.js +28 -0
  26. package/lib/tsconfig/rulesets/generated.public.js.map +1 -0
  27. package/lib/tsconfig/rulesets/incompatible-options.d.ts +4 -0
  28. package/lib/tsconfig/rulesets/incompatible-options.js +11 -0
  29. package/lib/tsconfig/rulesets/incompatible-options.js.map +1 -0
  30. package/lib/tsconfig/rulesets/minimal.public.d.ts +4 -0
  31. package/lib/tsconfig/rulesets/minimal.public.js +11 -0
  32. package/lib/tsconfig/rulesets/minimal.public.js.map +1 -0
  33. package/lib/tsconfig/rulesets/strict.public.d.ts +4 -0
  34. package/lib/tsconfig/rulesets/strict.public.js +29 -0
  35. package/lib/tsconfig/rulesets/strict.public.js.map +1 -0
  36. package/lib/tsconfig/tsconfig-validator.d.ts +16 -0
  37. package/lib/tsconfig/tsconfig-validator.js +46 -0
  38. package/lib/tsconfig/tsconfig-validator.js.map +1 -0
  39. package/lib/tsconfig/validator.d.ts +155 -0
  40. package/lib/tsconfig/validator.js +301 -0
  41. package/lib/tsconfig/validator.js.map +1 -0
  42. package/lib/version.d.ts +2 -2
  43. package/lib/version.js +2 -2
  44. package/lib/version.js.map +1 -1
  45. package/package.json +2 -1
package/lib/case.d.ts CHANGED
@@ -2,4 +2,5 @@ export declare const camel: (text: string) => string;
2
2
  export declare const constant: (text: string) => string;
3
3
  export declare const pascal: (text: string) => string;
4
4
  export declare const snake: (text: string) => string;
5
+ export declare const kebab: (text: string) => string;
5
6
  //# sourceMappingURL=case.d.ts.map
package/lib/case.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.snake = exports.pascal = exports.constant = exports.camel = void 0;
3
+ exports.kebab = exports.snake = exports.pascal = exports.constant = exports.camel = void 0;
4
4
  const Case = require("case");
5
5
  const withCache = (func) => (text) => Cache.fetch(text, func);
6
6
  exports.camel = withCache(Case.camel);
7
7
  exports.constant = withCache(Case.constant);
8
8
  exports.pascal = withCache(Case.pascal);
9
9
  exports.snake = withCache(Case.snake);
10
+ exports.kebab = withCache(Case.kebab);
10
11
  class Cache {
11
12
  static fetch(text, func) {
12
13
  // Check whether we have a cache for this function...
package/lib/case.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"case.js","sourceRoot":"","sources":["../src/case.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAE7B,MAAM,SAAS,GACb,CAAC,IAA8B,EAA8B,EAAE,CAC/D,CAAC,IAAY,EAAE,EAAE,CACf,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAEf,QAAA,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC9B,QAAA,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACpC,QAAA,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAChC,QAAA,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAE3C,MAAM,KAAK;IACF,MAAM,CAAC,KAAK,CAAC,IAAY,EAAE,IAA8B;QAC9D,qDAAqD;QACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,wBAAwB;YACxB,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,0DAA0D;QAC1D,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,yBAAyB;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxB,OAAO,MAAM,CAAC;IAChB,CAAC;IAKD,gBAAuB,CAAC;;AAHxB,uFAAuF;AAC/D,YAAM,GAAG,IAAI,OAAO,EAAiC,CAAC;AAKhF,MAAM,QAAQ;IACL,MAAM,CAAC,GAAG,CAAC,IAAS;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;QAC5C,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1C,OAAO,MAAM,CAAC;IAChB,CAAC;IAKD,gBAAuB,CAAC;;AAHxB,iGAAiG;AACzE,cAAK,GAAG,IAAI,GAAG,EAA0B,CAAC","sourcesContent":["import * as Case from 'case';\n\nconst withCache =\n (func: (text: string) => string): ((text: string) => string) =>\n (text: string) =>\n Cache.fetch(text, func);\n\nexport const camel = withCache(Case.camel);\nexport const constant = withCache(Case.constant);\nexport const pascal = withCache(Case.pascal);\nexport const snake = withCache(Case.snake);\n\nclass Cache {\n public static fetch(text: string, func: (text: string) => string): string {\n // Check whether we have a cache for this function...\n const cacheKey = CacheKey.for(func);\n let cache = this.CACHES.get(cacheKey);\n if (cache == null) {\n // If not, create one...\n cache = new Map<string, string>();\n this.CACHES.set(cacheKey, cache);\n }\n\n // Check if the current cache has a value for this text...\n const cached = cache.get(text);\n if (cached != null) {\n return cached;\n }\n\n // If not, compute one...\n const result = func(text);\n cache.set(text, result);\n return result;\n }\n\n // Cache is indexed on a weak CacheKey so the cache can be purged under memory pressure\n private static readonly CACHES = new WeakMap<CacheKey, Map<string, string>>();\n\n private constructor() {}\n}\n\nclass CacheKey {\n public static for(data: any) {\n const entry = this.STORE.get(data)?.deref();\n if (entry != null) {\n return entry;\n }\n const newKey = new CacheKey();\n this.STORE.set(data, new WeakRef(newKey));\n return newKey;\n }\n\n // Storing cache keys as weak references to allow garbage collection if there is memory pressure.\n private static readonly STORE = new Map<any, WeakRef<CacheKey>>();\n\n private constructor() {}\n}\n"]}
1
+ {"version":3,"file":"case.js","sourceRoot":"","sources":["../src/case.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAE7B,MAAM,SAAS,GACb,CAAC,IAA8B,EAA8B,EAAE,CAC/D,CAAC,IAAY,EAAE,EAAE,CACf,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAEf,QAAA,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC9B,QAAA,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACpC,QAAA,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAChC,QAAA,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC9B,QAAA,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAE3C,MAAM,KAAK;IACF,MAAM,CAAC,KAAK,CAAC,IAAY,EAAE,IAA8B;QAC9D,qDAAqD;QACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,wBAAwB;YACxB,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,0DAA0D;QAC1D,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,yBAAyB;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxB,OAAO,MAAM,CAAC;IAChB,CAAC;IAKD,gBAAuB,CAAC;;AAHxB,uFAAuF;AAC/D,YAAM,GAAG,IAAI,OAAO,EAAiC,CAAC;AAKhF,MAAM,QAAQ;IACL,MAAM,CAAC,GAAG,CAAC,IAAS;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;QAC5C,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1C,OAAO,MAAM,CAAC;IAChB,CAAC;IAKD,gBAAuB,CAAC;;AAHxB,iGAAiG;AACzE,cAAK,GAAG,IAAI,GAAG,EAA0B,CAAC","sourcesContent":["import * as Case from 'case';\n\nconst withCache =\n (func: (text: string) => string): ((text: string) => string) =>\n (text: string) =>\n Cache.fetch(text, func);\n\nexport const camel = withCache(Case.camel);\nexport const constant = withCache(Case.constant);\nexport const pascal = withCache(Case.pascal);\nexport const snake = withCache(Case.snake);\nexport const kebab = withCache(Case.kebab);\n\nclass Cache {\n public static fetch(text: string, func: (text: string) => string): string {\n // Check whether we have a cache for this function...\n const cacheKey = CacheKey.for(func);\n let cache = this.CACHES.get(cacheKey);\n if (cache == null) {\n // If not, create one...\n cache = new Map<string, string>();\n this.CACHES.set(cacheKey, cache);\n }\n\n // Check if the current cache has a value for this text...\n const cached = cache.get(text);\n if (cached != null) {\n return cached;\n }\n\n // If not, compute one...\n const result = func(text);\n cache.set(text, result);\n return result;\n }\n\n // Cache is indexed on a weak CacheKey so the cache can be purged under memory pressure\n private static readonly CACHES = new WeakMap<CacheKey, Map<string, string>>();\n\n private constructor() {}\n}\n\nclass CacheKey {\n public static for(data: any) {\n const entry = this.STORE.get(data)?.deref();\n if (entry != null) {\n return entry;\n }\n const newKey = new CacheKey();\n this.STORE.set(data, new WeakRef(newKey));\n return newKey;\n }\n\n // Storing cache keys as weak references to allow garbage collection if there is memory pressure.\n private static readonly STORE = new Map<any, WeakRef<CacheKey>>();\n\n private constructor() {}\n}\n"]}
package/lib/compiler.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as ts from 'typescript';
2
2
  import { Emitter } from './emitter';
3
3
  import { ProjectInfo } from './project-info';
4
+ import { TypeScriptConfigValidationRuleSet } from './tsconfig';
4
5
  export declare const DIAGNOSTICS = "diagnostics";
5
6
  export declare const JSII_DIAGNOSTICS_CODE = 9999;
6
7
  export interface CompilerOptions {
@@ -19,30 +20,38 @@ export interface CompilerOptions {
19
20
  /** Whether to add warnings for deprecated elements */
20
21
  addDeprecationWarnings?: boolean;
21
22
  /**
22
- * The name of the tsconfig file to generate
23
+ * The name of the tsconfig file to generate.
24
+ * Cannot be used at the same time as `typeScriptConfig`.
23
25
  * @default "tsconfig.json"
24
26
  */
25
27
  generateTypeScriptConfig?: string;
28
+ /**
29
+ * The name of the tsconfig file to use.
30
+ * Cannot be used at the same time as `generateTypeScriptConfig`.
31
+ * @default - generate the tsconfig file
32
+ */
33
+ typeScriptConfig?: string;
34
+ /**
35
+ * The ruleset to validate the provided tsconfig file against.
36
+ * Can only be used when `typeScriptConfig` is provided.
37
+ * @default TypeScriptConfigValidationRuleSet.STRICT - if `typeScriptConfig` is provided
38
+ */
39
+ validateTypeScriptConfig?: TypeScriptConfigValidationRuleSet;
26
40
  /**
27
41
  * Whether to compress the assembly
28
42
  * @default false
29
43
  */
30
44
  compressAssembly?: boolean;
31
45
  }
32
- export interface TypescriptConfig {
33
- compilerOptions: ts.CompilerOptions;
34
- include?: string[];
35
- exclude?: string[];
36
- references?: ts.ProjectReference[];
37
- }
38
46
  export declare class Compiler implements Emitter {
39
47
  private readonly options;
40
48
  private readonly system;
41
49
  private readonly compilerHost;
42
- private typescriptConfig?;
50
+ private readonly userProvidedTypeScriptConfig;
51
+ private readonly tsConfig;
43
52
  private rootFiles;
44
53
  private readonly configPath;
45
- private readonly projectReferences;
54
+ private readonly projectRoot;
46
55
  constructor(options: CompilerOptions);
47
56
  /**
48
57
  * Compiles the configured program.
@@ -61,18 +70,33 @@ export declare class Compiler implements Emitter {
61
70
  *
62
71
  * @param files the files that were specified as input in the CLI invocation.
63
72
  */
64
- private _prepareForBuild;
73
+ private configureTypeScript;
74
+ /**
75
+ * Final preparations of the project for build.
76
+ *
77
+ * These are preparations that either
78
+ * - must happen immediately before the build, or
79
+ * - can be different for every build like assigning the relevant root file(s).
80
+ *
81
+ * @param files the files that were specified as input in the CLI invocation.
82
+ */
83
+ private prepareForBuild;
65
84
  /**
66
85
  * Do a single build
67
86
  */
68
- private _buildOnce;
69
- private _consumeProgram;
87
+ private buildOnce;
88
+ private consumeProgram;
70
89
  /**
71
- * Build the TypeScript config object
90
+ * Build the TypeScript config object from jsii config
72
91
  *
73
- * This is the object that will be written to disk.
92
+ * This is the object that will be written to disk
93
+ * unless an existing tsconfig was provided.
74
94
  */
75
95
  private buildTypeScriptConfig;
96
+ /**
97
+ * Load the TypeScript config object from a provided file
98
+ */
99
+ private readTypeScriptConfig;
76
100
  /**
77
101
  * Creates a `tsconfig.json` file to improve the IDE experience.
78
102
  *
package/lib/compiler.js CHANGED
@@ -7,34 +7,15 @@ const chalk = require("chalk");
7
7
  const log4js = require("log4js");
8
8
  const ts = require("typescript");
9
9
  const assembler_1 = require("./assembler");
10
- const Case = require("./case");
11
10
  const find_utils_1 = require("./common/find-utils");
12
11
  const downlevel_dts_1 = require("./downlevel-dts");
13
12
  const jsii_diagnostic_1 = require("./jsii-diagnostic");
14
13
  const deprecation_warnings_1 = require("./transforms/deprecation-warnings");
14
+ const tsconfig_1 = require("./tsconfig");
15
+ const compiler_options_1 = require("./tsconfig/compiler-options");
16
+ const tsconfig_validator_1 = require("./tsconfig/tsconfig-validator");
17
+ const validator_1 = require("./tsconfig/validator");
15
18
  const utils = require("./utils");
16
- const BASE_COMPILER_OPTIONS = {
17
- alwaysStrict: true,
18
- declaration: true,
19
- experimentalDecorators: true,
20
- incremental: true,
21
- lib: ['lib.es2020.d.ts'],
22
- module: ts.ModuleKind.CommonJS,
23
- noEmitOnError: true,
24
- noFallthroughCasesInSwitch: true,
25
- noImplicitAny: true,
26
- noImplicitReturns: true,
27
- noImplicitThis: true,
28
- noUnusedLocals: true,
29
- noUnusedParameters: true,
30
- resolveJsonModule: true,
31
- skipLibCheck: true,
32
- strict: true,
33
- strictNullChecks: true,
34
- strictPropertyInitialization: true,
35
- stripInternal: false,
36
- target: ts.ScriptTarget.ES2020,
37
- };
38
19
  const LOG = log4js.getLogger('jsii/compiler');
39
20
  exports.DIAGNOSTICS = 'diagnostics';
40
21
  exports.JSII_DIAGNOSTICS_CODE = 9999;
@@ -42,28 +23,27 @@ class Compiler {
42
23
  constructor(options) {
43
24
  this.options = options;
44
25
  this.rootFiles = [];
45
- const rootDir = this.options.projectInfo.projectRoot;
26
+ if (options.generateTypeScriptConfig != null && options.typeScriptConfig != null) {
27
+ throw new Error('Cannot use `generateTypeScriptConfig` and `typeScriptConfig` together. Provide only one of them.');
28
+ }
29
+ this.projectRoot = this.options.projectInfo.projectRoot;
30
+ const configFileName = options.typeScriptConfig ?? options.generateTypeScriptConfig ?? 'tsconfig.json';
31
+ this.configPath = path.join(this.projectRoot, configFileName);
32
+ this.userProvidedTypeScriptConfig = Boolean(options.typeScriptConfig);
33
+ this.tsConfig = this.configureTypeScript();
46
34
  this.system = {
47
35
  ...ts.sys,
48
- getCurrentDirectory: () => rootDir,
49
- createDirectory: (pth) => ts.sys.createDirectory(path.resolve(rootDir, pth)),
50
- deleteFile: ts.sys.deleteFile && ((pth) => ts.sys.deleteFile(path.join(rootDir, pth))),
51
- fileExists: (pth) => ts.sys.fileExists(path.resolve(rootDir, pth)),
52
- getFileSize: ts.sys.getFileSize && ((pth) => ts.sys.getFileSize(path.resolve(rootDir, pth))),
53
- readFile: (pth, encoding) => ts.sys.readFile(path.resolve(rootDir, pth), encoding),
36
+ getCurrentDirectory: () => this.projectRoot,
37
+ createDirectory: (pth) => ts.sys.createDirectory(path.resolve(this.projectRoot, pth)),
38
+ deleteFile: ts.sys.deleteFile && ((pth) => ts.sys.deleteFile(path.join(this.projectRoot, pth))),
39
+ fileExists: (pth) => ts.sys.fileExists(path.resolve(this.projectRoot, pth)),
40
+ getFileSize: ts.sys.getFileSize && ((pth) => ts.sys.getFileSize(path.resolve(this.projectRoot, pth))),
41
+ readFile: (pth, encoding) => ts.sys.readFile(path.resolve(this.projectRoot, pth), encoding),
54
42
  watchFile: ts.sys.watchFile &&
55
- ((pth, callback, pollingInterval, watchOptions) => ts.sys.watchFile(path.resolve(rootDir, pth), callback, pollingInterval, watchOptions)),
56
- writeFile: (pth, data, writeByteOrderMark) => ts.sys.writeFile(path.resolve(rootDir, pth), data, writeByteOrderMark),
43
+ ((pth, callback, pollingInterval, watchOptions) => ts.sys.watchFile(path.resolve(this.projectRoot, pth), callback, pollingInterval, watchOptions)),
44
+ writeFile: (pth, data, writeByteOrderMark) => ts.sys.writeFile(path.resolve(this.projectRoot, pth), data, writeByteOrderMark),
57
45
  };
58
- this.compilerHost = ts.createIncrementalCompilerHost(BASE_COMPILER_OPTIONS, this.system);
59
- const configFileName = options.generateTypeScriptConfig ?? 'tsconfig.json';
60
- this.configPath = path.join(this.options.projectInfo.projectRoot, configFileName);
61
- this.projectReferences =
62
- options.projectReferences !== undefined
63
- ? options.projectReferences
64
- : options.projectInfo.projectReferences !== undefined
65
- ? options.projectInfo.projectReferences
66
- : false;
46
+ this.compilerHost = ts.createIncrementalCompilerHost(this.tsConfig.compilerOptions, this.system);
67
47
  }
68
48
  /**
69
49
  * Compiles the configured program.
@@ -71,18 +51,15 @@ class Compiler {
71
51
  * @param files can be specified to override the standard source code location logic. Useful for example when testing "negatives".
72
52
  */
73
53
  emit(...files) {
74
- this._prepareForBuild(...files);
75
- return this._buildOnce();
54
+ this.prepareForBuild(...files);
55
+ return this.buildOnce();
76
56
  }
77
57
  async watch(opts) {
78
- this._prepareForBuild();
79
- const pi = this.options.projectInfo;
80
- const projectRoot = pi.projectRoot;
58
+ this.prepareForBuild();
81
59
  const host = ts.createWatchCompilerHost(this.configPath, {
82
- ...pi.tsc,
83
- ...BASE_COMPILER_OPTIONS,
60
+ ...this.tsConfig.compilerOptions,
84
61
  noEmitOnError: false,
85
- }, this.system, ts.createEmitAndSemanticDiagnosticsBuilderProgram, opts?.reportDiagnostics, opts?.reportWatchStatus);
62
+ }, this.system, ts.createEmitAndSemanticDiagnosticsBuilderProgram, opts?.reportDiagnostics, opts?.reportWatchStatus, this.tsConfig.watchOptions);
86
63
  if (!host.getDefaultLibLocation) {
87
64
  throw new Error('No default library location was found on the TypeScript compiler host!');
88
65
  }
@@ -92,9 +69,9 @@ class Compiler {
92
69
  //
93
70
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
94
71
  host.afterProgramCreate = (builderProgram) => {
95
- const emitResult = this._consumeProgram(builderProgram.getProgram(), host.getDefaultLibLocation());
72
+ const emitResult = this.consumeProgram(builderProgram.getProgram(), host.getDefaultLibLocation());
96
73
  for (const diag of emitResult.diagnostics.filter((d) => d.code === exports.JSII_DIAGNOSTICS_CODE)) {
97
- utils.logDiagnostic(diag, projectRoot);
74
+ utils.logDiagnostic(diag, this.projectRoot);
98
75
  }
99
76
  if (orig) {
100
77
  orig.call(host, builderProgram);
@@ -117,35 +94,72 @@ class Compiler {
117
94
  *
118
95
  * @param files the files that were specified as input in the CLI invocation.
119
96
  */
120
- _prepareForBuild(...files) {
121
- this.buildTypeScriptConfig();
122
- this.writeTypeScriptConfig();
97
+ configureTypeScript() {
98
+ if (this.userProvidedTypeScriptConfig) {
99
+ const config = this.readTypeScriptConfig();
100
+ // emit a warning if validation is disabled
101
+ const rules = this.options.validateTypeScriptConfig ?? tsconfig_1.TypeScriptConfigValidationRuleSet.NONE;
102
+ if (rules === tsconfig_1.TypeScriptConfigValidationRuleSet.NONE) {
103
+ utils.logDiagnostic(jsii_diagnostic_1.JsiiDiagnostic.JSII_4009_DISABLED_TSCONFIG_VALIDATION.create(undefined, this.configPath), this.projectRoot);
104
+ }
105
+ // validate the user provided config
106
+ if (rules !== tsconfig_1.TypeScriptConfigValidationRuleSet.NONE) {
107
+ try {
108
+ const validator = new tsconfig_validator_1.TypeScriptConfigValidator(rules);
109
+ validator.validate({
110
+ ...config,
111
+ // convert the internal format to the user format which is what the validator operates on
112
+ compilerOptions: (0, compiler_options_1.convertForJson)(config.compilerOptions),
113
+ });
114
+ }
115
+ catch (error) {
116
+ if (error instanceof validator_1.ValidationError) {
117
+ utils.logDiagnostic(jsii_diagnostic_1.JsiiDiagnostic.JSII_4000_FAILED_TSCONFIG_VALIDATION.create(undefined, this.configPath, error.violations), this.projectRoot);
118
+ }
119
+ const configName = path.relative(this.projectRoot, this.configPath);
120
+ throw new Error(`Failed validation of tsconfig "compilerOptions" in "${configName}" against rule set "${rules}"!`);
121
+ }
122
+ }
123
+ return config;
124
+ }
125
+ // generated config if none is provided by the user
126
+ return this.buildTypeScriptConfig();
127
+ }
128
+ /**
129
+ * Final preparations of the project for build.
130
+ *
131
+ * These are preparations that either
132
+ * - must happen immediately before the build, or
133
+ * - can be different for every build like assigning the relevant root file(s).
134
+ *
135
+ * @param files the files that were specified as input in the CLI invocation.
136
+ */
137
+ prepareForBuild(...files) {
138
+ if (!this.userProvidedTypeScriptConfig) {
139
+ this.writeTypeScriptConfig();
140
+ }
123
141
  this.rootFiles = this.determineSources(files);
124
142
  }
125
143
  /**
126
144
  * Do a single build
127
145
  */
128
- _buildOnce() {
146
+ buildOnce() {
129
147
  if (!this.compilerHost.getDefaultLibLocation) {
130
148
  throw new Error('No default library location was found on the TypeScript compiler host!');
131
149
  }
132
- const tsconf = this.typescriptConfig;
133
- const pi = this.options.projectInfo;
150
+ const tsconf = this.tsConfig;
134
151
  const prog = ts.createIncrementalProgram({
135
152
  rootNames: this.rootFiles.concat(_pathOfLibraries(this.compilerHost)),
136
- options: {
137
- ...pi.tsc,
138
- ...(tsconf?.compilerOptions ?? BASE_COMPILER_OPTIONS),
139
- },
153
+ options: tsconf.compilerOptions,
140
154
  // Make the references absolute for the compiler
141
155
  projectReferences: tsconf.references?.map((ref) => ({
142
156
  path: path.resolve(path.dirname(this.configPath), ref.path),
143
157
  })),
144
158
  host: this.compilerHost,
145
159
  });
146
- return this._consumeProgram(prog.getProgram(), this.compilerHost.getDefaultLibLocation());
160
+ return this.consumeProgram(prog.getProgram(), this.compilerHost.getDefaultLibLocation());
147
161
  }
148
- _consumeProgram(program, stdlib) {
162
+ consumeProgram(program, stdlib) {
149
163
  const diagnostics = [...ts.getPreEmitDiagnostics(program)];
150
164
  let hasErrors = false;
151
165
  if (!hasErrors && this.diagsHaveAbortableErrors(diagnostics)) {
@@ -205,22 +219,28 @@ class Compiler {
205
219
  };
206
220
  }
207
221
  /**
208
- * Build the TypeScript config object
222
+ * Build the TypeScript config object from jsii config
209
223
  *
210
- * This is the object that will be written to disk.
224
+ * This is the object that will be written to disk
225
+ * unless an existing tsconfig was provided.
211
226
  */
212
227
  buildTypeScriptConfig() {
213
228
  let references;
214
- if (this.projectReferences) {
229
+ const isComposite = this.options.projectReferences !== undefined
230
+ ? this.options.projectReferences
231
+ : this.options.projectInfo.projectReferences !== undefined
232
+ ? this.options.projectInfo.projectReferences
233
+ : false;
234
+ if (isComposite) {
215
235
  references = this.findProjectReferences();
216
236
  }
217
237
  const pi = this.options.projectInfo;
218
- this.typescriptConfig = {
238
+ return {
219
239
  compilerOptions: {
220
240
  ...pi.tsc,
221
- ...BASE_COMPILER_OPTIONS,
241
+ ...compiler_options_1.BASE_COMPILER_OPTIONS,
222
242
  // Enable composite mode if project references are enabled
223
- composite: this.projectReferences,
243
+ composite: isComposite,
224
244
  // When incremental, configure a tsbuildinfo file
225
245
  tsBuildInfoFile: path.join(pi.tsc?.outDir ?? '.', 'tsconfig.tsbuildinfo'),
226
246
  },
@@ -241,6 +261,24 @@ class Compiler {
241
261
  references: references?.map((p) => ({ path: p })),
242
262
  };
243
263
  }
264
+ /**
265
+ * Load the TypeScript config object from a provided file
266
+ */
267
+ readTypeScriptConfig() {
268
+ const projectRoot = this.options.projectInfo.projectRoot;
269
+ const { config, error } = ts.readConfigFile(this.configPath, ts.sys.readFile);
270
+ if (error) {
271
+ utils.logDiagnostic(error, projectRoot);
272
+ throw new Error(`Failed to load tsconfig at ${this.configPath}`);
273
+ }
274
+ const extended = ts.parseJsonConfigFileContent(config, ts.sys, projectRoot);
275
+ // the tsconfig parser adds this in, but it is not an expected compilerOption
276
+ delete extended.options.configFilePath;
277
+ return {
278
+ compilerOptions: extended.options,
279
+ watchOptions: extended.watchOptions,
280
+ };
281
+ }
244
282
  /**
245
283
  * Creates a `tsconfig.json` file to improve the IDE experience.
246
284
  *
@@ -249,7 +287,7 @@ class Compiler {
249
287
  writeTypeScriptConfig() {
250
288
  const commentKey = '_generated_by_jsii_';
251
289
  const commentValue = 'Generated by jsii - safe to delete, and ideally should be in .gitignore';
252
- this.typescriptConfig[commentKey] = commentValue;
290
+ this.tsConfig[commentKey] = commentValue;
253
291
  if (fs.existsSync(this.configPath)) {
254
292
  const currentConfig = JSON.parse(fs.readFileSync(this.configPath, 'utf-8'));
255
293
  if (!(commentKey in currentConfig)) {
@@ -257,43 +295,11 @@ class Compiler {
257
295
  }
258
296
  }
259
297
  const outputConfig = {
260
- ...this.typescriptConfig,
261
- compilerOptions: {
262
- ...this.typescriptConfig?.compilerOptions,
263
- lib: this.typescriptConfig?.compilerOptions?.lib?.map((lib) =>
264
- // Drop the "lib." prefix and ".d.ts" suffix before writing up the tsconfig.json file
265
- lib.slice(4, lib.length - 5)),
266
- // Re-write the module, targets & jsx to be the JSON format instead of Programmatic API
267
- module: (this.typescriptConfig?.compilerOptions?.module &&
268
- ts.ModuleKind[this.typescriptConfig.compilerOptions.module]),
269
- newLine: newLineForTsconfigJson(this.typescriptConfig?.compilerOptions.newLine),
270
- target: (this.typescriptConfig?.compilerOptions?.target &&
271
- ts.ScriptTarget[this.typescriptConfig.compilerOptions.target]),
272
- jsx: (this.typescriptConfig?.compilerOptions?.jsx &&
273
- Case.snake(ts.JsxEmit[this.typescriptConfig.compilerOptions.jsx])),
274
- },
298
+ ...this.tsConfig,
299
+ compilerOptions: (0, compiler_options_1.convertForJson)(this.tsConfig?.compilerOptions),
275
300
  };
276
301
  LOG.debug(`Creating or updating ${chalk.blue(this.configPath)}`);
277
302
  fs.writeFileSync(this.configPath, JSON.stringify(outputConfig, null, 2), 'utf8');
278
- /**
279
- * This is annoying - the values expected in the tsconfig.json file are not
280
- * the same as the enum constant names, or their values. So we need this
281
- * function to map the "compiler API version" to the "tsconfig.json version"
282
- *
283
- * @param newLine the compiler form of the new line configuration
284
- *
285
- * @return the requivalent value to put in tsconfig.json
286
- */
287
- function newLineForTsconfigJson(newLine) {
288
- switch (newLine) {
289
- case ts.NewLineKind.CarriageReturnLineFeed:
290
- return 'crlf';
291
- case ts.NewLineKind.LineFeed:
292
- return 'lf';
293
- default:
294
- return undefined;
295
- }
296
- }
297
303
  }
298
304
  /**
299
305
  * Find all dependencies that look like TypeScript projects.
@@ -352,7 +358,7 @@ class Compiler {
352
358
  }
353
359
  else {
354
360
  const parseConfigHost = parseConfigHostFromCompilerHost(this.compilerHost);
355
- const parsed = ts.parseJsonConfigFileContent(this.typescriptConfig, parseConfigHost, this.options.projectInfo.projectRoot);
361
+ const parsed = ts.parseJsonConfigFileContent(this.tsConfig, parseConfigHost, this.options.projectInfo.projectRoot);
356
362
  ret.push(...parsed.fileNames);
357
363
  }
358
364
  return ret;
@@ -405,14 +411,14 @@ class Compiler {
405
411
  }
406
412
  exports.Compiler = Compiler;
407
413
  function _pathOfLibraries(host) {
408
- if (!BASE_COMPILER_OPTIONS.lib || BASE_COMPILER_OPTIONS.lib.length === 0) {
414
+ if (!compiler_options_1.BASE_COMPILER_OPTIONS.lib || compiler_options_1.BASE_COMPILER_OPTIONS.lib.length === 0) {
409
415
  return [];
410
416
  }
411
417
  const lib = host.getDefaultLibLocation?.();
412
418
  if (!lib) {
413
- throw new Error(`Compiler host doesn't have a default library directory available for ${BASE_COMPILER_OPTIONS.lib.join(', ')}`);
419
+ throw new Error(`Compiler host doesn't have a default library directory available for ${compiler_options_1.BASE_COMPILER_OPTIONS.lib.join(', ')}`);
414
420
  }
415
- return BASE_COMPILER_OPTIONS.lib.map((name) => path.join(lib, name));
421
+ return compiler_options_1.BASE_COMPILER_OPTIONS.lib.map((name) => path.join(lib, name));
416
422
  }
417
423
  function parseConfigHostFromCompilerHost(host) {
418
424
  // Copied from upstream