2013-05-23 14:51:56 -07:00
|
|
|
# Based on convert script from vwall/compass-twitter-bootstrap gem.
|
|
|
|
# https://github.com/vwall/compass-twitter-bootstrap/blob/master/build/convert.rb
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this work except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License in the LICENSE file, or at:
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
require 'open-uri'
|
|
|
|
require 'json'
|
|
|
|
|
|
|
|
class Converter
|
2013-06-13 13:58:34 -07:00
|
|
|
def initialize(branch)
|
|
|
|
@branch = branch || 'master'
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
def process
|
2013-05-24 16:59:48 -07:00
|
|
|
process_stylesheet_assets
|
|
|
|
process_javascript_assets
|
|
|
|
end
|
|
|
|
|
|
|
|
def process_stylesheet_assets
|
|
|
|
puts "\nProcessing stylesheets..."
|
|
|
|
bootstrap_less_files.each do |name|
|
2013-06-15 16:30:44 -07:00
|
|
|
file = open("https://raw.github.com/twitter/bootstrap/#{@branch}/less/#{name}").read
|
|
|
|
|
|
|
|
case name
|
|
|
|
when 'bootstrap.less'
|
|
|
|
file = replace_file_imports(file)
|
|
|
|
when 'mixins.less'
|
|
|
|
file = replace_vars(file)
|
|
|
|
file = replace_escaping(file)
|
|
|
|
file = replace_mixin_file(file)
|
|
|
|
file = replace_mixins(file)
|
|
|
|
when 'utilities.less'
|
|
|
|
file = replace_mixin_file(file)
|
|
|
|
file = convert_to_scss(file)
|
|
|
|
when 'variables.less'
|
|
|
|
file = convert_to_scss(file)
|
|
|
|
file = insert_default_vars(file)
|
|
|
|
else
|
|
|
|
file = convert_to_scss(file)
|
|
|
|
end
|
|
|
|
|
|
|
|
name = name.gsub(/\.less$/, '.scss')
|
|
|
|
if name == 'bootstrap.scss'
|
|
|
|
path = "vendor/assets/stylesheets/bootstrap/bootstrap.scss"
|
|
|
|
else
|
2013-05-24 16:59:48 -07:00
|
|
|
path = "vendor/assets/stylesheets/bootstrap/_#{name}"
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
2013-06-15 16:30:44 -07:00
|
|
|
save_file(path, file)
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-05-24 16:59:48 -07:00
|
|
|
def process_javascript_assets
|
|
|
|
puts "\nProcessing javascripts..."
|
|
|
|
bootstrap_js_files.each do |name|
|
|
|
|
file = open("https://raw.github.com/twitter/bootstrap/#{@branch}/js/#{name}").read
|
|
|
|
path = "vendor/assets/javascripts/bootstrap/#{name}"
|
|
|
|
save_file(path, file)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Update javascript manifest
|
|
|
|
content = ''
|
|
|
|
bootstrap_js_files.each do |name|
|
|
|
|
name = name.gsub(/\.js$/, '')
|
|
|
|
content << "//= require bootstrap/#{name}\n"
|
|
|
|
end
|
|
|
|
path = "vendor/assets/javascripts/bootstrap.js"
|
|
|
|
save_file(path, content)
|
|
|
|
end
|
|
|
|
|
2013-05-23 14:51:56 -07:00
|
|
|
private
|
|
|
|
|
2013-05-24 16:59:48 -07:00
|
|
|
# Get the sha of a dir
|
|
|
|
def get_tree_sha(dir)
|
2013-05-23 14:51:56 -07:00
|
|
|
trees = open("https://api.github.com/repos/twitter/bootstrap/git/trees/#{@branch}").read
|
|
|
|
trees = JSON.parse trees
|
2013-05-24 16:59:48 -07:00
|
|
|
trees['tree'].find{|t| t['path'] == dir}['sha']
|
|
|
|
end
|
|
|
|
|
|
|
|
def bootstrap_less_files
|
|
|
|
files = open("https://api.github.com/repos/twitter/bootstrap/git/trees/#{get_tree_sha('less')}").read
|
|
|
|
files = JSON.parse files
|
|
|
|
files['tree'].select{|f| f['type'] == 'blob' && f['path'] =~ /.less$/ }.map{|f| f['path'] }
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
|
2013-05-24 16:59:48 -07:00
|
|
|
def bootstrap_js_files
|
|
|
|
files = open("https://api.github.com/repos/twitter/bootstrap/git/trees/#{get_tree_sha('js')}").read
|
2013-05-23 14:51:56 -07:00
|
|
|
files = JSON.parse files
|
2013-05-24 16:59:48 -07:00
|
|
|
files['tree'].select{|f| f['type'] == 'blob' && f['path'] =~ /.js$/ }.map{|f| f['path'] }
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
def get_mixins_name
|
|
|
|
mixins = []
|
|
|
|
less_mixins = open("https://raw.github.com/twitter/bootstrap/#{@branch}/less/mixins.less").read
|
|
|
|
|
|
|
|
less_mixins.scan(/\.([\w-]+)\(.*\)\s?{?/) do |mixin|
|
|
|
|
mixins << mixin
|
|
|
|
end
|
|
|
|
|
|
|
|
mixins
|
|
|
|
end
|
|
|
|
|
2013-05-24 16:59:48 -07:00
|
|
|
def convert_to_scss(file)
|
2013-05-23 14:51:56 -07:00
|
|
|
file = replace_vars(file)
|
|
|
|
file = replace_mixins(file)
|
|
|
|
file = replace_less_extend(file)
|
|
|
|
file = replace_spin(file)
|
|
|
|
file = replace_image_urls(file)
|
|
|
|
file = replace_image_paths(file)
|
|
|
|
file = replace_escaping(file)
|
|
|
|
file = convert_less_ampersand(file)
|
|
|
|
file
|
|
|
|
end
|
|
|
|
|
2013-05-24 16:59:48 -07:00
|
|
|
def save_file(path, content, mode='w')
|
|
|
|
File.open(path, mode) { |file| file.write(content) }
|
|
|
|
puts "Saved #{path}\n"
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
|
2013-06-15 16:30:44 -07:00
|
|
|
def replace_file_imports(less)
|
|
|
|
less.gsub(/@import ["|']([\w-]+).less["|'];/, '@import "bootstrap/\1";');
|
|
|
|
end
|
|
|
|
|
2013-05-28 20:50:03 -07:00
|
|
|
# Replaces the following:
|
2013-07-16 23:29:41 -07:00
|
|
|
# .mixin() -> @import mixin()
|
|
|
|
# #scope > .mixin() -> @import scope-mixin()
|
2013-05-23 14:51:56 -07:00
|
|
|
def replace_mixins(less)
|
2013-05-28 23:39:29 -07:00
|
|
|
mixin_pattern = /(\s*)(([#|\.][\w-]+\s*>\s*)*)\.([\w-]+\(.*\))/
|
2013-05-28 20:50:03 -07:00
|
|
|
less.gsub(mixin_pattern) do |match|
|
|
|
|
matches = match.scan(mixin_pattern).flatten
|
|
|
|
scope = matches[1] || ''
|
|
|
|
if scope != ''
|
2013-07-16 23:29:41 -07:00
|
|
|
scope = scope.scan(/[\w-]+/).join('-') + '-'
|
2013-05-28 20:50:03 -07:00
|
|
|
end
|
2013-07-16 23:29:41 -07:00
|
|
|
"#{matches.first}@include #{scope}#{matches.last}"
|
2013-05-28 20:50:03 -07:00
|
|
|
end
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
def replace_mixin_file(less)
|
2013-07-16 23:29:41 -07:00
|
|
|
less.gsub(/^(\s*)\.([\w-]+\(.*\))(\s*{)/, '\1@mixin \2\3')
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
def replace_vars(less)
|
2013-05-25 00:36:55 -07:00
|
|
|
less.gsub(/(?!@media|@page|@keyframes|@font-face|@-\w)@/, '$')
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
def replace_less_extend(less)
|
|
|
|
less.gsub(/\#(\w+) \> \.([\w-]*)(\(.*\));?/, '@include \1-\2\3;')
|
|
|
|
end
|
|
|
|
|
|
|
|
def replace_spin(less)
|
|
|
|
less.gsub(/spin/, 'adjust-hue')
|
|
|
|
end
|
|
|
|
|
|
|
|
def replace_image_urls(less)
|
|
|
|
less.gsub(/background-image: url\("?(.*?)"?\);/) {|s| "background-image: image-url(\"#{$1}\");" }
|
|
|
|
end
|
|
|
|
|
|
|
|
def replace_image_paths(less)
|
|
|
|
less.gsub('../img/', '')
|
|
|
|
end
|
|
|
|
|
|
|
|
def replace_escaping(less)
|
2013-06-13 12:09:18 -07:00
|
|
|
less = less.gsub(/\~"([^"]+)"/, '#{\1}') # Get rid of ~"" escape
|
|
|
|
#less.gsub(/(\W)e\("([^\)]+)"\)/) {|s| "#{$1 if $1 != /\s/}#{$2}"} # Get rid of e escape
|
|
|
|
less.gsub(/(\W)e\(%\((.*)\)\)/, '\1\2') # Get rid of e(%("")) escape
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
def insert_default_vars(scss)
|
2013-06-13 12:29:03 -07:00
|
|
|
scss.gsub(/^(\$.+);/, '\1 !default;')
|
2013-05-23 14:51:56 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
# Converts &-
|
|
|
|
def convert_less_ampersand(less)
|
|
|
|
regx = /^\.badge\s*\{[\s\/\w\(\)]+(&{1}-{1})\w.*?^}$/m
|
|
|
|
|
|
|
|
tmp = ''
|
|
|
|
less.scan(/^(\s*&)(-[\w\[\]]+\s*{.+})$/) do |ampersand, css|
|
|
|
|
tmp << ".badge#{css}\n"
|
|
|
|
end
|
|
|
|
|
|
|
|
less.gsub(regx, tmp)
|
|
|
|
end
|
|
|
|
end
|