├── .gitignore
├── .travis.yml
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── Procfile
├── README.md
├── config.ru
├── contributing.md
├── deploy.sh
├── docker-compose.yml
├── front_end
├── ZeroClipboard.swf
├── app.rb
├── assets
│ ├── css
│ │ ├── _api.styl
│ │ ├── _base.styl
│ │ ├── _code_block.styl
│ │ ├── _converter.styl
│ │ ├── _fonts.styl
│ │ ├── _footer.styl
│ │ ├── _messages.styl
│ │ ├── _mo.styl
│ │ ├── _share.styl
│ │ ├── _variables.styl
│ │ ├── codemirror.css
│ │ └── master.styl
│ ├── favicon.ico
│ ├── img
│ │ ├── heart.png
│ │ ├── heart@2x.png
│ │ └── noise.png
│ └── js
│ │ ├── ZeroClipboard.min.js
│ │ ├── codemirror.js
│ │ ├── css.js
│ │ ├── main.js
│ │ ├── placeholder.js
│ │ └── sass.js
├── fonts
│ └── source-sans
│ │ ├── sourcesanspro-bold-webfont.svg
│ │ ├── sourcesanspro-bold-webfont.ttf
│ │ ├── sourcesanspro-bold-webfont.woff
│ │ ├── sourcesanspro-regular-webfont.eot
│ │ ├── sourcesanspro-regular-webfont.svg
│ │ ├── sourcesanspro-regular-webfont.ttf
│ │ └── sourcesanspro-regular-webfont.woff
└── views
│ ├── _api.haml
│ ├── _converter.haml
│ ├── _footer.haml
│ ├── _messages.haml
│ ├── _share.haml
│ ├── index.haml
│ └── layout.haml
├── functions.yml
├── node_converter.rb
├── package-lock.json
├── package.json
├── sass2stylus.js
├── spec
├── fixtures
│ ├── argument_splat.sass
│ ├── argument_splat.scss
│ ├── argument_splat.styl
│ ├── atroot.sass
│ ├── atroot.scss
│ ├── atroot.styl
│ ├── charset.scss
│ ├── charset.styl
│ ├── comments.scss
│ ├── comments.styl
│ ├── content.sass
│ ├── content.scss
│ ├── content.styl
│ ├── debug.sass
│ ├── debug.scss
│ ├── debug.styl
│ ├── disabled_functions.sass
│ ├── disabled_functions.scss
│ ├── disabled_functions.styl
│ ├── each.sass
│ ├── each.scss
│ ├── each.styl
│ ├── extend.sass
│ ├── extend.scss
│ ├── extend.styl
│ ├── font_face.sass
│ ├── font_face.scss
│ ├── font_face.styl
│ ├── foo.sass
│ ├── foo.scss
│ ├── foo.styl
│ ├── for.sass
│ ├── for.scss
│ ├── for.styl
│ ├── import.sass
│ ├── import.scss
│ ├── import.styl
│ ├── interpolated_key_values.sass
│ ├── interpolated_key_values.scss
│ ├── interpolated_key_values.styl
│ ├── interpolation.sass
│ ├── interpolation.scss
│ ├── interpolation.styl
│ ├── media_queries.sass
│ ├── media_queries.scss
│ ├── media_queries.styl
│ ├── multi_line_selectors.sass
│ ├── multi_line_selectors.scss
│ ├── multi_line_selectors.styl
│ ├── nested_properties.sass
│ ├── nested_properties.scss
│ ├── nested_properties.styl
│ ├── placeholder_selectors.sass
│ ├── placeholder_selectors.scss
│ ├── placeholder_selectors.styl
│ ├── prop_negated_variables.sass
│ ├── prop_negated_variables.scss
│ ├── prop_negated_variables.styl
│ ├── prop_operations.sass
│ ├── prop_operations.scss
│ ├── prop_operations.styl
│ ├── warn.sass
│ ├── warn.scss
│ ├── warn.styl
│ ├── while.sass
│ ├── while.scss
│ └── while.styl
└── to_stylus_spec.rb
└── to_stylus.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by http://www.gitignore.io
2 |
3 | ### Node ###
4 | lib-cov
5 | lcov.info
6 | *.seed
7 | *.log
8 | *.csv
9 | *.dat
10 | *.out
11 | *.pid
12 | *.gz
13 |
14 | pids
15 | logs
16 | results
17 | build
18 | .grunt
19 |
20 | node_modules
21 |
22 |
23 | ### SASS ###
24 | ### Sass Ignores - "Sassy CSS" http://sass-lang.com/
25 | *.sass-cache
26 |
27 |
28 | ### Ruby ###
29 | *.gem
30 | *.rbc
31 | /.config
32 | /coverage/
33 | /InstalledFiles
34 | /pkg/
35 | /spec/reports/
36 | /test/tmp/
37 | /test/version_tmp/
38 | /tmp/
39 |
40 | ## Documentation cache and generated files:
41 | /.yardoc/
42 | /_yardoc/
43 | /doc/
44 | /rdoc/
45 | */public/*
46 |
47 | ## Environment normalisation:
48 | /.bundle/
49 | /lib/bundler/man/
50 |
51 | # for a library or gem, you might want to ignore these files since the code is
52 | # intended to run in multiple environments; otherwise, check them in:
53 | # Gemfile.lock
54 | .ruby-version
55 | # .ruby-gemset
56 |
57 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
58 | .rvmrc
59 |
60 | .DS_Store
61 |
62 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | rvm:
2 | - 2.0.0
3 |
4 | script: bundle exec rspec spec
5 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ruby:2.4.9
2 |
3 | RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
4 | RUN apt-get update -qq && apt-get install -yq build-essential nodejs
5 |
6 | RUN mkdir /app
7 | WORKDIR /app
8 | ADD . /app
9 | RUN bundle install
10 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | ruby '2.4.9'
4 | gem 'sinatra'
5 | gem 'sass', '3.3.2'
6 | gem 'haml'
7 |
8 | group :development, :test do
9 | gem 'rspec'
10 | gem 'foreman'
11 | end
12 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | diff-lcs (1.2.5)
5 | foreman (0.85.0)
6 | thor (~> 0.19.1)
7 | haml (5.1.2)
8 | temple (>= 0.8.0)
9 | tilt
10 | rack (1.6.11)
11 | rack-protection (1.5.5)
12 | rack
13 | rspec (2.14.1)
14 | rspec-core (~> 2.14.0)
15 | rspec-expectations (~> 2.14.0)
16 | rspec-mocks (~> 2.14.0)
17 | rspec-core (2.14.8)
18 | rspec-expectations (2.14.5)
19 | diff-lcs (>= 1.1.3, < 2.0)
20 | rspec-mocks (2.14.6)
21 | sass (3.3.2)
22 | sinatra (1.4.4)
23 | rack (~> 1.4)
24 | rack-protection (~> 1.4)
25 | tilt (~> 1.3, >= 1.3.4)
26 | temple (0.8.1)
27 | thor (0.19.4)
28 | tilt (1.4.1)
29 |
30 | PLATFORMS
31 | ruby
32 |
33 | DEPENDENCIES
34 | foreman
35 | haml
36 | rspec
37 | sass (= 3.3.2)
38 | sinatra
39 |
40 | BUNDLED WITH
41 | 1.11.2
42 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | front_end: bundle exec rackup config.ru -p 3838 -o '0.0.0.0'
2 | assets: npm run watch
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Sass2Stylus
2 | ----------
3 | #[Use it live](http://sass2stylus.com)
4 |
5 | [](https://travis-ci.org/mojotech/sass2stylus)
6 |
7 | ### API Usage
8 |
9 | #### With cURL
10 | ```sh
11 | curl -F file=@/your/local/file.scss http://sass2stylus.com/api > new_file.styl
12 | ```
13 | #### With Ruby
14 | ```ruby
15 | RestClient.post('http://sass2stylus.com/api', file: File.open('local_file.scss'))
16 | ```
17 | ---
18 |
19 | ##### Sass2Stylus is curated by loving hands at...
20 |
(psst, [we're hiring](http://www.mojotech.com/jobs))
21 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'bundler'
3 |
4 | Bundler.require
5 |
6 | set :root, File.dirname(__FILE__)
7 | set :views, File.expand_path("front_end/views", settings.root)
8 | set :public_folder, File.expand_path("front_end/public", settings.root)
9 | require File.expand_path("front_end/app.rb", settings.root)
10 | run Sinatra::Application
11 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | Sass2Stylus
2 | ----------
3 | #[Use it live](http://sass2stylus.com)
4 |
5 | ### Development
6 | - Clone this repository
7 | - `bundle install`
8 | - `npm install`
9 | - `npm run watch`
10 | - `rackup config.ru`
11 |
12 | #### With Docker
13 | - `docker-compose build`
14 | - `docker-compose up`
15 | - Navigate to http://localhost:3838
16 |
17 | ### Deployment to Heroku
18 | - `heroku create`
19 | - `./deploy.sh`
20 |
21 | ---
22 |
23 | ##### Sass2Stylus is curated by loving hands at...
24 |
(psst, [we're hiring](http://www.mojotech.com/jobs))
25 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | sed -i.bak 's/\*\/public\/\*//' .gitignore
2 | rm .gitignore.bak
3 | npm run build
4 | git checkout -b deploy
5 | git add front_end
6 | git commit -m 'deploy'
7 | git push -f heroku deploy:master
8 | git checkout master
9 | git branch -D deploy
10 | git reset --hard
11 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | app:
2 | build: .
3 | command: bash -lc "bundle install && npm install && bundle exec foreman start"
4 | restart: unless-stopped
5 | tty: true
6 | stdin_open: true
7 | volumes:
8 | - .:/app
9 | ports:
10 | - "3838:3838"
11 |
--------------------------------------------------------------------------------
/front_end/ZeroClipboard.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/ZeroClipboard.swf
--------------------------------------------------------------------------------
/front_end/app.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra'
2 | require "haml"
3 |
4 | get '/' do
5 | haml :index
6 | end
7 |
8 | post '/ajax' do
9 | load File.expand_path('to_stylus.rb', settings.root)
10 | options = {syntax: params[:sass_textarea].include?(";") ? :scss : :sass}
11 | engine = Sass::Engine.new( params[:sass_textarea], options )
12 | begin
13 | tree = engine.to_tree
14 | stylus = ToStylus.visit(tree)
15 | rescue => e
16 | end
17 | e.nil? ? stylus : "Error: #{e.message} \nLine: #{e.sass_line}"
18 | end
19 |
20 | post '/download' do
21 | stylus_file = Tempfile.new("")
22 | stylus_file.write params[:stylus_textarea]
23 | stylus_file.rewind
24 | send_file(stylus_file, :filename => "new_file.styl")
25 | stylus_file.close!
26 | end
27 |
28 | post '/api' do
29 | load File.expand_path('to_stylus.rb', settings.root)
30 | options = Sass::Engine::DEFAULT_OPTIONS.merge({syntax: :scss})
31 | engine = Sass::Engine.for_file(params[:file][:tempfile], options)
32 | tree = engine.to_tree
33 | stylus = ToStylus.visit(tree)
34 |
35 | stylus_file = Tempfile.new('new_file.stylus')
36 | stylus_file.write stylus
37 | stylus_file.rewind
38 | send_file stylus_file
39 | stylus_file.close!
40 | end
41 |
--------------------------------------------------------------------------------
/front_end/assets/css/_api.styl:
--------------------------------------------------------------------------------
1 | .api-header
2 | padding-left med-padding-block
3 | padding-top med-padding-block
4 | margin-top 0
5 | .api
6 | background-color darken(light-blue, 5%)
7 | padding-top 10px
8 | .col-half
9 | padding 0 med-padding-block med-padding-block med-padding-block
10 | .api-code-block
11 | min-height inherit
12 | padding 10px
13 | font-size 12px
14 | white-space nowrap
15 | overflow-x scroll
16 | border-radius 0
17 | display inline-block
18 | width 78%
19 | height 28px
20 | vertical-align top
21 | line-height 10px
22 | .api-code-block::-webkit-scrollbar
23 | display none
24 |
25 |
--------------------------------------------------------------------------------
/front_end/assets/css/_base.styl:
--------------------------------------------------------------------------------
1 | *
2 | box-sizing border-box
3 | html, body
4 | height 100%
5 |
6 | html
7 | &.no_flash .no_flash
8 | width: 100%
9 |
10 | &.no_flash #download_btn
11 | width: 100%
12 |
13 | &.no_flash .flash_btn
14 | display none
15 |
16 | #content
17 | position: relative
18 | min-height: 100%
19 | padding-bottom: 323px
20 | background-color: #f2f6f9
21 | min-width 768px
22 |
23 | body
24 | margin 0
25 | padding 0
26 | font-family source-sans
27 | font-weight normal
28 |
29 | .base-content
30 | position absolute
31 | bottom 0
32 | width 100%
33 |
34 | h1, h2, h3, .btn
35 | font-family source-sans-bold
36 | font-weight normal
37 | h3
38 | margin 0 0 10px 0
39 | a
40 | color blue
41 | &:hover
42 | color lighten(blue, 20%)
43 |
44 | p
45 | margin 0
46 | code
47 | display block
48 | background light-blue
49 | padding med-padding-block
50 | min-height 350px
51 |
52 | strong
53 | font-family source-sans-bold
54 |
55 | .contain
56 | width 60%
57 | margin 0 auto
58 |
59 | .inline-link
60 | border-bottom 1px dotted blue
61 | transition color 100ms ease-out, border-bottom 100ms ease-out
62 | text-decoration none
63 | color blue
64 | &:hover
65 | text-decoration none
66 | color darken(blue, 50%)
67 | border-bottom 1px dotted darken(blue, 50%)
68 | .btn
69 | color white
70 | font-size 16px
71 | text-decoration none
72 | text-transform uppercase
73 | background green
74 | padding (small-padding-block - 7) small-padding-block
75 | outline: none
76 | border: none
77 | margin 0
78 | &:hover
79 | color white
80 | text-decoration none
81 | background-color lighten(green, 10%)
82 | cursor pointer
83 | &:active
84 | background-color darken(green, 20%)
85 | &.btn-stretch-row
86 | width 50%
87 | float left
88 | padding 15.5px 0
89 |
90 | .zeroclipboard-is-hover
91 | background-color #97d978
92 | .zeroclipboard-is-active
93 | position relative
94 | top 2px
95 |
96 | .col-header
97 | display inline-block
98 | width 50%
99 | background-color dark-blue
100 | margin 0
101 | padding small-padding-block 0 small-padding-block (med-padding-block + 14)
102 | color white
103 |
104 | .clear
105 | clear both
106 |
107 | form
108 | height 100%
109 |
110 | .col-half
111 | width 50%
112 | float left
113 | &.converter-col
114 | position relative
115 |
116 | .inner-padding
117 | height 100%
118 |
119 | .action-buttons
120 | display inline-block
121 | position absolute
122 | top 0
123 | right 0
124 | width: 50%
125 |
--------------------------------------------------------------------------------
/front_end/assets/css/_code_block.styl:
--------------------------------------------------------------------------------
1 | .CodeMirror,
2 | .cm-s-neat,
3 | .cm-s-default.CodeMirror
4 | background-color transparent
5 |
6 | .cm-s-default.CodeMirror
7 | border-right 1px solid darken(light-blue, 5%)
8 |
9 |
10 | .CodeMirror-gutters
11 | background-color lighten(light-blue, 25%)
12 | border none
13 |
14 | .cm-s-default.CodeMirror,
15 | .cm-s-neat
16 | border-radius 0
17 |
18 | .CodeMirror
19 | height 100%
20 |
21 | .CodeMirror pre
22 | font-family Monaco, monospace
23 | font-size 12px
24 |
25 | .sass-col, .styl-col
26 | background-color lighten(light-blue, 25%)
27 |
28 | .cm-s-default .cm-qualifier,
29 | .cm-qualifier
30 | color red
31 |
32 | .cm-s-default .cm-property,
33 | .cm-property,
34 | .cm-s-default .cm-tag
35 | color #7B7E9B
36 |
37 | .cm-s-default .cm-def,
38 | .cm-def
39 | color #8B8CA0
40 |
41 | .CodeMirror-linenumber
42 | color #C8D3E4
43 |
--------------------------------------------------------------------------------
/front_end/assets/css/_converter.styl:
--------------------------------------------------------------------------------
1 | .converter
2 | padding xl-padding-block
3 | .btn
4 | margin-bottom small-padding-block + 7
5 | #file_selector
6 | display none
7 |
--------------------------------------------------------------------------------
/front_end/assets/css/_fonts.styl:
--------------------------------------------------------------------------------
1 | @font-face
2 | font-family 'Source Sans Regular'
3 | src url('../fonts/source-sans/sourcesanspro-regular-webfont.eot')
4 | src url('../fonts/source-sans/sourcesanspro-regular-webfont.eot?#iefix') format('embedded-opentype'),
5 | url('../fonts/source-sans/sourcesanspro-regular-webfont.woff') format('woff'),
6 | url('../fonts/source-sans/sourcesanspro-regular-webfont.ttf') format('truetype'),
7 | url('../fonts/source-sans/sourcesanspro-regular-webfont.svg#webfont') format('svg');
8 | @font-face
9 | font-family 'Source Sans Bold'
10 | src url('../fonts/source-sans/sourcesanspro-bold-webfont.eot')
11 | src url('../fonts/source-sans/sourcesanspro-bold-webfont.eot?#iefix') format('embedded-opentype'),
12 | url('../fonts/source-sans/sourcesanspro-bold-webfont.woff') format('woff'),
13 | url('../fonts/source-sans/sourcesanspro-bold-webfont.ttf') format('truetype'),
14 | url('../fonts/source-sans/sourcesanspro-bold-webfont.svg#webfont') format('svg');
15 |
--------------------------------------------------------------------------------
/front_end/assets/css/_footer.styl:
--------------------------------------------------------------------------------
1 | .footer
2 | text-align center
3 | padding med-padding-block 0
4 | color light-blue
5 | background dark-grey
6 | font-size 13px
7 | #gh_btn
8 | position absolute
9 | right 10px
10 | bottom 22px
11 |
12 |
--------------------------------------------------------------------------------
/front_end/assets/css/_messages.styl:
--------------------------------------------------------------------------------
1 | .messages
2 | display none
3 | padding small-padding-block 0
4 | &.error
5 | background red
6 | .active-message
7 | display block
8 | .close
9 | margin-top -10px
10 | padding 7px 15px 14px 14px
11 | opacity 1
12 | transition all 500ms ease-out
13 | &:hover
14 | color white
15 | opacity 1
16 | transform rotateZ(180deg)
17 |
--------------------------------------------------------------------------------
/front_end/assets/css/_mo.styl:
--------------------------------------------------------------------------------
1 | pos(args...)
2 | positions = absolute, fixed, relative, static, inherit, initial
3 | props = top, right, bottom, left
4 |
5 | if args[0] in positions
6 | position: args[0]
7 | args = args[1..length(args)]
8 |
9 | if args[0] is 'fill'
10 | args = args[1..length(args)]
11 | for prop, i in props
12 | {prop}: args[i] or 0 unless args[i] is false
13 | else
14 | for arg, i in args
15 | {props[i]}: arg unless arg is false
16 |
17 | ellipsis(width = false)
18 | width: width unless width is false
19 | overflow: hidden
20 | white-space: nowrap
21 | text-overflow: ellipsis
22 |
23 | size(width, height = width)
24 | width: width
25 | height: height
26 |
27 | retina-background-image(name, extension = png)
28 | background-image url(name'.'extension)
29 | @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx)
30 | background-image url(name'@2x.'extension)
31 |
--------------------------------------------------------------------------------
/front_end/assets/css/_share.styl:
--------------------------------------------------------------------------------
1 | .share
2 | margin med-padding-block 0
3 |
4 | .social-network-link
5 | &.mt-share-inline-square-sm
6 | display inline-block
7 | width 42px
8 | text-align center
9 | img
10 | width 34px
11 | height auto
12 | border 0px
13 |
14 | .mt-google
15 | background-color rgb(221, 75, 57)
16 | &:hover
17 | background-color rgb(225, 95, 79)
18 |
19 | .mt-linkedin
20 | background-color rgb(14, 118, 168)
21 | &:hover
22 | background-color rgb(16, 135, 192)
23 |
24 | .mt-twitter
25 | background-color rgb(0, 172, 238)
26 | &:hover
27 | background-color rgb(8, 187, 255)
28 |
29 | .mt-facebook
30 | background-color rgb(59, 89, 152)
31 | &:hover
32 | background-color rgb(66, 100, 170)
33 |
34 | .mt-pinterest
35 | background-color rgb(204, 33, 39)
36 | &:hover
37 | background-color rgb(221, 42, 48)
38 |
39 |
--------------------------------------------------------------------------------
/front_end/assets/css/_variables.styl:
--------------------------------------------------------------------------------
1 | light-blue = #eef3f7
2 | blue = #00a6ea
3 | dark-blue = #333c4e
4 | green = #7dd056
5 | grey = #b1bfd4
6 | dark-grey = #333333
7 | red = #ed1c37
8 |
9 | med-padding-block = 26px
10 | small-padding-block = 10px
11 |
12 | source-sans = "Source Sans Regular", Helvetica, Helvetica, Arial, sans-serif
13 | source-sans-bold = "Source Sans Bold", Helvetica, Arial, sans-serif
14 |
--------------------------------------------------------------------------------
/front_end/assets/css/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | color: black;
8 | }
9 | .CodeMirror-scroll {
10 | /* Set scrolling behaviour here */
11 | overflow: auto;
12 | }
13 | .CodeMirror-code{
14 | min-height: 300px;
15 | }
16 |
17 | /* PADDING */
18 |
19 | .CodeMirror-lines {
20 | padding: 4px 0; /* Vertical padding around content */
21 | }
22 | .CodeMirror pre {
23 | padding: 0 4px; /* Horizontal padding of content */
24 | }
25 |
26 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
27 | background-color: white; /* The little square between H and V scrollbars */
28 | }
29 |
30 | /* GUTTER */
31 |
32 | .CodeMirror-gutters {
33 | border-right: 1px solid #ddd;
34 | background-color: #E9F0FA;
35 | white-space: nowrap;
36 | }
37 | .CodeMirror-linenumbers {}
38 | .CodeMirror-linenumber {
39 | padding: 0 3px 0 5px;
40 | min-width: 20px;
41 | text-align: right;
42 | color: #999;
43 | -moz-box-sizing: content-box;
44 | box-sizing: content-box;
45 | }
46 |
47 | /* CURSOR */
48 |
49 | .CodeMirror div.CodeMirror-cursor {
50 | border-left: 1px solid black;
51 | z-index: 3;
52 | }
53 | /* Shown when moving in bi-directional text */
54 | .CodeMirror div.CodeMirror-secondarycursor {
55 | border-left: 1px solid silver;
56 | }
57 | .CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
58 | width: auto;
59 | border: 0;
60 | background: #7e7;
61 | z-index: 1;
62 | }
63 | /* Can style cursor different in overwrite (non-insert) mode */
64 | .CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
65 |
66 | .cm-tab { display: inline-block; }
67 |
68 | .CodeMirror-ruler {
69 | border-left: 1px solid #ccc;
70 | position: absolute;
71 | }
72 |
73 | /* DEFAULT THEME */
74 | .cm-s-default.CodeMirror {
75 | background: #E9F0FA;
76 | color: #F8F8F8;
77 | -webkit-border-radius: 6px;
78 | -moz-border-radius: 6px;
79 | -o-border-radius: 6px;
80 | -ms-border-radius: 6px;
81 | border-radius: 6px;
82 | }
83 | .cm-s-default .cm-keyword {color: #708;}
84 | .cm-s-default .cm-atom {color: #219;}
85 | .cm-s-default .cm-number {color: #3a3;}
86 | .cm-s-default .cm-def {color: #00f;}
87 | .cm-s-default .cm-variable {color: black;}
88 | .cm-s-default .cm-variable-2 {color: #05a;}
89 | .cm-s-default .cm-variable-3 {color: #3a3;}
90 | .cm-s-default .cm-property {color: black;}
91 | .cm-s-default .cm-operator {color: black;}
92 | .cm-s-default .cm-comment {color: #a50;}
93 | .cm-s-default .cm-string {color: #a11;}
94 | .cm-s-default .cm-string-2 {color: #f50;}
95 | .cm-s-default .cm-meta {color: #555;}
96 | .cm-s-default .cm-qualifier {color: #555;}
97 | .cm-s-default .cm-builtin {color: #3a3;}
98 | .cm-s-default .cm-bracket {color: #997;}
99 | .cm-s-default .cm-tag {color: #000;}
100 | .cm-s-default .cm-attribute {color: #00c;}
101 | .cm-s-default .cm-header {color: blue;}
102 | .cm-s-default .cm-quote {color: #090;}
103 | .cm-s-default .cm-hr {color: #999;}
104 | .cm-s-default .cm-link {color: #00c;}
105 |
106 | .cm-negative {color: #d44;}
107 | .cm-positive {color: #292;}
108 | .cm-header, .cm-strong {font-weight: bold;}
109 | .cm-em {font-style: italic;}
110 | .cm-link {text-decoration: underline;}
111 |
112 | .cm-s-default .cm-error {color: #f00;}
113 | .cm-invalidchar {color: #f00;}
114 |
115 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
116 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
117 | .CodeMirror-activeline-background {background: #e8f2ff;}
118 |
119 | /* STOP */
120 |
121 | /* The rest of this file contains styles related to the mechanics of
122 | the editor. You probably shouldn't touch them. */
123 |
124 | .CodeMirror {
125 | line-height: 1.2;
126 | position: relative;
127 | overflow: hidden;
128 | background: white;
129 | color: black;
130 | }
131 |
132 | .CodeMirror-scroll {
133 | /* 30px is the magic margin used to hide the element's real scrollbars */
134 | /* See overflow: hidden in .CodeMirror */
135 | margin-bottom: -30px; margin-right: -30px;
136 | padding-bottom: 30px;
137 | height: 100%;
138 | outline: none; /* Prevent dragging from highlighting the element */
139 | position: relative;
140 | -moz-box-sizing: content-box;
141 | box-sizing: content-box;
142 | }
143 | .CodeMirror-sizer {
144 | position: relative;
145 | border-right: 30px solid transparent;
146 | -moz-box-sizing: content-box;
147 | box-sizing: content-box;
148 | }
149 |
150 | /* The fake, visible scrollbars. Used to force redraw during scrolling
151 | before actuall scrolling happens, thus preventing shaking and
152 | flickering artifacts. */
153 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
154 | position: absolute;
155 | z-index: 6;
156 | display: none;
157 | }
158 | .CodeMirror-vscrollbar {
159 | right: 0; top: 0;
160 | overflow-x: hidden;
161 | overflow-y: scroll;
162 | }
163 | .CodeMirror-hscrollbar {
164 | bottom: 0; left: 0;
165 | overflow-y: hidden;
166 | overflow-x: scroll;
167 | }
168 | .CodeMirror-scrollbar-filler {
169 | right: 0; bottom: 0;
170 | }
171 | .CodeMirror-gutter-filler {
172 | left: 0; bottom: 0;
173 | }
174 |
175 | .CodeMirror-gutters {
176 | position: absolute; left: 0; top: 0;
177 | padding-bottom: 30px;
178 | z-index: 3;
179 | }
180 | .CodeMirror-gutter {
181 | white-space: normal;
182 | height: 100%;
183 | -moz-box-sizing: content-box;
184 | box-sizing: content-box;
185 | padding-bottom: 30px;
186 | margin-bottom: -32px;
187 | display: inline-block;
188 | /* Hack to make IE7 behave */
189 | *zoom:1;
190 | *display:inline;
191 | }
192 | .CodeMirror-gutter-elt {
193 | position: absolute;
194 | cursor: default;
195 | z-index: 4;
196 | }
197 |
198 | .CodeMirror-lines {
199 | cursor: text;
200 | }
201 | .CodeMirror pre {
202 | /* Reset some styles that the rest of the page might have set */
203 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
204 | border-width: 0;
205 | background: transparent;
206 | font-family: inherit;
207 | font-size: inherit;
208 | margin: 0;
209 | white-space: pre;
210 | word-wrap: normal;
211 | line-height: inherit;
212 | color: black;
213 | z-index: 2;
214 | position: relative;
215 | overflow: visible;
216 | }
217 | .CodeMirror-wrap pre {
218 | word-wrap: break-word;
219 | white-space: pre-wrap;
220 | word-break: normal;
221 | }
222 |
223 | .CodeMirror-linebackground {
224 | position: absolute;
225 | left: 0; right: 0; top: 0; bottom: 0;
226 | z-index: 0;
227 | }
228 |
229 | .CodeMirror-linewidget {
230 | position: relative;
231 | z-index: 2;
232 | overflow: auto;
233 | }
234 |
235 | .CodeMirror-widget {}
236 |
237 | .CodeMirror-wrap .CodeMirror-scroll {
238 | overflow-x: hidden;
239 | }
240 |
241 | .CodeMirror-measure {
242 | position: absolute;
243 | width: 100%;
244 | height: 0;
245 | overflow: hidden;
246 | visibility: hidden;
247 | }
248 | .CodeMirror-measure pre { position: static; }
249 |
250 | .CodeMirror div.CodeMirror-cursor {
251 | position: absolute;
252 | visibility: hidden;
253 | border-right: none;
254 | width: 0;
255 | }
256 | .CodeMirror-focused div.CodeMirror-cursor {
257 | visibility: visible;
258 | }
259 |
260 | .CodeMirror-selected { background: #d9d9d9; }
261 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
262 |
263 | .cm-searching {
264 | background: #ffa;
265 | background: rgba(255, 255, 0, .4);
266 | }
267 |
268 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
269 | .CodeMirror span { *vertical-align: text-bottom; }
270 |
271 | @media print {
272 | /* Hide the cursor when printing */
273 | .CodeMirror div.CodeMirror-cursor {
274 | visibility: hidden;
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/front_end/assets/css/master.styl:
--------------------------------------------------------------------------------
1 | reset()
2 | base()
3 |
4 | @import '_mo'
5 | @import '_fonts'
6 | @import '_variables'
7 | @import '_base'
8 | @import '_converter'
9 | @import '_code_block'
10 | @import '_messages'
11 | @import '_api'
12 | @import '_footer'
13 | @import '_share'
14 |
--------------------------------------------------------------------------------
/front_end/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/assets/favicon.ico
--------------------------------------------------------------------------------
/front_end/assets/img/heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/assets/img/heart.png
--------------------------------------------------------------------------------
/front_end/assets/img/heart@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/assets/img/heart@2x.png
--------------------------------------------------------------------------------
/front_end/assets/img/noise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/assets/img/noise.png
--------------------------------------------------------------------------------
/front_end/assets/js/ZeroClipboard.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * ZeroClipboard
3 | * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.
4 | * Copyright (c) 2014 Jon Rohan, James M. Greene
5 | * Licensed MIT
6 | * http://zeroclipboard.org/
7 | * v1.3.2
8 | */
9 | !function(){"use strict";function a(a){return a.replace(/,/g,".").replace(/[^0-9\.]/g,"")}function b(b){return parseFloat(a(b))>=10}var c,d={bridge:null,version:"0.0.0",disabled:null,outdated:null,ready:null},e={},f=0,g={},h=0,i={},j=null,k=null,l=function(){var a,b,c,d,e="ZeroClipboard.swf";if(document.currentScript&&(d=document.currentScript.src));else{var f=document.getElementsByTagName("script");if("readyState"in f[0])for(a=f.length;a--&&("interactive"!==f[a].readyState||!(d=f[a].src)););else if("loading"===document.readyState)d=f[f.length-1].src;else{for(a=f.length;a--;){if(c=f[a].src,!c){b=null;break}if(c=c.split("#")[0].split("?")[0],c=c.slice(0,c.lastIndexOf("/")+1),null==b)b=c;else if(b!==c){b=null;break}}null!==b&&(d=b)}}return d&&(d=d.split("#")[0].split("?")[0],e=d.slice(0,d.lastIndexOf("/")+1)+e),e}(),m=function(){var a=/\-([a-z])/g,b=function(a,b){return b.toUpperCase()};return function(c){return c.replace(a,b)}}(),n=function(a,b){var c,d,e;return window.getComputedStyle?c=window.getComputedStyle(a,null).getPropertyValue(b):(d=m(b),c=a.currentStyle?a.currentStyle[d]:a.style[d]),"cursor"!==b||c&&"auto"!==c||(e=a.tagName.toLowerCase(),"a"!==e)?c:"pointer"},o=function(a){a||(a=window.event);var b;this!==window?b=this:a.target?b=a.target:a.srcElement&&(b=a.srcElement),I.activate(b)},p=function(a,b,c){a&&1===a.nodeType&&(a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,c))},q=function(a,b,c){a&&1===a.nodeType&&(a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent&&a.detachEvent("on"+b,c))},r=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)||a.classList.add(b),a;if(b&&"string"==typeof b){var c=(b||"").split(/\s+/);if(1===a.nodeType)if(a.className){for(var d=" "+a.className+" ",e=a.className,f=0,g=c.length;g>f;f++)d.indexOf(" "+c[f]+" ")<0&&(e+=" "+c[f]);a.className=e.replace(/^\s+|\s+$/g,"")}else a.className=b}return a},s=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)&&a.classList.remove(b),a;if(b&&"string"==typeof b||void 0===b){var c=(b||"").split(/\s+/);if(1===a.nodeType&&a.className)if(b){for(var d=(" "+a.className+" ").replace(/[\n\t]/g," "),e=0,f=c.length;f>e;e++)d=d.replace(" "+c[e]+" "," ");a.className=d.replace(/^\s+|\s+$/g,"")}else a.className=""}return a},t=function(){var a,b,c,d=1;return"function"==typeof document.body.getBoundingClientRect&&(a=document.body.getBoundingClientRect(),b=a.right-a.left,c=document.body.offsetWidth,d=Math.round(b/c*100)/100),d},u=function(a,b){var c={left:0,top:0,width:0,height:0,zIndex:A(b)-1};if(a.getBoundingClientRect){var d,e,f,g=a.getBoundingClientRect();"pageXOffset"in window&&"pageYOffset"in window?(d=window.pageXOffset,e=window.pageYOffset):(f=t(),d=Math.round(document.documentElement.scrollLeft/f),e=Math.round(document.documentElement.scrollTop/f));var h=document.documentElement.clientLeft||0,i=document.documentElement.clientTop||0;c.left=g.left+d-h,c.top=g.top+e-i,c.width="width"in g?g.width:g.right-g.left,c.height="height"in g?g.height:g.bottom-g.top}return c},v=function(a,b){var c=null==b||b&&b.cacheBust===!0&&b.useNoCache===!0;return c?(-1===a.indexOf("?")?"?":"&")+"noCache="+(new Date).getTime():""},w=function(a){var b,c,d,e=[],f=[],g=[];if(a.trustedOrigins&&("string"==typeof a.trustedOrigins?f.push(a.trustedOrigins):"object"==typeof a.trustedOrigins&&"length"in a.trustedOrigins&&(f=f.concat(a.trustedOrigins))),a.trustedDomains&&("string"==typeof a.trustedDomains?f.push(a.trustedDomains):"object"==typeof a.trustedDomains&&"length"in a.trustedDomains&&(f=f.concat(a.trustedDomains))),f.length)for(b=0,c=f.length;c>b;b++)if(f.hasOwnProperty(b)&&f[b]&&"string"==typeof f[b]){if(d=D(f[b]),!d)continue;if("*"===d){g=[d];break}g.push.apply(g,[d,"//"+d,window.location.protocol+"//"+d])}return g.length&&e.push("trustedOrigins="+encodeURIComponent(g.join(","))),"string"==typeof a.jsModuleId&&a.jsModuleId&&e.push("jsModuleId="+encodeURIComponent(a.jsModuleId)),e.join("&")},x=function(a,b,c){if("function"==typeof b.indexOf)return b.indexOf(a,c);var d,e=b.length;for("undefined"==typeof c?c=0:0>c&&(c=e+c),d=c;e>d;d++)if(b.hasOwnProperty(d)&&b[d]===a)return d;return-1},y=function(a){if("string"==typeof a)throw new TypeError("ZeroClipboard doesn't accept query strings.");return a.length?a:[a]},z=function(a,b,c,d){d?window.setTimeout(function(){a.apply(b,c)},0):a.apply(b,c)},A=function(a){var b,c;return a&&("number"==typeof a&&a>0?b=a:"string"==typeof a&&(c=parseInt(a,10))&&!isNaN(c)&&c>0&&(b=c)),b||("number"==typeof L.zIndex&&L.zIndex>0?b=L.zIndex:"string"==typeof L.zIndex&&(c=parseInt(L.zIndex,10))&&!isNaN(c)&&c>0&&(b=c)),b||0},B=function(a,b){if(a&&b!==!1&&"undefined"!=typeof console&&console&&(console.warn||console.log)){var c="`"+a+"` is deprecated. See docs for more info:\n https://github.com/zeroclipboard/zeroclipboard/blob/master/docs/instructions.md#deprecations";console.warn?console.warn(c):console.log(c)}},C=function(){var a,b,c,d,e,f,g=arguments[0]||{};for(a=1,b=arguments.length;b>a;a++)if(null!=(c=arguments[a]))for(d in c)if(c.hasOwnProperty(d)){if(e=g[d],f=c[d],g===f)continue;void 0!==f&&(g[d]=f)}return g},D=function(a){if(null==a||""===a)return null;if(a=a.replace(/^\s+|\s+$/g,""),""===a)return null;var b=a.indexOf("//");a=-1===b?a:a.slice(b+2);var c=a.indexOf("/");return a=-1===c?a:-1===b||0===c?null:a.slice(0,c),a&&".swf"===a.slice(-4).toLowerCase()?null:a||null},E=function(){var a=function(a,b){var c,d,e;if(null!=a&&"*"!==b[0]&&("string"==typeof a&&(a=[a]),"object"==typeof a&&"length"in a))for(c=0,d=a.length;d>c;c++)if(a.hasOwnProperty(c)&&(e=D(a[c]))){if("*"===e){b.length=0,b.push("*");break}-1===x(e,b)&&b.push(e)}},b={always:"always",samedomain:"sameDomain",never:"never"};return function(c,d){var e,f=d.allowScriptAccess;if("string"==typeof f&&(e=f.toLowerCase())&&/^always|samedomain|never$/.test(e))return b[e];var g=D(d.moviePath);null===g&&(g=c);var h=[];a(d.trustedOrigins,h),a(d.trustedDomains,h);var i=h.length;if(i>0){if(1===i&&"*"===h[0])return"always";if(-1!==x(c,h))return 1===i&&c===g?"sameDomain":"always"}return"never"}}(),F=function(a){if(null==a)return[];if(Object.keys)return Object.keys(a);var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b},G=function(a){if(a)for(var b in a)a.hasOwnProperty(b)&&delete a[b];return a},H=function(){var a=!1;if("boolean"==typeof d.disabled)a=d.disabled===!1;else{if("function"==typeof ActiveXObject)try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash")&&(a=!0)}catch(b){}!a&&navigator.mimeTypes["application/x-shockwave-flash"]&&(a=!0)}return a},I=function(a,b){return this instanceof I?(this.id=""+f++,g[this.id]={instance:this,elements:[],handlers:{}},a&&this.clip(a),"undefined"!=typeof b&&(B("new ZeroClipboard(elements, options)",L.debug),I.config(b)),this.options=I.config(),"boolean"!=typeof d.disabled&&(d.disabled=!H()),d.disabled===!1&&d.outdated!==!0&&null===d.bridge&&(d.outdated=!1,d.ready=!1,M()),void 0):new I(a,b)};I.prototype.setText=function(a){return a&&""!==a&&(e["text/plain"]=a,d.ready===!0&&d.bridge&&d.bridge.setText(a)),this},I.prototype.setSize=function(a,b){return d.ready===!0&&d.bridge&&d.bridge.setSize(a,b),this};var J=function(a){d.ready===!0&&d.bridge&&d.bridge.setHandCursor(a)};I.prototype.destroy=function(){this.unclip(),this.off(),delete g[this.id]};var K=function(){var a,b,c,d=[],e=F(g);for(a=0,b=e.length;b>a;a++)c=g[e[a]].instance,c&&c instanceof I&&d.push(c);return d};I.version="1.3.2";var L={swfPath:l,trustedDomains:window.location.host?[window.location.host]:[],cacheBust:!0,forceHandCursor:!1,zIndex:999999999,debug:!0,title:null,autoActivate:!0};I.config=function(a){"object"==typeof a&&null!==a&&C(L,a);{if("string"!=typeof a||!a){var b={};for(var c in L)L.hasOwnProperty(c)&&(b[c]="object"==typeof L[c]&&null!==L[c]?"length"in L[c]?L[c].slice(0):C({},L[c]):L[c]);return b}if(L.hasOwnProperty(a))return L[a]}},I.destroy=function(){I.deactivate();for(var a in g)if(g.hasOwnProperty(a)&&g[a]){var b=g[a].instance;b&&"function"==typeof b.destroy&&b.destroy()}var c=N(d.bridge);c&&c.parentNode&&(c.parentNode.removeChild(c),d.ready=null,d.bridge=null)},I.activate=function(a){c&&(s(c,L.hoverClass),s(c,L.activeClass)),c=a,r(a,L.hoverClass),O();var b=L.title||a.getAttribute("title");if(b){var e=N(d.bridge);e&&e.setAttribute("title",b)}var f=L.forceHandCursor===!0||"pointer"===n(a,"cursor");J(f)},I.deactivate=function(){var a=N(d.bridge);a&&(a.style.left="0px",a.style.top="-9999px",a.removeAttribute("title")),c&&(s(c,L.hoverClass),s(c,L.activeClass),c=null)};var M=function(){var a,b,c=document.getElementById("global-zeroclipboard-html-bridge");if(!c){var e=I.config();e.jsModuleId="string"==typeof j&&j||"string"==typeof k&&k||null;var f=E(window.location.host,L),g=w(e),h=L.moviePath+v(L.moviePath,L),i=' ';c=document.createElement("div"),c.id="global-zeroclipboard-html-bridge",c.setAttribute("class","global-zeroclipboard-container"),c.style.position="absolute",c.style.left="0px",c.style.top="-9999px",c.style.width="15px",c.style.height="15px",c.style.zIndex=""+A(L.zIndex),document.body.appendChild(c),c.innerHTML=i}a=document["global-zeroclipboard-flash-bridge"],a&&(b=a.length)&&(a=a[b-1]),d.bridge=a||c.children[0].lastElementChild},N=function(a){for(var b=/^OBJECT|EMBED$/,c=a&&a.parentNode;c&&b.test(c.nodeName)&&c.parentNode;)c=c.parentNode;return c||null},O=function(){if(c){var a=u(c,L.zIndex),b=N(d.bridge);b&&(b.style.top=a.top+"px",b.style.left=a.left+"px",b.style.width=a.width+"px",b.style.height=a.height+"px",b.style.zIndex=a.zIndex+1),d.ready===!0&&d.bridge&&d.bridge.setSize(a.width,a.height)}return this};I.prototype.on=function(a,b){var c,e,f,h={},i=g[this.id]&&g[this.id].handlers;if("string"==typeof a&&a)f=a.toLowerCase().split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)a.hasOwnProperty(c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&this.on(c,a[c]);if(f&&f.length){for(c=0,e=f.length;e>c;c++)a=f[c].replace(/^on/,""),h[a]=!0,i[a]||(i[a]=[]),i[a].push(b);h.noflash&&d.disabled&&R.call(this,"noflash",{}),h.wrongflash&&d.outdated&&R.call(this,"wrongflash",{flashVersion:d.version}),h.load&&d.ready&&R.call(this,"load",{flashVersion:d.version})}return this},I.prototype.off=function(a,b){var c,d,e,f,h,i=g[this.id]&&g[this.id].handlers;if(0===arguments.length)f=F(i);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)a.hasOwnProperty(c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&this.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),h=i[a],h&&h.length)if(b)for(e=x(b,h);-1!==e;)h.splice(e,1),e=x(b,h,e);else i[a].length=0;return this},I.prototype.handlers=function(a){var b,c=null,d=g[this.id]&&g[this.id].handlers;if(d){if("string"==typeof a&&a)return d[a]?d[a].slice(0):null;c={};for(b in d)d.hasOwnProperty(b)&&d[b]&&(c[b]=d[b].slice(0))}return c};var P=function(a,b,c,d){var e=g[this.id]&&g[this.id].handlers[a];if(e&&e.length){var f,h,i,j=b||this;for(f=0,h=e.length;h>f;f++)i=e[f],b=j,"string"==typeof i&&"function"==typeof window[i]&&(i=window[i]),"object"==typeof i&&i&&"function"==typeof i.handleEvent&&(b=i,i=i.handleEvent),"function"==typeof i&&z(i,b,c,d)}return this};I.prototype.clip=function(a){a=y(a);for(var b=0;bd;d++)f=g[c[d]].instance,f&&f instanceof I&&h.push(f);return h};L.hoverClass="zeroclipboard-is-hover",L.activeClass="zeroclipboard-is-active",L.trustedOrigins=null,L.allowScriptAccess=null,L.useNoCache=!0,L.moviePath="ZeroClipboard.swf",I.detectFlashSupport=function(){return B("ZeroClipboard.detectFlashSupport",L.debug),H()},I.dispatch=function(a,b){if("string"==typeof a&&a){var d=a.toLowerCase().replace(/^on/,"");if(d)for(var e=c?Q(c):K(),f=0,g=e.length;g>f;f++)R.call(e[f],d,b)}},I.prototype.setHandCursor=function(a){return B("ZeroClipboard.prototype.setHandCursor",L.debug),a="boolean"==typeof a?a:!!a,J(a),L.forceHandCursor=a,this},I.prototype.reposition=function(){return B("ZeroClipboard.prototype.reposition",L.debug),O()},I.prototype.receiveEvent=function(a,b){if(B("ZeroClipboard.prototype.receiveEvent",L.debug),"string"==typeof a&&a){var c=a.toLowerCase().replace(/^on/,"");c&&R.call(this,c,b)}},I.prototype.setCurrent=function(a){return B("ZeroClipboard.prototype.setCurrent",L.debug),I.activate(a),this},I.prototype.resetBridge=function(){return B("ZeroClipboard.prototype.resetBridge",L.debug),I.deactivate(),this},I.prototype.setTitle=function(a){if(B("ZeroClipboard.prototype.setTitle",L.debug),a=a||L.title||c&&c.getAttribute("title")){var b=N(d.bridge);b&&b.setAttribute("title",a)}return this},I.setDefaults=function(a){B("ZeroClipboard.setDefaults",L.debug),I.config(a)},I.prototype.addEventListener=function(a,b){return B("ZeroClipboard.prototype.addEventListener",L.debug),this.on(a,b)},I.prototype.removeEventListener=function(a,b){return B("ZeroClipboard.prototype.removeEventListener",L.debug),this.off(a,b)},I.prototype.ready=function(){return B("ZeroClipboard.prototype.ready",L.debug),d.ready===!0};var R=function(f,g){f=f.toLowerCase().replace(/^on/,"");var h=g&&g.flashVersion&&a(g.flashVersion)||null,i=c,j=!0;switch(f){case"load":if(h){if(!b(h))return R.call(this,"onWrongFlash",{flashVersion:h}),void 0;d.outdated=!1,d.ready=!0,d.version=h}break;case"wrongflash":h&&!b(h)&&(d.outdated=!0,d.ready=!1,d.version=h);break;case"mouseover":r(i,L.hoverClass);break;case"mouseout":L.autoActivate===!0&&I.deactivate();break;case"mousedown":r(i,L.activeClass);break;case"mouseup":s(i,L.activeClass);break;case"datarequested":var k=i.getAttribute("data-clipboard-target"),l=k?document.getElementById(k):null;if(l){var m=l.value||l.textContent||l.innerText;m&&this.setText(m)}else{var n=i.getAttribute("data-clipboard-text");n&&this.setText(n)}j=!1;break;case"complete":G(e)}var o=i,p=[this,g];return P.call(this,f,o,p,j)};"function"==typeof define&&define.amd?define(["require","exports","module"],function(a,b,c){return j=c&&c.id||null,I}):"object"==typeof module&&module&&"object"==typeof module.exports&&module.exports?(k=module.id||null,module.exports=I):window.ZeroClipboard=I}();
--------------------------------------------------------------------------------
/front_end/assets/js/css.js:
--------------------------------------------------------------------------------
1 | CodeMirror.defineMode("css", function(config, parserConfig) {
2 | "use strict";
3 |
4 | if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
5 |
6 | var indentUnit = config.indentUnit,
7 | tokenHooks = parserConfig.tokenHooks,
8 | mediaTypes = parserConfig.mediaTypes || {},
9 | mediaFeatures = parserConfig.mediaFeatures || {},
10 | propertyKeywords = parserConfig.propertyKeywords || {},
11 | colorKeywords = parserConfig.colorKeywords || {},
12 | valueKeywords = parserConfig.valueKeywords || {},
13 | fontProperties = parserConfig.fontProperties || {},
14 | allowNested = parserConfig.allowNested;
15 |
16 | var type, override;
17 | function ret(style, tp) { type = tp; return style; }
18 |
19 | // Tokenizers
20 |
21 | function tokenBase(stream, state) {
22 | var ch = stream.next();
23 | if (tokenHooks[ch]) {
24 | var result = tokenHooks[ch](stream, state);
25 | if (result !== false) return result;
26 | }
27 | if (ch == "@") {
28 | stream.eatWhile(/[\w\\\-]/);
29 | return ret("def", stream.current());
30 | } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
31 | return ret(null, "compare");
32 | } else if (ch == "\"" || ch == "'") {
33 | state.tokenize = tokenString(ch);
34 | return state.tokenize(stream, state);
35 | } else if (ch == "#") {
36 | stream.eatWhile(/[\w\\\-]/);
37 | return ret("atom", "hash");
38 | } else if (ch == "!") {
39 | stream.match(/^\s*\w*/);
40 | return ret("keyword", "important");
41 | } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
42 | stream.eatWhile(/[\w.%]/);
43 | return ret("number", "unit");
44 | } else if (ch === "-") {
45 | if (/[\d.]/.test(stream.peek())) {
46 | stream.eatWhile(/[\w.%]/);
47 | return ret("number", "unit");
48 | } else if (stream.match(/^[^-]+-/)) {
49 | return ret("meta", "meta");
50 | }
51 | } else if (/[,+>*\/]/.test(ch)) {
52 | return ret(null, "select-op");
53 | } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
54 | return ret("qualifier", "qualifier");
55 | } else if (/[:;{}\[\]\(\)]/.test(ch)) {
56 | return ret(null, ch);
57 | } else if (ch == "u" && stream.match("rl(")) {
58 | stream.backUp(1);
59 | state.tokenize = tokenParenthesized;
60 | return ret("property", "word");
61 | } else if (/[\w\\\-]/.test(ch)) {
62 | stream.eatWhile(/[\w\\\-]/);
63 | return ret("property", "word");
64 | } else {
65 | return ret(null, null);
66 | }
67 | }
68 |
69 | function tokenString(quote) {
70 | return function(stream, state) {
71 | var escaped = false, ch;
72 | while ((ch = stream.next()) != null) {
73 | if (ch == quote && !escaped) {
74 | if (quote == ")") stream.backUp(1);
75 | break;
76 | }
77 | escaped = !escaped && ch == "\\";
78 | }
79 | if (ch == quote || !escaped && quote != ")") state.tokenize = null;
80 | return ret("string", "string");
81 | };
82 | }
83 |
84 | function tokenParenthesized(stream, state) {
85 | stream.next(); // Must be '('
86 | if (!stream.match(/\s*[\"\']/, false))
87 | state.tokenize = tokenString(")");
88 | else
89 | state.tokenize = null;
90 | return ret(null, "(");
91 | }
92 |
93 | // Context management
94 |
95 | function Context(type, indent, prev) {
96 | this.type = type;
97 | this.indent = indent;
98 | this.prev = prev;
99 | }
100 |
101 | function pushContext(state, stream, type) {
102 | state.context = new Context(type, stream.indentation() + indentUnit, state.context);
103 | return type;
104 | }
105 |
106 | function popContext(state) {
107 | state.context = state.context.prev;
108 | return state.context.type;
109 | }
110 |
111 | function pass(type, stream, state) {
112 | return states[state.context.type](type, stream, state);
113 | }
114 | function popAndPass(type, stream, state, n) {
115 | for (var i = n || 1; i > 0; i--)
116 | state.context = state.context.prev;
117 | return pass(type, stream, state);
118 | }
119 |
120 | // Parser
121 |
122 | function wordAsValue(stream) {
123 | var word = stream.current().toLowerCase();
124 | if (valueKeywords.hasOwnProperty(word))
125 | override = "atom";
126 | else if (colorKeywords.hasOwnProperty(word))
127 | override = "keyword";
128 | else
129 | override = "variable";
130 | }
131 |
132 | var states = {};
133 |
134 | states.top = function(type, stream, state) {
135 | if (type == "{") {
136 | return pushContext(state, stream, "block");
137 | } else if (type == "}" && state.context.prev) {
138 | return popContext(state);
139 | } else if (type == "@media") {
140 | return pushContext(state, stream, "media");
141 | } else if (type == "@font-face") {
142 | return "font_face_before";
143 | } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
144 | return "keyframes";
145 | } else if (type && type.charAt(0) == "@") {
146 | return pushContext(state, stream, "at");
147 | } else if (type == "hash") {
148 | override = "builtin";
149 | } else if (type == "word") {
150 | override = "tag";
151 | } else if (type == "variable-definition") {
152 | return "maybeprop";
153 | } else if (type == "interpolation") {
154 | return pushContext(state, stream, "interpolation");
155 | } else if (type == ":") {
156 | return "pseudo";
157 | } else if (allowNested && type == "(") {
158 | return pushContext(state, stream, "params");
159 | }
160 | return state.context.type;
161 | };
162 |
163 | states.block = function(type, stream, state) {
164 | if (type == "word") {
165 | if (propertyKeywords.hasOwnProperty(stream.current().toLowerCase())) {
166 | override = "property";
167 | return "maybeprop";
168 | } else if (allowNested) {
169 | override = stream.match(/^\s*:/, false) ? "property" : "tag";
170 | return "block";
171 | } else {
172 | override += " error";
173 | return "maybeprop";
174 | }
175 | } else if (type == "meta") {
176 | return "block";
177 | } else if (!allowNested && (type == "hash" || type == "qualifier")) {
178 | override = "error";
179 | return "block";
180 | } else {
181 | return states.top(type, stream, state);
182 | }
183 | };
184 |
185 | states.maybeprop = function(type, stream, state) {
186 | if (type == ":") return pushContext(state, stream, "prop");
187 | return pass(type, stream, state);
188 | };
189 |
190 | states.prop = function(type, stream, state) {
191 | if (type == ";") return popContext(state);
192 | if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
193 | if (type == "}" || type == "{") return popAndPass(type, stream, state);
194 | if (type == "(") return pushContext(state, stream, "parens");
195 |
196 | if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
197 | override += " error";
198 | } else if (type == "word") {
199 | wordAsValue(stream);
200 | } else if (type == "interpolation") {
201 | return pushContext(state, stream, "interpolation");
202 | }
203 | return "prop";
204 | };
205 |
206 | states.propBlock = function(type, _stream, state) {
207 | if (type == "}") return popContext(state);
208 | if (type == "word") { override = "property"; return "maybeprop"; }
209 | return state.context.type;
210 | };
211 |
212 | states.parens = function(type, stream, state) {
213 | if (type == "{" || type == "}") return popAndPass(type, stream, state);
214 | if (type == ")") return popContext(state);
215 | return "parens";
216 | };
217 |
218 | states.pseudo = function(type, stream, state) {
219 | if (type == "word") {
220 | override = "variable-3";
221 | return state.context.type;
222 | }
223 | return pass(type, stream, state);
224 | };
225 |
226 | states.media = function(type, stream, state) {
227 | if (type == "(") return pushContext(state, stream, "media_parens");
228 | if (type == "}") return popAndPass(type, stream, state);
229 | if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
230 |
231 | if (type == "word") {
232 | var word = stream.current().toLowerCase();
233 | if (word == "only" || word == "not" || word == "and")
234 | override = "keyword";
235 | else if (mediaTypes.hasOwnProperty(word))
236 | override = "attribute";
237 | else if (mediaFeatures.hasOwnProperty(word))
238 | override = "property";
239 | else
240 | override = "error";
241 | }
242 | return state.context.type;
243 | };
244 |
245 | states.media_parens = function(type, stream, state) {
246 | if (type == ")") return popContext(state);
247 | if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
248 | return states.media(type, stream, state);
249 | };
250 |
251 | states.font_face_before = function(type, stream, state) {
252 | if (type == "{")
253 | return pushContext(state, stream, "font_face");
254 | return pass(type, stream, state);
255 | };
256 |
257 | states.font_face = function(type, stream, state) {
258 | if (type == "}") return popContext(state);
259 | if (type == "word") {
260 | if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
261 | override = "error";
262 | else
263 | override = "property";
264 | return "maybeprop";
265 | }
266 | return "font_face";
267 | };
268 |
269 | states.keyframes = function(type, stream, state) {
270 | if (type == "word") { override = "variable"; return "keyframes"; }
271 | if (type == "{") return pushContext(state, stream, "top");
272 | return pass(type, stream, state);
273 | };
274 |
275 | states.at = function(type, stream, state) {
276 | if (type == ";") return popContext(state);
277 | if (type == "{" || type == "}") return popAndPass(type, stream, state);
278 | if (type == "word") override = "tag";
279 | else if (type == "hash") override = "builtin";
280 | return "at";
281 | };
282 |
283 | states.interpolation = function(type, stream, state) {
284 | if (type == "}") return popContext(state);
285 | if (type == "{" || type == ";") return popAndPass(type, stream, state);
286 | if (type != "variable") override = "error";
287 | return "interpolation";
288 | };
289 |
290 | states.params = function(type, stream, state) {
291 | if (type == ")") return popContext(state);
292 | if (type == "{" || type == "}") return popAndPass(type, stream, state);
293 | if (type == "word") wordAsValue(stream);
294 | return "params";
295 | };
296 |
297 | return {
298 | startState: function(base) {
299 | return {tokenize: null,
300 | state: "top",
301 | context: new Context("top", base || 0, null)};
302 | },
303 |
304 | token: function(stream, state) {
305 | if (!state.tokenize && stream.eatSpace()) return null;
306 | var style = (state.tokenize || tokenBase)(stream, state);
307 | if (style && typeof style == "object") {
308 | type = style[1];
309 | style = style[0];
310 | }
311 | override = style;
312 | state.state = states[state.state](type, stream, state);
313 | return override;
314 | },
315 |
316 | indent: function(state, textAfter) {
317 | var cx = state.context, ch = textAfter && textAfter.charAt(0);
318 | var indent = cx.indent;
319 | if (cx.type == "prop" && ch == "}") cx = cx.prev;
320 | if (cx.prev &&
321 | (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
322 | ch == ")" && (cx.type == "parens" || cx.type == "params" || cx.type == "media_parens") ||
323 | ch == "{" && (cx.type == "at" || cx.type == "media"))) {
324 | indent = cx.indent - indentUnit;
325 | cx = cx.prev;
326 | }
327 | return indent;
328 | },
329 |
330 | electricChars: "}",
331 | blockCommentStart: "/*",
332 | blockCommentEnd: "*/",
333 | fold: "brace"
334 | };
335 | });
336 |
337 | (function() {
338 | function keySet(array) {
339 | var keys = {};
340 | for (var i = 0; i < array.length; ++i) {
341 | keys[array[i]] = true;
342 | }
343 | return keys;
344 | }
345 |
346 | var mediaTypes_ = [
347 | "all", "aural", "braille", "handheld", "print", "projection", "screen",
348 | "tty", "tv", "embossed"
349 | ], mediaTypes = keySet(mediaTypes_);
350 |
351 | var mediaFeatures_ = [
352 | "width", "min-width", "max-width", "height", "min-height", "max-height",
353 | "device-width", "min-device-width", "max-device-width", "device-height",
354 | "min-device-height", "max-device-height", "aspect-ratio",
355 | "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
356 | "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
357 | "max-color", "color-index", "min-color-index", "max-color-index",
358 | "monochrome", "min-monochrome", "max-monochrome", "resolution",
359 | "min-resolution", "max-resolution", "scan", "grid"
360 | ], mediaFeatures = keySet(mediaFeatures_);
361 |
362 | var propertyKeywords_ = [
363 | "align-content", "align-items", "align-self", "alignment-adjust",
364 | "alignment-baseline", "anchor-point", "animation", "animation-delay",
365 | "animation-direction", "animation-duration", "animation-fill-mode",
366 | "animation-iteration-count", "animation-name", "animation-play-state",
367 | "animation-timing-function", "appearance", "azimuth", "backface-visibility",
368 | "background", "background-attachment", "background-clip", "background-color",
369 | "background-image", "background-origin", "background-position",
370 | "background-repeat", "background-size", "baseline-shift", "binding",
371 | "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
372 | "bookmark-target", "border", "border-bottom", "border-bottom-color",
373 | "border-bottom-left-radius", "border-bottom-right-radius",
374 | "border-bottom-style", "border-bottom-width", "border-collapse",
375 | "border-color", "border-image", "border-image-outset",
376 | "border-image-repeat", "border-image-slice", "border-image-source",
377 | "border-image-width", "border-left", "border-left-color",
378 | "border-left-style", "border-left-width", "border-radius", "border-right",
379 | "border-right-color", "border-right-style", "border-right-width",
380 | "border-spacing", "border-style", "border-top", "border-top-color",
381 | "border-top-left-radius", "border-top-right-radius", "border-top-style",
382 | "border-top-width", "border-width", "bottom", "box-decoration-break",
383 | "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
384 | "caption-side", "clear", "clip", "color", "color-profile", "column-count",
385 | "column-fill", "column-gap", "column-rule", "column-rule-color",
386 | "column-rule-style", "column-rule-width", "column-span", "column-width",
387 | "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
388 | "cue-after", "cue-before", "cursor", "direction", "display",
389 | "dominant-baseline", "drop-initial-after-adjust",
390 | "drop-initial-after-align", "drop-initial-before-adjust",
391 | "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
392 | "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
393 | "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
394 | "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
395 | "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
396 | "font-stretch", "font-style", "font-synthesis", "font-variant",
397 | "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
398 | "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
399 | "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
400 | "grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end",
401 | "grid-column-start", "grid-row", "grid-row-end", "grid-row-start",
402 | "grid-template", "grid-template-areas", "grid-template-columns",
403 | "grid-template-rows", "hanging-punctuation", "height", "hyphens",
404 | "icon", "image-orientation", "image-rendering", "image-resolution",
405 | "inline-box-align", "justify-content", "left", "letter-spacing",
406 | "line-break", "line-height", "line-stacking", "line-stacking-ruby",
407 | "line-stacking-shift", "line-stacking-strategy", "list-style",
408 | "list-style-image", "list-style-position", "list-style-type", "margin",
409 | "margin-bottom", "margin-left", "margin-right", "margin-top",
410 | "marker-offset", "marks", "marquee-direction", "marquee-loop",
411 | "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
412 | "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
413 | "nav-left", "nav-right", "nav-up", "opacity", "order", "orphans", "outline",
414 | "outline-color", "outline-offset", "outline-style", "outline-width",
415 | "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
416 | "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
417 | "page", "page-break-after", "page-break-before", "page-break-inside",
418 | "page-policy", "pause", "pause-after", "pause-before", "perspective",
419 | "perspective-origin", "pitch", "pitch-range", "play-during", "position",
420 | "presentation-level", "punctuation-trim", "quotes", "region-break-after",
421 | "region-break-before", "region-break-inside", "region-fragment",
422 | "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
423 | "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
424 | "ruby-position", "ruby-span", "shape-inside", "shape-outside", "size",
425 | "speak", "speak-as", "speak-header",
426 | "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
427 | "tab-size", "table-layout", "target", "target-name", "target-new",
428 | "target-position", "text-align", "text-align-last", "text-decoration",
429 | "text-decoration-color", "text-decoration-line", "text-decoration-skip",
430 | "text-decoration-style", "text-emphasis", "text-emphasis-color",
431 | "text-emphasis-position", "text-emphasis-style", "text-height",
432 | "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
433 | "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
434 | "text-wrap", "top", "transform", "transform-origin", "transform-style",
435 | "transition", "transition-delay", "transition-duration",
436 | "transition-property", "transition-timing-function", "unicode-bidi",
437 | "vertical-align", "visibility", "voice-balance", "voice-duration",
438 | "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
439 | "voice-volume", "volume", "white-space", "widows", "width", "word-break",
440 | "word-spacing", "word-wrap", "z-index", "zoom",
441 | // SVG-specific
442 | "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
443 | "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
444 | "color-interpolation", "color-interpolation-filters", "color-profile",
445 | "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
446 | "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
447 | "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
448 | "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
449 | "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
450 | "glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode"
451 | ], propertyKeywords = keySet(propertyKeywords_);
452 |
453 | var colorKeywords_ = [
454 | "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
455 | "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
456 | "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
457 | "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
458 | "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
459 | "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
460 | "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
461 | "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
462 | "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
463 | "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
464 | "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
465 | "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
466 | "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
467 | "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
468 | "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
469 | "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
470 | "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
471 | "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
472 | "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
473 | "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
474 | "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
475 | "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon",
476 | "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
477 | "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
478 | "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
479 | "whitesmoke", "yellow", "yellowgreen"
480 | ], colorKeywords = keySet(colorKeywords_);
481 |
482 | var valueKeywords_ = [
483 | "above", "absolute", "activeborder", "activecaption", "afar",
484 | "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
485 | "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
486 | "arabic-indic", "armenian", "asterisks", "auto", "avoid", "avoid-column", "avoid-page",
487 | "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
488 | "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
489 | "both", "bottom", "break", "break-all", "break-word", "button", "button-bevel",
490 | "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
491 | "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
492 | "cell", "center", "checkbox", "circle", "cjk-earthly-branch",
493 | "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
494 | "col-resize", "collapse", "column", "compact", "condensed", "contain", "content",
495 | "content-box", "context-menu", "continuous", "copy", "cover", "crop",
496 | "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
497 | "decimal-leading-zero", "default", "default-button", "destination-atop",
498 | "destination-in", "destination-out", "destination-over", "devanagari",
499 | "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
500 | "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
501 | "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
502 | "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
503 | "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
504 | "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
505 | "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
506 | "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
507 | "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
508 | "ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
509 | "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
510 | "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
511 | "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
512 | "help", "hidden", "hide", "higher", "highlight", "highlighttext",
513 | "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
514 | "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
515 | "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
516 | "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
517 | "italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer",
518 | "landscape", "lao", "large", "larger", "left", "level", "lighter",
519 | "line-through", "linear", "lines", "list-item", "listbox", "listitem",
520 | "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
521 | "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
522 | "lower-roman", "lowercase", "ltr", "malayalam", "match",
523 | "media-controls-background", "media-current-time-display",
524 | "media-fullscreen-button", "media-mute-button", "media-play-button",
525 | "media-return-to-realtime-button", "media-rewind-button",
526 | "media-seek-back-button", "media-seek-forward-button", "media-slider",
527 | "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
528 | "media-volume-slider-container", "media-volume-sliderthumb", "medium",
529 | "menu", "menulist", "menulist-button", "menulist-text",
530 | "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
531 | "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
532 | "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
533 | "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
534 | "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
535 | "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
536 | "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
537 | "painted", "page", "paused", "persian", "plus-darker", "plus-lighter", "pointer",
538 | "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
539 | "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region",
540 | "relative", "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
541 | "ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
542 | "s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
543 | "searchfield-cancel-button", "searchfield-decoration",
544 | "searchfield-results-button", "searchfield-results-decoration",
545 | "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
546 | "single", "skip-white-space", "slide", "slider-horizontal",
547 | "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
548 | "small", "small-caps", "small-caption", "smaller", "solid", "somali",
549 | "source-atop", "source-in", "source-out", "source-over", "space", "square",
550 | "square-button", "start", "static", "status-bar", "stretch", "stroke",
551 | "sub", "subpixel-antialiased", "super", "sw-resize", "table",
552 | "table-caption", "table-cell", "table-column", "table-column-group",
553 | "table-footer-group", "table-header-group", "table-row", "table-row-group",
554 | "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
555 | "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
556 | "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
557 | "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
558 | "transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
559 | "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
560 | "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
561 | "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
562 | "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
563 | "window", "windowframe", "windowtext", "x-large", "x-small", "xor",
564 | "xx-large", "xx-small"
565 | ], valueKeywords = keySet(valueKeywords_);
566 |
567 | var fontProperties_ = [
568 | "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
569 | "font-stretch", "font-weight", "font-style"
570 | ], fontProperties = keySet(fontProperties_);
571 |
572 | var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);
573 | CodeMirror.registerHelper("hintWords", "css", allWords);
574 |
575 | function tokenCComment(stream, state) {
576 | var maybeEnd = false, ch;
577 | while ((ch = stream.next()) != null) {
578 | if (maybeEnd && ch == "/") {
579 | state.tokenize = null;
580 | break;
581 | }
582 | maybeEnd = (ch == "*");
583 | }
584 | return ["comment", "comment"];
585 | }
586 |
587 | function tokenSGMLComment(stream, state) {
588 | if (stream.skipTo("-->")) {
589 | stream.match("-->");
590 | state.tokenize = null;
591 | } else {
592 | stream.skipToEnd();
593 | }
594 | return ["comment", "comment"];
595 | }
596 |
597 | CodeMirror.defineMIME("text/css", {
598 | mediaTypes: mediaTypes,
599 | mediaFeatures: mediaFeatures,
600 | propertyKeywords: propertyKeywords,
601 | colorKeywords: colorKeywords,
602 | valueKeywords: valueKeywords,
603 | fontProperties: fontProperties,
604 | tokenHooks: {
605 | "<": function(stream, state) {
606 | if (!stream.match("!--")) return false;
607 | state.tokenize = tokenSGMLComment;
608 | return tokenSGMLComment(stream, state);
609 | },
610 | "/": function(stream, state) {
611 | if (!stream.eat("*")) return false;
612 | state.tokenize = tokenCComment;
613 | return tokenCComment(stream, state);
614 | }
615 | },
616 | name: "css"
617 | });
618 |
619 | CodeMirror.defineMIME("text/x-scss", {
620 | mediaTypes: mediaTypes,
621 | mediaFeatures: mediaFeatures,
622 | propertyKeywords: propertyKeywords,
623 | colorKeywords: colorKeywords,
624 | valueKeywords: valueKeywords,
625 | fontProperties: fontProperties,
626 | allowNested: true,
627 | tokenHooks: {
628 | "/": function(stream, state) {
629 | if (stream.eat("/")) {
630 | stream.skipToEnd();
631 | return ["comment", "comment"];
632 | } else if (stream.eat("*")) {
633 | state.tokenize = tokenCComment;
634 | return tokenCComment(stream, state);
635 | } else {
636 | return ["operator", "operator"];
637 | }
638 | },
639 | ":": function(stream) {
640 | if (stream.match(/\s*{/))
641 | return [null, "{"];
642 | return false;
643 | },
644 | "$": function(stream) {
645 | stream.match(/^[\w-]+/);
646 | if (stream.match(/^\s*:/, false))
647 | return ["variable-2", "variable-definition"];
648 | return ["variable-2", "variable"];
649 | },
650 | "#": function(stream) {
651 | if (!stream.eat("{")) return false;
652 | return [null, "interpolation"];
653 | }
654 | },
655 | name: "css",
656 | helperType: "scss"
657 | });
658 |
659 | CodeMirror.defineMIME("text/x-less", {
660 | mediaTypes: mediaTypes,
661 | mediaFeatures: mediaFeatures,
662 | propertyKeywords: propertyKeywords,
663 | colorKeywords: colorKeywords,
664 | valueKeywords: valueKeywords,
665 | fontProperties: fontProperties,
666 | allowNested: true,
667 | tokenHooks: {
668 | "/": function(stream, state) {
669 | if (stream.eat("/")) {
670 | stream.skipToEnd();
671 | return ["comment", "comment"];
672 | } else if (stream.eat("*")) {
673 | state.tokenize = tokenCComment;
674 | return tokenCComment(stream, state);
675 | } else {
676 | return ["operator", "operator"];
677 | }
678 | },
679 | "@": function(stream) {
680 | if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
681 | stream.eatWhile(/[\w\\\-]/);
682 | if (stream.match(/^\s*:/, false))
683 | return ["variable-2", "variable-definition"];
684 | return ["variable-2", "variable"];
685 | },
686 | "&": function() {
687 | return ["atom", "atom"];
688 | }
689 | },
690 | name: "css",
691 | helperType: "less"
692 | });
693 | })();
694 |
--------------------------------------------------------------------------------
/front_end/assets/js/main.js:
--------------------------------------------------------------------------------
1 | var S2S = S2S || {};
2 |
3 | S2S.submitForm = function (stylus) {
4 | $.ajax({
5 | type: "POST",
6 | url: '/ajax',
7 | data: $("#form").serialize(),
8 | success: function (data) {
9 | stylus.getDoc().setValue(data);
10 | },
11 | error: function () {
12 | alert("Sorry, we were not able to process your code. \n" +
13 | "Please create a new issue and copy/paste your code at the provided link to help us fix the issue. \n"+
14 | "https://github.com/mojotech/sass2stylus/issues/new")
15 | }
16 | });
17 | return false;
18 | };
19 |
20 | S2S.readFile = function (sass, stylus, fileSelector) {
21 | var files = fileSelector.files;
22 | var file = files[0];
23 | var reader = new FileReader();
24 |
25 | // If we use onloadend, we need to check the readyState.
26 | reader.onloadend = function (e) {
27 | if (e.target.readyState == FileReader.DONE) { // DONE == 2
28 | sass.getDoc().setValue(e.target.result);
29 | sass.save();
30 | S2S.submitForm(stylus);
31 | }
32 | };
33 |
34 | var blob = file.slice(0, file.size);
35 | reader.readAsBinaryString(blob);
36 | }
37 |
38 | S2S.selectText = function (element) {
39 | var doc = document
40 | , text = doc.getElementById(element)
41 | , range, selection
42 | ;
43 | if (doc.body.createTextRange) { //ms
44 | range = doc.body.createTextRange();
45 | range.moveToElementText(text);
46 | range.select();
47 | } else if (window.getSelection) { //all others
48 | selection = window.getSelection();
49 | range = doc.createRange();
50 | range.selectNodeContents(text);
51 | selection.removeAllRanges();
52 | selection.addRange(range);
53 | }
54 | }
55 |
56 | var sassPlaceholder = "# write your SASS/SCSS here or upload"+
57 | "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
58 |
59 | $(document).ready(function () {
60 |
61 | var copy_btn = new ZeroClipboard( document.getElementById("copy_btn") ),
62 | request_btn = new ZeroClipboard( document.getElementById("request_btn") ),
63 | response_btn = new ZeroClipboard( document.getElementById("response_btn") );
64 |
65 | copy_btn.on('noflash', function ( client, args ) {
66 | document.documentElement.className += "no_flash";
67 | });
68 |
69 | var sass_editor = CodeMirror.fromTextArea(document.getElementById("codemirror_sass"), {
70 | lineNumbers: true,
71 | matchBrackets: true,
72 | mode: "text/x-scss"
73 | });
74 | sass_editor.getDoc().setValue(sassPlaceholder);
75 |
76 | sass_editor.on('focus', function () {
77 | if( sass_editor.getValue() === sassPlaceholder ) {
78 | sass_editor.getDoc().setValue("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
79 | }
80 | });
81 |
82 | var stylus_editor = CodeMirror.fromTextArea(document.getElementById("codemirror_stylus"),{
83 | lineNumbers: true,
84 | });
85 | stylus_editor.getDoc().setValue("# your code will be here!"+
86 | "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
87 |
88 | copy_btn.on("dataRequested", function (client, args) {
89 | client.setText( stylus_editor.getValue() );
90 | });
91 |
92 | var fileSelector = document.getElementById('file_selector');
93 |
94 | fileSelector.onchange = function () {
95 | if (this.value !== "") {
96 | S2S.readFile(sass_editor, stylus_editor, fileSelector);
97 | }
98 | };
99 |
100 | $("#upload").click(function (e) {
101 | e.preventDefault();
102 | $("#file_selector").click();
103 | });
104 |
105 | $("#convert").click(function (e) {
106 | e.preventDefault();
107 | sass_editor.save();
108 | S2S.submitForm(stylus_editor);
109 | });
110 |
111 | $("#download_btn").click(function () {
112 | stylus_editor.save();
113 | document.getElementById("download_form").submit()
114 | });
115 |
116 | $('.api-code-block').click( function(){ S2S.selectText( $(this).attr('id')) });
117 |
118 | sass_editor.on('blur', function () {
119 | if( sass_editor.getValue().match(/^[\r\n ]+$/) ) {
120 | sass_editor.getDoc().setValue(sassPlaceholder);
121 | }
122 | });
123 |
124 | });
125 |
--------------------------------------------------------------------------------
/front_end/assets/js/placeholder.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
3 | var prev = old && old != CodeMirror.Init;
4 | if (val && !prev) {
5 | cm.on("blur", onBlur);
6 | cm.on("change", onChange);
7 | onChange(cm);
8 | } else if (!val && prev) {
9 | cm.off("blur", onBlur);
10 | cm.off("change", onChange);
11 | clearPlaceholder(cm);
12 | var wrapper = cm.getWrapperElement();
13 | wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
14 | }
15 |
16 | if (val && !cm.hasFocus()) onBlur(cm);
17 | });
18 |
19 | function clearPlaceholder(cm) {
20 | if (cm.state.placeholder) {
21 | cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
22 | cm.state.placeholder = null;
23 | }
24 | }
25 | function setPlaceholder(cm) {
26 | clearPlaceholder(cm);
27 | var elt = cm.state.placeholder = document.createElement("pre");
28 | elt.style.cssText = "height: 0; overflow: visible";
29 | elt.className = "CodeMirror-placeholder";
30 | elt.appendChild(document.createTextNode(cm.getOption("placeholder")));
31 | cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
32 | }
33 |
34 | function onBlur(cm) {
35 | if (isEmpty(cm)) setPlaceholder(cm);
36 | }
37 | function onChange(cm) {
38 | var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
39 | wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
40 |
41 | if (empty) setPlaceholder(cm);
42 | else clearPlaceholder(cm);
43 | }
44 |
45 | function isEmpty(cm) {
46 | return (cm.lineCount() === 1) && (cm.getLine(0) === "");
47 | }
48 | })();
49 |
--------------------------------------------------------------------------------
/front_end/assets/js/sass.js:
--------------------------------------------------------------------------------
1 | CodeMirror.defineMode("sass", function(config) {
2 | var tokenRegexp = function(words){
3 | return new RegExp("^" + words.join("|"));
4 | };
5 |
6 | var keywords = ["true", "false", "null", "auto"];
7 | var keywordsRegexp = new RegExp("^" + keywords.join("|"));
8 |
9 | var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"];
10 | var opRegexp = tokenRegexp(operators);
11 |
12 | var pseudoElementsRegexp = /^::?[\w\-]+/;
13 |
14 | var urlTokens = function(stream, state){
15 | var ch = stream.peek();
16 |
17 | if (ch === ")"){
18 | stream.next();
19 | state.tokenizer = tokenBase;
20 | return "operator";
21 | }else if (ch === "("){
22 | stream.next();
23 | stream.eatSpace();
24 |
25 | return "operator";
26 | }else if (ch === "'" || ch === '"'){
27 | state.tokenizer = buildStringTokenizer(stream.next());
28 | return "string";
29 | }else{
30 | state.tokenizer = buildStringTokenizer(")", false);
31 | return "string";
32 | }
33 | };
34 | var multilineComment = function(stream, state) {
35 | if (stream.skipTo("*/")){
36 | stream.next();
37 | stream.next();
38 | state.tokenizer = tokenBase;
39 | }else {
40 | stream.next();
41 | }
42 |
43 | return "comment";
44 | };
45 |
46 | var buildStringTokenizer = function(quote, greedy){
47 | if(greedy == null){ greedy = true; }
48 |
49 | function stringTokenizer(stream, state){
50 | var nextChar = stream.next();
51 | var peekChar = stream.peek();
52 | var previousChar = stream.string.charAt(stream.pos-2);
53 |
54 | var endingString = ((nextChar !== "\\" && peekChar === quote) || (nextChar === quote && previousChar !== "\\"));
55 |
56 | /*
57 | console.log("previousChar: " + previousChar);
58 | console.log("nextChar: " + nextChar);
59 | console.log("peekChar: " + peekChar);
60 | console.log("ending: " + endingString);
61 | */
62 |
63 | if (endingString){
64 | if (nextChar !== quote && greedy) { stream.next(); }
65 | state.tokenizer = tokenBase;
66 | return "string";
67 | }else if (nextChar === "#" && peekChar === "{"){
68 | state.tokenizer = buildInterpolationTokenizer(stringTokenizer);
69 | stream.next();
70 | return "operator";
71 | }else {
72 | return "string";
73 | }
74 | }
75 |
76 | return stringTokenizer;
77 | };
78 |
79 | var buildInterpolationTokenizer = function(currentTokenizer){
80 | return function(stream, state){
81 | if (stream.peek() === "}"){
82 | stream.next();
83 | state.tokenizer = currentTokenizer;
84 | return "operator";
85 | }else{
86 | return tokenBase(stream, state);
87 | }
88 | };
89 | };
90 |
91 | var indent = function(state){
92 | if (state.indentCount == 0){
93 | state.indentCount++;
94 | var lastScopeOffset = state.scopes[0].offset;
95 | var currentOffset = lastScopeOffset + config.indentUnit;
96 | state.scopes.unshift({ offset:currentOffset });
97 | }
98 | };
99 |
100 | var dedent = function(state){
101 | if (state.scopes.length == 1) { return; }
102 |
103 | state.scopes.shift();
104 | };
105 |
106 | var tokenBase = function(stream, state) {
107 | var ch = stream.peek();
108 |
109 | // Single line Comment
110 | if (stream.match('//')) {
111 | stream.skipToEnd();
112 | return "comment";
113 | }
114 |
115 | // Multiline Comment
116 | if (stream.match('/*')){
117 | state.tokenizer = multilineComment;
118 | return state.tokenizer(stream, state);
119 | }
120 |
121 | // Interpolation
122 | if (stream.match('#{')){
123 | state.tokenizer = buildInterpolationTokenizer(tokenBase);
124 | return "operator";
125 | }
126 |
127 | if (ch === "."){
128 | stream.next();
129 |
130 | // Match class selectors
131 | if (stream.match(/^[\w-]+/)){
132 | indent(state);
133 | return "atom";
134 | }else if (stream.peek() === "#"){
135 | indent(state);
136 | return "atom";
137 | }else{
138 | return "operator";
139 | }
140 | }
141 |
142 | if (ch === "#"){
143 | stream.next();
144 |
145 | // Hex numbers
146 | if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){
147 | return "number";
148 | }
149 |
150 | // ID selectors
151 | if (stream.match(/^[\w-]+/)){
152 | indent(state);
153 | return "atom";
154 | }
155 |
156 | if (stream.peek() === "#"){
157 | indent(state);
158 | return "atom";
159 | }
160 | }
161 |
162 | // Numbers
163 | if (stream.match(/^-?[0-9\.]+/)){
164 | return "number";
165 | }
166 |
167 | // Units
168 | if (stream.match(/^(px|em|in)\b/)){
169 | return "unit";
170 | }
171 |
172 | if (stream.match(keywordsRegexp)){
173 | return "keyword";
174 | }
175 |
176 | if (stream.match(/^url/) && stream.peek() === "("){
177 | state.tokenizer = urlTokens;
178 | return "atom";
179 | }
180 |
181 | // Variables
182 | if (ch === "$"){
183 | stream.next();
184 | stream.eatWhile(/[\w-]/);
185 |
186 | if (stream.peek() === ":"){
187 | stream.next();
188 | return "variable-2";
189 | }else{
190 | return "variable-3";
191 | }
192 | }
193 |
194 | if (ch === "!"){
195 | stream.next();
196 |
197 | if (stream.match(/^[\w]+/)){
198 | return "keyword";
199 | }
200 |
201 | return "operator";
202 | }
203 |
204 | if (ch === "="){
205 | stream.next();
206 |
207 | // Match shortcut mixin definition
208 | if (stream.match(/^[\w-]+/)){
209 | indent(state);
210 | return "meta";
211 | }else {
212 | return "operator";
213 | }
214 | }
215 |
216 | if (ch === "+"){
217 | stream.next();
218 |
219 | // Match shortcut mixin definition
220 | if (stream.match(/^[\w-]+/)){
221 | return "variable-3";
222 | }else {
223 | return "operator";
224 | }
225 | }
226 |
227 | // Indent Directives
228 | if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)){
229 | indent(state);
230 | return "meta";
231 | }
232 |
233 | // Other Directives
234 | if (ch === "@"){
235 | stream.next();
236 | stream.eatWhile(/[\w-]/);
237 | return "meta";
238 | }
239 |
240 | // Strings
241 | if (ch === '"' || ch === "'"){
242 | stream.next();
243 | state.tokenizer = buildStringTokenizer(ch);
244 | return "string";
245 | }
246 |
247 | // Pseudo element selectors
248 | if (ch == ':' && stream.match(pseudoElementsRegexp)){
249 | return "keyword";
250 | }
251 |
252 | // atoms
253 | if (stream.eatWhile(/[\w-&]/)){
254 | // matches a property definition
255 | if (stream.peek() === ":" && !stream.match(pseudoElementsRegexp, false))
256 | return "property";
257 | else
258 | return "atom";
259 | }
260 |
261 | if (stream.match(opRegexp)){
262 | return "operator";
263 | }
264 |
265 | // If we haven't returned by now, we move 1 character
266 | // and return an error
267 | stream.next();
268 | return null;
269 | };
270 |
271 | var tokenLexer = function(stream, state) {
272 | if (stream.sol()){
273 | state.indentCount = 0;
274 | }
275 | var style = state.tokenizer(stream, state);
276 | var current = stream.current();
277 |
278 | if (current === "@return"){
279 | dedent(state);
280 | }
281 |
282 | if (style === "atom"){
283 | indent(state);
284 | }
285 |
286 | if (style !== null){
287 | var startOfToken = stream.pos - current.length;
288 | var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount);
289 |
290 | var newScopes = [];
291 |
292 | for (var i = 0; i < state.scopes.length; i++){
293 | var scope = state.scopes[i];
294 |
295 | if (scope.offset <= withCurrentIndent){
296 | newScopes.push(scope);
297 | }
298 | }
299 |
300 | state.scopes = newScopes;
301 | }
302 |
303 |
304 | return style;
305 | };
306 |
307 | return {
308 | startState: function() {
309 | return {
310 | tokenizer: tokenBase,
311 | scopes: [{offset: 0, type: 'sass'}],
312 | definedVars: [],
313 | definedMixins: []
314 | };
315 | },
316 | token: function(stream, state) {
317 | var style = tokenLexer(stream, state);
318 |
319 | state.lastToken = { style: style, content: stream.current() };
320 |
321 | return style;
322 | },
323 |
324 | indent: function(state) {
325 | return state.scopes[0].offset;
326 | }
327 | };
328 | });
329 |
330 | CodeMirror.defineMIME("text/x-sass", "sass");
331 |
--------------------------------------------------------------------------------
/front_end/fonts/source-sans/sourcesanspro-bold-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/fonts/source-sans/sourcesanspro-bold-webfont.ttf
--------------------------------------------------------------------------------
/front_end/fonts/source-sans/sourcesanspro-bold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/fonts/source-sans/sourcesanspro-bold-webfont.woff
--------------------------------------------------------------------------------
/front_end/fonts/source-sans/sourcesanspro-regular-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/fonts/source-sans/sourcesanspro-regular-webfont.eot
--------------------------------------------------------------------------------
/front_end/fonts/source-sans/sourcesanspro-regular-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/fonts/source-sans/sourcesanspro-regular-webfont.ttf
--------------------------------------------------------------------------------
/front_end/fonts/source-sans/sourcesanspro-regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mojotech/sass2stylus/8ad3ad2e622c667837e49e38c6540a95ddbaaaca/front_end/fonts/source-sans/sourcesanspro-regular-webfont.woff
--------------------------------------------------------------------------------
/front_end/views/_api.haml:
--------------------------------------------------------------------------------
1 | .api
2 | .col-half
3 | %h3 1. Make a request
4 | %code#request_text.no_flash.api-code-block
5 | stylus_content = RestClient.post('http://sass2stylus.com/api', {'file' => File.new('YOUR-COMPASS-FILE.scss')})
6 | %button#request_btn.btn.flash_btn{"data-clipboard-target" => 'request_text'}
7 | Copy
8 | .col-half
9 | %h3 2. Parse a response
10 | %code#response_text.no_flash.api-code-block
11 | File.open('YOUR-NEW-STYLUS-FILE.styl', 'w') { |file| file.write(stylus_content) }
12 | %button#response_btn.btn.flash_btn{"data-clipboard-target" => 'response_text'}
13 | Copy
14 | .clear
15 |
--------------------------------------------------------------------------------
/front_end/views/_converter.haml:
--------------------------------------------------------------------------------
1 |
2 | .col-half.sass-col.converter-col
3 | %h2.col-header SASS/SCSS
4 | .action-buttons
5 | %input#file_selector{type:'file'}
6 | %button#upload.btn.btn-stretch-row Upload
7 | %button#convert.btn.btn-stretch-row Convert
8 | .inner-padding
9 | %form#form.sass-code.cf{method:'post', action:'/ajax'}
10 | %textarea#codemirror_sass{name:'sass_textarea'}
11 | .col-half.styl-col.converter-col
12 | %h2.col-header STYL
13 | .action-buttons
14 | %button#download_btn.btn-stretch-row.btn.download
15 | Download
16 | %button#copy_btn.btn.btn-stretch-row.copy.flash_btn
17 | Copy
18 | .inner-padding
19 | %form#download_form.styl-code.cf{method:'post', action:'download'}
20 | %textarea#codemirror_stylus{name:'stylus_textarea'}
21 |
--------------------------------------------------------------------------------
/front_end/views/_footer.haml:
--------------------------------------------------------------------------------
1 | .base-content
2 | = haml :_api
3 | .footer
4 | .contain
5 | = haml :_share
6 | #gh_btn
7 | %iframe{src: "http://ghbtns.com/github-btn.html?user=mojotech&repo=sass2stylus&type=fork", allowtransparency: "true", frameborder: "0", scrolling: "0", width: "62", height: "20"}
8 | %p.copyright.white
9 | © 2014 MojoTech · All rights reserved. Made by
10 | %a{href: 'http://mojotech.com', target: "_blank"} MojoTech
11 |
--------------------------------------------------------------------------------
/front_end/views/_messages.haml:
--------------------------------------------------------------------------------
1 | .messages.error
2 | .container
3 | .row
4 | %p.white.text-center
5 | | This is an error message.
6 | %a{class: 'close white pull-right', href: 'google.com'} ×
7 |
--------------------------------------------------------------------------------
/front_end/views/_share.haml:
--------------------------------------------------------------------------------
1 | .share
2 | %a.social-network-link.mt-facebook.mt-share-inline-square-sm{href: 'https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fsass2stylus.com'}
3 | %img{src: 'http://mojotech-static.s3.amazonaws.com/facebook@2x.png'}
4 | %a.social-network-link.mt-twitter.mt-share-inline-square-sm{href: 'http://twitter.com/intent/tweet?text=Easily%20convert%20sass%20to%20stylus&url=http%3A%2F%2Fsass2stylus.com'}
5 | %img{src: 'http://mojotech-static.s3.amazonaws.com/twitter@2x.png'}
6 | %a.social-network-link.mt-linkedin.mt-share-inline-square-sm{href: 'http://www.linkedin.com/shareArticle?mini=true&url=http%3A%2F%2Fsass2stylus.com&summary=Easily%20convert%20sass%20to%20stylus'}
7 | %img{src: 'http://mojotech-static.s3.amazonaws.com/linkedin@2x.png'}
8 | %a.social-network-link.mt-google.mt-share-inline-square-sm{href: 'https://plus.google.com/share?url=http%3A%2F%2Fsass2stylus.com'}
9 | %img{src: 'http://mojotech-static.s3.amazonaws.com/google@2x.png'}
10 |
--------------------------------------------------------------------------------
/front_end/views/index.haml:
--------------------------------------------------------------------------------
1 | = haml :_messages
2 | = haml :_converter
3 | .clear
4 |
--------------------------------------------------------------------------------
/front_end/views/layout.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %title SASS to STYLUS - Convert your SASS to STYLUS
5 |
6 | %meta{charset: "utf8"}
7 | %meta{"http-equiv" => "X-UA-Compatible", content: "IE=edge, chrome=1"}
8 | %meta{name: "sass2stylus", content: "Easily convert sass to stylus"}
9 |
10 | %link{rel: "stylesheet", href: "css/codemirror.css"}
11 | %link{rel: "stylesheet", href: "css/master.css"}
12 |
13 | %body
14 | #content
15 | =yield
16 | = haml :_footer
17 |
18 | %script{src: "https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"}
19 | %script{src: "js/codemirror.js"}
20 | %script{src: "js/css.js"}
21 | %script{src: "js/main.js"}
22 | %script{src: "js/placeholder.js"}
23 | %script{src: "js/sass.js"}
24 | %script{src: "js/ZeroClipboard.min.js"}
25 | %script{type: "text/javascript"}
26 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
27 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
28 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
29 | })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
30 | ga('create', 'UA-5925457-17', 'sass2stylus.com');
31 | ga('send', 'pageview');
32 |
--------------------------------------------------------------------------------
/functions.yml:
--------------------------------------------------------------------------------
1 | disabled_functions:
2 | - adjust-color
3 | - adjust-hue
4 | - append
5 | - call
6 | - change-color
7 | - comparable
8 | - fade-in
9 | - fade-out
10 | - feature-exists
11 | - function-exists
12 | - global-variable-exists
13 | - ie-hex-str
14 | - index
15 | - keywords
16 | - list-separator
17 | - map-get
18 | - map-remove
19 | - mixin-exists
20 | - nth
21 | - opacify
22 | - percentage
23 | - quote
24 | - random
25 | - scale-color
26 | - str-index
27 | - str-insert
28 | - str-length
29 | - str-slice
30 | - to-lower-case
31 | - to-upper-case
32 | - transparentize
33 | - unique-id
34 | - unitless
35 | - variable-exists
36 | - zip
37 |
--------------------------------------------------------------------------------
/node_converter.rb:
--------------------------------------------------------------------------------
1 | require_relative 'to_stylus.rb'
2 |
3 | puts ToStylus::convert(ARGV[0])
4 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sass2stylus",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "atob": {
8 | "version": "2.1.2",
9 | "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
10 | "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
11 | "dev": true
12 | },
13 | "balanced-match": {
14 | "version": "1.0.0",
15 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
16 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
17 | "dev": true
18 | },
19 | "brace-expansion": {
20 | "version": "1.1.11",
21 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
22 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
23 | "dev": true,
24 | "requires": {
25 | "balanced-match": "^1.0.0",
26 | "concat-map": "0.0.1"
27 | }
28 | },
29 | "concat-map": {
30 | "version": "0.0.1",
31 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
32 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
33 | "dev": true
34 | },
35 | "css": {
36 | "version": "2.2.4",
37 | "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
38 | "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
39 | "dev": true,
40 | "requires": {
41 | "inherits": "^2.0.3",
42 | "source-map": "^0.6.1",
43 | "source-map-resolve": "^0.5.2",
44 | "urix": "^0.1.0"
45 | },
46 | "dependencies": {
47 | "source-map": {
48 | "version": "0.6.1",
49 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
50 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
51 | "dev": true
52 | }
53 | }
54 | },
55 | "css-parse": {
56 | "version": "2.0.0",
57 | "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz",
58 | "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=",
59 | "dev": true,
60 | "requires": {
61 | "css": "^2.0.0"
62 | }
63 | },
64 | "debug": {
65 | "version": "3.1.0",
66 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
67 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
68 | "dev": true,
69 | "requires": {
70 | "ms": "2.0.0"
71 | }
72 | },
73 | "decode-uri-component": {
74 | "version": "0.2.0",
75 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
76 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
77 | "dev": true
78 | },
79 | "fs.realpath": {
80 | "version": "1.0.0",
81 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
82 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
83 | "dev": true
84 | },
85 | "glob": {
86 | "version": "7.1.4",
87 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
88 | "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
89 | "dev": true,
90 | "requires": {
91 | "fs.realpath": "^1.0.0",
92 | "inflight": "^1.0.4",
93 | "inherits": "2",
94 | "minimatch": "^3.0.4",
95 | "once": "^1.3.0",
96 | "path-is-absolute": "^1.0.0"
97 | }
98 | },
99 | "inflight": {
100 | "version": "1.0.6",
101 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
102 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
103 | "dev": true,
104 | "requires": {
105 | "once": "^1.3.0",
106 | "wrappy": "1"
107 | }
108 | },
109 | "inherits": {
110 | "version": "2.0.4",
111 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
112 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
113 | "dev": true
114 | },
115 | "minimatch": {
116 | "version": "3.0.4",
117 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
118 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
119 | "dev": true,
120 | "requires": {
121 | "brace-expansion": "^1.1.7"
122 | }
123 | },
124 | "minimist": {
125 | "version": "0.0.8",
126 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
127 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
128 | "dev": true
129 | },
130 | "mkdirp": {
131 | "version": "0.5.1",
132 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
133 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
134 | "dev": true,
135 | "requires": {
136 | "minimist": "0.0.8"
137 | }
138 | },
139 | "ms": {
140 | "version": "2.0.0",
141 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
142 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
143 | "dev": true
144 | },
145 | "once": {
146 | "version": "1.4.0",
147 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
148 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
149 | "dev": true,
150 | "requires": {
151 | "wrappy": "1"
152 | }
153 | },
154 | "path-is-absolute": {
155 | "version": "1.0.1",
156 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
157 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
158 | "dev": true
159 | },
160 | "resolve-url": {
161 | "version": "0.2.1",
162 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
163 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
164 | "dev": true
165 | },
166 | "safer-buffer": {
167 | "version": "2.1.2",
168 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
169 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
170 | "dev": true
171 | },
172 | "sax": {
173 | "version": "1.2.4",
174 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
175 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
176 | "dev": true
177 | },
178 | "semver": {
179 | "version": "6.3.0",
180 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
181 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
182 | "dev": true
183 | },
184 | "source-map": {
185 | "version": "0.7.3",
186 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
187 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
188 | "dev": true
189 | },
190 | "source-map-resolve": {
191 | "version": "0.5.2",
192 | "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
193 | "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
194 | "dev": true,
195 | "requires": {
196 | "atob": "^2.1.1",
197 | "decode-uri-component": "^0.2.0",
198 | "resolve-url": "^0.2.1",
199 | "source-map-url": "^0.4.0",
200 | "urix": "^0.1.0"
201 | }
202 | },
203 | "source-map-url": {
204 | "version": "0.4.0",
205 | "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
206 | "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
207 | "dev": true
208 | },
209 | "stylus": {
210 | "version": "0.54.7",
211 | "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.7.tgz",
212 | "integrity": "sha512-Yw3WMTzVwevT6ZTrLCYNHAFmanMxdylelL3hkWNgPMeTCpMwpV3nXjpOHuBXtFv7aiO2xRuQS6OoAdgkNcSNug==",
213 | "dev": true,
214 | "requires": {
215 | "css-parse": "~2.0.0",
216 | "debug": "~3.1.0",
217 | "glob": "^7.1.3",
218 | "mkdirp": "~0.5.x",
219 | "safer-buffer": "^2.1.2",
220 | "sax": "~1.2.4",
221 | "semver": "^6.0.0",
222 | "source-map": "^0.7.3"
223 | }
224 | },
225 | "urix": {
226 | "version": "0.1.0",
227 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
228 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
229 | "dev": true
230 | },
231 | "wrappy": {
232 | "version": "1.0.2",
233 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
234 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
235 | "dev": true
236 | }
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sass2stylus",
3 | "author": "Jake Buob, Cory Simmons / MojoTech, Andrey Popp",
4 | "main": "sass2stylus.js",
5 | "version": "1.0.0",
6 | "description": "Convert Sass (and SCSS) to Stylus",
7 | "keywords": [
8 | "sass",
9 | "scss",
10 | "stylus",
11 | "convert"
12 | ],
13 | "repository": [
14 | {
15 | "type": "git",
16 | "url": "https://github.com/mojotech/sass2stylus.git"
17 | }
18 | ],
19 | "scripts": {
20 | "clean": "rm -rf front_end/public && mkdir front_end/public",
21 | "watch": "npm run clean && npm run copy && npm run css:watch",
22 | "build": "npm run clean && npm run copy && npm run css:build",
23 | "copy": "npm run js:copy && npm run css:copy",
24 | "js:copy": "mkdir front_end/public/js && cp -r front_end/assets/js front_end/public",
25 | "css:copy": "mkdir front_end/public/css && cp front_end/assets/css/codemirror.css front_end/public/css/codemirror.css && cp -r front_end/fonts front_end/public/fonts",
26 | "css:watch": "stylus -w front_end/assets/css/master.styl -o front_end/public/css/master.css",
27 | "css:build": "stylus front_end/assets/css/master.styl -o front_end/public/css/master.css"
28 | },
29 | "github": "https://github.com/mojotech/sass2stylus",
30 | "preferGlobal": true,
31 | "bin": "./sass2stylus.js",
32 | "devDependencies": {
33 | "stylus": "^0.54.7"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/sass2stylus.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | var exec = require('child_process').exec,
4 | fs = require('fs'),
5 | cliArg = process.argv,
6 | filename = cliArg[2],
7 | rawFilename = filename.replace(/.scss|.sass/, ''),
8 | sassFile = filename.replace('.scss', '.sass'),
9 | converter = __dirname +'/node_converter.rb',
10 | s2s = function() {
11 | exec('ruby '+ converter +' '+ sassFile, function(error, stdout, stderr) {
12 | console.log('Converting Sass to Stylus');
13 | fs.writeFileSync(rawFilename + '.styl', stdout);
14 | if(error !== null) {
15 | console.log(error);
16 | }
17 | if(sassFile.match(/.tmp/) && sassFile.match(/.tmp/).length) {
18 | fs.unlinkSync(sassFile);
19 | }
20 | });
21 | };
22 |
23 | if(filename.match(/.scss/)) {
24 | // Convert SCSS to Sass
25 | sassFile = sassFile.replace('.sass', '.tmp.sass');
26 | exec('sass-convert '+ filename +' '+ sassFile, function(error, stdout, stderr) {
27 | s2s();
28 | if(error !== null) {
29 | console.log(error);
30 | }
31 | });
32 | } else if(filename.match(/.sass/)) {
33 | s2s();
34 | } else {
35 | console.log('You didn\'t pass a Sass (or SCSS) file.\nUsage: sass2stylus foo.scss');
36 | }
37 |
--------------------------------------------------------------------------------
/spec/fixtures/argument_splat.sass:
--------------------------------------------------------------------------------
1 | @function emCalc($values...)
2 | $max: length($values)
3 |
--------------------------------------------------------------------------------
/spec/fixtures/argument_splat.scss:
--------------------------------------------------------------------------------
1 | @function emCalc($values...) {
2 | $max: length($values);
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/argument_splat.styl:
--------------------------------------------------------------------------------
1 | emCalc($values...)
2 | $max = length($values)
3 |
--------------------------------------------------------------------------------
/spec/fixtures/atroot.sass:
--------------------------------------------------------------------------------
1 | .parent
2 | @at-root (without: media)
3 | .child1
4 | height: 100px
5 |
--------------------------------------------------------------------------------
/spec/fixtures/atroot.scss:
--------------------------------------------------------------------------------
1 | .parent {
2 | @at-root (without: media){
3 | .child1 {
4 | height: 100px;
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/atroot.styl:
--------------------------------------------------------------------------------
1 | //Below is a list of the Sass rules that could not be converted to Stylus
2 | // @at-root: line 2 in your Sass file
3 |
4 |
5 | .parent
6 | //Stylus does not support @at-root
7 | //@at-root (without: media)
8 | // .child1
9 | // height: 100px
10 |
--------------------------------------------------------------------------------
/spec/fixtures/charset.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | .foo {
4 | color: red;
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/charset.styl:
--------------------------------------------------------------------------------
1 | .foo
2 | color: red
3 |
--------------------------------------------------------------------------------
/spec/fixtures/comments.scss:
--------------------------------------------------------------------------------
1 | h1{
2 | //This is a comment
3 | //This is another comment
4 | color :blue;
5 | h2{
6 | /*This is
7 | *a
8 | *comment block
9 | */
10 | color: red;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/spec/fixtures/comments.styl:
--------------------------------------------------------------------------------
1 | h1
2 | //This is a comment
3 | //This is another comment
4 | color: blue
5 | h2
6 | /*This is
7 | *a
8 | *comment block
9 | */
10 | color: red
11 |
--------------------------------------------------------------------------------
/spec/fixtures/content.sass:
--------------------------------------------------------------------------------
1 | @media screen and (max-width: 100px)
2 | @content
3 |
--------------------------------------------------------------------------------
/spec/fixtures/content.scss:
--------------------------------------------------------------------------------
1 | @media screen and (max-width: 100px){
2 | @content;
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/content.styl:
--------------------------------------------------------------------------------
1 | @media screen and (max-width: 100px)
2 | {block}
3 |
--------------------------------------------------------------------------------
/spec/fixtures/debug.sass:
--------------------------------------------------------------------------------
1 | @debug 10em + 12em
2 |
--------------------------------------------------------------------------------
/spec/fixtures/debug.scss:
--------------------------------------------------------------------------------
1 | @debug 10em + 12em;
2 |
--------------------------------------------------------------------------------
/spec/fixtures/debug.styl:
--------------------------------------------------------------------------------
1 | //Below is a list of the Sass rules that could not be converted to Stylus
2 | // @debug: line 1 in your Sass file
3 |
4 |
5 | //Stylus does not support @debug
6 | //@debug 10em + 12em
7 |
--------------------------------------------------------------------------------
/spec/fixtures/disabled_functions.sass:
--------------------------------------------------------------------------------
1 | h1
2 | color: adjust-color(red, $blue: 5)
3 | color: adjust-hue(red, 10)
4 | $list: append($list1, $list2)
5 | color: call(rgb, 10, 100, 255)
6 | color: change-color(#102030, $blue: 5)
7 | $bool: comparable(2px, 1px)
8 | $color: fade-in(red, 10)
9 | $color: fade-out(red, 10)
10 | $bool: feature-exists(some-feature)
11 | $bool: function-exists(some-function)
12 | $bool: global-variable-exists(global)
13 | $str: ie-hex-str(#abc)
14 | $index: index(1px solid red, solid)
15 | @mixin foo($args...)
16 | $list: keywords($args)
17 |
18 | $listSep: list-separator(1px 2px 3px)
19 | $map: map-remove(("foo": 1, "bar": 2), "bar")
20 | $bool: mixin-exists(mixin)
21 | $index: nth(10px 20px 30px, 1)
22 | $color: opacify(rgba(0, 0, 0, 0.5), 0.1)
23 | $percent: percentage(0.2)
24 | $str: quote('string')
25 | $number: random(10)
26 | $color: scale-color(hsl(120, 70%, 80%), $lightness: 50%)
27 | $number: str-index(abcd, a)
28 | $str: str-insert('abcd', x, 1)
29 | $number: str-length('foo')
30 | $str: str-slice('abcd', 2, 3)
31 | $str: to-lower-case('lower')
32 | $str: to-upper-case('upper')
33 | $color: transparentize(rgba(0,0,0,0.5), 0.1)
34 | $number: unique-id()
35 | $bool: unitless(100)
36 | $bool: variable-exists(nonexistent)
37 | $list: zip(1px 1px 3px, solid dashed solid, red green blue)
38 | @function emCalc($values...)
39 | @return adjust-color(red, $blue: 5)
40 |
--------------------------------------------------------------------------------
/spec/fixtures/disabled_functions.scss:
--------------------------------------------------------------------------------
1 | h1{
2 | color: adjust-color(red, $blue: 5);
3 | color: adjust-hue(red, 10);
4 | $list: append($list1, $list2);
5 | color: call(rgb, 10, 100, 255);
6 | color: change-color(#102030, $blue: 5);
7 | $bool: comparable(2px, 1px);
8 | $color: fade-in(red, 10);
9 | $color: fade-out(red, 10);
10 | $bool: feature-exists(some-feature);
11 | $bool: function-exists(some-function);
12 | $bool: global-variable-exists(global);
13 | $str: ie-hex-str(#abc);
14 | $index: index(1px solid red, solid);
15 | @mixin foo($args...) {
16 | $list: keywords($args);
17 | }
18 | $listSep: list-separator(1px 2px 3px);
19 | $map: map-remove(("foo": 1, "bar": 2), "bar");
20 | $bool: mixin-exists(mixin);
21 | $index: nth(10px 20px 30px, 1);
22 | $color: opacify(rgba(0, 0, 0, 0.5), 0.1);
23 | $percent: percentage(0.2);
24 | $str: quote('string');
25 | $number: random(10);
26 | $color: scale-color(hsl(120, 70%, 80%), $lightness: 50%);
27 | $number: str-index(abcd, a);
28 | $str: str-insert('abcd', x, 1);
29 | $number: str-length('foo');
30 | $str: str-slice('abcd', 2, 3);
31 | $str: to-lower-case('lower');
32 | $str: to-upper-case('upper');
33 | $color: transparentize(rgba(0,0,0,0.5), 0.1);
34 | $number: unique-id();
35 | $bool: unitless(100);
36 | $bool: variable-exists(nonexistent);
37 | $list: zip(1px 1px 3px, solid dashed solid, red green blue);
38 | @function emCalc($values...) {
39 | @return adjust-color(red, $blue: 5);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/spec/fixtures/disabled_functions.styl:
--------------------------------------------------------------------------------
1 | //Below is a list of the Sass rules that could not be converted to Stylus
2 | //adjust-color: line 2 in your Sass file
3 | //adjust-hue: line 3 in your Sass file
4 | //append: line 4 in your Sass file
5 | //call: line 5 in your Sass file
6 | //change-color: line 6 in your Sass file
7 | //comparable: line 7 in your Sass file
8 | //fade-in: line 8 in your Sass file
9 | //fade-out: line 9 in your Sass file
10 | //feature-exists: line 10 in your Sass file
11 | //function-exists: line 11 in your Sass file
12 | //global-variable-exists: line 12 in your Sass file
13 | //ie-hex-str: line 13 in your Sass file
14 | //index: line 14 in your Sass file
15 | //keywords: line 16 in your Sass file
16 | //list-separator: line 18 in your Sass file
17 | //map-remove: line 19 in your Sass file
18 | //mixin-exists: line 20 in your Sass file
19 | //nth: line 21 in your Sass file
20 | //opacify: line 22 in your Sass file
21 | //percentage: line 23 in your Sass file
22 | //quote: line 24 in your Sass file
23 | //random: line 25 in your Sass file
24 | //scale-color: line 26 in your Sass file
25 | //index: line 27 in your Sass file
26 | //str-insert: line 28 in your Sass file
27 | //str-length: line 29 in your Sass file
28 | //str-slice: line 30 in your Sass file
29 | //to-lower-case: line 31 in your Sass file
30 | //to-upper-case: line 32 in your Sass file
31 | //transparentize: line 33 in your Sass file
32 | //unique-id: line 34 in your Sass file
33 | //unitless: line 35 in your Sass file
34 | //variable-exists: line 36 in your Sass file
35 | //zip: line 37 in your Sass file
36 | //adjust-color: line 39 in your Sass file
37 |
38 |
39 | h1
40 | //Function adjust-color is not supported in Stylus
41 | //color: adjust-color(red, $blue: 5)
42 | //Function adjust-hue is not supported in Stylus
43 | //color: adjust-hue(red, 10)
44 | //Function append is not supported in Stylus
45 | //$list = append($list1, $list2)
46 | //Function call is not supported in Stylus
47 | //color: call(rgb, 10, 100, 255)
48 | //Function change-color is not supported in Stylus
49 | //color: change-color(#102030, $blue: 5)
50 | //Function comparable is not supported in Stylus
51 | //$bool = comparable(2px, 1px)
52 | //Function fade-in is not supported in Stylus
53 | //$color = fade-in(red, 10)
54 | //Function fade-out is not supported in Stylus
55 | //$color = fade-out(red, 10)
56 | //Function feature-exists is not supported in Stylus
57 | //$bool = feature-exists(some-feature)
58 | //Function function-exists is not supported in Stylus
59 | //$bool = function-exists(some-function)
60 | //Function global-variable-exists is not supported in Stylus
61 | //$bool = global-variable-exists(global)
62 | //Function ie-hex-str is not supported in Stylus
63 | //$str = ie-hex-str(#aabbcc)
64 | //Function index is not supported in Stylus
65 | //$index = index(1px solid red, solid)
66 | foo()
67 | //Function keywords is not supported in Stylus
68 | //$list = keywords($args)
69 | //Function list-separator is not supported in Stylus
70 | //$listSep = list-separator(1px 2px 3px)
71 | //Function map-remove is not supported in Stylus
72 | //$map = map-remove(("foo": 1, "bar": 2), "bar")
73 | //Function mixin-exists is not supported in Stylus
74 | //$bool = mixin-exists(mixin)
75 | //Function nth is not supported in Stylus
76 | //$index = nth(10px 20px 30px, 1)
77 | //Function opacify is not supported in Stylus
78 | //$color = opacify(rgba(0, 0, 0, 0.5), 0.1)
79 | //Function percentage is not supported in Stylus
80 | //$percent = percentage(0.2)
81 | //Function quote is not supported in Stylus
82 | //$str = quote("string")
83 | //Function random is not supported in Stylus
84 | //$number = random(10)
85 | //Function scale-color is not supported in Stylus
86 | //$color = scale-color(hsl(120, 70%, 80%), $lightness: 50%)
87 | //Function index is not supported in Stylus
88 | //$number = str-index(abcd, a)
89 | //Function str-insert is not supported in Stylus
90 | //$str = str-insert("abcd", x, 1)
91 | //Function str-length is not supported in Stylus
92 | //$number = str-length("foo")
93 | //Function str-slice is not supported in Stylus
94 | //$str = str-slice("abcd", 2, 3)
95 | //Function to-lower-case is not supported in Stylus
96 | //$str = to-lower-case("lower")
97 | //Function to-upper-case is not supported in Stylus
98 | //$str = to-upper-case("upper")
99 | //Function transparentize is not supported in Stylus
100 | //$color = transparentize(rgba(0, 0, 0, 0.5), 0.1)
101 | //Function unique-id is not supported in Stylus
102 | //$number = unique-id()
103 | //Function unitless is not supported in Stylus
104 | //$bool = unitless(100)
105 | //Function variable-exists is not supported in Stylus
106 | //$bool = variable-exists(nonexistent)
107 | //Function zip is not supported in Stylus
108 | //$list = zip(1px 1px 3px, solid dashed solid, red green blue)
109 | emCalc($values...)
110 | //Function adjust-color is not supported in Stylus
111 | //adjust-color(red, $blue: 5)
112 |
--------------------------------------------------------------------------------
/spec/fixtures/each.sass:
--------------------------------------------------------------------------------
1 | $list: one two three four
2 |
3 | =mixy
4 | @each $number, $number2 in $list
5 | #hashtag
6 | background: image-url("#{$number}.png")
7 |
8 | =mixy
9 | @each $number in $list
10 | #hashtag
11 | background: image-url("#{$number}.png")
12 |
13 | @each $animal in puma, sea-slug, egret, salamander
14 | .#{$animal}-icon
15 | width: 10px
16 |
17 |
18 |
--------------------------------------------------------------------------------
/spec/fixtures/each.scss:
--------------------------------------------------------------------------------
1 | $list: one two three four;
2 |
3 | @mixin mixy {
4 | @each $number, $number2 in $list {
5 | #hashtag {
6 | background: image-url("#{$number}.png");
7 | }
8 | }
9 | }
10 |
11 | @mixin mixy {
12 | @each $number in $list {
13 | #hashtag {
14 | background: image-url("#{$number}.png");
15 | }
16 | }
17 | }
18 | @each $animal in puma, sea-slug, egret, salamander {
19 | .#{$animal}-icon {
20 | width: 10px;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/spec/fixtures/each.styl:
--------------------------------------------------------------------------------
1 | //Below is a list of the Sass rules that could not be converted to Stylus
2 | // @each: line 4 in your Sass file
3 |
4 |
5 | $list = one two three four
6 | mixy()
7 | //Cannot convert multi-variable each loops to Stylus
8 | //@each $number, $number2 in $list
9 | // #hashtag
10 | // background: image-url("#{$number}.png")
11 | mixy()
12 | for $number in $list
13 | #hashtag
14 | background: image-url("{$number}.png")
15 | for $animal in puma sea-slug egret salamander
16 | .{$animal}-icon
17 | width: 10px
18 |
--------------------------------------------------------------------------------
/spec/fixtures/extend.sass:
--------------------------------------------------------------------------------
1 | div
2 | @extend .block
3 |
4 |
--------------------------------------------------------------------------------
/spec/fixtures/extend.scss:
--------------------------------------------------------------------------------
1 | div{
2 | @extend .block;
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/extend.styl:
--------------------------------------------------------------------------------
1 | div
2 | @extend .block
3 |
--------------------------------------------------------------------------------
/spec/fixtures/font_face.sass:
--------------------------------------------------------------------------------
1 | @font-face
2 | font-family: "altisextra_bold"
3 | src: url('fonts/altis_extrabold/altis-extrabold-webfont.eot')
4 | src: url('fonts/altis_extrabold/altis-extrabold-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/altis_extrabold/altis-extrabold-webfont.woff') format('woff'), url('fonts/altis_extrabold/altis-extrabold-webfont.ttf') format('truetype'), url('fonts/altis_extrabold/altis-extrabold-webfont.svg#altisextra_bold') format('svg')
5 | font-weight: normal
6 | font-style: normal
7 |
--------------------------------------------------------------------------------
/spec/fixtures/font_face.scss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "altisextra_bold";
3 | src: url('fonts/altis_extrabold/altis-extrabold-webfont.eot');
4 | src: url('fonts/altis_extrabold/altis-extrabold-webfont.eot?#iefix') format('embedded-opentype'),
5 | url('fonts/altis_extrabold/altis-extrabold-webfont.woff') format('woff'),
6 | url('fonts/altis_extrabold/altis-extrabold-webfont.ttf') format('truetype'),
7 | url('fonts/altis_extrabold/altis-extrabold-webfont.svg#altisextra_bold') format('svg');
8 | font-weight: normal;
9 | font-style: normal;
10 | }
11 |
--------------------------------------------------------------------------------
/spec/fixtures/font_face.styl:
--------------------------------------------------------------------------------
1 | @font-face
2 | font-family: "altisextra_bold"
3 | src: url("fonts/altis_extrabold/altis-extrabold-webfont.eot")
4 | src: url("fonts/altis_extrabold/altis-extrabold-webfont.eot?#iefix") format("embedded-opentype"), url("fonts/altis_extrabold/altis-extrabold-webfont.woff") format("woff"), url("fonts/altis_extrabold/altis-extrabold-webfont.ttf") format("truetype"), url("fonts/altis_extrabold/altis-extrabold-webfont.svg#altisextra_bold") format("svg")
5 | font-weight: normal
6 | font-style: normal
7 |
--------------------------------------------------------------------------------
/spec/fixtures/foo.sass:
--------------------------------------------------------------------------------
1 | =foo
2 | background: red
3 |
4 | .bar
5 | +foo
6 |
--------------------------------------------------------------------------------
/spec/fixtures/foo.scss:
--------------------------------------------------------------------------------
1 | @mixin foo() {
2 | background: red;
3 | }
4 | .bar {
5 | @include foo();
6 | }
7 |
--------------------------------------------------------------------------------
/spec/fixtures/foo.styl:
--------------------------------------------------------------------------------
1 | foo()
2 | background: red
3 | .bar
4 | foo()
5 |
--------------------------------------------------------------------------------
/spec/fixtures/for.sass:
--------------------------------------------------------------------------------
1 | @for $i from 1 through 10
2 | $emValues: $i
3 |
4 | @for $i from 1 to 10
5 | $emValues: $i
6 |
7 | @for $i from 1 through $num
8 | $emValues: $i
9 |
10 | @for $i from 1 to $num
11 | $emValues: $i
12 |
--------------------------------------------------------------------------------
/spec/fixtures/for.scss:
--------------------------------------------------------------------------------
1 | @for $i from 1 through 10 {
2 | $emValues: $i;
3 | }
4 |
5 | @for $i from 1 to 10 {
6 | $emValues: $i;
7 | }
8 |
9 | @for $i from 1 through $num{
10 | $emValues: $i;
11 | }
12 |
13 | @for $i from 1 to $num{
14 | $emValues: $i;
15 | }
16 |
--------------------------------------------------------------------------------
/spec/fixtures/for.styl:
--------------------------------------------------------------------------------
1 | for $i in (1)..(10)
2 | $emValues = $i
3 | for $i in (1)..(9)
4 | $emValues = $i
5 | for $i in (1)..($num)
6 | $emValues = $i
7 | for $i in (1)..(($num) - 1)
8 | $emValues = $i
9 |
--------------------------------------------------------------------------------
/spec/fixtures/import.sass:
--------------------------------------------------------------------------------
1 | @import 'reset.css'
2 | @import url('hello.com')
3 | @import "http://www.mojotech.com"
4 | @import url(.com)
5 |
--------------------------------------------------------------------------------
/spec/fixtures/import.scss:
--------------------------------------------------------------------------------
1 | @import 'reset.css';
2 | @import url('hello.com');
3 | @import "http://www.mojotech.com";
4 | @import url(.com);
5 |
--------------------------------------------------------------------------------
/spec/fixtures/import.styl:
--------------------------------------------------------------------------------
1 | @import 'reset.css'
2 | @import url("hello.com")
3 | @import url("http://www.mojotech.com")
4 | @import url(.com)
5 |
--------------------------------------------------------------------------------
/spec/fixtures/interpolated_key_values.sass:
--------------------------------------------------------------------------------
1 | calc($property, $value)
2 | #{$property}: -webkit-calc(#{$value})
3 | #{$property}: calc(#{$value})
4 |
--------------------------------------------------------------------------------
/spec/fixtures/interpolated_key_values.scss:
--------------------------------------------------------------------------------
1 | @mixin calc($property, $value) {
2 | #{$property}: -webkit-calc(#{$value});
3 | #{$property}: calc(#{$value});
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/interpolated_key_values.styl:
--------------------------------------------------------------------------------
1 | calc($property, $value)
2 | {$property}: -webkit-calc({$value})
3 | {$property}: calc({$value})
4 |
--------------------------------------------------------------------------------
/spec/fixtures/interpolation.sass:
--------------------------------------------------------------------------------
1 | div
2 | #{$header}
3 | font-size: $size
4 |
5 |
--------------------------------------------------------------------------------
/spec/fixtures/interpolation.scss:
--------------------------------------------------------------------------------
1 | div {
2 | #{$header} {
3 | font-size: $size;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/interpolation.styl:
--------------------------------------------------------------------------------
1 | div
2 | {$header}
3 | font-size: $size
4 |
--------------------------------------------------------------------------------
/spec/fixtures/media_queries.sass:
--------------------------------------------------------------------------------
1 | @media screen and (max-width: 100px)
2 | width: 100px
3 |
--------------------------------------------------------------------------------
/spec/fixtures/media_queries.scss:
--------------------------------------------------------------------------------
1 | @media screen and (max-width: 100px) {
2 | width: 100px;
3 | }
4 |
--------------------------------------------------------------------------------
/spec/fixtures/media_queries.styl:
--------------------------------------------------------------------------------
1 | @media screen and (max-width: 100px)
2 | width: 100px
3 |
--------------------------------------------------------------------------------
/spec/fixtures/multi_line_selectors.sass:
--------------------------------------------------------------------------------
1 | html, body, div, span, applet, object, iframe,
2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
3 | a, abbr, acronym, address, big, cite, code,
4 | del, dfn, em, img, ins, kbd, q, s, samp,
5 | small, strike, strong, sub, sup, tt, var,
6 | b, i, u, center,
7 | dl, dt, dd, ol, ul, li,
8 | fieldset, form, label, legend,
9 | table, caption, tbody, tfoot, thead, tr, th, td,
10 | article, aside, canvas, details, embed, fieldset,
11 | figure, figcaption, footer, header, hgroup,
12 | menu, nav, output, ruby, section, summary,
13 | time, mark, audio, video
14 | margin: 0
15 | padding: 0
16 | border: 0
17 | vertical-align: baseline
18 | font: inherit
19 | font-size: 100%
20 |
--------------------------------------------------------------------------------
/spec/fixtures/multi_line_selectors.scss:
--------------------------------------------------------------------------------
1 | html, body, div, span, applet, object, iframe,
2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
3 | a, abbr, acronym, address, big, cite, code,
4 | del, dfn, em, img, ins, kbd, q, s, samp,
5 | small, strike, strong, sub, sup, tt, var,
6 | b, i, u, center,
7 | dl, dt, dd, ol, ul, li,
8 | fieldset, form, label, legend,
9 | table, caption, tbody, tfoot, thead, tr, th, td,
10 | article, aside, canvas, details, embed, fieldset,
11 | figure, figcaption, footer, header, hgroup,
12 | menu, nav, output, ruby, section, summary,
13 | time, mark, audio, video {
14 | margin: 0;
15 | padding: 0;
16 | border: 0;
17 | vertical-align: baseline;
18 | font: inherit;
19 | font-size: 100%;
20 | }
21 |
--------------------------------------------------------------------------------
/spec/fixtures/multi_line_selectors.styl:
--------------------------------------------------------------------------------
1 | html, body, div, span, applet, object, iframe,
2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
3 | a, abbr, acronym, address, big, cite, code,
4 | del, dfn, em, img, ins, kbd, q, s, samp,
5 | small, strike, strong, sub, sup, tt, var,
6 | b, i, u, center,
7 | dl, dt, dd, ol, ul, li,
8 | fieldset, form, label, legend,
9 | table, caption, tbody, tfoot, thead, tr, th, td,
10 | article, aside, canvas, details, embed, fieldset,
11 | figure, figcaption, footer, header, hgroup,
12 | menu, nav, output, ruby, section, summary,
13 | time, mark, audio, video
14 | margin: 0
15 | padding: 0
16 | border: 0
17 | vertical-align: baseline
18 | font: inherit
19 | font-size: 100%
20 |
--------------------------------------------------------------------------------
/spec/fixtures/nested_properties.sass:
--------------------------------------------------------------------------------
1 | .funky
2 | font:
3 | family: fantasy
4 | size: 30em
5 | weight: bold
6 | .doge
7 | font: 25px red
8 | weight: bold
9 |
--------------------------------------------------------------------------------
/spec/fixtures/nested_properties.scss:
--------------------------------------------------------------------------------
1 | .funky {
2 | font: {
3 | family: fantasy;
4 | size: 30em;
5 | weight: bold;
6 | }
7 | }
8 | .doge {
9 | font: 25px red {
10 | weight: bold;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/spec/fixtures/nested_properties.styl:
--------------------------------------------------------------------------------
1 | .funky
2 | font-family: fantasy
3 | font-size: 30em
4 | font-weight: bold
5 | .doge
6 | font: 25px red
7 | font-weight: bold
8 |
--------------------------------------------------------------------------------
/spec/fixtures/placeholder_selectors.sass:
--------------------------------------------------------------------------------
1 | %foo
2 | background: red
3 | h1
4 | @extend %foo
5 |
--------------------------------------------------------------------------------
/spec/fixtures/placeholder_selectors.scss:
--------------------------------------------------------------------------------
1 | %foo {
2 | background: red;
3 | }
4 | h1 {
5 | @extend %foo;
6 | }
7 |
--------------------------------------------------------------------------------
/spec/fixtures/placeholder_selectors.styl:
--------------------------------------------------------------------------------
1 | $foo
2 | background: red
3 | h1
4 | @extend $foo
5 |
--------------------------------------------------------------------------------
/spec/fixtures/prop_negated_variables.sass:
--------------------------------------------------------------------------------
1 | $foo: 10px
2 | .bar
3 | margin: -$foo
4 |
--------------------------------------------------------------------------------
/spec/fixtures/prop_negated_variables.scss:
--------------------------------------------------------------------------------
1 | $foo: 10px;
2 | .bar{
3 | margin: -$foo;
4 | }
5 |
--------------------------------------------------------------------------------
/spec/fixtures/prop_negated_variables.styl:
--------------------------------------------------------------------------------
1 | $foo = 10px
2 | .bar
3 | margin: -1*$foo
4 |
--------------------------------------------------------------------------------
/spec/fixtures/prop_operations.sass:
--------------------------------------------------------------------------------
1 | $foo: 10px
2 | .bar
3 | margin: $foo/2
4 |
--------------------------------------------------------------------------------
/spec/fixtures/prop_operations.scss:
--------------------------------------------------------------------------------
1 | $foo: 10px;
2 |
3 | .bar {
4 | margin: $foo/2;
5 | }
6 |
--------------------------------------------------------------------------------
/spec/fixtures/prop_operations.styl:
--------------------------------------------------------------------------------
1 | $foo = 10px
2 | .bar
3 | margin: ($foo / 2)
4 |
--------------------------------------------------------------------------------
/spec/fixtures/warn.sass:
--------------------------------------------------------------------------------
1 | =adjust-location($x, $y)
2 | @if unitless($x)
3 | @warn "Assuming #{$x} to be in pixels"
4 | $x: 1px * $x
5 |
--------------------------------------------------------------------------------
/spec/fixtures/warn.scss:
--------------------------------------------------------------------------------
1 | @mixin adjust-location($x, $y) {
2 | @if unitless($x) {
3 | @warn "Assuming #{$x} to be in pixels";
4 | $x: 1px * $x;
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/spec/fixtures/warn.styl:
--------------------------------------------------------------------------------
1 | //Below is a list of the Sass rules that could not be converted to Stylus
2 | // @warn: line 3 in your Sass file
3 |
4 |
5 | adjust-location($x, $y)
6 | if unitless($x)
7 | //Stylus does not support @warn
8 | //@warn "Assuming #{$x} to be in pixels"
9 | $x = 1px * $x
10 |
--------------------------------------------------------------------------------
/spec/fixtures/while.sass:
--------------------------------------------------------------------------------
1 | @while $types > 0
2 | .while-#{$types}
3 | width: $type-width + $types
4 | $types: $types - 1
5 |
--------------------------------------------------------------------------------
/spec/fixtures/while.scss:
--------------------------------------------------------------------------------
1 | @while $types > 0 {
2 | .while-#{$types} {
3 | width: $type-width + $types;
4 | }
5 | $types: $types - 1;
6 | }
7 |
--------------------------------------------------------------------------------
/spec/fixtures/while.styl:
--------------------------------------------------------------------------------
1 | //Below is a list of the Sass rules that could not be converted to Stylus
2 | // @while: line 1 in your Sass file
3 |
4 |
5 | //Stylus does not support while loops
6 | //@while $types > 0
7 | // .while-#{$types}
8 | // width: $type-width + $types
9 | // $types: $types - 1
10 |
--------------------------------------------------------------------------------
/spec/to_stylus_spec.rb:
--------------------------------------------------------------------------------
1 | $:.unshift(File.join(File.dirname(__FILE__), '..'))
2 | require 'to_stylus'
3 |
4 | describe ToStylus do
5 | before do
6 | @path = File.dirname(__FILE__)
7 | end
8 |
9 | it "converts a sass file to styl" do
10 | ToStylus.convert("#{@path}/fixtures/foo.sass").should eq(File.read("#{@path}/fixtures/foo.styl").chomp)
11 | end
12 |
13 | it "converts a scss file to styl" do
14 | ToStylus.convert("#{@path}/fixtures/foo.scss").should eq(File.read("#{@path}/fixtures/foo.styl").chomp)
15 | end
16 |
17 | it "handles scss extends" do
18 | ToStylus.convert("#{@path}/fixtures/extend.scss").should eq(File.read("#{@path}/fixtures/extend.styl").chomp)
19 | end
20 |
21 | it "handles sass extends" do
22 | ToStylus.convert("#{@path}/fixtures/extend.sass").should eq(File.read("#{@path}/fixtures/extend.styl").chomp)
23 | end
24 |
25 | it "handles scss media queries" do
26 | ToStylus.convert("#{@path}/fixtures/media_queries.scss").should eq(File.read("#{@path}/fixtures/media_queries.styl").chomp)
27 | end
28 |
29 | it "handles sass media queries" do
30 | ToStylus.convert("#{@path}/fixtures/media_queries.sass").should eq(File.read("#{@path}/fixtures/media_queries.styl").chomp)
31 | end
32 |
33 | it "handles scss import" do
34 | ToStylus.convert("#{@path}/fixtures/import.scss").should eq(File.read("#{@path}/fixtures/import.styl").chomp)
35 | end
36 |
37 | it "handles sass import" do
38 | ToStylus.convert("#{@path}/fixtures/import.sass").should eq(File.read("#{@path}/fixtures/import.styl").chomp)
39 | end
40 |
41 | it "handles scss argument splats" do
42 | ToStylus.convert("#{@path}/fixtures/argument_splat.scss").should eq(File.read("#{@path}/fixtures/argument_splat.styl").chomp)
43 | end
44 |
45 | it "handles sass argument splats" do
46 | ToStylus.convert("#{@path}/fixtures/argument_splat.sass").should eq(File.read("#{@path}/fixtures/argument_splat.styl").chomp)
47 | end
48 |
49 | it "converts scss content to {block}" do
50 | ToStylus.convert("#{@path}/fixtures/content.scss").should eq(File.read("#{@path}/fixtures/content.styl").chomp)
51 | end
52 |
53 | it "converts sass content to {block}" do
54 | ToStylus.convert("#{@path}/fixtures/content.sass").should eq(File.read("#{@path}/fixtures/content.styl").chomp)
55 | end
56 |
57 | it "handles sass for loops" do
58 | ToStylus.convert("#{@path}/fixtures/for.sass").should eq(File.read("#{@path}/fixtures/for.styl").chomp)
59 | end
60 |
61 | it "handles scss for loops" do
62 | ToStylus.convert("#{@path}/fixtures/for.scss").should eq(File.read("#{@path}/fixtures/for.styl").chomp)
63 | end
64 |
65 | it "handles sass interpolation" do
66 | ToStylus.convert("#{@path}/fixtures/interpolation.sass").should eq(File.read("#{@path}/fixtures/interpolation.styl").chomp)
67 | end
68 |
69 | it "handles scss interpolation" do
70 | ToStylus.convert("#{@path}/fixtures/interpolation.scss").should eq(File.read("#{@path}/fixtures/interpolation.styl").chomp)
71 | end
72 |
73 | it "converts sass each iteration to for loop" do
74 | ToStylus.convert("#{@path}/fixtures/each.sass").should eq(File.read("#{@path}/fixtures/each.styl").chomp)
75 | end
76 |
77 | it "converts scss each iteration to for loop" do
78 | ToStylus.convert("#{@path}/fixtures/each.scss").should eq(File.read("#{@path}/fixtures/each.styl").chomp)
79 | end
80 |
81 | it "comments out sass while loops" do
82 | ToStylus.convert("#{@path}/fixtures/while.sass").should eq(File.read("#{@path}/fixtures/while.styl").chomp)
83 | end
84 |
85 | it "comments out scss while loops" do
86 | ToStylus.convert("#{@path}/fixtures/while.scss").should eq(File.read("#{@path}/fixtures/while.styl").chomp)
87 | end
88 |
89 | it "comments out sass @at-root" do
90 | ToStylus.convert("#{@path}/fixtures/atroot.sass").should eq(File.read("#{@path}/fixtures/atroot.styl").chomp)
91 | end
92 |
93 | it "comments out scss @at-root" do
94 | ToStylus.convert("#{@path}/fixtures/atroot.scss").should eq(File.read("#{@path}/fixtures/atroot.styl").chomp)
95 | end
96 |
97 | it "comments out sass @debug" do
98 | ToStylus.convert("#{@path}/fixtures/debug.sass").should eq(File.read("#{@path}/fixtures/debug.styl").chomp)
99 | end
100 |
101 | it "comments out scss @debug" do
102 | ToStylus.convert("#{@path}/fixtures/debug.scss").should eq(File.read("#{@path}/fixtures/debug.styl").chomp)
103 | end
104 |
105 | it "comments out sass @warn" do
106 | ToStylus.convert("#{@path}/fixtures/warn.sass").should eq(File.read("#{@path}/fixtures/warn.styl").chomp)
107 | end
108 |
109 | it "comments out scss @warn" do
110 | ToStylus.convert("#{@path}/fixtures/warn.scss").should eq(File.read("#{@path}/fixtures/warn.styl").chomp)
111 | end
112 |
113 | it "handles sass placeholder selectors" do
114 | ToStylus.convert("#{@path}/fixtures/placeholder_selectors.sass").should eq(File.read("#{@path}/fixtures/placeholder_selectors.styl").chomp)
115 | end
116 |
117 | it "comments scss placeholder selectors" do
118 | ToStylus.convert("#{@path}/fixtures/placeholder_selectors.scss").should eq(File.read("#{@path}/fixtures/placeholder_selectors.styl").chomp)
119 | end
120 |
121 | it "handles sass nested properties" do
122 | ToStylus.convert("#{@path}/fixtures/nested_properties.sass").should eq(File.read("#{@path}/fixtures/nested_properties.styl").chomp)
123 | end
124 |
125 | it "handles scss nested properties" do
126 | ToStylus.convert("#{@path}/fixtures/nested_properties.scss").should eq(File.read("#{@path}/fixtures/nested_properties.styl").chomp)
127 | end
128 |
129 | it "handles sass interpolated key values" do
130 | ToStylus.convert("#{@path}/fixtures/interpolated_key_values.sass").should eq(File.read("#{@path}/fixtures/interpolated_key_values.styl").chomp)
131 | end
132 |
133 | it "handles scss interpolated key values" do
134 | ToStylus.convert("#{@path}/fixtures/interpolated_key_values.scss").should eq(File.read("#{@path}/fixtures/interpolated_key_values.styl").chomp)
135 | end
136 |
137 | it "comments out sass unsupported functions" do
138 | ToStylus.convert("#{@path}/fixtures/disabled_functions.sass").should eq(File.read("#{@path}/fixtures/disabled_functions.styl").chomp)
139 | end
140 |
141 | it "comments out scss unsupported functions" do
142 | ToStylus.convert("#{@path}/fixtures/disabled_functions.scss").should eq(File.read("#{@path}/fixtures/disabled_functions.styl").chomp)
143 | end
144 |
145 | it "conversts comments" do
146 | ToStylus.convert("#{@path}/fixtures/comments.scss").should eq(File.read("#{@path}/fixtures/comments.styl").chomp)
147 | end
148 |
149 | it "handles scss @font-face" do
150 | ToStylus.convert("#{@path}/fixtures/font_face.scss").should eq(File.read("#{@path}/fixtures/font_face.styl").chomp)
151 | end
152 |
153 | it "handles sass @font-face " do
154 | ToStylus.convert("#{@path}/fixtures/font_face.sass").should eq(File.read("#{@path}/fixtures/font_face.styl").chomp)
155 | end
156 |
157 | it "wraps scss prop operations in parentheses" do
158 | ToStylus.convert("#{@path}/fixtures/prop_operations.scss").should eq(File.read("#{@path}/fixtures/prop_operations.styl").chomp)
159 | end
160 |
161 | it "wraps sass prop operations in parentheses" do
162 | ToStylus.convert("#{@path}/fixtures/prop_operations.sass").should eq(File.read("#{@path}/fixtures/prop_operations.styl").chomp)
163 | end
164 |
165 | it "converts negated prop variables to operation scss" do
166 | ToStylus.convert("#{@path}/fixtures/prop_negated_variables.scss").should eq(File.read("#{@path}/fixtures/prop_negated_variables.styl").chomp)
167 | end
168 |
169 | it "converts negated prop variables to operation sass" do
170 | ToStylus.convert("#{@path}/fixtures/prop_negated_variables.sass").should eq(File.read("#{@path}/fixtures/prop_negated_variables.styl").chomp)
171 | end
172 |
173 | %w(sass scss).each do |type|
174 | it "handles multi-line selectors for #{type}" do
175 | ToStylus.convert("#{@path}/fixtures/multi_line_selectors.#{type}").should eq(File.read("#{@path}/fixtures/multi_line_selectors.styl").chomp)
176 | end
177 | end
178 |
179 | it "handles Sass charset directive" do
180 | ToStylus.convert("#{@path}/fixtures/charset.scss").should eq(File.read("#{@path}/fixtures/charset.styl").chomp)
181 | end
182 | end
183 |
--------------------------------------------------------------------------------
/to_stylus.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # Convert SASS/SCSS to Stylus
3 | # Initial work by Andrey Popp (https://github.com/andreypopp)
4 |
5 | require 'sass'
6 | require 'yaml'
7 |
8 | class ToStylus < Sass::Tree::Visitors::Base
9 | @@functions = YAML::load_file(File.join(__dir__ , 'functions.yml'))
10 |
11 | def self.convert(file)
12 | engine = Sass::Engine.for_file(file, {})
13 |
14 | tree = engine.to_tree
15 | visit(tree)
16 | end
17 |
18 | def visit(node)
19 | if self.class.respond_to? :node_name
20 | method = "visit_#{node.class.node_name}"
21 | else
22 | method = "visit_#{node_name node}"
23 | end
24 | return if node.is_a?(Sass::Tree::CharsetNode)
25 | if self.respond_to?(method, true)
26 | self.send(method, node) {visit_children(node)}
27 | else
28 | if self.class.respond_to? :node_name
29 | raise "unhandled node: '#{node.class.node_name}'"
30 | else
31 | raise "unhandled node: '#{node_name node}'"
32 | end
33 | end
34 | end
35 |
36 | def visit_children(node)
37 | @indent += 1
38 | super(node)
39 | @indent -= 1
40 | end
41 |
42 | def determine_support(node, is_value)
43 | is_value ? (node_class = node.value) : (node_class = node.expr)
44 | if node_class.is_a? Sass::Script::Tree::Funcall
45 | @@functions['disabled_functions'].each do |func|
46 | if !node_class.inspect.match(func.to_s).nil?
47 | @errors.push("//#{func}: line #{node.line} in your Sass file")
48 | emit "//Function #{func} is not supported in Stylus"
49 | return func
50 | end
51 | end
52 | return
53 | end
54 | end
55 |
56 | def visit_prop(node, output="")
57 | func_support = determine_support(node, true)
58 | if !node.children.empty?
59 | output << "#{node.name.join('')}-"
60 | unless node.value.to_sass.empty?
61 | #for nested scss with values, change the last "-" in the output to a ":" to format output correctly
62 | if node.value.is_a? Sass::Script::Tree::Operation
63 | func_output = "#{output}(#{node.value.to_sass})".sub(/(.*)-/, '\1: ').gsub("\#{","{")
64 | elsif node.value.is_a?(Sass::Script::Tree::UnaryOperation) && node.value.operator.to_s == 'minus'
65 | func_output = "#{output}".sub(/(.*)-/, '\1: ') <<"-1*#{node.value.operand.inspect}".gsub("\#{","{")
66 | else
67 | func_output = "#{output}#{node.value.to_sass}".sub(/(.*)-/, '\1: ').gsub("\#{","{")
68 | end
69 | func_support.nil? ? (emit func_output) : (emit "//" << func_output)
70 | end
71 | node.children.each do |child|
72 | visit_prop(child,output)
73 | end
74 | else
75 | unless node.is_a? Sass::Tree::CommentNode
76 | "#{node.name.join("")[0]}" == "#" ?
77 | node_name = "#{output}{#{node.name-[""]}}:".tr('[]','') : node_name = "#{output}#{node.name.join('')}:"
78 |
79 | if node.value.is_a? Sass::Script::Tree::Operation
80 | func_output = node_name << " (#{node.value.to_sass})".gsub("\#{", "{")
81 | elsif node.value.is_a?(Sass::Script::Tree::UnaryOperation) && node.value.operator.to_s == 'minus'
82 | func_output = node_name << " -1*#{node.value.operand.inspect}"
83 | else
84 | func_output = node_name << " #{node.value.to_sass}".gsub("\#{", "{")
85 | end
86 | func_support.nil? ? (emit func_output) : (emit "//" << func_output)
87 | else
88 | visit(node)
89 | end
90 | end
91 | end
92 |
93 | def visit_variable(node)
94 | func_support = determine_support(node, false)
95 | output = "$#{node.name} = #{node.expr.to_sass}"
96 | func_support.nil? ? (emit output) : (emit "//" << output)
97 | end
98 |
99 | def render_arg(arg)
100 | if arg.is_a? Array
101 | var = arg[0]
102 | default = arg[1]
103 | if default
104 | "#{arg[0].to_sass} = #{arg[1].to_sass}"
105 | else
106 | var.to_sass
107 | end
108 | else
109 | arg.to_sass
110 | end
111 | end
112 |
113 | def render_args(args)
114 | args.map { |a| render_arg(a) }.join(', ')
115 | end
116 |
117 | def emit(line)
118 | line = (' ' * @indent) + line
119 | @lines.push line
120 | end
121 |
122 | def visit_if(node, isElse = false)
123 | line = []
124 | line.push 'else' if isElse
125 | line.push "if #{node.expr.to_sass}" if node.expr
126 | emit line.join(' ')
127 | visit_children(node)
128 | visit_if(node.else, true) if node.else
129 | end
130 |
131 | def visit_return(node)
132 | func_support = determine_support(node, false)
133 | output = node.expr.to_sass
134 | func_support.nil? ? (emit output) : (emit "//" << output)
135 | end
136 |
137 | def visit_comment(node)
138 | node.invisible? ? lines = node.to_sass.lines : lines = node.value.first.split("\n")
139 | lines.each { |line| emit line.tr("\n", "")}
140 | end
141 |
142 | def visit_mixindef(node)
143 | emit "#{node.name}(#{render_args(node.args)})"
144 | visit_children node
145 | end
146 |
147 | def visit_media(node)
148 | emit "@media #{node.query.map{|i| i.inspect}.join}".gsub! /"/, ""
149 | visit_children node
150 | end
151 |
152 | def visit_content(node)
153 | emit '{block}'
154 | end
155 |
156 | def visit_mixin(node)
157 | emit "#{node.name}(#{render_args(node.args)})"
158 | end
159 |
160 | def visit_import(node)
161 | emit "@import '#{node.imported_filename}'"
162 | end
163 |
164 | def visit_cssimport(node)
165 | if node.to_sass.include?("http://") && !node.to_sass.include?("url")
166 | emit "@import url(#{node.uri})"
167 | elsif(node.to_sass.index("\"http") || node.to_sass.index("\'http"))
168 | emit "#{node.to_sass}".chomp!
169 | elsif(node.to_sass.index("http"))
170 | emit "@import #{node.uri}".gsub("(", "(\"").gsub(")", "\")")
171 | else
172 | emit "#{node.to_sass}".chomp!
173 | end
174 | end
175 |
176 | def visit_extend(node)
177 | emit "#{node.to_sass}".gsub("%","$").chomp!
178 | end
179 |
180 | def visit_function(node)
181 | if node.splat.nil?
182 | emit "#{node.name}(#{render_args(node.args)})"
183 | else
184 | node.args.push([node.splat, nil])
185 | emit "#{node.name}(#{render_args(node.args)}...)"
186 | end
187 | visit_children node
188 | end
189 |
190 | def visit_rule(node)
191 | rule = (node.rule.length == 1 && node.rule[0].is_a?(String)) ? node.rule[0] : node.to_sass.lines[0]
192 | emit "#{rule}".gsub("\#{", "{").gsub("%", "$").chomp
193 | visit_children node
194 | end
195 |
196 | def for_helper(node, from_or_to)
197 | @@functions['disabled_functions'].each do |func|
198 | unless (from_or_to).inspect.match(func.to_s).nil?
199 | @errors.push("//#{func}: line #{node.line} in your Sass file")
200 | emit "//Function #{func} is not supported in Stylus"
201 | end
202 | end
203 | end
204 |
205 | def visit_for(node)
206 | (node.from.is_a? Sass::Script::Tree::Funcall) ? for_helper(node, node.from) : nil
207 | from = node.from.to_sass
208 |
209 | (node.to.is_a? Sass::Script::Tree::Funcall) ? for_helper(node, node.to) : nil
210 | temp_to = node.to.to_sass
211 |
212 | (node.to.is_a? Sass::Script::Tree::Literal) ? exclusive_to = temp_to.to_i - 1 : exclusive_to = "(#{temp_to}) - 1"
213 | node.exclusive ? to = exclusive_to : to = temp_to
214 |
215 | emit "for $#{node.var} in (#{from})..(#{to})"
216 | visit_children node
217 | end
218 |
219 | def visit_directive(node)
220 | emit "#{node.name}"
221 | visit_children node
222 | end
223 |
224 | def comment_out(node)
225 | node.to_sass.lines.each {|l| emit "//#{l}".chomp }
226 | end
227 |
228 | def visit_each(node)
229 | if node.vars.length == 1
230 | emit "for $#{node.vars.first} in #{node.list.to_sass}".gsub(",","")
231 | visit_children node
232 | else
233 | emit "//Cannot convert multi-variable each loops to Stylus"
234 | @errors.push("// @each: line #{node.line} in your Sass file")
235 | comment_out(node)
236 | end
237 | end
238 |
239 | def visit_while(node)
240 | emit "//Stylus does not support while loops"
241 | @errors.push("// @while: line #{node.line} in your Sass file")
242 | comment_out(node)
243 | end
244 |
245 | def visit_atroot(node)
246 | emit "//Stylus does not support @at-root"
247 | @errors.push("// @at-root: line #{node.line} in your Sass file")
248 | comment_out(node)
249 | end
250 |
251 | def visit_debug(node)
252 | emit "//Stylus does not support @debug"
253 | @errors.push("// @debug: line #{node.line} in your Sass file")
254 | comment_out(node)
255 | end
256 |
257 | def visit_warn(node)
258 | emit "//Stylus does not support @warn"
259 | @errors.push("// @warn: line #{node.line} in your Sass file")
260 | comment_out(node)
261 | end
262 |
263 | def visit_root(node)
264 | @indent = -1
265 | @errors = []
266 | @lines = []
267 | visit_children(node)
268 | unless @errors.empty?
269 | @errors.unshift("//Below is a list of the Sass rules that could not be converted to Stylus")
270 | @errors.push("\n")
271 | @lines.unshift(*@errors)
272 | end
273 | @lines.join("\n")
274 | end
275 |
276 | end
277 |
--------------------------------------------------------------------------------