diff --git a/index.js b/index.js index 903e88ce..29a2e6ad 100755 --- a/index.js +++ b/index.js @@ -148,6 +148,22 @@ const hasDevDependency = (dependency, packageJson) => { ) } +const runSRegExp = + /(?<=^|[\s&;<>|(])(?:run-s|npm-run-all .*(?:--sequential|--serial|-s))(?=$|[\s&;<>|)])/ + +const isSequentialScript = (command) => + command.includes('*') && runSRegExp.test(command) + +const hasSequentialScript = (packageJson) => { + if (!hasDevDependency('npm-run-all', packageJson)) { + return false + } + const scripts = ['scripts', 'betterScripts'].flatMap((field) => + packageJson[field] ? Object.values(packageJson[field]) : [], + ) + return scripts.some((script) => isSequentialScript(script)) +} + const sortScripts = onObject((scripts, packageJson) => { const names = Object.keys(scripts) const prefixable = new Set() @@ -161,7 +177,7 @@ const sortScripts = onObject((scripts, packageJson) => { return name }) - if (!hasDevDependency('npm-run-all', packageJson)) { + if (!hasSequentialScript(packageJson)) { keys.sort() } diff --git a/tests/scripts.js b/tests/scripts.js index 0e5aa1da..558112c0 100644 --- a/tests/scripts.js +++ b/tests/scripts.js @@ -1,4 +1,5 @@ import test from 'ava' +import sortPackageJson from '../index.js' import { macro } from './_helpers.js' const fixture = { @@ -35,36 +36,76 @@ const expectAllSorted = { watch: 'watch things', } -const expectPreAndPostSorted = { - pretest: 'xyz', - test: 'node test.js', - posttest: 'abc', - multiply: '2 * 3', - prewatch: 'echo "about to watch"', - watch: 'watch things', - preinstall: 'echo "Installing"', - postinstall: 'echo "Installed"', - start: 'node server.js', - preprettier: 'echo "not pretty"', - prettier: 'prettier -l "**/*.js"', - postprettier: 'echo "so pretty"', - prepare: 'npm run build', - 'pre-fetch-info': 'foo', -} - for (const field of ['scripts', 'betterScripts']) { - test(`${field} when npm-run-all is not a dev dependency`, macro.sortObject, { + test(`${field} when npm-run-all is NOT a dev dependency`, macro.sortObject, { value: { [field]: fixture }, expect: { [field]: expectAllSorted }, }) - test(`${field} when npm-run-all is a dev dependency`, macro.sortObject, { - value: { - [field]: fixture, - devDependencies: { 'npm-run-all': '^1.0.0' }, - }, - expect: { - [field]: expectPreAndPostSorted, - devDependencies: { 'npm-run-all': '^1.0.0' }, + + test( + `${field} when npm-run-all IS a dev dependency, but is NOT used in scripts`, + macro.sortObject, + { + value: { + [field]: { z: 'z', a: 'a' }, + devDependencies: { 'npm-run-all': '^1.0.0' }, + }, + expect: { + [field]: { a: 'a', z: 'z' }, + devDependencies: { 'npm-run-all': '^1.0.0' }, + }, }, + ) +} + +// `run-s` command +function sortScriptsWithNpmRunAll(script) { + const packageJson = { + scripts: { z: 'z', a: 'a', maybeRunS: script }, + devDependencies: { 'npm-run-all': '^1.0.0' }, + } + + return Object.keys(sortPackageJson(packageJson).scripts) +} +const sortedScripts = ['a', 'maybeRunS', 'z'] +const unsortedScripts = ['z', 'a', 'maybeRunS'] +for (const { script, expected } of [ + // Should NOT sort + { script: 'run-s "lint:*"', expected: unsortedScripts }, + { script: 'npm-run-all -s "lint:*"', expected: unsortedScripts }, + { script: 'npm-run-all --sequential "lint:*"', expected: unsortedScripts }, + { script: 'npm-run-all --serial "lint:*"', expected: unsortedScripts }, + { script: 'npm-run-all "lint:*" --sequential', expected: unsortedScripts }, + { script: 'foo&&npm-run-all --serial "lint:*"', expected: unsortedScripts }, + { script: 'foo||npm-run-all --serial "lint:*"', expected: unsortedScripts }, + { script: 'foo|npm-run-all --serial "lint:*"', expected: unsortedScripts }, + { script: 'foo>npm-run-all --serial "lint:*"', expected: unsortedScripts }, + { script: 'foofoo', expected: unsortedScripts }, + { script: 'npm-run-all "lint:*" --serial { + t.deepEqual(sortScriptsWithNpmRunAll(script), expected) }) }