puppet-validator 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|