diff --git a/.circleci/config.yml b/.circleci/config.yml index 8b9ee59849e1..25ac5ff333ce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -62,8 +62,11 @@ jobs: name: '`yarn prettier` changes committed?' command: yarn prettier check-changed - run: - name: Lint - command: yarn lint:ci + name: Eslint + command: yarn eslint:ci + - run: + name: Lint JSON + command: yarn jsonlint workflows: version: 2 pipeline: diff --git a/package.json b/package.json index 59da6daa2234..44f3a2ac2034 100644 --- a/package.json +++ b/package.json @@ -47,14 +47,16 @@ }, "scripts": { "deduplicate": "node scripts/deduplicate.js", + "jsonlint": "node scripts/jsonlint.js", "hoist": "lerna bootstrap --hoist", "bootstrap": "lerna bootstrap", "build": "lerna run build --stream", "start": "lerna run start --parallel", "prettier": "node ./scripts/prettier.js", "test": "lerna run test --parallel", - "lint": "eslint . --cache --report-unused-disable-directives --ext .js,.ts,.tsx", - "lint:ci": "eslint . --report-unused-disable-directives --ext .js,.ts,.tsx" + "lint": "yarn eslint && yarn jsonlint", + "eslint": "eslint . --cache --report-unused-disable-directives --ext .js,.ts,.tsx", + "eslint:ci": "eslint . --report-unused-disable-directives --ext .js,.ts,.tsx" }, "setupFiles": [ "/src/setupTests.js" diff --git a/scripts/jsonlint.js b/scripts/jsonlint.js new file mode 100644 index 000000000000..697059d2d287 --- /dev/null +++ b/scripts/jsonlint.js @@ -0,0 +1,44 @@ +/* eslint-disable no-console */ +const chalk = require('chalk'); +const fse = require('fs-extra'); +const glob = require('glob-gitignore'); +const path = require('path'); + +const passMessage = (message) => `✓ ${chalk.gray(message)}`; +const failMessage = (message) => `✗ ${chalk.whiteBright(message)}`; + +async function run() { + const workspaceRoot = path.resolve(__dirname, '..'); + + const eslintignoreContent = await fse.readFile(path.join(workspaceRoot, '.eslintignore'), { + encoding: 'utf8', + }); + const eslintignore = eslintignoreContent.split(/\r?\n/).slice(0, -1); + + const filenames = glob.sync('**/*.json', { + cwd: workspaceRoot, + ignore: [...eslintignore, 'tsconfig*.json', 'tslint.json'], + }); + + let passed = true; + const checks = filenames.map(async (filename) => { + const content = await fse.readFile(path.join(workspaceRoot, filename), { encoding: 'utf8' }); + try { + JSON.parse(content); + console.log(passMessage(filename)); + } catch (error) { + passed = false; + console.error(failMessage(`Error parsing ${filename}:\n\n${String(error)}`)); + } + }); + + await Promise.all(checks); + if (passed === false) { + throw new Error('At least one file did not pass. Check the console output'); + } +} + +run().catch((error) => { + console.error(error); + process.exit(1); +});