From 367103943c1fd8d14934807ab20adde38db4150a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Mota?= Date: Mon, 30 Jul 2018 16:01:07 +0100 Subject: [PATCH 1/4] Breaking change: New config lookup --- .flowconfig | 3 +- appveyor.yml | 1 - package.json | 3 +- src/collect.js | 1 + src/get-program.js | 34 ++-- src/index.js | 193 ++++++++++++---------- test/codebases/column-offset/.flowconfig | 4 + test/codebases/coverage-fail/.flowconfig | 4 + test/codebases/coverage-fail2/.flowconfig | 4 + test/codebases/coverage-ok/.flowconfig | 4 + test/codebases/coverage-ok2/.flowconfig | 4 + test/codebases/flow-pragma-1/.flowconfig | 4 + test/codebases/flow-pragma-2/.flowconfig | 4 + test/codebases/html-support/.flowconfig | 4 + test/codebases/no-flow-pragma/.flowconfig | 4 + test/codebases/project-1/.flowconfig | 4 + test/format.spec.js | 29 ++-- yarn.lock | 43 ++++- 18 files changed, 228 insertions(+), 119 deletions(-) create mode 100644 test/codebases/column-offset/.flowconfig create mode 100644 test/codebases/coverage-fail/.flowconfig create mode 100644 test/codebases/coverage-fail2/.flowconfig create mode 100644 test/codebases/coverage-ok/.flowconfig create mode 100644 test/codebases/coverage-ok2/.flowconfig create mode 100644 test/codebases/flow-pragma-1/.flowconfig create mode 100644 test/codebases/flow-pragma-2/.flowconfig create mode 100644 test/codebases/html-support/.flowconfig create mode 100644 test/codebases/no-flow-pragma/.flowconfig create mode 100644 test/codebases/project-1/.flowconfig diff --git a/.flowconfig b/.flowconfig index 5f68302..4bc09c0 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,10 +1,11 @@ [ignore] -.*/node_modules/fbjs/.* +.*/node_modules/.* .*/git/.* .*/test/codebases/.* .*/test/.*\.example\.js [options] +suppress_comment=.*\\$FlowIgnore esproposal.class_static_fields=enable esproposal.class_instance_fields=enable esproposal.export_star_as=enable diff --git a/appveyor.yml b/appveyor.yml index dfcb707..0842ba1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,6 @@ test_script: - node --version - yarn -V - yarn test - - yarn spec-win install: - ps: Install-Product node $env:nodejs_version x64 diff --git a/package.json b/package.json index 7cef641..ea09b6c 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "prettier": "prettier --single-quote --write \"./src/*.js\"", "preversion": "npm run build", "spec": "npm run build && jest test/format.spec.js", - "spec-win": "npm run build && jest", "test": "flow && npm run lint && npm run spec" }, "repository": { @@ -37,6 +36,7 @@ ], "dependencies": { "babel-runtime": "^6.26.0", + "find-up": "^3.0.0", "slash": "^2.0.0" }, "devDependencies": { @@ -63,6 +63,7 @@ "eslint-plugin-import": "^2.12.0", "eslint-plugin-prettier": "^2.6.0", "eslint-plugin-vue": "^4.5.0", + "execa": "^0.10.0", "flow-bin": "^0.73.0", "jest-cli": "^23.0.0", "prettier": "^1.12.1", diff --git a/src/collect.js b/src/collect.js index 947e18d..98c4272 100644 --- a/src/collect.js +++ b/src/collect.js @@ -230,6 +230,7 @@ function spawnFlow( getFlowBin(), [mode, '--json', `--root=${root}`, filepath, ...extraOptions], { + cwd: root, input, encoding: 'utf-8' } diff --git a/src/get-program.js b/src/get-program.js index 54411c1..ec64763 100644 --- a/src/get-program.js +++ b/src/get-program.js @@ -5,17 +5,16 @@ type Pos = { column: number }; -type Loc = { +export type Loc = { start: Pos, end: Pos }; -type Program = { text: string, loc: Loc, offset: Pos }; - -export default function( source: Object, node: Object ): ?Program { +export type Program = { text: string, loc: Loc, offset: Pos }; +export default function(source: Object, node: Object): ?Program { // Ignore if body is empty. - if ( node.body.length === 0 ) { + if (node.body.length === 0) { return; } @@ -27,17 +26,20 @@ export default function( source: Object, node: Object ): ?Program { // With babel-eslint, program.loc.start.column is always 0, // workaround it by using the first node of the body to get the offset. - if ( comments0 ) { - start = node.range[0] < comments0.range[0] ? { - line: body0.loc.start.line, - column: body0.loc.start.column - } : { - line: comments0.loc.start.line, - column: comments0.loc.start.column - }; + if (comments0) { + start = + node.range[0] < comments0.range[0] + ? { + line: body0.loc.start.line, + column: body0.loc.start.column + } + : { + line: comments0.loc.start.line, + column: comments0.loc.start.column + }; range = [ - Math.min( node.range[0], comments0.range[0] ), - Math.max( node.range[1], node.comments[node.comments.length - 1].range[1] ) + Math.min(node.range[0], comments0.range[0]), + Math.max(node.range[1], node.comments[node.comments.length - 1].range[1]) ]; } else { start = { @@ -48,7 +50,7 @@ export default function( source: Object, node: Object ): ?Program { } return { - text: source.text.slice( range[0], range[1] ), + text: source.text.slice(range[0], range[1]), loc: { start, end: start diff --git a/src/index.js b/src/index.js index a347d6b..be3433d 100644 --- a/src/index.js +++ b/src/index.js @@ -2,45 +2,83 @@ import path from 'path'; import fs from 'fs'; +// $FlowIgnore +import findUp from 'find-up'; import { type CollectOutputElement, FlowSeverity, collect, coverage } from './collect'; -import getProgram from './get-program'; +import getProgram, { type Program, type Loc } from './get-program'; type EslintContext = { - getAllComments: Function, - getFilename: Function, - getSourceCode: Function, - report: Function, + getAllComments: () => { value: string }[], + getFilename: () => string, + getSourceCode: () => Object, + report: ({ loc: Loc, message: string }) => void, settings: ?{ 'flowtype-errors': ?{ - flowDir?: string, stopOnExit?: any } }, options: any[] }; -let runOnAllFiles; +type Info = { + flowDir: string, + program: Program +}; -function hasFlowPragma(source) { - return source.getAllComments().some(comment => /@flow/.test(comment.value)); -} +const DEFAULT_LOC = { + start: { + line: 1, + column: 0 + }, + end: { + line: 1, + column: 0 + } +}; + +function lookupInfo( + context: EslintContext, + source: Object, + node: Object +): ?Info { + const flowconfigFile = findUp.sync('.flowconfig', { + cwd: path.dirname(context.getFilename()) + }); + + if (flowconfigFile == null) { + const program = getProgram(source, node); + context.report({ + loc: program ? program.loc : DEFAULT_LOC, + message: "Could not find '.flowconfig' file" + }); + return null; + } + + const flowDir = path.dirname(flowconfigFile); + + const runOnAllFiles = fs + .readFileSync(flowconfigFile, 'utf8') + .includes('all=true'); + + const shouldRun = + runOnAllFiles || + source.getAllComments().some(comment => /@flow/.test(comment.value)); + + const program = shouldRun && getProgram(source, node); + + if (program) { + return { + flowDir, + program + }; + } -function lookupFlowDir(context: EslintContext): string { - const root = process.cwd(); - const flowDirSetting: string = - (context.settings && - context.settings['flowtype-errors'] && - context.settings['flowtype-errors'].flowDir) || - '.'; - - return fs.existsSync(path.join(root, flowDirSetting, '.flowconfig')) - ? path.join(root, flowDirSetting) - : root; + return null; } function stopOnExit(context: EslintContext): boolean { @@ -54,42 +92,28 @@ function stopOnExit(context: EslintContext): boolean { function errorFlowCouldNotRun(loc) { return { loc, - message: -`Flow could not be run. Possible causes include: + message: `Flow could not be run. Possible causes include: * Running on 32-bit OS (https://github.com/facebook/flow/issues/2262) * Recent glibc version not available (https://github.com/flowtype/flow-bin/issues/49) - * FLOW_BIN environment variable ${process.env.FLOW_BIN ? 'set incorrectly' : 'not set'} + * FLOW_BIN environment variable ${ + process.env.FLOW_BIN ? 'set incorrectly' : 'not set' + } .` }; } -function createFilteredErrorRule(filter: (CollectOutputElement) => any) { +function createFilteredErrorRule(filter: CollectOutputElement => any) { return function showErrors(context: EslintContext) { return { Program(node: Object) { const source = context.getSourceCode(); - const flowDir = lookupFlowDir(context); - - // Check to see if we should run on every file - if (runOnAllFiles === undefined) { - try { - runOnAllFiles = fs - .readFileSync(path.join(flowDir, '.flowconfig')) - .toString() - .includes('all=true'); - } catch (err) { - runOnAllFiles = false; - } - } + const info = lookupInfo(context, source, node); - if (runOnAllFiles === false && !hasFlowPragma(source)) { + if (!info) { return; } - const program = getProgram(source, node); - if ( !program ) { - return; - } + const { flowDir, program } = info; const collected = collect( program.text, @@ -136,50 +160,53 @@ export default { return { Program(node: Object) { const source = context.getSourceCode(); + const info = lookupInfo(context, source, node); + + if (!info) { + return; + } + + const { flowDir, program } = info; + + const res = coverage( + program.text, + flowDir, + stopOnExit(context), + context.getFilename() + ); + + if (res === true) { + return; + } + + if (res === false) { + context.report(errorFlowCouldNotRun(program.loc)); + return; + } + + const requiredCoverage = context.options[0]; + const { coveredCount, uncoveredCount } = res; + + /* eslint prefer-template: 0 */ + const percentage = Number( + Math.round(coveredCount / (coveredCount + uncoveredCount) * 10000) + + 'e-2' + ); - if (hasFlowPragma(source)) { - const program = getProgram(source, node); - if ( !program ) { - return; - } - - const res = coverage( - program.text, - lookupFlowDir(context), - stopOnExit(context), - context.getFilename() - ); - - if (res === true) { - return; - } - - if (res === false) { - context.report(errorFlowCouldNotRun(program.loc)); - return; - } - - const requiredCoverage = context.options[0]; - const { coveredCount, uncoveredCount } = res; - - /* eslint prefer-template: 0 */ - const percentage = Number( - Math.round( - coveredCount / (coveredCount + uncoveredCount) * 10000 - ) + 'e-2' - ); - - if (percentage < requiredCoverage) { - context.report({ - loc: program.loc, - message: `Expected coverage to be at least ${requiredCoverage}%, but is: ${percentage}%` - }); - } + if (percentage < requiredCoverage) { + context.report({ + loc: program.loc, + message: `Expected coverage to be at least ${requiredCoverage}%, but is: ${percentage}%` + }); } } }; }, - 'show-errors': createFilteredErrorRule(({ level }) => level !== FlowSeverity.Warning), - 'show-warnings': createFilteredErrorRule(({ level }) => level === FlowSeverity.Warning) + 'show-errors': createFilteredErrorRule( + ({ level }) => level !== FlowSeverity.Warning + ), + 'show-warnings': createFilteredErrorRule( + ({ level }) => level === FlowSeverity.Warning + ) } }; diff --git a/test/codebases/column-offset/.flowconfig b/test/codebases/column-offset/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/column-offset/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/codebases/coverage-fail/.flowconfig b/test/codebases/coverage-fail/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/coverage-fail/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/codebases/coverage-fail2/.flowconfig b/test/codebases/coverage-fail2/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/coverage-fail2/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/codebases/coverage-ok/.flowconfig b/test/codebases/coverage-ok/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/coverage-ok/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/codebases/coverage-ok2/.flowconfig b/test/codebases/coverage-ok2/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/coverage-ok2/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/codebases/flow-pragma-1/.flowconfig b/test/codebases/flow-pragma-1/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/flow-pragma-1/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/codebases/flow-pragma-2/.flowconfig b/test/codebases/flow-pragma-2/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/flow-pragma-2/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/codebases/html-support/.flowconfig b/test/codebases/html-support/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/html-support/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/codebases/no-flow-pragma/.flowconfig b/test/codebases/no-flow-pragma/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/no-flow-pragma/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/codebases/project-1/.flowconfig b/test/codebases/project-1/.flowconfig new file mode 100644 index 0000000..3fa7797 --- /dev/null +++ b/test/codebases/project-1/.flowconfig @@ -0,0 +1,4 @@ +[options] +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable diff --git a/test/format.spec.js b/test/format.spec.js index 6a18f6a..d316807 100644 --- a/test/format.spec.js +++ b/test/format.spec.js @@ -1,7 +1,8 @@ import path from 'path'; import { expect as chaiExpect } from 'chai'; import { readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'fs'; -import { sync as spawnSync } from 'cross-spawn'; +// $FlowIgnore +import execa from 'execa'; import { collect } from '../src/collect'; const testFilenames = [ @@ -17,18 +18,15 @@ const testFilenames = [ '10.example.js' ]; -const testResults = testFilenames.map((filename, index) => { - const root = path.resolve(process.cwd(), 'test'); - const filepath = path.join(root, filename); - const stdin = readFileSync(filepath).toString(); - const parsedJSONArray = collect(stdin, root, true, filepath, { line: 0, column: 0 }); - - return { parsedJSONArray, filename, index }; -}); - describe('Format', () => { - for (const { parsedJSONArray, filename } of testResults) { + for (const filename of testFilenames) { it(`${filename} - should have expected properties`, () => { + + const root = path.resolve(process.cwd(), 'test'); + const filepath = path.join(root, filename); + const stdin = readFileSync(filepath).toString(); + const parsedJSONArray = collect(stdin, root, true, filepath, { line: 0, column: 0 }); + chaiExpect(parsedJSONArray).to.be.an('array'); // Filter out the 'path' property because this changes between environments @@ -59,8 +57,8 @@ describe('Format', () => { const ESLINT_PATH = path.resolve('./node_modules/eslint/bin/eslint.js'); -function runEslint(cwd) { - const result = spawnSync(ESLINT_PATH, ['**/*.js', '**/*.vue'], { cwd }); +async function runEslint(cwd) { + const result = await execa(ESLINT_PATH, ['**/*.js', '**/*.vue'], { cwd }); result.stdout = result.stdout && result.stdout.toString(); result.stderr = result.stderr && result.stderr.toString(); return result; @@ -122,7 +120,6 @@ const eslintConfig = (enforceMinCoverage, html) => ` plugins: [${html ? `'html', 'vue',` : ''}'flowtype-errors'], settings: { 'flowtype-errors': { - flowDir: './subdir', stopOnExit: 'true' } }, @@ -154,7 +151,7 @@ describe('Check codebases', () => { folder = codebase; } - it(`${title} - eslint should give expected output`, () => { + it(`${title} - eslint should give expected output`, async() => { // eslint-disable-line no-loop-func const fullFolder = path.resolve(`./test/codebases/${folder}`); const configPath = path.resolve(fullFolder, '.eslintrc.js'); @@ -165,7 +162,7 @@ describe('Check codebases', () => { ); // Spawn a eslint process - const { stdout, stderr } = runEslint(fullFolder); + const { stdout, stderr } = await runEslint(fullFolder); const regexp = new RegExp( `^${fullFolder.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')}.+\\.(js|vue)$`, diff --git a/yarn.lock b/yarn.lock index 09df753..fad072b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1390,7 +1390,7 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^6.0.5: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" dependencies: @@ -1953,6 +1953,18 @@ exec-sh@^0.2.0: dependencies: merge "^1.1.3" +execa@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + dependencies: + cross-spawn "^6.0.0" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" @@ -2153,6 +2165,12 @@ find-up@^2.0.0, find-up@^2.1.0: dependencies: locate-path "^2.0.0" +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + dependencies: + locate-path "^3.0.0" + flat-cache@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" @@ -3308,6 +3326,13 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" @@ -3739,16 +3764,32 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" +p-limit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" dependencies: p-limit "^1.1.0" +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + dependencies: + p-limit "^2.0.0" + p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" +p-try@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" From 0851be8cfbcf2d9c2de1034ac34fde133d65d0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Mota?= Date: Mon, 30 Jul 2018 20:16:59 +0100 Subject: [PATCH 2/4] Fix tests --- test/format.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/format.spec.js b/test/format.spec.js index d316807..6a719b6 100644 --- a/test/format.spec.js +++ b/test/format.spec.js @@ -162,7 +162,7 @@ describe('Check codebases', () => { ); // Spawn a eslint process - const { stdout, stderr } = await runEslint(fullFolder); + const { stdout, stderr } = await runEslint(fullFolder).catch(e => e); const regexp = new RegExp( `^${fullFolder.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')}.+\\.(js|vue)$`, From 87a8da1733361fbb61ad406462ad90aae0e891aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Mota?= Date: Mon, 30 Jul 2018 20:31:25 +0100 Subject: [PATCH 3/4] Increase test timeout --- test/format.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/format.spec.js b/test/format.spec.js index 6a719b6..c0a7379 100644 --- a/test/format.spec.js +++ b/test/format.spec.js @@ -5,6 +5,8 @@ import { readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'fs'; import execa from 'execa'; import { collect } from '../src/collect'; +jest.setTimeout(10000); + const testFilenames = [ '1.example.js', '2.example.js', From 2fa752af2ce750cd68eb83d22bc93bc9a057e036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Mota?= Date: Wed, 1 Aug 2018 17:10:36 +0100 Subject: [PATCH 4/4] Don't strip eof (for now) --- test/format.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/format.spec.js b/test/format.spec.js index c0a7379..3d8a205 100644 --- a/test/format.spec.js +++ b/test/format.spec.js @@ -60,7 +60,7 @@ describe('Format', () => { const ESLINT_PATH = path.resolve('./node_modules/eslint/bin/eslint.js'); async function runEslint(cwd) { - const result = await execa(ESLINT_PATH, ['**/*.js', '**/*.vue'], { cwd }); + const result = await execa(ESLINT_PATH, ['**/*.js', '**/*.vue'], { cwd, stripEof: false }); result.stdout = result.stdout && result.stdout.toString(); result.stderr = result.stderr && result.stderr.toString(); return result;