puppet-validator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +13 -0
- data/README.md +149 -0
- data/bin/puppet-validator +78 -0
- data/config.ru +11 -0
- data/lib/puppet-validator.rb +132 -0
- data/public/info.png +0 -0
- data/public/prism-default.css +227 -0
- data/public/prism.js +961 -0
- data/public/styles.css +99 -0
- data/public/testing.html +38 -0
- data/views/index.erb +24 -0
- data/views/result.erb +37 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 27540dfa278a0cc463d85b7ed95420957b9f061f
|
4
|
+
data.tar.gz: 5d0c51971ca899cbddef2b63164722f18a0c8d68
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dfc4006d55991a8d84d381ef4be02a95e5df9e12164699509ed70e79b07cd68ccfbc5fa8059495748977d0ee5809c701ee435f6358a27f85f2744b04ec9a83f0
|
7
|
+
data.tar.gz: 753d447bf1e0cbcfc967da5fad07eecd85b2f3004eb37e58b230d8a0fa9fefca6c23f127532a85d22193eb38a0ef8f789aa5e34501af6cfab74534c7a3fce459
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2015 Puppet Labs, eduteam@puppetlabs.com
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# Puppet Validator:
|
2
|
+
## Puppet Code Validation as a service
|
3
|
+
|
4
|
+
Puppet Validator is a simple web service that accepts arbitrary code submissions and
|
5
|
+
validates it the way `puppet parser validate` would. It can optionally also
|
6
|
+
run `puppet-lint` checks on the code and display both results together.
|
7
|
+
|
8
|
+
Puppet Validator is completely themeable, albeit rather primitively.
|
9
|
+
|
10
|
+
### Usage:
|
11
|
+
|
12
|
+
#### Running the service directly
|
13
|
+
|
14
|
+
puppet-validator [-p <port>] [-l [logfile]] [-t <themedir>] [-d]
|
15
|
+
↳ Runs the Puppet Validator code validation service.
|
16
|
+
|
17
|
+
This is the simplest way to run Puppet Validator. It has no external dependencies, other
|
18
|
+
than the handful of gems it uses. This command will start the service. It will
|
19
|
+
not daemonize itself, though a `systemd` init script is provided that will take
|
20
|
+
care of that for you. It will default to running on port 9000, and will serve
|
21
|
+
content directly out of its installation directory. You can override and customize
|
22
|
+
the web content by passing the `-t` or `--theme` command-line argument. See
|
23
|
+
[Creating your own theme](#creating-your-own-theme) below.
|
24
|
+
|
25
|
+
Options:
|
26
|
+
|
27
|
+
-d, --debug Display or log debugging messages
|
28
|
+
-l, --logfile [LOGFILE] Path to logfile. Defaults to no logging, or
|
29
|
+
/var/log/puppet-validator if no filename is passed.
|
30
|
+
-p, --port PORT Port to listen on. Defaults to 9000.
|
31
|
+
-t, --theme THEMEDIR Path to the theme directory.
|
32
|
+
|
33
|
+
-h, --help Displays this help
|
34
|
+
|
35
|
+
#### Integrating with Middleware
|
36
|
+
|
37
|
+
If you plan to run this as a public service, then you may want to run it under
|
38
|
+
middleware, such as Phusion Passenger, for performance and scalability. The
|
39
|
+
specific implementation will depend on your choice of webserver and middleware.
|
40
|
+
|
41
|
+
To configure Puppet Validator on Apache and Passenger, you'll need to
|
42
|
+
<a href="https://www.phusionpassenger.com/library/install/apache/install/oss/el7/">
|
43
|
+
install and configure the appropriate packages</a>. Then you'll need to configure
|
44
|
+
a virtual host to contain the application.
|
45
|
+
|
46
|
+
``` Apache
|
47
|
+
# /etc/httpd/conf.d/puppet-validator.conf
|
48
|
+
Listen 9090
|
49
|
+
<VirtualHost *:9090>
|
50
|
+
ServerName 54.201.129.11
|
51
|
+
DocumentRoot /etc/puppet-validator/public
|
52
|
+
<Directory /etc/puppet-validator/public>
|
53
|
+
Require all granted
|
54
|
+
Allow from all
|
55
|
+
Options -MultiViews
|
56
|
+
</Directory>
|
57
|
+
</VirtualHost>
|
58
|
+
```
|
59
|
+
|
60
|
+
The `DocumentRoot` and `Directory` directives can point directly to the `public`
|
61
|
+
directory *within the gem installation directory*, or it can point to the `public`
|
62
|
+
directory of a custom theme you've created. See
|
63
|
+
[Creating your own theme](#creating-your-own-theme) below. The two directives
|
64
|
+
should point to the same directory.
|
65
|
+
|
66
|
+
In the directory directly above the `public` directory referenced above, you
|
67
|
+
should have a `config.ru` file. This file will actually bootstrap and start the
|
68
|
+
application. An example file exists in the root of the gem installation directory.
|
69
|
+
It looks similar to the file below and may be customized to pass in any options
|
70
|
+
you'd like.
|
71
|
+
|
72
|
+
``` Ruby
|
73
|
+
# /etc/puppet-validator/config.ru
|
74
|
+
require 'rubygems'
|
75
|
+
require 'puppet-validator'
|
76
|
+
|
77
|
+
logger = Logger.new('/var/log/puppet-validator')
|
78
|
+
logger.level = Logger::WARN
|
79
|
+
|
80
|
+
PuppetValidator.set :root, File.dirname(__FILE__)
|
81
|
+
PuppetValidator.set :logger, logger
|
82
|
+
|
83
|
+
run PuppetValidator
|
84
|
+
```
|
85
|
+
|
86
|
+
#### Creating your own theme
|
87
|
+
|
88
|
+
Creating a Puppet Validator theme is as simple as copying the content files to a directory
|
89
|
+
and customizing them. The `init` subcommand will do this for you. Note that the
|
90
|
+
command *will overwrite* existing files, but it will warn you before it does so.
|
91
|
+
|
92
|
+
root@master:~ # mkdir /etc/puppet-validator
|
93
|
+
root@master:~ # cd /etc/puppet-validator/
|
94
|
+
root@master:/etc/puppet-validator # puppet-validator init
|
95
|
+
Initializing directory as new Puppet Validator theme...
|
96
|
+
root@master:/etc/puppet-validator # tree
|
97
|
+
.
|
98
|
+
├── LICENSE
|
99
|
+
├── README.md
|
100
|
+
├── config.ru
|
101
|
+
├── public
|
102
|
+
│ ├── info.png
|
103
|
+
│ ├── prism-default.css
|
104
|
+
│ ├── prism.js
|
105
|
+
│ ├── styles.css
|
106
|
+
│ └── testing.html
|
107
|
+
└── views
|
108
|
+
├── index.erb
|
109
|
+
└── result.erb
|
110
|
+
|
111
|
+
Once you've created your theme, you can start the Puppet Validator service using the `-t`
|
112
|
+
or `--theme` command line arguments to tell Puppet Validator where to find your content.
|
113
|
+
|
114
|
+
root@master:~ # puppet-validator -t /etc/puppet-validator/
|
115
|
+
|
116
|
+
Alternatively, you can edit your webserver virtual host configuration to point
|
117
|
+
to the *public* directory within your new theme, as in the example shown above.
|
118
|
+
|
119
|
+
#### Disabling `puppet-lint` checks
|
120
|
+
|
121
|
+
Puppet-lint is an incredibly valuable tool. That said, some of the checks it runs
|
122
|
+
may not apply to your environment. It's easy to disable these checks, either on
|
123
|
+
the command-line, or in the `config.ru` file. By default, Puppet Validator will just run
|
124
|
+
all available checks.
|
125
|
+
|
126
|
+
Checks can be disabled either as a comma-separated list of checks:
|
127
|
+
|
128
|
+
root@master:~ # puppet-validator --disable 80chars,double_quoted_strings
|
129
|
+
|
130
|
+
Or in a file with one check per line.
|
131
|
+
|
132
|
+
root@master:~ # puppet-validator --disable /etc/puppet-validator/disabled_checks
|
133
|
+
root@master:~ # cat /etc/puppet-validator/disabled_checks
|
134
|
+
80chars
|
135
|
+
double_quoted_strings
|
136
|
+
|
137
|
+
This can also be done in your `config.ru`. Specifying a list would look like this:
|
138
|
+
|
139
|
+
``` Ruby
|
140
|
+
PuppetValidator.set :disabled_lint_checks, ['80chars', 'double_quoted_strings']
|
141
|
+
|
142
|
+
```
|
143
|
+
|
144
|
+
And loading the disabled checks from a file would look like:
|
145
|
+
|
146
|
+
``` Ruby
|
147
|
+
PuppetValidator.set :disabled_lint_checks, '/etc/puppet-validator/disabled_checks'
|
148
|
+
|
149
|
+
```
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'optparse'
|
5
|
+
require 'puppet-validator'
|
6
|
+
|
7
|
+
gemroot = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
8
|
+
options = {
|
9
|
+
:port => 9000,
|
10
|
+
:host => '0.0.0.0',
|
11
|
+
:bind => '0.0.0.0',
|
12
|
+
:root => gemroot,
|
13
|
+
}
|
14
|
+
logfile = $stderr
|
15
|
+
loglevel = Logger::WARN
|
16
|
+
|
17
|
+
optparse = OptionParser.new { |opts|
|
18
|
+
opts.banner = "Usage : puppet-validator [-p <port>] [-l [logfile]] [-t <themedir>] [-d]
|
19
|
+
↳ Runs the Puppet Validator code validation service.
|
20
|
+
|
21
|
+
puppet-validator init
|
22
|
+
↳ Copies the files needed to create a puppet-validator theme into $CWD.
|
23
|
+
This will overwrite existing files.
|
24
|
+
|
25
|
+
"
|
26
|
+
|
27
|
+
opts.on("-d", "--debug", "Display or log debugging messages") do
|
28
|
+
loglevel = Logger::DEBUG
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("--disable DISABLED_CHECKS", "Lint checks to disable. Either comma-separated list or filename.") do |arg|
|
32
|
+
puts "Disabling #{arg}"
|
33
|
+
options[:disabled_lint_checks] = arg
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on("-l [LOGFILE]", "--logfile [LOGFILE]", "Path to logfile. Defaults to no logging, or /var/log/puppet-validator if no filename is passed.") do |arg|
|
37
|
+
logfile = arg || '/var/log/puppet-validator'
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on("-p PORT", "--port", "Port to listen on. Defaults to 9000.") do |arg|
|
41
|
+
options[:port] = arg
|
42
|
+
end
|
43
|
+
|
44
|
+
opts.on("-t THEMEDIR", "--theme THEMEDIR", "Path to the theme directory.") do |arg|
|
45
|
+
options[:root] = arg
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.separator('')
|
49
|
+
|
50
|
+
opts.on("-h", "--help", "Displays this help") do
|
51
|
+
puts
|
52
|
+
puts opts
|
53
|
+
puts
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
}
|
57
|
+
optparse.parse!
|
58
|
+
|
59
|
+
if ARGV.first == 'init'
|
60
|
+
puts 'Initializing directory as new puppet-validator theme...'
|
61
|
+
unless (Dir.glob '**/*').empty?
|
62
|
+
puts '-- Overwriting existing files. Press Ctrl-C to cancel or <Enter> to continue.'
|
63
|
+
STDIN.gets
|
64
|
+
end
|
65
|
+
|
66
|
+
FileUtils.cp "#{gemroot}/config.ru", '.'
|
67
|
+
FileUtils.cp "#{gemroot}/LICENSE", '.'
|
68
|
+
FileUtils.cp "#{gemroot}/README.md", '.'
|
69
|
+
FileUtils.cp_r "#{gemroot}/public", '.'
|
70
|
+
FileUtils.cp_r "#{gemroot}/views", '.'
|
71
|
+
|
72
|
+
else
|
73
|
+
logger = Logger.new(logfile)
|
74
|
+
logger.level = loglevel
|
75
|
+
options[:logger] = logger
|
76
|
+
|
77
|
+
PuppetValidator.run! options
|
78
|
+
end
|
data/config.ru
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'puppet-validator'
|
3
|
+
|
4
|
+
logger = Logger.new('/var/log/puppet-validator')
|
5
|
+
logger.level = Logger::WARN
|
6
|
+
|
7
|
+
PuppetValidator.set :root, File.dirname(__FILE__)
|
8
|
+
PuppetValidator.set :logger, logger
|
9
|
+
PuppetValidator.set :disabled_lint_checks, ['80chars']
|
10
|
+
|
11
|
+
run PuppetValidator
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'puppet'
|
4
|
+
require 'puppet/parser'
|
5
|
+
require 'puppet-lint'
|
6
|
+
|
7
|
+
# something like 3,000 lines of code
|
8
|
+
MAXSIZE = 100000
|
9
|
+
CONTEXT = 3
|
10
|
+
|
11
|
+
class PuppetValidator < Sinatra::Base
|
12
|
+
set :logging, true
|
13
|
+
set :strict, true
|
14
|
+
|
15
|
+
before {
|
16
|
+
env["rack.logger"] = settings.logger if settings.logger
|
17
|
+
}
|
18
|
+
|
19
|
+
def initialize(app=nil)
|
20
|
+
super(app)
|
21
|
+
|
22
|
+
# there must be a better way
|
23
|
+
if settings.respond_to? :disabled_lint_checks
|
24
|
+
|
25
|
+
# can pass in an array, a filename, or a list of checks
|
26
|
+
if settings.disabled_lint_checks.class == String
|
27
|
+
path = File.expand_path(settings.disabled_lint_checks)
|
28
|
+
if File.file? path
|
29
|
+
data = File.readlines(path).map {|line| line.chomp }
|
30
|
+
data.reject! {|line| line.empty? or line.start_with? '#' }
|
31
|
+
|
32
|
+
settings.disabled_lint_checks = data
|
33
|
+
else
|
34
|
+
settings.disabled_lint_checks = settings.disabled_lint_checks.split(',')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
else
|
39
|
+
# this seems... gross, but I don't know a better way to make sure this
|
40
|
+
# option exists whether it was passed in or not.
|
41
|
+
def settings.disabled_lint_checks
|
42
|
+
[]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
get '/' do
|
49
|
+
erb :index
|
50
|
+
end
|
51
|
+
|
52
|
+
post '/validate' do
|
53
|
+
logger.info "Validating code from #{request.ip}."
|
54
|
+
logger.debug "validating #{request.ip}: #{params['code']}"
|
55
|
+
|
56
|
+
if request.body.size <= MAXSIZE
|
57
|
+
result = validate params['code']
|
58
|
+
lint = lint params['code'] if params['lint'] == 'on'
|
59
|
+
lint ||= {} # but make sure we have a data object to iterate
|
60
|
+
|
61
|
+
@code = params['code']
|
62
|
+
@message = result[:message]
|
63
|
+
@status = result[:status] ? :success : :fail
|
64
|
+
@line = result[:line]
|
65
|
+
@column = result[:pos]
|
66
|
+
@lint_warnings = ! lint.empty?
|
67
|
+
|
68
|
+
# initial highlighting for the potential syntax error
|
69
|
+
if @line
|
70
|
+
start = [@line - CONTEXT, 1].max
|
71
|
+
initial = {"#{start}-#{@line}" => nil}
|
72
|
+
else
|
73
|
+
initial = {}
|
74
|
+
end
|
75
|
+
|
76
|
+
# then add all the lint warnings and tooltip
|
77
|
+
@highlights = lint.inject(initial) do |acc, item|
|
78
|
+
acc.merge({item[:line] => "#{item[:kind].upcase}: #{item[:message]}"})
|
79
|
+
end.to_json
|
80
|
+
|
81
|
+
else
|
82
|
+
@message = "Submitted code size is #{request.body.size}, which is larger than the maximum size of #{MAXSIZE}."
|
83
|
+
@status = :fail
|
84
|
+
logger.error @message
|
85
|
+
end
|
86
|
+
|
87
|
+
erb :result
|
88
|
+
end
|
89
|
+
|
90
|
+
not_found do
|
91
|
+
halt 404, "You shall not pass! (page not found)\n"
|
92
|
+
end
|
93
|
+
|
94
|
+
helpers do
|
95
|
+
|
96
|
+
def validate(data)
|
97
|
+
begin
|
98
|
+
Puppet[:code] = data
|
99
|
+
validation_environment = Puppet.lookup(:current_environment)
|
100
|
+
|
101
|
+
validation_environment.check_for_reparse
|
102
|
+
validation_environment.known_resource_types.clear
|
103
|
+
|
104
|
+
{:status => true, :message => 'Syntax OK'}
|
105
|
+
rescue => detail
|
106
|
+
logger.warn detail.message
|
107
|
+
err = {:status => false, :message => detail.message}
|
108
|
+
err[:line] = detail.line if detail.methods.include? :line
|
109
|
+
err[:pos] = detail.pos if detail.methods.include? :pos
|
110
|
+
err
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def lint(data)
|
115
|
+
begin
|
116
|
+
settings.disabled_lint_checks.each do |check|
|
117
|
+
PuppetLint.configuration.send("disable_#{check}")
|
118
|
+
end
|
119
|
+
|
120
|
+
linter = PuppetLint.new
|
121
|
+
linter.code = data
|
122
|
+
linter.run
|
123
|
+
linter.print_problems
|
124
|
+
rescue => detail
|
125
|
+
logger.warn detail.message
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
data/public/info.png
ADDED
Binary file
|
@@ -0,0 +1,227 @@
|
|
1
|
+
/* http://prismjs.com/download.html?themes=prism&languages=puppet&plugins=line-highlight+line-numbers */
|
2
|
+
/**
|
3
|
+
* prism.js default theme for JavaScript, CSS and HTML
|
4
|
+
* Based on dabblet (http://dabblet.com)
|
5
|
+
* @author Lea Verou
|
6
|
+
*/
|
7
|
+
|
8
|
+
code[class*="language-"],
|
9
|
+
pre[class*="language-"] {
|
10
|
+
color: black;
|
11
|
+
background: none;
|
12
|
+
text-shadow: 0 1px white;
|
13
|
+
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
14
|
+
direction: ltr;
|
15
|
+
text-align: left;
|
16
|
+
white-space: pre;
|
17
|
+
word-spacing: normal;
|
18
|
+
word-break: normal;
|
19
|
+
word-wrap: normal;
|
20
|
+
line-height: 1.5;
|
21
|
+
|
22
|
+
-moz-tab-size: 4;
|
23
|
+
-o-tab-size: 4;
|
24
|
+
tab-size: 4;
|
25
|
+
|
26
|
+
-webkit-hyphens: none;
|
27
|
+
-moz-hyphens: none;
|
28
|
+
-ms-hyphens: none;
|
29
|
+
hyphens: none;
|
30
|
+
}
|
31
|
+
|
32
|
+
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
|
33
|
+
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
|
34
|
+
text-shadow: none;
|
35
|
+
background: #b3d4fc;
|
36
|
+
}
|
37
|
+
|
38
|
+
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
|
39
|
+
code[class*="language-"]::selection, code[class*="language-"] ::selection {
|
40
|
+
text-shadow: none;
|
41
|
+
background: #b3d4fc;
|
42
|
+
}
|
43
|
+
|
44
|
+
@media print {
|
45
|
+
code[class*="language-"],
|
46
|
+
pre[class*="language-"] {
|
47
|
+
text-shadow: none;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
/* Code blocks */
|
52
|
+
pre[class*="language-"] {
|
53
|
+
padding: 1em;
|
54
|
+
margin: .5em 0;
|
55
|
+
overflow: auto;
|
56
|
+
}
|
57
|
+
|
58
|
+
:not(pre) > code[class*="language-"],
|
59
|
+
pre[class*="language-"] {
|
60
|
+
background: #f5f2f0;
|
61
|
+
}
|
62
|
+
|
63
|
+
/* Inline code */
|
64
|
+
:not(pre) > code[class*="language-"] {
|
65
|
+
padding: .1em;
|
66
|
+
border-radius: .3em;
|
67
|
+
white-space: normal;
|
68
|
+
}
|
69
|
+
|
70
|
+
.token.comment,
|
71
|
+
.token.prolog,
|
72
|
+
.token.doctype,
|
73
|
+
.token.cdata {
|
74
|
+
color: slategray;
|
75
|
+
}
|
76
|
+
|
77
|
+
.token.punctuation {
|
78
|
+
color: #999;
|
79
|
+
}
|
80
|
+
|
81
|
+
.namespace {
|
82
|
+
opacity: .7;
|
83
|
+
}
|
84
|
+
|
85
|
+
.token.property,
|
86
|
+
.token.tag,
|
87
|
+
.token.boolean,
|
88
|
+
.token.number,
|
89
|
+
.token.constant,
|
90
|
+
.token.symbol,
|
91
|
+
.token.deleted {
|
92
|
+
color: #905;
|
93
|
+
}
|
94
|
+
|
95
|
+
.token.selector,
|
96
|
+
.token.attr-name,
|
97
|
+
.token.string,
|
98
|
+
.token.char,
|
99
|
+
.token.builtin,
|
100
|
+
.token.inserted {
|
101
|
+
color: #690;
|
102
|
+
}
|
103
|
+
|
104
|
+
.token.operator,
|
105
|
+
.token.entity,
|
106
|
+
.token.url,
|
107
|
+
.language-css .token.string,
|
108
|
+
.style .token.string {
|
109
|
+
color: #a67f59;
|
110
|
+
background: hsla(0, 0%, 100%, .5);
|
111
|
+
}
|
112
|
+
|
113
|
+
.token.atrule,
|
114
|
+
.token.attr-value,
|
115
|
+
.token.keyword {
|
116
|
+
color: #07a;
|
117
|
+
}
|
118
|
+
|
119
|
+
.token.function {
|
120
|
+
color: #DD4A68;
|
121
|
+
}
|
122
|
+
|
123
|
+
.token.regex,
|
124
|
+
.token.important,
|
125
|
+
.token.variable {
|
126
|
+
color: #e90;
|
127
|
+
}
|
128
|
+
|
129
|
+
.token.important,
|
130
|
+
.token.bold {
|
131
|
+
font-weight: bold;
|
132
|
+
}
|
133
|
+
.token.italic {
|
134
|
+
font-style: italic;
|
135
|
+
}
|
136
|
+
|
137
|
+
.token.entity {
|
138
|
+
cursor: help;
|
139
|
+
}
|
140
|
+
|
141
|
+
pre[data-line] {
|
142
|
+
position: relative;
|
143
|
+
padding: 1em 0 1em 3em;
|
144
|
+
}
|
145
|
+
|
146
|
+
.line-highlight {
|
147
|
+
position: absolute;
|
148
|
+
left: 0;
|
149
|
+
right: 0;
|
150
|
+
padding: inherit 0;
|
151
|
+
margin-top: 1em; /* Same as .prism’s padding-top */
|
152
|
+
|
153
|
+
background: hsla(24, 20%, 50%,.08);
|
154
|
+
background: -moz-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
|
155
|
+
background: -webkit-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
|
156
|
+
background: -o-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
|
157
|
+
background: linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
|
158
|
+
|
159
|
+
pointer-events: none;
|
160
|
+
|
161
|
+
line-height: inherit;
|
162
|
+
white-space: pre;
|
163
|
+
}
|
164
|
+
|
165
|
+
.line-highlight:before,
|
166
|
+
.line-highlight[data-end]:after {
|
167
|
+
content: attr(data-start);
|
168
|
+
position: absolute;
|
169
|
+
top: .4em;
|
170
|
+
left: .6em;
|
171
|
+
min-width: 1em;
|
172
|
+
padding: 0 .5em;
|
173
|
+
background-color: hsla(24, 20%, 50%,.4);
|
174
|
+
color: hsl(24, 20%, 95%);
|
175
|
+
font: bold 65%/1.5 sans-serif;
|
176
|
+
text-align: center;
|
177
|
+
vertical-align: .3em;
|
178
|
+
border-radius: 999px;
|
179
|
+
text-shadow: none;
|
180
|
+
box-shadow: 0 1px white;
|
181
|
+
}
|
182
|
+
|
183
|
+
.line-highlight[data-end]:after {
|
184
|
+
content: attr(data-end);
|
185
|
+
top: auto;
|
186
|
+
bottom: .4em;
|
187
|
+
}
|
188
|
+
pre.line-numbers {
|
189
|
+
position: relative;
|
190
|
+
padding-left: 3.8em;
|
191
|
+
counter-reset: linenumber;
|
192
|
+
}
|
193
|
+
|
194
|
+
pre.line-numbers > code {
|
195
|
+
position: relative;
|
196
|
+
}
|
197
|
+
|
198
|
+
.line-numbers .line-numbers-rows {
|
199
|
+
position: absolute;
|
200
|
+
pointer-events: none;
|
201
|
+
top: 0;
|
202
|
+
font-size: 100%;
|
203
|
+
left: -3.8em;
|
204
|
+
width: 3em; /* works for line-numbers below 1000 lines */
|
205
|
+
letter-spacing: -1px;
|
206
|
+
border-right: 1px solid #999;
|
207
|
+
|
208
|
+
-webkit-user-select: none;
|
209
|
+
-moz-user-select: none;
|
210
|
+
-ms-user-select: none;
|
211
|
+
user-select: none;
|
212
|
+
|
213
|
+
}
|
214
|
+
|
215
|
+
.line-numbers-rows > span {
|
216
|
+
pointer-events: none;
|
217
|
+
display: block;
|
218
|
+
counter-increment: linenumber;
|
219
|
+
}
|
220
|
+
|
221
|
+
.line-numbers-rows > span:before {
|
222
|
+
content: counter(linenumber);
|
223
|
+
color: #999;
|
224
|
+
display: block;
|
225
|
+
padding-right: 0.8em;
|
226
|
+
text-align: right;
|
227
|
+
}
|