├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── cli │ ├── annotator.ts │ ├── completor.ts │ ├── coverage-stats.ts │ ├── flag-list.ts │ ├── index.ts │ ├── input-output.ts │ └── interfaces.ts └── shared │ ├── data.ts │ ├── enums.ts │ ├── examples │ ├── files-import.md │ └── files-skip-others.md │ ├── interfaces.ts │ ├── tsconfig │ ├── CompilerOptionName.ts │ └── index.ts │ ├── types.ts │ └── utils.ts ├── tasks ├── build.ts ├── process.ts ├── release.ts ├── run-build.ts └── run-release.ts ├── test ├── exclude.spec.ts ├── files.spec.ts └── include.spec.ts ├── tsconfig-dev.json ├── tsconfig-test.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | 8 | [*.{js,ts,json,njk}] 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | node_modules 4 | /dist 5 | /dist-test 6 | 7 | !.gitkeep 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Barin Britva 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🤖 TsConfig Helper 2 | 3 | The tool will help you to debug `tsconfig.json` file of your project. 4 | 5 | _The project is at stage of prototype - only a part part of `tsconfig.json` options are supported at the moment._ 6 | 7 | ## 🚀 Getting started 8 | 9 | Using through global install: 10 | 11 | ```bash 12 | npm install -g tsch 13 | tsch tsconfig.json -e 14 | ``` 15 | 16 | Using `npx`: 17 | 18 | ```bash 19 | npx tsch tsconfig.json -e 20 | ``` 21 | 22 | ## ⚙ CLI Options 23 | 24 | ```bash 25 | tsch --help 26 | 27 | Options: 28 | --help Show help [boolean] 29 | --version Show version number [boolean] 30 | --coverage Show flags coverage status [boolean] 31 | -o, --out File path to write the result [string] 32 | -e, --explain Add explanations to output [boolean] 33 | -s, --short Short explanations instead of verbose [boolean] 34 | -i, --ignore Do not include empty default values such as falsy 35 | and empty arrays to result config [boolean] 36 | ``` 37 | 38 | ## 🗺 Roadmap 39 | 40 | * Full options coverage 41 | * Handle more complicated flag relations 42 | * Other useful advices 43 | * Visual Studio Code Plugin 44 | 45 | ## 🔙 Feedback 46 | Your feedback is really important for the project. Please, use contacts from [my profile](https://github.com/barinbritva) to send your questions, suggestions, help requests and others. Also, feel free to use [issues](https://github.com/barinbritva/tsconfig-helper/issues) section to report bugs and problems. 47 | 48 | ## 🌟 Credits 49 | 50 | The project is bootstrapped using [init-typescript-app](https://github.com/barinbritva/init-typescript-app). 51 | 52 | --- 53 | 54 | MIT, see [LICENSE](https://github.com/barinbritva/tsconfig-helper/blob/master/LICENSE) for the details. 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsch", 3 | "version": "1.0.1", 4 | "files": [ 5 | "/dist" 6 | ], 7 | "main": "./dist/cli/index.js", 8 | "types": "./dist/__types__", 9 | "bin": { 10 | "tsch": "./dist/cli/index.js" 11 | }, 12 | "engines": { 13 | "node": ">=12.10.0" 14 | }, 15 | "engineStrict": true, 16 | "scripts": { 17 | "build": "ts-node ./tasks/run-build.ts", 18 | "build:dev": "ts-node ./tasks/run-build.ts -d", 19 | "start": "node ./dist/cli/index.js", 20 | "build-tests:dev": "tsc --project ./tsconfig-test.json --watch", 21 | "test:dev": "jest --roots ./dist-test/test --watch", 22 | "build-tests": "tsc --project ./tsconfig-test.json", 23 | "test": "jest --roots ./dist-test/test", 24 | "release": "ts-node ./tasks/run-release.ts" 25 | }, 26 | "devDependencies": { 27 | "@types/jest": "^26.0.24", 28 | "@types/node": "^14.14.31", 29 | "jest": "^27.0.6", 30 | "ts-node": "^9.1.1", 31 | "typescript": "^4.4.0-beta" 32 | }, 33 | "dependencies": { 34 | "yargs": "^17.1.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/cli/annotator.ts: -------------------------------------------------------------------------------- 1 | import {DefaultDescriptor, OptionMap} from '../shared/types' 2 | import {OptionDescriptor} from '../shared/interfaces' 3 | import {isDefinedCondition, isMultipleCondition, isNonCondition} from '../shared/utils' 4 | import {getData} from '../shared/data' 5 | import {OptionAnnotation, TsConfig} from './interfaces' 6 | import {ConfigOption} from '../shared/tsconfig' 7 | import {InputOutput} from './input-output' 8 | 9 | export class Annotator { 10 | private configDescriptor: OptionMap 11 | private annotations: Record = {} 12 | 13 | constructor( 14 | private originalConfig: TsConfig, 15 | private resultConfig: TsConfig, 16 | private shortDefaultComments = false 17 | ) { 18 | this.configDescriptor = getData() 19 | this.generateAnnotations() 20 | } 21 | 22 | public generateAnnotatedConfig(): string { 23 | let config = InputOutput.toString(this.resultConfig) 24 | const annotationPairs = Object.entries(this.annotations) 25 | 26 | annotationPairs.forEach((annotationPair) => { 27 | const [optionToAnnotate, annotationsToAdd] = annotationPair 28 | const searchOptionLine = new RegExp(`$[\\s]*"${optionToAnnotate}":`, 'm') 29 | const optionMatch = config.match(searchOptionLine) 30 | 31 | if (optionMatch == null) { 32 | return 33 | } 34 | 35 | const matchedLine = optionMatch[0] 36 | const commentIndent = matchedLine.substr(0, matchedLine.indexOf(`"${optionToAnnotate}"`)) 37 | 38 | const annotations: string[] = [] 39 | if (annotationsToAdd.default !== undefined) { 40 | annotations.push(annotationsToAdd.default) 41 | } 42 | if (annotationsToAdd.deprecation !== undefined) { 43 | annotations.push(annotationsToAdd.deprecation) 44 | } 45 | 46 | const annotationComments = annotations.reduce( 47 | (accumulator, comment) => { 48 | return accumulator + commentIndent + '// ' + comment 49 | }, 50 | '' 51 | ) 52 | 53 | config = config.replace(matchedLine, annotationComments + matchedLine) 54 | }) 55 | 56 | return config 57 | } 58 | 59 | public getAnnotationFor(option: ConfigOption): OptionAnnotation { 60 | const annotation = this.annotations[option] 61 | if (annotation) { 62 | return annotation 63 | } else { 64 | return {} 65 | } 66 | } 67 | 68 | private generateAnnotations(): void { 69 | let resultConfigKeys = Object.keys(this.resultConfig) 70 | if (this.resultConfig.compilerOptions != null) { 71 | resultConfigKeys = resultConfigKeys.concat(Object.keys(this.resultConfig.compilerOptions)) 72 | } 73 | 74 | resultConfigKeys.forEach((key) => { 75 | const option = this.configDescriptor[key as ConfigOption] 76 | 77 | if (option != null) { 78 | if (this.annotations[option.name] == null) { 79 | this.annotations[option.name] = {} 80 | } 81 | 82 | this.addDefaultAnnotation(option) 83 | this.addDeprecationAnnotation(option) 84 | } 85 | }) 86 | } 87 | 88 | private addDefaultAnnotation(option: OptionDescriptor): void { 89 | if (this.isOptionDefined(this.originalConfig, option)) { 90 | return 91 | } 92 | 93 | let value = '' 94 | if (option.default == undefined) { 95 | value = 'no value' 96 | } else if (Array.isArray(option.default)) { 97 | value = option.default 98 | .map((item) => { 99 | return this.stringifyDefaultValue(item) 100 | }) 101 | .join(', ') 102 | } else { 103 | value = this.stringifyDefaultValue(option.default) 104 | } 105 | 106 | this.annotations[option.name].default = 'By default ' + value 107 | } 108 | 109 | private addDeprecationAnnotation(option: OptionDescriptor): void { 110 | if (option.deprecated) { 111 | const description = typeof option.deprecated === 'string' 112 | ? `, use \`${option.deprecated}\` instead` 113 | : '' 114 | this.annotations[option.name].deprecation = 'Deprecated' + description 115 | } 116 | } 117 | 118 | private stringifyDefaultValue(descriptor: DefaultDescriptor): string { 119 | if (this.shortDefaultComments) { 120 | if (isNonCondition(descriptor)) { 121 | return this.valueToString(descriptor.value) 122 | } else { 123 | return `depends on \`${descriptor.option}\`` 124 | } 125 | } else { 126 | if (isDefinedCondition(descriptor)) { 127 | const endPart = descriptor.conditions.notDefined === undefined 128 | ? '' 129 | : ` else ${this.valueToString(descriptor.conditions.notDefined)}` 130 | 131 | return `if \`${this.valueToString(descriptor.option)}\` is defined then ` + 132 | `${this.valueToString(descriptor.conditions.defined)}${endPart}` 133 | } else if (isMultipleCondition(descriptor)) { 134 | const simplifiedConditions: {value: unknown, cases: unknown[]}[] = [] 135 | descriptor.conditions.values.forEach((value) => { 136 | const foundValue = simplifiedConditions.find((simplifiedValue) => { 137 | return simplifiedValue.value === value[1] 138 | }) 139 | 140 | if (foundValue) { 141 | foundValue.cases.push(value[0]) 142 | } else { 143 | simplifiedConditions.push({value: value[1], cases: [value[0]] }) 144 | } 145 | }) 146 | 147 | let line = `if \`${descriptor.option}\` is equal ` 148 | line += simplifiedConditions.map((condition) => { 149 | return `${this.arrayToString(condition.cases)} then \`${this.valueToString(condition.value)}\`` 150 | }).join(', ') 151 | line += ` else \`${this.valueToString(descriptor.conditions.otherwise) ?? 'none'}\`` 152 | 153 | return line 154 | } else { 155 | return this.valueToString(descriptor.value) 156 | } 157 | } 158 | } 159 | 160 | // todo here is similar logic as in config-completor.ts - unify 161 | private isOptionDefined(config: TsConfig, option: OptionDescriptor): boolean { 162 | if (option.inRoot) { 163 | return config[option.name as keyof TsConfig] !== undefined 164 | } else { 165 | return config.compilerOptions[option.name as keyof TsConfig] !== undefined 166 | } 167 | } 168 | 169 | private valueToString(value: unknown): string { 170 | if (Array.isArray(value)) { 171 | const prepared = value.map((item) => { 172 | // now only array of string exists, if other cases appear, improve the logic 173 | if (typeof item === 'string') { 174 | return `"${item}"` 175 | } else { 176 | return item 177 | } 178 | }) 179 | return `[${prepared.join(', ')}]` 180 | } else { 181 | return String(value) 182 | } 183 | } 184 | 185 | private arrayToString(value: unknown[]): string { 186 | const stringifiedValue = '`' + value.join('`, `') + '`' 187 | 188 | if (value.length > 1) { 189 | const lastIndex = stringifiedValue.lastIndexOf(',') 190 | return stringifiedValue.substring(0, lastIndex) + 191 | ' or' + 192 | stringifiedValue.substring(lastIndex + 1) 193 | } else { 194 | return stringifiedValue 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/cli/completor.ts: -------------------------------------------------------------------------------- 1 | import {getData} from '../shared/data' 2 | import {DefaultDescriptor, OptionMap} from '../shared/types' 3 | import {isDefinedCondition, isMultipleCondition} from '../shared/utils' 4 | import {TsConfig} from './interfaces' 5 | 6 | export class Completor { 7 | private resultConfig: TsConfig 8 | private configDescriptor: OptionMap 9 | 10 | constructor(private originalConfig: TsConfig, private omitEmptyValues = false) { 11 | // instead of deep clone 12 | this.resultConfig = JSON.parse(JSON.stringify(this.originalConfig)) 13 | this.configDescriptor = getData() 14 | this.completeConfig() 15 | } 16 | 17 | public getResultConfig(): TsConfig { 18 | return this.resultConfig 19 | } 20 | 21 | public getOriginalConfig(): TsConfig { 22 | return this.originalConfig 23 | } 24 | 25 | private completeConfig(): TsConfig { 26 | const descriptors = Array.from(Object.entries(this.configDescriptor), (pair) => { 27 | return pair[1] 28 | }) 29 | 30 | descriptors.forEach((descriptor) => { 31 | // todo remove block after refactoring of sections 32 | if (descriptor.section != null) { 33 | return 34 | } 35 | 36 | if (descriptor.cliOnly) { 37 | return 38 | } 39 | 40 | if (descriptor.deprecated) { 41 | return 42 | } 43 | 44 | if ( 45 | descriptor.default === undefined || 46 | this.isOptionDefined(descriptor.name, descriptor.inRoot) 47 | ) { 48 | return 49 | } 50 | 51 | const defaultDescriptors: DefaultDescriptor[] = Array.isArray(descriptor.default) 52 | ? descriptor.default 53 | : [descriptor.default] 54 | 55 | const defaultValues = defaultDescriptors.map((defaultValue) => { 56 | if (isDefinedCondition(defaultValue)) { 57 | if (this.lookupDefinedValue(defaultValue.option) !== undefined) { 58 | return defaultValue.conditions.defined 59 | } else if (defaultValue.conditions.notDefined !== undefined) { 60 | return defaultValue.conditions.notDefined 61 | } 62 | } else if (isMultipleCondition(defaultValue)) { 63 | const relatedOptionValue = this.getDefinedValue(defaultValue.option, descriptor.inRoot) 64 | const suitablePair = defaultValue.conditions.values.find((value) => { 65 | // to remove difference between such values as es5/ES5 66 | if (typeof value[0] === 'string' && typeof relatedOptionValue === 'string') { 67 | return value[0].toLowerCase() === relatedOptionValue.toLowerCase() 68 | } else { 69 | return value[0] === relatedOptionValue 70 | } 71 | }) 72 | 73 | if (suitablePair === undefined) { 74 | if (defaultValue.conditions.otherwise !== undefined) { 75 | return defaultValue.conditions.otherwise 76 | } 77 | } else { 78 | return suitablePair[1] 79 | } 80 | } else { 81 | return defaultValue.value 82 | } 83 | }) 84 | 85 | // if omit mode and value is false or an empty array - don't add it 86 | if (this.omitEmptyValues && defaultValues.length === 1) { 87 | if ( 88 | defaultValues[0] === false || 89 | (Array.isArray(defaultValues[0]) && defaultValues[0].length === 0)) { 90 | return 91 | } 92 | } 93 | 94 | const mergedValue = this.mergeDefaultValuePieces(defaultValues) 95 | this.defineOption(descriptor.name, mergedValue, descriptor.inRoot) 96 | }) 97 | 98 | return this.resultConfig 99 | } 100 | 101 | private isOptionDefined(key: string, searchInRoot = false): boolean { 102 | // todo fix keyof TsConfig 103 | return this.getDefinedValue(key, searchInRoot) !== undefined 104 | } 105 | 106 | private getDefinedValue(key: string, searchInRoot = false): unknown { 107 | if (searchInRoot) { 108 | return this.resultConfig[key as keyof TsConfig] 109 | } else { 110 | return this.resultConfig.compilerOptions[key as keyof TsConfig] 111 | } 112 | } 113 | 114 | private defineOption(key: string, value: any, defineInRoot = false): void { 115 | if (defineInRoot) { 116 | this.resultConfig[key as keyof TsConfig] = value 117 | } else { 118 | this.resultConfig.compilerOptions[key as keyof TsConfig] = value 119 | } 120 | } 121 | 122 | // todo check for the same option names in root and compilerOptions 123 | private lookupDefinedValue(key: string): unknown { 124 | return this.getDefinedValue(key, true) ?? this.getDefinedValue(key, false) 125 | } 126 | 127 | private processDynamicValuesIfNeeded(value: unknown): unknown { 128 | if (typeof value === 'string') { 129 | const dynamicValueRegexp = /%(\w*)%/ 130 | const match = value.match(dynamicValueRegexp) 131 | 132 | if (match != null) { 133 | return value.replace(match[0], String(this.lookupDefinedValue(match[1]))) 134 | } 135 | 136 | return value 137 | } 138 | 139 | return value 140 | } 141 | 142 | private mergeDefaultValuePieces(pieces: unknown[]): unknown { 143 | if (pieces.length === 1) { 144 | return this.processDynamicValuesIfNeeded(pieces[0]) 145 | } 146 | 147 | const mergedValues: unknown[] = [] 148 | pieces.forEach((piece) => { 149 | if (piece === undefined) { 150 | return 151 | } 152 | 153 | if (Array.isArray(piece)) { 154 | mergedValues.push( 155 | ...piece.map((item) => { 156 | return this.processDynamicValuesIfNeeded(item) 157 | }) 158 | ) 159 | } else { 160 | // if other cases appear, improve the logic 161 | throw new Error('Value merging are available only for arrays. Given: ' + pieces.join(', ')) 162 | } 163 | }) 164 | 165 | return mergedValues 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/cli/coverage-stats.ts: -------------------------------------------------------------------------------- 1 | import {getData} from '../shared/data' 2 | import {ConfigOption} from '../shared/tsconfig' 3 | import {getFlagList} from './flag-list' 4 | 5 | export abstract class CoverageStats { 6 | public static show(): string { 7 | const configDescriptor = getData() 8 | const flagList = getFlagList() 9 | 10 | const descriptorKeys = Object.keys(configDescriptor) as ConfigOption[] 11 | const percentage = descriptorKeys.length * 100 / flagList.length 12 | 13 | return `Supported ${percentage}% of options / ` + 14 | `${descriptorKeys.length} from ${flagList.length}.` 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/cli/flag-list.ts: -------------------------------------------------------------------------------- 1 | import {ConfigOption} from "../shared/tsconfig" 2 | 3 | export function getFlagList(): ConfigOption[] { 4 | return [ 5 | "help", 6 | "watch", 7 | "preserveWatchOutput", 8 | "listFiles", 9 | "explainFiles", 10 | "listEmittedFiles", 11 | "pretty", 12 | "traceResolution", 13 | "diagnostics", 14 | "extendedDiagnostics", 15 | "generateCpuProfile", 16 | "generateTrace", 17 | "incremental", 18 | "assumeChangesOnlyAffectDirectDependencies", 19 | "locale", 20 | "all", 21 | "version", 22 | "init", 23 | "project", 24 | "build", 25 | "showConfig", 26 | "listFilesOnly", 27 | "target", 28 | "module", 29 | "lib", 30 | "allowJs", 31 | "checkJs", 32 | "jsx", 33 | "declaration", 34 | "declarationMap", 35 | "emitDeclarationOnly", 36 | "sourceMap", 37 | "outFile", 38 | "outDir", 39 | "rootDir", 40 | "composite", 41 | "tsBuildInfoFile", 42 | "removeComments", 43 | "noEmit", 44 | "importHelpers", 45 | "importsNotUsedAsValues", 46 | "downlevelIteration", 47 | "isolatedModules", 48 | "strict", 49 | "noImplicitAny", 50 | "strictNullChecks", 51 | "strictFunctionTypes", 52 | "strictBindCallApply", 53 | "strictPropertyInitialization", 54 | "noImplicitThis", 55 | "useUnknownInCatchVariables", 56 | "alwaysStrict", 57 | "noUnusedLocals", 58 | "noUnusedParameters", 59 | "exactOptionalPropertyTypes", 60 | "noImplicitReturns", 61 | "noFallthroughCasesInSwitch", 62 | "noUncheckedIndexedAccess", 63 | "noImplicitOverride", 64 | "noPropertyAccessFromIndexSignature", 65 | "moduleResolution", 66 | "baseUrl", 67 | "paths", 68 | "rootDirs", 69 | "typeRoots", 70 | "types", 71 | "allowSyntheticDefaultImports", 72 | "esModuleInterop", 73 | "preserveSymlinks", 74 | "allowUmdGlobalAccess", 75 | "sourceRoot", 76 | "mapRoot", 77 | "inlineSourceMap", 78 | "inlineSources", 79 | "experimentalDecorators", 80 | "emitDecoratorMetadata", 81 | "jsxFactory", 82 | "jsxFragmentFactory", 83 | "jsxImportSource", 84 | "resolveJsonModule", 85 | "out", 86 | "reactNamespace", 87 | "skipDefaultLibCheck", 88 | "charset", 89 | "emitBOM", 90 | "newLine", 91 | "noErrorTruncation", 92 | "noLib", 93 | "noResolve", 94 | "stripInternal", 95 | "disableSizeLimit", 96 | "disableSourceOfProjectReferenceRedirect", 97 | "disableSolutionSearching", 98 | "disableReferencedProjectLoad", 99 | "noImplicitUseStrict", 100 | "noEmitHelpers", 101 | "noEmitOnError", 102 | "preserveConstEnums", 103 | "declarationDir", 104 | "skipLibCheck", 105 | "allowUnusedLabels", 106 | "allowUnreachableCode", 107 | "suppressExcessPropertyErrors", 108 | "suppressImplicitAnyIndexErrors", 109 | "forceConsistentCasingInFileNames", 110 | "maxNodeModuleJsDepth", 111 | "noStrictGenericChecks", 112 | "useDefineForClassFields", 113 | "keyofStringsOnly", 114 | "plugins", 115 | "watchFile", 116 | "watchDirectory", 117 | "fallbackPolling", 118 | "synchronousWatchDirectory", 119 | "excludeDirectories", 120 | "excludeFiles", 121 | "verbose", 122 | "dry", 123 | "force", 124 | "clean", 125 | "enableAutoDiscovery", 126 | "enable", 127 | "include", 128 | "exclude", 129 | "disableFilenameBasedTypeAcquisition", 130 | // root 131 | "files", 132 | "include", 133 | "exclude", 134 | "extends", 135 | "references" 136 | ] 137 | } 138 | -------------------------------------------------------------------------------- /src/cli/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import yargs from 'yargs' 4 | import {Annotator} from './annotator' 5 | import {Completor} from './completor' 6 | import {InputOutput} from './input-output' 7 | import {CoverageStats} from './coverage-stats' 8 | 9 | const argv = yargs(process.argv.slice(2)) 10 | .option('coverage', { 11 | describe: 'Show flags coverage status', 12 | boolean: true 13 | }) 14 | .option('out', { 15 | alias: 'o', 16 | describe: 'File path to write the result', 17 | string: true 18 | }) 19 | .option('explain', { 20 | alias: 'e', 21 | describe: 'Add explanations to output', 22 | boolean: true 23 | }) 24 | .option('short', { 25 | alias: 's', 26 | describe: 'Short explanations instead of verbose', 27 | boolean: true 28 | }) 29 | .option('ignore', { 30 | alias: 'i', 31 | describe: 'Do not include empty default values such as falsy and empty arrays to result config', 32 | boolean: true 33 | }) 34 | .argv 35 | 36 | const showCoverage = argv['c'] == null ? false : Boolean(argv['c']) 37 | 38 | if (showCoverage) { 39 | console.log(CoverageStats.show()) 40 | } else { 41 | const configPath = argv._[0] == null ? 'tsconfig.json' : String(argv._[0]) 42 | const needToExplain = argv['e'] 43 | const outputFilePath = argv['o'] == null ? undefined : String(argv['o']) 44 | const showShortExplanations = argv['s'] == null ? false : Boolean(argv['s']) 45 | const ignoreEmptyValues = argv['i'] == null ? false : Boolean(argv['i']) 46 | 47 | const completor = new Completor(InputOutput.read(configPath), ignoreEmptyValues) 48 | let result = '' 49 | 50 | if (needToExplain === true) { 51 | const annotator = new Annotator( 52 | completor.getOriginalConfig(), 53 | completor.getResultConfig(), 54 | showShortExplanations 55 | ) 56 | result = annotator.generateAnnotatedConfig() 57 | } else { 58 | result = InputOutput.toString(completor.getResultConfig()) 59 | } 60 | 61 | if (outputFilePath != null) { 62 | InputOutput.write(result, outputFilePath) 63 | } else { 64 | console.log(result) 65 | } 66 | } 67 | 68 | process.exit(0) 69 | -------------------------------------------------------------------------------- /src/cli/input-output.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import {TsConfig} from './interfaces' 3 | 4 | export abstract class InputOutput { 5 | public static read(fullPath: string): TsConfig { 6 | InputOutput.assertConfigPathIsValid(fullPath) 7 | return InputOutput.readConfig(fullPath) 8 | } 9 | 10 | public static toString(config: TsConfig): string { 11 | return JSON.stringify(config, undefined, 2) 12 | } 13 | 14 | public static write(config: TsConfig | string, path: string): void { 15 | if (typeof config === 'object') { 16 | config = InputOutput.toString(config) 17 | } 18 | 19 | fs.writeFileSync(path, config) 20 | } 21 | 22 | private static assertConfigPathIsValid(path: string): void { 23 | if (path == null) { 24 | throw new Error('Config path not passed.') 25 | } 26 | 27 | if (!fs.existsSync(path)) { 28 | throw new Error('Config file not found in ' + path + '.') 29 | } 30 | } 31 | 32 | private static readConfig(path: string): TsConfig { 33 | const content = fs.readFileSync(path, {encoding: 'utf8'}) 34 | // todo remove comments 35 | // todo process `extends` option 36 | return JSON.parse(content) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/cli/interfaces.ts: -------------------------------------------------------------------------------- 1 | import {CompilerOptions} from 'typescript' 2 | 3 | export interface TsConfig { 4 | files?: string[] 5 | include?: string[] 6 | exclude?: string[] 7 | extends?: string 8 | // todo specify 9 | references?: any[] 10 | // todo mark ? 11 | compilerOptions: CompilerOptions 12 | } 13 | 14 | export interface OptionAnnotation { 15 | default?: string 16 | deprecation?: string 17 | } 18 | -------------------------------------------------------------------------------- /src/shared/data.ts: -------------------------------------------------------------------------------- 1 | import {OptionMap} from './types' 2 | 3 | export function getData(): OptionMap { 4 | return { 5 | // Top Level section 6 | 'files': { 7 | inRoot: true, 8 | name: 'files', 9 | }, 10 | 11 | 'extends': { 12 | inRoot: true, 13 | name: 'extends' 14 | }, 15 | 16 | 'include': { 17 | inRoot: true, 18 | name: 'include', 19 | default: { 20 | option: 'files', 21 | conditions: { 22 | defined: [], 23 | notDefined: ["**/*"] 24 | } 25 | } 26 | }, 27 | 28 | 'exclude': { 29 | inRoot: true, 30 | name: 'exclude', 31 | default: [ 32 | // todo check 33 | {value: ["node_modules", "bower_components", "jspm_packages"]}, 34 | { 35 | option: 'outDir', 36 | conditions: { 37 | defined: ["%outDir%"], 38 | } 39 | }, 40 | { 41 | option: 'declarationDir', 42 | conditions: { 43 | defined: ["%declarationDir%"], 44 | } 45 | } 46 | ] 47 | }, 48 | 49 | 'references': { 50 | inRoot: true, 51 | name: 'references' 52 | }, 53 | 54 | // Type Checking section 55 | 'allowUnreachableCode': { 56 | name: 'allowUnreachableCode', 57 | default: { 58 | value: undefined 59 | } 60 | }, 61 | 62 | 'allowUnusedLabels': { 63 | name: 'allowUnusedLabels', 64 | default: { 65 | value: undefined 66 | } 67 | }, 68 | 69 | 'alwaysStrict': { 70 | name: 'alwaysStrict', 71 | default: { 72 | option: 'strict', 73 | conditions: { 74 | values: [ 75 | [true, true] 76 | ], 77 | otherwise: false 78 | } 79 | } 80 | }, 81 | 82 | 'exactOptionalPropertyTypes': { 83 | name: 'exactOptionalPropertyTypes', 84 | default: { 85 | value: false 86 | } 87 | }, 88 | 89 | 'noFallthroughCasesInSwitch': { 90 | name: 'noFallthroughCasesInSwitch', 91 | default: { 92 | value: false 93 | } 94 | }, 95 | 96 | 'noImplicitAny': { 97 | name: 'noImplicitAny', 98 | default: { 99 | option: 'strict', 100 | conditions: { 101 | values: [ 102 | [true, true] 103 | ], 104 | otherwise: false 105 | } 106 | } 107 | }, 108 | 109 | 'noImplicitOverride': { 110 | name: 'noImplicitOverride', 111 | default: { 112 | value: false 113 | } 114 | }, 115 | 116 | 'noImplicitReturns': { 117 | name: 'noImplicitReturns', 118 | default: { 119 | value: false 120 | } 121 | }, 122 | 123 | 'noImplicitThis': { 124 | name: 'noImplicitThis', 125 | default: { 126 | option: 'strict', 127 | conditions: { 128 | values: [ 129 | [true, true] 130 | ], 131 | otherwise: false 132 | } 133 | } 134 | }, 135 | 136 | 'noPropertyAccessFromIndexSignature': { 137 | name: 'noPropertyAccessFromIndexSignature', 138 | default: { 139 | value: false 140 | } 141 | }, 142 | 143 | 'noUncheckedIndexedAccess': { 144 | name: 'noUncheckedIndexedAccess', 145 | default: { 146 | value: false 147 | } 148 | }, 149 | 150 | 'noUnusedLocals': { 151 | name: 'noUnusedLocals', 152 | default: { 153 | value: false 154 | } 155 | }, 156 | 157 | 'noUnusedParameters': { 158 | name: 'noUnusedParameters', 159 | default: { 160 | value: false 161 | } 162 | }, 163 | 164 | 'strict': { 165 | name: 'strict', 166 | default: { 167 | value: false 168 | } 169 | }, 170 | 171 | 'strictBindCallApply': { 172 | name: 'strictBindCallApply', 173 | default: { 174 | option: 'strict', 175 | conditions: { 176 | values: [ 177 | [true, true] 178 | ], 179 | otherwise: false 180 | } 181 | } 182 | }, 183 | 184 | 'strictFunctionTypes': { 185 | name: 'strictFunctionTypes', 186 | default: { 187 | option: 'strict', 188 | conditions: { 189 | values: [ 190 | [true, true] 191 | ], 192 | otherwise: false 193 | } 194 | } 195 | }, 196 | 197 | 'strictNullChecks': { 198 | name: 'strictNullChecks', 199 | default: { 200 | option: 'strict', 201 | conditions: { 202 | values: [ 203 | [true, true] 204 | ], 205 | otherwise: false 206 | } 207 | } 208 | }, 209 | 210 | 'strictPropertyInitialization': { 211 | name: 'strictPropertyInitialization', 212 | default: { 213 | option: 'strict', 214 | conditions: { 215 | values: [ 216 | [true, true] 217 | ], 218 | otherwise: false 219 | } 220 | } 221 | }, 222 | 223 | 'useUnknownInCatchVariables': { 224 | name: 'useUnknownInCatchVariables', 225 | default: { 226 | option: 'strict', 227 | conditions: { 228 | values: [ 229 | [true, true] 230 | ], 231 | otherwise: false 232 | } 233 | } 234 | }, 235 | 236 | // Modules section 237 | 'allowUmdGlobalAccess': { 238 | name: 'allowUmdGlobalAccess', 239 | default: { 240 | value: false 241 | } 242 | }, 243 | 244 | 'baseUrl': { 245 | name: 'baseUrl' 246 | }, 247 | 248 | 'module': { 249 | name: 'module', 250 | default: { 251 | option: 'target', 252 | conditions: { 253 | values: [ 254 | ['ES3', 'CommonJS'], 255 | ['ES5', 'CommonJS'], 256 | ['ES6', 'ES6'], 257 | ['ES2015', 'ES2015'], 258 | ], 259 | // check 260 | otherwise: 'ESNext' 261 | } 262 | } 263 | }, 264 | 265 | 'moduleResolution': { 266 | name: 'moduleResolution', 267 | default: { 268 | option: 'module', 269 | conditions: { 270 | values: [ 271 | ['AMD', 'Classic'], 272 | ['UMD', 'Classic'], 273 | ['System', 'Classic'] 274 | // todo check ES6 275 | ], 276 | otherwise: 'Node' 277 | } 278 | } 279 | }, 280 | 281 | 'noResolve': { 282 | name: 'noResolve', 283 | default: { 284 | value: false 285 | } 286 | }, 287 | 288 | 'paths': { 289 | name: 'paths' 290 | }, 291 | 292 | 'resolveJsonModule': { 293 | name: 'resolveJsonModule', 294 | default: { 295 | value: false 296 | } 297 | }, 298 | 299 | 'rootDir': { 300 | name: 'rootDir' 301 | // todo check relation to composite option 302 | }, 303 | 304 | 'rootDirs': { 305 | name: 'rootDirs' 306 | }, 307 | 308 | 'typeRoots': { 309 | name: 'typeRoots', 310 | default: { 311 | // todo check 312 | value: ["./node_modules/@types"] 313 | } 314 | }, 315 | 316 | 'types': { 317 | name: 'types', 318 | // means it includes any folder from "./node_modules/@types" by default 319 | }, 320 | 321 | // Emit section 322 | 'declaration': { 323 | name: 'declaration', 324 | default: { 325 | option: 'composite', 326 | conditions: { 327 | values: [ 328 | [true, true] 329 | ], 330 | otherwise: false 331 | } 332 | } 333 | }, 334 | 335 | 'declarationDir': { 336 | name: 'declarationDir' 337 | }, 338 | 339 | 'declarationMap': { 340 | name: 'declarationMap', 341 | default: { 342 | value: false 343 | } 344 | }, 345 | 346 | 'downlevelIteration': { 347 | name: 'downlevelIteration', 348 | default: { 349 | value: false 350 | } 351 | }, 352 | 353 | 'emitBOM': { 354 | name: 'emitBOM', 355 | default: { 356 | value: false 357 | } 358 | }, 359 | 360 | 'emitDeclarationOnly': { 361 | name: 'emitDeclarationOnly', 362 | default: { 363 | value: false 364 | } 365 | }, 366 | 367 | 'importHelpers': { 368 | name: 'importHelpers', 369 | default: { 370 | value: false 371 | } 372 | }, 373 | 374 | 'importsNotUsedAsValues': { 375 | name: 'importsNotUsedAsValues', 376 | default: { 377 | // values: remove, preserve, error 378 | // todo check 379 | value: 'remove' 380 | } 381 | }, 382 | 383 | 'inlineSourceMap': { 384 | name: 'inlineSourceMap', 385 | default: { 386 | value: false 387 | } 388 | }, 389 | 390 | 'inlineSources': { 391 | name: 'inlineSources', 392 | default: { 393 | value: false 394 | } 395 | }, 396 | 397 | 'mapRoot': { 398 | name: 'mapRoot', 399 | }, 400 | 401 | 'newLine': { 402 | name: 'newLine', 403 | // todo check if unix lf, other - crlf 404 | // values: crlf, lf 405 | }, 406 | 407 | 'noEmit': { 408 | name: 'noEmit', 409 | default: { 410 | value: false 411 | } 412 | }, 413 | 414 | 'noEmitHelpers': { 415 | name: 'noEmitHelpers', 416 | default: { 417 | value: false 418 | } 419 | }, 420 | 421 | 'noEmitOnError': { 422 | name: 'noEmitOnError', 423 | default: { 424 | value: false 425 | } 426 | }, 427 | 428 | 'outDir': { 429 | name: 'outDir' 430 | }, 431 | 432 | 'outFile': { 433 | name: 'outFile' 434 | }, 435 | 436 | 'preserveConstEnums': { 437 | name: 'preserveConstEnums', 438 | default: { 439 | value: false 440 | } 441 | }, 442 | 443 | 'preserveValueImports': { 444 | name: 'preserveValueImports', 445 | default: { 446 | value: false 447 | } 448 | }, 449 | 450 | 'removeComments': { 451 | name: 'removeComments', 452 | default: { 453 | value: false 454 | } 455 | }, 456 | 457 | 'sourceMap': { 458 | name: 'sourceMap', 459 | default: { 460 | value: false 461 | } 462 | }, 463 | 464 | 'sourceRoot': { 465 | name: 'sourceRoot', 466 | }, 467 | 468 | 'stripInternal': { 469 | name: 'stripInternal', 470 | default: { 471 | value: false 472 | } 473 | }, 474 | 475 | // JavaScript Support section 476 | 'allowJs': { 477 | name: 'allowJs', 478 | default: { 479 | option: 'checkJs', 480 | conditions: { 481 | values: [ 482 | [true, true] 483 | ], 484 | otherwise: false 485 | }, 486 | } 487 | }, 488 | 489 | 'checkJs': { 490 | name: 'checkJs', 491 | default: { 492 | value: false 493 | } 494 | }, 495 | 496 | 'maxNodeModuleJsDepth': { 497 | name: 'maxNodeModuleJsDepth', 498 | default: { 499 | value: 0 500 | } 501 | }, 502 | 503 | // Editor Support section 504 | 'disableSizeLimit': { 505 | name: 'disableSizeLimit', 506 | default: { 507 | value: false 508 | } 509 | }, 510 | 511 | 'plugins': { 512 | name: 'plugins' 513 | }, 514 | 515 | // Interop Constraints section 516 | 'allowSyntheticDefaultImports': { 517 | name: 'allowSyntheticDefaultImports', 518 | default: { 519 | option: 'module', 520 | conditions: { 521 | values: [ 522 | ['System', true] 523 | ], 524 | // todo true if module is system, or esModuleInterop and module is not es6/es2015 or esnext, false otherwise. 525 | otherwise: false 526 | } 527 | } 528 | }, 529 | 530 | 'esModuleInterop': { 531 | name: 'esModuleInterop', 532 | default: { 533 | value: false 534 | } 535 | }, 536 | 537 | 'forceConsistentCasingInFileNames': { 538 | name: 'forceConsistentCasingInFileNames', 539 | default: { 540 | value: false 541 | } 542 | }, 543 | 544 | 'isolatedModules': { 545 | name: 'isolatedModules', 546 | default: { 547 | value: false 548 | } 549 | }, 550 | 551 | 'preserveSymlinks': { 552 | name: 'preserveSymlinks', 553 | default: { 554 | value: false 555 | } 556 | }, 557 | 558 | // Backward Compatibility section 559 | 'charset': { 560 | name: 'charset', 561 | default: { 562 | value: 'utf8' 563 | }, 564 | deprecated: true 565 | }, 566 | 567 | 'keyofStringsOnly': { 568 | name: 'keyofStringsOnly', 569 | default: { 570 | value: false 571 | }, 572 | deprecated: true 573 | }, 574 | 575 | 'noImplicitUseStrict': { 576 | name: 'noImplicitUseStrict', 577 | default: { 578 | value: false 579 | } 580 | }, 581 | 582 | 'noStrictGenericChecks': { 583 | name: 'noStrictGenericChecks', 584 | default: { 585 | value: false 586 | } 587 | }, 588 | 589 | 'out': { 590 | name: 'out', 591 | deprecated: 'outDir' 592 | }, 593 | 594 | 'suppressExcessPropertyErrors': { 595 | name: 'suppressExcessPropertyErrors', 596 | default: { 597 | value: false 598 | } 599 | }, 600 | 601 | 'suppressImplicitAnyIndexErrors': { 602 | name: 'suppressImplicitAnyIndexErrors', 603 | default: { 604 | value: false 605 | } 606 | }, 607 | 608 | // Language and Environment section 609 | 'emitDecoratorMetadata': { 610 | name: 'emitDecoratorMetadata', 611 | default: { 612 | value: false 613 | } 614 | }, 615 | 616 | 'experimentalDecorators': { 617 | name: 'experimentalDecorators', 618 | default: { 619 | value: false 620 | } 621 | }, 622 | 623 | 'jsx': { 624 | name: 'jsx', 625 | // allowed: preserve, react, react-native, react-jsx, react-jsxdev 626 | }, 627 | 628 | 'jsxFactory': { 629 | name: 'jsxFactory', 630 | default: { 631 | option: 'jsx', 632 | conditions: { 633 | defined: 'React.createElement' 634 | } 635 | } 636 | }, 637 | 638 | 'jsxFragmentFactory': { 639 | name: 'jsxFragmentFactory', 640 | default: { 641 | option: 'jsx', 642 | conditions: { 643 | defined: 'Fragment' 644 | } 645 | } 646 | }, 647 | 648 | 'jsxImportSource': { 649 | name: 'jsxImportSource', 650 | default: { 651 | option: 'jsx', 652 | conditions: { 653 | defined: 'react' 654 | } 655 | } 656 | }, 657 | 658 | 'lib': { 659 | name: 'lib', 660 | default: [ 661 | { 662 | option: 'target', 663 | // picked from https://github.com/microsoft/TypeScript/blob/main/src/compiler/utilitiesPublic.ts 664 | // function getDefaultLibFileName 665 | conditions: { 666 | values: [ 667 | [ 668 | 'ES6', 669 | [ 670 | "ES2015", 671 | "DOM", 672 | "DOM.Iterable", 673 | "WebWorker.ImportScripts", 674 | "ScriptHost" 675 | ] 676 | ], 677 | [ 678 | 'ES2015', 679 | [ 680 | "ES2015", 681 | "DOM", 682 | "DOM.Iterable", 683 | "WebWorker.ImportScripts", 684 | "ScriptHost" 685 | ] 686 | ], 687 | [ 688 | 'ES7', 689 | [ 690 | "ES2016", 691 | "DOM", 692 | "DOM.Iterable", 693 | "WebWorker.ImportScripts", 694 | "ScriptHost" 695 | ] 696 | ], 697 | [ 698 | 'ES2016', 699 | [ 700 | "ES2016", 701 | "DOM", 702 | "DOM.Iterable", 703 | "WebWorker.ImportScripts", 704 | "ScriptHost" 705 | ] 706 | ], 707 | [ 708 | 'ES2017', 709 | [ 710 | "ES2017", 711 | "DOM", 712 | "DOM.Iterable", 713 | "WebWorker.ImportScripts", 714 | "ScriptHost" 715 | ] 716 | ], 717 | [ 718 | 'ES2018', 719 | [ 720 | "ES2018", 721 | "DOM", 722 | "DOM.Iterable", 723 | "WebWorker.ImportScripts", 724 | "ScriptHost" 725 | ] 726 | ], 727 | [ 728 | 'ES2019', 729 | [ 730 | "ES2019", 731 | "DOM", 732 | "DOM.Iterable", 733 | "WebWorker.ImportScripts", 734 | "ScriptHost" 735 | ] 736 | ], 737 | [ 738 | 'ES2020', 739 | [ 740 | "ES2020", 741 | "DOM", 742 | "DOM.Iterable", 743 | "WebWorker.ImportScripts", 744 | "ScriptHost" 745 | ] 746 | ], 747 | [ 748 | 'ES2021', 749 | [ 750 | "ES2021", 751 | "DOM", 752 | "DOM.Iterable", 753 | "WebWorker.ImportScripts", 754 | "ScriptHost" 755 | ] 756 | ], 757 | // todo check fo 2022 758 | [ 759 | 'ESNext', 760 | [ 761 | "ESNext", 762 | "DOM", 763 | "DOM.Iterable", 764 | "WebWorker.ImportScripts", 765 | "ScriptHost" 766 | ] 767 | ] 768 | ], 769 | otherwise: [ 770 | "ES5", 771 | "DOM", 772 | "WebWorker.ImportScripts", 773 | "ScriptHost" 774 | ] 775 | } 776 | }, 777 | // todo implement prioritization 778 | // { 779 | // option: 'noLib', 780 | // conditions: { 781 | // defined: [] 782 | // } 783 | // } 784 | ] 785 | }, 786 | 787 | 'noLib': { 788 | name: 'noLib', 789 | default: { 790 | value: false 791 | } 792 | }, 793 | 794 | 'reactNamespace': { 795 | name: 'reactNamespace', 796 | default: { 797 | option: 'jsx', 798 | conditions: { 799 | defined: 'React' 800 | } 801 | }, 802 | deprecated: 'jsxFactory' 803 | }, 804 | 805 | 'target': { 806 | name: 'target', 807 | default: { 808 | value: 'ES3' 809 | } 810 | }, 811 | 812 | 'useDefineForClassFields': { 813 | name: 'useDefineForClassFields', 814 | default: { 815 | option: 'target', 816 | conditions: { 817 | values: [ 818 | ['ES2022', true], 819 | ['ESNext', true], 820 | ], 821 | otherwise: false 822 | } 823 | } 824 | }, 825 | 826 | // Compiler Diagnostics 827 | 'diagnostics': { 828 | name: 'diagnostics', 829 | default: { 830 | value: false 831 | }, 832 | deprecated: 'extendedDiagnostics' 833 | }, 834 | 835 | 'explainFiles': { 836 | name: 'explainFiles', 837 | default: { 838 | value: false 839 | } 840 | }, 841 | 842 | 'extendedDiagnostics': { 843 | name: 'extendedDiagnostics', 844 | default: { 845 | value: false 846 | } 847 | }, 848 | 849 | 'generateCpuProfile': { 850 | name: 'generateCpuProfile', 851 | default: { 852 | value: 'profile.cpuprofile' 853 | }, 854 | // todo ignore option if cliOnly 855 | cliOnly: true 856 | }, 857 | 858 | 'listEmittedFiles': { 859 | name: 'listEmittedFiles', 860 | default: { 861 | value: false 862 | } 863 | }, 864 | 865 | 'listFiles': { 866 | name: 'listFiles', 867 | default: { 868 | value: false 869 | } 870 | }, 871 | 872 | 'traceResolution': { 873 | name: 'traceResolution', 874 | default: { 875 | value: false 876 | } 877 | }, 878 | 879 | // Projects section 880 | 'composite': { 881 | name: 'composite', 882 | default: { 883 | value: false 884 | } 885 | }, 886 | 887 | 'disableReferencedProjectLoad': { 888 | name: 'disableReferencedProjectLoad', 889 | default: { 890 | value: false 891 | } 892 | }, 893 | 894 | 'disableSolutionSearching': { 895 | name: 'disableSolutionSearching', 896 | default: { 897 | value: false 898 | } 899 | }, 900 | 901 | 'disableSourceOfProjectReferenceRedirect': { 902 | name: 'disableSourceOfProjectReferenceRedirect', 903 | default: { 904 | value: false 905 | } 906 | }, 907 | 908 | 'incremental': { 909 | name: 'incremental', 910 | default: { 911 | option: 'composite', 912 | conditions: { 913 | defined: true, 914 | notDefined: false 915 | } 916 | } 917 | }, 918 | 919 | 'tsBuildInfoFile': { 920 | name: 'tsBuildInfoFile', 921 | default: { 922 | option: 'incremental', 923 | conditions: { 924 | defined: '.tsbuildinfo' 925 | } 926 | } 927 | }, 928 | 929 | // Output Formatting section 930 | 'noErrorTruncation': { 931 | name: 'noErrorTruncation', 932 | default: { 933 | value: false 934 | } 935 | }, 936 | 937 | 'preserveWatchOutput': { 938 | name: 'preserveWatchOutput', 939 | default: { 940 | value: false 941 | } 942 | }, 943 | 944 | 'pretty': { 945 | name: 'pretty', 946 | default: { 947 | value: true 948 | } 949 | }, 950 | 951 | // Completeness section 952 | 'skipDefaultLibCheck': { 953 | name: 'skipDefaultLibCheck', 954 | default: { 955 | value: false 956 | }, 957 | deprecated: 'skipLibCheck' 958 | }, 959 | 960 | 'skipLibCheck': { 961 | name: 'skipLibCheck', 962 | default: { 963 | value: false 964 | } 965 | }, 966 | 967 | // Command Line sections 968 | // ??? 969 | 970 | // Watch Options section 971 | 'watch': { 972 | name: 'watch', 973 | default: { 974 | value: false 975 | } 976 | }, 977 | 978 | 'assumeChangesOnlyAffectDirectDependencies': { 979 | name: 'assumeChangesOnlyAffectDirectDependencies', 980 | default: { 981 | value: false 982 | } 983 | }, 984 | 985 | 'watchFile': { 986 | name: 'watchFile', 987 | default: { 988 | // allowed: fixedPollingInterval, priorityPollingInterval, dynamicPriorityPolling, useFsEvents, useFsEventsOnParentDirectory 989 | value: 'useFsEvents' 990 | }, 991 | section: 'watchOptions' 992 | }, 993 | 994 | 'watchDirectory': { 995 | name: 'watchDirectory', 996 | default: { 997 | // allowed: fixedPollingInterval, dynamicPriorityPolling, useFsEvents 998 | value: 'useFsEvents' 999 | }, 1000 | section: 'watchOptions' 1001 | }, 1002 | 1003 | 'fallbackPolling': { 1004 | name: 'fallbackPolling', 1005 | // allowed: fixedPollingInterval, priorityPollingInterval, dynamicPriorityPolling, synchronousWatchDirectory 1006 | section: 'watchOptions' 1007 | }, 1008 | 1009 | 'synchronousWatchDirectory': { 1010 | name: 'synchronousWatchDirectory', 1011 | default: { 1012 | // todo check 1013 | value: false 1014 | }, 1015 | section: 'watchOptions' 1016 | }, 1017 | 1018 | 'excludeDirectories': { 1019 | name: 'excludeDirectories', 1020 | // todo check default 1021 | section: 'watchOptions' 1022 | }, 1023 | 1024 | 'excludeFiles': { 1025 | name: 'excludeFiles', 1026 | section: 'watchOptions' 1027 | }, 1028 | 1029 | // Type Acquisition section 1030 | // todo enable,include,exclude anddisableFilenameBasedTypeAcquisition 1031 | } 1032 | } 1033 | -------------------------------------------------------------------------------- /src/shared/enums.ts: -------------------------------------------------------------------------------- 1 | export enum RelationType { 2 | // enables other flag 3 | Enables = 'enables', 4 | // changes value of other flag if it is not specified 5 | Changes = 'changes', 6 | // modifies some part of value, for example adds something to arrays 7 | Modifies = 'modifies', 8 | // needs in other flag enabled to work properly 9 | Needs = 'needs', 10 | // replace because other flag is deprecated 11 | Replaces = 'replaces', 12 | // just somehow related 13 | Related = 'related' 14 | } 15 | -------------------------------------------------------------------------------- /src/shared/examples/files-import.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barinbritva/tsconfig-helper/79f9e9c6ac876dfc31b423d9e1fd44cc500f2e12/src/shared/examples/files-import.md -------------------------------------------------------------------------------- /src/shared/examples/files-skip-others.md: -------------------------------------------------------------------------------- 1 | Example project file structure: 2 | 3 | ``` 4 | src 5 | ├── bye.ts 6 | ├── greeter.ts 7 | └── index.ts 8 | ``` 9 | 10 | Content of `tsconfig.json`: 11 | 12 | ```json 13 | { 14 | "compilerOptions": { 15 | "outDir": "./dist" 16 | }, 17 | "files": [ 18 | "src/index.ts" 19 | ] 20 | } 21 | ``` 22 | 23 | File `index.ts` doesn't use either `bye.ts` nor `greeter.ts`: 24 | 25 | ```typescript 26 | console.log('index.ts') 27 | ``` 28 | 29 | Only `index.ts` will be compiled. Any other files will be totally skipped. Even though they contain syntax errors. Fot instance `greeter.ts` file does: 30 | 31 | `greeter.ts`: 32 | 33 | ```typescript 34 | function sayHello(name: string): { 35 | // missed returning value after : 36 | console.log('Hello ' + name) 37 | } 38 | ``` 39 | 40 | The result: 41 | 42 | ``` 43 | dist 44 | └── index.js 45 | ``` 46 | -------------------------------------------------------------------------------- /src/shared/interfaces.ts: -------------------------------------------------------------------------------- 1 | import {RelationType} from './enums' 2 | import {ConfigSection, DefaultDescriptor} from './types' 3 | import {ConfigOption} from './tsconfig' 4 | 5 | export interface Relation { 6 | to: ConfigOption 7 | type: RelationType 8 | description: string 9 | } 10 | 11 | export interface BackRelation { 12 | to: ConfigOption 13 | look: RelationType 14 | description?: string 15 | } 16 | 17 | export interface OptionDescriptor { 18 | name: ConfigOption 19 | inRoot?: boolean 20 | default?: DefaultDescriptor | DefaultDescriptor[] 21 | deprecated?: true | ConfigOption 22 | cliOnly?: boolean 23 | section?: ConfigSection 24 | } 25 | -------------------------------------------------------------------------------- /src/shared/tsconfig/CompilerOptionName.ts: -------------------------------------------------------------------------------- 1 | // copied from https://github.com/microsoft/TypeScript-Website/blob/v2/packages/tsconfig-reference/data/_types.ts 2 | 3 | // __auto-generated__ 4 | 5 | export type CompilerOptionName = 6 | | "help" 7 | | "watch" 8 | | "preserveWatchOutput" 9 | | "listFiles" 10 | | "explainFiles" 11 | | "listEmittedFiles" 12 | | "pretty" 13 | | "traceResolution" 14 | | "diagnostics" 15 | | "extendedDiagnostics" 16 | | "generateCpuProfile" 17 | | "generateTrace" 18 | | "incremental" 19 | | "assumeChangesOnlyAffectDirectDependencies" 20 | | "locale" 21 | | "all" 22 | | "version" 23 | | "init" 24 | | "project" 25 | | "build" 26 | | "showConfig" 27 | | "listFilesOnly" 28 | | "target" 29 | | "module" 30 | | "lib" 31 | | "allowJs" 32 | | "checkJs" 33 | | "jsx" 34 | | "declaration" 35 | | "declarationMap" 36 | | "emitDeclarationOnly" 37 | | "sourceMap" 38 | | "outFile" 39 | | "outDir" 40 | | "rootDir" 41 | | "composite" 42 | | "tsBuildInfoFile" 43 | | "removeComments" 44 | | "noEmit" 45 | | "importHelpers" 46 | | "importsNotUsedAsValues" 47 | | "downlevelIteration" 48 | | "isolatedModules" 49 | | "strict" 50 | | "noImplicitAny" 51 | | "strictNullChecks" 52 | | "strictFunctionTypes" 53 | | "strictBindCallApply" 54 | | "strictPropertyInitialization" 55 | | "noImplicitThis" 56 | | "useUnknownInCatchVariables" 57 | | "alwaysStrict" 58 | | "noUnusedLocals" 59 | | "noUnusedParameters" 60 | | "exactOptionalPropertyTypes" 61 | | "noImplicitReturns" 62 | | "noFallthroughCasesInSwitch" 63 | | "noUncheckedIndexedAccess" 64 | | "noImplicitOverride" 65 | | "noPropertyAccessFromIndexSignature" 66 | | "moduleResolution" 67 | | "baseUrl" 68 | | "paths" 69 | | "rootDirs" 70 | | "typeRoots" 71 | | "types" 72 | | "allowSyntheticDefaultImports" 73 | | "esModuleInterop" 74 | | "preserveSymlinks" 75 | | "allowUmdGlobalAccess" 76 | | "sourceRoot" 77 | | "mapRoot" 78 | | "inlineSourceMap" 79 | | "inlineSources" 80 | | "experimentalDecorators" 81 | | "emitDecoratorMetadata" 82 | | "jsxFactory" 83 | | "jsxFragmentFactory" 84 | | "jsxImportSource" 85 | | "resolveJsonModule" 86 | | "out" 87 | | "reactNamespace" 88 | | "skipDefaultLibCheck" 89 | | "charset" 90 | | "emitBOM" 91 | | "newLine" 92 | | "noErrorTruncation" 93 | | "noLib" 94 | | "noResolve" 95 | | "stripInternal" 96 | | "disableSizeLimit" 97 | | "disableSourceOfProjectReferenceRedirect" 98 | | "disableSolutionSearching" 99 | | "disableReferencedProjectLoad" 100 | | "noImplicitUseStrict" 101 | | "noEmitHelpers" 102 | | "noEmitOnError" 103 | | "preserveConstEnums" 104 | | "declarationDir" 105 | | "skipLibCheck" 106 | | "allowUnusedLabels" 107 | | "allowUnreachableCode" 108 | | "suppressExcessPropertyErrors" 109 | | "suppressImplicitAnyIndexErrors" 110 | | "forceConsistentCasingInFileNames" 111 | | "maxNodeModuleJsDepth" 112 | | "noStrictGenericChecks" 113 | | "useDefineForClassFields" 114 | | "preserveValueImports" 115 | | "keyofStringsOnly" 116 | | "plugins" 117 | | "watchFile" 118 | | "watchDirectory" 119 | | "fallbackPolling" 120 | | "synchronousWatchDirectory" 121 | | "excludeDirectories" 122 | | "excludeFiles" 123 | | "verbose" 124 | | "dry" 125 | | "force" 126 | | "clean" 127 | | "enableAutoDiscovery" 128 | | "enable" 129 | | "include" 130 | | "exclude" 131 | | "disableFilenameBasedTypeAcquisition" 132 | -------------------------------------------------------------------------------- /src/shared/tsconfig/index.ts: -------------------------------------------------------------------------------- 1 | import {CompilerOptionName} from './CompilerOptionName' 2 | 3 | type RootOptionName = 'files' | 'include' | 'exclude' | 'extends' | 'references' 4 | type TypeAcquisition = 'enable' | 'include' | 'exclude' | 'disableFilenameBasedTypeAcquisition' 5 | type ConfigOption = CompilerOptionName | RootOptionName | TypeAcquisition 6 | 7 | export { 8 | CompilerOptionName, 9 | RootOptionName, 10 | ConfigOption 11 | } 12 | -------------------------------------------------------------------------------- /src/shared/types.ts: -------------------------------------------------------------------------------- 1 | import {ConfigOption} from './tsconfig' 2 | import {OptionDescriptor} from './interfaces' 3 | 4 | export interface Hint { 5 | brief: string 6 | text?: string 7 | } 8 | 9 | export interface DefaultValue { 10 | value: unknown 11 | } 12 | 13 | export interface DefaultDefinedCondition { 14 | option: ConfigOption, 15 | conditions: { 16 | defined: unknown 17 | notDefined?: unknown 18 | } 19 | } 20 | 21 | export interface DefaultMultipleCondition { 22 | option: ConfigOption, 23 | conditions: { 24 | values: [unknown, unknown][] 25 | otherwise?: unknown 26 | } 27 | } 28 | 29 | export type DefaultDescriptor = DefaultDefinedCondition | DefaultMultipleCondition | DefaultValue 30 | 31 | export type OptionMap = Partial> 32 | 33 | export type ConfigSection = 'root' | 'compilerOptions' | 'watchOptions' | 'typeAcquisition' 34 | -------------------------------------------------------------------------------- /src/shared/utils.ts: -------------------------------------------------------------------------------- 1 | import {BackRelation, Relation} from './interfaces' 2 | import {DefaultDefinedCondition, DefaultDescriptor, DefaultMultipleCondition, DefaultValue} from './types' 3 | 4 | export function isMultipleCondition(value: DefaultDescriptor): value is DefaultMultipleCondition { 5 | if ( 6 | 'conditions' in (value as DefaultMultipleCondition) && 7 | 'values' in (value as DefaultMultipleCondition).conditions 8 | ) { 9 | return true 10 | } 11 | 12 | return false 13 | } 14 | 15 | export function isDefinedCondition(value: DefaultDescriptor): value is DefaultDefinedCondition { 16 | if ( 17 | 'conditions' in (value as DefaultDefinedCondition) && 18 | 'defined' in (value as DefaultDefinedCondition).conditions 19 | ) { 20 | return true 21 | } 22 | 23 | return false 24 | } 25 | 26 | export function isNonCondition(value: DefaultDescriptor): value is DefaultValue { 27 | if ('value' in (value as DefaultValue)) { 28 | return true 29 | } 30 | 31 | return false 32 | } 33 | 34 | export function isBackRelation(value: Relation | BackRelation): value is BackRelation { 35 | if ('to' in value && 'look' in value) { 36 | return true 37 | } 38 | 39 | return false 40 | } 41 | 42 | export function isDirectRelation(value: Relation | BackRelation): value is Relation { 43 | if ('to' in value && 'type' in value) { 44 | return true 45 | } 46 | 47 | return false 48 | } 49 | -------------------------------------------------------------------------------- /tasks/build.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import { run } from './process' 3 | 4 | function readOutDirNameFromConfig (): string | null { 5 | const outDirRegExp = new RegExp(/["|']outDir["|']:\s?["|'](.*)["|']/) 6 | const configData = fs.readFileSync('./tsconfig.json', 'utf8') 7 | const matchResult = configData.match(outDirRegExp) 8 | 9 | if (matchResult == null) { 10 | return null 11 | } else { 12 | return matchResult[1] 13 | } 14 | } 15 | 16 | export async function build (mode: 'production' | 'development'): Promise { 17 | const distPath = readOutDirNameFromConfig() 18 | if (distPath == null) { 19 | throw new Error('Option "compilerOptions.outDir" must be specified in tsconfig.json.') 20 | } 21 | 22 | let buildCommand = 'tsc' 23 | if (mode === 'development') { 24 | buildCommand += ' --project ./tsconfig-dev.json' 25 | } 26 | 27 | console.info('Build mode: ' + mode + '.') 28 | 29 | if (fs.existsSync(distPath)) { 30 | console.info('Removing previous build...') 31 | fs.rmdirSync(distPath, { recursive: true }) 32 | } 33 | 34 | console.info('Running command: ' + buildCommand) 35 | return await run(buildCommand) 36 | } 37 | -------------------------------------------------------------------------------- /tasks/process.ts: -------------------------------------------------------------------------------- 1 | import { exec } from 'child_process' 2 | 3 | export function finishWithFail (error: Error): void { 4 | console.error(error) 5 | process.exit(1) 6 | } 7 | 8 | export function finishWithSuccess (message?: string): void { 9 | if (message != null) { 10 | console.info(message) 11 | } 12 | process.exit(0) 13 | } 14 | 15 | export async function run (command: string): Promise { 16 | return await new Promise(function (resolve, reject) { 17 | const output: string[] = [] 18 | 19 | const child = exec(command, { 20 | cwd: process.cwd(), 21 | env: process.env 22 | }) 23 | 24 | if (child.stdout != null) { 25 | child.stdout.on('data', function (data) { 26 | console.log(data) 27 | output.push(data.toString()) 28 | }) 29 | } 30 | 31 | if (child.stderr != null) { 32 | child.stderr.on('data', function (data) { 33 | console.log(data) 34 | output.push(data.toString()) 35 | }) 36 | } 37 | 38 | child.on('exit', function (code) { 39 | const outputString = output.join('\n') 40 | 41 | if (code === 0) { 42 | resolve(outputString) 43 | } else { 44 | const errorMessage = { 45 | code: code, 46 | message: outputString 47 | } 48 | reject(new Error(JSON.stringify(errorMessage))) 49 | } 50 | }) 51 | child.on('error', reject) 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /tasks/release.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import { finishWithFail, run } from './process' 3 | 4 | function getVersionFromPackage (): string { 5 | const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')) 6 | return packageJson.version 7 | } 8 | 9 | export async function release (): Promise { 10 | console.info('Check if working directory clean.') 11 | const gitStatusResult = await run('git status --porcelain') 12 | if (gitStatusResult !== '') { 13 | finishWithFail(new Error('Git working directory not clean. Please commit changes or stash them before release.')) 14 | } 15 | 16 | console.info('Building...') 17 | await run('npm run build') 18 | 19 | const currentPackageVersion = getVersionFromPackage() 20 | 21 | console.info(`Publish package as ${currentPackageVersion}.`) 22 | await run('npm publish --access public') 23 | 24 | console.info(`Tag version as ${currentPackageVersion}.`) 25 | await run(`git tag v${currentPackageVersion}`) 26 | 27 | console.info('Bump package version.') 28 | await run('npm --no-git-tag-version version patch') 29 | const newPackageVersion = getVersionFromPackage() 30 | await run('git add package.json package-lock.json') 31 | await run(`git commit -m "Bump version to ${newPackageVersion}."`) 32 | 33 | console.info('Push changes to Git.') 34 | await run('git push && git push --tags') 35 | } 36 | -------------------------------------------------------------------------------- /tasks/run-build.ts: -------------------------------------------------------------------------------- 1 | import { build } from './build' 2 | import { finishWithFail, finishWithSuccess } from './process' 3 | 4 | try { 5 | const args = process.argv.slice(2) 6 | const mode = args.includes('-d') ? 'development' : 'production' 7 | 8 | build(mode) 9 | .then(finishWithSuccess.bind(null, 'Successfully built.')) 10 | .catch(finishWithFail) 11 | } catch (error) { 12 | finishWithFail(error) 13 | } 14 | -------------------------------------------------------------------------------- /tasks/run-release.ts: -------------------------------------------------------------------------------- 1 | import { finishWithFail, finishWithSuccess } from './process' 2 | import { release } from './release' 3 | 4 | try { 5 | release() 6 | .then(finishWithSuccess.bind(null, 'Successfully released.')) 7 | .catch(finishWithFail) 8 | } catch (error) { 9 | finishWithFail(error) 10 | } 11 | -------------------------------------------------------------------------------- /test/exclude.spec.ts: -------------------------------------------------------------------------------- 1 | import {TsConfig} from '../src/cli/interfaces' 2 | import {Completor} from '../src/cli/completor' 3 | import {Annotator} from '../src/cli/annotator' 4 | 5 | interface ComposedConfig { 6 | result: TsConfig 7 | annotator: Annotator 8 | } 9 | 10 | function composeConfig(config: TsConfig): ComposedConfig { 11 | const completor = new Completor(config, true) 12 | const annotator = new Annotator( 13 | completor.getOriginalConfig(), 14 | completor.getResultConfig() 15 | ) 16 | 17 | return { 18 | result: completor.getResultConfig(), 19 | annotator: annotator 20 | } 21 | } 22 | 23 | test('exclude has specified value', () => { 24 | const composedConfig = composeConfig({ 25 | compilerOptions: {}, 26 | exclude: ['some-folder', 'some-other-folder'] 27 | }) 28 | 29 | const annotation = composedConfig.annotator.getAnnotationFor('exclude'); 30 | expect(composedConfig.result.exclude).toEqual(['some-folder', 'some-other-folder']) 31 | expect(annotation.default).toEqual(undefined) 32 | expect(annotation.deprecation).toEqual(undefined) 33 | }) 34 | 35 | test('exclude contains package managers folders', () => { 36 | const composedConfig = composeConfig({ 37 | compilerOptions: {}, 38 | }) 39 | 40 | const annotation = composedConfig.annotator.getAnnotationFor('exclude') 41 | expect(composedConfig.result.exclude).toEqual([ 42 | 'node_modules', 43 | 'bower_components', 44 | 'jspm_packages' 45 | ]) 46 | expect(annotation.default).toEqual( 47 | 'By default ["node_modules", "bower_components", "jspm_packages"], ' + 48 | 'if `outDir` is defined then ["%outDir%"], ' + 49 | 'if `declarationDir` is defined then ["%declarationDir%"]' 50 | ) 51 | expect(annotation.deprecation).toEqual(undefined) 52 | }) 53 | 54 | test('exclude contains package managers folders and outDir', () => { 55 | const composedConfig = composeConfig({ 56 | compilerOptions: { 57 | outDir: './build' 58 | } 59 | }) 60 | 61 | const annotation = composedConfig.annotator.getAnnotationFor('exclude') 62 | expect(composedConfig.result.exclude).toEqual([ 63 | 'node_modules', 64 | 'bower_components', 65 | 'jspm_packages', 66 | './build' 67 | ]) 68 | expect(annotation.default).toEqual( 69 | 'By default ["node_modules", "bower_components", "jspm_packages"], ' + 70 | 'if `outDir` is defined then ["%outDir%"], ' + 71 | 'if `declarationDir` is defined then ["%declarationDir%"]' 72 | ) 73 | expect(annotation.deprecation).toEqual(undefined) 74 | }) 75 | 76 | test('exclude contains package managers folders and declarationDir', () => { 77 | const composedConfig = composeConfig({ 78 | compilerOptions: { 79 | declarationDir: './types' 80 | } 81 | }) 82 | 83 | const annotation = composedConfig.annotator.getAnnotationFor('exclude') 84 | expect(composedConfig.result.exclude).toEqual([ 85 | 'node_modules', 86 | 'bower_components', 87 | 'jspm_packages', 88 | './types' 89 | ]) 90 | expect(annotation.default).toEqual( 91 | 'By default ["node_modules", "bower_components", "jspm_packages"], ' + 92 | 'if `outDir` is defined then ["%outDir%"], ' + 93 | 'if `declarationDir` is defined then ["%declarationDir%"]' 94 | ) 95 | expect(annotation.deprecation).toEqual(undefined) 96 | }) 97 | 98 | test('exclude contains package managers folders, outDir and declarationDir', () => { 99 | const composedConfig = composeConfig({ 100 | compilerOptions: { 101 | outDir: './build', 102 | declarationDir: './types' 103 | } 104 | }) 105 | 106 | const annotation = composedConfig.annotator.getAnnotationFor('exclude') 107 | expect(composedConfig.result.exclude).toEqual([ 108 | 'node_modules', 109 | 'bower_components', 110 | 'jspm_packages', 111 | './build', 112 | './types' 113 | ]) 114 | expect(annotation.default).toEqual( 115 | 'By default ["node_modules", "bower_components", "jspm_packages"], ' + 116 | 'if `outDir` is defined then ["%outDir%"], ' + 117 | 'if `declarationDir` is defined then ["%declarationDir%"]' 118 | ) 119 | expect(annotation.deprecation).toEqual(undefined) 120 | }) 121 | -------------------------------------------------------------------------------- /test/files.spec.ts: -------------------------------------------------------------------------------- 1 | test('files has specified value', () => { 2 | 3 | }) 4 | 5 | test('files is not defined by default', () => { 6 | 7 | }) 8 | -------------------------------------------------------------------------------- /test/include.spec.ts: -------------------------------------------------------------------------------- 1 | 2 | test('include has specified value', () => { 3 | 4 | }) 5 | 6 | 7 | test('include is empty array if files specified', () => { 8 | 9 | }) 10 | 11 | test('include is ["**/*"] if files specified', () => { 12 | 13 | }) 14 | -------------------------------------------------------------------------------- /tsconfig-dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | // Development specific 5 | "removeComments": false, 6 | "sourceMap": true, 7 | "watch": true, 8 | // Checks 9 | "noUnusedLocals": false, 10 | "noUnusedParameters": false, 11 | "allowUnreachableCode": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig-test.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "alwaysStrict": true, 5 | "downlevelIteration": true, 6 | "emitDecoratorMetadata": true, 7 | "esModuleInterop": true, 8 | "experimentalDecorators": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "module": "CommonJS", 11 | "moduleResolution": "Node", 12 | "target": "ES6", 13 | "outDir": "./dist-test", 14 | "resolveJsonModule": true, 15 | "skipLibCheck": true, 16 | "skipDefaultLibCheck": true, 17 | "sourceMap": true, 18 | // Checks 19 | "allowUnreachableCode": false, 20 | "noFallthroughCasesInSwitch": true, 21 | "noImplicitReturns": true, 22 | "noImplicitAny": true, 23 | "noImplicitThis": true, 24 | "noUnusedLocals": true, 25 | "noUnusedParameters": true, 26 | "strictBindCallApply": true, 27 | "strictFunctionTypes": true, 28 | "strictNullChecks": true, 29 | "strictPropertyInitialization": true, 30 | "exactOptionalPropertyTypes": true 31 | }, 32 | "include": [ 33 | "./test" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "alwaysStrict": true, 5 | "downlevelIteration": true, 6 | "emitDecoratorMetadata": true, 7 | "esModuleInterop": true, 8 | "experimentalDecorators": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "module": "CommonJS", 11 | "moduleResolution": "Node", 12 | "target": "ES2015", 13 | "outDir": "./dist", 14 | "declaration": true, 15 | "declarationDir": "./dist/__types__", 16 | "resolveJsonModule": true, 17 | "skipLibCheck": true, 18 | "skipDefaultLibCheck": true, 19 | // Production specific 20 | "removeComments": true, 21 | "sourceMap": false, 22 | "watch": false, 23 | // Checks 24 | "allowUnreachableCode": false, 25 | "noFallthroughCasesInSwitch": true, 26 | "noImplicitReturns": true, 27 | "noImplicitAny": true, 28 | "noImplicitThis": true, 29 | "noUnusedLocals": true, 30 | "noUnusedParameters": true, 31 | "strictBindCallApply": true, 32 | "strictFunctionTypes": true, 33 | "strictNullChecks": true, 34 | "strictPropertyInitialization": true, 35 | "exactOptionalPropertyTypes": true 36 | }, 37 | "files": [ 38 | "./src/cli/index.ts" 39 | ] 40 | } 41 | --------------------------------------------------------------------------------