├── .nvmrc ├── .eslintignore ├── .gitignore ├── renovate.json ├── assets ├── noErrorTruncation.false.png └── noErrorTruncation.true.png ├── _private ├── executable.json ├── module.json └── common.json ├── .vscode └── settings.json ├── agnostic-module.json ├── browser-module.json ├── browser-executable.json ├── tsconfig.configs.json ├── webworker-module.json ├── .editorconfig ├── .eslintrc.json ├── nodejs-module.json ├── tsconfig.json ├── nodejs-executable.json ├── .travis.yml ├── commitlint.config.js ├── src ├── shared.ts ├── browser-executable.test.ts ├── agnostic-module.test.ts ├── webworker-module.test.ts ├── browser-module.test.ts ├── nodejs-executable.test.ts ├── nodejs-module.test.ts ├── unit-test-macro.ts └── integration-test-macro.ts ├── CHANGELOG.md ├── package.json └── readme.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 15.4.0 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | lib 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | node_modules 3 | tsconfig.tsbuildinfo 4 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "github>mightyiam/renovate-config:js-lib" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /assets/noErrorTruncation.false.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightyiam/tsconfigs/HEAD/assets/noErrorTruncation.false.png -------------------------------------------------------------------------------- /assets/noErrorTruncation.true.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightyiam/tsconfigs/HEAD/assets/noErrorTruncation.true.png -------------------------------------------------------------------------------- /_private/executable.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./common", 3 | "compilerOptions": { 4 | "composite": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /_private/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./common", 3 | "compilerOptions": { 4 | "declaration": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.validate": [ 3 | "typescript" 4 | ], 5 | "typescript.tsdk": "node_modules/typescript/lib" 6 | } 7 | -------------------------------------------------------------------------------- /agnostic-module.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./_private/module", 3 | "compilerOptions": { 4 | "lib": ["ESNext"], 5 | "module": "CommonJS", 6 | "types": [] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /browser-module.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./_private/module", 3 | "compilerOptions": { 4 | "lib": ["ESNext", "DOM"], 5 | "module": "ESNext", 6 | "types": [] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /browser-executable.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./_private/executable", 3 | "compilerOptions": { 4 | "lib": ["ESNext", "DOM"], 5 | "module": "ESNext", 6 | "types": [] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.configs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./nodejs-executable", 3 | "compilerOptions": { 4 | "noEmit": true 5 | }, 6 | "files": [ 7 | "commitlint.config.js" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /webworker-module.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./_private/module", 3 | "compilerOptions": { 4 | "lib": ["ESNext", "WebWorker"], 5 | "module": "ESNext", 6 | "types": [] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard-with-typescript", 3 | "parserOptions": { 4 | "project": [ 5 | "./tsconfig.json", 6 | "./tsconfig.configs.json" 7 | ] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /nodejs-module.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./_private/module", 3 | "compilerOptions": { 4 | "lib": ["ESNext"], 5 | "module": "CommonJS", 6 | "types": [ 7 | "node" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./nodejs-executable", 3 | "compilerOptions": { 4 | "outDir": "./lib", 5 | "rootDir": "./src" 6 | }, 7 | "include": [ 8 | "./src/**/*" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /nodejs-executable.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./_private/executable", 3 | "compilerOptions": { 4 | "lib": ["ESNext"], 5 | "module": "CommonJS", 6 | "types": [ 7 | "node" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | - "12" 5 | - "14" 6 | - "15" 7 | before_install: 8 | - npm install -g npm 9 | install: npm install 10 | script: 11 | - commitlint-travis 12 | - npm run test 13 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'scope-enum': [2, 'always', [ 5 | 'commitlint', 6 | 'package', 7 | 'docs', 8 | 'deps' 9 | ]] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /_private/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "esModuleInterop": true, 5 | "forceConsistentCasingInFileNames": true, 6 | "moduleResolution": "Node", 7 | "newLine": "LF", 8 | "noErrorTruncation": true, 9 | "resolveJsonModule": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "target": "esnext" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/shared.ts: -------------------------------------------------------------------------------- 1 | export type ConfigName = 2 | 'nodejs-executable' | 3 | 'nodejs-module' | 4 | 'browser-executable' | 5 | 'browser-module' | 6 | 'webworker-module' | 7 | 'agnostic-module' 8 | 9 | export const common = { 10 | allowSyntheticDefaultImports: true, 11 | esModuleInterop: true, 12 | forceConsistentCasingInFileNames: true, 13 | moduleResolution: 'Node', 14 | newLine: 'lf', 15 | noErrorTruncation: true, 16 | resolveJsonModule: true, 17 | sourceMap: true, 18 | strict: true, 19 | target: 'ESNext' 20 | } 21 | 22 | export const executable = { composite: false } 23 | 24 | export const importable = { declaration: true } 25 | -------------------------------------------------------------------------------- /src/browser-executable.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { unitTest } from './unit-test-macro' 3 | import { common, executable } from './shared' 4 | import { integrationTest } from './integration-test-macro' 5 | 6 | test(unitTest, 'browser-executable', { 7 | compilerOptions: { 8 | ...common, 9 | ...executable, 10 | lib: ['ESNext', 'DOM'], 11 | module: 'ESNext', 12 | types: [] 13 | } 14 | }) 15 | 16 | test(integrationTest, { 17 | name: 'browser-executable', 18 | additionalDependencies: [], 19 | srcFiles: [ 20 | { 21 | filename: 'index.ts', 22 | contents: [ 23 | 'document.querySelector("div")', 24 | 'export const foo = 0' 25 | ].join('\n') 26 | } 27 | ], 28 | expectedOutputFiles: [ 29 | { 30 | filename: 'index.js', 31 | expectedContents: [ 32 | 'document.querySelector("div");', 33 | 'export const foo = 0;', 34 | '//# sourceMappingURL=index.js.map' 35 | ].join('\n') 36 | }, 37 | { 38 | filename: 'index.js.map', 39 | expectedContents: JSON.stringify({ 40 | version: 3, 41 | file: 'index.js', 42 | sourceRoot: '', 43 | sources: ['../src/index.ts'], 44 | names: [], 45 | mappings: 'AAAA,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;AAC7B,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAA' 46 | }) 47 | } 48 | ] 49 | }) 50 | -------------------------------------------------------------------------------- /src/agnostic-module.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { unitTest } from './unit-test-macro' 3 | import { common, importable } from './shared' 4 | import { integrationTest } from './integration-test-macro' 5 | 6 | test(unitTest, 'agnostic-module', { 7 | compilerOptions: { 8 | ...common, 9 | ...importable, 10 | lib: ['ESNext'], 11 | module: 'CommonJS', 12 | types: [] 13 | } 14 | }) 15 | 16 | test(integrationTest, { 17 | name: 'agnostic-module', 18 | additionalDependencies: [], 19 | srcFiles: [ 20 | { 21 | filename: 'index.ts', 22 | contents: 'export const foo = 0' 23 | } 24 | ], 25 | expectedOutputFiles: [ 26 | { 27 | filename: 'index.js', 28 | expectedContents: [ 29 | '"use strict";', 30 | 'Object.defineProperty(exports, "__esModule", { value: true });', 31 | 'exports.foo = void 0;', 32 | 'exports.foo = 0;', 33 | '//# sourceMappingURL=index.js.map' 34 | ].join('\n') 35 | }, 36 | { 37 | filename: 'index.d.ts', 38 | expectedContents: 'export declare const foo = 0;\n' 39 | }, 40 | { 41 | filename: 'index.js.map', 42 | expectedContents: JSON.stringify({ 43 | version: 3, 44 | file: 'index.js', 45 | sourceRoot: '', 46 | sources: ['../src/index.ts'], 47 | names: [], 48 | mappings: ';;;AAAa,QAAA,GAAG,GAAG,CAAC,CAAA' 49 | }) 50 | } 51 | ] 52 | }) 53 | -------------------------------------------------------------------------------- /src/webworker-module.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { unitTest } from './unit-test-macro' 3 | import { common, importable } from './shared' 4 | import { integrationTest } from './integration-test-macro' 5 | 6 | test(unitTest, 'webworker-module', { 7 | compilerOptions: { 8 | ...common, 9 | ...importable, 10 | lib: ['ESNext', 'WebWorker'], 11 | module: 'ESNext', 12 | types: [] 13 | } 14 | }) 15 | 16 | test(integrationTest, { 17 | name: 'webworker-module', 18 | additionalDependencies: [], 19 | srcFiles: [ 20 | { 21 | filename: 'index.ts', 22 | contents: [ 23 | 'self.importScripts()', 24 | 'export const foo = 0' 25 | ].join('\n') 26 | } 27 | ], 28 | expectedOutputFiles: [ 29 | { 30 | filename: 'index.js', 31 | expectedContents: [ 32 | 'self.importScripts();', 33 | 'export const foo = 0;', 34 | '//# sourceMappingURL=index.js.map' 35 | ].join('\n') 36 | }, 37 | { 38 | filename: 'index.d.ts', 39 | expectedContents: 'export declare const foo = 0;\n' 40 | }, 41 | { 42 | filename: 'index.js.map', 43 | expectedContents: JSON.stringify({ 44 | version: 3, 45 | file: 'index.js', 46 | sourceRoot: '', 47 | sources: ['../src/index.ts'], 48 | names: [], 49 | mappings: 'AAAA,IAAI,CAAC,aAAa,EAAE,CAAA;AACpB,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAA' 50 | }) 51 | } 52 | ] 53 | }) 54 | -------------------------------------------------------------------------------- /src/browser-module.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { unitTest } from './unit-test-macro' 3 | import { common, importable } from './shared' 4 | import { integrationTest } from './integration-test-macro' 5 | 6 | test(unitTest, 'browser-module', { 7 | compilerOptions: { 8 | ...common, 9 | ...importable, 10 | lib: ['ESNext', 'DOM'], 11 | module: 'ESNext', 12 | types: [] 13 | } 14 | }) 15 | 16 | test(integrationTest, { 17 | name: 'browser-module', 18 | additionalDependencies: [], 19 | srcFiles: [ 20 | { 21 | filename: 'index.ts', 22 | contents: [ 23 | 'document.querySelector("div")', 24 | 'export const foo = 0' 25 | ].join('\n') 26 | } 27 | ], 28 | expectedOutputFiles: [ 29 | { 30 | filename: 'index.js', 31 | expectedContents: [ 32 | 'document.querySelector("div");', 33 | 'export const foo = 0;', 34 | '//# sourceMappingURL=index.js.map' 35 | ].join('\n') 36 | }, 37 | { 38 | filename: 'index.d.ts', 39 | expectedContents: 'export declare const foo = 0;\n' 40 | }, 41 | { 42 | filename: 'index.js.map', 43 | expectedContents: JSON.stringify({ 44 | version: 3, 45 | file: 'index.js', 46 | sourceRoot: '', 47 | sources: ['../src/index.ts'], 48 | names: [], 49 | mappings: 'AAAA,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;AAC7B,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAA' 50 | }) 51 | } 52 | ] 53 | }) 54 | -------------------------------------------------------------------------------- /src/nodejs-executable.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { unitTest } from './unit-test-macro' 3 | import { common, executable } from './shared' 4 | import { integrationTest } from './integration-test-macro' 5 | 6 | test(unitTest, 'nodejs-executable', 7 | { 8 | compilerOptions: { 9 | ...common, 10 | ...executable, 11 | lib: ['ESNext'], 12 | module: 'CommonJS', 13 | types: [ 14 | 'node' 15 | ] 16 | } 17 | } 18 | ) 19 | 20 | test(integrationTest, { 21 | name: 'nodejs-executable', 22 | additionalDependencies: ['@types/node'], 23 | srcFiles: [ 24 | { 25 | filename: 'index.ts', 26 | contents: [ 27 | "console.log('foo')", 28 | 'export const foo = 0' 29 | ].join('\n') 30 | } 31 | ], 32 | expectedOutputFiles: [ 33 | { 34 | filename: 'index.js', 35 | expectedContents: [ 36 | '"use strict";', 37 | 'Object.defineProperty(exports, "__esModule", { value: true });', 38 | 'exports.foo = void 0;', 39 | 'console.log(\'foo\');', 40 | 'exports.foo = 0;', 41 | '//# sourceMappingURL=index.js.map' 42 | ].join('\n') 43 | }, 44 | { 45 | filename: 'index.js.map', 46 | expectedContents: JSON.stringify({ 47 | version: 3, 48 | file: 'index.js', 49 | sourceRoot: '', 50 | sources: ['../src/index.ts'], 51 | names: [], 52 | mappings: ';;;AAAA,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AACL,QAAA,GAAG,GAAG,CAAC,CAAA' 53 | }) 54 | } 55 | ] 56 | }) 57 | -------------------------------------------------------------------------------- /src/nodejs-module.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { unitTest } from './unit-test-macro' 3 | import { common, importable } from './shared' 4 | import { integrationTest } from './integration-test-macro' 5 | 6 | test(unitTest, 'nodejs-module', { 7 | compilerOptions: { 8 | ...common, 9 | ...importable, 10 | lib: ['ESNext'], 11 | module: 'CommonJS', 12 | types: [ 13 | 'node' 14 | ] 15 | } 16 | }) 17 | 18 | test(integrationTest, { 19 | name: 'nodejs-module', 20 | additionalDependencies: ['@types/node'], 21 | srcFiles: [ 22 | { 23 | filename: 'index.ts', 24 | contents: [ 25 | 'process.exit()', 26 | 'export const foo = 0' 27 | ].join('\n') 28 | } 29 | ], 30 | expectedOutputFiles: [ 31 | { 32 | filename: 'index.js', 33 | expectedContents: [ 34 | '"use strict";', 35 | 'Object.defineProperty(exports, "__esModule", { value: true });', 36 | 'exports.foo = void 0;', 37 | 'process.exit();', 38 | 'exports.foo = 0;', 39 | '//# sourceMappingURL=index.js.map' 40 | ].join('\n') 41 | }, 42 | { 43 | filename: 'index.d.ts', 44 | expectedContents: 'export declare const foo = 0;\n' 45 | }, 46 | { 47 | filename: 'index.js.map', 48 | expectedContents: JSON.stringify({ 49 | version: 3, 50 | file: 'index.js', 51 | sourceRoot: '', 52 | sources: ['../src/index.ts'], 53 | names: [], 54 | mappings: ';;;AAAA,OAAO,CAAC,IAAI,EAAE,CAAA;AACD,QAAA,GAAG,GAAG,CAAC,CAAA' 55 | }) 56 | } 57 | ] 58 | }) 59 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## [5.0.0](https://github.com/mightyiam/tsconfigs/compare/v4.0.2...v5.0.0) (2020-06-08) 6 | 7 | 8 | ### ⚠ BREAKING CHANGES 9 | 10 | * in order to disable automatic inclusion of @types packages, 11 | `compilerOptions.types` is set for all project kinds. in the case of 12 | `browser-module`, `browser-executable`, `webworker-module` and 13 | `agnostic-module`, it was previously unset and now it is set to `[]`. In order 14 | to include an @types package, `compilerOptions.types` must override the value 15 | set by the project kind. Extending from any of the `nodejs` kinds, the override 16 | should also include `"node"`. For example, to include the 17 | `@types/webpack-dev-server` package, the value of your 18 | `compilerOptions.types` should be `["node", "webpack-dev-server"]`. 19 | 20 | ### Features 21 | 22 | * `compilerOptions.types` is set for all kinds ([023cf78](https://github.com/mightyiam/tsconfigs/commit/023cf785e5d4a11b6cda319ce84d7f648b4bc02a)) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * skip tagging in npm release script ([8a5c0f2](https://github.com/mightyiam/tsconfigs/commit/8a5c0f235455f7c0e2bbc78d5fae4557e1faa795)) 28 | 29 | ### [4.0.2](https://github.com/mightyiam/tsconfigs/compare/v4.0.1...v4.0.2) (2019-11-22) 30 | 31 | ### [4.0.1](https://github.com/mightyiam/tsconfigs/compare/v4.0.0...v4.0.1) (2019-10-01) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * include _private base configs in package ([05dafd7](https://github.com/mightyiam/tsconfigs/commit/05dafd7)) 37 | 38 | ## [4.0.0](https://github.com/mightyiam/tsconfigs/compare/v3.0.0...v4.0.0) (2019-09-30) 39 | 40 | 41 | ### ⚠ BREAKING CHANGES 42 | 43 | * Complete rewrite. 44 | 45 | Co-authored-by: Cleaver Barnes 46 | 47 | ### Features 48 | 49 | * complete rewrite ([37e0629](https://github.com/mightyiam/tsconfigs/commit/37e0629)) 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsconfigs", 3 | "version": "5.0.0", 4 | "description": "Reusable TypeScript configuration files to extend from.", 5 | "scripts": { 6 | "release": "standard-version --skip.tag", 7 | "readme-toc": "doctoc readme.md", 8 | "lint": "eslint .", 9 | "transpile": "tsc", 10 | "unit": "ava", 11 | "test": "run-s lint transpile unit" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/mightyiam/tsconfigs.git" 16 | }, 17 | "keywords": [ 18 | "tsconfig", 19 | "common", 20 | "extend", 21 | "extends" 22 | ], 23 | "author": "Shahar Or (https://mightyi.am/)", 24 | "license": "ISC", 25 | "bugs": { 26 | "url": "https://github.com/mightyiam/tsconfigs/issues" 27 | }, 28 | "husky": { 29 | "hooks": { 30 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", 31 | "pre-commit": "npm run test" 32 | } 33 | }, 34 | "homepage": "https://github.com/mightyiam/tsconfigs#readme", 35 | "devDependencies": { 36 | "@commitlint/cli": "11.0.0", 37 | "@commitlint/config-conventional": "11.0.0", 38 | "@commitlint/travis-cli": "11.0.0", 39 | "@types/node": "14.14.17", 40 | "@typescript-eslint/eslint-plugin": "4.11.1", 41 | "ava": "3.14.0", 42 | "doctoc": "1.4.0", 43 | "eslint": "7.16.0", 44 | "eslint-config-standard-with-typescript": "19.0.1", 45 | "eslint-plugin-import": "2.22.1", 46 | "eslint-plugin-node": "11.1.0", 47 | "eslint-plugin-promise": "4.2.1", 48 | "eslint-plugin-standard": "4.1.0", 49 | "eslint-plugin-typescript": "0.14.0", 50 | "husky": "4.3.6", 51 | "npm-run-all": "4.1.5", 52 | "object.fromentries": "2.0.3", 53 | "read-pkg-up": "7.0.1", 54 | "standard-version": "9.1.0", 55 | "tempy": "1.0.0", 56 | "typescript": "4.1.3" 57 | }, 58 | "files": [ 59 | "browser-executable.json", 60 | "browser-module.json", 61 | "webworker-module.json", 62 | "nodejs-executable.json", 63 | "nodejs-module.json", 64 | "agnostic-module.json", 65 | "_private/common.json", 66 | "_private/executable.json", 67 | "_private/module.json" 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /src/unit-test-macro.ts: -------------------------------------------------------------------------------- 1 | import { Macro, ExecutionContext } from 'ava' 2 | import { resolve, dirname } from 'path' 3 | import { readFileSync } from 'fs' 4 | import { libMap, CompilerOptions, ModuleKind, ModuleResolutionKind, NewLineKind, ScriptTarget, readConfigFile, parseJsonConfigFileContent, sys } from 'typescript' 5 | import { ConfigName } from './shared' 6 | import 'object.fromentries/auto' 7 | declare module 'typescript' { 8 | export const libMap: Map 9 | } 10 | 11 | type OptionValue = CompilerOptions[string] 12 | type OptionParser = (value: any) => CompilerOptions[string] 13 | 14 | const optionParsers: { [key: string ]: OptionParser } = { 15 | lib: (libs: string[]): string[] => libs.map((lib): string => libMap.get(lib.toLowerCase()) as string), 16 | module: (kind: ModuleKind): string => ModuleKind[kind], 17 | moduleResolution: (kind: string): string => { 18 | const map: any = { 19 | node: ModuleResolutionKind.NodeJs, 20 | classic: ModuleResolutionKind.Classic 21 | } 22 | return map[kind.toLowerCase()] 23 | }, 24 | newLine: (kind: string): string => { 25 | const map: any = { 26 | lf: NewLineKind.LineFeed, 27 | crlf: NewLineKind.CarriageReturnLineFeed 28 | } 29 | return map[kind.toLowerCase()] 30 | }, 31 | target: (kind: ScriptTarget): string => ScriptTarget[kind] 32 | } 33 | 34 | const rawToCompilerOptions = (raw: any): CompilerOptions => ({ 35 | configFilePath: undefined, 36 | ...Object.fromEntries( 37 | Object.entries(raw) 38 | .map(([key, value]: [string, any]): [string, OptionValue] => { 39 | const parser = optionParsers[key] 40 | if (parser === undefined) return [key, value] 41 | return [key, parser(value)] 42 | }) 43 | ) 44 | }) 45 | 46 | export const unitTest: Macro<[ConfigName, any]> = ( 47 | t: ExecutionContext, 48 | configName: ConfigName, 49 | { compilerOptions: rawExpectedOptions }: any 50 | ): void => { 51 | const expectedOptions = rawToCompilerOptions(rawExpectedOptions) 52 | 53 | const path = resolve(__dirname, '..', `${configName}.json`) 54 | const { config } = readConfigFile( 55 | path, 56 | (path: string): string => readFileSync(path, { encoding: 'utf-8' }) 57 | ) 58 | const actual = parseJsonConfigFileContent(config, sys, dirname(path)) 59 | 60 | t.deepEqual(actual.options, expectedOptions) 61 | } 62 | 63 | unitTest.title = () => 'unit' 64 | -------------------------------------------------------------------------------- /src/integration-test-macro.ts: -------------------------------------------------------------------------------- 1 | import { Macro, ExecutionContext } from 'ava' 2 | import { ConfigName } from './shared' 3 | import tempy from 'tempy' 4 | import { spawnSync } from 'child_process' 5 | import { resolve } from 'path' 6 | import readPkgUp from 'read-pkg-up' 7 | import { writeFileSync, mkdirSync, readFileSync, readdirSync } from 'fs' 8 | 9 | export interface IntegrationTestInput { 10 | name: ConfigName 11 | additionalDependencies: string[] 12 | srcFiles: Array<{ 13 | filename: string 14 | contents: string 15 | }> 16 | expectedOutputFiles: Array<{ 17 | filename: string 18 | expectedContents: string 19 | }> 20 | } 21 | 22 | const srcDir = 'src' 23 | const outDir = 'lib' 24 | 25 | export const integrationTest: Macro<[IntegrationTestInput]> = ( 26 | t: ExecutionContext, 27 | { name, additionalDependencies, srcFiles, expectedOutputFiles } 28 | ) => { 29 | const tmpDirPath = tempy.directory() 30 | const pkgJson = readPkgUp.sync() 31 | if (pkgJson === undefined) throw new Error() 32 | if (pkgJson.packageJson === undefined) throw new Error() 33 | if (pkgJson.packageJson.devDependencies === undefined) throw new Error() 34 | const typescriptVersion = pkgJson.packageJson.devDependencies.typescript 35 | const npmInstallCmd = spawnSync( 36 | 'npm', 37 | [ 38 | 'install', 39 | '--loglevel', 'error', 40 | '--no-save', 41 | '--no-package-lock', 42 | `typescript@${typescriptVersion}`, 43 | ...additionalDependencies, 44 | resolve(__dirname, '..') 45 | ], 46 | { cwd: tmpDirPath } 47 | ) 48 | if (npmInstallCmd.status !== 0) { 49 | t.log(npmInstallCmd.stdout.toString()) 50 | t.log(npmInstallCmd.stderr.toString()) 51 | t.fail() 52 | } 53 | writeFileSync( 54 | resolve(tmpDirPath, 'tsconfig.json'), 55 | JSON.stringify({ 56 | extends: `tsconfigs/${name}`, 57 | compilerOptions: { outDir }, 58 | include: [`${srcDir}/**/*`] 59 | }) 60 | ) 61 | mkdirSync(resolve(tmpDirPath, srcDir)) 62 | srcFiles.forEach(({ filename, contents }) => { 63 | writeFileSync( 64 | resolve(tmpDirPath, srcDir, filename), 65 | contents 66 | ) 67 | }) 68 | const tscCmd = spawnSync('npx', ['tsc'], { cwd: tmpDirPath }) 69 | if (tscCmd.status !== 0) { 70 | t.log(tscCmd.stdout.toString()) 71 | t.log(tscCmd.stderr.toString()) 72 | t.fail() 73 | } 74 | expectedOutputFiles.forEach(({ filename, expectedContents }) => { 75 | const resultJs = readFileSync(resolve(tmpDirPath, outDir, filename)) 76 | t.is(resultJs.toString(), expectedContents) 77 | }) 78 | // eslint-disable-next-line @typescript-eslint/require-array-sort-compare 79 | const emittedFilenames = readdirSync(resolve(tmpDirPath, outDir)) 80 | .sort() 81 | // eslint-disable-next-line @typescript-eslint/require-array-sort-compare 82 | const expectedEmittedFilenames = expectedOutputFiles 83 | .map(({ filename }) => filename) 84 | .sort() 85 | t.deepEqual(emittedFilenames, expectedEmittedFilenames) 86 | } 87 | 88 | integrationTest.title = () => 'integration' 89 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ⚙️ tsconfigs ✨ 2 | 3 | [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com) [![Build Status](https://travis-ci.org/mightyiam/tsconfigs.svg?branch=master)](https://travis-ci.org/mightyiam/tsconfigs) [![Badge: npm version badge for package `tsconfigs`](https://img.shields.io/npm/v/tsconfigs.svg)](https://www.npmjs.com/package/tsconfigs) 4 | 5 | Reusable TypeScript configuration files 6 | 7 | 8 | 9 | ## Contents 10 | 11 | - [Overview](#overview) 12 | - [Project kinds](#project-kinds) 13 | - [Example](#example) 14 | - [Scope](#scope) 15 | - [Executable project options](#executable-project-options) 16 | - [Module project options](#module-project-options) 17 | - [Environment](#environment) 18 | - [Browser project options](#browser-project-options) 19 | - [Web Worker project options](#web-worker-project-options) 20 | - [Node.js project options](#nodejs-project-options) 21 | - [Agnostic project options](#agnostic-project-options) 22 | - [Common project options](#common-project-options) 23 | - [Strictness](#strictness) 24 | - [Paths](#paths) 25 | - [Test coverage](#test-coverage) 26 | 27 | 28 | 29 | ## Overview 30 | 31 | Say you're starting a new TypeScript project. And you're setting up the `tsconfig.json`. If you're a TypeScript wizard 🧙‍ you quickly fill in some options and you're done. But If you're a meer mortal like most of us, you go back to the documentation every time 🤔. After several times of that I decided to write this little project 💡. 32 | 33 | If your project is one of the following kinds of projects, you could extend from one of them, instead of writing your own from blank. And then you could override any options necessary. 34 | 35 | ## Project kinds 36 | 37 | | | [Module ⚙️](#module-project-options) | [Executable 🚄](#executable-project-options) | 38 | |-| ------ | ---------- | 39 | | [Browser 🌐](#browser-project-options) | [`browser-module`](browser-module.json) | [`browser-executable`](browser-executable.json) | 40 | | [Web Worker ⛏️](#web-worker-project-options) | [`webworker-module`](webworker-module.json) | 41 | | [Node.js ⬡](#nodejs-project-options) | [`nodejs-module`](nodejs-module.json) | [`nodejs-executable`](nodejs-executable.json) | 42 | | [Agnostic 🏳️](#agnostic-project-options) | [`agnostic-module`](agnostic-module.json) | 43 | 44 | ## Example 45 | 46 | Install this package ([`tsconfigs`](https://www.npmjs.com/package/tsconfigs)) and in your `tsconfig.json`: 47 | 48 | ```jsonc 49 | { 50 | "extends": "tsconfigs/nodejs-executable", // 🎆 51 | "compilerOptions": { 52 | "outDir": "lib" 53 | }, 54 | "include": [ 55 | "src/**/*" 56 | ] 57 | } 58 | ``` 59 | 60 | ## Scope 61 | 62 | ### Executable project options 63 | 64 | | Option | Default value | Our value | Comment | 65 | | ------ | ------------------ | --------- | ----------- | 66 | | `composite` | `true` | `false` | It seems to have no benefit for executables and it necessitates generation of declaration files, which seem useless in executables, as well. 67 | 68 | ### Module project options 69 | 70 | | Option | Default value | Our value | Comment | 71 | | ------ | ------------------ | --------- | ----------- | 72 | | `declaration` | `false` | `true` | Because we'd like to provide the importer with type definitions. | 73 | 74 | ## Environment 75 | 76 | ### Browser project options 77 | 78 | | Option | Default value | Our value | 79 | | ------ | ------------------ | --------- | 80 | | `lib` | depends | `["ESNext","DOM"]` | 81 | | `module` | depends | `"ESNext"` | 82 | 83 | ### Web Worker project options 84 | 85 | | Option | Default value | Our value | 86 | | ------ | ------------------ | --------- | 87 | | `lib` | depends | `["ESNext","WebWorker"]` | 88 | | `module` | depends | `"ESNext"` | 89 | 90 | ### Node.js project options 91 | 92 | | Option | Default value | Our value | Comment | 93 | | ------ | ------------------ | --------- | ------- | 94 | | `lib` | depends | `["ESNext"]`. | You'd most likely also like to install the [`@types/node` package](https://www.npmjs.com/package/@types/node). | 95 | | `module` | depends | `"CommonJS"` | 96 | 97 | ### Agnostic project options 98 | 99 | | Option | Default value | Our value | Comment | 100 | | ------ | ------------------ | --------- | ------- | 101 | | `lib` | depends | `["ESNext"]` | 102 | | `module` | depends | `"CommonJS"` | While for small packages, CommonJS could be just fine, for larger packages, where the ability to perform tree shaking is desirable, it seems that the agnostic project author should consider providing two builds. One CommonJS build and one ES modules build. 103 | 104 | ## Common project options 105 | 106 | | Option | Default value | Our value | Comment | 107 | | ------ | ------------------ | --------- | ----------- | 108 | | `allowSyntheticDefaultImports` | depends | `true` | [Stack Overflow question](https://stackoverflow.com/questions/56238356/understanding-esmoduleinterop-in-tsconfig-file) | 109 | | `esModuleInterop` | `false` | `true` | [Stack Overflow question](https://stackoverflow.com/questions/56238356/understanding-esmoduleinterop-in-tsconfig-file) 110 | | `forceConsistentCasingInFileNames` | `false` | `true` | While it does not enforce case sensitivity, it at least enforces consistent casing across references. | 111 | | `moduleResolution` | depends | `"node"` | The de-facto standard. | 112 | | `newLine` | depends | `"LF"` | For the sake of consistent build artifacts cross-platform. | 113 | | `noErrorTruncation` | `false` | `true` | Screenshots: [`false`](assets/noErrorTruncation.false.png) / [`true`](assets/noErrorTruncation.true.png) | 114 | | `resolveJsonModule` | `false` | `true` | Seems like a popular feature that does not involve drawbacks. | 115 | | `sourceMap` | `false` | `true` | We have chosen regular source maps because it seems like the simple choice that would serve most projects. 116 | | `strict` | `false` | `true` | See [`Strictness`](#strictness). | 117 | | `target` | `"es3"` | `"esnext"` | Down-transpilation is outside the scope of this project. Also, consider using [Babel](https://babeljs.io) instead of TypeScript for that. | 118 | 119 | ## Strictness 120 | 121 | We presume that strict type checking is generally desirable. 122 | 123 | New type checking features in future releases of TypeScript are, per policy, turned off by default, for backward compatibility. Effectively making new type features, *opt-in*. 124 | 125 | The `strict` option, however, turns on a set of strict type checking options. New strict options from future TypeScript releases will be included in it, effectively making new type checking features *opt-out*. 126 | 127 | tsconfigs maintains the *opt-out* behavior: we turn `strict` on and yet keep the individual type check options that it includes, off. 128 | 129 | ## Paths 130 | 131 | We would love to include some [path options like `include` and `outDir`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#details) but we feel that it would not be reliable, because TypeScript resolves relative paths from the configuration file in which they appear and not from the end-configuration file. See [this issue](https://github.com/mightyiam/tsconfigs/issues/83). 132 | 133 | ## Test coverage 134 | 135 | There are both [unit](src/unit-test-macro.ts) and [integration](src/integration-test-macro.ts) tests [for each config](src). 136 | --------------------------------------------------------------------------------