diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 00000000000000..0605f83bf90782 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,3 @@ +// Import the default config file and expose it in the project root. +// Useful for editor integrations. +module.exports = require( '@wordpress/scripts/config/.prettierrc.js' ); diff --git a/package-lock.json b/package-lock.json index c71a6f8db2f425..4a32668b6e2bce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7838,6 +7838,7 @@ "command-exists": "^1.2.8", "cross-spawn": "^5.1.0", "decompress-zip": "^0.2.2", + "dir-glob": "^3.0.1", "eslint": "^6.1.0", "jest": "^24.7.1", "jest-puppeteer": "^4.3.0", @@ -7845,6 +7846,7 @@ "lodash": "^4.17.15", "minimist": "^1.2.0", "npm-package-json-lint": "^4.0.2", + "prettier": "npm:wp-prettier@^1.18.2", "puppeteer": "^1.20.0", "read-pkg-up": "^1.0.1", "request": "^2.88.0", @@ -7858,6 +7860,23 @@ "webpack-bundle-analyzer": "^3.3.2", "webpack-cli": "^3.1.2", "webpack-livereload-plugin": "^2.2.0" + }, + "dependencies": { + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + } } }, "@wordpress/server-side-render": { @@ -26665,8 +26684,8 @@ }, "prettier": { "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-1.18.2.tgz", + "integrity": "sha512-OvmJZJ6j6KF+CqnNGPLRupSLt6zlFG8/D9dJL21eVJwad1HHEq5cGgeXqboloxE7DjtglkKd/6CEvO1dvqfQdA==", "dev": true }, "pretty-error": { diff --git a/package.json b/package.json index e1c25716bd94c0..a83b032b13cd31 100644 --- a/package.json +++ b/package.json @@ -172,6 +172,7 @@ "fixtures:server-registered": "wp-scripts env docker-run php ./bin/get-server-blocks.php > test/integration/full-content/server-registered.json", "fixtures:generate": "npm run fixtures:server-registered && cross-env GENERATE_MISSING_FIXTURES=y npm run test-unit", "fixtures:regenerate": "npm run fixtures:clean && npm run fixtures:generate", + "format-js": "wp-scripts format-js", "lint": "concurrently \"npm run lint-js\" \"npm run lint-pkg-json\" \"npm run lint-css\" \"npm run lint-types\"", "lint-js": "wp-scripts lint-js", "lint-js:fix": "npm run lint-js -- --fix", diff --git a/packages/scripts/config/.prettierrc.js b/packages/scripts/config/.prettierrc.js new file mode 100644 index 00000000000000..61b185ac2c203f --- /dev/null +++ b/packages/scripts/config/.prettierrc.js @@ -0,0 +1,12 @@ +module.exports = { + useTabs: true, + tabWidth: 2, + printWidth: 100, + singleQuote: true, + trailingComma: 'es5', + bracketSpacing: true, + parenSpacing: true, + jsxBracketSameLine: false, + semi: true, + arrowParens: 'always', +}; diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 20c95f9782c61d..caa4f61fb7304f 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -44,6 +44,7 @@ "command-exists": "^1.2.8", "cross-spawn": "^5.1.0", "decompress-zip": "^0.2.2", + "dir-glob": "^3.0.1", "eslint": "^6.1.0", "jest": "^24.7.1", "jest-puppeteer": "^4.3.0", @@ -51,6 +52,7 @@ "lodash": "^4.17.15", "minimist": "^1.2.0", "npm-package-json-lint": "^4.0.2", + "prettier": "npm:wp-prettier@^1.18.2", "puppeteer": "^1.20.0", "read-pkg-up": "^1.0.1", "request": "^2.88.0", diff --git a/packages/scripts/scripts/format-js.js b/packages/scripts/scripts/format-js.js new file mode 100644 index 00000000000000..7bd33400bd75ee --- /dev/null +++ b/packages/scripts/scripts/format-js.js @@ -0,0 +1,76 @@ +/** + * External dependencies + */ +const { sync: spawn } = require( 'cross-spawn' ); +const { sync: resolveBin } = require( 'resolve-bin' ); +const { sync: dirGlob } = require( 'dir-glob' ); + +/** + * Internal dependencies + */ +const { + fromConfigRoot, + fromProjectRoot, + getArgFromCLI, + getFileArgsFromCLI, + hasArgInCLI, + hasPackageProp, + hasProjectFile, +} = require( '../utils' ); + +// See: https://prettier.io/docs/en/configuration.html +const hasProjectPrettierConfig = + hasProjectFile( '.prettierrc' ) || + hasProjectFile( '.prettierrc.json' ) || + hasProjectFile( '.prettierrc.yaml' ) || + hasProjectFile( '.prettierrc.yml' ) || + hasProjectFile( '.prettierrc.js' ) || + hasProjectFile( '.prettierrc.config.js' ) || + hasProjectFile( '.prettierrc.toml' ) || + hasPackageProp( 'prettier' ); + +// Get the configuration file, with preference highest to lowers: +// 1. use the `--config` arg from CLI +// 2. use configuration provided by the project +// 3. use the default provided in the scripts module +let configArgs; +const configFromCLI = getArgFromCLI( '--config' ); +if ( configFromCLI ) { + configArgs = [ '--config', configFromCLI ]; +} else if ( hasProjectPrettierConfig ) { + configArgs = []; // no `--config` when project configuration is found: Prettier will find it +} else { + configArgs = [ '--config', fromConfigRoot( '.prettierrc.js' ) ]; +} + +// If `--ignore-path` is not explicitly specified, use the project's or global .eslintignore +let ignorePath = getArgFromCLI( '--ignore-path' ); +if ( ! ignorePath ) { + if ( hasProjectFile( '.eslintignore' ) ) { + ignorePath = fromProjectRoot( '.eslintignore' ); + } else { + ignorePath = fromConfigRoot( '.eslintignore' ); + } +} +const ignoreArgs = [ '--ignore-path', ignorePath ]; + +// forward the --require-pragma option that formats only files that already have the @format +// pragma in the first docblock. +const pragmaArgs = hasArgInCLI( '--require-pragma' ) ? [ '--require-pragma' ] : []; + +// Get the files and directories to format and convert them to globs +let fileArgs = getFileArgsFromCLI(); +if ( fileArgs.length === 0 ) { + fileArgs = [ '.' ]; +} + +// Converts `foo/bar` directory to `foo/bar/**/*.js` +const globArgs = dirGlob( fileArgs, { extensions: [ 'js' ] } ); + +const result = spawn( + resolveBin( 'prettier' ), + [ '--write', ...configArgs, ...ignoreArgs, ...pragmaArgs, ...globArgs ], + { stdio: 'inherit' } +); + +process.exit( result.status );