Created
August 10, 2016 06:06
-
-
Save foxyblocks/af783d1e447bfcfb4b1647a3e056d2d0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
ROOT_PATH = File.dirname(__FILE__) + '/js/dashboard/' | |
COMPONENT_REGEX = /window\.(\w+) =.+(React|Reflux)/ | |
files = Dir.glob(ROOT_PATH + "**/*.{js,jsx,coffee,cjsx}") | |
# hard coded modules that we want to require. This list will be amended by searching for | |
# `window.X = (React|Redux)` definitions in the code base | |
components = [ | |
{name: 'UserActions', import_path: 'user_actions'}, | |
{name: 'UrlService', import_path: 'services/url_service'}, | |
{name: 'Reflux', import_path: 'reflux'}, | |
{name: 'PureRenderMixin', import_path: 'react-addons-pure-render-mixin'}, | |
{name: 'ReactDOM', import_path: 'react-dom'}, | |
{name: 'React', import_path: 'react'}, | |
{name: 'classNames', import_path: 'classnames'}, | |
{name: 'InlineSVG', import_path: 'react-inline-svg'}, | |
{name: 'Routes', import_path: 'routes'}, | |
{name: 'HotKeyMixin', import_path: 'mixins/hot_key_mixin'}, | |
{name: 'Analytics', import_path: 'lib/analytics'}, | |
{name: 'Timezone', import_path: 'lib/timezone'}, | |
{name: 'Update', import_path: 'lib/update'}, | |
{name: 'APIRequestMixin', import_path: 'mixins/api_request_mixin'}, | |
{name: 'DocumentEventListenerMixin', import_path: 'mixins/document_event_listener_mixin'}, | |
{name: 'Utils', import_path: 'lib/utils'}, | |
] | |
def make_import_path(full_path) | |
full_path.gsub(ROOT_PATH, "").gsub(/\.\w+$/, '') | |
end | |
def make_import_statement(name, file_name, component_path) | |
path = make_import_path(component_path) | |
if is_coffee?(file_name) | |
"#{name} = require('#{path}')" | |
else | |
"import #{name} from '#{path}';" | |
end | |
end | |
def is_coffee?(file_name) | |
file_name.match(/\.(coffee|cjsx)/) | |
end | |
# for a files contents, finds the place where we should add the next import statment. | |
# this should be at the top, but after any comment blocks or other require/import statments already | |
# in the file. | |
def find_insertion_point(contents, file_name) | |
if is_coffee?(file_name) | |
comment = /^\#/ | |
block_comment_start = /\#{3}/ | |
block_comment_end = /\#{3}/ | |
import = /require/ | |
else | |
comment = /^\/\// | |
block_comment_start = /\/\*/ | |
block_comment_end = /\*\// | |
import = /(import|require)/ | |
end | |
line_number = 0 | |
in_block_comment = false | |
lines = contents.split("\n") | |
# step through the lines of the file until we reach the first line that isn't a comment or a | |
# a require statement. | |
lines.each_with_index do |line, index| | |
if in_block_comment | |
if line.match(block_comment_end) | |
in_block_comment = false | |
end | |
line_number = line_number + 1 | |
next | |
end | |
if line.match(block_comment_start) | |
in_block_comment = true | |
line_number = line_number + 1 | |
next | |
end | |
if line.match(comment) || line.match(import) | |
line_number = line_number + 1 | |
elsif line.empty? && lines[index + 1].match(import) | |
line_number = line_number + 1 | |
else | |
break | |
end | |
end | |
return line_number | |
end | |
# iterate over all files and find "window.Foo =" statements | |
# replace those with explicit exports and add them to the list of components | |
files.each do |file_name| | |
text = File.read(file_name) | |
matches = text.scan(COMPONENT_REGEX) | |
components += matches.map do |match| | |
{name: match[0], import_path: file_name} | |
end | |
replacement = | |
if is_coffee?(file_name) | |
'module.exports = \2' | |
else | |
'export default \2' | |
end | |
new_contents = text.gsub(COMPONENT_REGEX, replacement) | |
# To write changes to the file, use: | |
File.open(file_name, "w") {|file| file.puts new_contents } | |
end | |
# Add import/require statements to all the files where global components have been used | |
files.each do |file_name| | |
text = File.read(file_name) | |
new_contents = text | |
components.each do |component| | |
# skip if we are in the component file itself | |
next if make_import_path(file_name) == component[:import_path] | |
name = component[:name] | |
# skip if component isn't used in this file | |
next unless text.match(/(\W#{name}\W|^#{name}|#{name}\.)/) | |
# skip if we already imported that component | |
next if new_contents.match(/^(import #{name}|#{name} = require)/) | |
# find the next insertion point for an import statement | |
insertion_point = find_insertion_point(new_contents, file_name) | |
# split into lines | |
lines = new_contents.split("\n") | |
if insertion_point == 0 | |
lines.insert(insertion_point, "") | |
end | |
# insert new line | |
lines.insert(insertion_point, make_import_statement(name, file_name, component[:import_path])) | |
# join everything again | |
new_contents = lines.join("\n") | |
end | |
# write the new contents | |
File.open(file_name, "w") {|file| file.puts new_contents } | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment