Skip to content

Commit

Permalink
fix: use correct lint config for individual files (#167)
Browse files Browse the repository at this point in the history
When invoked with a list of files, linter configuration pertaining to
those files should be preferred rather than the gts default config.
  • Loading branch information
ofrobots committed Jun 7, 2018
1 parent 9689211 commit 09ca073
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 26 deletions.
66 changes: 46 additions & 20 deletions src/lint.ts
Expand Up @@ -28,28 +28,54 @@ import {Options} from './cli';
*/
export function lint(
options: Options, files: string[] = [], fix = false): boolean {
const configPath =
fs.existsSync(path.join(options.targetRootDir, 'tslint.json')) ?
path.join(options.targetRootDir, 'tslint.json') :
path.join(options.gtsRootDir, 'tslint.json');

const program = createProgram(options);
const configuration = Configuration.findConfiguration(configPath, '').results;
const linter = new Linter({fix, formatter: 'codeFrame'}, program);
const srcFiles = files.length > 0 ? files : Linter.getFileNames(program);
srcFiles.forEach(file => {
const sourceFile = program.getSourceFile(file);
if (sourceFile) {
const fileContents = sourceFile.getFullText();
linter.lint(file, fileContents, configuration);
if (files.length > 0) { // manually provided filenames.
const rcs = files.map(file => {
// Different config files may apply to each file.
const configPath = Configuration.findConfigurationPath(null, file) ||
path.join(options.gtsRootDir, 'tslint.json');

const configuration =
Configuration.loadConfigurationFromPath(configPath, '');
const source = fs.readFileSync(file, 'utf8');

const linter = new Linter({fix, formatter: 'codeFrame'});
linter.lint(file, source, configuration);
const result = linter.getResult();
if (result.errorCount || result.warningCount) {
options.logger.log(result.output);
return false;
}
return true;
});

return rcs.every(rc => rc); // if all files succeeded.
} else {
// Lint the set of files specified by the typescript program config.
const program = createProgram(options);
files = Linter.getFileNames(program);

const configPath =
fs.existsSync(path.join(options.targetRootDir, 'tslint.json')) ?
path.resolve(options.targetRootDir, 'tslint.json') :
path.resolve(options.gtsRootDir, 'tslint.json');

const configuration = Configuration.loadConfigurationFromPath(configPath);
const linter = new Linter({fix, formatter: 'codeFrame'}, program);

files.forEach(file => {
const sourceFile = program.getSourceFile(file);
if (sourceFile) {
const fileContents = sourceFile.getFullText();
linter.lint(file, fileContents, configuration);
}
});
const result = linter.getResult();
if (result.errorCount || result.warningCount) {
options.logger.log(result.output);
return false;
}
});
const result = linter.getResult();
if (result.errorCount || result.warningCount) {
options.logger.log(result.output);
return false;
return true;
}
return true;
}

export function createProgram(options: Options): ts.Program {
Expand Down
45 changes: 39 additions & 6 deletions test/test-lint.ts
Expand Up @@ -135,20 +135,21 @@ test.serial('lint should lint only specified files', async t => {
});
});

test.serial('lint should not throw for unrecognized files', async t => {
test.serial('lint should throw for unrecognized files', async t => {
await withFixtures(
{
'tsconfig.json': JSON.stringify({}),
'a.ts': GOOD_CODE,
},
async () => {
lint.lint(OPTIONS, ['z.ts']);
t.pass();
t.throws(() => {
lint.lint(OPTIONS, ['z.ts']);
});
});
});

test.serial('lint should prefer user config file over default', async t => {
const CUSTOM_LINT_CODE = 'const t: Object;';
const CUSTOM_LINT_CODE = 'debugger;';

// By defualt the above should fail lint.
await withFixtures(
Expand All @@ -158,7 +159,7 @@ test.serial('lint should prefer user config file over default', async t => {
},
async () => {
const okay = lint.lint(OPTIONS);
t.is(okay, false);
t.false(okay);
});

// User should be able to override the default config.
Expand All @@ -170,8 +171,40 @@ test.serial('lint should prefer user config file over default', async t => {
},
async () => {
const okay = lint.lint(OPTIONS);
t.is(okay, true);
t.true(okay);
});
});

test.serial(
'lint for specific files should use file-specific config', async t => {
const CODE_WITH_PARSEINT = 'parseInt(42);';
let logBuffer = '';
const optionsWithLog = Object.assign({}, OPTIONS, {
logger: {
log: (...args: string[]) => {
logBuffer += (args.join(' '));
},
error: nop,
dir: nop
}
});
await withFixtures(
{
dira: {
'a.ts': CODE_WITH_PARSEINT,
// no tslint, so default should apply.
},
dirb: {
'b.ts': CODE_WITH_PARSEINT,
'tslint.json': JSON.stringify({})
}
},
async () => {
const okay = lint.lint(optionsWithLog, ['dira/a.ts', 'dirb/b.ts']);
t.false(okay);
t.regex(logBuffer, /dira\/a\.ts/);
t.notRegex(logBuffer, /dirb\/b\.ts/);
});
});

// TODO: test for when tsconfig.json is missing.

0 comments on commit 09ca073

Please sign in to comment.