diff --git a/packages/upgrade/.yarn-offline-mirror/@mrmlnc-readdir-enhanced-2.2.1.tgz b/packages/upgrade/.yarn-offline-mirror/@mrmlnc-readdir-enhanced-2.2.1.tgz new file mode 100644 index 000000000000..dc876969e6ad Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/@mrmlnc-readdir-enhanced-2.2.1.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/@nodelib-fs.stat-1.1.3.tgz b/packages/upgrade/.yarn-offline-mirror/@nodelib-fs.stat-1.1.3.tgz new file mode 100644 index 000000000000..e5cb5d50b790 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/@nodelib-fs.stat-1.1.3.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/call-me-maybe-1.0.1.tgz b/packages/upgrade/.yarn-offline-mirror/call-me-maybe-1.0.1.tgz new file mode 100644 index 000000000000..73d5546e73eb Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/call-me-maybe-1.0.1.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/camelcase-5.0.0.tgz b/packages/upgrade/.yarn-offline-mirror/camelcase-5.0.0.tgz new file mode 100644 index 000000000000..cddba37f2c02 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/camelcase-5.0.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/fast-glob-2.2.6.tgz b/packages/upgrade/.yarn-offline-mirror/fast-glob-2.2.6.tgz new file mode 100644 index 000000000000..5b4966fdf5e8 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/fast-glob-2.2.6.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/glob-parent-3.1.0.tgz b/packages/upgrade/.yarn-offline-mirror/glob-parent-3.1.0.tgz new file mode 100644 index 000000000000..95901ec56da0 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/glob-parent-3.1.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/glob-to-regexp-0.3.0.tgz b/packages/upgrade/.yarn-offline-mirror/glob-to-regexp-0.3.0.tgz new file mode 100644 index 000000000000..b43595f7dbfd Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/glob-to-regexp-0.3.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/invert-kv-2.0.0.tgz b/packages/upgrade/.yarn-offline-mirror/invert-kv-2.0.0.tgz new file mode 100644 index 000000000000..1bbae5716e82 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/invert-kv-2.0.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/is-glob-3.1.0.tgz b/packages/upgrade/.yarn-offline-mirror/is-glob-3.1.0.tgz new file mode 100644 index 000000000000..49abf2e262fb Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/is-glob-3.1.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/lcid-2.0.0.tgz b/packages/upgrade/.yarn-offline-mirror/lcid-2.0.0.tgz new file mode 100644 index 000000000000..94ff786fd4f2 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/lcid-2.0.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/lodash.clonedeep-4.5.0.tgz b/packages/upgrade/.yarn-offline-mirror/lodash.clonedeep-4.5.0.tgz new file mode 100644 index 000000000000..16127a1b3e15 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/lodash.clonedeep-4.5.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/map-age-cleaner-0.1.3.tgz b/packages/upgrade/.yarn-offline-mirror/map-age-cleaner-0.1.3.tgz new file mode 100644 index 000000000000..2746037ffc50 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/map-age-cleaner-0.1.3.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/mem-4.0.0.tgz b/packages/upgrade/.yarn-offline-mirror/mem-4.0.0.tgz new file mode 100644 index 000000000000..dead3d9a08a8 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/mem-4.0.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/merge2-1.2.3.tgz b/packages/upgrade/.yarn-offline-mirror/merge2-1.2.3.tgz new file mode 100644 index 000000000000..a866b9e43a14 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/merge2-1.2.3.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/os-locale-3.1.0.tgz b/packages/upgrade/.yarn-offline-mirror/os-locale-3.1.0.tgz new file mode 100644 index 000000000000..094db49ccf45 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/os-locale-3.1.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/p-defer-1.0.0.tgz b/packages/upgrade/.yarn-offline-mirror/p-defer-1.0.0.tgz new file mode 100644 index 000000000000..ed54d412d8cb Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/p-defer-1.0.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/p-is-promise-1.1.0.tgz b/packages/upgrade/.yarn-offline-mirror/p-is-promise-1.1.0.tgz new file mode 100644 index 000000000000..cef35680b47c Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/p-is-promise-1.1.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/path-dirname-1.0.2.tgz b/packages/upgrade/.yarn-offline-mirror/path-dirname-1.0.2.tgz new file mode 100644 index 000000000000..d363eec47f46 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/path-dirname-1.0.2.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/y18n-4.0.0.tgz b/packages/upgrade/.yarn-offline-mirror/y18n-4.0.0.tgz new file mode 100644 index 000000000000..8c1fa1621234 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/y18n-4.0.0.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/yargs-12.0.5.tgz b/packages/upgrade/.yarn-offline-mirror/yargs-12.0.5.tgz new file mode 100644 index 000000000000..c2b6ea21e77e Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/yargs-12.0.5.tgz differ diff --git a/packages/upgrade/.yarn-offline-mirror/yargs-parser-11.1.1.tgz b/packages/upgrade/.yarn-offline-mirror/yargs-parser-11.1.1.tgz new file mode 100644 index 000000000000..a36aa9552196 Binary files /dev/null and b/packages/upgrade/.yarn-offline-mirror/yargs-parser-11.1.1.tgz differ diff --git a/packages/upgrade/bin/carbon-upgrade.js b/packages/upgrade/bin/carbon-upgrade.js index 0c52de8ba526..6d3ca91c3ad4 100755 --- a/packages/upgrade/bin/carbon-upgrade.js +++ b/packages/upgrade/bin/carbon-upgrade.js @@ -37,7 +37,7 @@ if (major < 8) { process.exit(1); } -var main = require('../src'); +var main = require('../src/cli'); main(process).catch(error => { console.error(error); diff --git a/packages/upgrade/fixtures/carbon-colors/a.scss b/packages/upgrade/fixtures/carbon-colors/a.scss new file mode 100644 index 000000000000..5e1248f0f3d2 --- /dev/null +++ b/packages/upgrade/fixtures/carbon-colors/a.scss @@ -0,0 +1,7 @@ +.selector { + color: $ibm-colors__blue--50; +} + +.animated { + transition-timing-function: map-get($easings, productive); +} diff --git a/packages/upgrade/fixtures/carbon-colors/package.json b/packages/upgrade/fixtures/carbon-colors/package.json index 63fd1cdf08dd..da4657dca456 100644 --- a/packages/upgrade/fixtures/carbon-colors/package.json +++ b/packages/upgrade/fixtures/carbon-colors/package.json @@ -1,5 +1,7 @@ { "dependencies": { - "@carbon/colors": "0.0.1-alpha.27" + "@carbon/colors": "0.0.1-alpha.27", + "@carbon/motion": "0.0.1-alpha.27", + "carbon-components": "9.x" } } diff --git a/packages/upgrade/package.json b/packages/upgrade/package.json index 1cb9775593b5..f4a89d040f15 100644 --- a/packages/upgrade/package.json +++ b/packages/upgrade/package.json @@ -15,9 +15,13 @@ }, "dependencies": { "chalk": "^2.4.2", - "commander": "^2.19.0", + "fast-glob": "^2.2.6", "fs-extra": "^7.0.1", - "inquirer": "^6.2.1" + "inquirer": "^6.2.1", + "jest-diff": "^23.6.0", + "lodash.clonedeep": "^4.5.0", + "semver": "^5.6.0", + "yargs": "^12.0.5" }, "devDependencies": { "@commitlint/cli": "^7.3.2", diff --git a/packages/upgrade/src/__mocks__/reporter.js b/packages/upgrade/src/__mocks__/reporter.js new file mode 100644 index 000000000000..bffabaeb79c2 --- /dev/null +++ b/packages/upgrade/src/__mocks__/reporter.js @@ -0,0 +1,21 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +module.exports = { + reporter: { + error: jest.fn(), + header: jest.fn(), + info: jest.fn(), + log: jest.fn(), + setLogLevel: jest.fn(), + stack: jest.fn(), + success: jest.fn(), + verbose: jest.fn(), + }, +}; diff --git a/packages/upgrade/src/cli.js b/packages/upgrade/src/cli.js new file mode 100644 index 000000000000..1c8b9394b1eb --- /dev/null +++ b/packages/upgrade/src/cli.js @@ -0,0 +1,101 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const cli = require('yargs'); +const packageJson = require('../package.json'); +const { UpgradeError } = require('./error'); +const { reporter } = require('./reporter'); +const { run, runInDirectory } = require('./runner'); + +async function main({ argv, cwd }) { + cli.scriptName(packageJson.name).version(packageJson.version); + + cli + .option('verbose', { + default: false, + describe: 'display the full output while running a command', + }) + .option('dry', { + alias: 'd', + describe: + 'view the result of running this command without changing any files', + default: false, + }) + .option('ignore', { + alias: 'i', + describe: 'provide a glob pattern for directories you would like ignored', + default: '', + }); + + cli + .usage('Usage: $0 [options]') + .command('$0', 'run to upgrade your project', {}, async args => { + const { dry, ignore, verbose } = args; + const options = { + cwd: cwd(), + dry, + ignore, + verbose, + }; + + await runCommand(() => runInDirectory(options), options); + }); + + cli.command( + 'migrate ', + 'run a specific migration for a package', + {}, + async args => { + const { dry, from, ignore, package: packageName, to, verbose } = args; + const options = { + cwd: cwd(), + dry, + ignore, + verbose, + }; + + await runCommand(() => run(packageName, from, to, options), options); + } + ); + + cli + .demandCommand() + .recommendCommands() + .strict() + .parse(argv.slice(2)).argv; +} + +async function runCommand(makePromise, options) { + reporter.info('Thanks for trying out carbon-upgrade! 🙏'); + reporter.info( + 'To help prevent any accidental changes, make sure to check in your ' + + 'work in version control first and use dry mode (-d flag) to ' + + 'preview any updates!' + ); + + if (options.verbose) { + reporter.setLogLevel('verbose'); + } + + try { + const start = Date.now(); + await makePromise(); + console.log(`✨ Done in ${Date.now() - start}ms`); + } catch (error) { + if (error instanceof UpgradeError) { + reporter.error(error.message); + return; + } + reporter.error('Yikes, looks like something really went wrong.'); + reporter.error('Please make an issue with the following info:'); + console.log(error); + } +} + +module.exports = main; diff --git a/packages/upgrade/src/__tests__/carbon-upgrade-test.js b/packages/upgrade/src/error.js similarity index 72% rename from packages/upgrade/src/__tests__/carbon-upgrade-test.js rename to packages/upgrade/src/error.js index d641690f75fb..5d1e983c019c 100644 --- a/packages/upgrade/src/__tests__/carbon-upgrade-test.js +++ b/packages/upgrade/src/error.js @@ -3,12 +3,12 @@ * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. - * - * @jest-environment node */ 'use strict'; -test('should work', () => { - // ... -}); +class UpgradeError extends Error {} + +module.exports = { + UpgradeError, +}; diff --git a/packages/upgrade/src/index.js b/packages/upgrade/src/index.js deleted file mode 100644 index 102fe5459da0..000000000000 --- a/packages/upgrade/src/index.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright IBM Corp. 2019, 2019 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ - -'use strict'; - -const program = require('commander'); -const packageJson = require('../package.json'); -const { reporter } = require('./reporter'); -const run = require('./run'); - -async function main({ argv, cwd }) { - program - .name(packageJson.name) - .version(packageJson.version) - .usage('[options]') - .option( - '-d, --dry', - 'view the result of running this command without changing any files', - false - ) - .option( - '--verbose', - 'display the full output while running this command', - false - ) - .action(async cmd => { - const { dry = false, verbose = false } = cmd; - if (verbose) { - reporter.setLogLevel('verbose'); - } - - try { - await run({ cwd: cwd(), dry, verbose }); - } catch (error) { - console.log( - 'Yikes, looks like something went wrong running this command' - ); - console.log('Please make an issue with the following info:'); - console.log(error); - process.exit(1); - } - }) - .parse(argv); -} - -module.exports = main; diff --git a/packages/upgrade/src/migrations/carbon-colors/0.0.1-alpha.28.js b/packages/upgrade/src/migrations/carbon-colors/0.0.1-alpha.28.js deleted file mode 100644 index 8dc847bbac64..000000000000 --- a/packages/upgrade/src/migrations/carbon-colors/0.0.1-alpha.28.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright IBM Corp. 2019, 2019 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ - -'use strict'; - -const { reporter } = require('../../reporter'); - -const TARGET_VERSION = '0.0.1-alpha.28'; - -module.exports = { - version: TARGET_VERSION, - from: [ - { - version: '0.0.1-alpha.27', - async migrate(dependency, cwd) { - reporter.info( - 'Running migration from 0.0.1-alpha.27 to 0.0.0-alpha.28' - ); - }, - }, - ], -}; diff --git a/packages/upgrade/src/migrations/carbon-colors/0.0.1-alpha.31.js b/packages/upgrade/src/migrations/carbon-colors/0.0.1-alpha.31.js new file mode 100644 index 000000000000..55a41b728fbb --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-colors/0.0.1-alpha.31.js @@ -0,0 +1,35 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const { reporter } = require('../../reporter'); +const { replace } = require('../../tools/replace'); + +const TARGET_VERSION = '0.0.1-alpha.31'; + +module.exports = { + version: TARGET_VERSION, + from: [ + { + version: '<=0.0.1-alpha.30', + async migrate(options) { + const changes = [ + { + from: /(\$ibm-colors__[a-z]+)(--)([\d]+)/gm, + // Capture group $1 refers to $ibm-colors__abcd + // $2 refers to double dash (--) + // $3 is the grade at the end + to: '$1-$3', + }, + ]; + + await replace('**/*.scss', changes, options); + }, + }, + ], +}; diff --git a/packages/upgrade/src/migrations/carbon-colors/__tests__/0.0.1-alpha.31.js b/packages/upgrade/src/migrations/carbon-colors/__tests__/0.0.1-alpha.31.js new file mode 100644 index 000000000000..59415f3482c5 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-colors/__tests__/0.0.1-alpha.31.js @@ -0,0 +1,29 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + * + * @jest-environment node + */ + +'use strict'; + +const { defineInlineTest } = require('../../../tools/testing'); + +defineInlineTest( + require.resolve('../0.0.1-alpha.31.js'), + '0.0.1-alpha.30', + ` +$ibm-colors__blue--50; +$ibm-colors__teal--50; + color: $ibm-colors__blue--50; + color: $ibm-colors__teal--50; + `, + ` +$ibm-colors__blue-50; +$ibm-colors__teal-50; + color: $ibm-colors__blue-50; + color: $ibm-colors__teal-50; + ` +); diff --git a/packages/upgrade/src/migrations/carbon-colors/index.js b/packages/upgrade/src/migrations/carbon-colors/index.js index 7db9cb91b413..0bcb13ea04c2 100644 --- a/packages/upgrade/src/migrations/carbon-colors/index.js +++ b/packages/upgrade/src/migrations/carbon-colors/index.js @@ -7,7 +7,7 @@ 'use strict'; -const migrations = new Set([require('./0.0.1-alpha.28')]); +const migrations = new Set([require('./0.0.1-alpha.31')]); module.exports = { name: '@carbon/colors', diff --git a/packages/upgrade/src/migrations/carbon-elements/0.0.1-alpha.31.js b/packages/upgrade/src/migrations/carbon-elements/0.0.1-alpha.31.js new file mode 100644 index 000000000000..628844f3a56d --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-elements/0.0.1-alpha.31.js @@ -0,0 +1,36 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const { reporter } = require('../../reporter'); +const colors = require('../carbon-colors/0.0.1-alpha.31'); +const grid = require('../carbon-grid/0.0.1-alpha.31'); +const layout = require('../carbon-layout/0.0.1-alpha.31'); +const motion = require('../carbon-motion/0.0.1-alpha.31'); + +const TARGET_VERSION = '0.0.1-alpha.31'; + +module.exports = { + version: TARGET_VERSION, + from: [ + { + version: '<=0.0.1-alpha.30', + async migrate(options) { + const migrations = [ + ...colors.from, + ...grid.from, + ...layout.from, + ...motion.from, + ].filter(({ version }) => version === '<=0.0.1-alpha.30'); + await Promise.all( + migrations.map(migration => migration.migrate(options)) + ); + }, + }, + ], +}; diff --git a/packages/upgrade/src/migrations/carbon-elements/__tests__/0.0.1-alpha.31.js b/packages/upgrade/src/migrations/carbon-elements/__tests__/0.0.1-alpha.31.js new file mode 100644 index 000000000000..5c3c68d34897 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-elements/__tests__/0.0.1-alpha.31.js @@ -0,0 +1,30 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + * + * @jest-environment node + */ + +'use strict'; + +const { defineInlineTest } = require('../../../tools/testing'); + +// Sanity check that at least one of our packages are working +defineInlineTest( + require.resolve('../0.0.1-alpha.31.js'), + '0.0.1-alpha.30', + ` +$ibm-colors__blue--50; +$ibm-colors__teal--50; + color: $ibm-colors__blue--50; + color: $ibm-colors__teal--50; + `, + ` +$ibm-colors__blue-50; +$ibm-colors__teal-50; + color: $ibm-colors__blue-50; + color: $ibm-colors__teal-50; + ` +); diff --git a/packages/upgrade/src/migrations/carbon-elements/index.js b/packages/upgrade/src/migrations/carbon-elements/index.js new file mode 100644 index 000000000000..9a9845dec929 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-elements/index.js @@ -0,0 +1,15 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const migrations = new Set([require('./0.0.1-alpha.31')]); + +module.exports = { + name: '@carbon/elements', + migrations, +}; diff --git a/packages/upgrade/src/migrations/carbon-grid/0.0.1-alpha.31.js b/packages/upgrade/src/migrations/carbon-grid/0.0.1-alpha.31.js new file mode 100644 index 000000000000..89bf511c092c --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-grid/0.0.1-alpha.31.js @@ -0,0 +1,76 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const { reporter } = require('../../reporter'); +const { replace } = require('../../tools/replace'); +const { + createFunctionRegex, + createVariableRegex, +} = require('../../tools/regex'); + +const TARGET_VERSION = '0.0.1-alpha.31'; +const changes = [ + // Columns + { + filename: '_col.scss', + from: createFunctionRegex('make-col-ready'), + to: 'carbon--make-col-ready', + }, + { + filename: '_col.scss', + from: createFunctionRegex('make-col'), + to: 'carbon--make-col', + }, + { + filename: '_col.scss', + from: createFunctionRegex('make-col-offset'), + to: 'carbon--make-col-offset', + }, + { + filename: '_col.scss', + from: createFunctionRegex('make-grid-columns'), + to: 'carbon--make-grid-columns', + }, + + // Container + { + filename: '_container.scss', + from: createFunctionRegex('make-container'), + to: 'carbon--make-container', + }, + { + filename: '_container.scss', + from: createFunctionRegex('set-largest-breakpoint'), + to: 'carbon--set-largest-breakpoint', + }, + { + filename: '_container.scss', + from: createFunctionRegex('make-container-max-widths'), + to: 'carbon--make-container-max-widths', + }, + + // Row + { + filename: '_row.scss', + from: createFunctionRegex('make-row'), + to: 'carbon--make-row', + }, +]; + +module.exports = { + version: TARGET_VERSION, + from: [ + { + version: '<=0.0.1-alpha.30', + async migrate(options) { + await replace('**/*.scss', changes, options); + }, + }, + ], +}; diff --git a/packages/upgrade/src/migrations/carbon-grid/index.js b/packages/upgrade/src/migrations/carbon-grid/index.js new file mode 100644 index 000000000000..7f77d5299328 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-grid/index.js @@ -0,0 +1,15 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const migrations = new Set([require('./0.0.1-alpha.31')]); + +module.exports = { + name: '@carbon/grid', + migrations, +}; diff --git a/packages/upgrade/src/migrations/carbon-layout/0.0.1-alpha.31.js b/packages/upgrade/src/migrations/carbon-layout/0.0.1-alpha.31.js new file mode 100644 index 000000000000..6131f57954b4 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-layout/0.0.1-alpha.31.js @@ -0,0 +1,168 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const { reporter } = require('../../reporter'); +const { replace } = require('../../tools/replace'); +const { + createFunctionRegex, + createVariableRegex, +} = require('../../tools/regex'); + +const TARGET_VERSION = '0.0.1-alpha.31'; +const changes = [ + // Breakpoints + { + filename: '_breakpoint.scss', + from: createVariableRegex('grid-cell-padding'), + to: '$carbon--grid-cell-padding', + }, + { + filename: '_breakpoint.scss', + from: createVariableRegex('grid-gutter'), + to: '$carbon--grid-gutter', + }, + { + filename: '_breakpoint.scss', + from: createVariableRegex('grid-breakpoints'), + to: '$carbon--grid-breakpoints', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('breakpoint-next'), + to: 'carbon--breakpoint-next', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('breakpoint-prev'), + to: 'carbon--breakpoint-prev', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('is-smallest-breakpoint'), + to: 'carbon--is-smallest-breakpoint', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('largest-breakpoint-name'), + to: 'carbon--largest-breakpoint-name', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('largest-breakpoint'), + to: 'carbon--largest-breakpoint', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('breakpoint-infix'), + to: 'carbon--breakpoint-infix', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('breakpoint-up'), + to: 'carbon--breakpoint-up', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('breakpoint-down'), + to: 'carbon--breakpoint-down', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('breakpoint-between'), + to: 'carbon--breakpoint-between', + }, + { + filename: '_breakpoint.scss', + from: createFunctionRegex('breakpoint'), + to: 'carbon--breakpoint', + }, + + // Conversion + { + filename: '_convert.scss', + // from: /\$base-font-size/gm, + from: createVariableRegex('base-font-size'), + to: '$carbon--base-font-size', + }, + { + filename: '_convert.scss', + from: createFunctionRegex('rem'), + to: 'carbon--rem', + }, + { + filename: '_convert.scss', + from: createFunctionRegex('em'), + to: 'carbon--em', + }, + + // Key heights + { + filename: '_key-height.scss', + from: createFunctionRegex('get-column-width'), + to: 'carbon--get-column-width', + }, + { + filename: '_key-height.scss', + from: createVariableRegex('key-height-scales'), + to: '$carbon--key-height-scales', + }, + { + filename: '_key-height.scss', + from: createFunctionRegex('key-height'), + to: 'carbon--key-height', + }, + + // Mini-units + { + filename: '_mini-unit.scss', + from: createVariableRegex('mini-unit-size'), + to: '$carbon--mini-unit-size', + }, + { + filename: '_mini-unit.scss', + from: createFunctionRegex('mini-units'), + to: 'carbon--mini-units', + }, + + // Spacing + { + filename: '_spacing.scss', + from: createVariableRegex('fixed-spacing-scale'), + to: '$carbon--fixed-spacing-scale', + }, + { + filename: '_spacing.scss', + from: createVariableRegex('fluid-spacing-scale'), + to: '$carbon--fluid-spacing-scale', + }, + { + filename: '_mini-unit.scss', + from: createFunctionRegex('spacing'), + to: 'carbon--spacing', + }, + + // Utilities + { + filename: '_utilities.scss', + from: createFunctionRegex('key-by-index'), + to: 'carbon--key-by-index', + }, +]; + +module.exports = { + version: TARGET_VERSION, + from: [ + { + version: '<=0.0.1-alpha.30', + async migrate(options) { + await replace('**/*.scss', changes, options); + }, + }, + ], +}; diff --git a/packages/upgrade/src/migrations/carbon-layout/index.js b/packages/upgrade/src/migrations/carbon-layout/index.js new file mode 100644 index 000000000000..6be844e966c6 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-layout/index.js @@ -0,0 +1,15 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const migrations = new Set([require('./0.0.1-alpha.31')]); + +module.exports = { + name: '@carbon/layout', + migrations, +}; diff --git a/packages/upgrade/src/migrations/carbon-motion/0.0.1-alpha.31.js b/packages/upgrade/src/migrations/carbon-motion/0.0.1-alpha.31.js new file mode 100644 index 000000000000..342f70be1c01 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-motion/0.0.1-alpha.31.js @@ -0,0 +1,42 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const { reporter } = require('../../reporter'); +const { replace } = require('../../tools/replace'); +const { + createFunctionRegex, + createVariableRegex, +} = require('../../tools/regex'); + +const TARGET_VERSION = '0.0.1-alpha.31'; + +module.exports = { + version: TARGET_VERSION, + from: [ + { + version: '<=0.0.1-alpha.30', + async migrate(options) { + const changes = [ + { + filename: 'motion.scss', + from: createVariableRegex('easings'), + to: '$carbon--easings', + }, + { + filename: 'motion.scss', + from: createFunctionRegex('motion'), + to: 'carbon--motion', + }, + ]; + + await replace('**/*.scss', changes, options); + }, + }, + ], +}; diff --git a/packages/upgrade/src/migrations/carbon-motion/index.js b/packages/upgrade/src/migrations/carbon-motion/index.js new file mode 100644 index 000000000000..e78886d30780 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-motion/index.js @@ -0,0 +1,15 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const migrations = new Set([require('./0.0.1-alpha.31')]); + +module.exports = { + name: '@carbon/motion', + migrations, +}; diff --git a/packages/upgrade/src/migrations/carbon-type/0.0.1-alpha.31.js b/packages/upgrade/src/migrations/carbon-type/0.0.1-alpha.31.js new file mode 100644 index 000000000000..be3fac470842 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-type/0.0.1-alpha.31.js @@ -0,0 +1,103 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const { reporter } = require('../../reporter'); +const { replace } = require('../../tools/replace'); +const { + createFunctionRegex, + createVariableRegex, +} = require('../../tools/regex'); + +const TARGET_VERSION = '0.0.1-alpha.31'; + +module.exports = { + version: TARGET_VERSION, + from: [ + { + version: '<=0.0.1-alpha.30', + async migrate(options) { + const changes = [ + // Classes + { + filename: '_classes.scss', + from: createFunctionRegex('type-classes'), + to: 'carbon--type-classes', + }, + + // Font family + { + filename: '_font-family.scss', + from: createVariableRegex('font-families'), + to: '$carbon--font-families', + }, + { + filename: '_font-family.scss', + from: createFunctionRegex('font-family'), + to: 'carbon--font-family', + }, + { + filename: '_font-family.scss', + from: createVariableRegex('font-weights'), + to: '$carbon--font-weights', + }, + { + filename: '_font-family.scss', + from: createFunctionRegex('font-weight'), + to: 'carbon--font-weight', + }, + + // Reset + { + filename: '_reset.scss', + from: createFunctionRegex('type-reset'), + to: 'carbon--type-reset', + }, + + // Scale + { + filename: '_scale.scss', + from: createFunctionRegex('get-type-size'), + to: 'carbon--get-type-size', + }, + { + filename: '_scale.scss', + from: createVariableRegex('type-scale'), + to: '$carbon--type-scale', + }, + { + filename: '_scale.scss', + from: createFunctionRegex('font-size'), + to: 'carbon--font-size', + }, + + // Spacing + { + filename: '_spacing.scss', + from: createVariableRegex('type-tokens'), + to: '$carbon--type-tokens', + }, + { + filename: '_spacing.scss', + from: createFunctionRegex('type-spacing'), + to: 'carbon--type-spacing', + }, + + // Styles + { + filename: '_styles.scss', + from: createFunctionRegex('type-style'), + to: 'carbon--type-style', + }, + ]; + + await replace('**/*.scss', changes, options); + }, + }, + ], +}; diff --git a/packages/upgrade/src/migrations/carbon-type/index.js b/packages/upgrade/src/migrations/carbon-type/index.js new file mode 100644 index 000000000000..f4112fbeaa73 --- /dev/null +++ b/packages/upgrade/src/migrations/carbon-type/index.js @@ -0,0 +1,15 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const migrations = new Set([require('./0.0.1-alpha.31')]); + +module.exports = { + name: '@carbon/type', + migrations, +}; diff --git a/packages/upgrade/src/migrations/index.js b/packages/upgrade/src/migrations/index.js index a093f2c164f6..29f7536cba88 100644 --- a/packages/upgrade/src/migrations/index.js +++ b/packages/upgrade/src/migrations/index.js @@ -8,7 +8,21 @@ 'use strict'; const colors = require('./carbon-colors'); +const elements = require('./carbon-elements'); +const grid = require('./carbon-grid'); +const layout = require('./carbon-layout'); +const motion = require('./carbon-motion'); +const type = require('./carbon-type'); -const migrations = new Map([[colors.name, colors.migrations]]); +const supportedPackages = new Map([ + [colors.name, colors.migrations], + [elements.name, elements.migrations], + [grid.name, grid.migrations], + [layout.name, layout.migrations], + [motion.name, motion.migrations], + [type.name, type.migrations], +]); -module.exports = migrations; +module.exports = { + supportedPackages, +}; diff --git a/packages/upgrade/src/project.js b/packages/upgrade/src/project.js index 455c31f40f0d..6518596178df 100644 --- a/packages/upgrade/src/project.js +++ b/packages/upgrade/src/project.js @@ -9,6 +9,7 @@ const fs = require('fs-extra'); const path = require('path'); +const { UpgradeError } = require('./error'); async function findPackageJson(folder) { let currentDirectory = folder; @@ -22,7 +23,9 @@ async function findPackageJson(folder) { } if (path.dirname(currentDirectory) === '/' && currentDirectory === '/') { - throw new Error('Unable to find package.json'); + throw new UpgradeError( + `Unable to find a \`package.json\` file in ${folder}` + ); } return path.join(currentDirectory, 'package.json'); diff --git a/packages/upgrade/src/reporter.js b/packages/upgrade/src/reporter.js index ee93b1f03812..7ef21283fe8b 100644 --- a/packages/upgrade/src/reporter.js +++ b/packages/upgrade/src/reporter.js @@ -1,3 +1,10 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + 'use strict'; const chalk = require('chalk'); @@ -32,8 +39,9 @@ class ConsoleReporter { this.log(this.format.bold(message)); } - info(message) { - this._logCategory('info', 'blue', chalk.white(message)); + info(...args) { + const message = args.length !== 0 ? args.join(' ') : ''; + this._logCategory('info', 'blue', message); } log(message = '') { diff --git a/packages/upgrade/src/run.js b/packages/upgrade/src/run.js deleted file mode 100644 index 4779ee9ed1a5..000000000000 --- a/packages/upgrade/src/run.js +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright IBM Corp. 2019, 2019 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ - -'use strict'; - -const fs = require('fs-extra'); -const inquirer = require('inquirer'); -const { findPackageJson } = require('./project'); -const { reporter } = require('./reporter'); -const safeAsync = require('./tools/safeAsync'); -const supportedPackageMigrations = require('./migrations'); - -async function run({ cwd, dry }) { - reporter.info('Thanks for trying out carbon-upgrade! 🙏'); - - const [result, findPackageJsonError] = await safeAsync(findPackageJson(cwd)); - if (findPackageJsonError) { - throw new Error(`Unable to find package.json file in: ${cwd}`); - } - - const [packageJsonPath] = result; - const packageJson = await fs.readJson(packageJsonPath); - const { dependencies = {}, devDependencies = {} } = packageJson; - const packageDependencies = [ - ...Object.keys(dependencies).map(name => ({ - name, - version: dependencies[name], - type: 'dependency', - })), - ...Object.keys(devDependencies).map(name => ({ - name, - version: devDependencies[name], - type: 'devDependency', - })), - ]; - - // TODO: make sure we don't double run a migration for a dependency - - const dependenciesToMigrate = packageDependencies - .map(dependency => { - if (supportedPackageMigrations.has(dependency.name)) { - const packageMigrations = supportedPackageMigrations.get( - dependency.name - ); - - for (const migration of packageMigrations) { - for (const { migrate, version } of migration.from) { - if (version === dependency.version) { - return [dependency, migrate, migration.version]; - } - } - } - } - return false; - }) - .filter(Boolean); - - if (dependenciesToMigrate.length === 0) { - reporter.info( - `No migrations found for dependencies in ${packageJsonPath}.` - ); - } else { - const answers = await inquirer.prompt({ - type: 'checkbox', - name: 'dependencies', - message: 'Select the migrations you would like us to run:', - choices: dependenciesToMigrate.map(([dependency, _, version]) => { - return { - name: createChoiceFrom(dependency, version), - short: dependency.name, - checked: true, - }; - }), - }); - - if (answers.dependencies.length > 0) { - await Promise.all( - dependenciesToMigrate - .filter(([dependency, _, version]) => { - return answers.dependencies.includes( - createChoiceFrom(dependency, version) - ); - }) - .map(([dependency, migrate]) => { - // TODO update package.json, making sure to respect dry option - return migrate(dependency, cwd); - }) - ); - } - } - - reporter.success('Done! ✨'); -} - -function createChoiceFrom(dependency, version) { - return `${dependency.name} from ${dependency.version} to ${version}`; -} - -module.exports = run; diff --git a/packages/upgrade/src/runner.js b/packages/upgrade/src/runner.js new file mode 100644 index 000000000000..996acad96ace --- /dev/null +++ b/packages/upgrade/src/runner.js @@ -0,0 +1,169 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const cloneDeep = require('lodash.clonedeep'); +const diff = require('jest-diff'); +const fs = require('fs-extra'); +const inquirer = require('inquirer'); +const path = require('path'); +const semver = require('semver'); +const { UpgradeError } = require('./error'); +const { supportedPackages } = require('./migrations'); +const { reporter } = require('./reporter'); + +async function run(packageName, from, to, options) { + if (!supportedPackages.has(packageName)) { + throw new UpgradeError( + `No support available for package \`${packageName}\`` + ); + } + + const packageMigrations = supportedPackages.get(packageName); + const migrationsForVersion = find(packageMigrations, versionMigration => { + return versionMigration.version === to; + }); + const migration = migrationsForVersion.from.find(migration => { + return semver.satisfies(from, migration.version); + }); + + if (!migration) { + throw new UpgradeError( + `No support available for updating package \`${packageName}\` to ` + + `version ${to} from ${from}` + ); + } + + reporter.info( + 'Running migration for:', + packageName, + 'from:', + from, + 'to:', + to + ); + + await migration.migrate(options); +} + +async function runInDirectory(options) { + const packageJsonPath = path.join(options.cwd, 'package.json'); + + if (!fs.existsSync(packageJsonPath)) { + throw new UpgradeError( + `Unable to find a \`package.json\` file at ${packageJsonPath}. ` + + `Please run at the root of your project where this file is located.` + ); + } + + const packageJson = await fs.readJson(packageJsonPath); + const { + dependencies = {}, + devDependencies = {}, + peerDependencies = {}, + } = packageJson; + const packageDependencies = [ + ...Object.keys(dependencies).map(name => ({ + name, + version: dependencies[name], + type: 'dependencies', + })), + ...Object.keys(devDependencies).map(name => ({ + name, + version: devDependencies[name], + type: 'devDependencies', + })), + ...Object.keys(peerDependencies).map(name => ({ + name, + version: peerDependencies[name], + type: 'peerDependencies', + })), + ] + .reduce((acc, pkg) => { + if (acc.find(({ name }) => name === pkg.name)) { + return acc; + } + return acc.concat(pkg); + }, []) + .filter(pkg => supportedPackages.has(pkg.name)); + + if (packageDependencies.length === 0) { + reporter.info( + "Yikes! We're sorry, but there does not seem to be a package in your " + + '`package.json` file that we can migrate.' + ); + } + + const questions = packageDependencies.map(dependency => { + const { name, version } = dependency; + const supportedVersions = supportedPackages.get(name); + return { + name, + type: 'list', + message: `Choose which version you would like to migrate to for ${name}`, + choices: [...supportedVersions] + .filter(supportedVersion => { + return semver.gte(supportedVersion.version, version); + }) + .map(supportedVersion => ({ + name: supportedVersion.version, + })), + }; + }); + + const answers = await inquirer.prompt(questions); + const nextPackageJson = cloneDeep(packageJson); + + for (const name of Object.keys(answers)) { + const dependency = packageDependencies.find( + dependency => dependency.name === name + ); + const to = answers[name]; + + await run(dependency.name, dependency.version, to, options); + + nextPackageJson[dependency.type][dependency.name] = to; + } + + if (options.dry) { + reporter.info('Your package.json file will change to:'); + console.log(); + console.log(diff(packageJson, nextPackageJson, { expand: false })); + console.log(); + } else { + await fs.writeFile(packageJsonPath, nextPackageJson); + } + + reporter.info( + "Migrations completed successfully! Make sure to run your project's install" + + 'command to get the latest dependencies' + ); +} + +function find(set, cb) { + for (const item of set) { + if (cb(item)) { + return item; + } + } +} + +function filter(set, cb) { + const s = new Set(); + for (const item of set) { + if (cb(item)) { + s.add(item); + } + } + return s; +} + +module.exports = { + run, + runInDirectory, +}; diff --git a/packages/upgrade/src/tools/__tests__/regex-test.js b/packages/upgrade/src/tools/__tests__/regex-test.js new file mode 100644 index 000000000000..66763cac5650 --- /dev/null +++ b/packages/upgrade/src/tools/__tests__/regex-test.js @@ -0,0 +1,113 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + * + * @jest-environment node + */ + +'use strict'; + +const { createFunctionRegex, createVariableRegex } = require('../regex'); + +describe('regex', () => { + describe('createFunctionRegex', () => { + it('should match a function or mixin', () => { + const regex = createFunctionRegex('foo'); + expect('@function foo() {}'.match(regex)).not.toBe(null); + expect('@mixin foo() {}'.match(regex)).not.toBe(null); + expect('foo'.match(regex)).toBe(null); + }); + + it('should not match with a partial match', () => { + const regex = createFunctionRegex('em'); + expect('@function em() {}'.match(regex)).not.toBe(null); + expect('@mixin em() {}'.match(regex)).not.toBe(null); + + expect('@function rem() {}'.match(regex)).toBe(null); + expect('@mixin rem() {}'.match(regex)).toBe(null); + }); + + it('should match a multiline function or mixin', () => { + const regex = createFunctionRegex('foo'); + expect( + `@function foo( +$a, +$b +) {}`.match(regex) + ).not.toBe(null); + expect( + `@mixin foo( +$a, +$b +) {}`.match(regex) + ).not.toBe(null); + }); + + it('should match when called in an expression', () => { + const regex = createFunctionRegex('foo'); + expect( + ` +.selector { + @include foo(); +} +`.match(regex) + ).not.toBe(null); + + expect( + ` +.selector { + @include foo( + 1 + ); +} +`.match(regex) + ).not.toBe(null); + + expect( + ` +.selector { + color: foo(); +} +`.match(regex) + ).not.toBe(null); + + expect( + ` +.selector { + color: foo( + 1 + ); +} +`.match(regex) + ).not.toBe(null); + }); + + it('should work in a nested function call', () => { + const regex = createFunctionRegex('foo'); + expect( + ` +.selector { + color: bar(foo()); +} +`.match(regex) + ).not.toBe(null); + }); + }); + + describe('createVariableRegex', () => { + it('should match variables in a source file', () => { + const regex = createVariableRegex('some-variable'); + + expect(regex.test('$some-variable: 1;')).toBe(true); + expect( + regex.test(` +.foo { + color: $some-variable; +}; + `) + ).toBe(true); + }); + }); +}); diff --git a/packages/upgrade/src/tools/regex.js b/packages/upgrade/src/tools/regex.js new file mode 100644 index 000000000000..e3ffb54af819 --- /dev/null +++ b/packages/upgrade/src/tools/regex.js @@ -0,0 +1,33 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +function createFunctionRegex(name) { + const parts = [ + // Make sure there is a space before the group, useful for things that might + // intersect + '(?<=[ \\(])', + // Positive lookahead for the function definition + // Support one-line, `my-function()` and multi-line `my-function(\n` + `(?=${name}\\(.*[\)\n])`, + // Negative lookahead for checking if already migrated + '(? replaceInFile(file, changes, options))); +} + +const diffOptions = { + expand: false, +}; + +async function replaceInFile(file, changes, options) { + const { dry } = options; + const original = await fs.readFile(file, 'utf8'); + let contents = original; + + for (const change of changes) { + if (dry) { + const match = contents.match(change.from); + if (match) { + console.log(); + // TODO: handle case where change.to is a function + reporter.info( + `Replace \`${match[0]}\` with \`${change.to}\` in file ` + + path.join(options.cwd, file) + ); + console.log(); + console.log( + diff(original.replace(change.from, change.to), original, diffOptions) + ); + console.log(); + } + continue; + } + + contents = contents.replace(change.from, change.to); + } + + if (contents !== original) { + await fs.writeFile(file, contents); + } +} + +module.exports = { + replace, +}; diff --git a/packages/upgrade/src/tools/testing.js b/packages/upgrade/src/tools/testing.js new file mode 100644 index 000000000000..794b9343ab98 --- /dev/null +++ b/packages/upgrade/src/tools/testing.js @@ -0,0 +1,63 @@ +/** + * Copyright IBM Corp. 2019, 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + * + * @jest-environment node + */ + +'use strict'; + +const semver = require.requireActual('semver'); + +function defineInlineTest( + pathToMigrations, + version, + input, + expectedOutput, + testName +) { + let mockInput = input; + let mockOutput; + let mockOptions; + let migration; + + beforeEach(() => { + jest.resetModules(); + jest.mock('fs-extra', () => { + return { + async readFile() { + return mockInput; + }, + async writeFile(filename, contents) { + mockOutput = contents; + }, + }; + }); + jest.mock('fast-glob', () => { + return () => ['mock-file-for-fast-glob']; + }); + jest.mock('../reporter'); + + mockOptions = {}; + + const migrations = require(pathToMigrations); + + [migration] = migrations.from.filter(migration => { + return semver.satisfies(version, migration.version); + }); + if (!migration) { + throw new Error('Unable to find migration for version: ' + version); + } + }); + + test(testName || 'transforms correctly', async () => { + await migration.migrate(mockOptions); + expect(mockOutput.trim()).toEqual(expectedOutput.trim()); + }); +} + +module.exports = { + defineInlineTest, +}; diff --git a/packages/upgrade/yarn.lock b/packages/upgrade/yarn.lock index a97469526f46..69a79a61142e 100644 --- a/packages/upgrade/yarn.lock +++ b/packages/upgrade/yarn.lock @@ -172,6 +172,19 @@ mkdirp "^0.5.1" rimraf "^2.5.2" +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@nodelib/fs.stat@^1.1.2": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" + integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== + "@samverschueren/stream-to-observable@^0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" @@ -692,6 +705,11 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= + caller-callsite@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" @@ -737,6 +755,11 @@ camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= +camelcase@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" + integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== + capture-exit@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" @@ -874,7 +897,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@^2.14.1, commander@^2.19.0, commander@^2.9.0: +commander@^2.14.1, commander@^2.9.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== @@ -1075,7 +1098,7 @@ decamelize-keys@^1.0.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.1.1: +decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -1421,6 +1444,18 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-glob@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.6.tgz#a5d5b697ec8deda468d85a74035290a025a95295" + integrity sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w== + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.1.2" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.3" + micromatch "^3.1.10" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -1674,6 +1709,19 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= + glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -1942,6 +1990,11 @@ invert-kv@^1.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + ip-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-3.0.0.tgz#0a934694b4066558c46294244a23cc33116bf732" @@ -2068,7 +2121,7 @@ is-extglob@^1.0.0: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= -is-extglob@^2.1.1: +is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= @@ -2104,6 +2157,13 @@ is-glob@^2.0.0, is-glob@^2.0.1: dependencies: is-extglob "^1.0.0" +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + is-glob@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" @@ -2821,6 +2881,13 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + left-pad@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" @@ -2956,6 +3023,11 @@ lodash._reinterpolate@~3.0.0: resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" @@ -3034,6 +3106,13 @@ makeerror@1.0.x: dependencies: tmpl "1.0.x" +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -3075,6 +3154,15 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" +mem@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf" + integrity sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^1.0.0" + p-is-promise "^1.1.0" + meow@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" @@ -3112,6 +3200,11 @@ merge-stream@^1.0.1: dependencies: readable-stream "^2.0.1" +merge2@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5" + integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA== + merge@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" @@ -3136,7 +3229,7 @@ micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" -micromatch@^3.1.4, micromatch@^3.1.8: +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -3502,6 +3595,15 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" +os-locale@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -3515,11 +3617,21 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -3603,6 +3715,11 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -4121,7 +4238,7 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -"semver@2 || 3 || 4 || 5", semver@5.6.0, semver@^5.3.0, semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@5.6.0, semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== @@ -4863,6 +4980,11 @@ y18n@^3.2.1: resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= +"y18n@^3.2.1 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -4880,6 +5002,14 @@ yargs-parser@^10.0.0: dependencies: camelcase "^4.1.0" +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^9.0.2: version "9.0.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" @@ -4904,3 +5034,21 @@ yargs@^11.0.0: which-module "^2.0.0" y18n "^3.2.1" yargs-parser "^9.0.2" + +yargs@^12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1"