change-version.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #!/usr/bin/env node
  2. /*!
  3. * Script to update version number references in the project.
  4. * Copyright 2017-2019 The Bootstrap Authors
  5. * Copyright 2017-2019 Twitter, Inc.
  6. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  7. */
  8. 'use strict'
  9. const fs = require('fs')
  10. const path = require('path')
  11. const sh = require('shelljs')
  12. sh.config.fatal = true
  13. // Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
  14. function regExpQuote(string) {
  15. return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&')
  16. }
  17. function regExpQuoteReplacement(string) {
  18. return string.replace(/[$]/g, '$$')
  19. }
  20. const DRY_RUN = false
  21. function walkAsync(directory, excludedDirectories, fileCallback, errback) {
  22. if (excludedDirectories.has(path.parse(directory).base)) {
  23. return
  24. }
  25. fs.readdir(directory, (err, names) => {
  26. if (err) {
  27. errback(err)
  28. return
  29. }
  30. names.forEach((name) => {
  31. const filepath = path.join(directory, name)
  32. fs.lstat(filepath, (err, stats) => {
  33. if (err) {
  34. process.nextTick(errback, err)
  35. return
  36. }
  37. if (stats.isDirectory()) {
  38. process.nextTick(walkAsync, filepath, excludedDirectories, fileCallback, errback)
  39. } else if (stats.isFile()) {
  40. process.nextTick(fileCallback, filepath)
  41. }
  42. })
  43. })
  44. })
  45. }
  46. function replaceRecursively(directory, excludedDirectories, allowedExtensions, original, replacement) {
  47. original = new RegExp(regExpQuote(original), 'g')
  48. replacement = regExpQuoteReplacement(replacement)
  49. const updateFile = DRY_RUN ? (filepath) => {
  50. if (allowedExtensions.has(path.parse(filepath).ext)) {
  51. console.log(`FILE: ${filepath}`)
  52. } else {
  53. console.log(`EXCLUDED:${filepath}`)
  54. }
  55. } : (filepath) => {
  56. if (allowedExtensions.has(path.parse(filepath).ext)) {
  57. sh.sed('-i', original, replacement, filepath)
  58. }
  59. }
  60. walkAsync(directory, excludedDirectories, updateFile, (err) => {
  61. console.error('ERROR while traversing directory!:')
  62. console.error(err)
  63. process.exit(1)
  64. })
  65. }
  66. function main(args) {
  67. if (args.length !== 2) {
  68. console.error('USAGE: change-version old_version new_version')
  69. console.error('Got arguments:', args)
  70. process.exit(1)
  71. }
  72. const oldVersion = args[0]
  73. const newVersion = args[1]
  74. const EXCLUDED_DIRS = new Set([
  75. '.git',
  76. 'node_modules',
  77. 'vendor'
  78. ])
  79. const INCLUDED_EXTENSIONS = new Set([
  80. // This extension whitelist is how we avoid modifying binary files
  81. '',
  82. '.css',
  83. '.html',
  84. '.js',
  85. '.json',
  86. '.md',
  87. '.scss',
  88. '.txt',
  89. '.yml'
  90. ])
  91. replaceRecursively('.', EXCLUDED_DIRS, INCLUDED_EXTENSIONS, oldVersion, newVersion)
  92. }
  93. main(process.argv.slice(2))