Skip to content

Commit

Permalink
Support passing custom config, add mocha reporter, stay silent in cas…
Browse files Browse the repository at this point in the history
…e of continuous integration environment
  • Loading branch information
Li0liQ committed Dec 13, 2017
1 parent e9e35d4 commit 58b456d
Show file tree
Hide file tree
Showing 17 changed files with 180 additions and 89 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ yarn add stricter --dev
```
yarn stricter
```
You can run `yarn stricter --help` for help.

# Configuration
Stricter uses `stricter.config.js` to read configuration.
Expand Down Expand Up @@ -95,7 +96,7 @@ interface RuleDefinition {
`onProject` should return an array of strings, describing violations, or an empty array if there is none.

# Debugging
It helps to use `src/cli.ts` as an entry point for debugging.
It helps to use `src/debug.ts` as an entry point for debugging.
A sample launch.json for VS Code might look like
```json
{
Expand Down
2 changes: 1 addition & 1 deletion bin/cli.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env node

var run = require('stricter').default;
var run = require('stricter').cli;
var result = run();
process.exit(result);
10 changes: 8 additions & 2 deletions fuse.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const FuseBox = require('fuse-box').FuseBox;
const { TypeScriptHelpers } = require('fuse-box');
const { ReplacePlugin , TypeScriptHelpers } = require('fuse-box');
const TypeHelper = require('fuse-box-typechecker').TypeHelper;
const isProduction = process.env.NODE_ENV === 'production';
const version = require('./package.json').version;

const typeHelper = TypeHelper({
tsConfig: './tsconfig.json',
Expand All @@ -16,7 +17,12 @@ const fuse = FuseBox.init({
name: 'stricter',
entry: 'src/index.js',
},
plugins: [TypeScriptHelpers()],
plugins: [
ReplacePlugin({
'process.env.STRICTER_VERSION': JSON.stringify(version),
}),
TypeScriptHelpers(),
],
homeDir: 'src',
output: 'dist/$name.js',
target: 'server',
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
},
"devDependencies": {
"@types/chalk": "^2.2.0",
"@types/commander": "^2.12.2",
"@types/jest": "^21.1.8",
"@types/node": "^8.0.58",
"cross-env": "^5.1.1",
Expand All @@ -66,7 +67,9 @@
"@babel/traverse": "7.0.0-beta.34",
"babylon": "^7.0.0-beta.34",
"chalk": "^2.3.0",
"cosmiconfig": "^3.1.0"
"commander": "^2.12.2",
"cosmiconfig": "^3.1.0",
"is-ci": "^1.0.10"
},
"engines": {
"node": ">=8.0.0"
Expand Down
28 changes: 23 additions & 5 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
// This is not the actual CLI deploye with the app.
// The sole purpose of the file is to help debugging.
let run = require('.').default;
let result = run();
process.exit(result);
import * as program from 'commander';
import * as isCi from 'is-ci';
import stricter from './stricter';

export default (): number => {
program
.version(process.env.STRICTER_VERSION as string)
.option('-c, --config <path>', 'specify config location')
.option(
'-r, --reporter <console|mocha>',
'specify reporter',
/^(console|mocha)$/i,
'console',
)
.parse(process.argv);
const result = stricter({
configPath: program.config,
reporter: program.reporter,
silent: isCi,
});

return result;
};
4 changes: 2 additions & 2 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import readConfig from './read-config';
import processConfig from './process-config';
import validateConfig from './validate-config';

export const getConfig = (): Config => {
const foundConfig = readConfig();
export const getConfig = (configPath?: string): Config => {
const foundConfig = readConfig(configPath);
validateConfig(foundConfig);
const processedConfig = processConfig(foundConfig);

Expand Down
3 changes: 2 additions & 1 deletion src/config/read-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { CosmiConfig } from './../types';

const moduleName = 'stricter';

export default (): CosmiConfig => {
export default (configPath?: string): CosmiConfig => {
const explorer = cosmiconfig(moduleName, {
configPath,
sync: true,
packageProp: false,
rc: false,
Expand Down
5 changes: 5 additions & 0 deletions src/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// This is not the actual CLI deploye with the app.
// The sole purpose of the file is to help debugging.
let run = require('.').cli;
let result = run();
process.exit(result);
30 changes: 2 additions & 28 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,2 @@
import { getConfig } from './config';
import { getRuleDefinitions, getRuleApplications, filterFilesToProcess } from './rule';
import { applyProjectRules, readDependencies, readFilesData } from './processor';
import { consoleLogger } from './logger';
import { listFiles } from './utils';

export default (): number => {
console.log('Stricter: Checking...');
const config = getConfig();

const fileList = listFiles(config.root);

const ruleDefinitions = getRuleDefinitions(config);
const ruleApplications = getRuleApplications(config, ruleDefinitions);
const filesToProcess = filterFilesToProcess(config.root, fileList, ruleApplications);

const filesData = readFilesData(filesToProcess);
const dependencies = readDependencies(filesData, config);
const projectResult = applyProjectRules(config.root, filesData, dependencies, ruleApplications);

const result = consoleLogger(projectResult);

if (result === 0) {
console.log('Stricter: No errors');
}

return result;
};
export { default as stricter } from './stricter';
export { default as cli } from './cli';
19 changes: 0 additions & 19 deletions src/logger/console.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ describe('consoleLogger', () => {

it('runs warn for every warning', () => {
const warn = {
filePath: 'filePath',
rule: 'rule',
warnings: ['warning1', 'warning2'],
};
Expand All @@ -24,7 +23,6 @@ describe('consoleLogger', () => {

it('runs error for every error', () => {
const error = {
filePath: 'filePath',
rule: 'rule',
errors: ['error1', 'error2'],
};
Expand All @@ -33,25 +31,8 @@ describe('consoleLogger', () => {
expect(errorMock.mock.calls.length).toBe(4);
});

it('log different file names', () => {
const error1 = {
filePath: 'filePath1',
rule: 'rule',
errors: ['error1'],
};
const error2 = {
filePath: 'filePath2',
rule: 'rule',
errors: ['error2'],
};
logConsole([error1, error2]);

expect(logMock.mock.calls.length).toBe(2);
});

it("doesn't log same file name twice", () => {
const error = {
filePath: 'filePath',
rule: 'rule',
errors: ['error1', 'error2'],
};
Expand Down
14 changes: 5 additions & 9 deletions src/logger/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@ import chalk from 'chalk';
import { LogEntry } from './../types';

export default (logs: LogEntry[]): void => {
let previousFilePath: string | undefined;
if (!logs.length) {
return;
}

logs.forEach(log => {
if (previousFilePath !== log.filePath) {
previousFilePath = log.filePath;

if (log.filePath) {
console.log(chalk.white(log.filePath));
}
}
console.log(chalk.bgBlackBright('Project'));

logs.forEach(log => {
if (log.warnings) {
log.warnings.forEach(warning => {
console.warn(chalk.yellow('warning: ') + chalk.gray(log.rule) + ' ' + warning);
Expand Down
25 changes: 6 additions & 19 deletions src/logger/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
import chalk from 'chalk';
import { RuleToRuleApplicationResult } from './../types';
import logToConsole from './console';
import { compactProjectLogs } from './flatten';
import { LogEntry } from './../types';

export const consoleLogger = (projectResult: RuleToRuleApplicationResult): number => {
const projectLogs = compactProjectLogs(projectResult);

if (projectLogs.length) {
console.log(chalk.bgBlackBright('Project'));
logToConsole(projectLogs);
}

const errorCount = Object.values(projectLogs).reduce(
(acc, i) => acc + ((i.errors && i.errors.length) || 0),
0,
);

return errorCount;
};
export { default as consoleLogger } from './console';
export { default as mochaLogger } from './mocha';
export { compactProjectLogs } from './flatten';
export const getErrorCount = (projectLogs: LogEntry[]) =>
Object.values(projectLogs).reduce((acc, i) => acc + ((i.errors && i.errors.length) || 0), 0);
47 changes: 47 additions & 0 deletions src/logger/mocha.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as fs from 'fs';
import { LogEntry } from './../types';

const reportFileName = 'stricter.json';

const encode = (str: string) => {
const substitutions = {
'&:': '&amp;',
'"': '&quot;',
"'": '&apos;',
'<': '&lt;',
'>': '&gt;',
};

const result = Object.entries(substitutions).reduce((acc, [original, substitution]) => {
return acc.replace(new RegExp(original, 'g'), substitution);
}, str);

return result;
};

export default (logs: LogEntry[]): void => {
const now = new Date();
const failuresCount = logs.reduce((acc, i) => acc + ((i.errors && i.errors.length) || 0), 0);

const report = {
stats: {
tests: failuresCount,
passes: 0,
failures: failuresCount,
duration: 0,
start: now,
end: now,
},
failures: logs.map(log => ({
title: log.rule,
fullTitle: log.rule,
duration: 0,
errorCount: (log.errors && log.errors.length) || 0,
error: log.errors && log.errors.map(i => encode(i)).join('\n'),
})),
passes: [],
skipped: [],
};

fs.writeFileSync(reportFileName, JSON.stringify(report, null, 2), 'utf-8');
};
48 changes: 48 additions & 0 deletions src/stricter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { getConfig } from './config';
import { getRuleDefinitions, getRuleApplications, filterFilesToProcess } from './rule';
import { applyProjectRules, readDependencies, readFilesData } from './processor';
import { consoleLogger, mochaLogger, compactProjectLogs, getErrorCount } from './logger';
import { listFiles } from './utils';
import { StricterArguments, Reporter } from './types';

export default ({
silent = false,
reporter = Reporter.CONSOLE,
configPath,
}: StricterArguments): number => {
if (!silent) {
console.log('Stricter: Checking...');
}

const config = getConfig(configPath);

const fileList = listFiles(config.root);

const ruleDefinitions = getRuleDefinitions(config);
const ruleApplications = getRuleApplications(config, ruleDefinitions);
const filesToProcess = filterFilesToProcess(config.root, fileList, ruleApplications);

const filesData = readFilesData(filesToProcess);
const dependencies = readDependencies(filesData, config);
const projectResult = applyProjectRules(config.root, filesData, dependencies, ruleApplications);

const logs = compactProjectLogs(projectResult);

if (reporter === Reporter.MOCHA) {
mochaLogger(logs);
} else {
consoleLogger(logs);
}

const result = getErrorCount(logs);

if (!silent) {
if (result === 0) {
console.log('Stricter: No errors');
} else {
console.log(`Stricter: ${result} error${result > 1 ? 's' : ''}`);
}
}

return result;
};
12 changes: 11 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export enum Level {
OFF = 'off',
}

export enum Reporter {
CONSOLE = 'console',
MOCHA = 'mocha',
}

export interface RuleUsageConfig {
[prop: string]: any;
}
Expand Down Expand Up @@ -81,8 +86,13 @@ export interface FileToRule {
}

export interface LogEntry {
filePath?: string;
rule: string;
errors?: string[];
warnings?: string[];
}

export interface StricterArguments {
silent?: boolean;
configPath?: string;
reporter?: Reporter;
}
4 changes: 4 additions & 0 deletions types/missing.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
declare module 'cosmiconfig'; // does not exist
declare module 'babylon'; // existing libdef misses plugins we use
declare module '@babel/traverse'; // existing libdef misses plugins we use
declare module 'is-ci' {
var isCi: boolean;
export = isCi;
}
Loading

0 comments on commit 58b456d

Please sign in to comment.