Skip to content

Commit 85cf53a

Browse files
authored
feat: add support for eslint for code style enforcement (#33)
* feat: add eslint * feat: add eslint to js standards * chore: add comments * chore: add comments * chore: add comments * refactor: simplify and electrify * test: foobar * test: remove test * docs: add jsdoc * fix: use sourcetype module * chore: remove sort imports * refactor: rename const to severity * refactor: here we go * refactor: run standardisation tools as a stream * chore: add babel-eslint as dep * refactor: change variable names for readability * refactor: export git commands * chore: add performance measurements for hotspots * chore: improve logging in verbose * chore: print amount of files for total time * chore: consistent logging * fix: abort early if there are no files to work on * refactor: rearrange structure * docs: update readme * docs: fix ugly formatting in readme * refactor: de-duplicate the code that runs js tools * fix: change command to runner * fix: remove confusing name from runner of commitlint * chore: only filter for violations once * fix: change output to debug level * chore: rename underscored functions to camelcase * chore: rename snake case to camel case * fix: add boolean to toggle between check and apply * fix: only write and stage modified files * fix: rename summary to summarize (verb vs. noun) * fix: track modified source * fix: reduce confusing logging * refactor: improve logging * fix: only do things when there are things to do * fix: remove unused prop * fix: make commit check consistent * docs: improve jsdocs * fix: ignore vendor folders for now * fix: make eslint a bit stricter for now * fix: do not use optional filename arg to execute on text
1 parent 2f1248c commit 85cf53a

File tree

17 files changed

+992
-227
lines changed

17 files changed

+992
-227
lines changed

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@
99
[![travis.com build](https://img.shields.io/travis/com/dhis2/cli-style.svg)](https://travis-ci.com/dhis2/cli-style)
1010
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org) [![Greenkeeper badge](https://badges.greenkeeper.io/dhis2/cli-style.svg)](https://greenkeeper.io/)
1111

12-
This tool applies our configuration for:
12+
This tool enforces DHIS2 configuration for:
1313

14-
- Git commit messages
15-
- Prettier (prettifies JavaScript)
16-
- Browserslist
14+
#### Git
15+
16+
- Git commit messages
17+
18+
#### JavaScript
19+
20+
- Prettier
21+
- ESLint
22+
- Browserslist
1723

1824
This tool is part of the [dhis2/cli](https://github.com/dhis2/cli)
1925
suite, but can also be used standalone which is useful for project level

config/eslint.config.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const SEVERITY = 2
2+
3+
module.exports = {
4+
root: true,
5+
6+
parser: 'babel-eslint',
7+
8+
env: {
9+
browser: true,
10+
node: true,
11+
jest: true,
12+
},
13+
14+
parserOptions: {
15+
// latest standard is ok, eq. to 9
16+
ecmaVersion: 2018,
17+
ecmaFeatures: {
18+
jsx: true,
19+
modules: true,
20+
},
21+
},
22+
23+
rules: {
24+
'max-params': [
25+
SEVERITY,
26+
{
27+
max: 3,
28+
},
29+
],
30+
'prefer-const': [
31+
SEVERITY,
32+
{
33+
destructuring: 'any',
34+
ignoreReadBeforeAssign: false,
35+
},
36+
],
37+
'no-mixed-spaces-and-tabs': [SEVERITY],
38+
},
39+
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"@commitlint/load": "^7.2.1",
1919
"@commitlint/read": "^7.1.2",
2020
"@dhis2/cli-helpers-engine": "^1.0.1",
21+
"babel-eslint": "^10.0.1",
22+
"eslint": "^5.16.0",
23+
"perfy": "^1.1.5",
2124
"prettier": "^1.15.3",
2225
"yargs": "^13.1.0"
2326
},

src/cmds/commit_cmds/check.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const log = require('@dhis2/cli-helpers-engine').reporter
2-
const fmt = require('../../commitlint.js')
2+
const { runner } = require('../../tools/git')
33

44
exports.command = 'check [msg]'
55

@@ -10,9 +10,11 @@ exports.builder = {}
1010
exports.handler = async function(argv) {
1111
const { msg } = argv
1212

13-
const report = await fmt(msg)
13+
const report = await runner(msg)
1414

15-
if (report.valid) {
15+
report.summarize()
16+
17+
if (report.hasViolations) {
1618
log.info('Commit message is valid')
1719
process.exit(0)
1820
} else {

src/cmds/js_cmds/apply.js

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
const { collectFiles, jsFiles } = require('../../files.js')
1+
const path = require('path')
2+
23
const log = require('@dhis2/cli-helpers-engine').reporter
34

4-
const { apply_fmt } = require('../../prettier.js')
5-
const { stage_files, staged_files } = require('../../git.js')
5+
const { selectFiles } = require('../../files.js')
6+
const { stageFiles } = require('../../git-files.js')
7+
8+
const { runner } = require('../../tools/js')
69

710
exports.command = 'apply [files..]'
811

@@ -25,34 +28,22 @@ exports.builder = {
2528

2629
exports.handler = argv => {
2730
const { all, stage, files } = argv
28-
const root_dir = process.cwd()
29-
30-
let codeFiles
31-
if (all) {
32-
codeFiles = collectFiles(root_dir)
33-
} else if (files) {
34-
codeFiles = files
35-
} else {
36-
codeFiles = staged_files(root_dir)
37-
}
3831

39-
// debug information about the folders
40-
log.debug('rootDir?', root_dir)
41-
log.debug('codeFiles?', codeFiles)
32+
const root = process.cwd()
33+
log.debug(`Root directory: ${root}`)
4234

43-
const js = jsFiles(codeFiles)
44-
const prettyFiles = apply_fmt(js)
35+
const codeFiles = selectFiles(files, all, root)
36+
const report = runner(codeFiles, true)
4537

46-
if (prettyFiles.length === 0) {
47-
if (js.length > 0) {
48-
log.info(`${js.length} file(s) reformatted.`)
49-
} else {
50-
log.info('No files to format.')
51-
}
38+
report.summarize()
39+
40+
if (report.hasViolations) {
41+
process.exit(1)
5242
}
5343

54-
if (stage) {
55-
const stagedFiles = stage_files(prettyFiles, root_dir)
56-
log.debug('Staged files', stagedFiles)
44+
const fixed = report.fix()
45+
46+
if (stage && fixed.length > 0) {
47+
stageFiles(fixed, root)
5748
}
5849
}

src/cmds/js_cmds/check.js

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
const path = require('path')
2-
const { collectFiles, jsFiles } = require('../../files.js')
31
const log = require('@dhis2/cli-helpers-engine').reporter
42

5-
const { check_fmt } = require('../../prettier.js')
6-
const { staged_files } = require('../../git.js')
3+
const { runner } = require('../../tools/js')
4+
const { selectFiles } = require('../../files.js')
75

86
exports.command = 'check [files..]'
97

@@ -19,40 +17,17 @@ exports.builder = {
1917
}
2018

2119
exports.handler = argv => {
22-
const { all, files } = argv
23-
const root_dir = process.cwd()
24-
25-
let codeFiles
26-
if (all) {
27-
codeFiles = collectFiles(root_dir)
28-
} else if (files) {
29-
codeFiles = files
30-
} else {
31-
codeFiles = staged_files(root_dir)
32-
}
20+
const { files, all } = argv
3321

34-
// debug information about the folders
35-
log.debug('rootDir?', root_dir)
36-
log.debug('codeFiles?', codeFiles)
22+
const root = process.cwd()
23+
log.debug(`Root directory: ${root}`)
3724

38-
const js = jsFiles(codeFiles)
39-
const prettyFiles = check_fmt(js)
25+
const codeFiles = selectFiles(files, all, root)
26+
const report = runner(codeFiles)
4027

41-
const success = prettyFiles.length > 0
28+
report.summarize()
4229

43-
if (success) {
44-
log.info(`${prettyFiles.length} file(s) needs to be formatted:`)
45-
prettyFiles.forEach(f =>
46-
log.print(`${path.relative(process.cwd(), f)}`)
47-
)
48-
log.print('')
30+
if (report.hasViolations) {
4931
process.exit(1)
50-
} else {
51-
if (js.length > 0) {
52-
log.info(`${js.length} file(s) passed the style check.`)
53-
} else {
54-
log.info('No files to check.')
55-
}
56-
process.exit(0)
5732
}
5833
}

src/config.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,29 @@ const log = require('@dhis2/cli-helpers-engine').reporter
55

66
const { readFile, writeFile } = require('./files.js')
77

8-
function wipe_prop_cfg(repo) {
9-
const pkg_path = path.join(repo, 'package.json')
8+
function wipeConfigProperties(repo) {
9+
const pkgPath = path.join(repo, 'package.json')
1010

1111
try {
12-
const fd = fs.readFileSync(pkg_path)
12+
const fd = fs.readFileSync(pkgPath)
1313
const data = JSON.parse(fd.toString('utf8'))
1414

1515
delete data.prettier
1616

1717
const out = JSON.stringify(data, null, 2) + '\n'
1818
try {
19-
fs.writeFileSync(pkg_path, out)
20-
log.debug(pkg_path + ' updated and saved')
19+
fs.writeFileSync(pkgPath, out)
20+
log.debug(pkgPath + ' updated and saved')
2121
} catch (err) {
2222
log.error('failed to get package.json for repo: ' + repo)
2323
}
2424
} catch (e) {
25-
log.error('failed to get package.json: ' + pkg_path)
25+
log.error('failed to get package.json: ' + pkgPath)
2626
}
2727
}
2828

29-
function wipe_file_cfg(repo) {
30-
const wipe_cfg_list = [
29+
function wipeConfigFiles(repo) {
30+
const configs = [
3131
'.prettierrc',
3232
'.prettierrc.yaml',
3333
'.prettierrc.yml',
@@ -40,7 +40,7 @@ function wipe_file_cfg(repo) {
4040
'.editorconfig',
4141
]
4242

43-
wipe_cfg_list.map(cfg => {
43+
configs.map(cfg => {
4444
try {
4545
fs.unlinkSync(path.join(repo, cfg))
4646
log.debug(cfg + ' removed from repo: ' + repo)
@@ -51,8 +51,8 @@ function wipe_file_cfg(repo) {
5151
}
5252

5353
function cleanup(repo) {
54-
wipe_prop_cfg(repo)
55-
wipe_file_cfg(repo)
54+
wipeConfigProperties(repo)
55+
wipeConfigFiles(repo)
5656
}
5757

5858
function copy(from, to) {

src/files.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ const path = require('path')
33

44
const log = require('@dhis2/cli-helpers-engine').reporter
55

6-
const blacklist = ['node_modules', 'build', 'dist', 'target', '.git']
6+
const { stagedFiles } = require('./git-files.js')
7+
8+
const blacklist = ['node_modules', 'build', 'dist', 'target', '.git', 'vendor']
79

810
const whitelists = {
911
js: ['.js', '.jsx', '.ts'],
@@ -48,6 +50,19 @@ function collectFiles(target) {
4850
.reduce((a, b) => a.concat(b), [])
4951
}
5052

53+
function selectFiles(files, all, dir) {
54+
let codeFiles
55+
if (all) {
56+
codeFiles = collectFiles(dir)
57+
} else if (files) {
58+
codeFiles = files
59+
} else {
60+
codeFiles = stagedFiles(dir)
61+
}
62+
63+
return codeFiles
64+
}
65+
5166
function readFile(fp) {
5267
try {
5368
const text = fs.readFileSync(fp, 'utf8')
@@ -72,6 +87,7 @@ module.exports = {
7287
collectFiles,
7388
collectAllFiles,
7489
collectJsFiles,
90+
selectFiles,
7591
jsFiles,
7692
readFile,
7793
writeFile,

src/git-files.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* This requires that there is a Git binary on $PATH
3+
*/
4+
const { execSync } = require('child_process')
5+
6+
const log = require('@dhis2/cli-helpers-engine').reporter
7+
8+
const stageFile = (file, dir) => {
9+
log.debug(`Staging ${file}...`)
10+
const added = execSync(`git add ${file}`, {
11+
cwd: dir,
12+
encoding: 'utf8',
13+
})
14+
return file
15+
}
16+
17+
const stageFiles = (files, dir) => {
18+
const staged = files.map(f => stageFile(f, dir))
19+
log.info(`Staged ${files.length} file(s).`)
20+
return staged
21+
}
22+
23+
const stagedFiles = dir => {
24+
const files = execSync('git diff --cached --name-only --relative', {
25+
cwd: dir,
26+
encoding: 'utf8',
27+
}).trim()
28+
if (!!files) {
29+
const s = files.split('\n')
30+
log.info(`Fetching staged files: ${s.length} file(s).`)
31+
return s
32+
}
33+
log.info('No staged files found.')
34+
return []
35+
}
36+
37+
module.exports = {
38+
stagedFiles,
39+
stageFiles,
40+
stageFile,
41+
}

src/git.js

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)