Skip to content

Commit 7881ccb

Browse files
bebrawjonathanglasmeyer
authored andcommitted
feat(cli): Support --all-scripts
Now it's possible to execute `webpack-validator --all-scripts` (or just `-a`). After executing, *webpack-validator* will go through your **package.json** `scripts` and tries to validate each. Closes #72.
1 parent 4e3806e commit 7881ccb

File tree

7 files changed

+140
-33
lines changed

7 files changed

+140
-33
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,10 @@ module.exports = validate(config, yourSchema)
8080
```
8181

8282
#### Quiet Mode
83-
If you want to mute console output apart from errors, set `--quiet` or `validate(config, yourSchema, {quiet: true})`. This is particularly useful if you are using webpack `--json` as you'll want to avoid writing additional text to the JSON output.
83+
If you want to mute console output apart from errors, set `--quiet` (`-q`) or `validate(config, yourSchema, {quiet: true})`. This is particularly useful if you are using webpack `--json` as you'll want to avoid writing additional text to the JSON output.
84+
85+
#### Validate All **package.json** `scripts`
86+
It is possible to use the CLI to validate all your **package.json** `scripts` related configurations at once by using `--all-scripts` (`-a`). The system will try to guess the convention you are using and then executes validation against each script target based on that.
8487

8588
#### Advanced Usage
8689
If you need to access the validation results directly and want to control the side-effects (i.e. console.log output, `process.exit(1)` on fail behaviour) yourself, you can call the validation function like so: `validate(config, yourSchema, { returnValidation: true })`. This will make 1) the function return the validation results instead of your configuration and 2) not perform any side effects.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"lint": "eslint .",
1616
"cover": "nyc --reporter=lcov --reporter=text --reporter=html mocha src/**/*.test.js",
1717
"report-coverage": "cat ./coverage/lcov.info | node_modules/.bin/codecov",
18-
"test": "mocha src/**/*.test.js",
18+
"test": "mocha \"src/**/*.test.js\"",
1919
"watch:test": "npm run test -- -w",
2020
"release": "npm run build && with-package git commit -am pkg.version && with-package git tag pkg.version && git push && npm publish && git push --tags",
2121
"release:beta": "npm run release && npm run tag:beta",

src/bin/script-parsers.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export function webpackConfig(script) {
2+
// Try to parse webpack config name. Not fool proof. Maybe
3+
// there's a neater way.
4+
const parts = script.split('--config')
5+
6+
if (parts.length > 1) {
7+
// Pick the last part, trim and split to extract
8+
return parts[parts.length - 1].trim().split(' ')[0]
9+
}
10+
11+
return 'webpack.config.js'
12+
}
13+
14+
export function nodeEnv(script) {
15+
const parsedScript = script.indexOf('SET ') === 0 ?
16+
script.split('SET ')[1] :
17+
script
18+
19+
const parts = parsedScript.split('NODE_ENV=')
20+
21+
if (parts.length < 2) {
22+
return ''
23+
}
24+
25+
const ret = parts[1]
26+
27+
if (ret.indexOf('&&') >= 0) {
28+
return ret.split('&&')[0].trim()
29+
}
30+
31+
return ret.split(' ')[0].trim()
32+
}

src/bin/script-parsers.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { webpackConfig, nodeEnv } from './script-parsers'
2+
3+
describe('webpack config name parser', () => {
4+
it('should parse --config', () => {
5+
assert(
6+
webpackConfig('NODE_ENV=development webpack --config demo.js') === 'demo.js'
7+
)
8+
})
9+
10+
it('should default to webpack.config.js', () => {
11+
assert(
12+
webpackConfig('webpack --profile --json > stats.json') === 'webpack.config.js'
13+
)
14+
})
15+
})
16+
17+
describe('node env parser', () => {
18+
it('should parse SET NODE_ENV', () => {
19+
assert(nodeEnv('SET NODE_ENV=development&& webpack') === 'development')
20+
})
21+
22+
it('should parse NODE_ENV', () => {
23+
assert(nodeEnv('NODE_ENV=development webpack') === 'development')
24+
})
25+
26+
it('should not parse invalid input', () => {
27+
assert(nodeEnv('foobar') === '') // throw error instead?
28+
})
29+
})

src/bin/validate-all-scripts.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const parse = require('./script-parsers')
2+
const validateConfig = require('./validate-config')
3+
4+
module.exports = function validateAllScripts(scripts, quiet) {
5+
Object.keys(scripts).forEach(name => {
6+
const script = scripts[name]
7+
const webpackConfigFile = parse.webpackConfig(script)
8+
9+
if (script.indexOf('SET NODE_ENV=') === 0 || script.indexOf('NODE_ENV=') === 0) {
10+
process.env.node_env = parse.nodeEnv(script)
11+
} else {
12+
process.env.npm_lifecycle_event = name
13+
}
14+
15+
if (!quiet) console.info('\nValidating', name)
16+
const validationResult = validateConfig(webpackConfigFile, quiet)
17+
18+
if (validationResult.error) {
19+
console.info(validationResult.error.annotate())
20+
process.exit(1)
21+
} else {
22+
if (!quiet) console.info(`${name} is valid`)
23+
}
24+
})
25+
}

src/bin/validate-config.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const path = require('path')
2+
const validate = require('../')
3+
4+
module.exports = function validateConfig(webpackConfigFile, quiet) {
5+
if (!quiet) console.log(`Reading: ${webpackConfigFile}`)
6+
const webpackConfigPath = path.join(process.cwd(), webpackConfigFile)
7+
8+
delete require.cache[
9+
require.resolve(webpackConfigPath)
10+
]
11+
12+
const config = require(webpackConfigPath)
13+
return validate(config, validate.schema, {
14+
returnValidation: true,
15+
quiet,
16+
})
17+
}

src/bin/webpack-validator.js

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ const fs = require('fs')
55
const path = require('path')
66
const program = require('commander')
77
const log = require('npmlog')
8-
const validate = require('../')
9-
const schema = require('../').schema
8+
const validateAllScripts = require('./validate-all-scripts')
9+
const validateConfig = require('./validate-config')
1010
let configFile
1111

1212
program
1313
.arguments('<configFileName>')
14+
.option('-a, --all-scripts', 'Validate all configurations from package.json scripts')
1415
.option('-q, --quiet', 'Quiet output')
1516
.action((configFileName) => {
1617
configFile = configFileName
@@ -26,40 +27,40 @@ function errorHandler(err) {
2627
process.exit(1)
2728
}
2829

29-
function validateConfig(webpackConfigFile, quiet) {
30-
if (!quiet) console.log(`Reading: ${webpackConfigFile}`)
31-
const config = require(path.join(process.cwd(), webpackConfigFile))
32-
const validationResult = validate(config, schema, {
33-
returnValidation: true,
34-
quiet,
30+
function validateFile(config, quiet) {
31+
fs.stat(configFile, (err, stats) => {
32+
if (err) {
33+
err.message = `Could not find file "${configFile}"` // eslint-disable-line no-param-reassign
34+
errorHandler(err)
35+
} else {
36+
if (stats.isFile()) {
37+
const validationResult = validateConfig(config, quiet)
38+
39+
if (validationResult.error) {
40+
console.info(validationResult.error.annotate())
41+
process.exit(1)
42+
} else {
43+
if (!quiet) console.info(`${config} is valid`)
44+
process.exit(0)
45+
}
46+
} else {
47+
const error = new Error(`Could not find file "${configFile}"`)
48+
error.type = 'EISDIR'
49+
errorHandler(error)
50+
}
51+
}
3552
})
36-
if (validationResult.error) {
37-
console.info(validationResult.error.annotate())
38-
process.exit(1)
39-
} else {
40-
if (!quiet) console.info(`${webpackConfigFile} is valid`)
41-
process.exit(0)
42-
}
4353
}
4454

45-
if (! configFile) {
55+
if (program.allScripts) {
56+
const pkg = require(path.join(process.cwd(), './package.json'))
57+
58+
validateAllScripts(pkg.scripts, program.quiet)
59+
} else if (!configFile) {
4660
const error = new Error(['No configuration file given',
4761
'Usage: webpack-validator-cli <configFileName>'].join('\n'))
4862
error.type = 'EUSAGE'
4963
errorHandler(error)
64+
} else {
65+
validateFile(configFile, program.quiet)
5066
}
51-
52-
fs.stat(configFile, (err, stats) => {
53-
if (err) {
54-
err.message = `Could not find file "${configFile}"` // eslint-disable-line no-param-reassign
55-
errorHandler(err)
56-
} else {
57-
if (stats.isFile()) {
58-
validateConfig(configFile, program.quiet)
59-
} else {
60-
const error = new Error(`Could not find file "${configFile}"`)
61-
error.type = 'EISDIR'
62-
errorHandler(error)
63-
}
64-
}
65-
})

0 commit comments

Comments
 (0)