From 5f35e0919ddfc89e27479b90e188cbc97446e9b1 Mon Sep 17 00:00:00 2001 From: Ali Ijaz Sheikh Date: Wed, 6 Feb 2019 13:23:57 -0800 Subject: [PATCH] feat!: switch to prettier for formatting (#259) * feat!: switch to prettier for formatting BREAKING CHANGE: Switch to prettier as the code formatter. Fixes: https://github.com/google/ts-style/issues/156 --- .prettierrc | 8 -- README.md | 4 +- package-lock.json | 73 +++-------- package.json | 4 +- prettier.config.js | 4 + src/clean.ts | 4 +- src/cli.ts | 14 +-- src/format.ts | 284 ++++++++----------------------------------- src/init.ts | 19 +-- src/lint.ts | 8 +- src/util.ts | 2 +- test/fixtures.ts | 2 +- test/test-clean.ts | 22 ++-- test/test-format.ts | 151 +++++++++++++---------- test/test-init.ts | 32 ++--- test/test-kitchen.ts | 12 +- test/test-lint.ts | 44 +++---- test/test-util.ts | 32 ++--- 18 files changed, 264 insertions(+), 455 deletions(-) delete mode 100644 .prettierrc create mode 100644 prettier.config.js diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index df6eac07..00000000 --- a/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ ---- -bracketSpacing: false -printWidth: 80 -semi: true -singleQuote: true -tabWidth: 2 -trailingComma: es5 -useTabs: false diff --git a/README.md b/README.md index bc9651d9..4e540724 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ - **Catch style issues & programmer errors early**. Save precious code review time by eliminating back-and-forth between reviewer & contributor. - **Opinionated, but not to a fault**. We recommend you use the default configuration, but if you *need* to customize compiler or linter config, you can. -Under the covers, we use [tslint][tslint-url] to enforce the style guide and provide automated fixes, and [clang-format][clang-format-url] to re-format code. +Under the covers, we use [tslint][tslint-url] to enforce the style guide and provide automated fixes, and [prettier][prettier-url] to re-format code. Made with ❤️ by the Google Node.js team. @@ -59,7 +59,7 @@ See [LICENSE](LICENSE) [circle-image]: https://circleci.com/gh/google/ts-style.svg?style=svg [circle-url]: https://circleci.com/gh/google/ts-style -[clang-format-url]: https://github.com/angular/clang-format +[prettier-url]: https://prettier.io/ [codecov-image]: https://codecov.io/gh/google/ts-style/branch/master/graph/badge.svg [codecov-url]: https://codecov.io/gh/google/ts-style [david-dev-image]: https://david-dm.org/google/ts-style/dev-status.svg diff --git a/package-lock.json b/package-lock.json index 631bc8dc..465475b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -505,6 +505,12 @@ "integrity": "sha512-a5AKF1/9pCU3HGMkesgY6LsBdXHUY3WU+I2qgpU0J+I8XuJA1aFr59eS84/HP0+dxsyBSNbt+4yGI2adUpHwSg==", "dev": true }, + "@types/prettier": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.15.2.tgz", + "integrity": "sha512-XIB0ZCaFZmWUHAa9dBqP5UKXXHwuukmVlP+XcyU94dui2k+l2lG+CHAbt2ffenHPUqoIs5Beh8Pdf2YEq/CZ7A==", + "dev": true + }, "@types/rimraf": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.2.tgz", @@ -808,11 +814,6 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" - }, "async-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", @@ -1352,16 +1353,6 @@ "integrity": "sha512-u6dx20FBXm+apMi+5x7UVm6EH7BL1gc4XrcnQewjcB7HWRcor/V5qWc3RG2HwpgDJ26gIi2DSEu3B7sXynAw/g==", "dev": true }, - "clang-format": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/clang-format/-/clang-format-1.2.3.tgz", - "integrity": "sha512-x90Hac4ERacGDcZSvHKK58Ga0STuMD+Doi5g0iG2zf7wlJef5Huvhs/3BvMRFxwRYyYSdl6mpQNrtfMxE8MQzw==", - "requires": { - "async": "^1.5.2", - "glob": "^7.0.0", - "resolve": "^1.1.6" - } - }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -2210,8 +2201,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -2232,14 +2222,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2254,20 +2242,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -2384,8 +2369,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -2397,7 +2381,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2412,7 +2395,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2420,14 +2402,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -2446,7 +2426,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -2527,8 +2506,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -2540,7 +2518,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -2626,8 +2603,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -2663,7 +2639,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2683,7 +2658,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2727,14 +2701,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -3890,7 +3862,6 @@ "version": "0.1.4", "bundled": true, "dev": true, - "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -4215,8 +4186,7 @@ "is-buffer": { "version": "1.1.6", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "is-builtin-module": { "version": "1.0.0", @@ -4300,7 +4270,6 @@ "version": "3.2.2", "bundled": true, "dev": true, - "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -4347,8 +4316,7 @@ "longest": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "lru-cache": { "version": "4.1.3", @@ -4614,8 +4582,7 @@ "repeat-string": { "version": "1.6.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "require-directory": { "version": "2.1.1", diff --git a/package.json b/package.json index b9988a40..6edb57ee 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,12 @@ "gts": "build/src/cli.js" }, "files": [ - ".clang-format", "CHANGELOG.md", "LICENSE", "README.md", "build/src", "build/types", + "prettier.config.js", "tsconfig-google.json", "tsconfig.json", "tslint.json" @@ -41,7 +41,6 @@ "license": "Apache-2.0", "dependencies": { "chalk": "^2.4.1", - "clang-format": "1.2.3", "diff": "^4.0.1", "entities": "^1.1.1", "inquirer": "^6.0.0", @@ -63,6 +62,7 @@ "@types/ncp": "^2.0.1", "@types/node": "^10.0.3", "@types/pify": "^3.0.2", + "@types/prettier": "^1.15.2", "@types/rimraf": "^2.0.2", "@types/tmp": "^0.0.33", "@types/update-notifier": "^2.2.0", diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 00000000..a425d3f7 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,4 @@ +module.exports = { + singleQuote: true, + trailingComma: 'es5', +}; diff --git a/src/clean.ts b/src/clean.ts index 1b15821a..fb4b74b9 100644 --- a/src/clean.ts +++ b/src/clean.ts @@ -16,8 +16,8 @@ import chalk from 'chalk'; import * as ts from 'typescript'; -import {Options} from './cli'; -import {getTSConfig, rimrafp} from './util'; +import { Options } from './cli'; +import { getTSConfig, rimrafp } from './util'; interface TSConfig { compilerOptions: ts.CompilerOptions; diff --git a/src/cli.ts b/src/cli.ts index 6dc2a7e5..cc59a54b 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -17,8 +17,8 @@ import * as path from 'path'; import * as meow from 'meow'; import * as updateNotifier from 'update-notifier'; -import {init} from './init'; -import {clean} from './clean'; +import { init } from './init'; +import { clean } from './clean'; const packageJson = require('../../package.json'); @@ -69,10 +69,10 @@ const cli = meow({ $ gts fix src/file1.ts src/file2.ts $ gts clean`, flags: { - help: {type: 'boolean'}, - yes: {type: 'boolean', alias: 'y'}, - no: {type: 'boolean', alias: 'n'}, - 'dry-run': {type: 'boolean'}, + help: { type: 'boolean' }, + yes: { type: 'boolean', alias: 'y' }, + no: { type: 'boolean', alias: 'n' }, + 'dry-run': { type: 'boolean' }, }, }); @@ -120,7 +120,7 @@ async function run(verb: string, files: string[]): Promise { } } -updateNotifier({pkg: packageJson}).notify(); +updateNotifier({ pkg: packageJson }).notify(); if (cli.input.length < 1) { usage(); diff --git a/src/format.ts b/src/format.ts index b61b08fd..331d0e27 100644 --- a/src/format.ts +++ b/src/format.ts @@ -13,41 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import chalk from 'chalk'; -import * as jsdiff from 'diff'; -import * as entities from 'entities'; -import * as fs from 'fs'; -import * as path from 'path'; - -import {Options} from './cli'; -import {createProgram} from './lint'; -import {readFilep} from './util'; -/** - * Object that contains the position of formatting issue within the file, the - * length of it, and the string to replace it with. - */ -export interface Replacement { - offset: number; - length: number; - fix: string; -} +import * as prettier from 'prettier'; +import * as fs from 'fs'; +import * as diff from 'diff'; -// Exported for testing purposes. -export const clangFormat = require('clang-format'); +import { Options } from './cli'; +import { createProgram } from './lint'; -const BASE_ARGS_FILE = ['-style=file']; -const BASE_ARGS_INLINE = [ - '-style', - '{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}', -]; +const PRETTIER_OPTIONS = require('../../prettier.config.js'); -/** - * Run tslint fix and clang fix with the default configuration - * @param options - * @param fix whether to automatically fix the format - * @param files files to format - */ export async function format( options: Options, files: string[] = [], @@ -58,14 +33,6 @@ export async function format( fix = false; } - // If the project has a .clang-format – use it. Else use the default as an - // inline argument. - const baseClangFormatArgs = fs.existsSync( - path.join(options.targetRootDir, '.clang-format') - ) - ? BASE_ARGS_FILE - : BASE_ARGS_INLINE; - const program = createProgram(options); // Obtain a list of source files to format. // We use program.getRootFileNames to get only the files that match the @@ -78,214 +45,63 @@ export async function format( ? files : program.getRootFileNames().filter(f => !f.endsWith('.d.ts')); - if (fix) { - return fixFormat(srcFiles, baseClangFormatArgs); - } else { - const result = await checkFormat(options, srcFiles, baseClangFormatArgs); - if (!result) { - options.logger.log( - 'clang-format reported errors... run `gts fix` to address.' - ); - } - return result; + const result = await checkFormat(srcFiles, options, fix); + if (!result) { + options.logger.log('prettier reported errors... run `gts fix` to address.'); } + return result; } -/** - * Runs clang-format to automatically fix the format of supplied files. - * - * @param srcFiles list of source files - */ -function fixFormat(srcFiles: string[], baseArgs: string[]): Promise { - return new Promise((resolve, reject) => { - const args = baseArgs.concat(['-i'], srcFiles); - clangFormat.spawnClangFormat( - args, - (err?: Error) => { - if (err) { - reject(err); - } else { - resolve(true); - } - }, - 'inherit' - ); - }); +interface FileConfig { + file: string; + config: prettier.Options | null; } -/** - * Runs clang-format on the list of files and checks whether they are formatted - * correctly. Returns true if all files are formatted correctly. - * - * @param srcFiles list of source files - */ -function checkFormat( - options: Options, - srcFiles: string[], - baseArgs: string[] -): Promise { - return new Promise((resolve, reject) => { - let output = ''; - const args = baseArgs.concat(['-output-replacements-xml'], srcFiles); - const out = clangFormat.spawnClangFormat( - args, - (err?: Error) => { - if (err) { - reject(err); - } - }, - ['ignore', 'pipe', process.stderr] - ).stdout; - out.setEncoding('utf8'); - out.on('data', (data: Buffer) => { - output += data; - }); - - out.on('end', async () => { - const files: string[] = output.split("\n").slice(1); - for (let i = 0; i < files.length; i++) { - if (files[i].indexOf(' 0) { - const diff = await getDiffObj(srcFiles[i], replacements); - printDiffs(diff, options); - } - } - resolve(output.indexOf(' { + const configs = await Promise.all( + srcFiles.map(file => prettier.resolveConfig(file)) + ); + return srcFiles.map((file, index) => { + return { file, config: configs[index] }; }); } /** - * Parses through xml string for the replacement string, offset, length and - * returns all of the necessary replacements for the file + * Checks formatting of the given file list. * - * @param output xml string from clangFormat + * @param srcFiles list of source files + * @param options gts options + * @param fix true to auto fix the formatting problems + * @returns false if there are still formatting problems */ -export function getReplacements(fileXML: string): Replacement[] { - const replacements: Replacement[] = []; - - let xmlLines = fileXML.trim().split('\n'); - // first and last elements are outer 'replacements' tags - xmlLines = xmlLines.slice(1, xmlLines.length - 1); - - for (let i = 0; i < xmlLines.length; i++) { - // Uses regex to capture the xml attributes and element - // XML format: - // FIX - const offset: string[] | null = /offset='(\d+)'/g.exec(xmlLines[i]); - const length: string[] | null = /length='(\d+)'/g.exec(xmlLines[i]); - const fix: string[] | null = /length='\d+'>(.*)<\/replacement>/g.exec( - xmlLines[i] - ); - - if (length === null || offset === null || fix === null) { - throw new Error('Unable to get replacement'); +async function checkFormat(srcFiles: string[], options: Options, fix: boolean) { + const configs = await mapFilesToFileConfigs(srcFiles); + + const checks = configs.map(({ file, config }: FileConfig) => { + config = config || PRETTIER_OPTIONS; + const contents = fs.readFileSync(file, 'utf8'); + + let formatted: string; + try { + formatted = prettier.format(contents, config!); + } catch (e) { + options.logger.log(`${file}: ${e}`); + return false; } - replacements[i] = { - offset: Number(offset[1]), - length: Number(length[1]), - fix: entities.decodeXML(fix[1]), - }; - } - return replacements; -} - -/** - * Gets an object containing the differences between the original file and after - * changes have been made - * - * @param file - * @param replacements array of all the formatting issues within in the file - */ -async function getDiffObj( - file: string, - replacements: Replacement[] -): Promise { - const text = await readFilep(file, 'utf8'); - const fixed = performFixes(text, replacements); - const diff = jsdiff.structuredPatch(file, '', text, fixed, '', '', { - context: 3, - }); - jsdiff.applyPatch('diff', diff); - return diff; -} - -/** - * Performs formatting fixes to the original string - * - * @param data original string - * @param errOffset start index of the formatting issue - * @param errLength length of formatting issue - * @param replacements string that resolves formatting issue - */ -function performFixes(data: string, replacements: Replacement[]) { - const replaced: string[] = []; - replaced.push(substring(data, 0, replacements[0].offset)); - for (let i = 0; i < replacements.length - 1; i++) { - replaced.push(replacements[i].fix); - replaced.push( - substring( - data, - replacements[i].offset + replacements[i].length, - replacements[i + 1].offset - ) - ); - } - replaced.push(replacements[replacements.length - 1].fix); - replaced.push( - substring( - data, - replacements[replacements.length - 1].offset + - replacements[replacements.length - 1].length, - Buffer.byteLength(data, 'utf8') - ) - ); - return replaced.join(''); -} - -/** - * Prints the lines with formatting issues - * - * @param diffs contains all information about the formatting changes - * @param options - */ -function printDiffs(diffs: jsdiff.ParsedDiff, options: Options) { - options.logger.log(chalk.inverse.bold(diffs.oldFileName!)); - diffs.hunks.forEach((diff: jsdiff.Hunk) => { - const log = ` Lines: ${diff.oldStart}-${diff.oldStart + diff.oldLines}`; - options.logger.log(chalk.bold(log)); - diff.lines.forEach((line: string) => { - if (line[0] === '-') { - options.logger.log(` ${chalk.red(line)}`); - } else if (line[0] === '+') { - options.logger.log(` ${chalk.green(line)}`); - } else { - options.logger.log(` ${chalk.gray(line)}`); - } - }); - options.logger.log('\n'); + if (contents === formatted) { + return true; + } + if (fix) { + fs.writeFileSync(file, formatted, 'utf8'); + return true; + } + const patch = diff.createPatch(file, contents, formatted); + options.logger.log(patch); + return false; }); -} -/** - * Substring using bytes - * - * @param str original string - * @param indexStart position where to start extraction - * @param indexEnd position (up to, but not including) where to end extraction - * @param encoding - */ -function substring( - str: string, - indexStart: number, - indexEnd: number, - encoding = 'utf8' -) { - return Buffer.from(str, encoding) - .slice(indexStart, indexEnd) - .toString(encoding); + return checks.reduce((sum, flag) => sum && flag, true); } diff --git a/src/init.ts b/src/init.ts index b1fbc770..d344910a 100644 --- a/src/init.ts +++ b/src/init.ts @@ -18,7 +18,7 @@ import * as cp from 'child_process'; import * as inquirer from 'inquirer'; import * as path from 'path'; -import {Options} from './cli'; +import { Options } from './cli'; import { readFilep as read, readJsonp as readJson, @@ -36,7 +36,7 @@ const DEFAULT_PACKAGE_JSON: PackageJson = { files: ['build/src'], license: 'Apache-2.0', keywords: [], - scripts: {test: 'echo "Error: no test specified" && exit 1'}, + scripts: { test: 'echo "Error: no test specified" && exit 1' }, }; export interface Bag { @@ -200,15 +200,18 @@ async function generateTsLintConfig(options: Options): Promise { async function generateTsConfig(options: Options): Promise { const config = formatJson({ extends: './node_modules/gts/tsconfig-google.json', - compilerOptions: {rootDir: '.', outDir: 'build'}, + compilerOptions: { rootDir: '.', outDir: 'build' }, include: ['src/*.ts', 'src/**/*.ts', 'test/*.ts', 'test/**/*.ts'], }); return generateConfigFile(options, './tsconfig.json', config); } -async function generateClangFormat(options: Options): Promise { - const style = await read(path.join(__dirname, '../../.clang-format'), 'utf8'); - return generateConfigFile(options, './.clang-format', style); +async function generatePrettierConfig(options: Options): Promise { + const style = await read( + path.join(__dirname, '../../prettier.config.js'), + 'utf8' + ); + return generateConfigFile(options, './prettier.config.js', style); } async function generateConfigFile( @@ -283,13 +286,13 @@ export async function init(options: Options): Promise { } await generateTsConfig(options); await generateTsLintConfig(options); - await generateClangFormat(options); + await generatePrettierConfig(options); // Run `npm install` after initial setup so `npm run check` works right away. if (!options.dryRun) { // --ignore-scripts so that compilation doesn't happen because there's no // source files yet. - cp.spawnSync('npm', ['install', '--ignore-scripts'], {stdio: 'inherit'}); + cp.spawnSync('npm', ['install', '--ignore-scripts'], { stdio: 'inherit' }); } return true; diff --git a/src/lint.ts b/src/lint.ts index 9b3144b9..6941a1ba 100644 --- a/src/lint.ts +++ b/src/lint.ts @@ -15,10 +15,10 @@ */ import * as fs from 'fs'; import * as path from 'path'; -import {Configuration, Linter} from 'tslint'; +import { Configuration, Linter } from 'tslint'; import * as ts from 'typescript'; -import {Options} from './cli'; +import { Options } from './cli'; /** * Run tslint with the default configuration. Returns true on success. @@ -51,7 +51,7 @@ export function lint( ); const source = fs.readFileSync(file, 'utf8'); - const linter = new Linter({fix, formatter: 'codeFrame'}); + const linter = new Linter({ fix, formatter: 'codeFrame' }); linter.lint(file, source, configuration); const result = linter.getResult(); if (result.errorCount || result.warningCount) { @@ -74,7 +74,7 @@ export function lint( : path.resolve(options.gtsRootDir, 'tslint.json'); const configuration = Configuration.loadConfigurationFromPath(configPath); - const linter = new Linter({fix, formatter: 'codeFrame'}, program); + const linter = new Linter({ fix, formatter: 'codeFrame' }, program); files.forEach(file => { const sourceFile = program.getSourceFile(file); diff --git a/src/util.ts b/src/util.ts index e95f98f6..209cfbe4 100644 --- a/src/util.ts +++ b/src/util.ts @@ -102,7 +102,7 @@ async function getBase( * @param inherited is then loaded and overwrites base */ function combineTSConfig(base: ConfigFile, inherited: ConfigFile): ConfigFile { - const result: ConfigFile = {compilerOptions: {}}; + const result: ConfigFile = { compilerOptions: {} }; Object.assign(result, base, inherited); Object.assign( diff --git a/test/fixtures.ts b/test/fixtures.ts index 0df3480f..7fb514f6 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -49,7 +49,7 @@ export async function withFixtures( fn: (fixturesDir: string) => PromiseLike ) { const keep = !!process.env.GTS_KEEP_TEMPDIRS; - const dir = tmp.dirSync({keep, unsafeCleanup: true}); + const dir = tmp.dirSync({ keep, unsafeCleanup: true }); await setupFixtures(dir.name, fixtures); diff --git a/test/test-clean.ts b/test/test-clean.ts index fe2c82a1..4486b805 100644 --- a/test/test-clean.ts +++ b/test/test-clean.ts @@ -18,11 +18,11 @@ import test from 'ava'; import * as fs from 'fs'; import * as path from 'path'; -import {clean} from '../src/clean'; -import {Options} from '../src/cli'; -import {nop} from '../src/util'; +import { clean } from '../src/clean'; +import { Options } from '../src/cli'; +import { nop } from '../src/util'; -import {withFixtures} from './fixtures'; +import { withFixtures } from './fixtures'; const OPTIONS: Options = { gtsRootDir: path.resolve(__dirname, '../..'), @@ -30,7 +30,7 @@ const OPTIONS: Options = { dryRun: false, yes: false, no: false, - logger: {log: nop, error: nop, dir: nop}, + logger: { log: nop, error: nop, dir: nop }, }; test.serial.failing('should gracefully error if tsconfig is missing', t => { @@ -42,7 +42,7 @@ test.serial.failing('should gracefully error if tsconfig is missing', t => { test.serial( 'should gracefully error if tsconfig does not have valid outDir', t => { - return withFixtures({'tsconfig.json': JSON.stringify({})}, async () => { + return withFixtures({ 'tsconfig.json': JSON.stringify({}) }, async () => { const deleted = await clean(OPTIONS); t.is(deleted, false); }); @@ -51,7 +51,7 @@ test.serial( test.serial('should avoid deleting .', t => { return withFixtures( - {'tsconfig.json': JSON.stringify({compilerOptions: {outDir: '.'}})}, + { 'tsconfig.json': JSON.stringify({ compilerOptions: { outDir: '.' } }) }, async () => { const deleted = await clean(OPTIONS); t.is(deleted, false); @@ -61,7 +61,11 @@ test.serial('should avoid deleting .', t => { test.serial.failing('should ensure that outDir is local to targetRoot', t => { return withFixtures( - {'tsconfig.json': JSON.stringify({compilerOptions: {outDir: '../out'}})}, + { + 'tsconfig.json': JSON.stringify({ + compilerOptions: { outDir: '../out' }, + }), + }, async () => { const deleted = await clean(OPTIONS); t.is(deleted, false); @@ -73,7 +77,7 @@ test.serial('should remove outDir', t => { const OUT = 'outputDirectory'; return withFixtures( { - 'tsconfig.json': JSON.stringify({compilerOptions: {outDir: OUT}}), + 'tsconfig.json': JSON.stringify({ compilerOptions: { outDir: OUT } }), [OUT]: {}, }, async dir => { diff --git a/test/test-format.ts b/test/test-format.ts index c9c5f57b..4ce63a86 100644 --- a/test/test-format.ts +++ b/test/test-format.ts @@ -18,18 +18,22 @@ import test from 'ava'; import * as fs from 'fs'; import * as path from 'path'; -import {Options} from '../src/cli'; +import { Options } from '../src/cli'; import * as format from '../src/format'; -import {nop} from '../src/util'; +import { nop } from '../src/util'; -import {withFixtures} from './fixtures'; +import { withFixtures } from './fixtures'; -// clang-format won't pass this code because of trailing spaces. const BAD_CODE = 'export const foo = [ "2" ];'; -const GOOD_CODE = "export const foo = ['2'];"; +const GOOD_CODE = "export const foo = ['2'];\n"; +const CODE_WITH_TABS = `module.exports = { +\treallyLongIdentified: 4, +\tanotherSuperLongIdentifier, +\tthisCannotFitOnTheSameLine +};\n`; -const CLANG_FORMAT_MESSAGE = - 'clang-format reported errors... run `gts fix` to address.'; +const PRETTIER_FORMAT_MESSAGE = + 'prettier reported errors... run `gts fix` to address.'; const OPTIONS: Options = { gtsRootDir: path.resolve(__dirname, '../..'), @@ -37,12 +41,12 @@ const OPTIONS: Options = { dryRun: false, yes: false, no: false, - logger: {log: console.log, error: console.error, dir: nop}, + logger: { log: console.log, error: console.error, dir: nop }, }; test.serial('format should return true for well-formatted files', t => { return withFixtures( - {'tsconfig.json': JSON.stringify({files: ['a.ts']}), 'a.ts': GOOD_CODE}, + { 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': GOOD_CODE }, async () => { const result = await format.format(OPTIONS, [], false); t.true(result); @@ -52,7 +56,7 @@ test.serial('format should return true for well-formatted files', t => { test.serial('format should return false for ill-formatted files', t => { return withFixtures( - {'tsconfig.json': JSON.stringify({files: ['a.ts']}), 'a.ts': BAD_CODE}, + { 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': BAD_CODE }, async () => { const result = await format.format(OPTIONS, [], false); t.false(result); @@ -63,8 +67,8 @@ test.serial('format should return false for ill-formatted files', t => { test.serial('format should only look in root files', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), - 'a.ts': "import {foo} from './b';\n", + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), + 'a.ts': "import { foo } from './b';\n", 'b.ts': BAD_CODE, }, async () => { @@ -76,7 +80,7 @@ test.serial('format should only look in root files', t => { test.serial('format should auto fix problems', t => { return withFixtures( - {'tsconfig.json': JSON.stringify({files: ['a.ts']}), 'a.ts': BAD_CODE}, + { 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': BAD_CODE }, async fixturesDir => { const result = await format.format(OPTIONS, [], true); t.true(result); @@ -89,7 +93,7 @@ test.serial('format should auto fix problems', t => { test.serial('format should format files listed in tsconfig.files', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': GOOD_CODE, 'b.ts': BAD_CODE, }, @@ -122,7 +126,7 @@ test.serial( async t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': BAD_CODE, 'b.ts': BAD_CODE, }, @@ -142,7 +146,7 @@ test.serial( test.serial('skip files listed in exclude', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({exclude: ['b.*']}), + 'tsconfig.json': JSON.stringify({ exclude: ['b.*'] }), 'a.ts': GOOD_CODE, 'b.ts': BAD_CODE, }, @@ -156,9 +160,9 @@ test.serial('skip files listed in exclude', t => { test.serial('format globs listed in include', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({include: ['dirb/*']}), - dira: {'a.ts': GOOD_CODE}, - dirb: {'b.ts': BAD_CODE}, + 'tsconfig.json': JSON.stringify({ include: ['dirb/*'] }), + dira: { 'a.ts': GOOD_CODE }, + dirb: { 'b.ts': BAD_CODE }, }, async () => { const okay = await format.format(OPTIONS); @@ -169,9 +173,9 @@ test.serial('format globs listed in include', t => { test.serial('format should not auto fix on dry-run', t => { return withFixtures( - {'tsconfig.json': JSON.stringify({files: ['a.ts']}), 'a.ts': BAD_CODE}, + { 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': BAD_CODE }, async fixturesDir => { - const optionsWithDryRun = Object.assign({}, OPTIONS, {dryRun: true}); + const optionsWithDryRun = Object.assign({}, OPTIONS, { dryRun: true }); const okay = await format.format(optionsWithDryRun, [], true); t.is(okay, false); const contents = fs.readFileSync(path.join(fixturesDir, 'a.ts'), 'utf8'); @@ -180,12 +184,25 @@ test.serial('format should not auto fix on dry-run', t => { ); }); -test.serial('format should use user provided config', t => { +test.serial('format should return false on code with tabs', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), - '.clang-format': 'Language: JavaScript', - 'a.ts': BAD_CODE, // but actually good under the custom JS format config. + 'tsconfig.json': JSON.stringify({ files: ['tabs.ts'] }), + 'tabs.ts': CODE_WITH_TABS, + }, + async () => { + const result = await format.format(OPTIONS, [], false); + t.false(result); + } + ); +}); + +test.serial('format should use user provided prettier.config.js', t => { + return withFixtures( + { + 'tsconfig.json': JSON.stringify({ files: ['tabs.ts'] }), + 'prettier.config.js': `module.exports = { useTabs: true }`, + 'tabs.ts': CODE_WITH_TABS, }, async () => { const result = await format.format(OPTIONS, [], false); @@ -194,36 +211,30 @@ test.serial('format should use user provided config', t => { ); }); -test.serial('format should prefer the files parameter over options', t => { +test.serial('format should use user provided .prettierrc', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), - 'a.ts': BAD_CODE, - 'good.ts': GOOD_CODE, + 'tsconfig.json': JSON.stringify({ files: ['tabs.ts'] }), + '.prettierrc': `useTabs: true\n`, + 'tabs.ts': CODE_WITH_TABS, }, async () => { - const result = await format.format(OPTIONS, ['good.ts'], false); + const result = await format.format(OPTIONS, [], false); t.true(result); } ); }); -test.serial('format should return error from failed spawn', async t => { +test.serial('format should prefer the files parameter over options', t => { return withFixtures( - {'tsconfig.json': JSON.stringify({files: ['a.ts']}), 'a.ts': GOOD_CODE}, + { + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), + 'a.ts': BAD_CODE, + 'good.ts': GOOD_CODE, + }, async () => { - const MESSAGE = '🦄'; - // Mock clangFormat. - const original = format.clangFormat.spawnClangFormat; - // tslint:disable-next-line:no-any - format.clangFormat.spawnClangFormat = (_: any, cb: Function) => { - setImmediate(() => { - cb(new Error(MESSAGE)); - }); - }; - await t.throwsAsync(format.format(OPTIONS, [], true), Error, MESSAGE); - await t.throwsAsync(format.format(OPTIONS, [], false), Error, MESSAGE); - format.clangFormat.spawnClangFormat = original; + const result = await format.format(OPTIONS, ['good.ts'], false); + t.true(result); } ); }); @@ -233,7 +244,7 @@ test.serial( t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': BAD_CODE, }, async () => { @@ -243,10 +254,10 @@ test.serial( output += n; }, }); - const options = Object.assign({}, OPTIONS, {logger: newLogger}); + const options = Object.assign({}, OPTIONS, { logger: newLogger }); await format.format(options, [], false); - t.true(output.search(CLANG_FORMAT_MESSAGE) !== -1); + t.true(output.search(PRETTIER_FORMAT_MESSAGE) !== -1); t.true(output.indexOf("+export const foo = ['2'];") !== -1); t.true(output.indexOf('-export const foo = [ "2" ];') !== -1); } @@ -259,7 +270,7 @@ test.serial( t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': "//🦄 This is a comment 🌷🏳️‍🌈 — /\nconst variable = '5'", }, async () => { @@ -269,10 +280,10 @@ test.serial( output += n; }, }); - const options = Object.assign({}, OPTIONS, {logger: newLogger}); + const options = Object.assign({}, OPTIONS, { logger: newLogger }); await format.format(options, [], false); - t.true(output.search(CLANG_FORMAT_MESSAGE) !== -1); + t.true(output.search(PRETTIER_FORMAT_MESSAGE) !== -1); t.true(output.indexOf('//🦄 This is a comment 🌷🏳️‍🌈 —') !== -1); t.true(output.indexOf("const variable = '5'") !== -1); } @@ -280,17 +291,29 @@ test.serial( } ); -test.serial( - 'should throw error if xml are missing offset, length, or fix values', - t => { - return withFixtures({}, async () => { - const missingLength = - "\n\nFIX"; - t.throws(() => { - format.getReplacements(missingLength); - }); - }); - } -); +// Files that cannot be formatted should be left untouched. +test.serial('format should leave the kitty unharmed', t => { + const KITTY = ` + /\\**/\\ + ( o_o )_) + ,(u u ,), + {}{}{}{}{}{}`; + + return withFixtures( + { + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), + 'a.ts': BAD_CODE, + 'kitty.kitty': KITTY, + }, + async fixturesDir => { + const result = await format.format(OPTIONS, ['kitty.kitty'], true); + t.false(result); // Well structured JS, the kitty is not. + // Well structured or not, the kitty should be left alone. + const contents = fs.readFileSync( + path.join(fixturesDir, 'kitty.kitty'), + 'utf8' + ); + t.deepEqual(contents, KITTY); + } + ); +}); diff --git a/test/test-init.ts b/test/test-init.ts index 920c8bee..1a3c808e 100644 --- a/test/test-init.ts +++ b/test/test-init.ts @@ -17,11 +17,11 @@ import test from 'ava'; import * as path from 'path'; -import {Options} from '../src/cli'; +import { Options } from '../src/cli'; import * as init from '../src/init'; -import {nop, readJsonp as readJson} from '../src/util'; +import { nop, readJsonp as readJson } from '../src/util'; -import {withFixtures} from './fixtures'; +import { withFixtures } from './fixtures'; const OPTIONS: Options = { gtsRootDir: path.resolve(__dirname, '../..'), @@ -29,11 +29,11 @@ const OPTIONS: Options = { dryRun: false, yes: false, no: false, - logger: {log: nop, error: nop, dir: nop}, + logger: { log: nop, error: nop, dir: nop }, }; -const OPTIONS_YES = Object.assign({}, OPTIONS, {yes: true}); -const OPTIONS_NO = Object.assign({}, OPTIONS, {no: true}); -const OPTIONS_DRY_RUN = Object.assign({}, OPTIONS, {dryRun: true}); +const OPTIONS_YES = Object.assign({}, OPTIONS, { yes: true }); +const OPTIONS_NO = Object.assign({}, OPTIONS, { no: true }); +const OPTIONS_DRY_RUN = Object.assign({}, OPTIONS, { dryRun: true }); function hasExpectedScripts(packageJson: init.PackageJson): boolean { return ( @@ -75,7 +75,7 @@ test('addScripts should not edit existing scripts on no', async t => { pretest: `fake run compile`, posttest: `fake run check`, }; - const pkg: init.PackageJson = {scripts: Object.assign({}, SCRIPTS)}; + const pkg: init.PackageJson = { scripts: Object.assign({}, SCRIPTS) }; const result = await init.addScripts(pkg, OPTIONS_NO); t.is(result, false); // no edits. @@ -92,7 +92,7 @@ test('addScripts should edit existing scripts on yes', async t => { pretest: `fake run compile`, posttest: `fake run check`, }; - const pkg: init.PackageJson = {scripts: Object.assign({}, SCRIPTS)}; + const pkg: init.PackageJson = { scripts: Object.assign({}, SCRIPTS) }; const result = await init.addScripts(pkg, OPTIONS_YES); t.is(result, true); // made edits. t.notDeepEqual(pkg.scripts, SCRIPTS); @@ -106,17 +106,17 @@ test('addDependencies should add a deps section if none exists', async t => { }); test('addDependencies should not edit existing deps on no', async t => { - const DEPS = {gts: 'something', typescript: 'or the other'}; - const pkg: init.PackageJson = {devDependencies: Object.assign({}, DEPS)}; - const OPTIONS_NO = Object.assign({}, OPTIONS, {no: true}); + const DEPS = { gts: 'something', typescript: 'or the other' }; + const pkg: init.PackageJson = { devDependencies: Object.assign({}, DEPS) }; + const OPTIONS_NO = Object.assign({}, OPTIONS, { no: true }); const result = await init.addDependencies(pkg, OPTIONS_NO); t.is(result, false); // no edits. t.deepEqual(pkg.devDependencies, DEPS); }); test('addDependencies should edit existing deps on yes', async t => { - const DEPS = {gts: 'something', typescript: 'or the other'}; - const pkg: init.PackageJson = {devDependencies: Object.assign({}, DEPS)}; + const DEPS = { gts: 'something', typescript: 'or the other' }; + const pkg: init.PackageJson = { devDependencies: Object.assign({}, DEPS) }; const result = await init.addDependencies(pkg, OPTIONS_YES); t.is(result, true); // made edits. @@ -127,9 +127,9 @@ test('addDependencies should edit existing deps on yes', async t => { // init test.serial('init should read local package.json', t => { - const originalContents = {some: 'property'}; + const originalContents = { some: 'property' }; return withFixtures( - {'package.json': JSON.stringify(originalContents)}, + { 'package.json': JSON.stringify(originalContents) }, async () => { // TODO: this test causes `npm install` to run in the fixture directory. // This may make it sensitive to the network, npm resiliency. Find a diff --git a/test/test-kitchen.ts b/test/test-kitchen.ts index 7e0bb246..410472ce 100644 --- a/test/test-kitchen.ts +++ b/test/test-kitchen.ts @@ -58,7 +58,7 @@ const execp = ( }; const keep = !!process.env.GTS_KEEP_TEMPDIRS; -const stagingDir = tmp.dirSync({keep, unsafeCleanup: true}); +const stagingDir = tmp.dirSync({ keep, unsafeCleanup: true }); const stagingPath = stagingDir.name; const execOpts = { cwd: `${stagingPath}/kitchen`, @@ -94,7 +94,7 @@ test.serial('init', async t => { // Ensure config files got generated. fs.accessSync(`${stagingPath}/kitchen/tsconfig.json`); fs.accessSync(`${stagingPath}/kitchen/tslint.json`); - fs.accessSync(`${stagingPath}/kitchen/.clang-format`); + fs.accessSync(`${stagingPath}/kitchen/prettier.config.js`); // Compilation shouldn't have happened. Hence no `build` directory. const dirContents = fs.readdirSync(`${stagingPath}/kitchen`); @@ -107,8 +107,8 @@ test.serial('use as a non-locally installed module', async t => { // Use from a directory different from where we have locally installed. This // simulates use as a globally installed module. const GTS = `${stagingPath}/kitchen/node_modules/.bin/gts`; - const tmpDir = tmp.dirSync({keep, unsafeCleanup: true}); - const opts = {cwd: `${tmpDir.name}/kitchen`}; + const tmpDir = tmp.dirSync({ keep, unsafeCleanup: true }); + const opts = { cwd: `${tmpDir.name}/kitchen` }; // Copy test files. await ncpp('test/fixtures', `${tmpDir.name}/`); @@ -153,9 +153,9 @@ test.serial('generated json files should terminate with newline', async t => { }); test.serial('check before fix', async t => { - const {exitCode, stdout} = await execp('npm run check', execOpts); + const { exitCode, stdout } = await execp('npm run check', execOpts); t.deepEqual(exitCode, 1); - t.notDeepEqual(stdout.indexOf('clang-format reported errors'), -1); + t.notDeepEqual(stdout.indexOf('prettier reported errors'), -1); t.pass(); }); diff --git a/test/test-lint.ts b/test/test-lint.ts index ffa8c226..083be356 100644 --- a/test/test-lint.ts +++ b/test/test-lint.ts @@ -18,12 +18,12 @@ import test from 'ava'; import * as fs from 'fs'; import * as path from 'path'; -import {Options} from '../src/cli'; -import {TSLINT_CONFIG} from '../src/init'; +import { Options } from '../src/cli'; +import { TSLINT_CONFIG } from '../src/init'; import * as lint from '../src/lint'; -import {nop} from '../src/util'; +import { nop } from '../src/util'; -import {withFixtures} from './fixtures'; +import { withFixtures } from './fixtures'; const OPTIONS: Options = { gtsRootDir: path.resolve(__dirname, '../..'), @@ -31,7 +31,7 @@ const OPTIONS: Options = { dryRun: false, yes: false, no: false, - logger: {log: nop, error: nop, dir: nop}, + logger: { log: nop, error: nop, dir: nop }, }; const BAD_CODE = `throw 'hello world';`; @@ -42,7 +42,7 @@ const FIXABLE_CODE = 'const x : Array = []'; const FIXABLE_CODE_FIXED = 'const x : string[] = [];'; test.serial('createProgram should return an object', t => { - return withFixtures({'tsconfig.json': '{}'}, async () => { + return withFixtures({ 'tsconfig.json': '{}' }, async () => { const program = lint.createProgram(OPTIONS); t.truthy(program); }); @@ -51,7 +51,7 @@ test.serial('createProgram should return an object', t => { test.serial('lint should return true on good code', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': GOOD_CODE, }, async () => { @@ -64,7 +64,7 @@ test.serial('lint should return true on good code', t => { test.serial('lint should return false on bad code', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': BAD_CODE, }, async () => { @@ -77,7 +77,7 @@ test.serial('lint should return false on bad code', t => { test.serial('lint should auto fix fixable errors', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': FIXABLE_CODE, }, async fixturesDir => { @@ -92,11 +92,11 @@ test.serial('lint should auto fix fixable errors', t => { test.serial('lint should not auto fix on dry-run', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': FIXABLE_CODE, }, async fixturesDir => { - const optionsWithDryRun = Object.assign({}, OPTIONS, {dryRun: true}); + const optionsWithDryRun = Object.assign({}, OPTIONS, { dryRun: true }); const okay = lint.lint(optionsWithDryRun, [], true); t.is(okay, false); const contents = fs.readFileSync(path.join(fixturesDir, 'a.ts'), 'utf8'); @@ -108,7 +108,7 @@ test.serial('lint should not auto fix on dry-run', t => { test.serial('lint should lint files listed in tsconfig.files', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': GOOD_CODE, 'b.ts': BAD_CODE, }, @@ -141,7 +141,7 @@ test.serial( async t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': FIXABLE_CODE, 'b.ts': BAD_CODE, }, @@ -161,7 +161,7 @@ test.serial( test.serial('lint should not lint files listed in exclude', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({exclude: ['b.*']}), + 'tsconfig.json': JSON.stringify({ exclude: ['b.*'] }), 'a.ts': GOOD_CODE, 'b.ts': BAD_CODE, }, @@ -175,9 +175,9 @@ test.serial('lint should not lint files listed in exclude', t => { test.serial('lint should lint globs listed in include', t => { return withFixtures( { - 'tsconfig.json': JSON.stringify({include: ['dirb/*']}), - dira: {'a.ts': GOOD_CODE}, - dirb: {'b.ts': BAD_CODE}, + 'tsconfig.json': JSON.stringify({ include: ['dirb/*'] }), + dira: { 'a.ts': GOOD_CODE }, + dirb: { 'b.ts': BAD_CODE }, }, async () => { const okay = lint.lint(OPTIONS); @@ -190,8 +190,8 @@ test.serial('lint should lint only specified files', t => { return withFixtures( { 'tsconfig.json': JSON.stringify({}), - dira: {'a.ts': GOOD_CODE}, - dirb: {'b.ts': BAD_CODE}, + dira: { 'a.ts': GOOD_CODE }, + dirb: { 'b.ts': BAD_CODE }, }, async () => { const aOkay = lint.lint(OPTIONS, ['dira/a.ts']); @@ -222,7 +222,7 @@ test.serial('lint should prefer user config file over default', async t => { // By default the above should fail lint. await withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'a.ts': CUSTOM_LINT_CODE, }, async () => { @@ -234,7 +234,7 @@ test.serial('lint should prefer user config file over default', async t => { // User should be able to override the default config. return withFixtures( { - 'tsconfig.json': JSON.stringify({files: ['a.ts']}), + 'tsconfig.json': JSON.stringify({ files: ['a.ts'] }), 'tslint.json': JSON.stringify({}), 'a.ts': CUSTOM_LINT_CODE, }, @@ -263,7 +263,7 @@ test.serial('lint for specific files should use file-specific config', t => { 'a.ts': CODE_WITH_PARSEINT, // no tslint, so default should apply. }, - dirb: {'b.ts': CODE_WITH_PARSEINT, 'tslint.json': JSON.stringify({})}, + dirb: { 'b.ts': CODE_WITH_PARSEINT, 'tslint.json': JSON.stringify({}) }, }, async () => { const okay = lint.lint(optionsWithLog, ['dira/a.ts', 'dirb/b.ts']); diff --git a/test/test-util.ts b/test/test-util.ts index e5636b52..732c7ca2 100644 --- a/test/test-util.ts +++ b/test/test-util.ts @@ -16,7 +16,7 @@ import test from 'ava'; import * as path from 'path'; -import {ConfigFile, getTSConfig} from '../src/util'; +import { ConfigFile, getTSConfig } from '../src/util'; /** * Creates a fake promisified readFile function from a map @@ -37,7 +37,7 @@ function createFakeReadFilep(myMap: Map) { test('get should parse the correct tsconfig file', async t => { const FAKE_DIRECTORY = '/some/fake/directory'; - const FAKE_CONFIG1 = {files: ['b']}; + const FAKE_CONFIG1 = { files: ['b'] }; function fakeReadFilep( configPath: string, @@ -53,9 +53,9 @@ test('get should parse the correct tsconfig file', async t => { test('should throw an error if it finds a circular reference', async t => { const FAKE_DIRECTORY = '/some/fake/directory'; - const FAKE_CONFIG1 = {files: ['b'], extends: 'FAKE_CONFIG2'}; - const FAKE_CONFIG2 = {extends: 'FAKE_CONFIG3'}; - const FAKE_CONFIG3 = {extends: 'tsconfig.json'}; + const FAKE_CONFIG1 = { files: ['b'], extends: 'FAKE_CONFIG2' }; + const FAKE_CONFIG2 = { extends: 'FAKE_CONFIG3' }; + const FAKE_CONFIG3 = { extends: 'tsconfig.json' }; const myMap = new Map(); myMap.set('/some/fake/directory/tsconfig.json', FAKE_CONFIG1); myMap.set('/some/fake/directory/FAKE_CONFIG2', FAKE_CONFIG2); @@ -71,14 +71,14 @@ test('should throw an error if it finds a circular reference', async t => { test('should follow dependency chain caused by extends files', async t => { const FAKE_DIRECTORY = '/some/fake/directory'; const FAKE_CONFIG1 = { - compilerOptions: {a: 'n'}, + compilerOptions: { a: 'n' }, files: ['b'], extends: 'FAKE_CONFIG2', }; - const FAKE_CONFIG2 = {include: ['/stuff/*'], extends: 'FAKE_CONFIG3'}; - const FAKE_CONFIG3 = {exclude: ['doesnt/look/like/anything/to/me']}; + const FAKE_CONFIG2 = { include: ['/stuff/*'], extends: 'FAKE_CONFIG3' }; + const FAKE_CONFIG3 = { exclude: ['doesnt/look/like/anything/to/me'] }; const combinedConfig = { - compilerOptions: {a: 'n'}, + compilerOptions: { a: 'n' }, files: ['b'], include: ['/stuff/*'], exclude: ['doesnt/look/like/anything/to/me'], @@ -98,10 +98,10 @@ test('should follow dependency chain caused by extends files', async t => { test('when a file contains an extends field, the base file is loaded first then overridden by the inherited files', async t => { const FAKE_DIRECTORY = '/some/fake/directory'; - const FAKE_CONFIG1 = {files: ['b'], extends: 'FAKE_CONFIG2'}; - const FAKE_CONFIG2 = {files: ['c'], extends: 'FAKE_CONFIG3'}; - const FAKE_CONFIG3 = {files: ['d']}; - const combinedConfig = {compilerOptions: {}, files: ['b']}; + const FAKE_CONFIG1 = { files: ['b'], extends: 'FAKE_CONFIG2' }; + const FAKE_CONFIG2 = { files: ['c'], extends: 'FAKE_CONFIG3' }; + const FAKE_CONFIG3 = { files: ['d'] }; + const combinedConfig = { compilerOptions: {}, files: ['b'] }; const myMap = new Map(); myMap.set('/some/fake/directory/tsconfig.json', FAKE_CONFIG1); myMap.set('/some/fake/directory/FAKE_CONFIG2', FAKE_CONFIG2); @@ -116,9 +116,9 @@ test('when a file contains an extends field, the base file is loaded first then test('when reading a file, all filepaths should be relative to the config file currently being read', async t => { const FAKE_DIRECTORY = '/some/fake/directory'; - const FAKE_CONFIG1 = {files: ['b'], extends: './foo/FAKE_CONFIG2'}; - const FAKE_CONFIG2 = {include: ['c'], extends: './bar/FAKE_CONFIG3'}; - const FAKE_CONFIG3 = {exclude: ['d']}; + const FAKE_CONFIG1 = { files: ['b'], extends: './foo/FAKE_CONFIG2' }; + const FAKE_CONFIG2 = { include: ['c'], extends: './bar/FAKE_CONFIG3' }; + const FAKE_CONFIG3 = { exclude: ['d'] }; const combinedConfig = { compilerOptions: {}, exclude: ['d'],