diff --git a/.prettierrc.js b/.prettierrc.js index 2cda2dfc..f209a68c 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -4,4 +4,6 @@ module.exports = Object.assign({}, prettierConfig, { // to prevent additional conflicts with update kcd-scripts, making // backmerging a little easier. printWidth: 80, + semi: false, + bracketSpacing: false, }) diff --git a/README.md b/README.md index 95c12c2d..983d8d40 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ Or, for `babel`, a `.babelrc` with: Or, for `jest`: ```js -const { jest: jestConfig } = require('cod-scripts/config'); +const {jest: jestConfig} = require('cod-scripts/config') module.exports = Object.assign(jestConfig, { // your overrides here @@ -96,7 +96,7 @@ module.exports = Object.assign(jestConfig, { transform: { '\\.(ts|tsx)$': '/node_modules/ts-jest/preprocessor.js', }, -}); +}) ``` Or, for `commitlint`, a `commitlint.config.js` file or `commitlint` prop in @@ -104,14 +104,14 @@ package.json: ```js // commitlint.config.js or .commitlintrc.js -const { commitlint: commitlintConfig } = require('cod-scripts/commitlint'); +const {commitlint: commitlintConfig} = require('cod-scripts/commitlint') module.exports = { ...commitlintConfig, rules: { // overrides here }, -}; +} ``` ```json diff --git a/babel.js b/babel.js index 953754cd..f46b0555 100644 --- a/babel.js +++ b/babel.js @@ -1 +1 @@ -module.exports = require('./dist/config/babelrc'); +module.exports = require('./dist/config/babelrc') diff --git a/commitlint.js b/commitlint.js index 23a4bda0..98e2af42 100644 --- a/commitlint.js +++ b/commitlint.js @@ -1 +1 @@ -module.exports = require('./dist/config/commitlint.config'); +module.exports = require('./dist/config/commitlint.config') diff --git a/config.js b/config.js index 6dc01060..bb07926b 100644 --- a/config.js +++ b/config.js @@ -1 +1 @@ -module.exports = require('./dist/config'); +module.exports = require('./dist/config') diff --git a/eslint.js b/eslint.js index 286e06ab..7cc6ee52 100644 --- a/eslint.js +++ b/eslint.js @@ -1 +1 @@ -module.exports = require('./dist/config/eslintrc'); +module.exports = require('./dist/config/eslintrc') diff --git a/husky.js b/husky.js index 8fa198b2..204c296c 100644 --- a/husky.js +++ b/husky.js @@ -1 +1 @@ -module.exports = require('./dist/config/huskyrc'); +module.exports = require('./dist/config/huskyrc') diff --git a/jest.config.js b/jest.config.js index f6fbc3c1..61f21edc 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,4 +1,4 @@ -const { jest: jestConfig } = require('./src/config'); +const {jest: jestConfig} = require('./src/config') module.exports = Object.assign(jestConfig, { coverageThreshold: null, @@ -6,4 +6,4 @@ module.exports = Object.assign(jestConfig, { ...jestConfig.testPathIgnorePatterns, './src/scripts/test.js', ], -}); +}) diff --git a/jest.js b/jest.js index 70169854..3a1bd4e9 100644 --- a/jest.js +++ b/jest.js @@ -1 +1 @@ -module.exports = require('./dist/config/jest.config'); +module.exports = require('./dist/config/jest.config') diff --git a/package.json b/package.json index 8854f4bc..cbe8d574 100644 --- a/package.json +++ b/package.json @@ -35,23 +35,23 @@ "author": "Chris O'Donnell (http://codfish.io/)", "license": "MIT", "dependencies": { - "@babel/cli": "^7.12.8", - "@babel/core": "^7.12.9", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-transform-modules-commonjs": "^7.12.1", - "@babel/plugin-transform-runtime": "^7.12.1", - "@babel/preset-env": "^7.12.7", - "@babel/preset-react": "^7.12.7", - "@babel/preset-typescript": "^7.12.7", - "@babel/runtime": "^7.12.5", - "@commitlint/cli": "^11.0.0", - "@commitlint/config-conventional": "^11.0.0", - "@rollup/plugin-babel": "^5.2.2", - "@rollup/plugin-commonjs": "^17.0.0", + "@babel/cli": "^7.13.0", + "@babel/core": "^7.13.1", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-transform-modules-commonjs": "^7.13.0", + "@babel/plugin-transform-runtime": "^7.13.7", + "@babel/preset-env": "^7.13.5", + "@babel/preset-react": "^7.12.13", + "@babel/preset-typescript": "^7.13.0", + "@babel/runtime": "^7.13.7", + "@commitlint/cli": "^12.0.0", + "@commitlint/config-conventional": "^12.0.0", + "@rollup/plugin-babel": "^5.3.0", + "@rollup/plugin-commonjs": "^17.1.0", "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^11.0.0", - "@rollup/plugin-replace": "^2.3.4", - "@types/jest": "^26.0.17", + "@rollup/plugin-node-resolve": "^11.2.0", + "@rollup/plugin-replace": "^2.4.1", + "@types/jest": "^26.0.20", "arrify": "^2.0.1", "babel-jest": "^26.6.3", "babel-plugin-macros": "^3.0.0", @@ -59,23 +59,24 @@ "babel-plugin-module-resolver": "^4.0.0", "babel-plugin-transform-inline-environment-variables": "^0.4.3", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", - "browserslist": "^4.14.7", + "browserslist": "^4.16.3", + "builtin-modules": "^3.2.0", "chalk": "^4.1.0", - "concurrently": "^5.3.0", + "concurrently": "^6.0.0", "cosmiconfig": "^7.0.0", "cross-env": "^7.0.3", "cross-spawn": "^7.0.3", "doctoc": "^2.0.0", - "eslint": "^7.15.0", - "eslint-config-codfish": "^8.2.0", - "eslint-config-prettier": "^7.0.0", + "eslint": "^7.20.0", + "eslint-config-codfish": "^8.3.0", + "eslint-config-prettier": "^8.1.0", "glob": "^7.1.5", - "husky": "^4.3.5", - "is-ci": "^2.0.0", + "husky": "^5.1.1", + "is-ci": "^3.0.0", "jest": "^26.6.1", "jest-serializer-path": "^0.1.15", "jest-watch-typeahead": "^0.6.1", - "lint-staged": "^10.5.3", + "lint-staged": "^10.5.4", "lodash.camelcase": "^4.3.0", "lodash.has": "^4.5.2", "lodash.omit": "^4.5.0", @@ -83,16 +84,16 @@ "prettier": "2.2.1", "react-app-polyfill": "^2.0.0", "read-pkg-up": "^7.0.1", - "resolve": "^1.19.0", + "resolve": "^1.20.0", "rimraf": "^3.0.2", - "rollup": "^2.34.2", + "rollup": "^2.39.1", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-globals": "^1.4.0", "rollup-plugin-size-snapshot": "^0.12.0", "rollup-plugin-terser": "^7.0.2", "semver": "^7.3.4", "which": "^2.0.2", - "yargs-parser": "^20.2.4" + "yargs-parser": "^20.2.6" }, "eslintConfig": { "extends": [ @@ -100,6 +101,10 @@ ], "rules": { "no-console": "off", + "semi": "off", + "babel/semi": "off", + "object-curly-spacing": "off", + "babel/object-curly-spacing": "off", "no-process-exit": "off", "global-require": "off", "no-prototype-builtins": "off", diff --git a/prettier.js b/prettier.js index 898d0336..de4ba09d 100644 --- a/prettier.js +++ b/prettier.js @@ -1 +1 @@ -module.exports = require('./dist/config/prettierrc'); +module.exports = require('./dist/config/prettierrc') diff --git a/src/__mocks__/cross-spawn.js b/src/__mocks__/cross-spawn.js index fcad0923..a16265e8 100644 --- a/src/__mocks__/cross-spawn.js +++ b/src/__mocks__/cross-spawn.js @@ -1,3 +1,3 @@ module.exports = { - sync: jest.fn(() => ({ status: 0 })), -}; + sync: jest.fn(() => ({status: 0})), +} diff --git a/src/__tests__/index.js b/src/__tests__/index.js index 43c837ba..83150096 100644 --- a/src/__tests__/index.js +++ b/src/__tests__/index.js @@ -1,58 +1,58 @@ -import path from 'path'; -import slash from 'slash'; -import cases from 'jest-in-case'; -import { unquoteSerializer } from '../scripts/__tests__/helpers/serializers'; +import path from 'path' +import slash from 'slash' +import cases from 'jest-in-case' +import {unquoteSerializer} from '../scripts/__tests__/helpers/serializers' -const projectRoot = path.join(__dirname, '../../'); +const projectRoot = path.join(__dirname, '../../') -expect.addSnapshotSerializer(unquoteSerializer); +expect.addSnapshotSerializer(unquoteSerializer) expect.addSnapshotSerializer({ print: val => slash(val.replace(projectRoot, '/')), test: val => typeof val === 'string' && val.includes(projectRoot), -}); +}) cases( 'format', - ({ snapshotLog = false, throws = false, signal = false, args = [] }) => { + ({snapshotLog = false, throws = false, signal = false, args = []}) => { // beforeEach - const { sync: crossSpawnSyncMock } = require('cross-spawn'); - const originalExit = process.exit; - const originalArgv = process.argv; - const originalLog = console.log; - process.exit = jest.fn(); - console.log = jest.fn(); + const {sync: crossSpawnSyncMock} = require('cross-spawn') + const originalExit = process.exit + const originalArgv = process.argv + const originalLog = console.log + process.exit = jest.fn() + console.log = jest.fn() try { // tests - process.argv = ['node', '../', ...args]; - crossSpawnSyncMock.mockClear(); + process.argv = ['node', '../', ...args] + crossSpawnSyncMock.mockClear() if (signal) { - crossSpawnSyncMock.mockReturnValueOnce({ result: 1, signal }); + crossSpawnSyncMock.mockReturnValueOnce({result: 1, signal}) } - require('..'); + require('..') if (snapshotLog) { - expect(console.log.mock.calls).toMatchSnapshot(); + expect(console.log.mock.calls).toMatchSnapshot() } else if (signal) { - expect(process.exit).toHaveBeenCalledTimes(1); - expect(process.exit).toHaveBeenCalledWith(1); - expect(console.log.mock.calls).toMatchSnapshot(); + expect(process.exit).toHaveBeenCalledTimes(1) + expect(process.exit).toHaveBeenCalledWith(1) + expect(console.log.mock.calls).toMatchSnapshot() } else { - expect(crossSpawnSyncMock).toHaveBeenCalledTimes(1); - const [firstCall] = crossSpawnSyncMock.mock.calls; - const [script, calledArgs] = firstCall; - expect([script, ...calledArgs].join(' ')).toMatchSnapshot(); + expect(crossSpawnSyncMock).toHaveBeenCalledTimes(1) + const [firstCall] = crossSpawnSyncMock.mock.calls + const [script, calledArgs] = firstCall + expect([script, ...calledArgs].join(' ')).toMatchSnapshot() } } catch (error) { if (throws) { - expect(error.message).toMatchSnapshot(); + expect(error.message).toMatchSnapshot() } else { - throw error; + throw error } } finally { // afterEach - process.exit = originalExit; - process.argv = originalArgv; - console.log = originalLog; - jest.resetModules(); + process.exit = originalExit + process.argv = originalArgv + console.log = originalLog + jest.resetModules() } }, { @@ -82,6 +82,6 @@ cases( signal: 'SIGBREAK', }, }, -); +) /* eslint complexity:0 */ diff --git a/src/__tests__/utils.js b/src/__tests__/utils.js index 1bed4d4f..ade59b09 100644 --- a/src/__tests__/utils.js +++ b/src/__tests__/utils.js @@ -1,91 +1,81 @@ jest.mock('read-pkg-up', () => ({ - sync: jest.fn(() => ({ packageJson: {}, path: '/blah/package.json' })), -})); -jest.mock('which', () => ({ sync: jest.fn(() => {}) })); + sync: jest.fn(() => ({packageJson: {}, path: '/blah/package.json'})), +})) +jest.mock('which', () => ({sync: jest.fn(() => {})})) jest.mock('cosmiconfig', () => { - const cosmiconfigExports = jest.requireActual('cosmiconfig'); - return { ...cosmiconfigExports, cosmiconfigSync: jest.fn() }; -}); + const cosmiconfigExports = jest.requireActual('cosmiconfig') + return {...cosmiconfigExports, cosmiconfigSync: jest.fn()} +}) -let whichSyncMock; -let readPkgUpSyncMock; - -function mockPkg({ package: pkg = {}, path = '/blah/package.json' }) { - readPkgUpSyncMock.mockImplementationOnce(() => ({ packageJson: pkg, path })); -} - -function mockCosmiconfig(result = null) { - const { cosmiconfigSync } = require('cosmiconfig'); - - cosmiconfigSync.mockImplementationOnce(() => ({ search: () => result })); -} +let whichSyncMock +let readPkgUpSyncMock beforeEach(() => { - jest.resetModules(); - whichSyncMock = require('which').sync; - readPkgUpSyncMock = require('read-pkg-up').sync; -}); + jest.resetModules() + whichSyncMock = require('which').sync + readPkgUpSyncMock = require('read-pkg-up').sync +}) test('package is the package.json', () => { - const myPkg = { name: 'blah' }; - mockPkg({ package: myPkg }); - expect(require('../utils').pkg).toBe(myPkg); -}); + const myPkg = {name: 'blah'} + mockPkg({package: myPkg}) + expect(require('../utils').pkg).toBe(myPkg) +}) test('appDirectory is the dirname to the package.json', () => { - const pkgPath = '/some/path/to'; - mockPkg({ path: `${pkgPath}/package.json` }); - expect(require('../utils').appDirectory).toBe(pkgPath); -}); + const pkgPath = '/some/path/to' + mockPkg({path: `${pkgPath}/package.json`}) + expect(require('../utils').appDirectory).toBe(pkgPath) +}) test('resolveCodScripts resolves to src/index.js when in the cod-scripts package', () => { - mockPkg({ package: { name: 'cod-scripts' } }); + mockPkg({package: {name: 'cod-scripts'}}) expect(require('../utils').resolveCodScripts()).toBe( require.resolve('../').replace(process.cwd(), '.'), - ); -}); + ) +}) test('resolveCodScripts resolves to cod-scripts if not in the cod-scripts package', () => { - mockPkg({ package: { name: 'not-cod-scripts' } }); - whichSyncMock.mockImplementationOnce(() => require.resolve('../')); - expect(require('../utils').resolveCodScripts()).toBe('cod-scripts'); -}); + mockPkg({package: {name: 'not-cod-scripts'}}) + whichSyncMock.mockImplementationOnce(() => require.resolve('../')) + expect(require('../utils').resolveCodScripts()).toBe('cod-scripts') +}) test(`resolveBin resolves to the full path when it's not in $PATH`, () => { expect(require('../utils').resolveBin('cross-env')).toBe( require.resolve('cross-env/src/bin/cross-env').replace(process.cwd(), '.'), - ); -}); + ) +}) test(`resolveBin resolves to the binary if it's in $PATH`, () => { whichSyncMock.mockImplementationOnce(() => require.resolve('cross-env/src/bin/cross-env').replace(process.cwd(), '.'), - ); - expect(require('../utils').resolveBin('cross-env')).toBe('cross-env'); - expect(whichSyncMock).toHaveBeenCalledTimes(1); - expect(whichSyncMock).toHaveBeenCalledWith('cross-env'); -}); + ) + expect(require('../utils').resolveBin('cross-env')).toBe('cross-env') + expect(whichSyncMock).toHaveBeenCalledTimes(1) + expect(whichSyncMock).toHaveBeenCalledWith('cross-env') +}) describe('for windows', () => { - let realpathSync; + let realpathSync beforeEach(() => { - jest.doMock('fs', () => ({ realpathSync: jest.fn() })); + jest.doMock('fs', () => ({realpathSync: jest.fn()})) realpathSync = require('fs').realpathSync; // eslint-disable-line - }); + }) afterEach(() => { - jest.unmock('fs'); - }); + jest.unmock('fs') + }) test('resolveBin resolves to .bin path when which returns a windows-style cmd', () => { - const fullBinPath = '\\project\\node_modules\\.bin\\concurrently.CMD'; - realpathSync.mockImplementation(() => fullBinPath); - expect(require('../utils').resolveBin('concurrently')).toBe(fullBinPath); - expect(realpathSync).toHaveBeenCalledTimes(2); - }); -}); + const fullBinPath = '\\project\\node_modules\\.bin\\concurrently.CMD' + realpathSync.mockImplementation(() => fullBinPath) + expect(require('../utils').resolveBin('concurrently')).toBe(fullBinPath) + expect(realpathSync).toHaveBeenCalledTimes(2) + }) +}) test('getConcurrentlyArgs gives good args to pass to concurrently', () => { expect( @@ -105,69 +95,90 @@ test('getConcurrentlyArgs gives good args to pass to concurrently', () => { i: 'echo i', j: 'echo j', }), - ).toMatchSnapshot(); -}); + ).toMatchSnapshot() +}) test('parseEnv parses the existing environment variable', () => { - const globals = { react: 'React', 'prop-types': 'PropTypes' }; - process.env.BUILD_GLOBALS = JSON.stringify(globals); - expect(require('../utils').parseEnv('BUILD_GLOBALS')).toEqual(globals); - delete process.env.BUILD_GLOBALS; -}); + const globals = {react: 'React', 'prop-types': 'PropTypes'} + process.env.BUILD_GLOBALS = JSON.stringify(globals) + expect(require('../utils').parseEnv('BUILD_GLOBALS')).toEqual(globals) + delete process.env.BUILD_GLOBALS +}) test(`parseEnv returns the default if the environment variable doesn't exist`, () => { - const defaultVal = { hello: 'world' }; + const defaultVal = {hello: 'world'} expect(require('../utils').parseEnv('DOES_NOT_EXIST', defaultVal)).toBe( defaultVal, - ); -}); + ) +}) test('ifAnyDep returns the true argument if true and false argument if false', () => { - mockPkg({ package: { peerDependencies: { react: '*' } } }); - const t = { a: 'b' }; - const f = { c: 'd' }; - expect(require('../utils').ifAnyDep('react', t, f)).toBe(t); - expect(require('../utils').ifAnyDep('preact', t, f)).toBe(f); -}); + mockPkg({package: {peerDependencies: {react: '*'}}}) + const t = {a: 'b'} + const f = {c: 'd'} + expect(require('../utils').ifAnyDep('react', t, f)).toBe(t) + expect(require('../utils').ifAnyDep('preact', t, f)).toBe(f) +}) test('ifAnyDep works with arrays of dependencies', () => { - mockPkg({ package: { peerDependencies: { react: '*' } } }); - const t = { a: 'b' }; - const f = { c: 'd' }; - expect(require('../utils').ifAnyDep(['preact', 'react'], t, f)).toBe(t); - expect(require('../utils').ifAnyDep(['preact', 'webpack'], t, f)).toBe(f); -}); + mockPkg({package: {peerDependencies: {react: '*'}}}) + const t = {a: 'b'} + const f = {c: 'd'} + expect(require('../utils').ifAnyDep(['preact', 'react'], t, f)).toBe(t) + expect(require('../utils').ifAnyDep(['preact', 'webpack'], t, f)).toBe(f) +}) test('ifScript returns the true argument if true and the false argument if false', () => { - mockPkg({ package: { scripts: { build: 'echo build' } } }); - const t = { e: 'f' }; - const f = { g: 'h' }; - expect(require('../utils').ifScript('build', t, f)).toBe(t); - expect(require('../utils').ifScript('lint', t, f)).toBe(f); -}); + mockPkg({package: {scripts: {build: 'echo build'}}}) + const t = {e: 'f'} + const f = {g: 'h'} + expect(require('../utils').ifScript('build', t, f)).toBe(t) + expect(require('../utils').ifScript('lint', t, f)).toBe(f) +}) test('ifFile returns the true argument if true and the false argument if false', () => { - mockPkg({ path: require.resolve('../../package.json') }); - const t = { e: 'f' }; - const f = { g: 'h' }; - expect(require('../utils').ifFile('package.json', t, f)).toBe(t); - expect(require('../utils').ifFile('does-not-exist.blah', t, f)).toBe(f); -}); + mockPkg({path: require.resolve('../../package.json')}) + const t = {e: 'f'} + const f = {g: 'h'} + expect(require('../utils').ifFile('package.json', t, f)).toBe(t) + expect(require('../utils').ifFile('does-not-exist.blah', t, f)).toBe(f) +}) test('hasLocalConfiguration returns false if no local configuration found', () => { - mockCosmiconfig(); + mockCosmiconfig() - expect(require('../utils').hasLocalConfig('module')).toBe(false); -}); + expect(require('../utils').hasLocalConfig('module')).toBe(false) +}) test('hasLocalConfig returns true if a local configuration found', () => { - mockCosmiconfig({ config: {}, filepath: 'path/to/config' }); + mockCosmiconfig({config: {}, filepath: 'path/to/config'}) - expect(require('../utils').hasLocalConfig('module')).toBe(true); -}); + expect(require('../utils').hasLocalConfig('module')).toBe(true) +}) test('hasLocalConfiguration returns true if a local config found and it is empty', () => { - mockCosmiconfig({ isEmpty: true }); + mockCosmiconfig({isEmpty: true}) + + expect(require('../utils').hasLocalConfig('module')).toBe(true) +}) - expect(require('../utils').hasLocalConfig('module')).toBe(true); -}); +test('should generate typescript definitions into provided folder', () => { + whichSyncMock.mockImplementationOnce(() => require.resolve('../')) + const {sync: crossSpawnSyncMock} = require('cross-spawn') + require('../utils').generateTypeDefs('destination folder') + expect(crossSpawnSyncMock).toHaveBeenCalledTimes(1) + const args = crossSpawnSyncMock.mock.calls[0][1] + const outDirIndex = args.findIndex(arg => arg === '--outDir') + 1 + + expect(args[outDirIndex]).toBe('destination folder') +}) + +function mockPkg({package: pkg = {}, path = '/blah/package.json'}) { + readPkgUpSyncMock.mockImplementationOnce(() => ({packageJson: pkg, path})) +} + +function mockCosmiconfig(result = null) { + const {cosmiconfigSync} = require('cosmiconfig') + + cosmiconfigSync.mockImplementationOnce(() => ({search: () => result})) +} diff --git a/src/config/__tests__/umbrella.js b/src/config/__tests__/umbrella.js index 1edb1d54..51af51e9 100644 --- a/src/config/__tests__/umbrella.js +++ b/src/config/__tests__/umbrella.js @@ -1,11 +1,11 @@ test('requiring some files does not blow up', () => { - require('../babel-transform'); - require('../babelrc'); - require('../commitlint.config'); - require('../eslintrc'); - require('../jest.config'); - require('../lintstagedrc'); - require('../prettierrc'); - require('../rollup.config'); - require('..').getRollupConfig(); -}); + require('../babel-transform') + require('../babelrc') + require('../commitlint.config') + require('../eslintrc') + require('../jest.config') + require('../lintstagedrc') + require('../prettierrc') + require('../rollup.config') + require('..').getRollupConfig() +}) diff --git a/src/config/babel-transform.js b/src/config/babel-transform.js index f0f1f482..cbda1e7a 100644 --- a/src/config/babel-transform.js +++ b/src/config/babel-transform.js @@ -1,5 +1,5 @@ -const babelJest = require('babel-jest'); +const babelJest = require('babel-jest') module.exports = babelJest.createTransformer({ presets: [require.resolve('./babelrc')], -}); +}) diff --git a/src/config/babelrc.js b/src/config/babelrc.js index dc4c871d..f382e372 100644 --- a/src/config/babelrc.js +++ b/src/config/babelrc.js @@ -1,5 +1,5 @@ -const browserslist = require('browserslist'); -const semver = require('semver'); +const browserslist = require('browserslist') +const semver = require('semver') const { ifDep, @@ -8,43 +8,44 @@ const { parseEnv, appDirectory, pkg, -} = require('../utils'); +} = require('../utils') -const { BABEL_ENV, NODE_ENV, BUILD_FORMAT } = process.env; -const isTest = (BABEL_ENV || NODE_ENV) === 'test'; -const isPreact = parseEnv('BUILD_PREACT', false); -const isRollup = parseEnv('BUILD_ROLLUP', false); -const isUMD = BUILD_FORMAT === 'umd'; -const isCJS = BUILD_FORMAT === 'cjs'; -const isWebpack = parseEnv('BUILD_WEBPACK', false); -const treeshake = parseEnv('BUILD_TREESHAKE', isRollup || isWebpack); -const alias = parseEnv('BUILD_ALIAS', isPreact ? { react: 'preact' } : null); +const {BABEL_ENV, NODE_ENV, BUILD_FORMAT} = process.env +const isTest = (BABEL_ENV || NODE_ENV) === 'test' +const isPreact = parseEnv('BUILD_PREACT', false) +const isRollup = parseEnv('BUILD_ROLLUP', false) +const isUMD = BUILD_FORMAT === 'umd' +const isCJS = BUILD_FORMAT === 'cjs' +const isWebpack = parseEnv('BUILD_WEBPACK', false) +const isMinify = parseEnv('BUILD_MINIFY', false) +const treeshake = parseEnv('BUILD_TREESHAKE', isRollup || isWebpack) +const alias = parseEnv('BUILD_ALIAS', isPreact ? {react: 'preact'} : null) const hasBabelRuntimeDep = Boolean( pkg.dependencies && pkg.dependencies['@babel/runtime'], -); +) const RUNTIME_HELPERS_WARN = - 'You should add @babel/runtime as dependency to your package. It will allow reusing "babel helpers" from node_modules rather than bundling their copies into your files.'; + 'You should add @babel/runtime as dependency to your package. It will allow reusing "babel helpers" from node_modules rather than bundling their copies into your files.' if (!treeshake && !hasBabelRuntimeDep && !isTest) { - throw new Error(RUNTIME_HELPERS_WARN); + throw new Error(RUNTIME_HELPERS_WARN) } else if (treeshake && !isUMD && !hasBabelRuntimeDep) { - console.warn(RUNTIME_HELPERS_WARN); + console.warn(RUNTIME_HELPERS_WARN) } -function getNodeVersion({ engines: { node: nodeVersion = '10.13' } = {} }) { +function getNodeVersion({engines: {node: nodeVersion = '10.13'} = {}}) { const oldestVersion = semver .validRange(nodeVersion) .replace(/[>=<|]/g, ' ') .split(' ') .filter(Boolean) - .sort(semver.compare)[0]; + .sort(semver.compare)[0] if (!oldestVersion) { throw new Error( `Unable to determine the oldest version in the range in your package.json at engines.node: "${nodeVersion}". Please attempt to make it less ambiguous.`, - ); + ) } - return oldestVersion; + return oldestVersion } /** @@ -53,17 +54,17 @@ function getNodeVersion({ engines: { node: nodeVersion = '10.13' } = {} }) { * * @see https://github.com/browserslist/browserslist/blob/master/node.js#L139 */ -const browsersConfig = browserslist.loadConfig({ path: appDirectory }) || [ +const browsersConfig = browserslist.loadConfig({path: appDirectory}) || [ 'ie 10', 'ios 7', -]; +] const envTargets = isTest - ? { node: 'current' } + ? {node: 'current'} : isWebpack || isRollup - ? { browsers: browsersConfig } - : { node: getNodeVersion(pkg) }; -const envOptions = { modules: false, loose: true, targets: envTargets }; + ? {browsers: browsersConfig} + : {node: getNodeVersion(pkg)} +const envOptions = {modules: false, loose: true, targets: envTargets} module.exports = () => ({ presets: [ @@ -72,7 +73,7 @@ module.exports = () => ({ ['react', 'preact'], [ require.resolve('@babel/preset-react'), - { pragma: isPreact ? ifDep('react', 'React.h', 'h') : undefined }, + {pragma: isPreact ? ifDep('react', 'React.h', 'h') : undefined}, ], ), ifTypescript([require.resolve('@babel/preset-typescript')]), @@ -80,29 +81,31 @@ module.exports = () => ({ plugins: [ [ require.resolve('@babel/plugin-transform-runtime'), - { useESModules: treeshake && !isCJS }, + {useESModules: treeshake && !isCJS}, ], require.resolve('babel-plugin-macros'), alias ? [ require.resolve('babel-plugin-module-resolver'), - { root: ['./src'], alias }, + {root: ['./src'], alias}, ] : null, - [ - require.resolve('babel-plugin-transform-react-remove-prop-types'), - isPreact ? { removeImport: true } : { mode: 'unsafe-wrap' }, - ], + ifAnyDep( + ['react', 'preact'], + [ + require.resolve('babel-plugin-transform-react-remove-prop-types'), + isPreact ? {removeImport: true} : {mode: 'unsafe-wrap'}, + ], + ), isUMD ? require.resolve('babel-plugin-transform-inline-environment-variables') : null, - [ - require.resolve('@babel/plugin-proposal-class-properties'), - { loose: true }, - ], - require.resolve('babel-plugin-minify-dead-code-elimination'), + [require.resolve('@babel/plugin-proposal-class-properties'), {loose: true}], + isMinify + ? require.resolve('babel-plugin-minify-dead-code-elimination') + : null, treeshake ? null : require.resolve('@babel/plugin-transform-modules-commonjs'), ].filter(Boolean), -}); +}) diff --git a/src/config/commitlint.config.js b/src/config/commitlint.config.js index 418698da..6768bc91 100644 --- a/src/config/commitlint.config.js +++ b/src/config/commitlint.config.js @@ -2,4 +2,4 @@ module.exports = { // https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional#type-enum extends: ['@commitlint/config-conventional'], -}; +} diff --git a/src/config/eslintrc.js b/src/config/eslintrc.js index 6ac90da4..df0a23b6 100644 --- a/src/config/eslintrc.js +++ b/src/config/eslintrc.js @@ -1,11 +1,11 @@ -const prettierConfig = require('./prettierrc'); -const { hasLocalConfig } = require('../utils'); +const prettierConfig = require('./prettierrc') +const {hasLocalConfig} = require('../utils') -const args = process.argv.slice(2); +const args = process.argv.slice(2) const useBuiltinConfig = - !args.includes('--config') && !hasLocalConfig('prettier'); -const ruleValue = useBuiltinConfig ? ['error', prettierConfig] : 'error'; + !args.includes('--config') && !hasLocalConfig('prettier') +const ruleValue = useBuiltinConfig ? ['error', prettierConfig] : 'error' module.exports = { extends: [require.resolve('eslint-config-codfish')].filter(Boolean), @@ -14,4 +14,4 @@ module.exports = { // local prettier config is found. 'prettier/prettier': ruleValue, }, -}; +} diff --git a/src/config/huskyrc.js b/src/config/huskyrc.js index 0afde656..b74b6480 100644 --- a/src/config/huskyrc.js +++ b/src/config/huskyrc.js @@ -1,10 +1,10 @@ -const { resolveCodScripts } = require('../utils'); +const {resolveCodScripts} = require('../utils') -const codScripts = resolveCodScripts(); +const codScripts = resolveCodScripts() module.exports = { hooks: { 'pre-commit': `"${codScripts}" pre-commit`, 'commit-msg': `"${codScripts}" commitlint -E HUSKY_GIT_PARAMS`, }, -}; +} diff --git a/src/config/index.js b/src/config/index.js index 5ae6f9c5..a616a205 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -7,4 +7,4 @@ module.exports = { lintStaged: require('./lintstagedrc'), prettier: require('./prettierrc'), getRollupConfig: () => require('./rollup.config'), -}; +} diff --git a/src/config/jest.config.js b/src/config/jest.config.js index ae13d5b2..8e979623 100644 --- a/src/config/jest.config.js +++ b/src/config/jest.config.js @@ -1,10 +1,10 @@ -const path = require('path'); -const { ifAnyDep, hasFile, ifFile, hasPkgProp, fromRoot } = require('../utils'); +const path = require('path') +const {ifAnyDep, hasFile, ifFile, hasPkgProp, fromRoot} = require('../utils') -const here = p => path.join(__dirname, p); +const here = p => path.join(__dirname, p) const useBuiltInBabelConfig = - !hasFile('.babelrc') && !hasFile('.babelrc.js') && !hasPkgProp('babel'); + !hasFile('.babelrc') && !hasFile('.babelrc.js') && !hasPkgProp('babel') const ignores = [ '/node_modules/', @@ -13,7 +13,7 @@ const ignores = [ '/__tests__/helpers/', '/__tests__/utils/', '__mocks__', -]; +] const jestConfig = { roots: [fromRoot(hasFile('src') ? 'src' : '')], @@ -46,7 +46,7 @@ const jestConfig = { require.resolve('jest-watch-typeahead/filename'), require.resolve('jest-watch-typeahead/testname'), ], -}; +} const setupFilesAfterEnv = [ ifAnyDep( @@ -59,20 +59,20 @@ const setupFilesAfterEnv = [ ifFile('tests/setup-env.js', fromRoot('tests/setup-env.js')), ifFile('tests/setup-env.ts', fromRoot('tests/setup-env.ts')), ifFile('tests/setup-env.tsx', fromRoot('tests/setup-env.tsx')), -].filter(Boolean); +].filter(Boolean) if (setupFilesAfterEnv.length) { - jestConfig.setupFilesAfterEnv = setupFilesAfterEnv; + jestConfig.setupFilesAfterEnv = setupFilesAfterEnv } if (useBuiltInBabelConfig) { jestConfig.transform = { '^.+\\.(js|jsx|ts|tsx)$': here('./babel-transform'), - }; + } } if (jestConfig.testEnvironment === 'jsdom') { - jestConfig.setupFiles = [require.resolve('react-app-polyfill/jsdom')]; + jestConfig.setupFiles = [require.resolve('react-app-polyfill/jsdom')] } -module.exports = jestConfig; +module.exports = jestConfig diff --git a/src/config/lintstagedrc.js b/src/config/lintstagedrc.js index 1245b6e8..097ac432 100644 --- a/src/config/lintstagedrc.js +++ b/src/config/lintstagedrc.js @@ -1,7 +1,7 @@ -const { resolveCodScripts, resolveBin } = require('../utils'); +const {resolveCodScripts, resolveBin} = require('../utils') -const codScripts = resolveCodScripts(); -const doctoc = resolveBin('doctoc'); +const codScripts = resolveCodScripts() +const doctoc = resolveBin('doctoc') // differs from kcd because of my eslint setup. Want to format everything other // than js first, then format + lint js using eslint with prettier plugin @@ -14,4 +14,4 @@ module.exports = { `${codScripts} lint --fix`, `${codScripts} test --findRelatedTests`, ].filter(Boolean), -}; +} diff --git a/src/config/prettierrc.js b/src/config/prettierrc.js index b1bb8359..2dff51a0 100644 --- a/src/config/prettierrc.js +++ b/src/config/prettierrc.js @@ -17,4 +17,4 @@ module.exports = { jsxBracketSameLine: false, proseWrap: 'always', vueIndentScriptAndStyle: false, -}; +} diff --git a/src/config/rollup.config.js b/src/config/rollup.config.js index 6e8aec8f..dfdf5092 100644 --- a/src/config/rollup.config.js +++ b/src/config/rollup.config.js @@ -1,20 +1,19 @@ -const path = require('path'); -const { babel: rollupBabel } = require('@rollup/plugin-babel'); -const commonjs = require('@rollup/plugin-commonjs'); -const json = require('@rollup/plugin-json'); +const path = require('path') +const builtInModules = require('builtin-modules') +const {babel: rollupBabel} = require('@rollup/plugin-babel') +const commonjs = require('@rollup/plugin-commonjs') +const json = require('@rollup/plugin-json') const { DEFAULTS: nodeResolveDefaults, nodeResolve, -} = require('@rollup/plugin-node-resolve'); - -const replace = require('@rollup/plugin-replace'); -const glob = require('glob'); -const camelcase = require('lodash.camelcase'); -const { terser } = require('rollup-plugin-terser'); -const nodeBuiltIns = require('rollup-plugin-node-builtins'); -const nodeGlobals = require('rollup-plugin-node-globals'); -const { sizeSnapshot } = require('rollup-plugin-size-snapshot'); -const omit = require('lodash.omit'); +} = require('@rollup/plugin-node-resolve') +const replace = require('@rollup/plugin-replace') +const camelcase = require('lodash.camelcase') +const {terser} = require('rollup-plugin-terser') +const nodeBuiltIns = require('rollup-plugin-node-builtins') +const nodeGlobals = require('rollup-plugin-node-globals') +const {sizeSnapshot} = require('rollup-plugin-size-snapshot') +const omit = require('lodash.omit') const { pkg, hasFile, @@ -22,137 +21,120 @@ const { hasDep, hasTypescript, parseEnv, - fromRoot, + getRollupInputs, + getRollupOutput, uniq, writeExtraEntry, -} = require('../utils'); +} = require('../utils') -const here = p => path.join(__dirname, p); -const capitalize = s => s[0].toUpperCase() + s.slice(1); +const here = p => path.join(__dirname, p) +const capitalize = s => s[0].toUpperCase() + s.slice(1) -const minify = parseEnv('BUILD_MINIFY', false); -const format = process.env.BUILD_FORMAT; -const isPreact = parseEnv('BUILD_PREACT', false); -const isNode = parseEnv('BUILD_NODE', false); -const name = process.env.BUILD_NAME || capitalize(camelcase(pkg.name)); -const useSizeSnapshot = parseEnv('BUILD_SIZE_SNAPSHOT', false); +const minify = parseEnv('BUILD_MINIFY', false) +const format = process.env.BUILD_FORMAT +const isPreact = parseEnv('BUILD_PREACT', false) +const isNode = parseEnv('BUILD_NODE', false) +const name = process.env.BUILD_NAME || capitalize(camelcase(pkg.name)) +const useSizeSnapshot = parseEnv('BUILD_SIZE_SNAPSHOT', false) -const esm = format === 'esm'; -const umd = format === 'umd'; +const esm = format === 'esm' +const umd = format === 'umd' const defaultGlobals = Object.keys(pkg.peerDependencies || {}).reduce( (deps, dep) => { // eslint-disable-next-line no-param-reassign - deps[dep] = capitalize(camelcase(dep)); - return deps; + deps[dep] = capitalize(camelcase(dep)) + return deps }, {}, -); +) -const deps = Object.keys(pkg.dependencies || {}); -const peerDeps = Object.keys(pkg.peerDependencies || {}); -const defaultExternal = umd ? peerDeps : deps.concat(peerDeps); +const deps = Object.keys(pkg.dependencies || {}) +const peerDeps = Object.keys(pkg.peerDependencies || {}) +const defaultExternal = builtInModules.concat( + umd ? peerDeps : deps.concat(peerDeps), +) -const input = glob.sync( - fromRoot( - process.env.BUILD_INPUT || - (hasTypescript ? 'src/index.{js,ts,tsx}' : 'src/index.js'), - ), -); -const codeSplitting = input.length > 1; - -if ( - codeSplitting && - uniq(input.map(single => path.basename(single))).length !== input.length -) { - throw new Error( - 'Filenames of code-splitted entries should be unique to get deterministic output filenames.' + - `\nReceived those: ${input}.`, - ); -} - -const filenameSuffix = process.env.BUILD_FILENAME_SUFFIX || ''; -const filenamePrefix = - process.env.BUILD_FILENAME_PREFIX || (isPreact ? 'preact/' : ''); const globals = parseEnv( 'BUILD_GLOBALS', - isPreact - ? Object.assign(defaultGlobals, { preact: 'preact' }) - : defaultGlobals, -); + isPreact ? Object.assign(defaultGlobals, {preact: 'preact'}) : defaultGlobals, +) const external = parseEnv( 'BUILD_EXTERNAL', isPreact ? defaultExternal.concat(['preact', 'prop-types']) : defaultExternal, -).filter((e, i, arry) => arry.indexOf(e) === i); +).filter((e, i, arry) => arry.indexOf(e) === i) if (isPreact) { - delete globals.react; - delete globals['prop-types']; // TODO: is this necessary? - external.splice(external.indexOf('react'), 1); + delete globals.react + delete globals['prop-types'] // TODO: is this necessary? + external.splice(external.indexOf('react'), 1) } -const externalPattern = new RegExp(`^(${external.join('|')})($|/)`); +const externalPattern = new RegExp(`^(${external.join('|')})($|/)`) function externalPredicate(id) { - const isDep = external.length > 0 && externalPattern.test(id); + const isDep = external.length > 0 && externalPattern.test(id) if (umd) { // for UMD, we want to bundle all non-peer deps - return isDep; + return isDep } // for esm/cjs we want to make all node_modules external // TODO: support bundledDependencies if someone needs it ever... - const isNodeModule = id.includes('node_modules'); - const isRelative = id.startsWith('.'); - return isDep || (!isRelative && !path.isAbsolute(id)) || isNodeModule; + const isNodeModule = id.includes('node_modules') + const isRelative = id.startsWith('.') + return isDep || (!isRelative && !path.isAbsolute(id)) || isNodeModule } -const filename = [ - pkg.name, - filenameSuffix, - `.${format}`, - minify ? '.min' : null, - '.js', -] - .filter(Boolean) - .join(''); - -const dirpath = path.join(...[filenamePrefix, 'dist'].filter(Boolean)); - -const output = [ - { - name, - ...(codeSplitting - ? { dir: path.join(dirpath, format) } - : { file: path.join(dirpath, filename) }), - format: esm ? 'es' : format, - exports: esm ? 'named' : 'auto', - globals, - }, -]; - const useBuiltinConfig = !hasFile('.babelrc') && !hasFile('.babelrc.js') && !hasFile('babel.config.js') && - !hasPkgProp('babel'); -const babelPresets = useBuiltinConfig ? [here('../config/babelrc.js')] : []; + !hasPkgProp('babel') +const babelPresets = useBuiltinConfig ? [here('../config/babelrc.js')] : [] const replacements = Object.entries( umd ? process.env : omit(process.env, ['NODE_ENV']), ).reduce((acc, [key, value]) => { - let val; + let val if (value === 'true' || value === 'false' || Number.isInteger(+value)) { - val = value; + val = value } else { - val = JSON.stringify(value); + val = JSON.stringify(value) } - acc[`process.env.${key}`] = val; - return acc; -}, {}); + acc[`process.env.${key}`] = val + return acc +}, {}) const extensions = hasTypescript ? [...nodeResolveDefaults.extensions, '.ts', '.tsx'] - : nodeResolveDefaults.extensions; + : nodeResolveDefaults.extensions + +const input = getRollupInputs() +const codeSplitting = input.length > 1 + +if ( + codeSplitting && + uniq(input.map(single => path.basename(single))).length !== input.length +) { + throw new Error( + 'Filenames of code-splitted entries should be unique to get deterministic output filenames.' + + `\nReceived those: ${input}.`, + ) +} + +const {dirpath, filename} = getRollupOutput() + +const output = [ + { + name, + ...(codeSplitting + ? {dir: path.join(dirpath, format)} + : {file: path.join(dirpath, filename)}), + format: esm ? 'es' : format, + exports: esm ? 'named' : 'auto', + globals, + }, +] module.exports = { input: codeSplitting ? input : input[0], @@ -166,7 +148,7 @@ module.exports = { mainFields: ['module', 'main', 'jsnext', 'browser'], extensions, }), - commonjs({ include: 'node_modules/**' }), + commonjs({include: 'node_modules/**'}), json(), rollupBabel({ presets: babelPresets, @@ -175,27 +157,27 @@ module.exports = { extensions, }), replace(replacements), - useSizeSnapshot ? sizeSnapshot({ printInfo: false }) : null, + useSizeSnapshot ? sizeSnapshot({printInfo: false}) : null, minify ? terser() : null, codeSplitting && ((writes = 0) => ({ onwrite() { // eslint-disable-next-line if (++writes !== input.length) { - return; + return } input .filter(single => single.indexOf('index.js') === -1) .forEach(single => { - const chunk = path.basename(single); + const chunk = path.basename(single) writeExtraEntry(chunk.replace(/\..+$/, ''), { cjs: `${dirpath}/cjs/${chunk}`, esm: `${dirpath}/esm/${chunk}`, - }); - }); + }) + }) }, }))(), ].filter(Boolean), -}; +} diff --git a/src/index.js b/src/index.js index 5a8ba7f1..2dcdb9d1 100755 --- a/src/index.js +++ b/src/index.js @@ -1,12 +1,12 @@ #!/usr/bin/env node -let shouldThrow = false; +let shouldThrow = false try { - const [major, minor] = process.version.slice(1).split('.').map(Number); + const [major, minor] = process.version.slice(1).split('.').map(Number) shouldThrow = // eslint-disable-next-line global-require,import/no-dynamic-require require(`${process.cwd()}/package.json`).name === 'cod-scripts' && - (major < 10 || (major === 10 && minor < 18)); + (major < 10 || (major === 10 && minor < 18)) } catch (error) { // ignore } @@ -14,7 +14,7 @@ try { if (shouldThrow) { throw new Error( 'You must use Node version 10.18 or greater to run the scripts within cod-scripts, because we dogfood the untranspiled version of the scripts.', - ); + ) } -require('./run-script'); +require('./run-script') diff --git a/src/run-script.js b/src/run-script.js index e1d6bd1a..66705135 100755 --- a/src/run-script.js +++ b/src/run-script.js @@ -1,14 +1,14 @@ -const path = require('path'); -const spawn = require('cross-spawn'); -const glob = require('glob'); +const path = require('path') +const spawn = require('cross-spawn') +const glob = require('glob') -const [executor, ignoredBin, script] = process.argv; +const [executor, ignoredBin, script] = process.argv if (script && script !== '--help' && script !== 'help') { - spawnScript(); + spawnScript() } else { - const scriptsPath = path.join(__dirname, 'scripts/'); - const scriptsAvailable = glob.sync(path.join(__dirname, 'scripts', '*')); + const scriptsPath = path.join(__dirname, 'scripts/') + const scriptsAvailable = glob.sync(path.join(__dirname, 'scripts', '*')) // `glob.sync` returns paths with unix style path separators even on Windows. // So we normalize it before attempting to strip out the scripts path. const scriptsAvailableMessage = scriptsAvailable @@ -21,7 +21,7 @@ if (script && script !== '--help' && script !== 'help') { ) .filter(Boolean) .join('\n ') - .trim(); + .trim() const fullMessage = ` Usage: ${ignoredBin} [script] [--flags] @@ -32,8 +32,8 @@ Options: All options depend on the script. Docs will be improved eventually, but for most scripts you can assume that the args you pass will be forwarded to the respective tool that's being run under the hood. May the force be with you. - `.trim(); - console.log(`\n${fullMessage}\n`); + `.trim() + console.log(`\n${fullMessage}\n`) } function getEnv() { @@ -41,9 +41,9 @@ function getEnv() { // https://github.com/kentcdodds/kcd-scripts/issues/4 return Object.keys(process.env) .filter(key => process.env[key] !== undefined) - .reduce((envCopy, key) => ({ ...envCopy, [key]: process.env[key] }), { + .reduce((envCopy, key) => ({...envCopy, [key]: process.env[key]}), { [`SCRIPTS_${script.toUpperCase()}`]: true, - }); + }) } function handleSignal(result) { @@ -52,29 +52,29 @@ function handleSignal(result) { `The script "${script}" failed because the process exited too early. ` + 'This probably means the system ran out of memory or someone called ' + '`kill -9` on the process.', - ); + ) } else if (result.signal === 'SIGTERM') { console.log( `The script "${script}" failed because the process exited too early. ` + 'Someone might have called `kill` or `killall`, or the system could ' + 'be shutting down.', - ); + ) } - process.exit(1); + process.exit(1) } function attemptResolve(...resolveArgs) { try { - return require.resolve(...resolveArgs); + return require.resolve(...resolveArgs) } catch (error) { - return null; + return null } } function spawnScript() { // get all the arguments of the script and find the position of our script // commands - const args = process.argv.slice(2); + const args = process.argv.slice(2) const scriptIndex = args.findIndex(x => [ 'build', @@ -86,20 +86,20 @@ function spawnScript() { 'commitlint', 'typecheck', ].includes(x), - ); + ) // Extract the node arguments so we can pass them to node later on - const buildCommand = scriptIndex === -1 ? args[0] : args[scriptIndex]; - const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : []; + const buildCommand = scriptIndex === -1 ? args[0] : args[scriptIndex] + const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : [] if (!buildCommand) { - throw new Error(`Unknown script "${script}".`); + throw new Error(`Unknown script "${script}".`) } - const relativeScriptPath = path.join(__dirname, './scripts', buildCommand); - const scriptPath = attemptResolve(relativeScriptPath); + const relativeScriptPath = path.join(__dirname, './scripts', buildCommand) + const scriptPath = attemptResolve(relativeScriptPath) if (!scriptPath) { - throw new Error(`Unknown script "${script}".`); + throw new Error(`Unknown script "${script}".`) } // Attempt to strt the script with the passed node arguments @@ -110,11 +110,11 @@ function spawnScript() { stdio: 'inherit', env: getEnv(), }, - ); + ) if (result.signal) { - handleSignal(result); + handleSignal(result) } else { - process.exit(result.status); + process.exit(result.status) } } diff --git a/src/scripts/__tests__/format.js b/src/scripts/__tests__/format.js index d796bcae..489d0fc6 100644 --- a/src/scripts/__tests__/format.js +++ b/src/scripts/__tests__/format.js @@ -1,35 +1,35 @@ -import cases from 'jest-in-case'; -import { unquoteSerializer, winPathSerializer } from './helpers/serializers'; +import cases from 'jest-in-case' +import {unquoteSerializer, winPathSerializer} from './helpers/serializers' -expect.addSnapshotSerializer(unquoteSerializer); -expect.addSnapshotSerializer(winPathSerializer); +expect.addSnapshotSerializer(unquoteSerializer) +expect.addSnapshotSerializer(winPathSerializer) cases( 'format', - ({ args }) => { + ({args}) => { // beforeEach - const { sync: crossSpawnSyncMock } = require('cross-spawn'); - const originalExit = process.exit; - const originalArgv = process.argv; - const utils = require('../../utils'); - utils.resolveBin = (modName, { executable = modName } = {}) => executable; - process.exit = jest.fn(); + const {sync: crossSpawnSyncMock} = require('cross-spawn') + const originalExit = process.exit + const originalArgv = process.argv + const utils = require('../../utils') + utils.resolveBin = (modName, {executable = modName} = {}) => executable + process.exit = jest.fn() // tests - process.argv = ['node', '../format', ...args]; - require('../format'); - expect(crossSpawnSyncMock).toHaveBeenCalledTimes(2); - const [firstCall] = crossSpawnSyncMock.mock.calls; - const [script, calledArgs] = firstCall; - expect([script, ...calledArgs].join(' ')).toMatchSnapshot(); - const [secondCall] = crossSpawnSyncMock.mock.calls; - const [secondScript, secondCalledArgs] = secondCall; - expect([secondScript, ...secondCalledArgs].join(' ')).toMatchSnapshot(); + process.argv = ['node', '../format', ...args] + require('../format') + expect(crossSpawnSyncMock).toHaveBeenCalledTimes(2) + const [firstCall] = crossSpawnSyncMock.mock.calls + const [script, calledArgs] = firstCall + expect([script, ...calledArgs].join(' ')).toMatchSnapshot() + const [secondCall] = crossSpawnSyncMock.mock.calls + const [secondScript, secondCalledArgs] = secondCall + expect([secondScript, ...secondCalledArgs].join(' ')).toMatchSnapshot() // afterEach - process.exit = originalExit; - process.argv = originalArgv; - jest.resetModules(); + process.exit = originalExit + process.argv = originalArgv + jest.resetModules() }, { 'calls prettier CLI with args': { @@ -45,4 +45,4 @@ cases( args: ['--ignore-path', './.myignore'], }, }, -); +) diff --git a/src/scripts/__tests__/helpers/serializers.js b/src/scripts/__tests__/helpers/serializers.js index baede0a5..3cded83a 100644 --- a/src/scripts/__tests__/helpers/serializers.js +++ b/src/scripts/__tests__/helpers/serializers.js @@ -1,25 +1,25 @@ -import slash from 'slash'; +import slash from 'slash' // this removes the quotes around strings... export const unquoteSerializer = { print: val => val, test: val => typeof val === 'string', -}; +} // this converts windows style file paths to unix... export const winPathSerializer = { print: val => slash(val), test: val => typeof val === 'string' && val.includes('\\'), -}; +} function normalizePaths(value) { if (typeof value !== 'string') { - return value; + return value } - return slash(value.split(process.cwd()).join('')); + return slash(value.split(process.cwd()).join('')) } export const relativePathSerializer = { print: val => normalizePaths(val), test: val => normalizePaths(val) !== val, -}; +} diff --git a/src/scripts/__tests__/lint.js b/src/scripts/__tests__/lint.js index 3a3094d0..d3c0c3bf 100644 --- a/src/scripts/__tests__/lint.js +++ b/src/scripts/__tests__/lint.js @@ -1,13 +1,13 @@ -import cases from 'jest-in-case'; +import cases from 'jest-in-case' import { unquoteSerializer, winPathSerializer, relativePathSerializer, -} from './helpers/serializers'; +} from './helpers/serializers' -expect.addSnapshotSerializer(unquoteSerializer); -expect.addSnapshotSerializer(winPathSerializer); -expect.addSnapshotSerializer(relativePathSerializer); +expect.addSnapshotSerializer(unquoteSerializer) +expect.addSnapshotSerializer(winPathSerializer) +expect.addSnapshotSerializer(relativePathSerializer) cases( 'lint', @@ -19,34 +19,34 @@ cases( setup = () => () => {}, }) => { // beforeEach - const { sync: crossSpawnSyncMock } = require('cross-spawn'); - const originalArgv = process.argv; - const originalExit = process.exit; + const {sync: crossSpawnSyncMock} = require('cross-spawn') + const originalArgv = process.argv + const originalExit = process.exit Object.assign(utils, { hasPkgProp, hasFile, - resolveBin: (modName, { executable = modName } = {}) => executable, - }); - process.exit = jest.fn(); - const teardown = setup(); + resolveBin: (modName, {executable = modName} = {}) => executable, + }) + process.exit = jest.fn() + const teardown = setup() - process.argv = ['node', '../lint', ...args]; + process.argv = ['node', '../lint', ...args] try { // tests - require('../lint'); - expect(crossSpawnSyncMock).toHaveBeenCalledTimes(1); - const [firstCall] = crossSpawnSyncMock.mock.calls; - const [script, calledArgs] = firstCall; - expect([script, ...calledArgs].join(' ')).toMatchSnapshot(); + require('../lint') + expect(crossSpawnSyncMock).toHaveBeenCalledTimes(1) + const [firstCall] = crossSpawnSyncMock.mock.calls + const [script, calledArgs] = firstCall + expect([script, ...calledArgs].join(' ')).toMatchSnapshot() } catch (error) { - throw error; + throw error } finally { - teardown(); + teardown() // afterEach - process.exit = originalExit; - process.argv = originalArgv; - jest.resetModules(); + process.exit = originalExit + process.argv = originalArgv + jest.resetModules() } }, { @@ -89,4 +89,4 @@ cases( ], }, }, -); +) diff --git a/src/scripts/__tests__/pre-commit.js b/src/scripts/__tests__/pre-commit.js index d9530a5e..12f653bc 100644 --- a/src/scripts/__tests__/pre-commit.js +++ b/src/scripts/__tests__/pre-commit.js @@ -1,8 +1,8 @@ -import cases from 'jest-in-case'; -import { unquoteSerializer, winPathSerializer } from './helpers/serializers'; +import cases from 'jest-in-case' +import {unquoteSerializer, winPathSerializer} from './helpers/serializers' -expect.addSnapshotSerializer(unquoteSerializer); -expect.addSnapshotSerializer(winPathSerializer); +expect.addSnapshotSerializer(unquoteSerializer) +expect.addSnapshotSerializer(winPathSerializer) cases( 'pre-commit', @@ -13,34 +13,34 @@ cases( hasFile = () => false, }) => { // beforeEach - const { sync: crossSpawnSyncMock } = require('cross-spawn'); - const originalArgv = process.argv; - const originalExit = process.exit; + const {sync: crossSpawnSyncMock} = require('cross-spawn') + const originalArgv = process.argv + const originalExit = process.exit Object.assign(utils, { hasPkgProp, hasFile, - resolveBin: (modName, { executable = modName } = {}) => executable, - }); - process.exit = jest.fn(); + resolveBin: (modName, {executable = modName} = {}) => executable, + }) + process.exit = jest.fn() - process.argv = ['node', '../pre-commit', ...args]; + process.argv = ['node', '../pre-commit', ...args] try { // tests - require('../pre-commit'); - expect(crossSpawnSyncMock).toHaveBeenCalledTimes(2); - const [firstCall, secondCall] = crossSpawnSyncMock.mock.calls; - const [scriptOne, calledArgsOne] = firstCall; - expect([scriptOne, ...calledArgsOne].join(' ')).toMatchSnapshot(); - const [scriptTwo, calledArgsTwo] = secondCall; - expect([scriptTwo, ...calledArgsTwo].join(' ')).toMatchSnapshot(); + require('../pre-commit') + expect(crossSpawnSyncMock).toHaveBeenCalledTimes(2) + const [firstCall, secondCall] = crossSpawnSyncMock.mock.calls + const [scriptOne, calledArgsOne] = firstCall + expect([scriptOne, ...calledArgsOne].join(' ')).toMatchSnapshot() + const [scriptTwo, calledArgsTwo] = secondCall + expect([scriptTwo, ...calledArgsTwo].join(' ')).toMatchSnapshot() } catch (error) { - throw error; + throw error } finally { // afterEach - process.exit = originalExit; - process.argv = originalArgv; - jest.resetModules(); + process.exit = originalExit + process.argv = originalArgv + jest.resetModules() } }, { @@ -61,4 +61,4 @@ cases( args: ['--verbose'], }, }, -); +) diff --git a/src/scripts/__tests__/test.js b/src/scripts/__tests__/test.js index c8add504..3069a317 100644 --- a/src/scripts/__tests__/test.js +++ b/src/scripts/__tests__/test.js @@ -1,12 +1,12 @@ -import cases from 'jest-in-case'; -import { unquoteSerializer } from './helpers/serializers'; +import cases from 'jest-in-case' +import {unquoteSerializer} from './helpers/serializers' -jest.mock('jest', () => ({ run: jest.fn() })); -jest.mock('../../config/jest.config', () => ({ builtInConfig: true })); -let mockIsCI = false; -jest.mock('is-ci', () => mockIsCI); +jest.mock('jest', () => ({run: jest.fn()})) +jest.mock('../../config/jest.config', () => ({builtInConfig: true})) +let mockIsCI = false +jest.mock('is-ci', () => mockIsCI) -expect.addSnapshotSerializer(unquoteSerializer); +expect.addSnapshotSerializer(unquoteSerializer) cases( 'test', @@ -21,37 +21,37 @@ cases( }) => { // beforeEach // eslint-disable-next-line jest/no-jest-import - const { run: jestRunMock } = require('jest'); - const originalArgv = process.argv; - const prevCI = mockIsCI; - const prevPreCommit = process.env['SCRIPTS_PRE-COMMIT']; - mockIsCI = ci; - process.env['SCRIPTS_PRE-COMMIT'] = preCommit; + const {run: jestRunMock} = require('jest') + const originalArgv = process.argv + const prevCI = mockIsCI + const prevPreCommit = process.env['SCRIPTS_PRE-COMMIT'] + mockIsCI = ci + process.env['SCRIPTS_PRE-COMMIT'] = preCommit Object.assign(utils, { hasPkgProp: () => pkgHasJestProp, hasFile: () => hasJestConfigFile, - }); - process.exit = jest.fn(); - const teardown = setup(); + }) + process.exit = jest.fn() + const teardown = setup() - process.argv = ['node', '../test', ...args]; + process.argv = ['node', '../test', ...args] try { // tests - require('../test'); - expect(jestRunMock).toHaveBeenCalledTimes(1); - const [firstCall] = jestRunMock.mock.calls; - const [jestArgs] = firstCall; - expect(jestArgs.join(' ')).toMatchSnapshot(); + require('../test') + expect(jestRunMock).toHaveBeenCalledTimes(1) + const [firstCall] = jestRunMock.mock.calls + const [jestArgs] = firstCall + expect(jestArgs.join(' ')).toMatchSnapshot() } catch (error) { - throw error; + throw error } finally { - teardown(); + teardown() // afterEach - process.argv = originalArgv; - mockIsCI = prevCI; - process.env['SCRIPTS_PRE-COMMIT'] = prevPreCommit; - jest.resetModules(); + process.argv = originalArgv + mockIsCI = prevCI + process.env['SCRIPTS_PRE-COMMIT'] = prevPreCommit + jest.resetModules() } }, { @@ -84,4 +84,4 @@ cases( args: ['--coverage', '--watch'], }, }, -); +) diff --git a/src/scripts/__tests__/validate.js b/src/scripts/__tests__/validate.js index 4e7b50df..c92380e3 100644 --- a/src/scripts/__tests__/validate.js +++ b/src/scripts/__tests__/validate.js @@ -1,73 +1,73 @@ -import cases from 'jest-in-case'; -import { unquoteSerializer } from './helpers/serializers'; +import cases from 'jest-in-case' +import {unquoteSerializer} from './helpers/serializers' -expect.addSnapshotSerializer(unquoteSerializer); +expect.addSnapshotSerializer(unquoteSerializer) function setupWithScripts(scripts = ['test', 'lint', 'build', 'typecheck']) { return function setup() { - const utils = require('../../utils'); - const originalIfScript = utils.ifScript; - utils.ifScript = (script, t, f) => (scripts.includes(script) ? t : f); + const utils = require('../../utils') + const originalIfScript = utils.ifScript + utils.ifScript = (script, t, f) => (scripts.includes(script) ? t : f) return function teardown() { - utils.ifScript = originalIfScript; - }; - }; + utils.ifScript = originalIfScript + } + } } function setupWithArgs(args = []) { return function setup() { - const utils = require('../../utils'); - const originalResolveBin = utils.resolveBin; - utils.resolveBin = (modName, { executable = modName } = {}) => executable; - const originalArgv = process.argv; - process.argv = ['node', '../format', ...args]; + const utils = require('../../utils') + const originalResolveBin = utils.resolveBin + utils.resolveBin = (modName, {executable = modName} = {}) => executable + const originalArgv = process.argv + process.argv = ['node', '../format', ...args] return function teardown() { - process.argv = originalArgv; - utils.resolveBin = originalResolveBin; - }; - }; + process.argv = originalArgv + utils.resolveBin = originalResolveBin + } + } } function withDefaultSetup(setupFn) { return function defaultSetup() { - const utils = require('../../utils'); - utils.resolveBin = (modName, { executable = modName } = {}) => executable; - const argsTeardown = setupWithArgs()(); - const teardownScripts = setupWithScripts()(); - const teardownFn = setupFn(); + const utils = require('../../utils') + utils.resolveBin = (modName, {executable = modName} = {}) => executable + const argsTeardown = setupWithArgs()() + const teardownScripts = setupWithScripts()() + const teardownFn = setupFn() return function defaultTeardown() { - argsTeardown(); - teardownFn(); - teardownScripts(); - }; - }; + argsTeardown() + teardownFn() + teardownScripts() + } + } } cases( 'validate', - ({ setup = () => () => {} }) => { + ({setup = () => () => {}}) => { // beforeEach - const { sync: crossSpawnSyncMock } = require('cross-spawn'); - const originalExit = process.exit; - process.exit = jest.fn(); - process.env['SCRIPTS_PRE-COMMIT'] = 'false'; - const teardown = setup(); + const {sync: crossSpawnSyncMock} = require('cross-spawn') + const originalExit = process.exit + process.exit = jest.fn() + process.env['SCRIPTS_PRE-COMMIT'] = 'false' + const teardown = setup() try { // tests - require('../validate'); - const [firstCall] = crossSpawnSyncMock.mock.calls; - const [script, calledArgs] = firstCall || ['', []]; - expect([script, ...calledArgs].join(' ')).toMatchSnapshot(); + require('../validate') + const [firstCall] = crossSpawnSyncMock.mock.calls + const [script, calledArgs] = firstCall || ['', []] + expect([script, ...calledArgs].join(' ')).toMatchSnapshot() } catch (error) { - throw error; + throw error } finally { - teardown(); + teardown() } // afterEach - process.exit = originalExit; - jest.resetModules(); + process.exit = originalExit + jest.resetModules() }, { 'calls concurrently with all scripts': { @@ -90,15 +90,15 @@ cases( }, [`doesn't use test or lint if it's in pre-commit`]: { setup: withDefaultSetup(() => { - const previousVal = process.env['SCRIPTS_PRE-COMMIT']; - process.env['SCRIPTS_PRE-COMMIT'] = 'true'; + const previousVal = process.env['SCRIPTS_PRE-COMMIT'] + process.env['SCRIPTS_PRE-COMMIT'] = 'true' return function teardown() { - process.env['SCRIPTS_PRE-COMMIT'] = previousVal; - }; + process.env['SCRIPTS_PRE-COMMIT'] = previousVal + } }), }, 'exits if there are no scripts to be run': { setup: withDefaultSetup(setupWithScripts([])), }, }, -); +) diff --git a/src/scripts/build/babel.js b/src/scripts/build/babel.js index 3041b2e8..b176ceb0 100644 --- a/src/scripts/build/babel.js +++ b/src/scripts/build/babel.js @@ -1,9 +1,9 @@ -const path = require('path'); -const { DEFAULT_EXTENSIONS } = require('@babel/core'); -const spawn = require('cross-spawn'); -const yargsParser = require('yargs-parser'); -const rimraf = require('rimraf'); -const glob = require('glob'); +const path = require('path') +const {DEFAULT_EXTENSIONS} = require('@babel/core') +const spawn = require('cross-spawn') +const yargsParser = require('yargs-parser') +const rimraf = require('rimraf') +const glob = require('glob') const { hasPkgProp, fromRoot, @@ -11,47 +11,52 @@ const { hasFile, hasTypescript, generateTypeDefs, -} = require('../../utils'); +} = require('../../utils') -let args = process.argv.slice(2); -const here = p => path.join(__dirname, p); +let args = process.argv.slice(2) +const here = p => path.join(__dirname, p) -const parsedArgs = yargsParser(args); +const parsedArgs = yargsParser(args) const useBuiltinConfig = !args.includes('--presets') && !hasFile('.babelrc') && !hasFile('.babelrc.js') && !hasFile('babel.config.js') && - !hasPkgProp('babel'); + !hasPkgProp('babel') const config = useBuiltinConfig ? ['--presets', here('../../config/babelrc.js')] - : []; + : [] const extensions = args.includes('--extensions') || args.includes('--x') ? [] - : ['--extensions', [...DEFAULT_EXTENSIONS, '.ts', '.tsx']]; + : ['--extensions', [...DEFAULT_EXTENSIONS, '.ts', '.tsx']] -const builtInIgnore = '**/__tests__/**,**/__mocks__/**'; +const builtInIgnore = '**/__tests__/**,**/__mocks__/**' -const ignore = args.includes('--ignore') ? [] : ['--ignore', builtInIgnore]; +const ignore = args.includes('--ignore') ? [] : ['--ignore', builtInIgnore] -const copyFiles = args.includes('--no-copy-files') ? [] : ['--copy-files']; +const copyFiles = args.includes('--no-copy-files') ? [] : ['--copy-files'] -const useSpecifiedOutDir = args.includes('--out-dir') || args.includes('-d'); -const builtInOutDir = 'dist'; -const outDir = useSpecifiedOutDir ? [] : ['--out-dir', builtInOutDir]; +const useSpecifiedOutDir = args.includes('--out-dir') +const builtInOutDir = 'dist' +const outDir = useSpecifiedOutDir ? [] : ['--out-dir', builtInOutDir] +const noTypeDefinitions = args.includes('--no-ts-defs') if (!useSpecifiedOutDir && !args.includes('--no-clean')) { - rimraf.sync(fromRoot('dist')); + rimraf.sync(fromRoot('dist')) } else { - args = args.filter(a => a !== '--no-clean'); + args = args.filter(a => a !== '--no-clean') +} + +if (noTypeDefinitions) { + args = args.filter(a => a !== '--no-ts-defs') } function go() { let result = spawn.sync( - resolveBin('@babel/cli', { executable: 'babel' }), + resolveBin('@babel/cli', {executable: 'babel'}), [ ...outDir, ...copyFiles, @@ -60,31 +65,32 @@ function go() { ...config, 'src', ].concat(args), - { stdio: 'inherit' }, - ); - if (result.status !== 0) return result.status; - - if (hasTypescript && !args.includes('--no-ts-defs')) { - console.log('Generating TypeScript definitions'); - result = generateTypeDefs(); - console.log('TypeScript definitions generated'); - if (result.status !== 0) return result.status; + {stdio: 'inherit'}, + ) + if (result.status !== 0) return result.status + + const pathToOutDir = fromRoot(parsedArgs.outDir || builtInOutDir) + + if (hasTypescript && !noTypeDefinitions) { + console.log('Generating TypeScript definitions') + result = generateTypeDefs(pathToOutDir) + console.log('TypeScript definitions generated') + if (result.status !== 0) return result.status } // because babel will copy even ignored files, we need to remove the ignored files - const pathToOutDir = fromRoot(parsedArgs.outDir || builtInOutDir); const ignoredPatterns = (parsedArgs.ignore || builtInIgnore) .split(',') - .map(pattern => path.join(pathToOutDir, pattern)); + .map(pattern => path.join(pathToOutDir, pattern)) const ignoredFiles = ignoredPatterns.reduce( (all, pattern) => [...all, ...glob.sync(pattern)], [], - ); + ) ignoredFiles.forEach(ignoredFile => { - rimraf.sync(ignoredFile); - }); + rimraf.sync(ignoredFile) + }) - return result.status; + return result.status } -process.exit(go()); +process.exit(go()) diff --git a/src/scripts/build/index.js b/src/scripts/build/index.js index f3f380db..a209b7aa 100644 --- a/src/scripts/build/index.js +++ b/src/scripts/build/index.js @@ -1,9 +1,9 @@ if (process.argv.includes('--browser')) { - console.error('--browser has been deprecated, use --bundle instead'); + console.error('--browser has been deprecated, use --bundle instead') } if (process.argv.includes('--bundle')) { - require('./rollup'); + require('./rollup') } else { - require('./babel'); + require('./babel') } diff --git a/src/scripts/build/rollup.js b/src/scripts/build/rollup.js index daadaa0d..19b858ed 100644 --- a/src/scripts/build/rollup.js +++ b/src/scripts/build/rollup.js @@ -1,9 +1,9 @@ -const path = require('path'); -const fs = require('fs'); -const spawn = require('cross-spawn'); -const glob = require('glob'); -const rimraf = require('rimraf'); -const yargsParser = require('yargs-parser'); +const path = require('path') +const fs = require('fs') +const spawn = require('cross-spawn') +const glob = require('glob') +const rimraf = require('rimraf') +const yargsParser = require('yargs-parser') const { hasFile, resolveBin, @@ -12,64 +12,66 @@ const { writeExtraEntry, hasTypescript, generateTypeDefs, -} = require('../../utils'); + getRollupInputs, + getRollupOutput, +} = require('../../utils') -const crossEnv = resolveBin('cross-env'); -const rollup = resolveBin('rollup'); -const args = process.argv.slice(2); -const here = p => path.join(__dirname, p); -const hereRelative = p => here(p).replace(process.cwd(), '.'); -const parsedArgs = yargsParser(args); +const crossEnv = resolveBin('cross-env') +const rollup = resolveBin('rollup') +const args = process.argv.slice(2) +const here = p => path.join(__dirname, p) +const hereRelative = p => here(p).replace(process.cwd(), '.') +const parsedArgs = yargsParser(args) const useBuiltinConfig = - !args.includes('--config') && !hasFile('rollup.config.js'); + !args.includes('--config') && !hasFile('rollup.config.js') // eslint-disable-next-line const config = useBuiltinConfig ? `--config ${hereRelative('../../config/rollup.config.js')}` : args.includes('--config') ? '' - : '--config'; // --config will pick up the rollup.config.js file + : '--config' // --config will pick up the rollup.config.js file const environment = parsedArgs.environment ? `--environment ${parsedArgs.environment}` - : ''; -const watch = parsedArgs.watch ? '--watch' : ''; -const sizeSnapshot = parsedArgs['size-snapshot']; + : '' +const watch = parsedArgs.watch ? '--watch' : '' +const sizeSnapshot = parsedArgs['size-snapshot'] -let formats = ['esm', 'cjs', 'umd', 'umd.min']; +let formats = ['esm', 'cjs', 'umd', 'umd.min'] if (typeof parsedArgs.bundle === 'string') { - formats = parsedArgs.bundle.split(','); + formats = parsedArgs.bundle.split(',') } -const defaultEnv = 'BUILD_ROLLUP=true'; +const defaultEnv = 'BUILD_ROLLUP=true' const getCommand = (env, ...flags) => [crossEnv, defaultEnv, env, rollup, config, environment, watch, ...flags] .filter(Boolean) - .join(' '); + .join(' ') -const buildPreact = args.includes('--p-react'); +const buildPreact = args.includes('--p-react') const scripts = getConcurrentlyArgs( buildPreact ? getPReactCommands() : getCommands(), -); +) -const cleanBuildDirs = !args.includes('--no-clean'); +const cleanBuildDirs = !args.includes('--no-clean') if (cleanBuildDirs) { - rimraf.sync(fromRoot('dist')); + rimraf.sync(fromRoot('dist')) if (buildPreact) { - rimraf.sync(fromRoot('preact')); + rimraf.sync(fromRoot('preact')) } } function go() { let result = spawn.sync(resolveBin('concurrently'), scripts, { stdio: 'inherit', - }); + }) - if (result.status !== 0) return result.status; + if (result.status !== 0) return result.status if (buildPreact && !args.includes('--no-package-json')) { writeExtraEntry( @@ -79,22 +81,44 @@ function go() { esm: glob.sync(fromRoot('preact/**/*.esm.js'))[0], }, false, - ); + ) } if (hasTypescript && !args.includes('--no-ts-defs')) { - console.log('Generating TypeScript definitions'); - result = generateTypeDefs(); - if (result.status !== 0) return result.status; + console.log('Generating TypeScript definitions') + result = generateTypeDefs(fromRoot('dist')) + if (result.status !== 0) return result.status + + const rollupInputs = getRollupInputs() + const typeDefFiles = rollupInputs.map(input => { + return input + .replace(path.join(process.cwd(), 'src'), 'dist') + .replace(/\.(t|j)sx?$/, '.d.ts') + }) for (const format of formats) { - const [formatFile] = glob.sync(fromRoot(`dist/*.${format}.js`)); - const { name } = path.parse(formatFile); - // make a .d.ts file for every generated file that re-exports index.d.ts - fs.writeFileSync( - fromRoot('dist', `${name}.d.ts`), - 'export * from ".";\n', - ); + const {dirpath, filename} = getRollupOutput(format) + + const isCodesplitting = rollupInputs.length > 1 + + const outputs = isCodesplitting + ? glob.sync(fromRoot(path.join(dirpath, format, '*.js'))) + : [fromRoot(path.join(dirpath, filename))] + + for (const output of outputs) { + const {name, dir} = path.parse(output) + const typeDef = isCodesplitting + ? typeDefFiles.find(f => path.basename(f) === `${name}.d.ts`) + : 'dist/index.d.ts' + const relativePath = path + .join(path.relative(dir, process.cwd()), typeDef) + .replace(/\.d\.ts$/, '') + // make a .d.ts file for every generated file that re-exports index.d.ts + fs.writeFileSync( + path.join(dir, `${name}.d.ts`), + `export * from "${relativePath}";\n`, + ) + } } // because typescript generates type defs for ignored files, we need to @@ -102,36 +126,36 @@ function go() { const ignoredFiles = [ ...glob.sync(fromRoot('dist', '**/__tests__/**')), ...glob.sync(fromRoot('dist', '**/__mocks__/**')), - ]; + ] ignoredFiles.forEach(ignoredFile => { - rimraf.sync(ignoredFile); - }); - console.log('TypeScript definitions generated'); + rimraf.sync(ignoredFile) + }) + console.log('TypeScript definitions generated') } - return result.status; + return result.status } function getPReactCommands() { return { ...prefixKeys('react.', getCommands()), - ...prefixKeys('preact.', getCommands({ preact: true })), - }; + ...prefixKeys('preact.', getCommands({preact: true})), + } } function prefixKeys(prefix, object) { return Object.entries(object).reduce((cmds, [key, value]) => { - cmds[`${prefix}${key}`] = value; - return cmds; - }, {}); + cmds[`${prefix}${key}`] = value + return cmds + }, {}) } -function getCommands({ preact = false } = {}) { +function getCommands({preact = false} = {}) { return formats.reduce((cmds, format) => { - const [formatName, minify = false] = format.split('.'); - const nodeEnv = minify ? 'production' : 'development'; - const sourceMap = formatName === 'umd' ? '--sourcemap' : ''; - const buildMinify = Boolean(minify); + const [formatName, minify = false] = format.split('.') + const nodeEnv = minify ? 'production' : 'development' + const sourceMap = formatName === 'umd' ? '--sourcemap' : '' + const buildMinify = Boolean(minify) cmds[format] = getCommand( [ @@ -144,9 +168,9 @@ function getCommands({ preact = false } = {}) { `BUILD_REACT_NATIVE=${process.env.BUILD_REACT_NATIVE || false}`, ].join(' '), sourceMap, - ); - return cmds; - }, {}); + ) + return cmds + }, {}) } -process.exit(go()); +process.exit(go()) diff --git a/src/scripts/commitlint.js b/src/scripts/commitlint.js index 38d8cf54..fbbaa1ee 100644 --- a/src/scripts/commitlint.js +++ b/src/scripts/commitlint.js @@ -1,10 +1,10 @@ -const path = require('path'); -const spawn = require('cross-spawn'); -const { hasPkgProp, resolveBin, hasFile } = require('../utils'); +const path = require('path') +const spawn = require('cross-spawn') +const {hasPkgProp, resolveBin, hasFile} = require('../utils') -const args = process.argv.slice(2); -const here = p => path.join(__dirname, p); -const hereRelative = p => here(p).replace(process.cwd(), '.'); +const args = process.argv.slice(2) +const here = p => path.join(__dirname, p) +const hereRelative = p => here(p).replace(process.cwd(), '.') const useBuiltinConfig = !args.includes('--config') && @@ -13,14 +13,14 @@ const useBuiltinConfig = !hasFile('.commitlintrc.js') && !hasFile('.commitlintrc.json') && !hasFile('.commitlintrc.yml') && - !hasPkgProp('commitlint'); + !hasPkgProp('commitlint') const config = useBuiltinConfig ? ['--config', hereRelative('../config/commitlint.config.js')] - : []; + : [] const result = spawn.sync(resolveBin('commitlint'), [...config, ...args], { stdio: 'inherit', -}); +}) -process.exit(result.status); +process.exit(result.status) diff --git a/src/scripts/format.js b/src/scripts/format.js index 31ac7753..148da7b5 100644 --- a/src/scripts/format.js +++ b/src/scripts/format.js @@ -1,49 +1,49 @@ -const path = require('path'); -const spawn = require('cross-spawn'); -const yargsParser = require('yargs-parser'); +const path = require('path') +const spawn = require('cross-spawn') +const yargsParser = require('yargs-parser') const { resolveBin, hasFile, hasLocalConfig, resolveCodScripts, -} = require('../utils'); +} = require('../utils') -const args = process.argv.slice(2); -const parsedArgs = yargsParser(args); +const args = process.argv.slice(2) +const parsedArgs = yargsParser(args) -const here = p => path.join(__dirname, p); -const hereRelative = p => here(p).replace(process.cwd(), '.'); +const here = p => path.join(__dirname, p) +const hereRelative = p => here(p).replace(process.cwd(), '.') const useBuiltinConfig = - !args.includes('--config') && !hasLocalConfig('prettier'); + !args.includes('--config') && !hasLocalConfig('prettier') const config = useBuiltinConfig ? ['--config', hereRelative('../config/prettierrc.js')] - : []; + : [] const useBuiltinIgnore = - !args.includes('--ignore-path') && !hasFile('.prettierignore'); + !args.includes('--ignore-path') && !hasFile('.prettierignore') const ignore = useBuiltinIgnore ? ['--ignore-path', hereRelative('../config/prettierignore')] - : []; + : [] -const write = args.includes('--no-write') ? [] : ['--write']; +const write = args.includes('--no-write') ? [] : ['--write'] // this ensures that when running format as a pre-commit hook and we get // the full file path, we make that non-absolute so it is treated as a glob, // This way the prettierignore will be applied -const relativeArgs = args.map(a => a.replace(`${process.cwd()}/`, '')); +const relativeArgs = args.map(a => a.replace(`${process.cwd()}/`, '')) const filesToApply = parsedArgs._.length ? [] - : ['**/*.+(md|json|yml|yaml|css|less|scss|sass|graphql|ts|tsx)']; + : ['**/*.+(md|json|yml|yaml|css|less|scss|sass|graphql|ts|tsx)'] // run prettier on all non-js files const prettierResult = spawn.sync( resolveBin('prettier'), [...config, ...ignore, ...write, ...filesToApply].concat(relativeArgs), - { stdio: 'inherit' }, -); + {stdio: 'inherit'}, +) if (prettierResult.status !== 0 || args.includes('--no-eslint')) { - process.exit(prettierResult.status); + process.exit(prettierResult.status) } // run eslint for js files (`eslint-plugin-prettier` will run prettier for us) @@ -53,6 +53,6 @@ const eslintResult = spawn.sync( { stdio: 'inherit', }, -); +) -process.exit(eslintResult.status); +process.exit(eslintResult.status) diff --git a/src/scripts/lint.js b/src/scripts/lint.js index 1bed23f8..9baeebb2 100644 --- a/src/scripts/lint.js +++ b/src/scripts/lint.js @@ -1,35 +1,35 @@ -const path = require('path'); -const spawn = require('cross-spawn'); -const yargsParser = require('yargs-parser'); -const { hasPkgProp, resolveBin, hasFile, fromRoot } = require('../utils'); +const path = require('path') +const spawn = require('cross-spawn') +const yargsParser = require('yargs-parser') +const {hasPkgProp, resolveBin, hasFile, fromRoot} = require('../utils') -let args = process.argv.slice(2); -const here = p => path.join(__dirname, p); -const hereRelative = p => here(p).replace(process.cwd(), '.'); -const parsedArgs = yargsParser(args); +let args = process.argv.slice(2) +const here = p => path.join(__dirname, p) +const hereRelative = p => here(p).replace(process.cwd(), '.') +const parsedArgs = yargsParser(args) const useBuiltinConfig = !args.includes('--config') && !hasFile('.eslintrc') && !hasFile('.eslintrc.js') && - !hasPkgProp('eslintConfig'); + !hasPkgProp('eslintConfig') const config = useBuiltinConfig ? ['--config', hereRelative('../config/eslintrc.js')] - : []; + : [] -const defaultExtensions = 'js,ts,tsx'; -const ext = args.includes('--ext') ? [] : ['--ext', defaultExtensions]; -const extensions = (parsedArgs.ext || defaultExtensions).split(','); +const defaultExtensions = 'js,ts,tsx' +const ext = args.includes('--ext') ? [] : ['--ext', defaultExtensions] +const extensions = (parsedArgs.ext || defaultExtensions).split(',') const useBuiltinIgnore = !args.includes('--ignore-path') && !hasFile('.eslintignore') && - !hasPkgProp('eslintIgnore'); + !hasPkgProp('eslintIgnore') const ignore = useBuiltinIgnore ? ['--ignore-path', hereRelative('../config/eslintignore')] - : []; + : [] const cache = args.includes('--no-cache') ? [] @@ -37,10 +37,10 @@ const cache = args.includes('--no-cache') '--cache', '--cache-location', fromRoot('node_modules/.cache/.eslintcache'), - ]; + ] -const filesGiven = parsedArgs._.length > 0; -const filesToApply = filesGiven ? [] : ['.']; +const filesGiven = parsedArgs._.length > 0 +const filesToApply = filesGiven ? [] : ['.'] if (filesGiven) { // we need to take all the flag-less arguments (the files that should be linted) @@ -48,13 +48,13 @@ if (filesGiven) { // may be passed through args = args.filter( a => !parsedArgs._.includes(a) || extensions.some(e => a.endsWith(e)), - ); + ) } const result = spawn.sync( resolveBin('eslint'), [...config, ...ext, ...ignore, ...cache, ...args, ...filesToApply], - { stdio: 'inherit' }, -); + {stdio: 'inherit'}, +) -process.exit(result.status); +process.exit(result.status) diff --git a/src/scripts/pre-commit.js b/src/scripts/pre-commit.js index 1ea2c0fe..97f084aa 100644 --- a/src/scripts/pre-commit.js +++ b/src/scripts/pre-commit.js @@ -1,40 +1,40 @@ -const path = require('path'); -const spawn = require('cross-spawn'); -const { hasPkgProp, hasFile, resolveBin, ifScript } = require('../utils'); +const path = require('path') +const spawn = require('cross-spawn') +const {hasPkgProp, hasFile, resolveBin, ifScript} = require('../utils') -const here = p => path.join(__dirname, p); -const hereRelative = p => here(p).replace(process.cwd(), '.'); +const here = p => path.join(__dirname, p) +const hereRelative = p => here(p).replace(process.cwd(), '.') -const args = process.argv.slice(2); +const args = process.argv.slice(2) const useBuiltInConfig = !args.includes('--config') && !hasFile('.lintstagedrc') && !hasFile('lint-staged.config.js') && - !hasPkgProp('lint-staged'); + !hasPkgProp('lint-staged') const config = useBuiltInConfig ? ['--config', hereRelative('../config/lintstagedrc.js')] - : []; + : [] function go() { - let result; + let result result = spawn.sync(resolveBin('lint-staged'), [...config, ...args], { stdio: 'inherit', - }); + }) - if (result.status !== 0) return result.status; + if (result.status !== 0) return result.status if (ifScript('validate', true)) { result = spawn.sync('npm', ['run', 'validate'], { stdio: 'inherit', - }); + }) - return result.status; + return result.status } - return 0; + return 0 } -process.exit(go()); +process.exit(go()) diff --git a/src/scripts/test.js b/src/scripts/test.js index d02dad7b..106a2d09 100644 --- a/src/scripts/test.js +++ b/src/scripts/test.js @@ -1,10 +1,10 @@ -process.env.BABEL_ENV = 'test'; -process.env.NODE_ENV = 'test'; +process.env.BABEL_ENV = 'test' +process.env.NODE_ENV = 'test' -const isCI = require('is-ci'); -const { hasPkgProp, parseEnv, hasFile } = require('../utils'); +const isCI = require('is-ci') +const {hasPkgProp, parseEnv, hasFile} = require('../utils') -const args = process.argv.slice(2); +const args = process.argv.slice(2) const watch = !isCI && @@ -13,14 +13,14 @@ const watch = !args.includes('--coverage') && !args.includes('--updateSnapshot') ? ['--watch'] - : []; + : [] const config = !args.includes('--config') && !hasFile('jest.config.js') && !hasPkgProp('jest') ? ['--config', JSON.stringify(require('../config/jest.config'))] - : []; + : [] // eslint-disable-next-line jest/no-jest-import -require('jest').run([...config, ...watch, ...args]); +require('jest').run([...config, ...watch, ...args]) diff --git a/src/scripts/typecheck.js b/src/scripts/typecheck.js index 283d5365..155fa9b0 100644 --- a/src/scripts/typecheck.js +++ b/src/scripts/typecheck.js @@ -1,35 +1,31 @@ -const spawn = require('cross-spawn'); -const yargsParser = require('yargs-parser'); -const { hasAnyDep, resolveBin, hasFile } = require('../utils'); +const spawn = require('cross-spawn') +const yargsParser = require('yargs-parser') +const {hasAnyDep, resolveBin, hasFile} = require('../utils') -let args = process.argv.slice(2); -const parsedArgs = yargsParser(args); +let args = process.argv.slice(2) +const parsedArgs = yargsParser(args) if (!hasAnyDep('typescript')) { throw new Error( 'Cannot use the "typecheck" script in a project that does not have typescript listed as a dependency (or devDependency).', - ); + ) } if (!parsedArgs.project && !parsedArgs.build && !hasFile('tsconfig.json')) { throw new Error( 'Cannot use the "typecheck" script without --project or --build in a project that does not have a tsconfig.json file.', - ); + ) } // if --project is provided, we can't pass --build // if --build is provided, we don't need to add it // if --no-build is passed, we'll just trust they know what they're doing if (!parsedArgs.project && !parsedArgs.build && !parsedArgs.noBuild) { - args = ['--build', ...args]; + args = ['--build', ...args] } -const result = spawn.sync( - resolveBin('typescript', { executable: 'tsc' }), - args, - { - stdio: 'inherit', - }, -); +const result = spawn.sync(resolveBin('typescript', {executable: 'tsc'}), args, { + stdio: 'inherit', +}) -process.exit(result.status); +process.exit(result.status) diff --git a/src/scripts/validate.js b/src/scripts/validate.js index 543ad0d3..a3b74c6c 100644 --- a/src/scripts/validate.js +++ b/src/scripts/validate.js @@ -1,19 +1,19 @@ -const spawn = require('cross-spawn'); +const spawn = require('cross-spawn') const { parseEnv, resolveBin, ifScript, getConcurrentlyArgs, -} = require('../utils'); +} = require('../utils') // pre-commit runs linting and tests on the relevant files // so those scripts don't need to be run if we're running // this in the context of a pre-commit hook. -const preCommit = parseEnv('SCRIPTS_PRE-COMMIT', false); +const preCommit = parseEnv('SCRIPTS_PRE-COMMIT', false) -const validateScripts = process.argv[2]; +const validateScripts = process.argv[2] -const useDefaultScripts = typeof validateScripts !== 'string'; +const useDefaultScripts = typeof validateScripts !== 'string' const scripts = useDefaultScripts ? { @@ -30,9 +30,9 @@ const scripts = useDefaultScripts [name]: `npm run ${name} --silent`, }), {}, - ); + ) -const scriptCount = Object.values(scripts).filter(Boolean).length; +const scriptCount = Object.values(scripts).filter(Boolean).length if (scriptCount > 0) { const result = spawn.sync( @@ -41,9 +41,9 @@ if (scriptCount > 0) { { stdio: 'inherit', }, - ); + ) - process.exit(result.status); + process.exit(result.status) } else { - process.exit(0); + process.exit(0) } diff --git a/src/utils.js b/src/utils.js index 4b3c2c5c..9fc7f921 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,45 +1,43 @@ -const fs = require('fs'); -const path = require('path'); -const spawn = require('cross-spawn'); -const rimraf = require('rimraf'); -const mkdirp = require('mkdirp'); -const arrify = require('arrify'); -const has = require('lodash.has'); -const readPkgUp = require('read-pkg-up'); -const which = require('which'); -const { cosmiconfigSync } = require('cosmiconfig'); - -const { packageJson: pkg, path: pkgPath } = readPkgUp.sync({ +const fs = require('fs') +const path = require('path') +const spawn = require('cross-spawn') +const rimraf = require('rimraf') +const mkdirp = require('mkdirp') +const arrify = require('arrify') +const has = require('lodash.has') +const glob = require('glob') +const readPkgUp = require('read-pkg-up') +const which = require('which') +const {cosmiconfigSync} = require('cosmiconfig') + +const {packageJson: pkg, path: pkgPath} = readPkgUp.sync({ cwd: fs.realpathSync(process.cwd()), -}); -const appDirectory = path.dirname(pkgPath); - -function resolveBin( - modName, - { executable = modName, cwd = process.cwd() } = {}, -) { - let pathFromWhich; +}) +const appDirectory = path.dirname(pkgPath) + +function resolveBin(modName, {executable = modName, cwd = process.cwd()} = {}) { + let pathFromWhich try { - pathFromWhich = fs.realpathSync(which.sync(executable)); - if (pathFromWhich && pathFromWhich.includes('.CMD')) return pathFromWhich; + pathFromWhich = fs.realpathSync(which.sync(executable)) + if (pathFromWhich && pathFromWhich.includes('.CMD')) return pathFromWhich } catch (_error) { // ignore _error } try { - const modPkgPath = require.resolve(`${modName}/package.json`); - const modPkgDir = path.dirname(modPkgPath); + const modPkgPath = require.resolve(`${modName}/package.json`) + const modPkgDir = path.dirname(modPkgPath) const { bin } = require(modPkgPath); // eslint-disable-line - const binPath = typeof bin === 'string' ? bin : bin[executable]; - const fullPathToBin = path.join(modPkgDir, binPath); + const binPath = typeof bin === 'string' ? bin : bin[executable] + const fullPathToBin = path.join(modPkgDir, binPath) if (fullPathToBin === pathFromWhich) { - return executable; + return executable } - return fullPathToBin.replace(cwd, '.'); + return fullPathToBin.replace(cwd, '.') } catch (error) { if (pathFromWhich) { - return executable; + return executable } - throw error; + throw error } } @@ -49,59 +47,59 @@ function resolveCodScripts() { // this happens on install of husky within cod-scripts locally appDirectory.includes(path.join(__dirname, '..')) ) { - return require.resolve('./').replace(process.cwd(), '.'); + return require.resolve('./').replace(process.cwd(), '.') } - return resolveBin('cod-scripts'); + return resolveBin('cod-scripts') } -const fromRoot = (...p) => path.join(appDirectory, ...p); -const hasFile = (...p) => fs.existsSync(fromRoot(...p)); +const fromRoot = (...p) => path.join(appDirectory, ...p) +const hasFile = (...p) => fs.existsSync(fromRoot(...p)) const ifFile = (files, t, f) => - arrify(files).some(file => hasFile(file)) ? t : f; + arrify(files).some(file => hasFile(file)) ? t : f -const hasPkgProp = props => arrify(props).some(prop => has(pkg, prop)); +const hasPkgProp = props => arrify(props).some(prop => has(pkg, prop)) const hasPkgSubProp = pkgProp => props => - hasPkgProp(arrify(props).map(p => `${pkgProp}.${p}`)); + hasPkgProp(arrify(props).map(p => `${pkgProp}.${p}`)) const ifPkgSubProp = pkgProp => (props, t, f) => - hasPkgSubProp(pkgProp)(props) ? t : f; + hasPkgSubProp(pkgProp)(props) ? t : f -const hasScript = hasPkgSubProp('scripts'); -const hasPeerDep = hasPkgSubProp('peerDependencies'); -const hasDep = hasPkgSubProp('dependencies'); -const hasDevDep = hasPkgSubProp('devDependencies'); -const hasAnyDep = args => [hasDep, hasDevDep, hasPeerDep].some(fn => fn(args)); +const hasScript = hasPkgSubProp('scripts') +const hasPeerDep = hasPkgSubProp('peerDependencies') +const hasDep = hasPkgSubProp('dependencies') +const hasDevDep = hasPkgSubProp('devDependencies') +const hasAnyDep = args => [hasDep, hasDevDep, hasPeerDep].some(fn => fn(args)) -const ifPeerDep = ifPkgSubProp('peerDependencies'); -const ifDep = ifPkgSubProp('dependencies'); -const ifDevDep = ifPkgSubProp('devDependencies'); -const ifAnyDep = (deps, t, f) => (hasAnyDep(arrify(deps)) ? t : f); -const ifScript = ifPkgSubProp('scripts'); +const ifPeerDep = ifPkgSubProp('peerDependencies') +const ifDep = ifPkgSubProp('dependencies') +const ifDevDep = ifPkgSubProp('devDependencies') +const ifAnyDep = (deps, t, f) => (hasAnyDep(arrify(deps)) ? t : f) +const ifScript = ifPkgSubProp('scripts') function envIsSet(name) { return ( process.env.hasOwnProperty(name) && process.env[name] && process.env[name] !== 'undefined' - ); + ) } -const hasTypescript = hasAnyDep('typescript') && hasFile('tsconfig.json'); -const ifTypescript = (t, f) => (hasTypescript ? t : f); +const hasTypescript = hasAnyDep('typescript') && hasFile('tsconfig.json') +const ifTypescript = (t, f) => (hasTypescript ? t : f) function parseEnv(name, def) { if (envIsSet(name)) { try { - return JSON.parse(process.env[name]); + return JSON.parse(process.env[name]) } catch (err) { - return process.env[name]; + return process.env[name] } } - return def; + return def } -function getConcurrentlyArgs(scripts, { killOthers = true } = {}) { +function getConcurrentlyArgs(scripts, {killOthers = true} = {}) { const colors = [ 'bgBlue', 'bgGreen', @@ -111,22 +109,22 @@ function getConcurrentlyArgs(scripts, { killOthers = true } = {}) { 'bgRed', 'bgBlack', 'bgYellow', - ]; + ] // eslint-disable-next-line no-param-reassign scripts = Object.entries(scripts).reduce((all, [name, script]) => { if (script) { // eslint-disable-next-line no-param-reassign - all[name] = script; + all[name] = script } - return all; - }, {}); + return all + }, {}) const prefixColors = Object.keys(scripts) .reduce( (pColors, _s, i) => pColors.concat([`${colors[i % colors.length]}.bold.white`]), [], ) - .join(','); + .join(',') // prettier-ignore return [ @@ -140,17 +138,17 @@ function getConcurrentlyArgs(scripts, { killOthers = true } = {}) { } function uniq(arr) { - return Array.from(new Set(arr)); + return Array.from(new Set(arr)) } -function writeExtraEntry(name, { cjs, esm }, clean = true) { +function writeExtraEntry(name, {cjs, esm}, clean = true) { if (clean) { - rimraf.sync(fromRoot(name)); + rimraf.sync(fromRoot(name)) } - mkdirp.sync(fromRoot(name)); + mkdirp.sync(fromRoot(name)) - const pkgJson = fromRoot(`${name}/package.json`); - const entryDir = fromRoot(name); + const pkgJson = fromRoot(`${name}/package.json`) + const entryDir = fromRoot(name) fs.writeFileSync( pkgJson, @@ -163,28 +161,59 @@ function writeExtraEntry(name, { cjs, esm }, clean = true) { null, 2, ), - ); + ) } function hasLocalConfig(moduleName, searchOptions = {}) { - const explorerSync = cosmiconfigSync(moduleName, searchOptions); - const result = explorerSync.search(pkgPath); + const explorerSync = cosmiconfigSync(moduleName, searchOptions) + const result = explorerSync.search(pkgPath) - return result !== null; + return result !== null } -function generateTypeDefs() { +function generateTypeDefs(outputDir) { return spawn.sync( - resolveBin('typescript', { executable: 'tsc' }), + resolveBin('typescript', {executable: 'tsc'}), // prettier-ignore [ '--declaration', '--emitDeclarationOnly', '--noEmit', 'false', - '--outDir', fromRoot('dist'), + '--outDir', outputDir, ], - { stdio: 'inherit' }, - ); + {stdio: 'inherit'}, + ) +} + +function getRollupInputs() { + const buildInputGlob = + process.env.BUILD_INPUT || + (hasTypescript ? 'src/index.{js,ts,tsx}' : 'src/index.js') + const input = glob.sync(fromRoot(buildInputGlob)) + if (!input.length) { + throw new Error(`Unable to find files with this glob: ${buildInputGlob}`) + } + return input +} + +function getRollupOutput(format = process.env.BUILD_FORMAT) { + const minify = parseEnv('BUILD_MINIFY', false) + const filenameSuffix = process.env.BUILD_FILENAME_SUFFIX || '' + const filename = [ + pkg.name, + filenameSuffix, + `.${format}`, + minify ? '.min' : null, + '.js', + ] + .filter(Boolean) + .join('') + + const isPreact = parseEnv('BUILD_PREACT', false) + const filenamePrefix = + process.env.BUILD_FILENAME_PREFIX || (isPreact ? 'preact/' : '') + const dirpath = path.join(...[filenamePrefix, 'dist'].filter(Boolean)) + return {dirpath, filename} } module.exports = { @@ -212,4 +241,6 @@ module.exports = { uniq, writeExtraEntry, generateTypeDefs, -}; + getRollupInputs, + getRollupOutput, +}